From 7962b95fbd0e4b944c16d2ed121dbc84320c3903 Mon Sep 17 00:00:00 2001 From: Stephen Hurd Date: Fri, 25 Aug 2017 01:42:36 -0700 Subject: [PATCH 0001/2207] Various pkt-gen fixes - Add a -N option to not normalize units. Useful for automated tools. - Or in -o option so command-line order of -I, -X, -r, -z, -Z, and -A doesn't matter. - Avoid unaligned access, some new compilers will warn on it, and pkt-gen uses -Werror -Wall. - Document all supported options in usage() (even -m). - Remove documentation of unsupported -r and -t options - Align tabs in usage() --- apps/include/ctrs.h | 17 ++- apps/pkt-gen/pkt-gen.c | 319 ++++++++++++++++++++++++----------------- 2 files changed, 196 insertions(+), 140 deletions(-) diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h index e8717875d..d2c195e7b 100644 --- a/apps/include/ctrs.h +++ b/apps/include/ctrs.h @@ -16,21 +16,26 @@ struct my_ctrs { * Caller has to make sure that the buffer is large enough. */ static const char * -norm2(char *buf, double val, char *fmt) +norm2(char *buf, double val, char *fmt, int normalize) { char *units[] = { "", "K", "M", "G", "T" }; u_int i; - - for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++) - val /= 1000; + if (normalize) + for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++) + val /= 1000; + else + i=0; sprintf(buf, fmt, val, units[i]); return buf; } static __inline const char * -norm(char *buf, double val) +norm(char *buf, double val, int normalize) { - return norm2(buf, val, "%.3f %s"); + if (normalize) + return norm2(buf, val, "%.3f %s", normalize); + else + return norm2(buf, val, "%.0f %s", normalize); } static __inline int diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index a1d063a63..137e42110 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -186,6 +186,7 @@ const char *indirect_payload="netmap pkt-gen indirect payload\n" "http://info.iet.unipi.it/~luigi/netmap/ "; int verbose = 0; +int normalize = 1; #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ @@ -752,39 +753,39 @@ dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) static void update_ip(struct pkt *pkt, struct glob_arg *g) { - struct ip *ip; - struct udphdr *udp; + struct ip ip; + struct udphdr udp; uint32_t oaddr, naddr; uint16_t oport, nport; uint16_t ip_sum, udp_sum; - ip = &pkt->ipv4.ip; - udp = &pkt->ipv4.udp; + memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); + memcpy(&udp, &pkt->ipv4.udp, sizeof(udp)); do { ip_sum = udp_sum = 0; - naddr = oaddr = ntohl(ip->ip_src.s_addr); - nport = oport = ntohs(udp->uh_sport); + naddr = oaddr = ntohl(ip.ip_src.s_addr); + nport = oport = ntohs(udp.uh_sport); if (g->options & OPT_RANDOM_SRC) { - ip->ip_src.s_addr = random(); - udp->uh_sport = random(); - naddr = ntohl(ip->ip_src.s_addr); - nport = ntohs(udp->uh_sport); + ip.ip_src.s_addr = random(); + udp.uh_sport = random(); + naddr = ntohl(ip.ip_src.s_addr); + nport = ntohs(udp.uh_sport); break; } if (oport < g->src_ip.port1) { nport = oport + 1; - udp->uh_sport = htons(nport); + udp.uh_sport = htons(nport); break; } nport = g->src_ip.port0; - udp->uh_sport = htons(nport); + udp.uh_sport = htons(nport); if (oaddr < g->src_ip.ipv4.end) { naddr = oaddr + 1; - ip->ip_src.s_addr = htonl(naddr); + ip.ip_src.s_addr = htonl(naddr); break; } naddr = g->src_ip.ipv4.start; - ip->ip_src.s_addr = htonl(naddr); + ip.ip_src.s_addr = htonl(naddr); } while (0); /* update checksums if needed */ if (oaddr != naddr) { @@ -798,29 +799,29 @@ update_ip(struct pkt *pkt, struct glob_arg *g) udp_sum = cksum_add(udp_sum, nport); } do { - naddr = oaddr = ntohl(ip->ip_dst.s_addr); - nport = oport = ntohs(udp->uh_dport); + naddr = oaddr = ntohl(ip.ip_dst.s_addr); + nport = oport = ntohs(udp.uh_dport); if (g->options & OPT_RANDOM_DST) { - ip->ip_dst.s_addr = random(); - udp->uh_dport = random(); - naddr = ntohl(ip->ip_dst.s_addr); - nport = ntohs(udp->uh_dport); + ip.ip_dst.s_addr = random(); + udp.uh_dport = random(); + naddr = ntohl(ip.ip_dst.s_addr); + nport = ntohs(udp.uh_dport); break; } if (oport < g->dst_ip.port1) { nport = oport + 1; - udp->uh_dport = htons(nport); + udp.uh_dport = htons(nport); break; } nport = g->dst_ip.port0; - udp->uh_dport = htons(nport); + udp.uh_dport = htons(nport); if (oaddr < g->dst_ip.ipv4.end) { naddr = oaddr + 1; - ip->ip_dst.s_addr = htonl(naddr); + ip.ip_dst.s_addr = htonl(naddr); break; } naddr = g->dst_ip.ipv4.start; - ip->ip_dst.s_addr = htonl(naddr); + ip.ip_dst.s_addr = htonl(naddr); } while (0); /* update checksums */ if (oaddr != naddr) { @@ -834,11 +835,13 @@ update_ip(struct pkt *pkt, struct glob_arg *g) udp_sum = cksum_add(udp_sum, nport); } if (udp_sum != 0) - udp->uh_sum = ~cksum_add(~udp->uh_sum, htons(udp_sum)); + udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum)); if (ip_sum != 0) { - ip->ip_sum = ~cksum_add(~ip->ip_sum, htons(ip_sum)); - udp->uh_sum = ~cksum_add(~udp->uh_sum, htons(ip_sum)); + ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum)); + udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(ip_sum)); } + memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); + memcpy(&pkt->ipv4.udp, &udp, sizeof(udp)); } #ifndef s6_addr16 @@ -847,41 +850,41 @@ update_ip(struct pkt *pkt, struct glob_arg *g) static void update_ip6(struct pkt *pkt, struct glob_arg *g) { - struct ip6_hdr *ip6; - struct udphdr *udp; + struct ip6_hdr ip6; + struct udphdr udp; uint16_t udp_sum; uint16_t oaddr, naddr; uint16_t oport, nport; uint8_t group; - ip6 = &pkt->ipv6.ip; - udp = &pkt->ipv6.udp; + memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6)); + memcpy(&udp, &pkt->ipv6.udp, sizeof(udp)); do { udp_sum = 0; group = g->src_ip.ipv6.sgroup; - naddr = oaddr = ntohs(ip6->ip6_src.s6_addr16[group]); - nport = oport = ntohs(udp->uh_sport); + naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]); + nport = oport = ntohs(udp.uh_sport); if (g->options & OPT_RANDOM_SRC) { - ip6->ip6_src.s6_addr16[group] = random(); - udp->uh_sport = random(); - naddr = ntohs(ip6->ip6_src.s6_addr16[group]); - nport = ntohs(udp->uh_sport); + ip6.ip6_src.s6_addr16[group] = random(); + udp.uh_sport = random(); + naddr = ntohs(ip6.ip6_src.s6_addr16[group]); + nport = ntohs(udp.uh_sport); break; } if (oport < g->src_ip.port1) { nport = oport + 1; - udp->uh_sport = htons(nport); + udp.uh_sport = htons(nport); break; } nport = g->src_ip.port0; - udp->uh_sport = htons(nport); + udp.uh_sport = htons(nport); if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) { naddr = oaddr + 1; - ip6->ip6_src.s6_addr16[group] = htons(naddr); + ip6.ip6_src.s6_addr16[group] = htons(naddr); break; } naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); - ip6->ip6_src.s6_addr16[group] = htons(naddr); + ip6.ip6_src.s6_addr16[group] = htons(naddr); } while (0); /* update checksums if needed */ if (oaddr != naddr) @@ -891,29 +894,29 @@ update_ip6(struct pkt *pkt, struct glob_arg *g) cksum_add(~oport, nport)); do { group = g->dst_ip.ipv6.egroup; - naddr = oaddr = ntohs(ip6->ip6_dst.s6_addr16[group]); - nport = oport = ntohs(udp->uh_dport); + naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]); + nport = oport = ntohs(udp.uh_dport); if (g->options & OPT_RANDOM_DST) { - ip6->ip6_dst.s6_addr16[group] = random(); - udp->uh_dport = random(); - naddr = ntohs(ip6->ip6_dst.s6_addr16[group]); - nport = ntohs(udp->uh_dport); + ip6.ip6_dst.s6_addr16[group] = random(); + udp.uh_dport = random(); + naddr = ntohs(ip6.ip6_dst.s6_addr16[group]); + nport = ntohs(udp.uh_dport); break; } if (oport < g->dst_ip.port1) { nport = oport + 1; - udp->uh_dport = htons(nport); + udp.uh_dport = htons(nport); break; } nport = g->dst_ip.port0; - udp->uh_dport = htons(nport); + udp.uh_dport = htons(nport); if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) { naddr = oaddr + 1; - ip6->ip6_dst.s6_addr16[group] = htons(naddr); + ip6.ip6_dst.s6_addr16[group] = htons(naddr); break; } naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]); - ip6->ip6_dst.s6_addr16[group] = htons(naddr); + ip6.ip6_dst.s6_addr16[group] = htons(naddr); } while (0); /* update checksums */ if (oaddr != naddr) @@ -923,7 +926,9 @@ update_ip6(struct pkt *pkt, struct glob_arg *g) udp_sum = cksum_add(udp_sum, cksum_add(~oport, nport)); if (udp_sum != 0) - udp->uh_sum = ~cksum_add(~udp->uh_sum, udp_sum); + udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum); + memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); + memcpy(&pkt->ipv6.udp, &udp, sizeof(udp)); } static void @@ -944,9 +949,10 @@ initialize_packet(struct targ *targ) { struct pkt *pkt = &targ->pkt; struct ether_header *eh; - struct ip6_hdr *ip6; - struct ip *ip; - struct udphdr *udp; + struct ip6_hdr ip6; + struct ip ip; + struct udphdr udp; + void *udp_ptr; uint16_t paylen; uint32_t csum; const char *payload = targ->g->options & OPT_INDIRECT ? @@ -978,7 +984,7 @@ initialize_packet(struct targ *targ) #endif paylen = targ->g->pkt_size - sizeof(*eh) - - (targ->g->af == AF_INET ? sizeof(*ip): sizeof(*ip6)); + (targ->g->af == AF_INET ? sizeof(ip): sizeof(ip6)); /* create a nice NUL-terminated string */ for (i = 0; i < paylen; i += l0) { @@ -995,56 +1001,61 @@ initialize_packet(struct targ *targ) if (targ->g->af == AF_INET) { eh->ether_type = htons(ETHERTYPE_IP); - ip = &pkt->ipv4.ip; - udp = &pkt->ipv4.udp; - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_id = 0; - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = htons(targ->g->pkt_size - sizeof(*eh)); - ip->ip_id = 0; - ip->ip_off = htons(IP_DF); /* Don't fragment */ - ip->ip_ttl = IPDEFTTL; - ip->ip_p = IPPROTO_UDP; - ip->ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); - ip->ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); - ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0)); + memcpy(&ip, &pkt->ipv4.ip, sizeof(ip)); + udp_ptr = &pkt->ipv4.udp; + ip.ip_v = IPVERSION; + ip.ip_hl = sizeof(ip) >> 2; + ip.ip_id = 0; + ip.ip_tos = IPTOS_LOWDELAY; + ip.ip_len = htons(targ->g->pkt_size - sizeof(*eh)); + ip.ip_id = 0; + ip.ip_off = htons(IP_DF); /* Don't fragment */ + ip.ip_ttl = IPDEFTTL; + ip.ip_p = IPPROTO_UDP; + ip.ip_dst.s_addr = htonl(targ->g->dst_ip.ipv4.start); + ip.ip_src.s_addr = htonl(targ->g->src_ip.ipv4.start); + ip.ip_sum = wrapsum(checksum(&ip, sizeof(ip), 0)); + memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); } else { eh->ether_type = htons(ETHERTYPE_IPV6); - ip6 = &pkt->ipv6.ip; - udp = &pkt->ipv6.udp; - ip6->ip6_flow = 0; - ip6->ip6_plen = htons(paylen); - ip6->ip6_vfc = IPV6_VERSION; - ip6->ip6_nxt = IPPROTO_UDP; - ip6->ip6_hlim = IPV6_DEFHLIM; - ip6->ip6_src = targ->g->src_ip.ipv6.start; - ip6->ip6_dst = targ->g->dst_ip.ipv6.start; - } - - udp->uh_sport = htons(targ->g->src_ip.port0); - udp->uh_dport = htons(targ->g->dst_ip.port0); - udp->uh_ulen = htons(paylen); + memcpy(&ip6, &pkt->ipv4.ip, sizeof(ip6)); + udp_ptr = &pkt->ipv6.udp; + ip6.ip6_flow = 0; + ip6.ip6_plen = htons(paylen); + ip6.ip6_vfc = IPV6_VERSION; + ip6.ip6_nxt = IPPROTO_UDP; + ip6.ip6_hlim = IPV6_DEFHLIM; + ip6.ip6_src = targ->g->src_ip.ipv6.start; + ip6.ip6_dst = targ->g->dst_ip.ipv6.start; + } + memcpy(&udp, udp_ptr, sizeof(udp)); + + udp.uh_sport = htons(targ->g->src_ip.port0); + udp.uh_dport = htons(targ->g->dst_ip.port0); + udp.uh_ulen = htons(paylen); if (targ->g->af == AF_INET) { /* Magic: taken from sbin/dhclient/packet.c */ - udp->uh_sum = wrapsum( - checksum(udp, sizeof(*udp), /* udp header */ + udp.uh_sum = wrapsum( + checksum(&udp, sizeof(udp), /* udp header */ checksum(pkt->ipv4.body, /* udp payload */ - paylen - sizeof(*udp), + paylen - sizeof(udp), checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */ 2 * sizeof(pkt->ipv4.ip.ip_src), - IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen))))); + IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen))))); + memcpy(&pkt->ipv4.ip, &ip, sizeof(ip)); } else { /* Save part of pseudo header checksum into csum */ csum = IPPROTO_UDP << 24; csum = checksum(&csum, sizeof(csum), paylen); - udp->uh_sum = wrapsum( - checksum(udp, sizeof(*udp), /* udp header */ + udp.uh_sum = wrapsum( + checksum(udp_ptr, sizeof(udp), /* udp header */ checksum(pkt->ipv6.body, /* udp payload */ - paylen - sizeof(*udp), + paylen - sizeof(udp), checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */ 2 * sizeof(pkt->ipv6.ip.ip6_src), csum)))); + memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6)); } + memcpy(udp_ptr, &udp, sizeof(udp)); bzero(&pkt->vh, sizeof(pkt->vh)); // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); @@ -1864,6 +1875,7 @@ txseq_body(void *data) unsigned int space; unsigned int head; int fcnt; + uint16_t sum; if (!rate_limit) { budget = targ->g->burst; @@ -1910,19 +1922,19 @@ txseq_body(void *data) sent < limit; sent++, sequence++) { struct netmap_slot *slot = &ring->slot[head]; char *p = NETMAP_BUF(ring, slot->buf_idx); - uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t, - *sum = (uint16_t *)(targ->g->af == AF_INET ? - &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum); + uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t; + + memcpy(&sum, targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, sizeof(sum)); slot->flags = 0; t = *w; PKT(pkt, body, targ->g->af)[0] = sequence >> 24; PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; - *sum = ~cksum_add(~*sum, cksum_add(~t, *w)); + sum = ~cksum_add(~sum, cksum_add(~t, *w)); t = *++w; PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; - *sum = ~cksum_add(~*sum, cksum_add(~t, *w)); + sum = ~cksum_add(~sum, cksum_add(~t, *w)); nm_pkt_copy(frame, p, size); if (fcnt == frags) { update_addresses(pkt, targ->g); @@ -1952,6 +1964,7 @@ txseq_body(void *data) budget--; } } + memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum)); ring->cur = ring->head = head; @@ -2209,7 +2222,7 @@ tx_output(struct my_ctrs *cur, double delta, const char *msg) abs = cur->pkts / (double)(cur->events); printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", - norm(b1, pps), norm(b2, bw), norm(b3, raw_bw), abs); + norm(b1, pps, normalize), norm(b2, bw, normalize), norm(b3, raw_bw, normalize), abs); } static void @@ -2219,38 +2232,72 @@ usage(void) fprintf(stderr, "Usage:\n" "%s arguments\n" - "\t-i interface interface name\n" - "\t-f function tx rx ping pong txseq rxseq\n" - "\t-n count number of iterations (can be 0)\n" - "\t-t pkts_to_send also forces tx mode\n" - "\t-r pkts_to_receive also forces rx mode\n" - "\t-l pkt_size in bytes excluding CRC\n" - "\t (if passed a second time, use random sizes\n" - "\t bigger than the second one and lower than\n" - "\t the first one)\n" - "\t-d dst_ip[:port[-dst_ip:port]] single or range\n" - "\t-s src_ip[:port[-src_ip:port]] single or range\n" - "\t-D dst-mac\n" - "\t-S src-mac\n" - "\t-a cpu_id use setaffinity\n" - "\t-b burst size testing, mostly\n" - "\t-c cores cores to use\n" - "\t-p threads processes/threads to use\n" - "\t-T report_ms milliseconds between reports\n" - "\t-w wait_for_link_time in seconds\n" - "\t-R rate in packets per second\n" - "\t-X dump payload\n" - "\t-H len add empty virtio-net-header with size 'len'\n" - "\t-E pipes allocate extra space for a number of pipes\n" - "\t-r do not touch the buffers (send rubbish)\n" - "\t-P file load packet from pcap file\n" - "\t-z use random IPv4 src address/port\n" - "\t-Z use random IPv4 dst address/port\n" - "\t-F num_frags send multi-slot packets\n" - "\t-A activate pps stats on receiver\n" - "", + "\t-i interface interface name\n" + "\t-f function tx rx ping pong txseq rxseq\n" + "\t-n count number of iterations (can be 0)\n" +#ifdef notyet + "\t-t pkts_to_send also forces tx mode\n" + "\t-r pkts_to_receive also forces rx mode\n" +#endif + "\t-l pkt_size in bytes excluding CRC\n" + "\t (if passed a second time, use random sizes\n" + "\t bigger than the second one and lower than\n" + "\t the first one)\n" + "\t-d dst_ip[:port[-dst_ip:port]] single or range\n" + "\t-s src_ip[:port[-src_ip:port]] single or range\n" + "\t-D dst-mac\n" + "\t-S src-mac\n" + "\t-a cpu_id use setaffinity\n" + "\t-b burst size testing, mostly\n" + "\t-c cores cores to use\n" + "\t-p threads processes/threads to use\n" + "\t-T report_ms milliseconds between reports\n" + "\t-w wait_for_link_time in seconds\n" + "\t-R rate in packets per second\n" + "\t-X dump payload\n" + "\t-H len add empty virtio-net-header with size 'len'\n" + "\t-E pipes allocate extra space for a number of pipes\n" + "\t-r do not touch the buffers (send rubbish)\n" + "\t-P file load packet from pcap file\n" + "\t-z use random IPv4 src address/port\n" + "\t-Z use random IPv4 dst address/port\n" + "\t-F num_frags send multi-slot packets\n" + "\t-A activate pps stats on receiver\n" + "\t-4 IPv4\n" + "\t-6 IPv6\n" + "\t-N don't normalize units (Kbps/Mbps/etc)\n" + "\t-I use indirect buffers, tx only\n" + "\t-o options data generation options (parsed using atoi)\n" + "\t OPT_PREFETCH 1\n" + "\t OPT_ACCESS 2\n" + "\t OPT_COPY 4\n" + "\t OPT_MEMCPY 8\n" + "\t OPT_TS 16 (add a timestamp)\n" + "\t OPT_INDIRECT 32 (use indirect buffers)\n" + "\t OPT_DUMP 64 (dump rx/tx traffic)\n" + "\t OPT_RUBBISH 256\n" + "\t (send wathever the buffers contain)\n" + "\t OPT_RANDOM_SRC 512\n" + "\t OPT_RANDOM_DST 1024\n" + "\t OPT_PPS_STATS 2048\n" + "\t-W exit RX with no traffic\n" + "\t-v verbose (more v = more verbose)\n" + "\t-C vale-config specify a vale config\n" +#ifdef notyet + "\t The configuration may consist of 0 to 4\n" + "\t numbers separated by commas:\n" + "\t #tx-slots,#rx-slots,#tx-rings,#rx-rings.\n" + "\t Missing numbers or zeroes stand for default\n" + "\t values. As an additional convenience, if\n" + "\t exactly one number is specified, then this\n" + "\t is assigned to both #tx-slots and #rx-slots.\n" + "\t If there is no 4th number, then the 3rd is\n" + "\t assigned to both #tx-rings and #rx-rings.\n" +#endif + "\t-e extra-bufs extra_bufs - goes in nr_arg3\n" + "\t-m ignored\n" + "", cmd); - exit(0); } @@ -2405,13 +2452,13 @@ main_thread(struct glob_arg *g) ppsdev = sqrt(ppsdev); snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", - norm(b1, ppsavg), norm(b2, ppsdev)); + norm(b1, ppsavg, normalize), norm(b2, ppsdev, normalize)); } D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", - norm(b1, pps), b4, - norm(b2, (double)x.pkts), - norm(b3, (double)x.bytes*8), + norm(b1, pps, normalize), b4, + norm(b2, (double)x.pkts, normalize), + norm(b3, (double)x.bytes*8, normalize), (unsigned long long)usec, abs, (int)cur.min_space); prev = cur; @@ -2589,7 +2636,7 @@ main(int arc, char **argv) g.virt_header = 0; g.wait_link = 2; - while ((ch = getopt(arc, argv, "46a:f:F:n:i:Il:d:s:D:S:b:c:o:p:" + while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:" "T:w:WvR:XC:H:e:E:m:rP:zZA")) != -1) { switch(ch) { @@ -2606,6 +2653,10 @@ main(int arc, char **argv) g.af = AF_INET6; break; + case 'N': + normalize = 0; + break; + case 'n': g.npackets = strtoull(optarg, NULL, 10); break; @@ -2633,7 +2684,7 @@ main(int arc, char **argv) break; case 'o': /* data generation options */ - g.options = atoi(optarg); + g.options |= atoi(optarg); break; case 'a': /* force affinity */ From e570a30f9cb4ba69dc27e2d3c57e0205dac92452 Mon Sep 17 00:00:00 2001 From: Juha-Matti Tilli Date: Sat, 2 Sep 2017 16:05:07 +0300 Subject: [PATCH 0002/2207] apps: make compiling apps on Raspberry Pi possible There were quite many format mismatch errors and also one left-shifting of 32-bit integer by 32. Fixes issue #357 --- apps/lb/lb.c | 2 +- apps/nmreplay/nmreplay.c | 12 ++++++------ apps/pkt-gen/pkt-gen.c | 6 ++++-- apps/tlem/tlem.c | 32 ++++++++++++++++---------------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 57a2d1c24..64c9bce04 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -941,7 +941,7 @@ int main(int argc, char **argv) if (hash == 0) { non_ip++; // XXX ?? } - rs->ptr = hash | (1UL << 32); + rs->ptr = hash | (1ULL << 32); // prefetch the buffer for the next round next_cur = nm_ring_next(rxring, next_cur); next_slot = &rxring->slot[next_cur]; diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c index de72c0abd..01d74566c 100644 --- a/apps/nmreplay/nmreplay.c +++ b/apps/nmreplay/nmreplay.c @@ -771,7 +771,7 @@ pcap_prod(void *_pa) need = loops * pf->tot_bytes_rounded + sizeof(struct q_pkt); q->buf = calloc(1, need); if (q->buf == NULL) { - D("alloc %ld bytes for queue failed, exiting",(_P64)need); + D("alloc %lld bytes for queue failed, exiting",(long long)need); goto fail; } q->prod_head = q->prod_tail = 0; @@ -1261,9 +1261,9 @@ main(int argc, char **argv) struct _qs *q0 = &bp[0].q; sleep(1); - ED("%ld -> %ld maxq %d round %ld", - (_P64)(q0->rx - olda.rx), (_P64)(q0->tx - olda.tx), - q0->rx_qmax, (_P64)q0->prod_max_gap + ED("%lld -> %lld maxq %d round %lld", + (long long)(q0->rx - olda.rx), (long long)(q0->tx - olda.tx), + q0->rx_qmax, (long long)q0->prod_max_gap ); ED("plr nominal %le actual %le", (double)(q0->c_loss.d[0])/(1<<24), @@ -1529,7 +1529,7 @@ uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) dmax = parse_time(av[2]); if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax) return 1; - D("dmin %ld dmax %ld", (_P64)dmin, (_P64)dmax); + D("dmin %lld dmax %lld", (long long)dmin, (long long)dmax); dst->d[0] = dmin; dst->d[1] = dmax; dst->d[2] = dmax - dmin; @@ -1592,7 +1592,7 @@ exp_delay_run(struct _qs *q, struct _cfg *arg) { uint64_t *t = (uint64_t *)arg->arg; q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)]; - RD(5, "delay %lu", (_P64)q->cur_delay); + RD(5, "delay %llu", (unsigned long long)q->cur_delay); return 0; } diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index a1d063a63..891c4e6ce 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1324,7 +1324,8 @@ ping_body(void *data) ts.tv_nsec += 1000000000; ts.tv_sec--; } - if (0) D("seq %d/%lu delta %d.%09d", seq, sent, + if (0) D("seq %d/%llu delta %d.%09d", seq, + (unsigned long long)sent, (int)ts.tv_sec, (int)ts.tv_nsec); t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; if (t_cur < t_min) @@ -1409,7 +1410,8 @@ pong_body(void *data) return NULL; } if (n > 0) - D("understood ponger %lu but don't know how to do it", n); + D("understood ponger %llu but don't know how to do it", + (unsigned long long)n); while (!targ->cancel && (n == 0 || sent < n)) { uint32_t txcur, txavail; //#define BUSYWAIT diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c index ec9789b41..121fbc8ed 100644 --- a/apps/tlem/tlem.c +++ b/apps/tlem/tlem.c @@ -513,8 +513,8 @@ no_room(struct _qs *q) q_reclaim(q); if (q->prod_queued > q->qsize) { q->prod_drop++; - RD(1, "too many bytes queued %lu, drop %lu", - (_P64)q->prod_queued, (_P64)q->prod_drop); + RD(1, "too many bytes queued %llu, drop %llu", + (unsigned long long)q->prod_queued, (unsigned long long)q->prod_drop); return 1; } } @@ -523,8 +523,8 @@ no_room(struct _qs *q) h = q->prod_head = q->head; /* re-read head, just in case */ /* repeat the test */ if ((h <= t && new_t == 0 && h == 0) || (h > t && (new_t == 0 || new_t >= h)) ) { - ND(1, "no room for insert h %ld t %ld new_t %ld", - (_P64)h, (_P64)t, (_P64)new_t); + ND(1, "no room for insert h %lld t %lld new_t %lld", + (long long)h, (long long)t, (long long)new_t); return 1; /* no room for insert */ } } @@ -906,17 +906,17 @@ tlem_main(void *_a) q->buf = calloc(1, need); if (q->buf == NULL) { - ED("alloc %ld bytes for queue failed, exiting", (_P64)need); + ED("alloc %lld bytes for queue failed, exiting", (long long)need); nm_close(a->pa); nm_close(a->pb); return(NULL); } q->buflen = need; - ED("----\n\t%s -> %s : bps %ld delay %s loss %s queue %ld bytes" - "\n\tbuffer %lu bytes", + ED("----\n\t%s -> %s : bps %lld delay %s loss %s queue %lld bytes" + "\n\tbuffer %llu bytes", q->prod_ifname, q->cons_ifname, - (_P64)q->max_bps, q->c_delay.optarg, q->c_loss.optarg, (_P64)q->qsize, - (_P64)q->buflen); + (long long)q->max_bps, q->c_delay.optarg, q->c_loss.optarg, + (long long)q->qsize, (unsigned long long)q->buflen); q->src_port = a->pa; @@ -1258,11 +1258,11 @@ main(int argc, char **argv) struct _qs *q0 = &bp[0].q, *q1 = &bp[1].q; sleep(1); - ED("%ld -> %ld maxq %d round %ld, %ld <- %ld maxq %d round %ld", - (_P64)(q0->rx - olda.rx), (_P64)(q0->tx - olda.tx), - q0->rx_qmax, (_P64)q0->prod_max_gap, - (_P64)(q1->rx - oldb.rx), (_P64)(q1->tx - oldb.tx), - q1->rx_qmax, (_P64)q1->prod_max_gap + ED("%lld -> %lld maxq %d round %lld, %lld <- %lld maxq %d round %lld", + (long long)(q0->rx - olda.rx), (long long)(q0->tx - olda.tx), + q0->rx_qmax, (long long)q0->prod_max_gap, + (long long)(q1->rx - oldb.rx), (long long)(q1->tx - oldb.tx), + q1->rx_qmax, (long long)q1->prod_max_gap ); ED("plr nominal %le actual %le", (double)(q0->c_loss.d[0])/(1<<24), @@ -1553,7 +1553,7 @@ uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) dmax = parse_time(av[2]); if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax) return 1; - D("dmin %ld dmax %ld", (_P64)dmin, (_P64)dmax); + D("dmin %lld dmax %lld", (long long)dmin, (long long)dmax); dst->d[0] = dmin; dst->d[1] = dmax; dst->d[2] = dmax - dmin; @@ -1618,7 +1618,7 @@ exp_delay_run(struct _qs *q, struct _cfg *arg) { uint64_t *t = (uint64_t *)arg->arg; q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)]; - RD(5, "delay %lu", (_P64)q->cur_delay); + RD(5, "delay %llu", (unsigned long long)q->cur_delay); return 0; } From 0093fc2f51de9aba00b1da4d0b279e5da15c4f8b Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Sun, 3 Sep 2017 11:05:22 +0200 Subject: [PATCH 0003/2207] mem: removed stale forward decl --- sys/dev/netmap/netmap_mem2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index 4a8ebb212..710050468 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -441,7 +441,6 @@ struct netmap_mem_d nm_mem = { /* Our memory allocator. */ /* blueprint for the private memory allocators */ -extern struct netmap_mem_ops netmap_mem_private_ops; /* forward */ /* XXX clang is not happy about using name as a print format */ static const struct netmap_mem_d nm_blueprint = { .pools = { From 43ce8cda7d7c892c8579339bd317c2780f6140d7 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Sun, 3 Sep 2017 11:18:13 +0200 Subject: [PATCH 0004/2207] mem: fix error path in private allocator creation --- sys/dev/netmap/netmap_mem2.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index 710050468..c7b42de90 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -1450,7 +1450,7 @@ _netmap_mem_private_new(struct netmap_obj_params *p, int *perr) err = nm_mem_assign_id(d); if (err) - goto error; + goto error_free; snprintf(d->name, NM_MEM_NAMESZ, "%d", d->nm_id); for (i = 0; i < NETMAP_POOLS_NR; i++) { @@ -1465,14 +1465,18 @@ _netmap_mem_private_new(struct netmap_obj_params *p, int *perr) err = netmap_mem_config(d); if (err) - goto error; + goto error_rel_id; d->flags &= ~NETMAP_MEM_FINALIZED; return d; +error_rel_id: + NMA_LOCK_DESTROY(d); + nm_mem_release_id(d); +error_free: + nm_os_free(d); error: - netmap_mem_delete(d); if (perr) *perr = err; return NULL; From e440b2305df7811abdba112b0457609d9592c873 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 4 Sep 2017 13:34:38 +0200 Subject: [PATCH 0005/2207] linux: ported patches to 4.13 --- .../vanilla--e1000--20620--31200 | 2 +- .../vanilla--e1000--31200--99999 | 2 +- .../vanilla--e1000e--20620--30100 | 2 +- .../vanilla--e1000e--30100--30400 | 2 +- .../vanilla--e1000e--30400--30900 | 2 +- .../vanilla--e1000e--30900--99999 | 2 +- .../vanilla--forcedeth.c--20626--99999 | 2 +- .../final-patches/vanilla--i40e--30c00--40100 | 4 +- .../final-patches/vanilla--i40e--40100--40300 | 4 +- .../final-patches/vanilla--i40e--40300--40400 | 4 +- .../final-patches/vanilla--i40e--40400--40700 | 4 +- .../final-patches/vanilla--i40e--40700--99999 | 4 +- .../final-patches/vanilla--igb--20621--20623 | 2 +- .../final-patches/vanilla--igb--20623--30200 | 2 +- .../final-patches/vanilla--igb--30200--30800 | 2 +- .../final-patches/vanilla--igb--30800--30f00 | 2 +- .../final-patches/vanilla--igb--30f00--40100 | 2 +- .../final-patches/vanilla--igb--40100--40400 | 2 +- .../final-patches/vanilla--igb--40400--99999 | 2 +- .../vanilla--ixgbe--20620--20622 | 2 +- .../vanilla--ixgbe--20622--20623 | 2 +- .../vanilla--ixgbe--20623--20625 | 2 +- .../vanilla--ixgbe--20625--20626 | 2 +- .../vanilla--ixgbe--20626--30100 | 2 +- .../vanilla--ixgbe--30100--30200 | 2 +- .../vanilla--ixgbe--30200--30400 | 2 +- .../vanilla--ixgbe--30400--30500 | 2 +- .../vanilla--ixgbe--30500--30700 | 2 +- .../vanilla--ixgbe--30700--30a00 | 2 +- .../vanilla--ixgbe--30a00--30d00 | 2 +- .../vanilla--ixgbe--30d00--30f00 | 2 +- .../vanilla--ixgbe--30f00--31300 | 2 +- .../vanilla--ixgbe--31300--40900 | 2 +- .../vanilla--ixgbe--40900--99999 | 2 +- ...--30500 => vanilla--ixgbevf--30200--30500} | 20 +-- .../vanilla--ixgbevf--30500--30600 | 2 +- .../vanilla--ixgbevf--30600--30700 | 2 +- .../vanilla--ixgbevf--30700--30d00 | 2 +- .../vanilla--ixgbevf--30d00--30e00 | 2 +- .../vanilla--ixgbevf--30e00--30f00 | 2 +- .../vanilla--ixgbevf--30f00--31200 | 2 +- .../vanilla--ixgbevf--31200--31300 | 2 +- .../vanilla--ixgbevf--31300--40000 | 2 +- .../vanilla--ixgbevf--40000--40900 | 2 +- ...--40b00 => vanilla--ixgbevf--40900--99999} | 2 +- .../vanilla--ixgbevf--40b00--40c00 | 109 ---------------- .../vanilla--ixgbevf--40c00--99999 | 118 ------------------ .../vanilla--r8169.c--20620--20625 | 2 +- .../vanilla--r8169.c--20625--20626 | 2 +- .../vanilla--r8169.c--20626--30400 | 2 +- .../vanilla--veth.c--20620--30900 | 2 +- .../vanilla--veth.c--30900--30f00 | 2 +- .../vanilla--veth.c--30f00--99999 | 2 +- .../vanilla--virtio_net.c--20622--20625 | 2 +- .../vanilla--virtio_net.c--20625--20626 | 2 +- .../vanilla--virtio_net.c--20626--30300 | 2 +- .../vanilla--virtio_net.c--30300--30500 | 2 +- .../vanilla--virtio_net.c--30500--30800 | 2 +- .../vanilla--virtio_net.c--30800--30b00 | 2 +- .../vanilla--virtio_net.c--30b00--31100 | 2 +- .../vanilla--virtio_net.c--31100--31300 | 2 +- .../vanilla--virtio_net.c--31300--40100 | 2 +- .../vanilla--virtio_net.c--40100--40900 | 2 +- .../vanilla--virtio_net.c--40900--40c00 | 2 +- .../vanilla--virtio_net.c--40c00--99999 | 2 +- 65 files changed, 77 insertions(+), 304 deletions(-) rename LINUX/final-patches/{vanilla--ixgbevf--20622--30500 => vanilla--ixgbevf--30200--30500} (84%) rename LINUX/final-patches/{vanilla--ixgbevf--40900--40b00 => vanilla--ixgbevf--40900--99999} (98%) delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--40b00--40c00 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--40c00--99999 diff --git a/LINUX/final-patches/vanilla--e1000--20620--31200 b/LINUX/final-patches/vanilla--e1000--20620--31200 index 0d8bb0577..c36154ed8 100644 --- a/LINUX/final-patches/vanilla--e1000--20620--31200 +++ b/LINUX/final-patches/vanilla--e1000--20620--31200 @@ -1,5 +1,5 @@ diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c -index bcd192c..013f528 100644 +index bcd192ca47b0..013f52897fd8 100644 --- a/e1000/e1000_main.c +++ b/e1000/e1000_main.c @@ -190,6 +190,10 @@ static struct pci_error_handlers e1000_err_handler = { diff --git a/LINUX/final-patches/vanilla--e1000--31200--99999 b/LINUX/final-patches/vanilla--e1000--31200--99999 index eeca93fd1..e3cd77bd4 100644 --- a/LINUX/final-patches/vanilla--e1000--31200--99999 +++ b/LINUX/final-patches/vanilla--e1000--31200--99999 @@ -1,5 +1,5 @@ diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c -index 24f3986..c28425f 100644 +index 24f3986cfae2..c28425f57a81 100644 --- a/e1000/e1000_main.c +++ b/e1000/e1000_main.c @@ -200,6 +200,10 @@ static const struct pci_error_handlers e1000_err_handler = { diff --git a/LINUX/final-patches/vanilla--e1000e--20620--30100 b/LINUX/final-patches/vanilla--e1000e--20620--30100 index 85fb9c8e4..947e1a4ed 100644 --- a/LINUX/final-patches/vanilla--e1000e--20620--30100 +++ b/LINUX/final-patches/vanilla--e1000e--20620--30100 @@ -1,5 +1,5 @@ diff --git a/e1000e/netdev.c b/e1000e/netdev.c -index fad8f9e..cd4abfd 100644 +index fad8f9ea0043..cd4abfdb51c4 100644 --- a/e1000e/netdev.c +++ b/e1000e/netdev.c @@ -87,6 +87,10 @@ static int e1000_desc_unused(struct e1000_ring *ring) diff --git a/LINUX/final-patches/vanilla--e1000e--30100--30400 b/LINUX/final-patches/vanilla--e1000e--30100--30400 index 7163c8fbf..dbf41231c 100644 --- a/LINUX/final-patches/vanilla--e1000e--30100--30400 +++ b/LINUX/final-patches/vanilla--e1000e--30100--30400 @@ -1,5 +1,5 @@ diff --git a/e1000e/netdev.c b/e1000e/netdev.c -index 2198e61..588f1ec 100644 +index 2198e615f241..588f1ecdcb1d 100644 --- a/e1000e/netdev.c +++ b/e1000e/netdev.c @@ -452,6 +452,10 @@ static int e1000_desc_unused(struct e1000_ring *ring) diff --git a/LINUX/final-patches/vanilla--e1000e--30400--30900 b/LINUX/final-patches/vanilla--e1000e--30400--30900 index 8c8534cf5..9936324a8 100644 --- a/LINUX/final-patches/vanilla--e1000e--30400--30900 +++ b/LINUX/final-patches/vanilla--e1000e--30400--30900 @@ -1,5 +1,5 @@ diff --git a/e1000e/netdev.c b/e1000e/netdev.c -index 9520a6a..bf94805 100644 +index 9520a6ac1f30..bf94805911f9 100644 --- a/e1000e/netdev.c +++ b/e1000e/netdev.c @@ -467,6 +467,10 @@ static int e1000_desc_unused(struct e1000_ring *ring) diff --git a/LINUX/final-patches/vanilla--e1000e--30900--99999 b/LINUX/final-patches/vanilla--e1000e--30900--99999 index 742729b4f..c20b7abe9 100644 --- a/LINUX/final-patches/vanilla--e1000e--30900--99999 +++ b/LINUX/final-patches/vanilla--e1000e--30900--99999 @@ -1,5 +1,5 @@ diff --git a/e1000e/netdev.c b/e1000e/netdev.c -index 7e615e2..32ce408 100644 +index 7e615e2bf7e6..32ce408f6b77 100644 --- a/e1000e/netdev.c +++ b/e1000e/netdev.c @@ -473,6 +473,10 @@ static int e1000_desc_unused(struct e1000_ring *ring) diff --git a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 b/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 index e9723a2aa..4eb888276 100644 --- a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 +++ b/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 @@ -1,5 +1,5 @@ diff --git a/forcedeth.c b/forcedeth.c -index 9c0b1ba..b081d6b 100644 +index 9c0b1bac6af6..b081d6ba11a2 100644 --- a/forcedeth.c +++ b/forcedeth.c @@ -1865,12 +1865,25 @@ static void nv_init_tx(struct net_device *dev) diff --git a/LINUX/final-patches/vanilla--i40e--30c00--40100 b/LINUX/final-patches/vanilla--i40e--30c00--40100 index 9e3b301de..2d28f6fe9 100644 --- a/LINUX/final-patches/vanilla--i40e--30c00--40100 +++ b/LINUX/final-patches/vanilla--i40e--30c00--40100 @@ -1,5 +1,5 @@ diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c -index 221aa47..4e61898 100644 +index 221aa4795017..4e61898c06ab 100644 --- a/i40e/i40e_main.c +++ b/i40e/i40e_main.c @@ -86,6 +86,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); @@ -62,7 +62,7 @@ index 221aa47..4e61898 100644 err_rings: diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c -index 49d2cfa..83f3c56 100644 +index 49d2cfa9b0cc..83f3c560887a 100644 --- a/i40e/i40e_txrx.c +++ b/i40e/i40e_txrx.c @@ -27,6 +27,10 @@ diff --git a/LINUX/final-patches/vanilla--i40e--40100--40300 b/LINUX/final-patches/vanilla--i40e--40100--40300 index 048bcfc69..f01b14737 100644 --- a/LINUX/final-patches/vanilla--i40e--40100--40300 +++ b/LINUX/final-patches/vanilla--i40e--40100--40300 @@ -1,5 +1,5 @@ diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c -index 5b5bea1..c8a32923 100644 +index 5b5bea159bd5..c8a329231fcf 100644 --- a/i40e/i40e_main.c +++ b/i40e/i40e_main.c @@ -91,6 +91,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); @@ -62,7 +62,7 @@ index 5b5bea1..c8a32923 100644 err_rings: diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c -index 9d95042d..80f8a88 100644 +index 9d95042d5a0f..80f8a88a3ae8 100644 --- a/i40e/i40e_txrx.c +++ b/i40e/i40e_txrx.c @@ -29,6 +29,10 @@ diff --git a/LINUX/final-patches/vanilla--i40e--40300--40400 b/LINUX/final-patches/vanilla--i40e--40300--40400 index 153fcc710..27fc6ca1b 100644 --- a/LINUX/final-patches/vanilla--i40e--40300--40400 +++ b/LINUX/final-patches/vanilla--i40e--40300--40400 @@ -1,5 +1,5 @@ diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c -index 3dd26cd..05b8960 100644 +index 3dd26cdd0bf2..05b896037ee4 100644 --- a/i40e/i40e_main.c +++ b/i40e/i40e_main.c @@ -94,6 +94,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); @@ -63,7 +63,7 @@ index 3dd26cd..05b8960 100644 err_rings: diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c -index 738aca6..77e14b3 100644 +index 738aca68f665..77e14b3828d7 100644 --- a/i40e/i40e_txrx.c +++ b/i40e/i40e_txrx.c @@ -29,6 +29,10 @@ diff --git a/LINUX/final-patches/vanilla--i40e--40400--40700 b/LINUX/final-patches/vanilla--i40e--40400--40700 index e8669c0f4..62ecf0dd3 100644 --- a/LINUX/final-patches/vanilla--i40e--40400--40700 +++ b/LINUX/final-patches/vanilla--i40e--40400--40700 @@ -1,5 +1,5 @@ diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c -index 4a9873ec..2803d11 100644 +index 4a9873ec28c7..2803d1142f17 100644 --- a/i40e/i40e_main.c +++ b/i40e/i40e_main.c @@ -97,6 +97,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); @@ -63,7 +63,7 @@ index 4a9873ec..2803d11 100644 err_rings: diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c -index 635b3ac..baed465 100644 +index 635b3ac17877..baed465e8b35 100644 --- a/i40e/i40e_txrx.c +++ b/i40e/i40e_txrx.c @@ -29,6 +29,10 @@ diff --git a/LINUX/final-patches/vanilla--i40e--40700--99999 b/LINUX/final-patches/vanilla--i40e--40700--99999 index 912df8274..a3b01f104 100644 --- a/LINUX/final-patches/vanilla--i40e--40700--99999 +++ b/LINUX/final-patches/vanilla--i40e--40700--99999 @@ -1,5 +1,5 @@ diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c -index 501f15d..df24012 100644 +index 501f15d9f4d6..df240129be69 100644 --- a/i40e/i40e_main.c +++ b/i40e/i40e_main.c @@ -110,6 +110,10 @@ MODULE_LICENSE("GPL"); @@ -62,7 +62,7 @@ index 501f15d..df24012 100644 err_rings: diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c -index a8868e1..9186a17 100644 +index a8868e1bf832..9186a17975b8 100644 --- a/i40e/i40e_txrx.c +++ b/i40e/i40e_txrx.c @@ -29,6 +29,10 @@ diff --git a/LINUX/final-patches/vanilla--igb--20621--20623 b/LINUX/final-patches/vanilla--igb--20621--20623 index 470149b91..22476d6f2 100644 --- a/LINUX/final-patches/vanilla--igb--20621--20623 +++ b/LINUX/final-patches/vanilla--igb--20621--20623 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index c881347..a2af379 100644 +index c881347cb26d..a2af3799f5a8 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -226,6 +226,10 @@ char *igb_get_hw_dev_name(struct e1000_hw *hw) diff --git a/LINUX/final-patches/vanilla--igb--20623--30200 b/LINUX/final-patches/vanilla--igb--20623--30200 index 7708b0fff..a258b2391 100644 --- a/LINUX/final-patches/vanilla--igb--20623--30200 +++ b/LINUX/final-patches/vanilla--igb--20623--30200 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index cea37e0..81fd28b 100644 +index cea37e0837ff..81fd28b8cb4e 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -201,6 +201,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); diff --git a/LINUX/final-patches/vanilla--igb--30200--30800 b/LINUX/final-patches/vanilla--igb--30200--30800 index 4043728f5..9ae06fa01 100644 --- a/LINUX/final-patches/vanilla--igb--30200--30800 +++ b/LINUX/final-patches/vanilla--igb--30200--30800 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index ced5444..43c2419 100644 +index ced544499f1b..43c2419cd340 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -225,6 +225,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); diff --git a/LINUX/final-patches/vanilla--igb--30800--30f00 b/LINUX/final-patches/vanilla--igb--30800--30f00 index 1e3643441..1eaa64b3c 100644 --- a/LINUX/final-patches/vanilla--igb--30800--30f00 +++ b/LINUX/final-patches/vanilla--igb--30800--30f00 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index 31cfe2e..2776ed4 100644 +index 31cfe2ec75df..2776ed444bf4 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -247,6 +247,10 @@ static int debug = -1; diff --git a/LINUX/final-patches/vanilla--igb--30f00--40100 b/LINUX/final-patches/vanilla--igb--30f00--40100 index 8f7a2004a..81138684a 100644 --- a/LINUX/final-patches/vanilla--igb--30f00--40100 +++ b/LINUX/final-patches/vanilla--igb--30f00--40100 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index 16430a8..c2c4622 100644 +index 16430a8440fa..c2c462218ec3 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -257,6 +257,10 @@ static int debug = -1; diff --git a/LINUX/final-patches/vanilla--igb--40100--40400 b/LINUX/final-patches/vanilla--igb--40100--40400 index dfee4bdf4..00a867770 100644 --- a/LINUX/final-patches/vanilla--igb--40100--40400 +++ b/LINUX/final-patches/vanilla--igb--40100--40400 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index a0a9b1f..85be1eb 100644 +index a0a9b1fcb5e8..85be1ebd02ab 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -251,6 +251,10 @@ static int debug = -1; diff --git a/LINUX/final-patches/vanilla--igb--40400--99999 b/LINUX/final-patches/vanilla--igb--40400--99999 index f73685ad5..5d5ea3430 100644 --- a/LINUX/final-patches/vanilla--igb--40400--99999 +++ b/LINUX/final-patches/vanilla--igb--40400--99999 @@ -1,5 +1,5 @@ diff --git a/igb/igb_main.c b/igb/igb_main.c -index ea7b098..ddb376e 100644 +index ea7b09887245..ddb376efc198 100644 --- a/igb/igb_main.c +++ b/igb/igb_main.c @@ -253,6 +253,10 @@ static int debug = -1; diff --git a/LINUX/final-patches/vanilla--ixgbe--20620--20622 b/LINUX/final-patches/vanilla--ixgbe--20620--20622 index 6245f0b5f..2dde2dca8 100644 --- a/LINUX/final-patches/vanilla--ixgbe--20620--20622 +++ b/LINUX/final-patches/vanilla--ixgbe--20620--20622 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index a456578..a14c3e0 100644 +index a456578b8578..a14c3e048f07 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -337,6 +337,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, diff --git a/LINUX/final-patches/vanilla--ixgbe--20622--20623 b/LINUX/final-patches/vanilla--ixgbe--20622--20623 index b8da63001..4c4bed7b9 100644 --- a/LINUX/final-patches/vanilla--ixgbe--20622--20623 +++ b/LINUX/final-patches/vanilla--ixgbe--20622--20623 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 6c00ee4..f14b8b8 100644 +index 6c00ee493a3b..f14b8b8259a4 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -400,6 +400,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, diff --git a/LINUX/final-patches/vanilla--ixgbe--20623--20625 b/LINUX/final-patches/vanilla--ixgbe--20623--20625 index 82b14fa39..5cfb5869d 100644 --- a/LINUX/final-patches/vanilla--ixgbe--20623--20625 +++ b/LINUX/final-patches/vanilla--ixgbe--20623--20625 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 74d9b6d..db08827 100644 +index 74d9b6df3029..db08827fb443 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--20625--20626 b/LINUX/final-patches/vanilla--ixgbe--20625--20626 index 662c8615a..3aaf231af 100644 --- a/LINUX/final-patches/vanilla--ixgbe--20625--20626 +++ b/LINUX/final-patches/vanilla--ixgbe--20625--20626 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index eee0b29..cbaf599 100644 +index eee0b298bd36..cbaf5999579d 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--20626--30100 b/LINUX/final-patches/vanilla--ixgbe--20626--30100 index a9262c9ed..4713f5aed 100644 --- a/LINUX/final-patches/vanilla--ixgbe--20626--30100 +++ b/LINUX/final-patches/vanilla--ixgbe--20626--30100 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 30f9ccf..12a830c 100644 +index 30f9ccfb4f87..12a830cb307f 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -221,6 +221,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30100--30200 b/LINUX/final-patches/vanilla--ixgbe--30100--30200 index 8c5ce9f46..70bab4192 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30100--30200 +++ b/LINUX/final-patches/vanilla--ixgbe--30100--30200 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index e1fcc95..2d2dfb9 100644 +index e1fcc9589278..2d2dfb932f9d 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -249,6 +249,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30200--30400 b/LINUX/final-patches/vanilla--ixgbe--30200--30400 index 71a34caef..8475092dc 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30200--30400 +++ b/LINUX/final-patches/vanilla--ixgbe--30200--30400 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 8ef92d1..342f0d3 100644 +index 8ef92d1a6aa1..342f0d33d259 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -188,6 +188,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30400--30500 b/LINUX/final-patches/vanilla--ixgbe--30400--30500 index c2cfb9b2b..389f5b069 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30400--30500 +++ b/LINUX/final-patches/vanilla--ixgbe--30400--30500 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 467948e9..6ab3fb5 100644 +index 467948e9ecd9..6ab3fb525641 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30500--30700 b/LINUX/final-patches/vanilla--ixgbe--30500--30700 index 78c8bf0c9..bd3168fd3 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30500--30700 +++ b/LINUX/final-patches/vanilla--ixgbe--30500--30700 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index e242104..eab0e89 100644 +index e242104ab471..eab0e8928662 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30700--30a00 b/LINUX/final-patches/vanilla--ixgbe--30700--30a00 index 8fb08b834..9365f5a72 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30700--30a00 +++ b/LINUX/final-patches/vanilla--ixgbe--30700--30a00 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index fa3d552..8de2ce7 100644 +index fa3d552e1f4a..8de2ce7e652d 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -205,6 +205,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 index c7a5bedf6..858adec65 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 +++ b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index d30fbdd..0b4f668 100644 +index d30fbdd81fca..0b4f66839b1e 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -248,6 +248,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 index 02824dea4..5f9bd64b2 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 +++ b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 5bcc870..1d71e2a 100644 +index 5bcc870f8367..1d71e2a9d4d5 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--30f00--31300 b/LINUX/final-patches/vanilla--ixgbe--30f00--31300 index 16484392e..1487e7fb8 100644 --- a/LINUX/final-patches/vanilla--ixgbe--30f00--31300 +++ b/LINUX/final-patches/vanilla--ixgbe--30f00--31300 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index d62e7a2..b413a71 100644 +index d62e7a25cf97..b413a71d799c 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -417,6 +417,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--31300--40900 b/LINUX/final-patches/vanilla--ixgbe--31300--40900 index 45fdf7aae..fb675aec2 100644 --- a/LINUX/final-patches/vanilla--ixgbe--31300--40900 +++ b/LINUX/final-patches/vanilla--ixgbe--31300--40900 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index 67b02bd..ddc67ff 100644 +index 67b02bde179e..ddc67ff5a63e 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbe--40900--99999 b/LINUX/final-patches/vanilla--ixgbe--40900--99999 index 6704bf5d5..f7c9cd011 100644 --- a/LINUX/final-patches/vanilla--ixgbe--40900--99999 +++ b/LINUX/final-patches/vanilla--ixgbe--40900--99999 @@ -1,5 +1,5 @@ diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c -index fee1f2918..dcf36a3 100644 +index fee1f2918ead..dcf36a33f3c7 100644 --- a/ixgbe/ixgbe_main.c +++ b/ixgbe/ixgbe_main.c @@ -497,6 +497,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = { diff --git a/LINUX/final-patches/vanilla--ixgbevf--20622--30500 b/LINUX/final-patches/vanilla--ixgbevf--30200--30500 similarity index 84% rename from LINUX/final-patches/vanilla--ixgbevf--20622--30500 rename to LINUX/final-patches/vanilla--ixgbevf--30200--30500 index 8ecad6fdd..15822950e 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--20622--30500 +++ b/LINUX/final-patches/vanilla--ixgbevf--30200--30500 @@ -1,8 +1,8 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 0cd6202..8e59446 100644 +index 4c8e19951d57..7a6d084c0aff 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c -@@ -209,6 +209,24 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter, +@@ -180,6 +180,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter, static void ixgbevf_tx_timeout(struct net_device *netdev); @@ -27,7 +27,7 @@ index 0cd6202..8e59446 100644 /** * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure -@@ -224,6 +242,20 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter, +@@ -195,6 +213,20 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter, unsigned int i, eop, count = 0; unsigned int total_bytes = 0, total_packets = 0; @@ -48,7 +48,7 @@ index 0cd6202..8e59446 100644 i = tx_ring->next_to_clean; eop = tx_ring->tx_buffer_info[i].next_to_watch; eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); -@@ -507,6 +539,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, +@@ -465,6 +497,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, int cleaned_count = 0; unsigned int total_rx_bytes = 0, total_rx_packets = 0; @@ -65,7 +65,7 @@ index 0cd6202..8e59446 100644 i = rx_ring->next_to_clean; rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); staterr = le32_to_cpu(rx_desc->wb.upper.status_error); -@@ -1289,6 +1331,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter, +@@ -1261,6 +1303,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter, } /** @@ -74,7 +74,7 @@ index 0cd6202..8e59446 100644 * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset * @adapter: board private structure * -@@ -1319,6 +1363,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) +@@ -1291,6 +1335,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) */ txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; @@ -84,7 +84,7 @@ index 0cd6202..8e59446 100644 IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); } } -@@ -1582,6 +1629,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) +@@ -1524,6 +1571,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) ixgbevf_configure_rx(adapter); for (i = 0; i < adapter->num_rx_queues; i++) { struct ixgbevf_ring *ring = &adapter->rx_ring[i]; @@ -94,8 +94,8 @@ index 0cd6202..8e59446 100644 ixgbevf_alloc_rx_buffers(adapter, ring, ring->count); ring->next_to_use = ring->count - 1; writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail); -@@ -3485,6 +3535,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, - hw_dbg(hw, "LRO is disabled \n"); +@@ -3460,6 +3510,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + hw_dbg(hw, "LRO is disabled\n"); hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); + @@ -106,7 +106,7 @@ index 0cd6202..8e59446 100644 cards_found++; return 0; -@@ -3516,6 +3571,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) +@@ -3491,6 +3546,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbevf_adapter *adapter = netdev_priv(netdev); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 b/LINUX/final-patches/vanilla--ixgbevf--30500--30600 index 057e9b5f7..4773cfd6d 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 +++ b/LINUX/final-patches/vanilla--ixgbevf--30500--30600 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 41e3225..487ea85 100644 +index 41e32257a4e8..487ea8562d7e 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -186,6 +186,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter, diff --git a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 b/LINUX/final-patches/vanilla--ixgbevf--30600--30700 index 7cadf029f..b44318194 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 +++ b/LINUX/final-patches/vanilla--ixgbevf--30600--30700 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 60ef645..6594f9e 100644 +index 60ef64587412..6594f9ec0a4a 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 index acf84d794..f44136526 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 +++ b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index de1ad50..b0079d7 100644 +index de1ad506665d..b0079d74c050 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 index da625d5b0..aea9f7489 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 +++ b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 92ef4cb..f9818b2 100644 +index 92ef4cb5a8e8..f9818b2403c4 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 index 2c5f90a29..772eaf8c9 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 +++ b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 9df2898..f29d0f6 100644 +index 9df28985eba7..f29d0f651271 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -175,6 +175,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 index cd3dc1446..da01a1f14 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 +++ b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index d0799e8..e8037a4 100644 +index d0799e8e31e4..e8037a4c0441 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 b/LINUX/final-patches/vanilla--ixgbevf--31200--31300 index 68d8394f4..8c0fc3a2e 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 +++ b/LINUX/final-patches/vanilla--ixgbevf--31200--31300 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 030a219..b1cefd7 100644 +index 030a219c85e3..b1cefd751648 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 b/LINUX/final-patches/vanilla--ixgbevf--31300--40000 index 81cf84e97..7d96790a2 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 +++ b/LINUX/final-patches/vanilla--ixgbevf--31300--40000 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 38c7a0b..a533005 100644 +index 38c7a0be8197..a53300522c16 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -208,6 +208,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, diff --git a/LINUX/final-patches/vanilla--ixgbevf--40000--40900 b/LINUX/final-patches/vanilla--ixgbevf--40000--40900 index 659b3dea5..b3e4ae7e2 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--40000--40900 +++ b/LINUX/final-patches/vanilla--ixgbevf--40000--40900 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 4186981..5bdcba7 100644 +index 4186981e562d..5bdcba71c944 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -283,6 +283,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--40b00 b/LINUX/final-patches/vanilla--ixgbevf--40900--99999 similarity index 98% rename from LINUX/final-patches/vanilla--ixgbevf--40900--40b00 rename to LINUX/final-patches/vanilla--ixgbevf--40900--99999 index 4dcb4d137..384a5f546 100644 --- a/LINUX/final-patches/vanilla--ixgbevf--40900--40b00 +++ b/LINUX/final-patches/vanilla--ixgbevf--40900--99999 @@ -1,5 +1,5 @@ diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index cbf70fe..1a006e1 100644 +index cbf70fe4028a..1a006e1c8a5d 100644 --- a/ixgbevf/ixgbevf_main.c +++ b/ixgbevf/ixgbevf_main.c @@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) diff --git a/LINUX/final-patches/vanilla--ixgbevf--40b00--40c00 b/LINUX/final-patches/vanilla--ixgbevf--40b00--40c00 deleted file mode 100644 index 82557a9bc..000000000 --- a/LINUX/final-patches/vanilla--ixgbevf--40b00--40c00 +++ /dev/null @@ -1,109 +0,0 @@ -diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index 80bab26..0aed560 100644 ---- a/ixgbevf/ixgbevf_main.c -+++ b/ixgbevf/ixgbevf_main.c -@@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) - ixgbevf_tx_timeout_reset(adapter); - } - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+/* -+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to -+ * be a reference on how to implement netmap support in a driver. -+ * Additional comments are in ixgbe_netmap_linux.h . -+ * -+ * The code is originally developed on FreeBSD and in the interest -+ * of maintainability we try to limit differences between the two systems. -+ * -+ * contains functions for netmap support -+ * that extend the standard driver. -+ * It also defines DEV_NETMAP so further conditional sections use -+ * that instead of CONFIG_NETMAP -+ */ -+#define NM_IXGBEVF -+#include -+#endif -+ - /** - * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes - * @q_vector: board private structure -@@ -313,6 +331,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, - if (test_bit(__IXGBEVF_DOWN, &adapter->state)) - return true; - -+#ifdef DEV_NETMAP -+ /* -+ * In netmap mode, all the work is done in the context -+ * of the client thread. Interrupt handlers only wake up -+ * clients, which may be sleeping on individual rings -+ * or on a global resource for all rings. -+ */ -+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) -+ return true; -+#endif /* DEV_NETMAP */ -+ -+ - tx_buffer = &tx_ring->tx_buffer_info[i]; - tx_desc = IXGBEVF_TX_DESC(tx_ring, i); - i -= tx_ring->count; -@@ -919,6 +949,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, - u16 cleaned_count = ixgbevf_desc_unused(rx_ring); - struct sk_buff *skb = rx_ring->skb; - -+#ifdef DEV_NETMAP -+ /* -+ * Same as the txeof routine: only wakeup clients on intr. -+ */ -+ int dummy, nm_irq; -+ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); -+ if (nm_irq != NM_IRQ_PASS) -+ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; -+#endif /* DEV_NETMAP */ -+ - while (likely(total_rx_packets < budget)) { - union ixgbe_adv_rx_desc *rx_desc; - -@@ -1555,6 +1595,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, - - clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state); - -+#ifdef DEV_NETMAP -+ txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl); -+#endif /* DEV_NETMAP */ -+ - IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl); - - /* poll to verify queue is enabled */ -@@ -1742,6 +1786,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, - IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); - - ixgbevf_rx_desc_queue_enable(adapter, ring); -+#ifdef DEV_NETMAP -+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) -+ return; -+#endif /* DEV_NETMAP */ - ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); - } - -@@ -4120,6 +4168,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) - break; - } - -+#ifdef DEV_NETMAP -+ ixgbe_netmap_attach(adapter); -+#endif /* DEV_NETMAP */ -+ - return 0; - - err_register: -@@ -4157,6 +4209,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) - if (!netdev) - return; - -+#ifdef DEV_NETMAP -+ netmap_detach(netdev); -+#endif /* DEV_NETMAP */ -+ - adapter = netdev_priv(netdev); - - set_bit(__IXGBEVF_REMOVING, &adapter->state); diff --git a/LINUX/final-patches/vanilla--ixgbevf--40c00--99999 b/LINUX/final-patches/vanilla--ixgbevf--40c00--99999 deleted file mode 100644 index 8c0c4eac9..000000000 --- a/LINUX/final-patches/vanilla--ixgbevf--40c00--99999 +++ /dev/null @@ -1,118 +0,0 @@ -diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c -index eee29bd..54102fd 100644 ---- a/ixgbevf/ixgbevf_main.c -+++ b/ixgbevf/ixgbevf_main.c -@@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) - ixgbevf_tx_timeout_reset(adapter); - } - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+/* -+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to -+ * be a reference on how to implement netmap support in a driver. -+ * Additional comments are in ixgbe_netmap_linux.h . -+ * -+ * The code is originally developed on FreeBSD and in the interest -+ * of maintainability we try to limit differences between the two systems. -+ * -+ * contains functions for netmap support -+ * that extend the standard driver. -+ * It also defines DEV_NETMAP so further conditional sections use -+ * that instead of CONFIG_NETMAP -+ */ -+#define NM_IXGBEVF -+#include -+#endif -+ - /** - * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes - * @q_vector: board private structure -@@ -313,6 +331,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, - if (test_bit(__IXGBEVF_DOWN, &adapter->state)) - return true; - -+#ifdef DEV_NETMAP -+ /* -+ * In netmap mode, all the work is done in the context -+ * of the client thread. Interrupt handlers only wake up -+ * clients, which may be sleeping on individual rings -+ * or on a global resource for all rings. -+ */ -+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) -+ return true; -+#endif /* DEV_NETMAP */ -+ -+ - tx_buffer = &tx_ring->tx_buffer_info[i]; - tx_desc = IXGBEVF_TX_DESC(tx_ring, i); - i -= tx_ring->count; -@@ -919,6 +949,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, - u16 cleaned_count = ixgbevf_desc_unused(rx_ring); - struct sk_buff *skb = rx_ring->skb; - -+#ifdef DEV_NETMAP -+ /* -+ * Same as the txeof routine: only wakeup clients on intr. -+ */ -+ int dummy, nm_irq; -+ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); -+ if (nm_irq != NM_IRQ_PASS) -+ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; -+#endif /* DEV_NETMAP */ -+ - while (likely(total_rx_packets < budget)) { - union ixgbe_adv_rx_desc *rx_desc; - -@@ -1555,6 +1595,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, - - clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state); - -+#ifdef DEV_NETMAP -+ txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl); -+#endif /* DEV_NETMAP */ -+ - IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl); - - /* poll to verify queue is enabled */ -@@ -1563,7 +1607,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, - txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(reg_idx)); - } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); - if (!wait_loop) -- hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx); -+ pr_err("Could not enable Tx Queue %d\n", reg_idx); - } - - /** -@@ -1763,6 +1807,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, - IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); - - ixgbevf_rx_desc_queue_enable(adapter, ring); -+#ifdef DEV_NETMAP -+ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) -+ return; -+#endif /* DEV_NETMAP */ - ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); - } - -@@ -4147,6 +4195,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) - break; - } - -+#ifdef DEV_NETMAP -+ ixgbe_netmap_attach(adapter); -+#endif /* DEV_NETMAP */ -+ - return 0; - - err_register: -@@ -4185,6 +4237,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) - if (!netdev) - return; - -+#ifdef DEV_NETMAP -+ netmap_detach(netdev); -+#endif /* DEV_NETMAP */ -+ - adapter = netdev_priv(netdev); - - set_bit(__IXGBEVF_REMOVING, &adapter->state); diff --git a/LINUX/final-patches/vanilla--r8169.c--20620--20625 b/LINUX/final-patches/vanilla--r8169.c--20620--20625 index d4a8f3781..20b7a6018 100644 --- a/LINUX/final-patches/vanilla--r8169.c--20620--20625 +++ b/LINUX/final-patches/vanilla--r8169.c--20620--20625 @@ -1,5 +1,5 @@ diff --git a/r8169.c b/r8169.c -index 0fe2fc9..5d363e5 100644 +index 0fe2fc90f207..5d363e589803 100644 --- a/r8169.c +++ b/r8169.c @@ -537,6 +537,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget); diff --git a/LINUX/final-patches/vanilla--r8169.c--20625--20626 b/LINUX/final-patches/vanilla--r8169.c--20625--20626 index fe419354f..e5cf077e7 100644 --- a/LINUX/final-patches/vanilla--r8169.c--20625--20626 +++ b/LINUX/final-patches/vanilla--r8169.c--20625--20626 @@ -1,5 +1,5 @@ diff --git a/r8169.c b/r8169.c -index 53b13de..ced4849 100644 +index 53b13deade95..ced4849577f0 100644 --- a/r8169.c +++ b/r8169.c @@ -535,6 +535,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget); diff --git a/LINUX/final-patches/vanilla--r8169.c--20626--30400 b/LINUX/final-patches/vanilla--r8169.c--20626--30400 index 5e6d6473a..a1b9eb6f6 100644 --- a/LINUX/final-patches/vanilla--r8169.c--20626--30400 +++ b/LINUX/final-patches/vanilla--r8169.c--20626--30400 @@ -1,5 +1,5 @@ diff --git a/r8169.c b/r8169.c -index 7ffdb80..fc92723 100644 +index 7ffdb80adf40..fc9272305d02 100644 --- a/r8169.c +++ b/r8169.c @@ -590,6 +590,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget); diff --git a/LINUX/final-patches/vanilla--veth.c--20620--30900 b/LINUX/final-patches/vanilla--veth.c--20620--30900 index fffae7d65..c63d70bf1 100644 --- a/LINUX/final-patches/vanilla--veth.c--20620--30900 +++ b/LINUX/final-patches/vanilla--veth.c--20620--30900 @@ -1,5 +1,5 @@ diff --git a/veth.c b/veth.c -index 52af501..a416e43 100644 +index 52af5017c46b..a416e437bebf 100644 --- a/veth.c +++ b/veth.c @@ -38,6 +38,10 @@ struct veth_priv { diff --git a/LINUX/final-patches/vanilla--veth.c--30900--30f00 b/LINUX/final-patches/vanilla--veth.c--30900--30f00 index e2ca5b885..04f5b4e43 100644 --- a/LINUX/final-patches/vanilla--veth.c--30900--30f00 +++ b/LINUX/final-patches/vanilla--veth.c--30900--30f00 @@ -1,5 +1,5 @@ diff --git a/veth.c b/veth.c -index 07a4af0..672375e 100644 +index 07a4af0aa3dc..672375e5c5c8 100644 --- a/veth.c +++ b/veth.c @@ -36,6 +36,10 @@ struct veth_priv { diff --git a/LINUX/final-patches/vanilla--veth.c--30f00--99999 b/LINUX/final-patches/vanilla--veth.c--30f00--99999 index 0e17d9ca0..9d0b49ad7 100644 --- a/LINUX/final-patches/vanilla--veth.c--30f00--99999 +++ b/LINUX/final-patches/vanilla--veth.c--30f00--99999 @@ -1,5 +1,5 @@ diff --git a/veth.c b/veth.c -index b4a10bc..52b7c37 100644 +index b4a10bcb66a0..52b7c371f06b 100644 --- a/veth.c +++ b/veth.c @@ -37,6 +37,10 @@ struct veth_priv { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 index 775493f38..342b63b0b 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 +++ b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index b0577dd..0c873c4 100644 +index b0577dd1a42d..0c873c4ae173 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -64,6 +64,10 @@ struct virtnet_info diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 index 2e013c912..8edbcc909 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 +++ b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index b6d4028..60bb2b2 100644 +index b6d402806ae6..60bb2b2cc257 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -67,6 +67,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 index 03ad70378..d6a60b6db 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 +++ b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 82dba5a..06324f8 100644 +index 82dba5aaf423..06324f8b2593 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -67,6 +67,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 index deba61c7e..7f5e9463b 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 +++ b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 4880aa8..64e3625 100644 +index 4880aa8b4c28..64e3625b1750 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -80,6 +80,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 index 91c23fba3..51dbf469e 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 +++ b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index f18149a..cc935cf 100644 +index f18149ae2588..cc935cfce8b2 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -90,6 +90,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 b/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 index 4bec12874..b75bfeb91 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 +++ b/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 35c00c5..bfbb178 100644 +index 35c00c5ea02a..bfbb1787ec55 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -132,6 +132,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 index 06d6ee96a..29a0d5966 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 +++ b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 3d2a90a..2365434 100644 +index 3d2a90a62649..23654348b613 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -131,6 +131,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 index 9f1b59fc6..09db3f340 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 +++ b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 59caa06..b64cb15 100644 +index 59caa06f34a6..b64cb151db9f 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -145,6 +145,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 index a703e7170..bc49240cf 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 +++ b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 059fdf1..d79cd6a 100644 +index 059fdf1bf5ee..d79cd6a386e0 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -142,6 +142,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 index e83d330fa..3e453fd44 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 +++ b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 63c7810..f5fc43c 100644 +index 63c7810e1545..f5fc43c34afa 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -142,6 +142,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 index 437566ac0..e852dffa3 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 +++ b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index cbf1c61..be4daab 100644 +index cbf1c613c67a..be4daabbc51b 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -155,6 +155,10 @@ struct virtnet_info { diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 index 8ebf13e41..b254abd9b 100644 --- a/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 +++ b/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 @@ -1,5 +1,5 @@ diff --git a/virtio_net.c b/virtio_net.c -index 143d8a9..27de2c2 100644 +index 143d8a95a60d..27de2c282e08 100644 --- a/virtio_net.c +++ b/virtio_net.c @@ -170,6 +170,10 @@ struct virtnet_info { From d4ce22ebc39737e839411a7000aa628d11bac01e Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 4 Sep 2017 20:35:50 +0200 Subject: [PATCH 0006/2207] linux/i40e: Intel 2.1.26 version --- LINUX/configure | 1 + LINUX/default-config.mak.in_ | 2 +- LINUX/final-patches/intel--i40e--2.1.26 | 154 ++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 LINUX/final-patches/intel--i40e--2.1.26 diff --git a/LINUX/configure b/LINUX/configure index 5d1a53068..9c4b17eea 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1660,6 +1660,7 @@ EOF add_test 'define I40E_PTR_STATE' < + #pragma GCC diagnostic error "-Wincompatible-pointer-types" int dummy(struct i40e_pf *pf) { diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index cdde8e010..c2255753a 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -17,4 +17,4 @@ e1000e@cflags := -fno-pie $(call enabled_intel_driver,e1000e,3.3.5.3) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(call enabled_intel_driver,igb,5.3.5.4) -$(call enabled_intel_driver,i40e,2.0.30) +$(call enabled_intel_driver,i40e,2.1.26) diff --git a/LINUX/final-patches/intel--i40e--2.1.26 b/LINUX/final-patches/intel--i40e--2.1.26 new file mode 100644 index 000000000..233f25275 --- /dev/null +++ b/LINUX/final-patches/intel--i40e--2.1.26 @@ -0,0 +1,154 @@ +diff --git a/i40e/Makefile b/src/Makefile +index f653b71..c356d02 100644 +--- a/i40e/Makefile ++++ b/i40e/Makefile +@@ -30,9 +30,9 @@ ifneq ($(KERNELRELEASE),) + ccflags-y += -I$(src) + subdir-ccflags-y += -I$(src) + +-obj-$(CONFIG_I40E) += i40e.o ++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o + +-i40e-y := i40e_main.o \ ++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \ + i40e_ethtool.o \ + i40e_adminq.o \ + i40e_common.o \ +@@ -46,13 +46,13 @@ i40e-y := i40e_main.o \ + i40e_client.o \ + i40e_virtchnl_pf.o + +-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o +-i40e-y += kcompat.o ++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o ++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := i40e ++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -92,9 +92,12 @@ ccc: clean + @+$(call kernelbuild,modules,coccicheck MODE=report) + + # Build manfiles +-manfile: ++manfile: ../${DRIVER}.${MANSECTION} + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../${DRIVER}.${MANSECTION}: ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call kernelbuild,clean) +diff --git a/i40e/i40e_main.c b/src/i40e_main.c +index 4c70594..32a22ad 100644 +--- a/i40e/i40e_main.c ++++ b/i40e/i40e_main.c +@@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION); + + static struct workqueue_struct *i40e_wq; + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++#define NETMAP_I40E_MAIN ++#include ++#endif ++ + /** + * i40e_get_lump - find a lump of free generic resource + * @pf: board private structure +@@ -3215,6 +3220,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) + /* cache tail off for easier writes later */ + ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q); + ++#ifdef DEV_NETMAP ++ i40e_netmap_configure_tx_ring(ring); ++#endif /* DEV_NETMAP */ ++ + return 0; + } + +@@ -3291,6 +3300,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) + ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q); + writel(0, ring->tail); + ++#ifdef DEV_NETMAP ++ if (i40e_netmap_configure_rx_ring(ring)) ++ return 0; ++#endif /* DEV_NETMAP */ ++ + i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); + + return 0; +@@ -10844,6 +10858,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi) + return -ENODEV; + } + ++#ifdef DEV_NETMAP ++ if (vsi->netdev_registered) ++ netmap_detach(vsi->netdev); ++#endif ++ + uplink_seid = vsi->uplink_seid; + if (vsi->type != I40E_VSI_SRIOV) { + if (vsi->netdev_registered) { +@@ -11212,6 +11231,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, + (vsi->type == I40E_VSI_VMDQ2)) { + ret = i40e_vsi_config_rss(vsi); + } ++ ++#ifdef DEV_NETMAP ++ if (vsi->netdev_registered) ++ i40e_netmap_attach(vsi); ++#endif ++ + return vsi; + + err_rings: +diff --git a/i40e/i40e_txrx.c b/src/i40e_txrx.c +index cbd49a9..7c83c01 100644 +--- a/i40e/i40e_txrx.c ++++ b/i40e/i40e_txrx.c +@@ -26,6 +26,10 @@ + #include "i40e_trace.h" + #include "i40e_prototype.h" + ++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE) ++#include ++#endif /* DEV_NETMAP */ ++ + static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, + u32 td_tag) + { +@@ -729,6 +733,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, + unsigned int total_bytes = 0, total_packets = 0; + unsigned int budget = vsi->work_limit; + ++#ifdef DEV_NETMAP ++ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buf = &tx_ring->tx_bi[i]; + tx_desc = I40E_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -2148,6 +2157,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) + u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); + bool failure = false; + ++#ifdef DEV_NETMAP ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) { ++ return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget; ++ } ++#endif /* DEV_NETMAP */ ++ ++ + while (likely(total_rx_packets < (unsigned int)budget)) { + struct i40e_rx_buffer *rx_buffer; + union i40e_rx_desc *rx_desc; From 4c9d0a71d883d4ba517a7c593c9969aafbd6e513 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 4 Sep 2017 20:54:33 +0200 Subject: [PATCH 0007/2207] linux/ixgbe: Intel 5.2.3 version --- LINUX/default-config.mak.in_ | 2 +- LINUX/final-patches/intel--ixgbe--5.2.3 | 171 ++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 LINUX/final-patches/intel--ixgbe--5.2.3 diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index c2255753a..d60a7390e 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -11,7 +11,7 @@ endef enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2)))) -$(call enabled_intel_driver,ixgbe,5.2.1) +$(call enabled_intel_driver,ixgbe,5.2.3) $(call enabled_intel_driver,ixgbevf,4.2.1) e1000e@cflags := -fno-pie $(call enabled_intel_driver,e1000e,3.3.5.3) diff --git a/LINUX/final-patches/intel--ixgbe--5.2.3 b/LINUX/final-patches/intel--ixgbe--5.2.3 new file mode 100644 index 000000000..5540a0320 --- /dev/null +++ b/LINUX/final-patches/intel--ixgbe--5.2.3 @@ -0,0 +1,171 @@ +diff --git a/ixgbe/Makefile b/src/Makefile +index a3cc895..a038975 100644 +--- a/ixgbe/Makefile ++++ b/ixgbe/Makefile +@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver + # + +-obj-$(CONFIG_IXGBE) += ixgbe.o ++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o + +-define ixgbe-y ++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y + ixgbe_main.o + ixgbe_api.o + ixgbe_common.o +@@ -49,24 +49,24 @@ define ixgbe-y + ixgbe_x540.o + ixgbe_x550.o + endef +-ixgbe-y := $(strip ${ixgbe-y}) ++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y}) + +-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o + +-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o + +-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o + +-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o + +-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o + +-ixgbe-y += kcompat.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := ixgbe ++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -127,9 +127,12 @@ ccc: clean + @+$(call devkernelbuild,modules,coccicheck MODE=report)) + + # Build manfiles +-manfile: ++manfile: ../$(DRIVER).$(MANSECTION) + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../$(DRIVER).$(MANSECTION): ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call devkernelbuild,clean) +diff --git a/ixgbe/ixgbe_main.c b/src/ixgbe_main.c +index 68bead6..ef93357 100644 +--- a/ixgbe/ixgbe_main.c ++++ b/ixgbe/ixgbe_main.c +@@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev); + } + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#include ++#endif ++ + /** + * ixgbe_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: structure containing interrupt and ring information +@@ -771,6 +788,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -2053,6 +2081,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, + #endif /* CONFIG_FCOE */ + u16 cleaned_count = ixgbe_desc_unused(rx_ring); + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + while (likely(total_rx_packets < budget)) { + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *rx_buffer; +@@ -3336,6 +3374,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, + + clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state); + ++#ifdef DEV_NETMAP ++ txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl); ++#endif /* DEV_NETMAP */ ++ + /* enable queue */ + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl); + +@@ -3979,6 +4021,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl); + + ixgbe_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring)); + } + +@@ -11400,6 +11446,10 @@ no_info_string: + hw->mac.ops.setup_eee(hw, eee_enable); + } + ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -11445,6 +11495,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) + return; + + netdev = adapter->netdev; ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + #ifdef HAVE_IXGBE_DEBUG_FS + ixgbe_dbg_adapter_exit(adapter); + From be906bcb7bcd59709c06c0814b9d79f6d04976ed Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 4 Sep 2017 20:56:18 +0200 Subject: [PATCH 0008/2207] linux/e1000e: Intel 3.3.5.10 version --- LINUX/default-config.mak.in_ | 2 +- LINUX/final-patches/intel--e1000e--3.3.5.10 | 110 ++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 LINUX/final-patches/intel--e1000e--3.3.5.10 diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index d60a7390e..78b8216ca 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -14,7 +14,7 @@ enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driv $(call enabled_intel_driver,ixgbe,5.2.3) $(call enabled_intel_driver,ixgbevf,4.2.1) e1000e@cflags := -fno-pie -$(call enabled_intel_driver,e1000e,3.3.5.3) +$(call enabled_intel_driver,e1000e,3.3.5.10) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(call enabled_intel_driver,igb,5.3.5.4) $(call enabled_intel_driver,i40e,2.1.26) diff --git a/LINUX/final-patches/intel--e1000e--3.3.5.10 b/LINUX/final-patches/intel--e1000e--3.3.5.10 new file mode 100644 index 000000000..ea1d58a7b --- /dev/null +++ b/LINUX/final-patches/intel--e1000e--3.3.5.10 @@ -0,0 +1,110 @@ +diff --git a/e1000e/Makefile b/e1000e/Makefile +index c4558ce..b951433 100644 +--- a/e1000e/Makefile ++++ b/e1000e/Makefile +@@ -36,7 +36,7 @@ ifeq (,$(BUILD_KERNEL)) + BUILD_KERNEL=$(shell uname -r) + endif + +-DRIVER_NAME = e1000e ++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX) + + ########################################################################### + # Environment tests +@@ -139,7 +139,7 @@ ifeq ($(ARCH),ppc64) + endif + + # extra flags for module builds +-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]') ++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]') + EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME) + EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]') + # standard flags for module builds +@@ -345,6 +345,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \ + $(MANFILE).gz: ../$(MANFILE) + gzip -c $< > $@ + ++../$(MANFILE): ++ touch $@ ++ + install: default $(MANFILE).gz + # remove all old versions of the driver + find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true +diff --git a/e1000e/netdev.c b/e1000e/netdev.c +index 6018f28..816a77c 100644 +--- a/e1000e/netdev.c ++++ b/e1000e/netdev.c +@@ -499,6 +499,10 @@ static int e1000_desc_unused(struct e1000_ring *ring) + return ring->count + ring->next_to_clean - ring->next_to_use - 1; + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++#include ++#endif ++ + #ifdef HAVE_HW_TIME_STAMP + /** + * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp +@@ -1022,6 +1026,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring) + bool cleaned = false; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++#ifdef CONFIG_E1000E_NAPI ++#define NETMAP_DUMMY work_done ++#else ++ int dummy; ++#define NETMAP_DUMMY &dummy ++#endif ++ if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY)) ++ return true; ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC_EXT(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1333,6 +1348,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring) + unsigned int total_tx_bytes = 0, total_tx_packets = 0; + unsigned int bytes_compl = 0, pkts_compl = 0; + ++#ifdef DEV_NETMAP ++ if (netmap_tx_irq(netdev, 0)) ++ return true; /* cleaned ok */ ++#endif /* DEV_NETMAP */ ++ + i = tx_ring->next_to_clean; + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); +@@ -4225,6 +4245,10 @@ static void e1000_configure(struct e1000_adapter *adapter) + #endif + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); ++#ifdef DEV_NETMAP ++ if (e1000e_netmap_init_buffers(adapter)) ++ return; ++#endif /* DEV_NETMAP */ + adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL); + } + +@@ -8408,6 +8432,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + if (err) + goto err_register; + ++#ifdef DEV_NETMAP ++ e1000_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + +@@ -8509,6 +8537,10 @@ static void e1000_remove(struct pci_dev *pdev) + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + iounmap(adapter->hw.hw_addr); + if ((adapter->hw.flash_address) && + (adapter->hw.mac.type < e1000_pch_spt)) From f63dc502268a0a9a00f05de9ec938cfccdeee55b Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 4 Sep 2017 20:57:31 +0200 Subject: [PATCH 0009/2207] linux/igb: Intel 5.3.5.10 version --- LINUX/default-config.mak.in_ | 2 +- LINUX/final-patches/intel--igb--5.3.5.10 | 135 +++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 LINUX/final-patches/intel--igb--5.3.5.10 diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index 78b8216ca..75037da5f 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -16,5 +16,5 @@ $(call enabled_intel_driver,ixgbevf,4.2.1) e1000e@cflags := -fno-pie $(call enabled_intel_driver,e1000e,3.3.5.10) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie -$(call enabled_intel_driver,igb,5.3.5.4) +$(call enabled_intel_driver,igb,5.3.5.10) $(call enabled_intel_driver,i40e,2.1.26) diff --git a/LINUX/final-patches/intel--igb--5.3.5.10 b/LINUX/final-patches/intel--igb--5.3.5.10 new file mode 100644 index 000000000..d1b9580f4 --- /dev/null +++ b/LINUX/final-patches/intel--igb--5.3.5.10 @@ -0,0 +1,135 @@ +diff --git a/igb/Makefile b/src/Makefile +index e3bd4f3..ef900a4 100644 +--- a/igb/Makefile ++++ b/igb/Makefile +@@ -28,7 +28,7 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) Gigabit Ethernet Linux Driver + # + +-obj-$(CONFIG_IGB) += igb.o ++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o + + define igb-y + igb_main.o +@@ -46,19 +46,19 @@ define igb-y + e1000_82575.o + e1000_i210.o + endef +-igb-y := $(strip ${igb-y}) ++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y}) + +-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o ++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o + +-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o ++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o + + +-igb-y += kcompat.o ++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := igb ++DRIVER := igb$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -115,9 +115,12 @@ ccc: clean + @+$(call devkernelbuild,modules,coccicheck MODE=report)) + + # Build manfiles +-manfile: ++manfile: ../$(DRIVER).$(MANSECTION) + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../$(DRIVER).$(MANSECTION): ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call devkernelbuild,clean) +diff --git a/igb/igb_main.c b/src/igb_main.c +index 3ee1ec7..b6809c6 100644 +--- a/igb/igb_main.c ++++ b/igb/igb_main.c +@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; + module_param(debug, int, 0); + MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)"); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++#include ++#endif ++ + /** + * igb_init_module - Driver Registration Routine + * +@@ -3052,6 +3056,10 @@ static int igb_probe(struct pci_dev *pdev, + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + ++#ifdef DEV_NETMAP ++ igb_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + #ifdef IGB_DCA + if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) { + adapter->flags |= IGB_FLAG_DCA_ENABLED; +@@ -3255,6 +3263,10 @@ static void igb_remove(struct pci_dev *pdev) + */ + igb_release_hw_control(adapter); + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + unregister_netdev(netdev); + + igb_clear_interrupt_scheme(adapter); +@@ -3663,6 +3675,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter, + + txdctl |= E1000_TXDCTL_QUEUE_ENABLE; + E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl); ++#ifdef DEV_NETMAP ++ igb_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -7211,6 +7226,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) + if (test_bit(__IGB_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index)) ++ return true; /* cleaned ok */ ++#endif /* DEV_NETMAP */ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IGB_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -8225,6 +8245,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget) + unsigned int total_bytes = 0, total_packets = 0; + u16 cleaned_count = igb_desc_unused(rx_ring); + ++#ifdef DEV_NETMAP ++ if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets)) ++ return true; ++#endif /* DEV_NETMAP */ ++ + do { + struct igb_rx_buffer *rx_buffer; + union e1000_adv_rx_desc *rx_desc; +@@ -8543,6 +8568,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count) + struct igb_rx_buffer *bi; + u16 i = rx_ring->next_to_use; + ++#ifdef DEV_NETMAP ++ if (igb_netmap_configure_rx_ring(rx_ring)) ++ return; ++#endif /* DEV_NETMAP */ ++ + /* nothing to do */ + if (!cleaned_count) + return; From 4695fe8eaec58bbceab2e3dc7650f24dc6dfd6c4 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 8 Sep 2017 07:28:28 +0200 Subject: [PATCH 0010/2207] pkt-gen: fix compilation problem --- apps/pkt-gen/pkt-gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index b8c63f953..d3cdbd287 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1877,7 +1877,7 @@ txseq_body(void *data) unsigned int space; unsigned int head; int fcnt; - uint16_t sum; + uint16_t sum = 0; if (!rate_limit) { budget = targ->g->burst; From 84898122355ab0ef1b5e6cbf58ecd231df535422 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Sun, 10 Sep 2017 15:12:28 +0200 Subject: [PATCH 0011/2207] linux/ixgbe: Intel 5.2.4 version --- LINUX/final-patches/intel--ixgbe--5.2.4 | 171 ++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 LINUX/final-patches/intel--ixgbe--5.2.4 diff --git a/LINUX/final-patches/intel--ixgbe--5.2.4 b/LINUX/final-patches/intel--ixgbe--5.2.4 new file mode 100644 index 000000000..5c62eecce --- /dev/null +++ b/LINUX/final-patches/intel--ixgbe--5.2.4 @@ -0,0 +1,171 @@ +diff --git a/src/Makefile b/src/Makefile +index a3cc895..a038975 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver + # + +-obj-$(CONFIG_IXGBE) += ixgbe.o ++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o + +-define ixgbe-y ++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y + ixgbe_main.o + ixgbe_api.o + ixgbe_common.o +@@ -49,24 +49,24 @@ define ixgbe-y + ixgbe_x540.o + ixgbe_x550.o + endef +-ixgbe-y := $(strip ${ixgbe-y}) ++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y}) + +-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o + +-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o + +-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o + +-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o + +-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o + +-ixgbe-y += kcompat.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := ixgbe ++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -127,9 +127,12 @@ ccc: clean + @+$(call devkernelbuild,modules,coccicheck MODE=report)) + + # Build manfiles +-manfile: ++manfile: ../$(DRIVER).$(MANSECTION) + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../$(DRIVER).$(MANSECTION): ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call devkernelbuild,clean) +diff --git a/src/ixgbe_main.c b/src/ixgbe_main.c +index c7a1499..f2a3c3e 100644 +--- a/src/ixgbe_main.c ++++ b/src/ixgbe_main.c +@@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev); + } + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#include ++#endif ++ + /** + * ixgbe_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: structure containing interrupt and ring information +@@ -771,6 +788,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -2053,6 +2081,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, + #endif /* CONFIG_FCOE */ + u16 cleaned_count = ixgbe_desc_unused(rx_ring); + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + while (likely(total_rx_packets < budget)) { + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *rx_buffer; +@@ -3336,6 +3374,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, + + clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state); + ++#ifdef DEV_NETMAP ++ txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl); ++#endif /* DEV_NETMAP */ ++ + /* enable queue */ + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl); + +@@ -3979,6 +4021,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl); + + ixgbe_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring)); + } + +@@ -11400,6 +11446,10 @@ no_info_string: + hw->mac.ops.setup_eee(hw, eee_enable); + } + ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -11445,6 +11495,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) + return; + + netdev = adapter->netdev; ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + #ifdef HAVE_IXGBE_DEBUG_FS + ixgbe_dbg_adapter_exit(adapter); + From 6bd27e1f5fa10f5f0f2751df476ab1f62bbaaad0 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Sun, 10 Sep 2017 15:12:47 +0200 Subject: [PATCH 0012/2207] linux/ixgbevf: Intel 4.2.2 version --- LINUX/final-patches/intel--ixgbevf--4.2.2 | 178 ++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 LINUX/final-patches/intel--ixgbevf--4.2.2 diff --git a/LINUX/final-patches/intel--ixgbevf--4.2.2 b/LINUX/final-patches/intel--ixgbevf--4.2.2 new file mode 100644 index 000000000..c59915e20 --- /dev/null +++ b/LINUX/final-patches/intel--ixgbevf--4.2.2 @@ -0,0 +1,178 @@ +diff --git a/src/Makefile b/src/Makefile +index ca79ef6..939f185 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver + # + +-obj-$(CONFIG_IXGBE) += ixgbevf.o ++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o + +-define ixgbevf-y ++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y + ixgbevf_main.o + ixgbevf_ethtool.o + ixgbe_vf.o + ixgbe_mbx.o + endef +-ixgbevf-y := $(strip ${ixgbevf-y}) +-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o +-ixgbevf-y += kcompat.o ++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y}) ++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o ++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := ixgbevf ++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -90,9 +90,12 @@ ccc: clean + @+$(call kernelbuild,modules,coccicheck MODE=report)) + + # Build manfiles +-manfile: ++manfile: ../$(DRIVER).$(MANSECTION) + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../$(DRIVER).$(MANSECTION): ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call kernelbuild,clean) +diff --git a/src/ixgbevf_main.c b/src/ixgbevf_main.c +index c1f7021..d4dd337 100644 +--- a/src/ixgbevf_main.c ++++ b/src/ixgbevf_main.c +@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) + ixgbevf_tx_timeout_reset(adapter); + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif + + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes +@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -1192,6 +1220,17 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + u16 cleaned_count = ixgbevf_desc_unused(rx_ring); + struct sk_buff *skb = rx_ring->skb; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ ++ + do { + union ixgbe_adv_rx_desc *rx_desc; + +@@ -1816,6 +1855,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + + clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state); + ++#ifdef DEV_NETMAP ++ txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl); ++#endif /* DEV_NETMAP */ ++ + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl); + + /* poll to verify queue is enabled */ +@@ -1826,7 +1869,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + if (!wait_loop) + DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx); + } +- ++ + /** + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure +@@ -1997,6 +2040,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -4919,8 +4966,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + if (netdev->features & NETIF_F_GRO) + DPRINTK(PROBE, INFO, "GRO is enabled\n"); + #endif +- + DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ + cards_found++; + return 0; + +@@ -4959,6 +5008,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) + if (!netdev) + return; + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + adapter = netdev_priv(netdev); + + set_bit(__IXGBEVF_REMOVE, &adapter->state); +diff --git a/src/kcompat.h b/src/kcompat.h +index 6b93e54..34d4440 100644 +--- a/src/kcompat.h ++++ b/src/kcompat.h +@@ -25,6 +25,8 @@ + #ifndef _KCOMPAT_H_ + #define _KCOMPAT_H_ + ++#include ++ + #ifndef LINUX_VERSION_CODE + #include + #else From aa128b9877984a6176d51c164f6d4f6eaa1d69da Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sun, 12 Jun 2016 12:21:22 +0200 Subject: [PATCH 0013/2207] linux: emulated adapter: remove redundant generic_ndo --- LINUX/netmap_linux.c | 9 ++++----- sys/dev/netmap/netmap_kern.h | 8 +++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 4db034ab3..07c6de913 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -688,15 +688,14 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept) /* Save a redundant copy of ndo_start_xmit(). */ gna->save_start_xmit = ifp->netdev_ops->ndo_start_xmit; - gna->generic_ndo = *ifp->netdev_ops; /* Copy all */ - gna->generic_ndo.ndo_start_xmit = &generic_ndo_start_xmit; + gna->up.nm_ndo = *ifp->netdev_ops; /* copy all, replace some */ + gna->up.nm_ndo.ndo_start_xmit = &generic_ndo_start_xmit; #ifndef NETMAP_LINUX_SELECT_QUEUE D("No packet steering support"); #else - gna->generic_ndo.ndo_select_queue = &generic_ndo_select_queue; + gna->up.nm_ndo.ndo_select_queue = &generic_ndo_select_queue; #endif - - ifp->netdev_ops = &gna->generic_ndo; + ifp->netdev_ops = &gna->up.nm_ndo; } else { /* Restore the original netdev_ops. */ diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 19a0bdd36..8877284de 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -922,12 +922,10 @@ struct netmap_generic_adapter { /* emulated device */ /* Pointer to a previously used netmap adapter. */ struct netmap_adapter *prev; - /* generic netmap adapters support: - * a net_device_ops struct overrides ndo_select_queue(), - * save_if_input saves the if_input hook (FreeBSD), - * mit implements rx interrupt mitigation, + /* Emulated netmap adapters support: + * - save_if_input saves the if_input hook (FreeBSD); + * - mit implements rx interrupt mitigation; */ - struct net_device_ops generic_ndo; void (*save_if_input)(struct ifnet *, struct mbuf *); struct nm_generic_mit *mit; From a6cf650b2ea3297d0a76cd836fd50f7ed9ec3efd Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 12 Jan 2017 11:47:56 -0500 Subject: [PATCH 0014/2207] lb: Broala name change to Corelight --- apps/lb/lb.8 | 6 +++--- apps/lb/lb.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/lb/lb.8 b/apps/lb/lb.8 index b0019f07f..6cf14b5b3 100644 --- a/apps/lb/lb.8 +++ b/apps/lb/lb.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2016 Broala and Universita` di Pisa +.\" Copyright (c) 2017 Corelight, Inc. and Universita` di Pisa .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -106,7 +106,7 @@ to remove any stale persistent VALE port. .Nm has been written by .An Seth Hall -at Broala, USA. The facilities related to extra buffers and pipe groups +at Corelight, USA. The facilities related to extra buffers and pipe groups have been added by .An Giuseppe Lettieri -at University of Pisa, Italy, under contract by Broala, USA. +at University of Pisa, Italy, under contract by Corelight, USA. diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 14ea8eed6..c1b9eb6f9 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Broala and Universita` di Pisa. All rights reserved. + * Copyright (C) 2017 Corelight, Inc. and Universita` di Pisa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions From ba055665511e41677609e04cefe22a740bde2ddd Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 12 Jan 2017 11:47:56 -0500 Subject: [PATCH 0015/2207] lb: small fixes to man page --- apps/lb/lb.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/lb/lb.8 b/apps/lb/lb.8 index 6cf14b5b3..643040e8a 100644 --- a/apps/lb/lb.8 +++ b/apps/lb/lb.8 @@ -43,13 +43,13 @@ .Nm reads packets from an input netmap port and sends them to a number of netmap pipes, trying to balance the packets received by each pipe. Packets belonging to the -same flow will always be sent to the same pipe. +same connection will always be sent to the same pipe. .Pp .Pp Command line options are listed below. .Bl -tag -width Ds .It Fl i Ar port -Name of a netmap port. It must be supplied exactly once to indentify +Name of a netmap port. It must be supplied exactly once to identify the input port. Any netmap port type (physical interface, VALE switch, pipe, monitor port...) can be used. From f7020ae4a4405c9c3a7e44893b2b002135b48bb4 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 18 Jan 2017 16:54:37 +0100 Subject: [PATCH 0016/2207] lb: metris output as JSON to syslog and/or stdout --- apps/include/ctrs.h | 5 +- apps/lb/lb.c | 171 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 136 insertions(+), 40 deletions(-) diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h index 40c6b3dfb..95e1583c9 100644 --- a/apps/include/ctrs.h +++ b/apps/include/ctrs.h @@ -5,9 +5,11 @@ /* counters to accumulate statistics */ struct my_ctrs { - uint64_t pkts, bytes, events, drop; + uint64_t pkts, bytes, events; + uint64_t drop, drop_bytes; uint64_t min_space; struct timeval t; + uint32_t oq_n; /* number of elements in overflow queue (used in lb) */ }; /* very crude code to print a number in normalized form. @@ -104,3 +106,4 @@ wait_for_next_report(struct timeval *prev, struct timeval *cur, return delta.tv_sec* 1000000 + delta.tv_usec; } #endif /* CTRS_H_ */ + diff --git a/apps/lb/lb.c b/apps/lb/lb.c index c1b9eb6f9..c99f4946a 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -84,8 +84,9 @@ struct compact_ipv6_hdr { #define DEF_EXTRA_BUFS 0 #define DEF_BATCH 2048 #define DEF_WAIT_LINK 2 -#define DEF_SYSLOG_INT 600 +#define DEF_STATS_INT 600 #define BUF_REVOKE 100 +#define STAT_MSG_MAXSIZE 1024 struct { char ifname[MAX_IFNAMELEN]; @@ -95,6 +96,7 @@ struct { uint16_t num_groups; uint32_t extra_bufs; uint16_t batch; + int stdout_interval; int syslog_interval; int wait_link; } glob_arg; @@ -158,7 +160,10 @@ static volatile int do_abort = 0; uint64_t dropped = 0; uint64_t forwarded = 0; +uint64_t received_bytes = 0; +uint64_t received_pkts = 0; uint64_t non_ip = 0; +uint32_t freeq_n = 0; struct port_des { struct my_ctrs ctr; @@ -190,7 +195,6 @@ print_stats(void *arg) int sys_int = 0; (void)arg; struct my_ctrs cur, prev; - char b1[40], b2[40]; struct my_ctrs *pipe_prev; pipe_prev = calloc(npipes, sizeof(struct my_ctrs)); @@ -199,60 +203,111 @@ print_stats(void *arg) exit(1); } + char stat_msg[STAT_MSG_MAXSIZE]; + memset(&prev, 0, sizeof(prev)); gettimeofday(&prev.t, NULL); while (!do_abort) { - int j, dosyslog = 0; - uint64_t pps, dps, usec; + int j, dosyslog, dostdout = 0; + uint64_t pps, dps, bps, dbps, usec; struct my_ctrs x; memset(&cur, 0, sizeof(cur)); usec = wait_for_next_report(&prev.t, &cur.t, 1000); - if (++sys_int == glob_arg.syslog_interval) { - dosyslog = 1; - sys_int = 0; - } + ++sys_int; + if (glob_arg.stdout_interval && sys_int % glob_arg.stdout_interval == 0) + dostdout = 1; + if (glob_arg.syslog_interval && sys_int % glob_arg.syslog_interval == 0) + dosyslog = 1; for (j = 0; j < npipes; ++j) { struct port_des *p = &ports[j]; - cur.pkts += p->ctr.pkts; cur.drop += p->ctr.drop; + cur.drop_bytes += p->ctr.drop_bytes; + cur.bytes += p->ctr.bytes; x.pkts = p->ctr.pkts - pipe_prev[j].pkts; x.drop = p->ctr.drop - pipe_prev[j].drop; + x.bytes = p->ctr.bytes - pipe_prev[j].bytes; + x.drop_bytes = p->ctr.drop_bytes - pipe_prev[j].drop_bytes; pps = (x.pkts*1000000 + usec/2) / usec; dps = (x.drop*1000000 + usec/2) / usec; - printf("%s/%s|", norm(b1, pps), norm(b2, dps)); + bps = ((x.bytes*1000000 + usec/2) / usec) * 8; + dbps = ((x.drop_bytes*1000000 + usec/2) / usec) * 8; pipe_prev[j] = p->ctr; - if (dosyslog) { - syslog(LOG_INFO, - "{" - "\"interface\":\"%s\"," - "\"output_ring\":%"PRIu16"," - "\"packets_forwarded\":%"PRIu64"," - "\"packets_dropped\":%"PRIu64 - "}", glob_arg.ifname, j, p->ctr.pkts, p->ctr.drop); - } - } - printf("\n"); - if (dosyslog) { - syslog(LOG_INFO, - "{" - "\"interface\":\"%s\"," - "\"output_ring\":null," - "\"packets_forwarded\":%"PRIu64"," - "\"packets_dropped\":%"PRIu64"," - "\"non_ip_packets\":%"PRIu64 - "}", glob_arg.ifname, forwarded, dropped, non_ip); + if ( dosyslog || dostdout ) + snprintf(stat_msg, STAT_MSG_MAXSIZE, + "{" + "\"ts\":%.6f," + "\"interface\":\"%s\"," + "\"output_ring\":%" PRIu16 "," + "\"packets_forwarded\":%" PRIu64 "," + "\"packets_dropped\":%" PRIu64 "," + "\"data_forward_rate_Mbps\":%.4f," + "\"data_drop_rate_Mbps\":%.4f," + "\"packet_forward_rate_kpps\":%.4f," + "\"packet_drop_rate_kpps\":%.4f," + "\"overflow_queue_size\":%" PRIu32 + "}", cur.t.tv_sec + (cur.t.tv_usec / 1000000.0), + glob_arg.ifname, + j, + p->ctr.pkts, + p->ctr.drop, + (double)bps / 1024 / 1024, + (double)dbps / 1024 / 1024, + (double)pps / 1000, + (double)dps / 1000, + p->ctr.oq_n); + + if (dosyslog) + syslog(LOG_INFO, stat_msg); + if (dostdout) + printf("%s\n", stat_msg); } x.pkts = cur.pkts - prev.pkts; x.drop = cur.drop - prev.drop; + x.bytes = cur.bytes - prev.bytes; + x.drop_bytes = cur.drop_bytes - prev.drop_bytes; pps = (x.pkts*1000000 + usec/2) / usec; dps = (x.drop*1000000 + usec/2) / usec; - printf("===> aggregate %spps %sdps\n", norm(b1, pps), norm(b2, dps)); + bps = ((x.bytes*1000000 + usec/2) / usec) * 8; + dbps = ((x.drop_bytes*1000000 + usec/2) / usec) * 8; + + if ( dosyslog || dostdout ) + snprintf(stat_msg, STAT_MSG_MAXSIZE, + "{" + "\"ts\":%.6f," + "\"interface\":\"%s\"," + "\"output_ring\":null," + "\"packets_received\":%" PRIu64 "," + "\"packets_forwarded\":%" PRIu64 "," + "\"packets_dropped\":%" PRIu64 "," + "\"non_ip_packets\":%" PRIu64 "," + "\"data_forward_rate_Mbps\":%.4f," + "\"data_drop_rate_Mbps\":%.4f," + "\"packet_forward_rate_kpps\":%.4f," + "\"packet_drop_rate_kpps\":%.4f," + "\"free_buffer_slots\":%" PRIu32 + "}", cur.t.tv_sec + (cur.t.tv_usec / 1000000.0), + glob_arg.ifname, + received_pkts, + cur.pkts, + cur.drop, + non_ip, + (double)bps / 1024 / 1024, + (double)dbps / 1024 / 1024, + (double)pps / 1000, + (double)dps / 1000, + freeq_n); + + if (dosyslog) + syslog(LOG_INFO, stat_msg); + if (dostdout) + printf("%s\n", stat_msg); + prev = cur; } @@ -303,13 +358,14 @@ void usage() { printf("usage: lb [options]\n"); printf("where options are:\n"); + printf(" -h view help text\n"); printf(" -i iface interface name (required)\n"); printf(" -p [prefix:]npipes add a new group of output pipes\n"); printf(" -B nbufs number of extra buffers (default: %d)\n", DEF_EXTRA_BUFS); printf(" -b batch batch size (default: %d)\n", DEF_BATCH); printf(" -w seconds wait for link up (default: %d)\n", DEF_WAIT_LINK); - printf(" -s seconds seconds between syslog messages (default: %d)\n", - DEF_SYSLOG_INT); + printf(" -s seconds seconds between syslog stats messages (default: 0)\n"); + printf(" -o seconds seconds between stdout stats messages (default: 0)\n"); exit(0); } @@ -441,6 +497,7 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs) */ dropped++; port->ctr.drop++; + port->ctr.drop_bytes += rs->len; return rs->buf_idx; } @@ -473,6 +530,7 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs) // XXX optimize this cycle for (j = 0; lp->oq->n && j < BUF_REVOKE; j++) { struct netmap_slot tmp = oq_deq(lp->oq); + lp->ctr.drop_bytes += tmp.len; oq_enq(freeq, &tmp); } @@ -495,9 +553,10 @@ int main(int argc, char **argv) glob_arg.output_rings = 0; glob_arg.batch = DEF_BATCH; glob_arg.wait_link = DEF_WAIT_LINK; - glob_arg.syslog_interval = DEF_SYSLOG_INT; + glob_arg.syslog_interval = 0; + glob_arg.stdout_interval = 0; - while ( (ch = getopt(argc, argv, "i:p:b:B:s:")) != -1) { + while ( (ch = getopt(argc, argv, "hi:p:b:B:s:o:")) != -1) { switch (ch) { case 'i': D("interface is %s", optarg); @@ -529,16 +588,23 @@ int main(int argc, char **argv) D("batch is %d", glob_arg.batch); break; + case 'o': + glob_arg.stdout_interval = atoi(optarg); + break; + case 's': glob_arg.syslog_interval = atoi(optarg); - D("syslog interval is %d", glob_arg.syslog_interval); + break; + + case 'h': + usage(); + return 0; break; default: D("bad option %c %s", ch, optarg); usage(); return 1; - } } @@ -559,8 +625,10 @@ int main(int argc, char **argv) if (glob_arg.num_groups == 0) parse_pipes(""); - setlogmask(LOG_UPTO(LOG_INFO)); - openlog("lb", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); + if (glob_arg.syslog_interval) { + setlogmask(LOG_UPTO(LOG_INFO)); + openlog("lb", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); + } uint32_t npipes = glob_arg.output_rings; @@ -799,6 +867,8 @@ int main(int argc, char **argv) while (!nm_ring_empty(rxring)) { struct netmap_slot *rs = next_slot; struct group_des *g = &groups[0]; + ++received_pkts; + received_bytes += rs->len; // CHOOSE THE CORRECT OUTPUT PIPE uint32_t hash = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B'); @@ -828,6 +898,29 @@ int main(int argc, char **argv) } } + + /* + * If there are overflow queues, copy the number of them for each + * port to the ctrs.oq_n variable for each port, otherwise set it to 0. + */ + for (i=0; i < npipes + 1; i++) { + if (ports[i].oq != NULL) { + ports[i].ctr.oq_n = ports[i].oq->n; + } else { + ports[i].ctr.oq_n = 0; + } + } + + } + + /* + * If freeq exists, copy the number to the freeq_n member of the + * message struct, otherwise set it to 0. + */ + if (freeq != NULL) { + freeq_n = freeq->n; + } else { + freeq_n = 0; } pthread_join(stat_thread, NULL); From 3a68b4ff3a979a89676be46e1bf8e1c3e1936748 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 17 Jan 2017 11:59:32 +0100 Subject: [PATCH 0017/2207] lb: fix format string in syslog --- apps/lb/lb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index c99f4946a..52e977096 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -263,7 +263,7 @@ print_stats(void *arg) p->ctr.oq_n); if (dosyslog) - syslog(LOG_INFO, stat_msg); + syslog(LOG_INFO, "%s", stat_msg); if (dostdout) printf("%s\n", stat_msg); } @@ -304,7 +304,7 @@ print_stats(void *arg) freeq_n); if (dosyslog) - syslog(LOG_INFO, stat_msg); + syslog(LOG_INFO, "%s", stat_msg); if (dostdout) printf("%s\n", stat_msg); From 196d6a03847f47979874dd38b665208d28c986c4 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Thu, 9 Feb 2017 18:35:46 +0100 Subject: [PATCH 0018/2207] lb: take consistent snapshots of the counters --- apps/include/ctrs.h | 2 +- apps/lb/lb.c | 162 ++++++++++++++++++++++++++++---------------- 2 files changed, 105 insertions(+), 59 deletions(-) diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h index 95e1583c9..e8717875d 100644 --- a/apps/include/ctrs.h +++ b/apps/include/ctrs.h @@ -89,7 +89,7 @@ timespec_sub(struct timespec a, struct timespec b) return ret; } -static uint64_t +static __inline uint64_t wait_for_next_report(struct timeval *prev, struct timeval *cur, int report_interval) { diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 52e977096..776f59faa 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -80,6 +80,7 @@ struct compact_ipv6_hdr { }; #define MAX_IFNAMELEN 64 +#define MAX_PORTNAMELEN (MAX_IFNAMELEN + 40) #define DEF_OUT_PIPES 2 #define DEF_EXTRA_BUFS 0 #define DEF_BATCH 2048 @@ -166,6 +167,7 @@ uint64_t non_ip = 0; uint32_t freeq_n = 0; struct port_des { + char interface[MAX_PORTNAMELEN]; struct my_ctrs ctr; unsigned int last_sync; struct overflow_queue *oq; @@ -188,6 +190,21 @@ struct group_des { struct group_des *groups; +/* statistcs */ +struct counters { + struct timeval ts; + struct my_ctrs *ctrs; + uint64_t received_pkts; + uint64_t received_bytes; + uint64_t non_ip; + uint32_t freeq_n; + int status __attribute__((aligned(64))); +#define COUNTERS_EMPTY 0 +#define COUNTERS_FULL 1 +}; + +struct counters counters_buf; + static void * print_stats(void *arg) { @@ -203,17 +220,27 @@ print_stats(void *arg) exit(1); } - char stat_msg[STAT_MSG_MAXSIZE]; + char stat_msg[STAT_MSG_MAXSIZE] = ""; memset(&prev, 0, sizeof(prev)); - gettimeofday(&prev.t, NULL); while (!do_abort) { - int j, dosyslog, dostdout = 0; - uint64_t pps, dps, bps, dbps, usec; + int j, dosyslog, dostdout = 0, newdata; + uint64_t pps = 0, dps = 0, bps = 0, dbps = 0, usec = 0; struct my_ctrs x; + counters_buf.status = COUNTERS_EMPTY; + newdata = 0; memset(&cur, 0, sizeof(cur)); - usec = wait_for_next_report(&prev.t, &cur.t, 1000); + sleep(1); + if (counters_buf.status == COUNTERS_FULL) { + __sync_synchronize(); + newdata = 1; + cur.t = counters_buf.ts; + if (prev.t.tv_sec || prev.t.tv_usec) { + usec = (cur.t.tv_sec - prev.t.tv_sec) * 1000000 + + cur.t.tv_usec - prev.t.tv_usec; + } + } ++sys_int; if (glob_arg.stdout_interval && sys_int % glob_arg.stdout_interval == 0) @@ -222,23 +249,25 @@ print_stats(void *arg) dosyslog = 1; for (j = 0; j < npipes; ++j) { - struct port_des *p = &ports[j]; - cur.pkts += p->ctr.pkts; - cur.drop += p->ctr.drop; - cur.drop_bytes += p->ctr.drop_bytes; - cur.bytes += p->ctr.bytes; - - x.pkts = p->ctr.pkts - pipe_prev[j].pkts; - x.drop = p->ctr.drop - pipe_prev[j].drop; - x.bytes = p->ctr.bytes - pipe_prev[j].bytes; - x.drop_bytes = p->ctr.drop_bytes - pipe_prev[j].drop_bytes; - pps = (x.pkts*1000000 + usec/2) / usec; - dps = (x.drop*1000000 + usec/2) / usec; - bps = ((x.bytes*1000000 + usec/2) / usec) * 8; - dbps = ((x.drop_bytes*1000000 + usec/2) / usec) * 8; - pipe_prev[j] = p->ctr; + struct my_ctrs *c = &counters_buf.ctrs[j]; + cur.pkts += c->pkts; + cur.drop += c->drop; + cur.drop_bytes += c->drop_bytes; + cur.bytes += c->bytes; + + if (usec) { + x.pkts = c->pkts - pipe_prev[j].pkts; + x.drop = c->drop - pipe_prev[j].drop; + x.bytes = c->bytes - pipe_prev[j].bytes; + x.drop_bytes = c->drop_bytes - pipe_prev[j].drop_bytes; + pps = (x.pkts*1000000 + usec/2) / usec; + dps = (x.drop*1000000 + usec/2) / usec; + bps = ((x.bytes*1000000 + usec/2) / usec) * 8; + dbps = ((x.drop_bytes*1000000 + usec/2) / usec) * 8; + } + pipe_prev[j] = *c; - if ( dosyslog || dostdout ) + if ( (dosyslog || dostdout) && newdata ) snprintf(stat_msg, STAT_MSG_MAXSIZE, "{" "\"ts\":%.6f," @@ -252,31 +281,33 @@ print_stats(void *arg) "\"packet_drop_rate_kpps\":%.4f," "\"overflow_queue_size\":%" PRIu32 "}", cur.t.tv_sec + (cur.t.tv_usec / 1000000.0), - glob_arg.ifname, + ports[j].interface, j, - p->ctr.pkts, - p->ctr.drop, + c->pkts, + c->drop, (double)bps / 1024 / 1024, (double)dbps / 1024 / 1024, (double)pps / 1000, (double)dps / 1000, - p->ctr.oq_n); + c->oq_n); - if (dosyslog) + if (dosyslog && stat_msg[0]) syslog(LOG_INFO, "%s", stat_msg); - if (dostdout) + if (dostdout && stat_msg[0]) printf("%s\n", stat_msg); } - x.pkts = cur.pkts - prev.pkts; - x.drop = cur.drop - prev.drop; - x.bytes = cur.bytes - prev.bytes; - x.drop_bytes = cur.drop_bytes - prev.drop_bytes; - pps = (x.pkts*1000000 + usec/2) / usec; - dps = (x.drop*1000000 + usec/2) / usec; - bps = ((x.bytes*1000000 + usec/2) / usec) * 8; - dbps = ((x.drop_bytes*1000000 + usec/2) / usec) * 8; - - if ( dosyslog || dostdout ) + if (usec) { + x.pkts = cur.pkts - prev.pkts; + x.drop = cur.drop - prev.drop; + x.bytes = cur.bytes - prev.bytes; + x.drop_bytes = cur.drop_bytes - prev.drop_bytes; + pps = (x.pkts*1000000 + usec/2) / usec; + dps = (x.drop*1000000 + usec/2) / usec; + bps = ((x.bytes*1000000 + usec/2) / usec) * 8; + dbps = ((x.drop_bytes*1000000 + usec/2) / usec) * 8; + } + + if ( (dosyslog || dostdout) && newdata ) snprintf(stat_msg, STAT_MSG_MAXSIZE, "{" "\"ts\":%.6f," @@ -296,16 +327,16 @@ print_stats(void *arg) received_pkts, cur.pkts, cur.drop, - non_ip, + counters_buf.non_ip, (double)bps / 1024 / 1024, (double)dbps / 1024 / 1024, (double)pps / 1000, (double)dps / 1000, - freeq_n); + counters_buf.freeq_n); - if (dosyslog) + if (dosyslog && stat_msg[0]) syslog(LOG_INFO, "%s", stat_msg); - if (dostdout) + if (dostdout && stat_msg[0]) printf("%s\n", stat_msg); prev = cur; @@ -643,6 +674,13 @@ int main(int argc, char **argv) struct port_des *rxport = &ports[npipes]; init_groups(); + memset(&counters_buf, 0, sizeof(counters_buf)); + counters_buf.ctrs = calloc(npipes, sizeof(struct my_ctrs)); + if (!counters_buf.ctrs) { + D("failed to allocate the counters snapshot buffer"); + return 1; + } + if (pthread_create(&stat_thread, NULL, print_stats, NULL) == -1) { D("unable to create the stats thread: %s", strerror(errno)); return 1; @@ -731,19 +769,18 @@ int main(int argc, char **argv) int k; for (k = 0; k < g->nports; ++k) { struct port_des *p = &g->ports[k]; - char interface[25]; - sprintf(interface, "netmap:%s{%d/xT@%d", g->pipename, g->first_id + k, + snprintf(p->interface, MAX_PORTNAMELEN, "netmap:%s{%d/xT@%d", g->pipename, g->first_id + k, rxport->nmd->req.nr_arg2); - D("opening pipe named %s", interface); + D("opening pipe named %s", p->interface); - p->nmd = nm_open(interface, NULL, 0, rxport->nmd); + p->nmd = nm_open(p->interface, NULL, 0, rxport->nmd); if (p->nmd == NULL) { - D("cannot open %s", interface); + D("cannot open %s", p->interface); return (1); } else { D("successfully opened pipe #%d %s (tx slots: %d)", - k + 1, interface, p->nmd->req.nr_tx_slots); + k + 1, p->interface, p->nmd->req.nr_tx_slots); p->ring = NETMAP_TXRING(p->nmd->nifp, 0); } D("zerocopy %s", @@ -899,18 +936,27 @@ int main(int argc, char **argv) } - /* - * If there are overflow queues, copy the number of them for each - * port to the ctrs.oq_n variable for each port, otherwise set it to 0. - */ - for (i=0; i < npipes + 1; i++) { - if (ports[i].oq != NULL) { - ports[i].ctr.oq_n = ports[i].oq->n; - } else { - ports[i].ctr.oq_n = 0; - } + if (counters_buf.status == COUNTERS_FULL) + continue; + /* take a new snapshot of the counters */ + gettimeofday(&counters_buf.ts, NULL); + for (i = 0; i < npipes; i++) { + struct my_ctrs *c = &counters_buf.ctrs[i]; + *c = ports[i].ctr; + /* + * If there are overflow queues, copy the number of them for each + * port to the ctrs.oq_n variable for each port. + */ + if (ports[i].oq != NULL) + c->oq_n = ports[i].oq->n; } - + counters_buf.received_pkts = received_pkts; + counters_buf.received_bytes = received_bytes; + counters_buf.non_ip = non_ip; + if (freeq != NULL) + counters_buf.freeq_n = freeq->n; + __sync_synchronize(); + counters_buf.status = COUNTERS_FULL; } /* From 673881aea964b01eaa6b0c55066db540e18e7401 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 1 Feb 2017 13:39:12 -0500 Subject: [PATCH 0019/2207] lb: Small fixes for packet stats --- apps/lb/lb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 776f59faa..3dd4edc2a 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -504,6 +504,7 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs) ts->flags |= NS_BUF_CHANGED; ts->ptr = rs->ptr; ring->head = ring->cur = nm_ring_next(ring, ring->cur); + port->ctr.bytes += rs->len; port->ctr.pkts++; forwarded++; if (old_slot.ptr && !g->last) { @@ -561,13 +562,15 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs) // XXX optimize this cycle for (j = 0; lp->oq->n && j < BUF_REVOKE; j++) { struct netmap_slot tmp = oq_deq(lp->oq); + + dropped++; + lp->ctr.drop++; lp->ctr.drop_bytes += tmp.len; + oq_enq(freeq, &tmp); } ND(1, "revoked %d buffers from %s", j, lq->name); - lp->ctr.drop += j; - dropped += j; } return oq_deq(freeq).buf_idx; @@ -888,8 +891,6 @@ int main(int argc, char **argv) ring->cur = nm_ring_next(ring, ring->cur); } ring->head = ring->cur; - forwarded += lim; - p->ctr.pkts += lim; } } From 4b55ebaf9e761acae56759a965923a8d6f0e1a19 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 10 Mar 2017 10:06:16 +0100 Subject: [PATCH 0020/2207] lb: fixing the syslog stats internal --- apps/lb/lb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 3dd4edc2a..40c69fc12 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -224,7 +224,7 @@ print_stats(void *arg) memset(&prev, 0, sizeof(prev)); while (!do_abort) { - int j, dosyslog, dostdout = 0, newdata; + int j, dosyslog = 0, dostdout = 0, newdata; uint64_t pps = 0, dps = 0, bps = 0, dbps = 0, usec = 0; struct my_ctrs x; From d259fb84cd79d178e2e952b945576d3d15084d8e Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 10 Mar 2017 10:19:16 +0100 Subject: [PATCH 0021/2207] lb: fixe an issue where the link wait time couldn't be specified --- apps/lb/lb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 40c69fc12..d6629006b 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -590,7 +590,7 @@ int main(int argc, char **argv) glob_arg.syslog_interval = 0; glob_arg.stdout_interval = 0; - while ( (ch = getopt(argc, argv, "hi:p:b:B:s:o:")) != -1) { + while ( (ch = getopt(argc, argv, "hi:p:b:B:s:o:w:")) != -1) { switch (ch) { case 'i': D("interface is %s", optarg); @@ -622,6 +622,11 @@ int main(int argc, char **argv) D("batch is %d", glob_arg.batch); break; + case 'w': + glob_arg.wait_link = atoi(optarg); + D("link wait for up time is %d", glob_arg.wait_link); + break; + case 'o': glob_arg.stdout_interval = atoi(optarg); break; From 4bcbaab75b865ebf0a7cd14c73cd2e63bf9a4980 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 10 Mar 2017 10:22:58 +0100 Subject: [PATCH 0022/2207] lb: delays stats until link wait is done --- apps/lb/lb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index d6629006b..c6a5d6a8f 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -689,12 +689,6 @@ int main(int argc, char **argv) return 1; } - if (pthread_create(&stat_thread, NULL, print_stats, NULL) == -1) { - D("unable to create the stats thread: %s", strerror(errno)); - return 1; - } - - /* we need base_req to specify pipes and extra bufs */ struct nmreq base_req; memset(&base_req, 0, sizeof(base_req)); @@ -824,6 +818,12 @@ int main(int argc, char **argv) sleep(glob_arg.wait_link); + /* start stats thread after wait_link */ + if (pthread_create(&stat_thread, NULL, print_stats, NULL) == -1) { + D("unable to create the stats thread: %s", strerror(errno)); + return 1; + } + struct pollfd pollfd[npipes + 1]; memset(&pollfd, 0, sizeof(pollfd)); signal(SIGINT, sigint_h); From db98d417d20ae63b364cdb73d2b03b22d50d5b8f Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 10 Mar 2017 10:24:02 +0100 Subject: [PATCH 0023/2207] lb: Add a busy-wait option (-W) --- apps/lb/lb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index c6a5d6a8f..455fdc1ef 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -100,6 +100,7 @@ struct { int stdout_interval; int syslog_interval; int wait_link; + bool busy_wait; } glob_arg; /* @@ -395,6 +396,7 @@ void usage() printf(" -B nbufs number of extra buffers (default: %d)\n", DEF_EXTRA_BUFS); printf(" -b batch batch size (default: %d)\n", DEF_BATCH); printf(" -w seconds wait for link up (default: %d)\n", DEF_WAIT_LINK); + printf(" -W enable busy waiting. this will run your CPU at 100%%\n"); printf(" -s seconds seconds between syslog stats messages (default: 0)\n"); printf(" -o seconds seconds between stdout stats messages (default: 0)\n"); exit(0); @@ -587,10 +589,11 @@ int main(int argc, char **argv) glob_arg.output_rings = 0; glob_arg.batch = DEF_BATCH; glob_arg.wait_link = DEF_WAIT_LINK; + glob_arg.busy_wait = false; glob_arg.syslog_interval = 0; glob_arg.stdout_interval = 0; - while ( (ch = getopt(argc, argv, "hi:p:b:B:s:o:w:")) != -1) { + while ( (ch = getopt(argc, argv, "hi:p:b:B:s:o:w:W")) != -1) { switch (ch) { case 'i': D("interface is %s", optarg); @@ -627,6 +630,10 @@ int main(int argc, char **argv) D("link wait for up time is %d", glob_arg.wait_link); break; + case 'W': + glob_arg.busy_wait = true; + break; + case 'o': glob_arg.stdout_interval = atoi(optarg); break; @@ -833,7 +840,7 @@ int main(int argc, char **argv) for (i = 0; i < npipes; ++i) { struct netmap_ring *ring = ports[i].ring; - if (nm_ring_next(ring, ring->tail) == ring->cur) { + if (!glob_arg.busy_wait && nm_ring_next(ring, ring->tail) == ring->cur) { /* no need to poll, there are no packets pending */ continue; } From 2794aa61f8c3ee6baf523ca4846f221f4b17eb64 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Fri, 10 Mar 2017 10:41:12 +0100 Subject: [PATCH 0024/2207] lb: send stats and update ts even when traffic is silent --- apps/lb/lb.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index 455fdc1ef..debe196f5 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -584,6 +584,7 @@ int main(int argc, char **argv) uint32_t i; int rv; unsigned int iter = 0; + int poll_timeout = 10; /* default */ glob_arg.ifname[0] = '\0'; glob_arg.output_rings = 0; @@ -834,6 +835,15 @@ int main(int argc, char **argv) struct pollfd pollfd[npipes + 1]; memset(&pollfd, 0, sizeof(pollfd)); signal(SIGINT, sigint_h); + + /* make sure we wake up as often as needed, even when there are no + * packets coming in + */ + if (glob_arg.syslog_interval > 0 && glob_arg.syslog_interval < poll_timeout) + poll_timeout = glob_arg.syslog_interval; + if (glob_arg.stdout_interval > 0 && glob_arg.stdout_interval < poll_timeout) + poll_timeout = glob_arg.stdout_interval; + while (!do_abort) { u_int polli = 0; iter++; @@ -856,11 +866,11 @@ int main(int argc, char **argv) ++polli; //RD(5, "polling %d file descriptors", polli+1); - rv = poll(pollfd, polli, 10); + rv = poll(pollfd, polli, poll_timeout); if (rv <= 0) { if (rv < 0 && errno != EAGAIN && errno != EINTR) RD(1, "poll error %s", strerror(errno)); - continue; + goto send_stats; } if (oq) { @@ -949,6 +959,7 @@ int main(int argc, char **argv) } + send_stats: if (counters_buf.status == COUNTERS_FULL) continue; /* take a new snapshot of the counters */ From 981201b16b8e4ba8fa28d69cbd5cbc921e3eecfc Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 14 Mar 2017 11:54:27 +0100 Subject: [PATCH 0025/2207] fix locking and error checking in netmap_mem_pools_info_get() --- sys/dev/netmap/netmap.c | 9 ++++++++- sys/dev/netmap/netmap_mem2.c | 9 +++------ sys/dev/netmap/netmap_mem2.h | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 852152968..d572739d8 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2288,7 +2288,14 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread break; } else if (i == NETMAP_POOLS_INFO_GET) { /* get information from the memory allocator */ - error = netmap_mem_pools_info_get(nmr, priv->np_na); + NMG_LOCK(); + if (priv->np_na && priv->np_na->nm_mem) { + struct netmap_mem_d *nmd = priv->np_na->nm_mem; + error = netmap_mem_pools_info_get(nmr, nmd); + } else { + error = EINVAL; + } + NMG_UNLOCK(); break; } else if (i != 0) { D("nr_cmd must be 0 not %d", i); diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index b4c0d90df..982d84e7a 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -1867,20 +1867,15 @@ struct netmap_mem_ops netmap_mem_global_ops = { }; int -netmap_mem_pools_info_get(struct nmreq *nmr, struct netmap_adapter *na) +netmap_mem_pools_info_get(struct nmreq *nmr, struct netmap_mem_d *nmd) { uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1; struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp); - struct netmap_mem_d *nmd = na->nm_mem; struct netmap_pools_info pi; unsigned int memsize; uint16_t memid; int ret; - if (!nmd) { - return -1; - } - ret = netmap_mem_get_info(nmd, &memsize, NULL, &memid); if (ret) { return ret; @@ -1888,6 +1883,7 @@ netmap_mem_pools_info_get(struct nmreq *nmr, struct netmap_adapter *na) pi.memsize = memsize; pi.memid = memid; + NMA_LOCK(nmd); pi.if_pool_offset = 0; pi.if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal; pi.if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize; @@ -1900,6 +1896,7 @@ netmap_mem_pools_info_get(struct nmreq *nmr, struct netmap_adapter *na) nmd->pools[NETMAP_RING_POOL].memtotal; pi.buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; pi.buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; + NMA_UNLOCK(nmd); ret = copyout(&pi, upi, sizeof(pi)); if (ret) { diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h index 423b21451..102c66d79 100644 --- a/sys/dev/netmap/netmap_mem2.h +++ b/sys/dev/netmap/netmap_mem2.h @@ -155,7 +155,7 @@ struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *); #endif /* WITH_PTNETMAP_GUEST */ -int netmap_mem_pools_info_get(struct nmreq *, struct netmap_adapter *); +int netmap_mem_pools_info_get(struct nmreq *, struct netmap_mem_d *); #define NETMAP_MEM_PRIVATE 0x2 /* allocator uses private address space */ #define NETMAP_MEM_IO 0x4 /* the underlying memory is mmapped I/O */ From 09356dd0a97db4a5013bd70370160f56af81de96 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 14 Mar 2017 11:56:11 +0100 Subject: [PATCH 0026/2207] testmmap: restore version after nmr reset --- utils/testmmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/testmmap.c b/utils/testmmap.c index 484724c14..ef3a86d1c 100644 --- a/utils/testmmap.c +++ b/utils/testmmap.c @@ -955,6 +955,8 @@ void do_nmr_reset() { bzero(&curr_nmr, sizeof(curr_nmr)); + curr_nmr.nr_version = NETMAP_API; + curr_nmr.nr_flas = NR_REG_ALL_NIC; } void From f7970b23bc87423ebbf395663473b366a7a2ba7b Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 14 Mar 2017 11:56:25 +0100 Subject: [PATCH 0027/2207] testmmap: pools-info-get command --- utils/testmmap.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/utils/testmmap.c b/utils/testmmap.c index ef3a86d1c..d08e734cf 100644 --- a/utils/testmmap.c +++ b/utils/testmmap.c @@ -144,8 +144,10 @@ void do_close() #include #include #include +#include struct nmreq curr_nmr = { .nr_version = NETMAP_API, .nr_flags = NR_REG_ALL_NIC, }; +struct netmap_pools_info curr_pools_info; char nmr_name[64]; void parse_nmr_config(char* w, struct nmreq *nmr) @@ -796,6 +798,26 @@ nmr_arg_error() nmr_arg_unexpected(3); } +void +nmr_pools_info_get() +{ + uintptr_t *pp = (uintptr_t *)&curr_nmr.nr_arg1; + struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp); + + printf("arg1+2+3: %p\n", pp); + printf(" memsize: %"PRIu64"\n", upi->memsize); + printf(" memid: %"PRIu32"\n", upi->memid); + printf(" if off: %"PRIu32"\n", upi->if_pool_offset); + printf(" if tot: %"PRIu32"\n", upi->if_pool_objtotal); + printf(" if siz: %"PRIu32"\n", upi->if_pool_objsize); + printf(" ring off: %"PRIu32"\n", upi->ring_pool_offset); + printf(" ring tot: %"PRIu32"\n", upi->ring_pool_objtotal); + printf(" ring siz: %"PRIu32"\n", upi->ring_pool_objsize); + printf(" buf off: %"PRIu32"\n", upi->buf_pool_offset); + printf(" buf tot: %"PRIu32"\n", upi->buf_pool_objtotal); + printf(" buf siz: %"PRIu32"\n", upi->buf_pool_objsize); +} + void nmr_arg_extra() { @@ -894,6 +916,10 @@ do_nmr_dump() printf("BDG_POLLING_OFF"); arg_interp = nmr_arg_error; break; + case NETMAP_POOLS_INFO_GET: + printf("POOLS_INFO_GET"); + arg_interp = nmr_pools_info_get; + break; default: printf("???"); arg_interp = nmr_arg_error; @@ -956,7 +982,7 @@ do_nmr_reset() { bzero(&curr_nmr, sizeof(curr_nmr)); curr_nmr.nr_version = NETMAP_API; - curr_nmr.nr_flas = NR_REG_ALL_NIC; + curr_nmr.nr_flags = NR_REG_ALL_NIC; } void @@ -1025,6 +1051,9 @@ do_nmr_cmd() curr_nmr.nr_cmd = NETMAP_PT_HOST_CREATE; } else if (strcmp(arg, "pt-host-delete") == 0) { curr_nmr.nr_cmd = NETMAP_PT_HOST_DELETE; + } else if (strcmp(arg, "pools-info-get") == 0) { + curr_nmr.nr_cmd = NETMAP_POOLS_INFO_GET; + nmreq_pointer_put(&curr_nmr, &curr_pools_info); } out: output("cmd=%x", curr_nmr.nr_cmd); From 72a2b2aad03302778cc4633a56dfd041206ac95b Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 16 Mar 2017 12:48:00 +0100 Subject: [PATCH 0028/2207] python: pktman.py: fix handling of nm_open() suffixes --- extra/python/pktman.py | 105 ++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 70 deletions(-) diff --git a/extra/python/pktman.py b/extra/python/pktman.py index dce7189c3..4df06ada8 100755 --- a/extra/python/pktman.py +++ b/extra/python/pktman.py @@ -1,4 +1,10 @@ #!/usr/bin/env python +# +# Packet generator written in Python, providing functionalities +# similar to the netmap pkt-gen written in C +# +# Author: Vincenzo Maffione +# import netmap # our module import time # time measurements @@ -48,10 +54,10 @@ def build_packet(args, parser): return ret -def transmit(idx, suffix, args, parser, queue): +def transmit(idx, ifname, args, parser, queue): # use nm_open() to open the netmap device and register an interface # using an extended interface name - nmd = netmap.NetmapDesc(args.interface + suffix) + nmd = netmap.NetmapDesc(ifname) time.sleep(args.wait_link) # build the packet that will be transmitted @@ -94,10 +100,10 @@ def transmit(idx, suffix, args, parser, queue): pass -def receive(idx, suffix, args, parser, queue): +def receive(idx, ifname, args, parser, queue): # use nm_open() to open the netmap device and register an interface # using an extended interface name - nmd = netmap.NetmapDesc(args.interface + suffix) + nmd = netmap.NetmapDesc(ifname) time.sleep(args.wait_link) # select the right ring @@ -139,39 +145,6 @@ def receive(idx, suffix, args, parser, queue): pass -# How many netmap ring couples has 'ifname'? -def netmap_max_rings(ifname): - if ifname.startswith('netmap:'): - ifname = ifname[7:] - - nm = netmap.Netmap() - nm.open() - nm.if_name = ifname - nm.getinfo() - - return nm.tx_rings - -# extract the (nr_ringid, nr_flags) specified by the extended -# interface name (nm_open() ifname) -def netmap_get_ringid(ifname): - if ifname.startswith('netmap:'): - ifname = ifname[7:] - - nm = netmap.Netmap() - nm.open() - nm.if_name = ifname - nm.getinfo() - - return nm.ringid, nm.flags - -def netmap_remove_ifname_suffix(ifname_ext): - m = re.match(r'\w+:\w+', ifname_ext) - if m == None: - return None - - return m.group(0) - - ############################## MAIN ########################### if __name__ == '__main__': @@ -222,33 +195,24 @@ def netmap_remove_ifname_suffix(ifname_ext): print('Invalid number of threads\n') help_quit(parser) - try: - # compute 'ifname' removing the suffix from the extended name - # specified by the user - ifname = netmap_remove_ifname_suffix(args.interface) - if ifname == None: - print('Invalid ifname "%s"' % (args.interface, )) - help_quit(parser) - - # compute 'max_couples', which is the number of tx/rx rings couples to be registered - # according to 'args.interface' - nr_ringid, nr_flags = netmap_get_ringid(args.interface) - if nr_flags in [netmap.RegAllNic, netmap.RegNicSw]: - # ask netmap for the number of available couples - max_couples = netmap_max_rings(args.interface) - suffix_required = True - ringid_offset = 0 - else: - # all the others netmap.Reg* specifies just one couple of rings - max_couples = 1 - suffix_required = False - ringid_offset = nr_ringid - if args.threads > max_couples: - print('You cannot use more than %s (tx,rx) rings couples with "%s"' % (max_couples, args.interface)) - help_quit(parser) - except netmap.error as e: - print(e) - quit() + # Temporary open a netmap descriptor to get some info about + # number of involved rings or the specific ring couple involved + d = netmap.NetmapDesc(args.interface) + if d.getflags() in [netmap.RegAllNic, netmap.RegNicSw]: + max_couples = min(len(d.receive_rings), len(d.transmit_rings)) + if d.getflags() == netmap.RegAllNic: + max_couples -= 1 + ringid_offset = 0 + suffix_required = True + else: + max_couples = 1 + ringid_offset = d.getringid() + suffix_required = False + del d + + if args.threads > max_couples: + print('You cannot use more than %s (tx,rx) rings couples with "%s"' % (max_couples, args.interface)) + quit(1) jobs = [] # array of worker processes queues = [] # array of queues for IPC @@ -256,20 +220,21 @@ def netmap_remove_ifname_suffix(ifname_ext): queue = multiprocessing.Queue() queues.append(queue) - # 'i_off' contains the ring idx on which the process below will operate - i_off = i + ringid_offset + # 'ring_id' contains the ring idx on which the process below will operate + ring_id = i + ringid_offset # it may also be necessary to add an extension suffix to the interface # name specified by the user + ifname = args.interface if suffix_required: - suffix = '-' + str(i_off) - else: - suffix = '' + ifname += '-' + str(ring_id) + + print("Run worker #%d on %s, ring_id %d" % (i, ifname, ring_id)) # create a new process that will execute the user-selected handler function, # with the arguments specified by the 'args' tuple job = multiprocessing.Process(name = 'worker-' + str(i), target = handler[args.function], - args = (i_off, suffix, args, parser, queue)) + args = (ring_id, ifname, args, parser, queue)) job.deamon = True # ensure work termination jobs.append(job) From 777709dcdfc4e420dd9e0e6a66b7088f1d9ae584 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Thu, 16 Mar 2017 21:55:06 -0400 Subject: [PATCH 0029/2207] lb: Fix 2-tuple fallback hashing. --- apps/lb/pkt_hash.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c index f775b2a3e..ebd439592 100644 --- a/apps/lb/pkt_hash.c +++ b/apps/lb/pkt_hash.c @@ -169,17 +169,20 @@ decode_ip_n_hash(struct ip *iph, uint8_t hash_split, uint8_t seed) rc = decode_ip_n_hash((struct ip *)((uint8_t *)iph + (iph->ip_hl<<2)), hash_split, seed); break; + case IPPROTO_ICMP: + case IPPROTO_GRE: + case IPPROTO_ESP: + case IPPROTO_PIM: + case IPPROTO_IGMP: default: /* ** the hash strength (although weaker but) should still hold ** even with 2 fields + **/ rc = sym_hash_fn(ntohl(iph->ip_src.s_addr), ntohl(iph->ip_dst.s_addr), ntohs(0xFFFD) + seed, ntohs(0xFFFE) + seed); - **/ - // We return 0 to indicate that the packet couldn't be balanced. - return 0; break; } } From 47a924c1cc94ff7f50ac1d0457efafe69731c6a5 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Sun, 19 Mar 2017 11:54:53 -0400 Subject: [PATCH 0030/2207] Updates nmreplay usage display to match functionality. "-i" is only accepted a single time and the "-f" flag to provide a pcap file wasn't given at all in the usage output. --- apps/nmreplay/nmreplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c index f22209992..de72c0abd 100644 --- a/apps/nmreplay/nmreplay.c +++ b/apps/nmreplay/nmreplay.c @@ -971,7 +971,7 @@ usage(void) { fprintf(stderr, "usage: nmreplay [-v] [-D delay] [-B {[constant,]bps|ether,bps|real,speedup}] [-L loss]\n" - "\t[-b burst] -i ifa-or-pcap-file -i ifb\n"); + "\t[-b burst] -f pcap-file -i ifb\n"); exit(1); } From 94e5c7fd7747038a01719ca23170f166835fac4d Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 21 Mar 2017 17:42:46 +0100 Subject: [PATCH 0031/2207] pkt-gen: fix typo in ping body --- apps/pkt-gen/pkt-gen.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 725f831bb..b7f676c84 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1183,7 +1183,7 @@ msb64(uint64_t x) #define PAY_OFS 42 /* where in the pkt... */ static void * -pinger_body(void *data) +ping_body(void *data) { struct targ *targ = (struct targ *) data; struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; @@ -1213,7 +1213,7 @@ pinger_body(void *data) struct netmap_ring *ring = NETMAP_TXRING(nifp, 0); struct netmap_slot *slot; char *p; - for (i = 0; i < 1; i++) { /* XXX why the loop for 1 pkt ? */ + slot = &ring->slot[ring->cur]; slot->len = size; p = NETMAP_BUF(ring, slot->buf_idx); @@ -1231,7 +1231,7 @@ pinger_body(void *data) sent++; ring->head = ring->cur = nm_ring_next(ring, ring->cur); } - } + /* should use a parameter to decide how often to send */ if (poll(&pfd, 1, 3000) <= 0) { D("poll error/timeout on queue %d: %s", targ->me, @@ -1239,8 +1239,8 @@ pinger_body(void *data) continue; } /* see what we got back */ - for (i = targ->nmd->first_tx_ring; - i <= targ->nmd->last_tx_ring; i++) { + for (i = targ->nmd->first_rx_ring; + i <= targ->nmd->last_rx_ring; i++) { ring = NETMAP_RXRING(nifp, i); while (!nm_ring_empty(ring)) { uint32_t seq; @@ -1318,7 +1318,7 @@ pinger_body(void *data) * reply to ping requests */ static void * -ponger_body(void *data) +pong_body(void *data) { struct targ *targ = (struct targ *) data; struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; @@ -2403,8 +2403,8 @@ struct td_desc { static struct td_desc func[] = { { TD_TYPE_SENDER, "tx", sender_body }, { TD_TYPE_RECEIVER, "rx", receiver_body }, - { TD_TYPE_OTHER, "ping", pinger_body }, - { TD_TYPE_OTHER, "pong", ponger_body }, + { TD_TYPE_OTHER, "ping", ping_body }, + { TD_TYPE_OTHER, "pong", pong_body }, { TD_TYPE_SENDER, "txseq", txseq_body }, { TD_TYPE_RECEIVER, "rxseq", rxseq_body }, { 0, NULL, NULL } From db6e3d7eaafe74d6b532831ebcf23069ebf4b760 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 28 Mar 2017 18:55:57 +0200 Subject: [PATCH 0032/2207] pkt-gen: avoid confusing 'Success' message on timeout --- apps/pkt-gen/pkt-gen.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index b7f676c84..d96e4427d 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1213,7 +1213,9 @@ ping_body(void *data) struct netmap_ring *ring = NETMAP_TXRING(nifp, 0); struct netmap_slot *slot; char *p; + int rv; + for (i = 0; i < 1; i++) { /* XXX why the loop for 1 pkt ? */ slot = &ring->slot[ring->cur]; slot->len = size; p = NETMAP_BUF(ring, slot->buf_idx); @@ -1233,9 +1235,9 @@ ping_body(void *data) } /* should use a parameter to decide how often to send */ - if (poll(&pfd, 1, 3000) <= 0) { - D("poll error/timeout on queue %d: %s", targ->me, - strerror(errno)); + if ( (rv = poll(&pfd, 1, 3000)) <= 0) { + D("poll error on queue %d: %s", targ->me, + (rv ? strerror(errno) : "timeout")); continue; } /* see what we got back */ @@ -1338,9 +1340,10 @@ pong_body(void *data) #ifdef BUSYWAIT ioctl(pfd.fd, NIOCRXSYNC, NULL); #else - if (poll(&pfd, 1, 1000) <= 0) { - D("poll error/timeout on queue %d: %s", targ->me, - strerror(errno)); + int rv; + if ( (rv = poll(&pfd, 1, 1000)) <= 0) { + D("poll error on queue %d: %s", targ->me, + rv ? strerror(errno) : "timeout"); continue; } #endif From 18a3f86936331db70d196b2a8f6078738801c8a0 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 10:51:22 +0200 Subject: [PATCH 0033/2207] pkt-gen: use -R option also for pinger --- apps/pkt-gen/pkt-gen.c | 91 ++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index d96e4427d..b1dcc9dc9 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1175,6 +1175,24 @@ msb64(uint64_t x) return 0; } +/* + * wait until ts, either busy or sleeping if more than 1ms. + * Return wakeup time. + */ +static struct timespec +wait_time(struct timespec ts) +{ + for (;;) { + struct timespec w, cur; + clock_gettime(CLOCK_REALTIME_PRECISE, &cur); + w = timespec_sub(ts, cur); + if (w.tv_sec < 0) + return cur; + else if (w.tv_sec > 0 || w.tv_nsec > 1000000) + poll(NULL, 0, 1); + } +} + /* * Send a packet, and wait for a response. * The payload (after UDP header, ofs 42) has a 4-byte sequence @@ -1192,9 +1210,11 @@ ping_body(void *data) void *frame; int size; struct timespec ts, now, last_print; + struct timespec nexttime = { 0, 0}; // XXX silence compiler uint64_t sent = 0, n = targ->g->npackets; uint64_t count = 0, t_cur, t_min = ~0, av = 0; uint64_t buckets[64]; /* bins for delays, ns */ + int rate_limit = targ->g->tx_rate, tosend = 0; frame = &targ->pkt; frame += sizeof(targ->pkt.vh) - targ->g->virt_header; @@ -1209,31 +1229,50 @@ ping_body(void *data) bzero(&buckets, sizeof(buckets)); clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); now = last_print; + if (rate_limit) { + targ->tic = timespec_add(now, (struct timespec){2,0}); + targ->tic.tv_nsec = 0; + wait_time(targ->tic); + nexttime = targ->tic; + } while (!targ->cancel && (n == 0 || sent < n)) { struct netmap_ring *ring = NETMAP_TXRING(nifp, 0); struct netmap_slot *slot; char *p; int rv; + uint64_t limit; - for (i = 0; i < 1; i++) { /* XXX why the loop for 1 pkt ? */ - slot = &ring->slot[ring->cur]; - slot->len = size; - p = NETMAP_BUF(ring, slot->buf_idx); - - if (nm_ring_empty(ring)) { - D("-- ouch, cannot send"); - } else { - struct tstamp *tp; - nm_pkt_copy(frame, p, size); - clock_gettime(CLOCK_REALTIME_PRECISE, &ts); - bcopy(&sent, p+42, sizeof(sent)); - tp = (struct tstamp *)(p+46); - tp->sec = (uint32_t)ts.tv_sec; - tp->nsec = (uint32_t)ts.tv_nsec; - sent++; - ring->head = ring->cur = nm_ring_next(ring, ring->cur); + if (rate_limit && tosend <= 0) { + tosend = targ->g->burst; + nexttime = timespec_add(nexttime, targ->g->tx_period); + wait_time(nexttime); } + limit = rate_limit ? tosend : targ->g->burst; + if (n > 0 && n - sent < limit) + limit = n - sent; + for (i = 0; (unsigned)i < limit; i++) { + slot = &ring->slot[ring->cur]; + slot->len = size; + p = NETMAP_BUF(ring, slot->buf_idx); + + if (nm_ring_empty(ring)) { + D("-- ouch, cannot send"); + break; + } else { + struct tstamp *tp; + nm_pkt_copy(frame, p, size); + clock_gettime(CLOCK_REALTIME_PRECISE, &ts); + bcopy(&sent, p+42, sizeof(sent)); + tp = (struct tstamp *)(p+46); + tp->sec = (uint32_t)ts.tv_sec; + tp->nsec = (uint32_t)ts.tv_nsec; + sent++; + ring->head = ring->cur = nm_ring_next(ring, ring->cur); + } + } + if (rate_limit) + tosend -= i; /* should use a parameter to decide how often to send */ if ( (rv = poll(&pfd, 1, 3000)) <= 0) { D("poll error on queue %d: %s", targ->me, @@ -1398,24 +1437,6 @@ pong_body(void *data) } -/* - * wait until ts, either busy or sleeping if more than 1ms. - * Return wakeup time. - */ -static struct timespec -wait_time(struct timespec ts) -{ - for (;;) { - struct timespec w, cur; - clock_gettime(CLOCK_REALTIME_PRECISE, &cur); - w = timespec_sub(ts, cur); - if (w.tv_sec < 0) - return cur; - else if (w.tv_sec > 0 || w.tv_nsec > 1000000) - poll(NULL, 0, 1); - } -} - static void * sender_body(void *data) { From d6519d2a2bfef955a5ecdbafa7bcf46ae04b6b99 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 10:52:14 +0200 Subject: [PATCH 0034/2207] pkt-gen: use different default burst sizes for ping and other senders --- apps/pkt-gen/pkt-gen.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index b1dcc9dc9..679c89599 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -2422,16 +2422,17 @@ struct td_desc { int ty; char *key; void *f; + int default_burst; }; static struct td_desc func[] = { - { TD_TYPE_SENDER, "tx", sender_body }, - { TD_TYPE_RECEIVER, "rx", receiver_body }, - { TD_TYPE_OTHER, "ping", ping_body }, - { TD_TYPE_OTHER, "pong", pong_body }, - { TD_TYPE_SENDER, "txseq", txseq_body }, - { TD_TYPE_RECEIVER, "rxseq", rxseq_body }, - { 0, NULL, NULL } + { TD_TYPE_SENDER, "tx", sender_body, 512 }, + { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, + { TD_TYPE_OTHER, "ping", ping_body, 1 }, + { TD_TYPE_OTHER, "pong", pong_body, 1 }, + { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, + { TD_TYPE_RECEIVER, "rxseq", rxseq_body, 512 }, + { 0, NULL, NULL, 0 } }; static int @@ -2508,11 +2509,13 @@ main(int arc, char **argv) int ch; int devqueues = 1; /* how many device queues */ + struct td_desc *fn = func; + bzero(&g, sizeof(g)); g.main_fd = -1; - g.td_body = receiver_body; - g.td_type = TD_TYPE_RECEIVER; + g.td_body = fn->f; + g.td_type = fn->ty; g.report_interval = 1000; /* report interval */ g.affinity = -1; /* ip addresses can also be a range x.x.x.x-x.x.x.y */ @@ -2522,7 +2525,6 @@ main(int arc, char **argv) g.dst_mac.name = "ff:ff:ff:ff:ff:ff"; g.src_mac.name = NULL; g.pkt_size = 60; - g.burst = 512; // default g.nthreads = 1; g.cpus = 1; // default g.forever = 1; @@ -2534,7 +2536,6 @@ main(int arc, char **argv) while ((ch = getopt(arc, argv, "46a:f:F:n:i:Il:d:s:D:S:b:c:o:p:" "T:w:WvR:XC:H:e:E:m:rP:zZA")) != -1) { - struct td_desc *fn; switch(ch) { default: @@ -2706,6 +2707,11 @@ main(int arc, char **argv) usage(); } + if (g.burst == 0) { + g.burst = fn->default_burst; + D("using default burst size: %d", g.burst); + } + g.system_cpus = i = system_ncpus(); if (g.cpus < 0 || g.cpus > i) { D("%d cpus is too high, have only %d cpus", g.cpus, i); From c8f8580641c34c2e89d43da160b2038078fc6ade Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 10:55:05 +0200 Subject: [PATCH 0035/2207] pkt-gen: avoid confusing message in ponger --- apps/pkt-gen/pkt-gen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 679c89599..3af392a8a 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1372,7 +1372,8 @@ pong_body(void *data) D("can only reply ping with 1 thread"); return NULL; } - D("understood ponger %lu but don't know how to do it", n); + if (n > 0) + D("understood ponger %lu but don't know how to do it", n); while (!targ->cancel && (n == 0 || sent < n)) { uint32_t txcur, txavail; //#define BUSYWAIT From c3a9c27379a3031590b025b8221aadbaf547f065 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 11:00:51 +0200 Subject: [PATCH 0036/2207] pkt-gen: update stats also in pinger --- apps/pkt-gen/pkt-gen.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 3af392a8a..9a339d08f 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1240,7 +1240,7 @@ ping_body(void *data) struct netmap_slot *slot; char *p; int rv; - uint64_t limit; + uint64_t limit, event = 0; if (rate_limit && tosend <= 0) { tosend = targ->g->burst; @@ -1271,6 +1271,11 @@ ping_body(void *data) ring->head = ring->cur = nm_ring_next(ring, ring->cur); } } + if (i > 0) + event++; + targ->ctr.pkts = sent; + targ->ctr.bytes = sent*size; + targ->ctr.events = event; if (rate_limit) tosend -= i; /* should use a parameter to decide how often to send */ From 2d0f2d44acbb60e5d2a3fd4f90c835d74f6bb674 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 11:14:22 +0200 Subject: [PATCH 0037/2207] pkt-gen: print total stats on pinger exit --- apps/pkt-gen/pkt-gen.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 9a339d08f..4f1df829a 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1213,6 +1213,7 @@ ping_body(void *data) struct timespec nexttime = { 0, 0}; // XXX silence compiler uint64_t sent = 0, n = targ->g->npackets; uint64_t count = 0, t_cur, t_min = ~0, av = 0; + uint64_t g_min = ~0, g_av = 0; uint64_t buckets[64]; /* bins for delays, ns */ int rate_limit = targ->g->tx_rate, tosend = 0; @@ -1347,12 +1348,18 @@ ping_body(void *data) D("k: %d .. %d\n\t%s", 1< 0) + D("RTT over %"PRIu64" packets: min %d av %d ns", sent, (int)g_min, (int)((double)g_av/sent)); + /* reset the ``used`` flag. */ targ->used = 0; From a89963bd1a0161a9fe039c52f88c8b0c101d2802 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 11:21:00 +0200 Subject: [PATCH 0038/2207] pkt-gen: avoid thread error message on ping/pong exit --- apps/pkt-gen/pkt-gen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 4f1df829a..ab196b97f 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1359,6 +1359,7 @@ ping_body(void *data) if (sent > 0) D("RTT over %"PRIu64" packets: min %d av %d ns", sent, (int)g_min, (int)((double)g_av/sent)); + targ->completed = 1; /* reset the ``used`` flag. */ targ->used = 0; @@ -1443,6 +1444,8 @@ pong_body(void *data) //D("tx %d rx %d", sent, rx); } + targ->completed = 1; + /* reset the ``used`` flag. */ targ->used = 0; From 94dc0f16d8d2eea9de83ef8cde1af3e57998f940 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 11:21:51 +0200 Subject: [PATCH 0039/2207] pkt-gen: don't print recevier stats for ping/pong --- apps/pkt-gen/pkt-gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index ab196b97f..643bf8dae 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -2430,7 +2430,7 @@ main_thread(struct glob_arg *g) delta_t = toc.tv_sec + 1e-6* toc.tv_usec; if (g->td_type == TD_TYPE_SENDER) tx_output(&cur, delta_t, "Sent"); - else + else if (g->td_type == TD_TYPE_RECEIVER) tx_output(&cur, delta_t, "Received"); } From 0be9f120bb9763fb017472fc951b1e1270b6e8f7 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 15:56:36 +0200 Subject: [PATCH 0040/2207] pkt-gen: add busywait option to ping --- apps/pkt-gen/pkt-gen.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 643bf8dae..d8571ebb7 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1206,7 +1206,7 @@ ping_body(void *data) struct targ *targ = (struct targ *) data; struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; struct netmap_if *nifp = targ->nmd->nifp; - int i, rx = 0; + int i, m, rx = 0; void *frame; int size; struct timespec ts, now, last_print; @@ -1252,7 +1252,7 @@ ping_body(void *data) limit = rate_limit ? tosend : targ->g->burst; if (n > 0 && n - sent < limit) limit = n - sent; - for (i = 0; (unsigned)i < limit; i++) { + for (m = 0; (unsigned)m < limit; m++) { slot = &ring->slot[ring->cur]; slot->len = size; p = NETMAP_BUF(ring, slot->buf_idx); @@ -1272,20 +1272,31 @@ ping_body(void *data) ring->head = ring->cur = nm_ring_next(ring, ring->cur); } } - if (i > 0) + if (m > 0) event++; targ->ctr.pkts = sent; targ->ctr.bytes = sent*size; targ->ctr.events = event; if (rate_limit) - tosend -= i; + tosend -= m; +#ifdef BUSYWAIT + rv = ioctl(pfd.fd, NIOCTXSYNC, NULL); + if (rv < 0) { + D("TXSYNC error on queue %d: %s", targ->me, + strerror(errno)); + } + again: + ioctl(pfd.fd, NIOCRXSYNC, NULL); +#else /* should use a parameter to decide how often to send */ if ( (rv = poll(&pfd, 1, 3000)) <= 0) { D("poll error on queue %d: %s", targ->me, (rv ? strerror(errno) : "timeout")); continue; } +#endif /* BUSYWAIT */ /* see what we got back */ + rx = 0; for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { ring = NETMAP_RXRING(nifp, i); @@ -1355,6 +1366,10 @@ ping_body(void *data) t_min = ~0; last_print = now; } +#ifdef BUSYWAIT + if (rx < m && ts.tv_sec <= 3 && !targ->cancel) + goto again; +#endif /* BUSYWAIT */ } if (sent > 0) From 87037716bc353fb8d39f0e363a1a30ea1a94a8a9 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 29 Mar 2017 17:48:25 +0200 Subject: [PATCH 0041/2207] pkt-gen: restored rx-as-default behaviour --- apps/pkt-gen/pkt-gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index d8571ebb7..a70136706 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -2457,8 +2457,8 @@ struct td_desc { }; static struct td_desc func[] = { + { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, /* default */ { TD_TYPE_SENDER, "tx", sender_body, 512 }, - { TD_TYPE_RECEIVER, "rx", receiver_body, 512}, { TD_TYPE_OTHER, "ping", ping_body, 1 }, { TD_TYPE_OTHER, "pong", pong_body, 1 }, { TD_TYPE_SENDER, "txseq", txseq_body, 512 }, From fff01599ec9b98865fc6141ddfb3666e5713e439 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 31 Mar 2017 15:27:57 +0200 Subject: [PATCH 0042/2207] linux: virtio-net: temporarily release rtnl lock do avoid deadlock --- LINUX/virtio_netmap.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index 1eec93fde..1b01ef351 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -322,8 +322,14 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) * memory, otherwise we have leakage. */ free_unused_bufs(vi); - /* Also free the pages allocated by the driver. */ + + /* Also free the pages allocated by the driver. Since + * Linux 4.10, free_receive_bufs() takes the rtnl lock + * to support XDP. To avoid deadlock, we temporarily + * release the lock during this call. */ + rtnl_unlock(); free_receive_bufs(vi); + rtnl_lock(); /* enable netmap mode */ virtio_netmap_set_kring_mode(na, NKR_NETMAP_ON); From 95bc31357b806d6be64ffd8c74b2a6c9eeb67a9b Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 1 Apr 2017 17:49:02 +0200 Subject: [PATCH 0043/2207] bridge: add -L option to support loopback mode --- apps/bridge/bridge.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c index df47d5e0e..7982c5bc3 100644 --- a/apps/bridge/bridge.c +++ b/apps/bridge/bridge.c @@ -143,7 +143,7 @@ static void usage(void) { fprintf(stderr, - "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [ifa [ifb [burst]]]\n"); + "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [-L] [ifa [ifb [burst]]]\n"); exit(1); } @@ -163,11 +163,12 @@ main(int argc, char **argv) struct nm_desc *pa = NULL, *pb = NULL; char *ifa = NULL, *ifb = NULL; char ifabuf[64] = { 0 }; + int loopback = 0; fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__); - while ( (ch = getopt(argc, argv, "b:ci:vw:")) != -1) { + while ((ch = getopt(argc, argv, "b:ci:vw:L")) != -1) { switch (ch) { default: D("bad option %c %s", ch, optarg); @@ -194,6 +195,9 @@ main(int argc, char **argv) case 'w': wait_link = atoi(optarg); break; + case 'L': + loopback = 1; + break; } } @@ -222,9 +226,13 @@ main(int argc, char **argv) wait_link = 4; } if (!strcmp(ifa, ifb)) { - D("same interface, endpoint 0 goes to host"); - snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa); - ifa = ifabuf; + if (!loopback) { + D("same interface, endpoint 0 goes to host"); + snprintf(ifabuf, sizeof(ifabuf) - 1, "%s^", ifa); + ifa = ifabuf; + } else { + D("same interface, loopbacking traffic"); + } } else { /* two different interfaces. Take all rings on if1 */ } From e2299b8f26c10bd3e5f02cf40be853cfb0b03af3 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 1 Apr 2017 17:55:06 +0200 Subject: [PATCH 0044/2207] bridge: add -h option --- apps/bridge/bridge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c index 7982c5bc3..374c81d77 100644 --- a/apps/bridge/bridge.c +++ b/apps/bridge/bridge.c @@ -168,10 +168,12 @@ main(int argc, char **argv) fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__); - while ((ch = getopt(argc, argv, "b:ci:vw:L")) != -1) { + while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) { switch (ch) { default: D("bad option %c %s", ch, optarg); + /* fallthrough */ + case 'h': usage(); break; case 'b': /* burst */ From 065afb76346eec4afc9ce3b25e9248d4bd751a4e Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 1 Apr 2017 18:17:52 +0200 Subject: [PATCH 0045/2207] bridge: clean up a bit and add some documentation --- apps/bridge/bridge.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c index 374c81d77..b419777b4 100644 --- a/apps/bridge/bridge.c +++ b/apps/bridge/bridge.c @@ -143,7 +143,20 @@ static void usage(void) { fprintf(stderr, - "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [-L] [ifa [ifb [burst]]]\n"); + "netmap bridge program: forward packets between two " + "network interfaces\n" + " usage(1): bridge [-v] [-i ifa] [-i ifb] [-b burst] " + "[-w wait_time] [-L]\n" + " usage(2): bridge [-v] [-w wait_time] [-L] " + "[ifa [ifb [burst]]]\n" + "\n" + " ifa and ifb are specified using the nm_open() syntax.\n" + " When ifb is missing (or is equal to ifa), bridge will\n" + " forward between between ifa and the host stack if -L\n" + " is not specified, otherwise loopback traffic on ifa.\n" + "\n" + " example: bridge -w 10 -i netmap:eth3 -i netmap:eth1\n" + ); exit(1); } @@ -165,8 +178,7 @@ main(int argc, char **argv) char ifabuf[64] = { 0 }; int loopback = 0; - fprintf(stderr, "%s built %s %s\n", - argv[0], __DATE__, __TIME__); + fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__); while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) { switch (ch) { @@ -253,7 +265,7 @@ main(int argc, char **argv) zerocopy = zerocopy && (pa->mem == pb->mem); D("------- zerocopy %ssupported", zerocopy ? "" : "NOT "); - /* setup poll(2) variables. */ + /* setup poll(2) array */ memset(pollfd, 0, sizeof(pollfd)); pollfd[0].fd = pa->fd; pollfd[1].fd = pb->fd; @@ -297,8 +309,10 @@ main(int argc, char **argv) pollfd[0].events |= POLLOUT; else pollfd[1].events |= POLLIN; + + /* poll() also cause kernel to txsync/rxsync the NICs */ ret = poll(pollfd, 2, 2500); -#endif //defined(_WIN32) || defined(BUSYWAIT) +#endif /* defined(_WIN32) || defined(BUSYWAIT) */ if (ret <= 0 || verbose) D("poll %s [0] ev %x %x rx %d@%d tx %d," " [1] ev %x %x rx %d@%d tx %d", @@ -328,14 +342,12 @@ main(int argc, char **argv) } if (pollfd[0].revents & POLLOUT) { move(pb, pa, burst); - // XXX we don't need the ioctl */ - // ioctl(me[0].fd, NIOCTXSYNC, NULL); } if (pollfd[1].revents & POLLOUT) { move(pa, pb, burst); - // XXX we don't need the ioctl */ - // ioctl(me[1].fd, NIOCTXSYNC, NULL); } + /* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here, + * kernel will txsync on next poll(). */ } D("exiting"); nm_close(pb); From f16d9fd511d4bd941f7742fd613a6c0f25e07dc6 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 3 Apr 2017 19:07:19 +0200 Subject: [PATCH 0046/2207] netmap-pt: allow passthrough of netmap pipes --- sys/dev/netmap/netmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index d572739d8..a79ee0a0b 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -1756,7 +1756,8 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags D("deprecated API, old ringid 0x%x -> ringid %x reg %d", ringid, i, reg); } - if ((flags & NR_PTNETMAP_HOST) && (reg != NR_REG_ALL_NIC || + if ((flags & NR_PTNETMAP_HOST) && ((reg != NR_REG_ALL_NIC && + reg != NR_REG_PIPE_MASTER && reg != NR_REG_PIPE_SLAVE) || flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) { D("Error: only NR_REG_ALL_NIC supported with netmap passthrough"); return EINVAL; From a6b21fe94859cadc9b3bc148566e07a64c4b2f1f Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 4 Apr 2017 11:48:35 +0200 Subject: [PATCH 0047/2207] linux: virtio: use dynamically allocated virtio-net headers This allows for cache-friendly memory layout. --- LINUX/virtio_netmap.h | 55 +++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index 1b01ef351..6b760846b 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -271,6 +271,9 @@ virtio_netmap_set_kring_mode(struct netmap_adapter *na, int mode) } +static struct virtio_net_hdr_mrg_rxbuf *shared_tx_vnet_hdr; +static struct virtio_net_hdr_mrg_rxbuf *shared_rx_vnet_hdr; + /* Register and unregister. */ static int virtio_netmap_reg(struct netmap_adapter *na, int onoff) @@ -300,6 +303,26 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) } if (onoff) { + /* TX shared virtio-net header must be zeroed because its + * content is exposed to the host. RX shared virtio-net + * header is zeroed only for security reasons. */ + BUG_ON(shared_tx_vnet_hdr); + BUG_ON(shared_rx_vnet_hdr); + shared_tx_vnet_hdr = kzalloc(sizeof(*shared_tx_vnet_hdr), + GFP_KERNEL); + if (!shared_tx_vnet_hdr) { + D("Failed to allocate TX shared vnet header"); + return ENOMEM; + } + shared_rx_vnet_hdr = kzalloc(sizeof(*shared_rx_vnet_hdr), + GFP_KERNEL); + if (!shared_rx_vnet_hdr) { + kfree(shared_tx_vnet_hdr); + shared_tx_vnet_hdr = NULL; + D("Failed to allocate RX shared vnet header"); + return ENOMEM; + } + /* Get and free any used buffers. This is necessary * before calling free_unused_bufs(), that uses * virtqueue_detach_unused_buf(). */ @@ -343,6 +366,11 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) virtio_netmap_clean_used_rings(vi, na); virtio_netmap_reclaim_unused(vi); + + kfree(shared_tx_vnet_hdr); + shared_tx_vnet_hdr = NULL; + kfree(shared_rx_vnet_hdr); + shared_rx_vnet_hdr = NULL; } if (was_up) { @@ -353,9 +381,6 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) return (error); } -static struct virtio_net_hdr_mrg_rxbuf shared_tx_vnet_hdr; -static struct virtio_net_hdr_mrg_rxbuf shared_rx_vnet_hdr; - /* Reconcile kernel and user view of the transmit ring. */ static int virtio_netmap_txsync(struct netmap_kring *kring, int flags) @@ -376,8 +401,8 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) struct virtqueue *vq = GET_TX_VQ(vi, ring_nr); struct scatterlist *sg = GET_TX_SG(vi, ring_nr); size_t vnet_hdr_len = vi->mergeable_rx_bufs ? - sizeof(shared_tx_vnet_hdr) : - sizeof(shared_tx_vnet_hdr.hdr); + sizeof(*shared_tx_vnet_hdr) : + sizeof(shared_tx_vnet_hdr->hdr); struct netmap_adapter *token; virtqueue_disable_cb(vq); @@ -423,7 +448,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) /* Initialize the scatterlist and expose it to * the hypervisor. */ COMPAT_INIT_SG(sg); - sg_set_buf(sg, &shared_tx_vnet_hdr, vnet_hdr_len); + sg_set_buf(sg, shared_tx_vnet_hdr, vnet_hdr_len); sg_set_buf(sg + 1, addr, len); nospace = virtqueue_add_outbuf(vq, sg, 2, na, GFP_ATOMIC); if (nospace) { @@ -476,8 +501,8 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags) struct virtqueue *vq = GET_RX_VQ(vi, ring_nr); struct scatterlist *sg = GET_RX_SG(vi, ring_nr); size_t vnet_hdr_len = vi->mergeable_rx_bufs ? - sizeof(shared_rx_vnet_hdr) : - sizeof(shared_rx_vnet_hdr.hdr); + sizeof(*shared_rx_vnet_hdr) : + sizeof(shared_rx_vnet_hdr->hdr); /* XXX netif_carrier_ok ? */ @@ -552,7 +577,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags) /* Initialize the scatterlist and expose it to * the hypervisor. */ COMPAT_INIT_SG(sg); - sg_set_buf(sg, &shared_rx_vnet_hdr, vnet_hdr_len); + sg_set_buf(sg, shared_rx_vnet_hdr, vnet_hdr_len); sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na)); nospace = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC); if (nospace) { @@ -589,8 +614,8 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) struct ifnet *ifp = vi->dev; struct netmap_adapter* na = NA(ifp); size_t vnet_hdr_len = vi->mergeable_rx_bufs ? - sizeof(shared_rx_vnet_hdr) : - sizeof(shared_rx_vnet_hdr.hdr); + sizeof(*shared_rx_vnet_hdr) : + sizeof(shared_rx_vnet_hdr->hdr); unsigned int r; if (!nm_native_on(na)) @@ -620,7 +645,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) slot = &ring->slot[i]; addr = NMB(na, slot); COMPAT_INIT_SG(sg); - sg_set_buf(sg, &shared_rx_vnet_hdr, vnet_hdr_len); + sg_set_buf(sg, shared_rx_vnet_hdr, vnet_hdr_len); sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na)); err = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC); if (err < 0) { @@ -667,12 +692,6 @@ virtio_netmap_attach(struct virtnet_info *vi) { struct netmap_adapter na; /* temporary container of methods */ - /* TX shared virtio-net header must be zeroed because its - * content is exposed to the host. RX shared virtio-net - * header is zeroed only for security reasons. */ - bzero(&shared_tx_vnet_hdr, sizeof(shared_tx_vnet_hdr)); - bzero(&shared_rx_vnet_hdr, sizeof(shared_rx_vnet_hdr)); - bzero(&na, sizeof(na)); na.ifp = vi->dev; From 36ede9084d0796b7344071191316c4896e0dc7b3 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 4 Apr 2017 12:51:55 +0200 Subject: [PATCH 0048/2207] linux: virtio: always enable TX interrupts when TX vring is full There was a bug such that if txsync is called but does not publish any TX descriptor, the virtqueue interrupt are not re-enabled (and won't forever). --- LINUX/virtio_netmap.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index 6b760846b..e2af8e0ca 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -404,6 +404,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) sizeof(*shared_tx_vnet_hdr) : sizeof(shared_tx_vnet_hdr->hdr); struct netmap_adapter *token; + int nospace = 0; virtqueue_disable_cb(vq); @@ -434,8 +435,6 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) nm_i = kring->nr_hwcur; if (nm_i != head) { /* we have new packets to send */ - int nospace = 0; - nic_i = netmap_idx_k2n(kring, nm_i); for (n = 0; nm_i != head; n++) { struct netmap_slot *slot = &ring->slot[nm_i]; @@ -465,16 +464,15 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) /* Update hwcur depending on where we stopped. */ kring->nr_hwcur = nm_i; /* note we migth break early */ - - /* No more free virtio descriptors or netmap slots? Ask the - * hypervisor for notifications, possibly only when a - * considerable amount of work has been done. - */ - if (nospace || nm_kr_txempty(kring)) { - virtqueue_enable_cb_delayed(vq); - } } out: + /* No more free virtio descriptors or netmap slots? Ask the + * hypervisor for notifications, possibly only when it has + * freed a considerable amount of pending descriptors. + */ + if (nm_kr_txempty(kring) || nospace) { + virtqueue_enable_cb_delayed(vq); + } return 0; } From dfa95b9f93797d2d0b0de3e30ef70537cfa1851d Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 3 Apr 2017 15:57:30 +0200 Subject: [PATCH 0049/2207] mem: debug put/get operations --- sys/dev/netmap/netmap_mem2.c | 7 +++++-- sys/dev/netmap/netmap_mem2.h | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index 982d84e7a..23325846b 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -255,7 +255,7 @@ static struct netmap_mem_d *netmap_last_mem_d = &nm_mem; NM_MTX_T nm_mem_list_lock; struct netmap_mem_d * -netmap_mem_get(struct netmap_mem_d *nmd) +__netmap_mem_get(struct netmap_mem_d *nmd, const char *func, int line) { NM_MTX_LOCK(nm_mem_list_lock); nmd->refcount++; @@ -265,7 +265,7 @@ netmap_mem_get(struct netmap_mem_d *nmd) } void -netmap_mem_put(struct netmap_mem_d *nmd) +__netmap_mem_put(struct netmap_mem_d *nmd, const char *func, int line) { int last; NM_MTX_LOCK(nm_mem_list_lock); @@ -524,6 +524,7 @@ nm_mem_assign_id_locked(struct netmap_mem_d *nmd) scan->prev = nmd; netmap_last_mem_d = nmd; nmd->refcount = 1; + NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); error = 0; break; } @@ -568,6 +569,7 @@ netmap_mem_find(nm_memid_t id) do { if (!(nmd->flags & NETMAP_MEM_HIDDEN) && nmd->nm_id == id) { nmd->refcount++; + NM_DBG_REFC(nmd, __FUNCTION__, __LINE__); NM_MTX_UNLOCK(nm_mem_list_lock); return nmd; } @@ -2288,6 +2290,7 @@ netmap_mem_pt_guest_find_memid(nm_memid_t mem_id) ((struct netmap_mem_ptg *)(scan))->host_mem_id == mem_id) { mem = scan; mem->refcount++; + NM_DBG_REFC(mem, __FUNCTION__, __LINE__); break; } scan = scan->next; diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h index 102c66d79..66e688afd 100644 --- a/sys/dev/netmap/netmap_mem2.h +++ b/sys/dev/netmap/netmap_mem2.h @@ -142,8 +142,10 @@ struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_ u_int extra_bufs, u_int npipes, int* error); void netmap_mem_delete(struct netmap_mem_d *); -struct netmap_mem_d* netmap_mem_get(struct netmap_mem_d *); -void netmap_mem_put(struct netmap_mem_d *); +#define netmap_mem_get(d) __netmap_mem_get(d, __FUNCTION__, __LINE__) +#define netmap_mem_put(d) __netmap_mem_put(d, __FUNCTION__, __LINE__) +struct netmap_mem_d* __netmap_mem_get(struct netmap_mem_d *, const char *, int); +void __netmap_mem_put(struct netmap_mem_d *, const char *, int); struct netmap_mem_d* netmap_mem_find(nm_memid_t); #ifdef WITH_PTNETMAP_GUEST From 4d01727ddb902e92e75c35f5c4739a5768506099 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 3 Apr 2017 15:36:38 +0200 Subject: [PATCH 0050/2207] always release temporary allocator reference during REGIF --- sys/dev/netmap/netmap.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index a79ee0a0b..73a52afcf 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2316,6 +2316,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread } if (nmr->nr_arg2) { + /* find the allocator and get a reference */ nmd = netmap_mem_find(nmr->nr_arg2); if (nmd == NULL) { error = EINVAL; @@ -2378,9 +2379,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread } while (0); if (error) { netmap_unget_na(na, ifp); - if (nmd) - netmap_mem_put(nmd); } + /* release the reference from netmap_mem_find() or + * netmap_mem_ext_create() + */ + if (nmd) + netmap_mem_put(nmd); NMG_UNLOCK(); break; From 3c12a9bc7f3ff8125764c0efc0d5e3afb98949d8 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 4 Apr 2017 22:55:00 +0200 Subject: [PATCH 0051/2207] remove old files --- private/.gitattributes | 1 - private/LINUX/bnx2x_netmap_linux.h | 595 ------- private/LINUX/mlx4_netmap_linux.h | 726 -------- private/LINUX/vhost-port/Makefile | 32 - private/LINUX/vhost-port/buildpkt.c | 216 --- private/LINUX/vhost-port/buildpkt.h | 26 - private/LINUX/vhost-port/clean.sh | 18 - private/LINUX/vhost-port/e1000_regs.h | 893 ---------- private/LINUX/vhost-port/init.sh | 29 - private/LINUX/vhost-port/net.c | 1279 -------------- private/LINUX/vhost-port/paravirt.h | 153 -- private/LINUX/vhost-port/test.c | 682 -------- private/LINUX/vhost-port/tun_alloc.c | 59 - private/LINUX/vhost-port/tun_alloc.h | 26 - private/LINUX/vhost-port/v1000.c | 335 ---- private/LINUX/vhost-port/v1000.h | 104 -- private/LINUX/vhost-port/v1000_user.h | 42 - .../LINUX/vhost-port/vhost-code-tracking.txt | 7 - .../wip-patches/diff--mellanox--30300--30800 | 145 -- .../wip-patches/diff--mlx4--20630--30200 | 163 -- private/NOTES | 1193 ------------- private/OSX/README | 7 - private/OSX/netmap.kext/Contents/Info.plist | 35 - .../OSX/netmap.kext/Contents/MacOS/Makefile | 9 - .../netmap.kext/Contents/MacOS/netmap_osx.c | 23 - .../OSX/netmap.kext/Contents/MacOS/osx_glue.h | 41 - private/README | 3 - private/extra/20130220-bsd-em-head.diff | 825 --------- private/extra/20130222-bsd-em-head.diff | 546 ------ private/extra/20130224-qemu-head.diff | 1499 ----------------- private/extra/20140109-click.diff | 309 ---- private/extra/README | 8 - private/extra/bro-netmap.diff | 95 -- private/extra/bsd-lem-intr_latency.diff | 33 - private/extra/e1000-paravirt.diff | 396 ----- private/extra/libpcap-netmap.diff | 389 ----- private/extra/netreceive.c | 264 --- private/extra/paravirt.h | 153 -- private/extra/python/Makefile | 13 - private/extra/python/README | 100 -- private/extra/python/netmap.c | 345 ---- private/extra/python/netmap_classes.h | 110 -- private/extra/python/netmap_desc.c | 247 --- private/extra/python/netmap_interface.c | 225 --- private/extra/python/netmap_manager.c | 582 ------- private/extra/python/netmap_memory.c | 126 -- private/extra/python/netmap_ring.c | 338 ---- private/extra/python/netmap_slot.c | 240 --- private/extra/python/pktgen.py | 61 - private/extra/python/pktman.py | 292 ---- private/extra/python/setup.py | 15 - private/extra/python/test.py | 14 - .../extra/qemu-1.2.0-e1000-mitigation.diff | 157 -- private/extra/tstmp.diff | 146 -- private/extra/wireshark-netmap.diff | 83 - private/netmap-drop-2.diff | 435 ----- private/qemu/PICOBSD | 154 -- private/qemu/PICOBSD.amd64 | 193 --- private/qemu/PICOBSD.arm | 141 -- private/qemu/PICOBSD.hints | 39 - private/qemu/config | 71 - private/qemu/crunch.conf | 245 --- private/qemu/crunch.conf.amd64 | 209 --- private/qemu/floppy.tree.exclude | 2 - private/qemu/floppy.tree/boot/loader.conf | 2 - private/qemu/floppy.tree/etc/motd | 12 - private/qemu/floppy.tree/etc/rc.conf.defaults | 188 --- private/qemu/floppy.tree/root/.profile | 5 - private/qemu/floppy.tree/root/bri | 4 - private/qemu/floppy.tree/root/bri.click | 19 - private/qemu/floppy.tree/root/rates | 2 - private/qemu/floppy.tree/root/start_test | 7 - private/qemu/floppy.tree/root/t1.ck | 11 - private/qemu/floppy.tree/root/t2.ck | 14 - private/qemu/floppy.tree/root/test | 84 - private/qemu/floppy.tree/test | 52 - private/qemu/run | 158 -- private/sys/dev/netmap/cxgbe_netmap.h | 145 -- private/sys/dev/netmap/if_bge_netmap.h | 360 ---- private/sys/dev/netmap/if_sfxge_netmap.h | 340 ---- private/test/Makefile | 10 - private/test/arp-daemon.c | 355 ---- private/test/arp-request.c | 337 ---- private/test/interrupt_stats.c | 50 - private/test/lro.html | 59 - private/test/nest.c | 20 - private/test/netmap_drop.diff | 567 ------- private/test/test-nest | 27 - private/test/test_device.c | 191 --- private/test/test_device.h | 12 - private/test/test_speed.c | 83 - private/test/test_speed.h | 68 - private/test/test_userspace.c | 58 - private/test/test_userspace.h | 175 -- private/test/testnetmap.c | 22 - private/test/testnetmap.h | 34 - private/tools/luigi.sh | 55 - private/tools/qemu/PICOBSD | 154 -- private/tools/qemu/PICOBSD.hints | 39 - private/tools/qemu/config | 68 - private/tools/qemu/crunch.conf | 209 --- private/tools/qemu/floppy.tree.exclude | 2 - private/tools/qemu/floppy.tree/etc/motd | 9 - .../qemu/floppy.tree/etc/rc.conf.defaults | 188 --- .../tools/qemu/floppy.tree/etc/sysctl.conf | 1 - private/tools/qemu/floppy.tree/root/.profile | 2 - private/tools/qemu/floppy.tree/root/bri.click | 19 - private/tools/qemu/floppy.tree/root/rates | 2 - .../tools/qemu/floppy.tree/root/start_test | 7 - private/tools/qemu/floppy.tree/root/t1.ck | 11 - private/tools/qemu/floppy.tree/root/t2.ck | 14 - private/tools/qemu/floppy.tree/root/test | 83 - .../qemu/floppy.tree/root/test_coarse.sh | 35 - private/tools/qemu/floppy.tree/test | 42 - private/vale.4 | 253 --- 115 files changed, 20606 deletions(-) delete mode 100644 private/.gitattributes delete mode 100644 private/LINUX/bnx2x_netmap_linux.h delete mode 100644 private/LINUX/mlx4_netmap_linux.h delete mode 100644 private/LINUX/vhost-port/Makefile delete mode 100644 private/LINUX/vhost-port/buildpkt.c delete mode 100644 private/LINUX/vhost-port/buildpkt.h delete mode 100755 private/LINUX/vhost-port/clean.sh delete mode 100644 private/LINUX/vhost-port/e1000_regs.h delete mode 100755 private/LINUX/vhost-port/init.sh delete mode 100644 private/LINUX/vhost-port/net.c delete mode 100644 private/LINUX/vhost-port/paravirt.h delete mode 100644 private/LINUX/vhost-port/test.c delete mode 100644 private/LINUX/vhost-port/tun_alloc.c delete mode 100644 private/LINUX/vhost-port/tun_alloc.h delete mode 100644 private/LINUX/vhost-port/v1000.c delete mode 100644 private/LINUX/vhost-port/v1000.h delete mode 100644 private/LINUX/vhost-port/v1000_user.h delete mode 100644 private/LINUX/vhost-port/vhost-code-tracking.txt delete mode 100644 private/LINUX/wip-patches/diff--mellanox--30300--30800 delete mode 100644 private/LINUX/wip-patches/diff--mlx4--20630--30200 delete mode 100644 private/NOTES delete mode 100644 private/OSX/README delete mode 100644 private/OSX/netmap.kext/Contents/Info.plist delete mode 100644 private/OSX/netmap.kext/Contents/MacOS/Makefile delete mode 100644 private/OSX/netmap.kext/Contents/MacOS/netmap_osx.c delete mode 100644 private/OSX/netmap.kext/Contents/MacOS/osx_glue.h delete mode 100644 private/README delete mode 100644 private/extra/20130220-bsd-em-head.diff delete mode 100644 private/extra/20130222-bsd-em-head.diff delete mode 100644 private/extra/20130224-qemu-head.diff delete mode 100644 private/extra/20140109-click.diff delete mode 100644 private/extra/README delete mode 100644 private/extra/bro-netmap.diff delete mode 100644 private/extra/bsd-lem-intr_latency.diff delete mode 100644 private/extra/e1000-paravirt.diff delete mode 100644 private/extra/libpcap-netmap.diff delete mode 100644 private/extra/netreceive.c delete mode 100644 private/extra/paravirt.h delete mode 100644 private/extra/python/Makefile delete mode 100644 private/extra/python/README delete mode 100644 private/extra/python/netmap.c delete mode 100644 private/extra/python/netmap_classes.h delete mode 100644 private/extra/python/netmap_desc.c delete mode 100644 private/extra/python/netmap_interface.c delete mode 100644 private/extra/python/netmap_manager.c delete mode 100644 private/extra/python/netmap_memory.c delete mode 100644 private/extra/python/netmap_ring.c delete mode 100644 private/extra/python/netmap_slot.c delete mode 100644 private/extra/python/pktgen.py delete mode 100644 private/extra/python/pktman.py delete mode 100644 private/extra/python/setup.py delete mode 100644 private/extra/python/test.py delete mode 100644 private/extra/qemu-1.2.0-e1000-mitigation.diff delete mode 100644 private/extra/tstmp.diff delete mode 100644 private/extra/wireshark-netmap.diff delete mode 100644 private/netmap-drop-2.diff delete mode 100644 private/qemu/PICOBSD delete mode 100644 private/qemu/PICOBSD.amd64 delete mode 100644 private/qemu/PICOBSD.arm delete mode 100644 private/qemu/PICOBSD.hints delete mode 100644 private/qemu/config delete mode 100644 private/qemu/crunch.conf delete mode 100644 private/qemu/crunch.conf.amd64 delete mode 100644 private/qemu/floppy.tree.exclude delete mode 100644 private/qemu/floppy.tree/boot/loader.conf delete mode 100644 private/qemu/floppy.tree/etc/motd delete mode 100644 private/qemu/floppy.tree/etc/rc.conf.defaults delete mode 100644 private/qemu/floppy.tree/root/.profile delete mode 100644 private/qemu/floppy.tree/root/bri delete mode 100644 private/qemu/floppy.tree/root/bri.click delete mode 100644 private/qemu/floppy.tree/root/rates delete mode 100644 private/qemu/floppy.tree/root/start_test delete mode 100644 private/qemu/floppy.tree/root/t1.ck delete mode 100644 private/qemu/floppy.tree/root/t2.ck delete mode 100755 private/qemu/floppy.tree/root/test delete mode 100755 private/qemu/floppy.tree/test delete mode 100755 private/qemu/run delete mode 100644 private/sys/dev/netmap/cxgbe_netmap.h delete mode 100644 private/sys/dev/netmap/if_bge_netmap.h delete mode 100644 private/sys/dev/netmap/if_sfxge_netmap.h delete mode 100644 private/test/Makefile delete mode 100644 private/test/arp-daemon.c delete mode 100644 private/test/arp-request.c delete mode 100644 private/test/interrupt_stats.c delete mode 100644 private/test/lro.html delete mode 100644 private/test/nest.c delete mode 100644 private/test/netmap_drop.diff delete mode 100644 private/test/test-nest delete mode 100644 private/test/test_device.c delete mode 100644 private/test/test_device.h delete mode 100644 private/test/test_speed.c delete mode 100644 private/test/test_speed.h delete mode 100644 private/test/test_userspace.c delete mode 100644 private/test/test_userspace.h delete mode 100644 private/test/testnetmap.c delete mode 100644 private/test/testnetmap.h delete mode 100644 private/tools/luigi.sh delete mode 100644 private/tools/qemu/PICOBSD delete mode 100644 private/tools/qemu/PICOBSD.hints delete mode 100644 private/tools/qemu/config delete mode 100644 private/tools/qemu/crunch.conf delete mode 100644 private/tools/qemu/floppy.tree.exclude delete mode 100644 private/tools/qemu/floppy.tree/etc/motd delete mode 100644 private/tools/qemu/floppy.tree/etc/rc.conf.defaults delete mode 100644 private/tools/qemu/floppy.tree/etc/sysctl.conf delete mode 100644 private/tools/qemu/floppy.tree/root/.profile delete mode 100644 private/tools/qemu/floppy.tree/root/bri.click delete mode 100644 private/tools/qemu/floppy.tree/root/rates delete mode 100644 private/tools/qemu/floppy.tree/root/start_test delete mode 100644 private/tools/qemu/floppy.tree/root/t1.ck delete mode 100644 private/tools/qemu/floppy.tree/root/t2.ck delete mode 100755 private/tools/qemu/floppy.tree/root/test delete mode 100644 private/tools/qemu/floppy.tree/root/test_coarse.sh delete mode 100755 private/tools/qemu/floppy.tree/test delete mode 100644 private/vale.4 diff --git a/private/.gitattributes b/private/.gitattributes deleted file mode 100644 index 43d156222..000000000 --- a/private/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* merge=ignore -diff diff --git a/private/LINUX/bnx2x_netmap_linux.h b/private/LINUX/bnx2x_netmap_linux.h deleted file mode 100644 index a8b94bb20..000000000 --- a/private/LINUX/bnx2x_netmap_linux.h +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright (C) 2012-2014 Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * $Id: bnx2x_netmap_linux.h $ - * - * netmap support for bnx2x (LINUX version) - * - * The programming manual is publicly available at - * http://www.broadcom.com/collateral/pg/57710_57711-PG200-R.pdf - * http://www.broadcom.com/collateral/pg/57XX-PG105-R.pdf - * but they do not match the code in the Linux or FreeBSD driversi (bnx2x, bxe). - * The FreeBSD driver has a number of comments in the code that explain a lot - * of the constraints in the firmware. - * - * Of particular relevance: - -The buffer descriptor (bd) and packet (pkt) indexes handled by -the firmware are 16-bit values, no matter how big the rings are. -The current driver then has a number of BD slots which is also -a power of 2 so truncation does the right thing when accessing the arrays. -Conversion of these indexes to NIC ring indexes should be done -using TX_BD() and RX_BD() macros - -In the linux driver, NUM_TX_RINGS and NUM_RX_RINGS do not indicate -NIC rings but the number of 4K pages used to store the rings. -NIC rings are made of 8(rx) or 16(tx) byte entries, with the -last 16 bytes in each page containing the pointer to the next page. -Hence index increment should use the NEXT_TX_IDX() and NEXT_RX_IDX() -macros to skip the link entries. - -RX completions and other events are reported through a Request Completion Queue -(RCQ) with 16-byte entries, again linked with the usual scheme. -Navigate through them with the NEXT_RCQ_IDX() macro, and truncate -the values with RCQ_BD() - -The TX ring REQUIRES at least two BD per packet even though the -programming manual says differently. - -For each Class Of Service (COS) we have NUM_TX_BD slots in total. - - */ - - -#include -#include -#include -#define SOFTC_T bnx2x - -int bnx2x_netmap_config(struct SOFTC_T *adapter); - -#ifdef NETMAP_BNX2X_MAIN -static inline void -nm_pkt_dump(int i, char *buf, int len) -{ - uint8_t *s = buf+6, *d = buf; - RD(10, "%d len %4d %02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x", - i, - len, - s[0], s[1], s[2], s[3], s[4], s[5], - d[0], d[1], d[2], d[3], d[4], d[5]); -} - -/* - * Some diagnostic to figure out the configuration. - */ -static inline void -bnx2x_netmap_diag(struct ifnet *ifp) -{ - struct SOFTC_T *bp = netdev_priv(ifp); - struct bnx2x_fastpath *fp = &bp->fp[0]; - struct bnx2x_fp_txdata *txdata = &fp->txdata[0]; - int i; - - D("---- device %s ---- fp0 %p txdata %p q %d txq %d rxq %d -------", - ifp->name, fp, txdata, BNX2X_NUM_QUEUES(bp), - ifp->num_tx_queues, ifp->num_rx_queues); - // txq is actually 48, whereas rxq is a reasonable number. - for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) { - fp = &bp->fp[i]; - txdata = &fp->txdata[0]; - D("TX%2d: desc_ring %p %p cid %d txq_index %d cons_sb %p", i, - txdata->tx_desc_ring, - &txdata->tx_desc_ring[10].start_bd, - txdata->cid, txdata->txq_index, - txdata->tx_cons_sb); - } -} - -/* - * Register/unregister. We are already under (netmap) core lock. - * Only called on the first register or the last unregister. - */ -static int -bnx2x_netmap_reg(struct netmap_adapter *na, int onoff) -{ - struct ifnet *ifp = na->ifp; - struct SOFTC_T *adapter = netdev_priv(ifp); - int error = 0, need_load = 0; - - /* - * On enable, flush pending ops, set flag and reinit rings. - * On disable, flush again, and restart the interface. - */ - D("setting netmap mode for %s to %s", na->name, onoff ? "ON" : "OFF"); - // bnx2x_netmap_diag(ifp); - - rtnl_lock(); // required by bnx2x_nic_unload() - if (netif_running(ifp)) { - D("unloading the nic"); - bnx2x_nic_unload(adapter, UNLOAD_NORMAL); - need_load = 1; - } - -if (0) // only load/unload - error = EINVAL; -else - if (onoff) { /* enable netmap mode */ - nm_set_native_flags(na); - D("-------------- set the SKIP_INTR flag"); - // XXX na->na_flags |= NAF_SKIP_INTR; /* during load, use regular interrupts */ - } else { /* reset normal mode */ - nm_clear_native_flags(na); - } - if (need_load) { - D("loading the NIC"); - bnx2x_nic_load(adapter, LOAD_NORMAL); - } - rtnl_unlock(); - return (error); -} - - -/* - * Reconcile kernel and user view of the transmit ring. - -Broadcom: the tx routine is bnx2x_start_xmit() - -The card has 16 hardware queues ("fastpath contexts"), -each possibly with several "Class of Service" (COS) queues. -(the data sheet says up to 16 COS, but the software seems to use 4). -The linux driver numbers queues 0..15 for COS=0, 16..31 for COS=1, -and so on. The low 4 bits are used to indicate the fastpath context. - -The tx ring is made of one or more pages containing Buffer Descriptors (BD) -stored in fp->tx_desc_ring[], -each 16-byte long (NOTE: different from the rx side). The last BD in a page -(also 16 bytes) points to the next page (8 for physical address + 8 reserved bytes). -These page are presumably contiguous in virtual address space so all it takes -is to skip the reserved entries when we reach the last entry on the page -(MAX_TX_DESC_CNT - 1, or 255). - -The driver differs from the documentation. In particular the END_BD flag -seems not to exist anymore, presumably the firmware can derive the number -of buffers from the START_BD flag plus nbd. -It is unclear from the docs whether we can have only one BD per packet -The field to initialize are (all in LE format) - addr_lo, addr_hi LE32, physical buffer address - nbytes LE16, packet size - vlan LE16 ?? producer index ??? - nbd L8 2 seems the min required - bd_flags.as_bitfield L8 START_BD XXX no END_BD - general_data L8 0 0..5: header_nbd; 6-7: addr type - -and once we are done 'ring the doorbell' (write to a register) -to tell the NIC the first empty slot in the queue. - - struct bnx2x_fastpath *fp = &bp->fp[ring_nr % 16]; - struct bnx2x_fp_txdata *txdata = &fp->txdata[ring_nr / 16]; - -In txdata, The HOST ring is tx_buf_ring, and the NIC RING tx_desc_ring, -cid is the 'context id' or ring_nr % 16 . - -We operate under the assumption that we use only the first -set of queues. - - */ -static int -bnx2x_netmap_txsync(struct netmap_adapter *na, u_int ring_nr, int flags) -{ - struct ifnet *ifp = na->ifp; - struct netmap_kring *kring = &na->tx_rings[ring_nr]; - struct netmap_ring *ring = kring->ring; - u_int nm_i; /* index into the netmap ring */ - u_int nic_i; /* index into the NIC ring */ - u_int n; - u_int const lim = kring->nkr_num_slots - 1; - u_int const head = kring->rhead; - /* - * interrupts on every tx packet are expensive so request - * them every half ring, or where NS_REPORT is set - */ - u_int report_frequency = kring->nkr_num_slots >> 1; - - struct SOFTC_T *adapter = netdev_priv(ifp); - struct bnx2x_fastpath *fp = &adapter->fp[ring_nr]; - struct bnx2x_fp_txdata *txdata = &fp->txdata[0]; - int error = 0; - - if (!netif_carrier_ok(ifp)) { - goto out; - } - - nm_i = kring->nr_hwcur; - if (nm_i != head) { /* we have new packets to send */ - if (txdata->tx_desc_ring == NULL) { - D("------------------- bad! tx_desc_ring not set"); - error = EINVAL; - goto err; - } - nic_i = txdata->tx_bd_prod; - ND(10,"=======>========== send from %d to %d at bd %d", j, k, l); - for (n = 0; nm_i != head; n++) { - struct netmap_slot *slot = &ring->slot[nm_i]; - uint16_t len = slot->len; - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - /* device-specific */ - struct eth_tx_start_bd *bd = - &txdata->tx_desc_ring[TX_BD(nic_i)].start_bd; - uint16_t mac_type = UNICAST_ADDRESS; - - // nm_pkt_dump(j, addr, len); - ND(5, "start_bd j %d l %d is %p", j, l, bd); - - NM_CHECK_ADDR_LEN(addr, len); - - if (slot->flags & NS_BUF_CHANGED) { - /* buffer has changed, unload and reload map */ - // netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr); - } - slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); - /* - * Fill the slot in the NIC ring. FreeBSD's if_bxe.c has - * a lot of notes including: - * - min number of nbd is 2 even if the parsing bd is not used, - * otherwise we get an MC assert! error - * - if vlan is not used, firmware expect a packet number there. - * - do we care for mac-type ? - */ - - bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; - bd->vlan_or_ethertype = cpu_to_le16(txdata->tx_pkt_prod); - - bd->addr_lo = cpu_to_le32(U64_LO(paddr)); - bd->addr_hi = cpu_to_le32(U64_HI(paddr)); - bd->nbytes = cpu_to_le16(len); - bd->nbd = cpu_to_le16(2); - if (unlikely(is_multicast_ether_addr(addr))) { - if (is_broadcast_ether_addr(addr)) - mac_type = BROADCAST_ADDRESS; - else - mac_type = MULTICAST_ADDRESS; - } - SET_FLAG(bd->general_data, ETH_TX_START_BD_ETH_ADDR_TYPE, mac_type); - SET_FLAG(bd->general_data, ETH_TX_START_BD_HDR_NBDS, 1 /* XXX */ ); - - nm_i = nm_next(nm_i, lim); - txdata->tx_pkt_prod++; - nic_i = NEXT_TX_IDX(nic_i); // skip link fields. - /* clear the parsing block */ - bzero(&txdata->tx_desc_ring[TX_BD(nic_i)], sizeof(*bd)); - nic_i = NEXT_TX_IDX(nic_i); // skip link fields. - } - kring->nr_hwcur = head; - /* decrease avail by # of packets sent minus previous ones */ - - /* XXX Check how to deal with nkr_hwofs */ - /* these two are always in sync. */ - txdata->tx_bd_prod = nic_i; - txdata->tx_db.data.prod = nic_i; // update doorbell - - wmb(); /* synchronize writes to the NIC ring */ - barrier(); // XXX - /* (re)start the transmitter up to slot l (excluded) */ - ND(5, "doorbell cid %d data 0x%x", txdata->cid, txdata->tx_db.raw); - DOORBELL(adapter, ring_nr, txdata->tx_db.raw); - } - - /* - * Second part: reclaim buffers for completed transmissions. - * - * Reclaim buffers for completed transmissions, as in bnx2x_tx_int(). - * Maybe we could do it lazily. - */ - for (n=0;n < 5;n++) { - /* - * Record completed transmissions. - * The card writes the current (pkt ?) index in memory in - * le16_to_cpu(*txdata->tx_cons_sb); - * This seems to be a sequential index with no skips modulo 2^16 - * irrespective of the actual ring size. - * We need to adjust buffer and packet indexes. - * In netmap we can use 1 pkt/1bd so the pkt_cons - * is an index in the netmap buffer. The bd_index - * however should be computed with some trick. - * We (re)use the driver's txr->tx_pkt_cons to keep - * track of the most recently completed transmission. - */ - nic_i = le16_to_cpu(*txdata->tx_cons_sb); - if (nic_i != txdata->tx_pkt_cons) { // XXX buffers, not slots - ND(5, "txr %d completed %d packets", ring_nr, delta); - /* some tx completed, advance hwtail. */ - kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); - /* XXX lazy solution - consume 2 buffers */ - for (;txdata->tx_pkt_cons != nic_i; txdata->tx_pkt_cons++) { - txdata->tx_bd_cons = NEXT_TX_IDX(txdata->tx_bd_cons); - txdata->tx_bd_cons = NEXT_TX_IDX(txdata->tx_bd_cons); - } - } - } - if (txdata->tx_pkt_cons != txdata->tx_pkt_prod) { - // XXX kick the sender, does not seem to help. - wmb(); /* synchronize writes to the NIC ring */ - barrier(); // XXX - /* (re)start the transmitter up to slot l (excluded) */ - ND(5, "doorbell cid %d data 0x%x", txdata->cid, txdata->tx_db.raw); - DOORBELL(adapter, ring_nr, txdata->tx_db.raw); - } -out: - return 0; -err: - if (error) - return netmap_ring_reinit(kring); - return 0; -} - - -/* - * Reconcile kernel and user view of the receive ring. - -Broadcom: - -see bnx2x_cmn.c :: bnx2x_rx_int() - -the software keeps two sets of producer and consumer indexes: -one in the completion queue (fp->rx_comp_cons, fp->rx_comp_prod) -and one in the buffer descriptors (fp->rx_bd_cons, fp->rx_bd_prod). - -The processing loop iterates on the completion queue, and -buffers are consumed only after 'fastpath' events. - -The hardware reports the first empty slot through -(*fp->rx_cons_sb) (skipping the link field). - -20120913 -The code in bnx2x_rx_int() has a strange thing, it keeps -two running counters bd_prod and bd_prod_fw which are -apparently the same. - - - */ -static int -bnx2x_netmap_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags) -{ - struct ifnet *ifp = na->ifp; - struct netmap_kring *kring = &na->rx_rings[ring_nr]; - struct netmap_ring *ring = kring->ring; - u_int nm_i; /* index into the netmap ring */ - u_int nic_i; /* index into the NIC ring */ - u_int n; - u_int const lim = kring->nkr_num_slots - 1; - u_int const head = kring->rhead; - int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; - - struct SOFTC_T *adapter = netdev_priv(ifp); - struct bnx2x_fastpath *rxr = &adapter->fp[ring_nr]; - uint16_t hw_comp_cons, sw_comp_cons; - -return 0; // XXX unsupported now - - if (!netif_carrier_ok(ifp)) - return 0; - - if (head > lim) - return netmap_ring_reinit(kring); - - rmb(); - /* - * First part, import newly received packets into the netmap ring. - * - * rxr->next_to_check is set to 0 on a ring reinit - */ - - /* scan the completion queue to see what is going on. - * Note that we do not use l here. - */ - sw_comp_cons = RCQ_BD(rxr->rx_comp_cons); - nic_i = rxr->rx_bd_cons; - nm_i = netmap_idx_n2k(kring, nic_i); - hw_comp_cons = le16_to_cpu(*rxr->rx_cons_sb); - if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) - hw_comp_cons++; - - rmb(); // XXX -ND("start ring %d k %d lim %d hw_comp_cons %d", ring_nr, k, lim, hw_comp_cons); -goto done; // XXX debugging - - if (netmap_no_pendintr || force_update) { - uint16_t slot_flags = kring->nkr_slot_flags; - - for (n = 0; sw_comp_cons != hw_comp_cons; sw_comp_cons = RCQ_BD(NEXT_RCQ_IDX(sw_comp_cons)) ) { - union eth_rx_cqe *cqe = &rxr->rx_comp_ring[l]; - struct eth_fast_path_rx_cqe *cqe_fp = &cqe->fast_path_cqe; - // XXX fetch event, process slowpath as in the main driver, - if (1 /* slowpath */) - continue; - ring->slot[nm_i].len = le16_to_cpu(cqe_fp->pkt_len_or_gro_seg_len); - ring->slot[nm_i].flags = slot_flags; - - nic_i = NEXT_RX_IDX(nic_i); - nm_i = nm_next(nic_i, lim) - n++; - } - if (n) { /* update the state variables */ - rxr->rx_comp_cons = sw_comp_cons; // XXX adjust nkr_hwofs - rxr->rx_bd_cons = nic_i; // XXX adjust nkr_hwofs - kring->nr_hwtail = nm_i; - } - kring->nr_kflags &= ~NKR_PENDINTR; - } - - /* - * Second part: skip past packets that userspace has released. - */ - nm_i = kring->nr_hwcur; - if (nm_i != head) { /* userspace has released some packets. */ - uint16_t sw_comp_prod = 0; // XXX - - nic_i = netmap_idx_k2n(kring, nic_i); - for (n = 0; nm_i != head; n++) { -#if 0 // XXX receive code still incomplete - struct netmap_slot *slot = &ring->slot[nm_i]; - union ixgbe_adv_rx_desc *curr = IXGBE_RX_DESC_ADV(rxr, nic_i); - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - if (addr == NETMAP_BUF_BASE(na)) /* bad buf */ - goto ring_reset; - - if (slot->flags & NS_BUF_CHANGED) { - // netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr); - slot->flags &= ~NS_BUF_CHANGED; - } - curr->wb.upper.status_error = 0; - curr->read.pkt_addr = htole64(paddr); -#endif // XXX - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - } - kring->nr_hwcur = head; - // XXXX cons = ... - wmb(); - /* Update producers */ - bnx2x_update_rx_prod(adapter, rxr, nic_i, sw_comp_prod, - rxr->rx_sge_prod); - } -done: - - return 0; - -ring_reset: - return netmap_ring_reinit(kring); -} - - -/* - * If in netmap mode, attach the netmap buffers to the ring and return true. - * Otherwise return false. - * Called at the end of bnx2x_alloc_fp_mem_at(), sets both tx and rx - * buffer entries. At init time we allocate the max number of entries - * for the card, but at runtime the card might use a smaller number, - * so be careful on where we fetch the information. - */ -int -bnx2x_netmap_config(struct SOFTC_T *bp) -{ - struct netmap_adapter *na = NA(bp->dev); - struct netmap_slot *slot; - struct bnx2x_fastpath *fp; - struct bnx2x_fp_txdata *txdata; - int j, ring_nr; - int nq; /* number of queues to use */ - - slot = netmap_reset(na, NR_TX, 0, 0); // quick test on first ring - if (!slot) - return 0; // not in native mode - nq = na->num_rx_rings; - D("# queues: tx %d rx %d act %d %d", - bp->dev->num_tx_queues, bp->dev->num_rx_queues, - BNX2X_NUM_QUEUES(bp), nq ); - if (BNX2X_NUM_QUEUES(bp) < nq) { - nq = BNX2X_NUM_QUEUES(bp); - D("******** wartning, truncate to %d rings", nq); - } - D("allocate memory, tx/rx slots: %d %d max %d %d", - (int)bp->tx_ring_size, (int)bp->rx_ring_size, - na->num_tx_desc, na->num_rx_desc); - for (ring_nr = 0; ring_nr < nq; ring_nr++) { - netmap_reset(na, NR_TX, ring_nr, 0); - } - /* - * Do nothing on the tx ring, addresses are set up at tx time. - */ - fp = &bp->fp[0]; - txdata = &fp->txdata[0]; - ND("tx: pkt cons/prod %d -> %d, bd cons/prod %d -> %d, cons_sb %p", - txdata->tx_pkt_cons, txdata->tx_pkt_prod, - txdata->tx_bd_cons, txdata->tx_bd_prod, - txdata->tx_cons_sb ); - /* - * on the receive ring, must set buf addresses into the slots. - */ - for (ring_nr = 0; ring_nr < nq; ring_nr++) { - slot = netmap_reset(na, NR_RX, ring_nr, 0); - fp = &bp->fp[ring_nr]; - txdata = &fp->txdata[0]; - ND("rx: comp cons/prod %d -> %d, bd cons/prod %d -> %d, cons_sb %p", - fp->rx_comp_cons, fp->rx_comp_prod, - fp->rx_bd_cons, fp->rx_bd_prod, - fp->rx_cons_sb ); - for (j = 0; j < na->num_rx_desc; j++) { - uint64_t paddr; - void *addr = PNMB(na, slot + j, &paddr); - // XXX to be completed - } - } - /* now use regular interrupts */ - D("------------- clear the SKIP_INTR flag"); - // XXX na->na_flags &= ~NAF_SKIP_INTR; - return 1; -} - - -/* - * The attach routine, called near the end of bnx2x_init_one(), - * fills the parameters for netmap_attach() and calls it. - * It cannot fail, in the worst case (such as no memory) - * netmap mode will be disabled and the driver will only - * operate in standard mode. - */ -static void -bnx2x_netmap_attach(struct SOFTC_T *adapter) -{ - struct netmap_adapter na; - struct net_device *dev = adapter->dev; - - bzero(&na, sizeof(na)); - - na.ifp = dev; - na.pdev = &adapter->pdev->dev; - /* The ring size is the number of tx bd, but since we use 2 per - * packet, make the tx ring shorter. - * Let's see what to do with the - * skipping those continuation blocks. - */ - na.num_tx_desc = adapter->tx_ring_size / 2 - 10; - na.num_rx_desc = na.num_tx_desc; // XXX see above - na.nm_txsync = bnx2x_netmap_txsync; - na.nm_rxsync = bnx2x_netmap_rxsync; - na.nm_register = bnx2x_netmap_reg; - /* same number of tx and rx queues. queue 0 is somewhat special - * but we still cosider it. If FCOE is supported, the last hw - * queue is used for it. - */ - na.num_tx_rings = na.num_rx_rings = BNX2X_NUM_ETH_QUEUES(adapter); - netmap_attach(&na); - D("%d queues, tx: %d rx %d slots", na.num_rx_rings, - na.num_tx_desc, na.num_rx_desc); -} -#endif /* NETMAP_BNX2X_MAIN */ -/* end of file */ diff --git a/private/LINUX/mlx4_netmap_linux.h b/private/LINUX/mlx4_netmap_linux.h deleted file mode 100644 index 8a8e6544a..000000000 --- a/private/LINUX/mlx4_netmap_linux.h +++ /dev/null @@ -1,726 +0,0 @@ -/* - * Copyright (C) 2012-2014 Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * $Id: mlx4_netmap_linux.h $ - * - * netmap support for mlx4 (LINUX version) - * - */ - - -#include -#include -#include -#define SOFTC_T mlx4_en_priv - -/* - * This driver is split in multiple small files. - * The main device descriptor has type struct mlx4_en_priv *priv; - * and we attach to the device in mlx4_en_init_netdev() - * (do port numbers start from 1 ?) - * - * The reconfig routine is in mlx4_en_start_port() (also here) - * which is called on a mlx4_en_restart() (watchdog), open and set-mtu. - * - * priv->num_frags ?? - * DS_SIZE ?? - * apparently each rx desc is followed by frag.descriptors - * and the rx desc is rounded up to a power of 2. - * - * Receive code is in en_rx.c - * priv->rx_ring_num number of rx rings - * rxr = prov->rx_ring[ring_ind] rx ring descriptor - * rxr->size number of slots - * rxr->prod producer - * probably written into a mmio reg at *rxr->wqres.db.db - * trimmed to 16 bits. - * - * Rx init routine: - * mlx4_en_activate_rx_rings() - * mlx4_en_init_rx_desc() - * Transmit code is in en_tx.c - */ - -int mlx4_netmap_rx_config(struct SOFTC_T *priv, int ring_nr); -int mlx4_netmap_tx_config(struct SOFTC_T *priv, int ring_nr); - -int mlx4_tx_desc_dump(struct mlx4_en_tx_desc *tx_desc); - -#ifdef NETMAP_MLX4_MAIN -static inline void -nm_pkt_dump(int i, char *buf, int len) -{ - uint8_t *s __attribute__((unused)) = buf+6, *d __attribute__((unused)) = buf; - - RD(10, "%d len %4d %02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x", - i, - len, - s[0], s[1], s[2], s[3], s[4], s[5], - d[0], d[1], d[2], d[3], d[4], d[5]); -} - -/* show the content of the descriptor. Only the first block is printed - * to make sure we do not fail on wraparounds (otherwise we would need - * base, index and ring size). - */ -int -mlx4_tx_desc_dump(struct mlx4_en_tx_desc *tx_desc) -{ - struct mlx4_wqe_ctrl_seg *ctrl = &tx_desc->ctrl; - uint32_t *p = (uint32_t *)tx_desc; - int i, l = ctrl->fence_size; - - RD(5,"------- txdesc %p size 0x%x", tx_desc, ctrl->fence_size); - if (l > 4) - l = 4; - for (i = 0; i < l; i++) { - RD(20, "[%2d]: 0x%08x 0x%08x 0x%08x 0x%08x", i, - ntohl(p[0]), ntohl(p[1]), ntohl(p[2]), ntohl(p[3])); - p += 4; - } - return 0; -} - - -/* - * Register/unregister. We are already under (netmap) core lock. - * Only called on the first register or the last unregister. - */ -static int -mlx4_netmap_reg(struct netmap_adapter *na, int onoff) -{ - struct ifnet *ifp = na->ifp; - struct SOFTC_T *priv = netdev_priv(ifp); - int error = 0, need_load = 0; - struct mlx4_en_dev *mdev = priv->mdev; - - /* - * On enable, flush pending ops, set flag and reinit rings. - * On disable, flush again, and restart the interface. - */ - D("setting netmap mode for %s to %s", na->name, onoff ? "ON" : "OFF"); - // rtnl_lock(); // ??? - if (netif_running(ifp)) { - D("unloading %s", na->name); - //double_mutex_state_lock(mdev); - mutex_lock(&mdev->state_lock); - if (onoff == 0) { - int i; - /* coming from netmap mode, clean up the ring pointers - * so we do not crash in mlx4_en_free_tx_buf() - * XXX should STAMP the txdesc value to pretend the hw got there - * 0x7fffffff plus the bit set to - * !!(ring->cons & ring->size) - */ - for (i = 0; i < na->num_tx_rings; i++) { - struct mlx4_en_tx_ring *txr = &priv->tx_ring[i]; - ND("txr %d : cons %d prod %d txbb %d", i, txr->cons, txr->prod, txr->last_nr_txbb); - txr->cons += txr->last_nr_txbb; // XXX should be 1 - for (;txr->cons != txr->prod; txr->cons++) { - uint16_t j = txr->cons & txr->size_mask; - uint32_t new_val, *ptr = (uint32_t *)(txr->buf + j * TXBB_SIZE); - new_val = cpu_to_be32(STAMP_VAL | (!!(txr->cons & txr->size) << STAMP_SHIFT)); - ND(10, "old 0x%08x new 0x%08x", *ptr, new_val); - *ptr = new_val; - } - } - } - mlx4_en_stop_port(ifp); - need_load = 1; - } - -retry: - if (onoff) { /* enable netmap mode */ - nm_set_native_flags(na); - } else { /* reset normal mode */ - nm_clear_native_flags(na); - } - if (need_load) { - D("loading %s", na->name); - error = mlx4_en_start_port(ifp); - D("start_port returns %d", error); - if (error && onoff) { - onoff = 0; - goto retry; - } - mutex_unlock(&mdev->state_lock); - //double_mutex_state_unlock(mdev); - } - // rtnl_unlock(); - return (error); -} - - -/* - * Reconcile kernel and user view of the transmit ring. - * This routine might be called frequently so it must be efficient. - * - -OUTGOING (txr->prod) -Tx packets need to fill a 64-byte block with one control block and -one descriptor (both 16-byte). Probably we need to fill the other -two data entries in the block with NULL entries as done in rx_config(). -One can request completion reports (intr) on all entries or only -on selected ones. The std. driver reports every 16 packets. - -txr->prod points to the first available slot to send. - -COMPLETION (txr->cons) -TX events are reported through a Completion Queue (CQ) whose entries -can be 32 or 64 bytes. In case of 64 bytes, the interesting part is -at odd indexes. The "factor" variable does the addressing. - -txr->cons points to the last completed block (XXX note so it is 1 behind) - -There is no link back from the txring to the completion -queue so we need to track it ourselves. HOWEVER mlx4_en_alloc_resources() -uses the same index for cq and ring so tx_cq and tx_ring correspond, -same for rx_cq and rx_ring. - - */ -static int -mlx4_netmap_txsync(struct netmap_adapter *na, u_int ring_nr, int flags) -{ - struct ifnet *ifp = na->ifp; - struct netmap_kring *kring = &na->tx_rings[ring_nr]; - struct netmap_ring *ring = kring->ring; - u_int nm_i; /* index into the netmap ring */ - u_int nic_i; /* index into the NIC ring */ - u_int n; - u_int const lim = kring->nkr_num_slots - 1; - u_int const head = kring->rhead; - /* - * interrupts on every tx packet are expensive so request - * them every half ring, or where NS_REPORT is set - */ - u_int report_frequency = kring->nkr_num_slots >> 1; - - struct SOFTC_T *priv = netdev_priv(ifp); - int error = 0; - - if (!netif_carrier_ok(ifp)) { - goto out; - } - - // XXX debugging, only print if sending something - n = (txr->prod - txr->cons - 1) & 0xffffff; // should be modulo 2^24 ? - if (n >= txr->size) { - RD(5, "XXXXXXXXXXX txr %d overflow: cons %u prod %u size %d delta %d", - ring_nr, txr->cons, txr->prod, txr->size, n); - } - - /* - * First part: process new packets to send. - */ - nm_i = kring->nr_hwcur; - // XXX debugging, assuming lim is 2^x-1 - n = 0; // XXX debugging - if (nm_i != head) { /* we have new packets to send */ - ND(5,"START: txr %u cons %u prod %u hwcur %u head %u tail %d send %d", - ring_nr, txr->cons, txr->prod, kring->nr_hwcur, ring->head, kring->nr_hwtail, - (head - nm_i) & lim); - - // XXX see en_tx.c :: mlx4_en_xmit() - /* - * In netmap the descriptor has one control segment - * and one data segment. The control segment is 16 bytes, - * the data segment is another 16 bytes mlx4_wqe_data_seg. - * The alignment is TXBB_SIZE (64 bytes) though, so we are - * forced to use 64 bytes each. - */ - - ND(10,"=======>========== send from %d to %d at bd %d", j, k, txr->prod); - for (n = 0; nm_i != head; n++) { - struct netmap_slot *slot = &ring->slot[nm_i]; - u_int len = slot->len; - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - /* device-specific */ - uint32_t l = txr->prod & txr->size_mask; - struct mlx4_en_tx_desc *tx_desc = txr->buf + l * TXBB_SIZE; - struct mlx4_wqe_ctrl_seg *ctrl = &tx_desc->ctrl; - - NM_CHECK_ADDR_LEN(addr, len); - - - if (slot->flags & NS_BUF_CHANGED) { - /* buffer has changed, unload and reload map */ - // netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr); - } - slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); - /* - * Fill the slot in the NIC ring. - */ - ctrl->vlan_tag = 0; // not used - ctrl->ins_vlan = 0; // NO - ctrl->fence_size = 2; // used descriptor size in 16byte blocks - // request notification. XXX later report only if NS_REPORT or not too often. - ctrl->srcrb_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | - MLX4_WQE_CTRL_SOLICITED); - - // XXX do we need to copy the mac dst address ? - if (1) { // XXX do we need this ? - uint64_t mac = mlx4_en_mac_to_u64(addr); - uint32_t mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16); - uint32_t mac_l = (u32) (mac & 0xffffffff); - - ctrl->srcrb_flags |= cpu_to_be32(mac_h); - ctrl->imm = cpu_to_be32(mac_l); - } - - tx_desc->data.addr = cpu_to_be64(paddr); - tx_desc->data.lkey = cpu_to_be32(priv->mdev->mr.key); - wmb(); // XXX why here ? - tx_desc->data.byte_count = cpu_to_be32(len); // XXX crc corrupt ? - wmb(); - ctrl->owner_opcode = cpu_to_be32( - MLX4_OPCODE_SEND | - ((txr->prod & txr->size) ? MLX4_EN_BIT_DESC_OWN : 0) ); - txr->prod++; - nm_i = nm_next(nm_i, lim); - } - kring->nr_hwcur = head; - - /* XXX Check how to deal with nkr_hwofs */ - /* these two are always in sync. */ - wmb(); /* synchronize writes to the NIC ring */ - /* (re)start the transmitter up to slot l (excluded) */ - ND(5, "doorbell cid %d data 0x%x", txdata->cid, txdata->tx_db.raw); - // XXX is this doorbell correct ? - iowrite32be(txr->doorbell_qpn, txr->bf.uar->map + MLX4_SEND_DOORBELL); - } - // XXX debugging, only print if sent something - if (n) - ND(5, "SENT: txr %d cons %u prod %u hwcur %u cur %u tail %d sent %d", - ring_nr, txr->cons, txr->prod, kring->nr_hwcur, ring->cur, kring->nr_hwtail, n); - - /* - * Second part: reclaim buffers for completed transmissions. - */ - - { - struct mlx4_en_cq *cq = &priv->tx_cq[ring_nr]; - struct mlx4_cq *mcq = &cq->mcq; - - int size = cq->size; // number of entries - struct mlx4_cqe *buf = cq->buf; // base of cq entries - uint32_t size_mask = txr->size_mask; // same in txq and cq ?....... - uint16_t new_index, ring_index; - int factor = priv->cqe_factor; // 1 for 64 bytes, 0 for 32 bytes - - /* - * Reclaim buffers for completed transmissions. The CQE tells us - * where the consumer (NIC) is. Bit 7 of the owner_sr_opcode - * is the ownership bit. It toggles up and down so the - * non-bitwise XNOR trick lets us detect toggles as the ring - * wraps around. On even rounds, the second operand is 0 so - * we exit when the MLX4_CQE_OWNER_MASK bit is 1, viceversa - * on odd rounds. - */ - new_index = ring_index = txr->cons & size_mask; - - for (n = 0; n < 2*lim; n++) { - uint16_t index = mcq->cons_index & size_mask; - struct mlx4_cqe *cqe = &buf[(index << factor) + factor]; - - if (!XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, - mcq->cons_index & size)) - break; - /* - * make sure we read the CQE after we read the - * ownership bit - */ - rmb(); - - /* Skip over last polled CQE */ - new_index = be16_to_cpu(cqe->wqe_index) & size_mask; - ND(5, "txq %d new_index %d", ring_nr, new_index); - mcq->cons_index++; - } - if (n > lim) { - D("XXXXXXXXXXX too many notifications %d", n); - } - /* now we have updated cons-index, notify the card. */ - /* XXX can we make it conditional ? */ - wmb(); - mlx4_cq_set_ci(mcq); - // XXX the following enables interrupts... */ - // mlx4_en_arm_cq(priv, cq); // XXX always ? - wmb(); - /* XXX unsigned arithmetic below */ - n = (new_index - ring_index) & size_mask; - if (n) { - ND(5, "txr %d completed %d packets", ring_nr, n); - txr->cons += n; - /* XXX watch out, index is probably modulo */ - kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, (new_index & size_mask)), lim); - } - if (nm_kr_txempty(kring)) { - mlx4_en_arm_cq(priv, cq); - } - } - -out: - return 0; - -err: - if (error) - return netmap_ring_reinit(kring); - return 0; -} - - -/* - * Reconcile kernel and user view of the receive ring. - -MELLANOX: - -the ring has prod and cons indexes, the size is a power of 2, -size and actual_size indicate how many entries can be allocated, -stride is the size of each entry. - -mlx4_en_update_rx_prod_db() tells the NIC where it can go -(to be used when new buffers are freed). - - */ -static int -mlx4_netmap_rxsync(struct netmap_adapter *na, u_int ring_nr, int flags) -{ - struct ifnet *ifp = na->ifp; - struct netmap_kring *kring = &na->rx_rings[ring_nr]; - struct netmap_ring *ring = kring->ring; - u_int nm_i; /* index into the netmap ring */ - u_int nic_i; /* index into the NIC ring */ - u_int n; - u_int const lim = kring->nkr_num_slots - 1; - u_int const head = kring->rhead; - int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; - - struct SOFTC_T *priv = netdev_priv(ifp); - struct mlx4_en_rx_ring *rxr = &priv->rx_ring[ring_nr]; - - if (!priv->port_up) // XXX as in mlx4_en_process_rx_cq() - return 0; - - if (!netif_carrier_ok(ifp)) // XXX maybe above is redundant ? - return 0; - - if (head > lim) - return netmap_ring_reinit(kring); - - ND(5, "START rxr %d cons %d prod %d kcur %d ktail %d cur %d tail %d", - ring_nr, rxr->cons, rxr->prod, kring->nr_hwcur, kring->nr_hwtail, ring->cur, ring->tail); - - /* - * First part, import newly received packets. - */ - - /* scan the completion queue to see what is going on. - * The mapping is 1:1. The hardware toggles the OWNER bit in the - * descriptor at mcq->cons_index & size_mask, which is mapped 1:1 - * to an entry in the RXR. - * XXX there are two notifications sent to the hw: - * mlx4_cq_set_ci(struct mlx4_cq *cq); - * *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff); - * mlx4_en_update_rx_prod_db(rxr); - * *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); - * apparently they point to the same memory word - * (see mlx4_en_activate_cq() ) and are initialized to 0 - * DB is the doorbell page (sec.15.1.2 ?) - * wqres is set in mlx4_alloc_hwq_res() - * and in turn mlx4_alloc_hwq_res() - */ - if (1 || netmap_no_pendintr || force_update) { - uint16_t slot_flags = kring->nkr_slot_flags; - - struct mlx4_en_cq *cq = &priv->rx_cq[ring_nr]; - struct mlx4_cq *mcq = &cq->mcq; - int factor = priv->cqe_factor; - uint32_t size_mask = rxr->size_mask; - int size = cq->size; - struct mlx4_cqe *buf = cq->buf; - - nm_i = kring->nr_hwtail; - - /* Process all completed CQEs, use same logic as in TX */ - for (n = 0; n <= 2*lim ; n++) { - int index = mcq->cons_index & size_mask; - struct mlx4_cqe *cqe = &buf[(index << factor) + factor]; - prefetch(cqe+1); - if (!XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, mcq->cons_index & size)) - break; - - rmb(); /* make sure data is up to date */ - ring->slot[nm_i].len = be32_to_cpu(cqe->byte_cnt) - rxr->fcs_del; - ring->slot[nm_i].flags = slot_flags; - mcq->cons_index++; - nm_i = nm_next(nm_i, lim); - } - if (n) { /* update the state variables */ - if (n >= 2*lim) - D("XXXXXXXXXXXXX too many received packets %d", n); - ND(5, "received %d packets", n); - kring->nr_hwtail = nm_i; - rxr->cons += n; - ND(5, "RECVD %d rxr %d cons %d prod %d kcur %d ktail %d cur %d tail %d", - n, - ring_nr, rxr->cons, rxr->prod, kring->nr_hwcur, kring->nr_hwtail, ring->cur, ring->tail); - - /* XXX ack completion queue */ - mlx4_cq_set_ci(mcq); - } - kring->nr_kflags &= ~NKR_PENDINTR; - } - - /* - * Second part: skip past packets that userspace has released. - */ - nm_i = kring->nr_hwcur; /* netmap ring index */ - if (nm_i != head) { /* userspace has released some packets. */ - nic_i = netmap_idx_k2n(kring, nm_i); - for (n = 0; nm_i != head; n++) { - /* collect per-slot info, with similar validations - struct netmap_slot *slot = &ring->slot[nm_i]; - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - struct mlx4_en_rx_desc *rx_desc = rxr->buf + (nic_i * rxr->stride); - - if (addr == NETMAP_BUF_BASE(na)) /* bad buf */ - goto ring_reset; - - if (slot->flags & NS_BUF_CHANGED) { - // netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr); - slot->flags &= ~NS_BUF_CHANGED; - } - - /* XXX - * The rx descriptor only contains buffer descriptors, - * probably only the length is changed or not even that one. - */ - // see mlx4_en_prepare_rx_desc() and mlx4_en_alloc_frag() - rx_desc->data[0].addr = cpu_to_be64(paddr); - rx_desc->data[0].byte_count = cpu_to_be32(NETMAP_BUF_SIZE); - rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key); - -#if 0 - int jj, possible_frags; - /* we only use one fragment, so the rest is padding */ - possible_frags = (rxr->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE; - for (jj = 1; jj < possible_frags; jj++) { - rx_desc->data[jj].byte_count = 0; - rx_desc->data[jj].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD); - rx_desc->data[jj].addr = 0; - } -#endif - - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - } - - /* XXX note that mcq->cons_index and ring->cons are not in sync */ - wmb(); - rxr->prod += n; - kring->nr_hwcur = head; - - /* and now tell the system that there are more buffers available. - * should use mlx4_en_update_rx_prod_db(rxr) but it is static in - * en_rx.c so we do not see it here - */ - *rxr->wqres.db.db = cpu_to_be32(rxr->prod & 0xffff); - - ND(5, "FREED rxr %d cons %d prod %d kcur %d ktail %d", - ring_nr, rxr->cons, rxr->prod, - kring->nr_hwcur, kring->nr_hwtail); - } - - - return 0; - -ring_reset: - return netmap_ring_reinit(kring); -} - - -/* - * If in netmap mode, attach the netmap buffers to the ring and return true. - * Otherwise return false. - * Called at the end of mlx4_en_start_port(). - * XXX TODO: still incomplete. - */ -int -mlx4_netmap_tx_config(struct SOFTC_T *priv, int ring_nr) -{ - struct netmap_adapter *na = NA(priv->dev); - struct netmap_slot *slot; - struct mlx4_en_cq *cq; - - ND(5, "priv %p ring_nr %d", priv, ring_nr); - -/* - CONFIGURE TX RINGS IN NETMAP MODE - little if anything to do - The main code does - mlx4_en_activate_cq() - mlx4_en_activate_tx_ring() - - - */ - slot = netmap_reset(na, NR_TX, ring_nr, 0); - if (!slot) - return 0; // not in netmap native mode; - ND(5, "init tx ring %d with %d slots (driver %d)", ring_nr, - na->num_tx_desc, - priv->tx_ring[ring_nr].size); - /* enable interrupts on the netmap queues */ - cq = &priv->tx_cq[ring_nr]; // derive from the txring - - return 1; -} - -int -mlx4_netmap_rx_config(struct SOFTC_T *priv, int ring_nr) -{ - struct netmap_adapter *na = NA(priv->dev); - struct netmap_slot *slot; - struct mlx4_en_rx_ring *rxr; - struct netmap_kring *kring; - int i, j, possible_frags; - - /* - * on the receive ring, must set buf addresses into the slots. - - The ring is activated by mlx4_en_activate_rx_rings(), near the end - the rx ring is also 'started' with mlx4_en_update_rx_prod_db() - so we patch into that routine. - - */ - slot = netmap_reset(na, NR_RX, ring_nr, 0); - if (!slot) - return 0; // not in native netmap mode - kring = &na->rx_rings[ring_nr]; - rxr = &priv->rx_ring[ring_nr]; - ND(20, "ring %d slots %d (driver says %d) frags %d stride %d", ring_nr, - kring->nkr_num_slots, rxr->actual_size, priv->num_frags, rxr->stride); - rxr->prod--; // XXX avoid wraparounds ? - if (kring->nkr_num_slots != rxr->actual_size) { - D("mismatch between slots and actual size, %d vs %d", - kring->nkr_num_slots, rxr->actual_size); - return 1; // XXX error - } - possible_frags = (rxr->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE; - RD(1, "stride %d possible frags %d descsize %d DS_SIZE %d", rxr->stride, possible_frags, (int)sizeof(struct mlx4_en_rx_desc), (int)DS_SIZE ); - /* then fill the slots with our entries */ - for (i = 0; i < kring->nkr_num_slots; i++) { - uint64_t paddr; - struct mlx4_en_rx_desc *rx_desc = rxr->buf + (i * rxr->stride); - - PNMB(na, slot + i, &paddr); - - // see mlx4_en_prepare_rx_desc() and mlx4_en_alloc_frag() - rx_desc->data[0].addr = cpu_to_be64(paddr); - rx_desc->data[0].byte_count = cpu_to_be32(NETMAP_BUF_SIZE); - rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key); - - /* we only use one fragment, so the rest is padding */ - for (j = 1; j < possible_frags; j++) { - rx_desc->data[j].byte_count = 0; - rx_desc->data[j].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD); - rx_desc->data[j].addr = 0; - } - } - RD(5, "ring %d done", ring_nr); - return 1; -} - -static int -mlx4_netmap_config(struct netmap_adapter *na, - u_int *txr, u_int *txd, u_int *rxr, u_int *rxd) -{ - struct net_device *ifp = na->ifp; - struct SOFTC_T *priv = netdev_priv(ifp); - - *txr = priv->tx_ring_num; - *txd = priv->tx_ring[0].size; - - - *rxr = priv->rx_ring_num; - if (*txr > *rxr) { - D("using only %d out of %d tx queues", *rxr, *txr); - *txr = *rxr; - } - *rxd = priv->rx_ring[0].size; - D("txr %d txd %d bufsize %d -- rxr %d rxd %d act %d bufsize %d", - *txr, *txd, priv->tx_ring[0].buf_size, - *rxr, *rxd, priv->rx_ring[0].actual_size, - priv->rx_ring[0].buf_size); - return 0; -} - - -/* - * The attach routine, called near the end of mlx4_en_init_netdev(), - * fills the parameters for netmap_attach() and calls it. - * It cannot fail, in the worst case (such as no memory) - * netmap mode will be disabled and the driver will only - * operate in standard mode. - * - * XXX TODO: - * at the moment use a single lock, and only init a max of 4 queues. - */ -static void -mlx4_netmap_attach(struct SOFTC_T *priv) -{ - struct netmap_adapter na; - struct net_device *dev = priv->dev; - int rxq, txq; - - bzero(&na, sizeof(na)); - - na.ifp = dev; - na.pdev = &priv->pdev->dev; - rxq = priv->rx_ring_num; - txq = priv->tx_ring_num; - /* this card has 1k tx queues, so better limit the number */ - if (rxq > 16) - rxq = 16; - if (txq > rxq) - txq = rxq; - if (txq < 1 && rxq < 1) - txq = rxq = 1; - na.num_tx_rings = txq; - na.num_rx_rings = rxq; - na.num_tx_desc = priv->tx_ring[0].size; - na.num_rx_desc = priv->rx_ring[0].size; - na.nm_txsync = mlx4_netmap_txsync; - na.nm_rxsync = mlx4_netmap_rxsync; - na.nm_register = mlx4_netmap_reg; - na.nm_config = mlx4_netmap_config; - netmap_attach(&na); -} -#endif /* NETMAP_MLX4_MAIN */ -/* end of file */ diff --git a/private/LINUX/vhost-port/Makefile b/private/LINUX/vhost-port/Makefile deleted file mode 100644 index d19dbb8cd..000000000 --- a/private/LINUX/vhost-port/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -obj-m += v1000_net.o -v1000_net-objs := v1000.o net.o - - -KSRC=/lib/modules/$(shell uname -r)/build - -all: module test tags - -module: - make -C $(KSRC) M=$(PWD) modules - -install: - make -C $(KSRC) INSTALL_MOD_DIR=extramodules M=$(PWD) modules_install - -test: test.o tun_alloc.o buildpkt.o - gcc -Wall -g -o test test.o tun_alloc.o buildpkt.o -lpthread - -test.o: test.c v1000_user.h tun_alloc.h - gcc -Wall -g -c test.c - -tun_alloc.o: tun_alloc.c tun_alloc.h - gcc -Wall -g -c tun_alloc.c - -buildpkt.o: - gcc -Wall -g -c buildpkt.c - -clean: - make -C $(KSRC) M=$(PWD) clean - -rm test *.o tags cscope.out - -tags: v1000.c v1000.h net.c test.c - ctags -R diff --git a/private/LINUX/vhost-port/buildpkt.c b/private/LINUX/vhost-port/buildpkt.c deleted file mode 100644 index 870cd1ab4..000000000 --- a/private/LINUX/vhost-port/buildpkt.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "buildpkt.h" - - -#include -#include -#include -#include -#include -#include - -#include /* if_nametoindex() */ -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - - - -/* Program arguments */ -struct arguments { - u_int8_t dst_mac[6]; /* User specified destination MAC. */ - u_int8_t src_mac[6]; /* User specified source MAC. */ - struct in_addr dst_ip; /* User specified destination IP. */ - struct in_addr src_ip; /* User specified source IP. */ - int dst_port; /* User specified destination port. */ - int src_port; /* User specified source port. */ - int packet_len; /* User specified frame length. */ - uint32_t seed; /* Used to fill the UDP payload. */ - int checksum; /* Do we calculate the UDP checksum? */ - void *packet; /* Packet buffer pointer. */ -}; - -/* Compute the checksum of the given ip header. */ -static uint16_t checksum(const void *data, uint16_t len, uint32_t sum) -{ - const uint8_t *addr = data; - uint32_t i; - - /* Checksum all the pairs of bytes first... */ - for (i = 0; i < (len & ~1U); i += 2) { - sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); - if (sum > 0xFFFF) - sum -= 0xFFFF; - } - /* - * If there's a single byte left over, checksum it, too. - * Network byte order is big-endian, so the remaining byte is - * the high byte. - */ - if (i < len) { - sum += addr[i] << 8; - if (sum > 0xFFFF) - sum -= 0xFFFF; - } - return sum; -} - -static u_int16_t wrapsum(u_int32_t sum) -{ - sum = ~sum & 0xFFFF; - return (htons(sum)); -} - -static void initialize_packet(struct arguments *a) -{ - struct pkt *pkt = a->packet; - struct ether_header *eh; - struct ip *ip; - struct udphdr *udp; - uint16_t paylen = a->packet_len - sizeof(*eh) - sizeof(struct ip); - int i, l, l0 = sizeof(a->seed); - - for (i = 0; i < paylen;) { - l = l0 < paylen - i ? l0 : paylen - i; - bcopy(&a->seed, pkt->body + i, l); - i += l; - } - ip = &pkt->ip; - - ip->ip_v = IPVERSION; - ip->ip_hl = 5; - ip->ip_id = 0; - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = ntohs(a->packet_len - sizeof(*eh)); - ip->ip_id = 0; - ip->ip_off = htons(IP_DF); /* Don't fragment */ - ip->ip_ttl = IPDEFTTL; - ip->ip_p = IPPROTO_UDP; - ip->ip_dst.s_addr = a->dst_ip.s_addr; - ip->ip_src.s_addr = a->src_ip.s_addr; - ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0)); - - - udp = &pkt->udp; - udp->uh_sport = htons(a->src_port); - udp->uh_dport = htons(a->dst_port); - udp->uh_ulen = htons(paylen); - if (a->checksum) { - /* Magic: taken from sbin/dhclient/packet.c */ - udp->uh_sum = wrapsum(checksum(udp, sizeof(*udp), - checksum(pkt->body, - paylen - sizeof(*udp), - checksum(&ip->ip_src, 2 * sizeof(ip->ip_src), - IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen) - ) - ) - )); - } else - udp->uh_sum = 0; - - eh = &pkt->eh; - bcopy(a->src_mac, eh->ether_shost, 6); - bcopy(a->dst_mac, eh->ether_dhost, 6); - eh->ether_type = htons(ETHERTYPE_IP); -} - - -static int parse_mac(char *buf, u_int8_t mac[6]) -{ - char *p = buf, *q; - int i = 0; - long int tmp; - - for (i = 0; i < 6; i++) { - tmp = strtol(p, &q, 16); - if ( (i < 5 && *q != ':') || (i == 5 && *q) || tmp < 0 || tmp > 255 ) { - return -1; - } - mac[i] = tmp; - p = q + 1; - } - return 0; -} - -static int fill_arguments(int argc, char *argv[], struct arguments * a) -{ - long payloadsize, srcport, dstport; - char * dummy; - - /* MAC addresses. */ - if (parse_mac(argv[0], a->dst_mac) < 0) { - fprintf(stderr, "invalid macaddr: %s\n", argv[0]); - return -1; - } - - if (parse_mac(argv[1], a->src_mac) < 0) { - fprintf(stderr, "invalid macaddr: %s\n", argv[1]); - return -1; - } - - /* IP addresses. */ - if (inet_aton(argv[2], &a->dst_ip) == 0) { - fprintf(stderr, "invalid destination IP: %s\n", argv[2]); - return -1; - } - - if (inet_aton(argv[3], &a->src_ip) == 0) { - fprintf(stderr, "invalid source IP: %s\n", argv[3]); - return -1; - } - - /* UDP ports. */ - dstport = strtoul(argv[4], &dummy, 10); - if (dstport < 0 || dstport > 65536 || *dummy != '\0') { - fprintf(stderr, "invalid destination port\n"); - return -1; - } - a->dst_port = dstport; - - srcport = strtoul(argv[5], &dummy, 10); - if (srcport < 0 || srcport > 65536 || *dummy != '\0') { - fprintf(stderr, "invalid source port\n"); - return -1; - } - a->src_port = srcport; - - /* Ethernet frame size. */ - payloadsize = strtoul(argv[6], &dummy, 10); - if (payloadsize < 46 || *dummy != '\0') { - fprintf(stderr, "payloadsize < 46\n"); - return -1; - } - if (payloadsize > 70000) { - fprintf(stderr, "payloadsize > 1500\n"); - return -1; - } - a->packet_len = payloadsize; - - return 0; -} - - -void build_packet_from_args(int argc, char *argv[], struct pkt * p, - uint32_t seed, int checksum) -{ - struct arguments a; - - fill_arguments(argc, argv, &a); - - a.packet = p; /* Memory for *p is allocated from the user. */ - a.seed = seed; - a.checksum = checksum; - - initialize_packet(&a); -} diff --git a/private/LINUX/vhost-port/buildpkt.h b/private/LINUX/vhost-port/buildpkt.h deleted file mode 100644 index 67f174912..000000000 --- a/private/LINUX/vhost-port/buildpkt.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __BUILD__PACKET__HH -#define __BUILD__PACKET__HH - -#define _BSD_SOURCE - - -#include -#include -#include -#include - - - -/* An UDP packet. */ -struct pkt { - struct ether_header eh; - struct ip ip; - struct udphdr udp; - uint8_t body[2048]; -} __attribute__((__packed__)); - - -void build_packet_from_args(int argc, char *argv[], struct pkt * p, - uint32_t seed, int checksum); - -#endif diff --git a/private/LINUX/vhost-port/clean.sh b/private/LINUX/vhost-port/clean.sh deleted file mode 100755 index 86b2559eb..000000000 --- a/private/LINUX/vhost-port/clean.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -x - -sudo rmmod v1000_net.ko -#sudo rm /dev/v1000 - -mv .test.c test.c - -sudo arp -d "10.1.1.1" -sudo arp -d "10.1.1.2" - -sudo ip link set br1 down -sudo brctl delbr br1 -sudo ip link set tap1 up -sudo ip link set tap2 up -sudo ip tuntap del mode tap name tap1 -sudo ip tuntap del mode tap name tap2 diff --git a/private/LINUX/vhost-port/e1000_regs.h b/private/LINUX/vhost-port/e1000_regs.h deleted file mode 100644 index c9cb79e64..000000000 --- a/private/LINUX/vhost-port/e1000_regs.h +++ /dev/null @@ -1,893 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2006 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, see . - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -/* e1000_hw.h - * Structures, enums, and macros for the MAC - */ - -#ifndef _E1000_HW_H_ -#define _E1000_HW_H_ - - -/* PCI Device IDs */ -#define E1000_DEV_ID_82542 0x1000 -#define E1000_DEV_ID_82543GC_FIBER 0x1001 -#define E1000_DEV_ID_82543GC_COPPER 0x1004 -#define E1000_DEV_ID_82544EI_COPPER 0x1008 -#define E1000_DEV_ID_82544EI_FIBER 0x1009 -#define E1000_DEV_ID_82544GC_COPPER 0x100C -#define E1000_DEV_ID_82544GC_LOM 0x100D -#define E1000_DEV_ID_82540EM 0x100E -#define E1000_DEV_ID_82540EM_LOM 0x1015 -#define E1000_DEV_ID_82540EP_LOM 0x1016 -#define E1000_DEV_ID_82540EP 0x1017 -#define E1000_DEV_ID_82540EP_LP 0x101E -#define E1000_DEV_ID_82545EM_COPPER 0x100F -#define E1000_DEV_ID_82545EM_FIBER 0x1011 -#define E1000_DEV_ID_82545GM_COPPER 0x1026 -#define E1000_DEV_ID_82545GM_FIBER 0x1027 -#define E1000_DEV_ID_82545GM_SERDES 0x1028 -#define E1000_DEV_ID_82546EB_COPPER 0x1010 -#define E1000_DEV_ID_82546EB_FIBER 0x1012 -#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D -#define E1000_DEV_ID_82541EI 0x1013 -#define E1000_DEV_ID_82541EI_MOBILE 0x1018 -#define E1000_DEV_ID_82541ER_LOM 0x1014 -#define E1000_DEV_ID_82541ER 0x1078 -#define E1000_DEV_ID_82547GI 0x1075 -#define E1000_DEV_ID_82541GI 0x1076 -#define E1000_DEV_ID_82541GI_MOBILE 0x1077 -#define E1000_DEV_ID_82541GI_LF 0x107C -#define E1000_DEV_ID_82546GB_COPPER 0x1079 -#define E1000_DEV_ID_82546GB_FIBER 0x107A -#define E1000_DEV_ID_82546GB_SERDES 0x107B -#define E1000_DEV_ID_82546GB_PCIE 0x108A -#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 -#define E1000_DEV_ID_82547EI 0x1019 -#define E1000_DEV_ID_82547EI_MOBILE 0x101A -#define E1000_DEV_ID_82571EB_COPPER 0x105E -#define E1000_DEV_ID_82571EB_FIBER 0x105F -#define E1000_DEV_ID_82571EB_SERDES 0x1060 -#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 -#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 -#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 -#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC -#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 -#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA -#define E1000_DEV_ID_82572EI_COPPER 0x107D -#define E1000_DEV_ID_82572EI_FIBER 0x107E -#define E1000_DEV_ID_82572EI_SERDES 0x107F -#define E1000_DEV_ID_82572EI 0x10B9 -#define E1000_DEV_ID_82573E 0x108B -#define E1000_DEV_ID_82573E_IAMT 0x108C -#define E1000_DEV_ID_82573L 0x109A -#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 -#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 -#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 -#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA -#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB - -#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 -#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A -#define E1000_DEV_ID_ICH8_IGP_C 0x104B -#define E1000_DEV_ID_ICH8_IFE 0x104C -#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 -#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 -#define E1000_DEV_ID_ICH8_IGP_M 0x104D - -/* Register Set. (82543, 82544) - * - * Registers are defined to be 32 bits and should be accessed as 32 bit values. - * These registers are physically located on the NIC, but are mapped into the - * host memory address space. - * - * RW - register is both readable and writable - * RO - register is read only - * WO - register is write only - * R/clr - register is read only and is cleared when read - * A - register array - */ -#define E1000_CTRL 0x00000 /* Device Control - RW */ -#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ -#define E1000_STATUS 0x00008 /* Device Status - RO */ -#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ -#define E1000_EERD 0x00014 /* EEPROM Read - RW */ -#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ -#define E1000_FLA 0x0001C /* Flash Access - RW */ -#define E1000_MDIC 0x00020 /* MDI Control - RW */ -#define E1000_SCTL 0x00024 /* SerDes Control - RW */ -#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */ -#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ -#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ -#define E1000_FCT 0x00030 /* Flow Control Type - RW */ -#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ -#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ -#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ -#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ -#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ -#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ -#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ -#define E1000_RCTL 0x00100 /* RX Control - RW */ -#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ -#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ -#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */ -#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */ -#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ -#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ -#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ -#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ -#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ -#define E1000_TCTL 0x00400 /* TX Control - RW */ -#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */ -#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ -#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ -#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ -#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ -#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ -#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ -#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ -#define FEXTNVM_SW_CONFIG 0x0001 -#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ -#define E1000_PBS 0x01008 /* Packet Buffer Size */ -#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ -#define E1000_FLASH_UPDATES 1000 -#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ -#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ -#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ -#define E1000_FLSWCTL 0x01030 /* FLASH control register */ -#define E1000_FLSWDATA 0x01034 /* FLASH data register */ -#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ -#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ -#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ -#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ -#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ -#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ -#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ -#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ -#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ -#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ -#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ -#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ -#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ -#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ -#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ -#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ -#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ -#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ -#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */ -#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */ -#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ -#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ -#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ -#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ -#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ -#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ -#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ -#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ -#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */ -#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */ -#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ -#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ -#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ -#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ -#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ -#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ -#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ -#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ -#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ -#define E1000_TARC0 0x03840 /* TX Arbitration Count (0) */ -#define E1000_TDBAL1 0x03900 /* TX Desc Base Address Low (1) - RW */ -#define E1000_TDBAH1 0x03904 /* TX Desc Base Address High (1) - RW */ -#define E1000_TDLEN1 0x03908 /* TX Desc Length (1) - RW */ -#define E1000_TDH1 0x03910 /* TX Desc Head (1) - RW */ -#define E1000_TDT1 0x03918 /* TX Desc Tail (1) - RW */ -#define E1000_TXDCTL1 0x03928 /* TX Descriptor Control (1) - RW */ -#define E1000_TARC1 0x03940 /* TX Arbitration Count (1) */ -#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ -#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ -#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ -#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ -#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ -#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ -#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ -#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ -#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ -#define E1000_COLC 0x04028 /* Collision Count - R/clr */ -#define E1000_DC 0x04030 /* Defer Count - R/clr */ -#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ -#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ -#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ -#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ -#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ -#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ -#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ -#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ -#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ -#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ -#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ -#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ -#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ -#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ -#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ -#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ -#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ -#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ -#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ -#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ -#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ -#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ -#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ -#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ -#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ -#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ -#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ -#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ -#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ -#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ -#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ -#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ -#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ -#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ -#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ -#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ -#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ -#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ -#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ -#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ -#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ -#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ -#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ -#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ -#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ -#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ -#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ -#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */ -#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */ -#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */ -#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */ -#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */ -#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */ -#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ -#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ -#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ -#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ -#define E1000_RA 0x05400 /* Receive Address - RW Array */ -#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ -#define E1000_WUC 0x05800 /* Wakeup Control - RW */ -#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ -#define E1000_WUS 0x05810 /* Wakeup Status - RO */ -#define E1000_MANC 0x05820 /* Management Control - RW */ -#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ -#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ -#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ -#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ -#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ -#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ -#define E1000_HOST_IF 0x08800 /* Host Interface */ -#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ -#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ - -#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */ -#define E1000_MDPHYA 0x0003C /* PHY address - RW */ -#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ -#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ - -#define E1000_GCR 0x05B00 /* PCI-Ex Control */ -#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ -#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ -#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ -#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ -#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ -#define E1000_SWSM 0x05B50 /* SW Semaphore */ -#define E1000_FWSM 0x05B54 /* FW Semaphore */ -#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ -#define E1000_HICR 0x08F00 /* Host Inteface Control */ - -/* RSS registers */ -#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ -#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ -#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */ -#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */ -#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ -#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ - -/* PHY 1000 MII Register/Bit Definitions */ -/* PHY Registers defined by IEEE */ -#define PHY_CTRL 0x00 /* Control Register */ -#define PHY_STATUS 0x01 /* Status Regiser */ -#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ -#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ -#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ -#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ -#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ -#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ -#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ -#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ -#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ -#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ - -#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ -#define MAX_PHY_MULTI_PAGE_REG 0xF /* Registers equal on all pages */ - -/* M88E1000 Specific Registers */ -#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ -#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ -#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ -#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ -#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ -#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ - -#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ -#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ -#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ -#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ -#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ - -/* PHY Control Register */ -#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ -#define MII_CR_POWER_DOWN 0x0800 /* Power down */ -#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ - -/* PHY Status Register */ -#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ - -/* Interrupt Cause Read */ -#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ -#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ -#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ -#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ -#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ -#define E1000_ICR_RXO 0x00000040 /* rx overrun */ -#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ -#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ -#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ -#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ -#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ -#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ -#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ -#define E1000_ICR_TXD_LOW 0x00008000 -#define E1000_ICR_SRPD 0x00010000 -#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ -#define E1000_ICR_MNG 0x00040000 /* Manageability event */ -#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ -#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ -#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ -#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ -#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ -#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ -#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ -#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ -#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ -#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ - -/* Interrupt Cause Set */ -#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ -#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ -#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_ICS_SRPD E1000_ICR_SRPD -#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ -#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ -#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ -#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ -#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ -#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ -#define E1000_ICS_DSW E1000_ICR_DSW -#define E1000_ICS_PHYINT E1000_ICR_PHYINT -#define E1000_ICS_EPRST E1000_ICR_EPRST - -/* Interrupt Mask Set */ -#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ -#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ -#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMS_SRPD E1000_ICR_SRPD -#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ -#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ -#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ -#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ -#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ -#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ -#define E1000_IMS_DSW E1000_ICR_DSW -#define E1000_IMS_PHYINT E1000_ICR_PHYINT -#define E1000_IMS_EPRST E1000_ICR_EPRST - -/* Interrupt Mask Clear */ -#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ -#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ -#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMC_SRPD E1000_ICR_SRPD -#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ -#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ -#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ -#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ -#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ -#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ -#define E1000_IMC_DSW E1000_ICR_DSW -#define E1000_IMC_PHYINT E1000_ICR_PHYINT -#define E1000_IMC_EPRST E1000_ICR_EPRST - -/* Receive Control */ -#define E1000_RCTL_RST 0x00000001 /* Software reset */ -#define E1000_RCTL_EN 0x00000002 /* enable */ -#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ -#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ -#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ -#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ -#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ -#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ -#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ -#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ -#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ -#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ -#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ -#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ -#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ -#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ -#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ -#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ -#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ -#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ -#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ -#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ -#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ -#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ -#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ -#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ -#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ -#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ -#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ -#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ -#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ -#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ -#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ - - -#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ -#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ -#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM read/write registers */ -#define E1000_EEPROM_RW_REG_DONE 0x10 /* Offset to READ/WRITE done bit */ -#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start operation */ -#define E1000_EEPROM_RW_ADDR_SHIFT 8 /* Shift to the address bits */ -#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */ -#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */ -/* Register Bit Masks */ -/* Device Control */ -#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ -#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ -#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ -#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ -#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ -#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ -#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ -#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ -#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ -#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ -#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ -#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ -#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ -#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ -#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ -#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ -#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ -#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ -#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ -#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ -#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ -#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ -#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ -#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ -#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ -#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ -#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ -#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ -#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ -#define E1000_CTRL_RST 0x04000000 /* Global reset */ -#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ -#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ -#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ -#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ -#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ -#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ - -/* Device Status */ -#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ -#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ -#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ -#define E1000_STATUS_FUNC_SHIFT 2 -#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ -#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ -#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ -#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ -#define E1000_STATUS_SPEED_MASK 0x000000C0 -#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ -#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ -#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ -#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion - by EEPROM/Flash */ -#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ -#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ -#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ -#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ -#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ -#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ -#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ -#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ -#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ -#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ -#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ -#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ -#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */ -#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ -#define E1000_STATUS_FUSE_8 0x04000000 -#define E1000_STATUS_FUSE_9 0x08000000 -#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ -#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ - -/* EEPROM/Flash Control */ -#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ -#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ -#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ -#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ -#define E1000_EECD_FWE_MASK 0x00000030 -#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ -#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ -#define E1000_EECD_FWE_SHIFT 4 -#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ -#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ -#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ -#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ -#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type - * (0-small, 1-large) */ -#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */ -#ifndef E1000_EEPROM_GRANT_ATTEMPTS -#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ -#endif -#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */ -#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */ -#define E1000_EECD_SIZE_EX_SHIFT 11 -#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ -#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ -#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ -#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ -#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ -#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ -#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ -#define E1000_EECD_SECVAL_SHIFT 22 -#define E1000_STM_OPCODE 0xDB00 -#define E1000_HICR_FW_RESET 0xC0 - -#define E1000_SHADOW_RAM_WORDS 2048 -#define E1000_ICH_NVM_SIG_WORD 0x13 -#define E1000_ICH_NVM_SIG_MASK 0xC0 - -/* MDI Control */ -#define E1000_MDIC_DATA_MASK 0x0000FFFF -#define E1000_MDIC_REG_MASK 0x001F0000 -#define E1000_MDIC_REG_SHIFT 16 -#define E1000_MDIC_PHY_MASK 0x03E00000 -#define E1000_MDIC_PHY_SHIFT 21 -#define E1000_MDIC_OP_WRITE 0x04000000 -#define E1000_MDIC_OP_READ 0x08000000 -#define E1000_MDIC_READY 0x10000000 -#define E1000_MDIC_INT_EN 0x20000000 -#define E1000_MDIC_ERROR 0x40000000 - -/* EEPROM Commands - Microwire */ -#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */ -#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */ -#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */ -#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */ -#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */ - -/* EEPROM Word Offsets */ -#define EEPROM_COMPAT 0x0003 -#define EEPROM_ID_LED_SETTINGS 0x0004 -#define EEPROM_VERSION 0x0005 -#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */ -#define EEPROM_PHY_CLASS_WORD 0x0007 -#define EEPROM_INIT_CONTROL1_REG 0x000A -#define EEPROM_INIT_CONTROL2_REG 0x000F -#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010 -#define EEPROM_INIT_CONTROL3_PORT_B 0x0014 -#define EEPROM_INIT_3GIO_3 0x001A -#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020 -#define EEPROM_INIT_CONTROL3_PORT_A 0x0024 -#define EEPROM_CFG 0x0012 -#define EEPROM_FLASH_VERSION 0x0032 -#define EEPROM_CHECKSUM_REG 0x003F - -#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ -#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */ - -/* Transmit Descriptor */ -struct e1000_tx_desc { - uint64_t buffer_addr; /* Address of the descriptor's data buffer */ - union { - uint32_t data; - struct { - uint16_t length; /* Data buffer length */ - uint8_t cso; /* Checksum offset */ - uint8_t cmd; /* Descriptor control */ - } flags; - } lower; - union { - uint32_t data; - struct { - uint8_t status; /* Descriptor status */ - uint8_t css; /* Checksum start */ - uint16_t special; - } fields; - } upper; -}; - -/* Transmit Descriptor bit definitions */ -#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ -#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ -#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ -#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ -#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ -#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ -#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ -#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ -#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ -#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ -#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ -#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ -#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ -#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ -#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ -#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ -#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ -#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ -#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ -#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ - -/* Transmit Control */ -#define E1000_TCTL_RST 0x00000001 /* software reset */ -#define E1000_TCTL_EN 0x00000002 /* enable tx */ -#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ -#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ -#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ -#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ -#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ -#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ -#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ -#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ -#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ - -/* Receive Descriptor */ -struct e1000_rx_desc { - uint64_t buffer_addr; /* Address of the descriptor's data buffer */ - uint16_t length; /* Length of data DMAed into data buffer */ - uint16_t csum; /* Packet checksum */ - uint8_t status; /* Descriptor status */ - uint8_t errors; /* Descriptor Errors */ - uint16_t special; -}; - -/* Receive Descriptor bit definitions */ -#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ -#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ -#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ -#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ -#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ -#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ -#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ -#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ -#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ -#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ -#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ -#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ -#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ -#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ -#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ -#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ -#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ -#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ -#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ -#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ -#define E1000_RXD_SPC_PRI_SHIFT 13 -#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ -#define E1000_RXD_SPC_CFI_SHIFT 12 - -#define E1000_RXDEXT_STATERR_CE 0x01000000 -#define E1000_RXDEXT_STATERR_SE 0x02000000 -#define E1000_RXDEXT_STATERR_SEQ 0x04000000 -#define E1000_RXDEXT_STATERR_CXE 0x10000000 -#define E1000_RXDEXT_STATERR_TCPE 0x20000000 -#define E1000_RXDEXT_STATERR_IPE 0x40000000 -#define E1000_RXDEXT_STATERR_RXE 0x80000000 - -#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 -#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF - -/* Receive Address */ -#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ - -/* Offload Context Descriptor */ -struct e1000_context_desc { - union { - uint32_t ip_config; - struct { - uint8_t ipcss; /* IP checksum start */ - uint8_t ipcso; /* IP checksum offset */ - uint16_t ipcse; /* IP checksum end */ - } ip_fields; - } lower_setup; - union { - uint32_t tcp_config; - struct { - uint8_t tucss; /* TCP checksum start */ - uint8_t tucso; /* TCP checksum offset */ - uint16_t tucse; /* TCP checksum end */ - } tcp_fields; - } upper_setup; - uint32_t cmd_and_length; /* */ - union { - uint32_t data; - struct { - uint8_t status; /* Descriptor status */ - uint8_t hdr_len; /* Header length */ - uint16_t mss; /* Maximum segment size */ - } fields; - } tcp_seg_setup; -}; - -/* Offload data descriptor */ -struct e1000_data_desc { - uint64_t buffer_addr; /* Address of the descriptor's buffer address */ - union { - uint32_t data; - struct { - uint16_t length; /* Data buffer length */ - uint8_t typ_len_ext; /* */ - uint8_t cmd; /* */ - } flags; - } lower; - union { - uint32_t data; - struct { - uint8_t status; /* Descriptor status */ - uint8_t popts; /* Packet Options */ - uint16_t special; /* */ - } fields; - } upper; -}; - -/* Management Control */ -#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ -#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ -#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ -#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ -#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ -#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ -#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ -#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ -#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ -#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery - * Filtering */ -#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ -#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ -#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ -#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ -#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ -#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ -#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address - * filtering */ -#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host - * memory */ -#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address - * filtering */ -#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ -#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ -#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ -#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ -#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ -#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ -#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ -#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ - -#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ -#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ - -/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ -#define EEPROM_SUM 0xBABA - -#endif /* _E1000_HW_H_ */ diff --git a/private/LINUX/vhost-port/init.sh b/private/LINUX/vhost-port/init.sh deleted file mode 100755 index 766be7ca1..000000000 --- a/private/LINUX/vhost-port/init.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -set -x - -sudo modprobe tun -sudo modprobe macvtap - -sudo ip tuntap add mode tap name tap1 -sudo ip tuntap add mode tap name tap2 -sudo ip link set tap1 up -sudo ip link set tap2 up -sudo brctl addbr br1 -sudo brctl addif br1 tap1 -sudo brctl addif br1 tap2 -sudo ip link set br1 up -sudo ip addr add 10.1.1.200/24 dev br1 - -sudo arp -s "10.1.1.1" "00:aa:bb:cc:de:1" -sudo arp -s "10.1.1.2" "00:aa:bb:cc:de:2" - -cp test.c .test.c -BR0MAC=$(ip link | tail -1 | awk '{print $2}') -sed -i "s|BR0MAC|${BR0MAC}|" test.c -make "test" - - -sudo insmod v1000_net.ko -sudo chmod a+rw /dev/v1000 - diff --git a/private/LINUX/vhost-port/net.c b/private/LINUX/vhost-port/net.c deleted file mode 100644 index 8a617d005..000000000 --- a/private/LINUX/vhost-port/net.c +++ /dev/null @@ -1,1279 +0,0 @@ -/* Author: Vincenzo Maffione - * - * Based on the vhost/vhost-net work. - * - * This work is licensed under the terms of the GNU GPL, version 2. - * - * e1000-paravirt server in host kernel. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "paravirt.h" -#include "v1000.h" - - -//#define DEBUG /* Enables communication debugging. */ -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -//#define RATE /* Enables communication statistics. */ -#ifdef RATE -#define IFRATE(x) x -struct rate_stats { - unsigned long gtxk; /* Guest --> Host Tx kicks. */ - unsigned long grxk; /* Guest --> Host Rx kicks. */ - unsigned long htxk; /* Host --> Guest Tx kicks. */ - unsigned long hrxk; /* Host --> Guest Rx Kicks. */ - unsigned long btxwu; /* Backend Tx wake-up. */ - unsigned long brxwu; /* Backend Rx wake-up. */ - unsigned long txpkts; /* Transmitted packets. */ - unsigned long rxpkts; /* Received packets. */ - unsigned long txfl; /* TX flushes requests. */ -}; - -struct rate_context { - struct timer_list timer; - struct rate_stats new; - struct rate_stats old; -}; - -#define RATE_PERIOD 2 -static void rate_callback(unsigned long arg) -{ - struct rate_context * ctx = (struct rate_context *)arg; - struct rate_stats cur = ctx->new; - int r; - - printk("txp = %lu Hz\n", (cur.txpkts - ctx->old.txpkts)/RATE_PERIOD); - printk("gtxk = %lu Hz\n", (cur.gtxk - ctx->old.gtxk)/RATE_PERIOD); - printk("htxk = %lu Hz\n", (cur.htxk - ctx->old.htxk)/RATE_PERIOD); - printk("btxw = %lu Hz\n", (cur.btxwu - ctx->old.btxwu)/RATE_PERIOD); - printk("rxp = %lu Hz\n", (cur.rxpkts - ctx->old.rxpkts)/RATE_PERIOD); - printk("grxk = %lu Hz\n", (cur.grxk - ctx->old.grxk)/RATE_PERIOD); - printk("hrxk = %lu Hz\n", (cur.hrxk - ctx->old.hrxk)/RATE_PERIOD); - printk("brxw = %lu Hz\n", (cur.brxwu - ctx->old.brxwu)/RATE_PERIOD); - printk("txfl = %lu Hz\n", (cur.txfl - ctx->old.txfl)/RATE_PERIOD); - printk("\n"); - - ctx->old = cur; - r = mod_timer(&ctx->timer, jiffies + - msecs_to_jiffies(RATE_PERIOD * 1000)); - if (unlikely(r)) - printk("[v1000] Error: mod_timer()\n"); -} -#else -#define IFRATE(x) -#endif - - -struct e1000_tx_context { - bool vlan_needed; - uint8_t ipcss; - uint8_t ipcso; - uint16_t ipcse; - uint32_t paylen; - bool tcp; -}; - -struct e1000_state { - uint32_t tdt; - uint32_t tdh; - uint32_t rdt; - uint32_t rdh; - struct e1000_tx_context txc; - uint32_t txnum; /* Number of TX descriptors. */ - uint32_t rxnum; /* Number of RX descriptors. */ -}; - -/* Max number of bytes transferred before requeueing the job. - * Using this limit prevents one virtqueue from starving others. */ -#define V1000_NET_WEIGHT 0x80000 - -/* A set of callbacks through wich the v1000 frontend interacts - with a backend (socket or netmap). */ -struct v1000_backend { - /* Get the file struct attached to the backend. */ - struct file *(*get_file)(void *opaque); - /* Send a packet to the backend. */ - int (*sendmsg)(void *opaque, struct msghdr *msg, size_t iovlen, unsigned flags); - /* Get the length of the next rx buffer ready into the backend. */ - int (*peek_head_len)(void *opaque); - /* Receive a packet from the backend. */ - int (*recvmsg)(void *opaque, struct msghdr *msg, size_t len); -}; - -struct v1000_net { - struct v1000_dev dev; - struct v1000_ring tx_ring, rx_ring; - struct v1000_poll tx_poll, rx_poll; - - struct V1000Config config; - bool configured; - struct e1000_tx_desc __user * tx_desc; - struct e1000_rx_desc __user * rx_desc; - struct paravirt_csb __user * csb; - struct virtio_net_hdr __user * tx_hdr; - struct virtio_net_hdr __user * rx_hdr; - struct e1000_state state; - bool broken; - struct v1000_backend backend; - IFRATE(struct rate_context rate_ctx); -}; - -/* #################### SOCKET BACKEND CALLBACKS ################### */ -static struct file *socket_backend_get_file(void *opaque) -{ - struct socket *sock = (struct socket *)opaque; - - return sock->file; -} - -static int socket_backend_sendmsg(void *opaque, struct msghdr *msg, - size_t iovlen, unsigned flags) -{ - struct socket *sock = (struct socket *)opaque; - - return sock->ops->sendmsg(NULL, sock, msg, iovlen); -} - -static int socket_backend_peek_head_len(void *opaque) -{ - struct socket *sock = (struct socket *)opaque; - struct sock *sk = sock->sk; - struct sk_buff *head; - int len = 0; - unsigned long flags; - - spin_lock_irqsave(&sk->sk_receive_queue.lock, flags); - head = skb_peek(&sk->sk_receive_queue); - if (likely(head)) { - len = head->len; - if (vlan_tx_tag_present(head)) - len += VLAN_HLEN; - } - - spin_unlock_irqrestore(&sk->sk_receive_queue.lock, flags); - return len; -} - -static int socket_backend_recvmsg(void *opaque, struct msghdr *msg, - size_t len) -{ - struct socket *sock = (struct socket *)opaque; - - return sock->ops->recvmsg(NULL, sock, msg, len, - MSG_DONTWAIT | MSG_TRUNC); -} - -#ifdef DEBUG -/* Print the translation table. */ -static void print_translations(struct v1000_net * net) -{ - struct V1000Translation * tr = &net->config.tr; - int i; - - printk("Translation table.%p: (#%u)\n", net, tr->num); - for (i=0; inum; i++) { - printk(" idx=%d, pa=%llu, l=%llu, va=%p\n", i, - tr->table[i].phy, - tr->table[i].length, - tr->table[i].virt); - } - printk("\n"); -} -#endif - -static void * lookup_translation(struct v1000_net * net, uint64_t address, uint64_t length) -{ - struct V1000Translation * tr = &net->config.tr; - int i; - - for (i=0; inum; i++) { - /* printk("(%llu,%llu) against (%llu,%llu,%p)\n", address, length, - tr->table[i].phy, tr->table[i].length, tr->table[i].virt); */ - if (address >= tr->table[i].phy && address + length <= - tr->table[i].phy + tr->table[i].length) { - /* The requested address range is completely included - in this traslated memory chunk. We have a (complete) - hit. */ - return (void *)(((uint64_t)tr->table[i].virt + address) - tr->table[i].phy); - } - } - - return NULL; -} - -#define CSB_READ(csb, field, r) \ - do { \ - if (get_user(r, &csb->field)) { \ - r = -EFAULT; \ - } \ - } while (0) - -#define CSB_WRITE(csb, field, v) \ - do { \ - if (put_user(v, &csb->field)) { \ - v = -EFAULT; \ - } \ - } while (0) - -static inline void v1000_set_txkick(struct v1000_net *net, bool enable) -{ - uint32_t v = enable ? 1 : 0; - - CSB_WRITE(net->csb, host_need_txkick, v); -} - -static inline bool v1000_tx_interrupts_enabled(struct v1000_net * net) -{ - uint32_t v; - - CSB_READ(net->csb, guest_need_txkick, v); - - return v; -} - -/* Expects to be always run from workqueue - which acts as - * read-size critical section for our kind of RCU. */ -static void handle_tx(struct v1000_net *net) -{ - struct v1000_ring *vr = &net->tx_ring; - struct msghdr msg = { - .msg_name = NULL, - .msg_namelen = 0, - .msg_control = NULL, - .msg_controllen = 0, - .msg_iov = vr->iov, - .msg_flags = MSG_DONTWAIT, - }; - struct virtio_net_hdr hdr; - size_t iovlen, total_len = 0; - int err; - void *opaque; - struct e1000_state * st = &net->state; - struct e1000_tx_desc desc; - struct e1000_context_desc * ctxdp = - (struct e1000_context_desc *)&desc; - void __user * va; - unsigned iovcnt, wbcnt, i; - bool work = false; - uint16_t len; - uint32_t desc_type; - bool eop; - uint32_t next_tdh; - - mutex_lock(&vr->mutex); - opaque = vr->private_data; - if (unlikely(!opaque || net->broken)) { - printk("[v1000] Broken device\n"); - goto leave; - } - - /* Disable notifications. */ - v1000_set_txkick(net, false); - - next_tdh = st->tdh + 1; - if (unlikely(next_tdh == st->txnum)) { - next_tdh = 0; - } - - smp_mb(); - CSB_READ(net->csb, guest_tdt, st->tdt); - if (unlikely(st->tdt >= st->txnum)) { - net->broken = true; - goto leave; - } - for (;;) { - /* Nothing new? Wait for eventfd to tell us they refilled. */ - if (st->tdt == st->tdh) { - /* Reenable notifications. */ - v1000_set_txkick(net, true); - /* Doublecheck. */ - smp_mb(); - CSB_READ(net->csb, guest_tdt, st->tdt); - if (unlikely(st->tdt >= st->txnum)) { - net->broken = true; - goto leave; - } - if (unlikely(st->tdt != st->tdh)) { - v1000_set_txkick(net, false); - continue; - } - break; - } - - /* Use the first iovec slot for the virtio-net header. */ - vr->iov[0].iov_base = net->tx_hdr + st->tdh; - vr->iov[0].iov_len = sizeof(struct virtio_net_hdr); - memset(&hdr, 0, sizeof(struct virtio_net_hdr)); -#if VIRTIO_NET_HDR_GSO_NONE - hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE; -#endif - /* TODO refer to a global zero (null) vnet-hdr to avoid the - copy_to_user when the header is zero. */ - - /* Collect the TX descriptors. */ - iovcnt = 1; - wbcnt = 0; - eop = false; - do { - if (unlikely(st->tdh == st->tdt)) { - printk("[v1000] Broken TX descriptor chain: expected EOP\n"); - break; - } - - /* Read a descriptor. */ - if (unlikely(copy_from_user(&desc, net->tx_desc + st->tdh, - sizeof(struct e1000_tx_desc)))) { - printk("copy_from_user(txdesc) FAILED!!!\n"); - net->broken = true; - goto leave; - } - - /* Process the descriptor. */ - if (desc.lower.data & E1000_TXD_CMD_RS) { - /* Register a writeback operation. */ - vr->wb[wbcnt].addr = (uint8_t *)&net->tx_desc[st->tdh].upper.data; - vr->wb[wbcnt].value = E1000_TXD_STAT_DD; - wbcnt++; - } - desc_type = desc.lower.data & (E1000_TXD_CMD_DEXT - | E1000_TXD_DTYP_D); - if (desc_type == E1000_TXD_CMD_DEXT) { /* Context descriptor. */ - if (unlikely(iovcnt != 1)) { - printk("[v1000] Warning: TX context descriptor in the" - "middle of a packet. Discarding %d data" - "descriptors\n", iovcnt - 1); - eop = true; - } - st->txc.ipcss = ctxdp->lower_setup.ip_fields.ipcss; - st->txc.ipcso = ctxdp->lower_setup.ip_fields.ipcso; - st->txc.ipcse = ctxdp->lower_setup.ip_fields.ipcse; - st->txc.paylen = ctxdp->cmd_and_length & 0xfffff; - st->txc.tcp = ((ctxdp->cmd_and_length & - E1000_TXD_CMD_TCP) != 0); - - if ((ctxdp->cmd_and_length & E1000_TXD_CMD_TSE)) { - hdr.gso_type = (ctxdp->cmd_and_length & - E1000_TXD_CMD_IP) ? VIRTIO_NET_HDR_GSO_TCPV4: - VIRTIO_NET_HDR_GSO_TCPV6; - hdr.gso_size = ctxdp->tcp_seg_setup.fields.mss; - hdr.hdr_len = ctxdp->tcp_seg_setup.fields.hdr_len; - } - - hdr.csum_start = ctxdp->upper_setup.tcp_fields.tucss; - hdr.csum_offset = ctxdp->upper_setup.tcp_fields.tucso - ctxdp->upper_setup.tcp_fields.tucss; - if (unlikely(ctxdp->upper_setup.tcp_fields.tucse)) { - printk("[v1000] Warning: Checksum on partial payload\n"); - } - } else { /* Data descriptor. */ - if (desc_type == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { - /* Extended descriptor. */ - if (iovcnt == 1) { - if (desc.upper.data & (E1000_TXD_POPTS_TXSM << 8)) - hdr.flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM; - /* Don't check for IP checksumming, it's already computed - by the guest kernel. - if (desc.upper.data & (E1000_TXD_POPTS_IXSM << 8)) { - } */ - } - if (unlikely(hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE && - !(desc.lower.data & E1000_TXD_CMD_TSE))) { - printk("[v1000] TCP segmentation error\n"); - goto next; - } - } else { - /* Legacy descriptor. */ - } - - len = desc.lower.data & 0xffff; - va = lookup_translation(net, desc.buffer_addr, len); - if (unlikely(!va)) { - printk("Address translation FAILED: tdh=%u, phy=%llu, len=%u\n", st->tdh, desc.buffer_addr, len); - net->broken = true; - goto leave; - } - DBG(printk("tx: phy=%llu,len=%u,virt=%p,TDH=%u,TDT=%u\n", desc.buffer_addr, len, va, st->tdh, st->tdt)); - vr->iov[iovcnt].iov_base = va; - vr->iov[iovcnt].iov_len = len; - iovcnt++; - - if (desc.lower.data & E1000_TXD_CMD_EOP) { - eop = true; - /* Insert virtio-net header. */ - DBG(printk("hdr: flags=%X, cs=%u, co=%u, gso_t=%u, gso_s=%u, hlen=%u\n", hdr.flags, hdr.csum_start, hdr.csum_offset, hdr.gso_type, hdr.gso_size, hdr.hdr_len)); - if (unlikely(copy_to_user(vr->iov->iov_base, &hdr, sizeof(hdr)))) { - printk("copy_to_user(vnet_hdr)\n"); - net->broken = true; - break; - } - - /* Reset the TX context. */ - st->txc.vlan_needed = 0; - - /* Once we have collected all the frame fragments, - we can send it through the backend. */ - msg.msg_iovlen = iovcnt; - /* TODO compute iovlen during the cycle */ - iovlen = iov_length(vr->iov, iovcnt); - err = net->backend.sendmsg(opaque, &msg, iovlen, - st->tdt == next_tdh ? 0 : MSG_MORE); - IFRATE(if (st->tdt == next_tdh) net->rate_ctx.new.txfl++); - if (unlikely(err < 0)) { - printk("sendmsg() err!!\n"); - goto leave; // XXX - } - if (unlikely(err != iovlen)) - pr_debug("Truncated TX packet\n"); - total_len += iovlen; - IFRATE(net->rate_ctx.new.txpkts++); - - smp_wmb(); - for (i=0; iwb[i].value, - vr->wb[i].addr))) { - printk("copy_to_user(tx writeback)\n"); - net->broken = true; - goto leave; - } - } - work = true; - } - } - -next: - st->tdh = next_tdh; - if (unlikely(++next_tdh == st->txnum)) - next_tdh = 0; - } while (!eop); - - if (unlikely(total_len >= V1000_NET_WEIGHT)) { - v1000_poll_queue(&vr->poll); - break; - } - - if (st->tdt == st->tdh) { - /* Reload 'tdt' only when necessary. */ - smp_mb(); - CSB_READ(net->csb, guest_tdt, st->tdt); - if (unlikely(st->tdt >= st->txnum)) { - net->broken = true; - goto leave; - } - } - } - -leave: - if (work && v1000_tx_interrupts_enabled(net)) { - eventfd_signal(vr->call_ctx, 1); - IFRATE(net->rate_ctx.new.htxk++); - } - mutex_unlock(&vr->mutex); - - return; -} - -static inline uint32_t v1000_avail_rx(struct v1000_net * net) -{ - return ((net->state.rxnum + net->state.rdt) - net->state.rdh) % net->state.rxnum; -} - -static uint32_t v1000_avail_rx_bytes(struct v1000_net * net) -{ - return v1000_avail_rx(net) * net->config.rxbuf_size; -} - -static inline void v1000_set_rxkick(struct v1000_net *net, bool enable) -{ - uint32_t v; - - if (enable) { - v = (net->state.rdt + 1 + (net->state.rxnum - v1000_avail_rx(net) - 1) * 3/4) % net->state.rxnum; - } else - v = NET_PARAVIRT_NONE; - CSB_WRITE(net->csb, host_rxkick_at, v); -} - -static inline bool v1000_rx_interrupts_enabled(struct v1000_net * net) -{ - uint32_t v; - - CSB_READ(net->csb, guest_need_rxkick, v); - - return v; -} - -#if 0 -long lj = 0; -long cj; -int c = 0; -#endif - -/* Expects to be always run from workqueue - which acts as - * read-size critical section for our kind of RCU. */ -static void handle_rx(struct v1000_net *net) -{ - struct v1000_ring *vr = &net->rx_ring; - struct msghdr msg = { - .msg_name = NULL, - .msg_namelen = 0, - .msg_control = NULL, /* FIXME: get and handle RX aux data. */ - .msg_controllen = 0, - .msg_iov = vr->iov, - .msg_flags = MSG_DONTWAIT, - }; - size_t total_len = 0; - int err; - size_t sock_len; - void *opaque; - struct e1000_state * st = &net->state; - struct e1000_rx_desc desc; - void __user * va; - uint32_t avail_bytes; - unsigned fill; - uint16_t wblen; - uint32_t rdh; - unsigned iovcnt, i; - - DBG(printk("handle_rx()\n")); - - mutex_lock(&vr->mutex); - opaque = vr->private_data; - if (unlikely(!opaque || net->broken)) { - printk("[v1000] Broken device\n"); - goto leave; - } - - /* XXX Disable notification only when NOT using host_rxkick_at. */ - v1000_set_rxkick(net, false); - CSB_READ(net->csb, guest_rdt, st->rdt); - - while ((sock_len = net->backend.peek_head_len(opaque))) { - fill = sock_len; - sock_len += sizeof(struct virtio_net_hdr); - avail_bytes = v1000_avail_rx_bytes(net); - if (avail_bytes < sock_len) { - /* Reload rdt only when necessary. */ - CSB_READ(net->csb, guest_rdt, st->rdt); - avail_bytes = v1000_avail_rx_bytes(net); - if (avail_bytes < sock_len) { - /* If not enough space, reenable notifications. */ - v1000_set_rxkick(net, true); - smp_mb(); - /* Doublecheck. */ - CSB_READ(net->csb, guest_rdt, st->rdt); - avail_bytes = v1000_avail_rx_bytes(net); - if (avail_bytes < sock_len) - break; - v1000_set_rxkick(net, false); - } - } - - rdh = st->rdh; - /* The first slot of the iovec into which receive a new frame - will be used for the virtio-net header. */ - vr->iov[0].iov_base = net->rx_hdr + rdh; - vr->iov[0].iov_len = sizeof(struct virtio_net_hdr); - - /* Use RX descriptors to fill the remainder of vr->iov. */ - iovcnt = 1; - while (fill) { - /* Read the address into the descriptor. */ - if (unlikely(get_user(desc.buffer_addr, - (uint64_t *)(net->rx_desc + rdh)))) { - printk("copy_from_user(rxdesc) FAILED!!!\n"); - net->broken = true; - goto leave; - } - - /* Process the descriptor. */ - va = lookup_translation(net, desc.buffer_addr, - net->config.rxbuf_size); - if (unlikely(!va)) { - printk("Address translation FAILED: rdh=%u, phy=%llu, len=%u\n", rdh, desc.buffer_addr, net->config.rxbuf_size); - net->broken = true; - goto leave; - } - wblen = desc.length = net->config.rxbuf_size; - if (fill <= net->config.rxbuf_size) { - /* Last fragment. */ - desc.length = fill; - wblen = fill + 4; /* FCS aka Ethernet CRC. */ - } - - vr->iov[iovcnt].iov_base = va; - vr->iov[iovcnt].iov_len = desc.length; - vr->wb[iovcnt-1].addr = &net->rx_desc[rdh].status; - vr->wb[iovcnt-1].value = E1000_RXD_STAT_DD; - iovcnt++; - - /* Length writeback. */ - if (unlikely(put_user(wblen, &net->rx_desc[rdh].length))) { - printk("copy_to_user(rx len writeback)\n"); - net->broken = true; - goto leave; - } - - if (unlikely(++rdh == st->rxnum)) - rdh = 0; - fill -= desc.length; - } - vr->wb[iovcnt-2].value |= E1000_RXD_STAT_EOP; - msg.msg_iovlen = iovcnt; - - err = net->backend.recvmsg(opaque, &msg, sock_len); - /* Userspace might have consumed the packet meanwhile: - * it's not supposed to do this usually, but might be hard - * to prevent. Discard data we got (if any) and keep going. */ - if (unlikely(err != sock_len)) { - printk("Discarded rx packet: " - " len %d, expected %zd\n", err, sock_len); - /* Recover the RX descriptors. */ - continue; - } - - smp_mb(); - - /* Descriptors writeback. */ - for (i=0; iwb[i].value, vr->wb[i].addr))) { - printk("copy_to_user(rx writeback)\n"); - net->broken = true; - goto leave; - } - } - - st->rdh = rdh; - IFRATE(net->rate_ctx.new.rxpkts++); - - DBG(printk("received packet [len=%u,iovcnt=%u,rdh=%u,rdt=%u,avail=%u]\n", (unsigned)sock_len, iovcnt, st->rdh, st->rdt, avail_bytes)); -#if 0 - if (++c == 100000) { - cj = jiffies; - if (cj != lj) - printk("%lu pps\n", 300 * c / (cj - lj)); - c = 0; - lj = jiffies; - } -#endif - - total_len += sock_len; - if (unlikely(total_len >= V1000_NET_WEIGHT)) { - v1000_poll_queue(&vr->poll); - break; - } - } - -leave: - if (v1000_rx_interrupts_enabled(net)) { - eventfd_signal(vr->call_ctx, 1); - IFRATE(net->rate_ctx.new.hrxk++); - } - mutex_unlock(&vr->mutex); - DBG(printk("rxintr=%d\n", v1000_rx_interrupts_enabled(net))); -} - -static void handle_tx_kick(struct v1000_work *work) -{ - struct v1000_ring *vr = container_of(work, struct v1000_ring, - poll.work); - struct v1000_net *net = container_of(vr->dev, struct v1000_net, dev); - - IFRATE(net->rate_ctx.new.gtxk++); - handle_tx(net); -} - -static void handle_rx_kick(struct v1000_work *work) -{ - struct v1000_ring *vr = container_of(work, struct v1000_ring, - poll.work); - struct v1000_net *net = container_of(vr->dev, struct v1000_net, dev); - - IFRATE(net->rate_ctx.new.grxk++); - handle_rx(net); -} - -static void handle_tx_net(struct v1000_work *work) -{ - struct v1000_net *net = container_of(work, struct v1000_net, - tx_poll.work); - - IFRATE(net->rate_ctx.new.btxwu++); - handle_tx(net); -} - -static void handle_rx_net(struct v1000_work *work) -{ - struct v1000_net *net = container_of(work, struct v1000_net, - rx_poll.work); - - IFRATE(net->rate_ctx.new.brxwu++); - handle_rx(net); -} - -static int v1000_open(struct inode *inode, struct file *f) -{ - struct v1000_net *n = kmalloc(sizeof *n, GFP_KERNEL); - struct v1000_dev *dev; - int r; - - printk("%p.OPEN()\n", n); - if (!n) - return -ENOMEM; - n->configured = n->broken = false; - memset(&n->state, 0, sizeof(struct e1000_state)); - - dev = &n->dev; - n->tx_ring.handle_kick = handle_tx_kick; - n->rx_ring.handle_kick = handle_rx_kick; - r = v1000_dev_init(dev, &n->tx_ring, &n->rx_ring); - if (r < 0) { - kfree(n); - return r; - } - - v1000_poll_init(&n->tx_poll, handle_tx_net, POLLOUT, dev); - v1000_poll_init(&n->rx_poll, handle_rx_net, POLLIN, dev); - - f->private_data = n; - -#ifdef RATE - memset(&n->rate_ctx, 0, sizeof(n->rate_ctx)); - setup_timer(&n->rate_ctx.timer, &rate_callback, - (unsigned long)&n->rate_ctx); - r = mod_timer(&n->rate_ctx.timer, jiffies + msecs_to_jiffies(1500)); - if (r) - printk("[v1000] Error: mod_timer()\n"); -#endif - - printk("%p.OPEN_END()\n", n); - - return 0; -} - -static void v1000_net_disable_vr(struct v1000_net *n, - struct v1000_ring *vr) -{ - if (!vr->private_data) - return; - if (vr == &n->tx_ring) - v1000_poll_stop(&n->tx_poll); - else - v1000_poll_stop(&n->rx_poll); -} - -static int v1000_net_enable_vr(struct v1000_net *n, - struct v1000_ring *vr) -{ - void *opaque; - int ret; - - opaque = vr->private_data; - if (!opaque) - return 0; - if (vr == &n->tx_ring) { - ret = v1000_poll_start(&n->tx_poll, n->backend.get_file(opaque)); - } else - ret = v1000_poll_start(&n->rx_poll, n->backend.get_file(opaque)); - - return ret; -} - -static void *v1000_net_stop_vr(struct v1000_net *n, - struct v1000_ring *vr) -{ - void *opaque; - - mutex_lock(&vr->mutex); - opaque = vr->private_data; - v1000_net_disable_vr(n, vr); - vr->private_data = NULL; - mutex_unlock(&vr->mutex); - return opaque; -} - -static void v1000_net_stop(struct v1000_net *n, void **tx_opaque, - void **rx_opaque) -{ - *tx_opaque = v1000_net_stop_vr(n, &n->tx_ring); - *rx_opaque = v1000_net_stop_vr(n, &n->rx_ring); -} - -static void v1000_net_flush(struct v1000_net *n) -{ - v1000_poll_flush(&n->rx_poll); - v1000_poll_flush(&n->dev.rx_ring->poll); - v1000_poll_flush(&n->tx_poll); - v1000_poll_flush(&n->dev.tx_ring->poll); -} - -static int v1000_release(struct inode *inode, struct file *f) -{ - struct v1000_net *n = f->private_data; - void *tx_opaque; - void *rx_opaque; - - printk("%p.RELEASE()\n", n); - v1000_net_stop(n, &tx_opaque, &rx_opaque); - v1000_net_flush(n); - v1000_dev_stop(&n->dev); - v1000_dev_cleanup(&n->dev); - if (tx_opaque) - fput(n->backend.get_file(tx_opaque)); - if (rx_opaque) - fput(n->backend.get_file(rx_opaque)); - /* We do an extra flush before freeing memory, - * since jobs can re-queue themselves. */ - v1000_net_flush(n); - - IFRATE(del_timer(&n->rate_ctx.timer)); - kfree(n); - printk("%p.RELEASE_END()\n", n); - - return 0; -} - -static struct socket *get_raw_socket(int fd) -{ - struct { - struct sockaddr_ll sa; - char buf[MAX_ADDR_LEN]; - } uaddr; - int uaddr_len = sizeof uaddr, r; - struct socket *sock = sockfd_lookup(fd, &r); - - if (!sock) - return ERR_PTR(-ENOTSOCK); - - /* Parameter checking */ - if (sock->sk->sk_type != SOCK_RAW) { - r = -ESOCKTNOSUPPORT; - goto err; - } - - r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, - &uaddr_len, 0); - if (r) - goto err; - - if (uaddr.sa.sll_family != AF_PACKET) { - r = -EPFNOSUPPORT; - goto err; - } - return sock; -err: - fput(sock->file); - return ERR_PTR(r); -} - -static struct socket *get_tap_socket(int fd) -{ - struct file *file = fget(fd); - struct socket *sock; - - if (!file) - return ERR_PTR(-EBADF); - sock = tun_get_socket(file); - if (!IS_ERR(sock)) - return sock; - sock = macvtap_get_socket(file); - if (IS_ERR(sock)) - fput(file); - return sock; -} - -struct socket *get_netmap_socket(int fd); -void *netmap_get_backend(int fd); -struct file *netmap_backend_get_file(void *opaque); -int netmap_backend_sendmsg(void *opaque, struct msghdr *m, size_t len, - unsigned flags); -int netmap_backend_peek_head_len(void *opaque); -int netmap_backend_recvmsg(void *opaque, struct msghdr *m, size_t len); - -static struct socket *get_socket(int fd) -{ - struct socket *sock; - - /* special case to disable backend */ - if (fd == -1) - return NULL; - sock = get_raw_socket(fd); - if (!IS_ERR(sock)) - return sock; - sock = get_tap_socket(fd); - if (!IS_ERR(sock)) - return sock; - sock = get_netmap_socket(fd); - if (!IS_ERR(sock)) - return sock; - return ERR_PTR(-ENOTSOCK); -} - -static void *get_backend(struct v1000_net *n, int fd) -{ - /* Probe for the netmap backend first. */ - void *ret = netmap_get_backend(fd); - - if (!IS_ERR(ret)) { - /* Set the netmap backend ops. */ - n->backend.get_file = &netmap_backend_get_file; - n->backend.sendmsg = &netmap_backend_sendmsg; - n->backend.peek_head_len = &netmap_backend_peek_head_len; - n->backend.recvmsg = &netmap_backend_recvmsg; - printk("[v1000] netmap backend selected\n"); - return ret; - } - - /* Probe for a socket backend. */ - ret = get_socket(fd); - if (!IS_ERR(ret)) { - /* Set the socket backend ops. */ - n->backend.get_file = &socket_backend_get_file; - n->backend.sendmsg = &socket_backend_sendmsg; - n->backend.peek_head_len = &socket_backend_peek_head_len; - n->backend.recvmsg = &socket_backend_recvmsg; - printk("[v1000] socket backend selected\n"); - } else { - printk("[v1000] no backend found\n"); - } - - return ret; -} - -static long v1000_net_set_backend(struct v1000_net *n, struct v1000_ring *vr, int fd) -{ - void *opaque; - int r = 0; - - mutex_lock(&vr->mutex); - - opaque = get_backend(n, fd); - if (IS_ERR(opaque)) { - r = PTR_ERR(opaque); - goto err_vr; - } - - /* start polling new backend */ - //v1000_net_disable_vr(n, vr); - vr->private_data = opaque; - if (r) - goto err_used; - //r = v1000_net_enable_vr(n, vr); - if (r) - goto err_used; - - mutex_unlock(&vr->mutex); - - return 0; - -err_used: - v1000_net_enable_vr(n, vr); - fput(n->backend.get_file(opaque)); -err_vr: - mutex_unlock(&vr->mutex); - return r; -} - -static ssize_t v1000_read(struct file* file_ptr, char __user * buffer, - size_t n, loff_t * offset_ptr) -{ - n = 0; - *offset_ptr += n; - - return n; -} - -static int v1000_set_memory(struct v1000_net * net) -{ - struct V1000Translation *newmem, *oldmem; - - /* Use the new table to translate rings and csb memory. */ - if (!(net->tx_desc = lookup_translation(net, net->config.tx_ring.phy, - net->config.tx_ring.num * sizeof(struct e1000_tx_desc)))) - return -EFAULT; - if (!(net->rx_desc = lookup_translation(net, net->config.rx_ring.phy, - net->config.rx_ring.num * sizeof(struct e1000_rx_desc)))) - return -EFAULT; - net->tx_hdr = net->config.tx_ring.hdr.virt; - net->rx_hdr = lookup_translation(net, net->config.rx_ring.hdr.phy, - net->config.rx_ring.num * sizeof(struct virtio_net_hdr)); - if (!net->rx_hdr) - return -EFAULT; - if (!(net->csb = lookup_translation(net, net->config.csb_phy, - sizeof(struct paravirt_csb)))) - return -EFAULT; - - printk("[v1000] virtuals: tx=%p, rx=%p, tx_hdr=%p, rx_hdr=%p, csb=%p\n", - net->tx_desc, net->rx_desc, net->tx_hdr, net->rx_hdr, net->csb); - - newmem = kmalloc(sizeof(struct V1000Translation), GFP_KERNEL); - if (!newmem) - return -ENOMEM; - - memcpy(newmem, &net->config.tr, sizeof(struct V1000Translation)); - - oldmem = rcu_dereference_protected(net->dev.memory, - lockdep_is_held(&net->dev->mutex)); - rcu_assign_pointer(net->dev.memory, newmem); - synchronize_rcu(); - kfree(oldmem); - - return 0; -} - -static int v1000_set_eventfds_ring(struct v1000_ring * vr, struct V1000RingConfig * vrc) -{ - vr->kick = eventfd_fget(vrc->ioeventfd); - if (IS_ERR(vr->kick)) - return PTR_ERR(vr->kick); - - vr->call = eventfd_fget(vrc->irqfd); - if (IS_ERR(vr->call)) - return PTR_ERR(vr->call); - vr->call_ctx = eventfd_ctx_fileget(vr->call); - - if (vrc->resamplefd != ~0U) { - vr->resample = eventfd_fget(vrc->resamplefd); - if (IS_ERR(vr->resample)) - return PTR_ERR(vr->resample); - vr->resample_ctx = eventfd_ctx_fileget(vr->resample); - } else { - vr->resample = NULL; - vr->resample_ctx = NULL; - } - - return 0; -} - -static int v1000_set_eventfds(struct v1000_net * net) -{ - int r; - - if ((r = v1000_set_eventfds_ring(&net->tx_ring, &net->config.tx_ring))) - return r; - if ((r = v1000_set_eventfds_ring(&net->rx_ring, &net->config.rx_ring))) - return r; - - return 0; -} - -static void v1000_print_configuration(struct v1000_net * net) -{ - int i; - struct V1000Config * cfg = &net->config; - - printk("[v1000] configuration:\n"); - printk("TX: phy=%llu, num=%u, hdr.virt=%p, io=%u, irq=%u, resample=%u\n", - cfg->tx_ring.phy, cfg->tx_ring.num, - cfg->tx_ring.hdr.virt, cfg->tx_ring.ioeventfd, - cfg->tx_ring.irqfd, cfg->tx_ring.resamplefd); - printk("RX: phy=%llu, num=%u, hdr.phy=%llu, io=%u, irq=%u, resample=%u\n", - cfg->rx_ring.phy, cfg->rx_ring.num, - cfg->rx_ring.hdr.phy, cfg->rx_ring.ioeventfd, - cfg->rx_ring.irqfd, cfg->rx_ring.resamplefd); - printk("rxbuf_size=%u, csb_phy=%llu, tapfd=%d\n", - cfg->rxbuf_size, cfg->csb_phy, cfg->tapfd); - for (i=0; iconfig.tr.num; i++) { - printk(" pa=%llu, len=%llu, va=%p\n", net->config.tr.table[i].phy, - net->config.tr.table[i].length, net->config.tr.table[i].virt); - } -} - -static int v1000_configure(struct v1000_net * net) -{ - int r; - - /* Configure. */ - if ((r = v1000_dev_set_owner(&net->dev))) - return r; - if ((r = v1000_set_memory(net))) - return r; - if ((r = v1000_set_eventfds(net))) - return r; - if ((r = v1000_net_set_backend(net, &net->rx_ring, net->config.tapfd))) - return r; - if ((r = v1000_net_set_backend(net, &net->tx_ring, net->config.tapfd))) - return r; - net->state.txnum = net->config.tx_ring.num; - net->state.rxnum = net->config.rx_ring.num; - - v1000_print_configuration(net); - - /* Start polling. */ - if (net->tx_ring.handle_kick && (r = v1000_poll_start(&net->tx_ring.poll, net->tx_ring.kick))) - return r; - if (net->rx_ring.handle_kick && (r = v1000_poll_start(&net->rx_ring.poll, net->rx_ring.kick))) - return r; - if ((r = v1000_net_enable_vr(net, &net->tx_ring))) - return r; - if ((r = v1000_net_enable_vr(net, &net->rx_ring))) - return r; - - return 0; -} - -static int v1000_access_ok(struct v1000_net * net) -{ - struct V1000Translation * tr = &net->config.tr; - int i; - - for (i=0; inum; i++) { - if (!access_ok(VERIFY_WRITE, tr->table[i].virt, tr->table[i].length)) - return -1; - } - - return !(access_ok(VERIFY_WRITE, net->tx_desc, - net->config.tx_ring.num * sizeof(struct e1000_tx_desc)) - && access_ok(VERIFY_WRITE, net->rx_desc, - net->config.rx_ring.num * sizeof(struct e1000_rx_desc)) - && access_ok(VERIFY_READ, net->tx_hdr, - net->config.tx_ring.num * sizeof(struct virtio_net_hdr)) - && access_ok(VERIFY_WRITE, net->rx_hdr, - net->config.rx_ring.num * sizeof(struct virtio_net_hdr)) - && access_ok(VERIFY_WRITE, net->csb, sizeof(struct paravirt_csb)) - ); -} - -static ssize_t v1000_write(struct file * file_ptr, const char __user * buffer, size_t n, loff_t * offset_ptr) -{ - struct v1000_net * net = (struct v1000_net *)file_ptr->private_data; - int res; - - /* TODO if n->configured?? */ - - mutex_lock(&net->dev.mutex); - - if (n != sizeof(struct V1000Config)) { - n = -EINVAL; - goto leave; - } - - /* Read the configuration from userspace. */ - if (copy_from_user(&net->config, buffer, sizeof(struct V1000Config))) { - printk(KERN_ALERT "v1000_first_write(): copy_from_user()\n"); - n = -EFAULT; - goto leave; - } - - //printk("[v1000] configuration read\n"); - if ((res = v1000_configure(net))) { - n = res; - goto leave; - } - - if ((res = v1000_access_ok(net))) { - n = res; - goto leave; - } - //printk("[v1000] configuration OK\n"); - net->configured = true; - - *offset_ptr += n; - -leave: - mutex_unlock(&net->dev.mutex); - - return n; -} - -static const struct file_operations v1000_fops = { - .owner = THIS_MODULE, - .release = v1000_release, - .open = v1000_open, - .write = v1000_write, - .read = v1000_read, - .llseek = noop_llseek, -}; - - -/* Device number associated to the v1000 char device. */ -static dev_t device_number; -static struct cdev v1000_cdev; -static struct class *cl; - -static int __init v1000_init(void) -{ - int ret; - - printk(KERN_ALERT "[v1000] Module loaded\n"); - - /* Dynamic allocation of a device number */ - if ((ret = alloc_chrdev_region(&device_number, 0, 1, "v1000")) < 0) { - printk(KERN_ALERT "alloc_chrdev_region() failed"); - goto exit_after_error; - } - printk(KERN_INFO "[v1000] Device number allocated = (%d,%d)\n", MAJOR(device_number), MINOR(device_number)); - if ((cl = class_create(THIS_MODULE, "chardrv")) == NULL) { - printk(KERN_ALERT "class_create() failed"); - unregister_chrdev_region(device_number, 1); - goto exit_after_error; - } - if (device_create(cl, NULL, device_number, NULL, "v1000") == NULL) { - printk(KERN_ALERT "device_create() failed"); - class_destroy(cl); - unregister_chrdev_region(device_number, 1); - goto exit_after_error; - } - - /* Registering a char device into the kernel */ - cdev_init(&(v1000_cdev), &v1000_fops); - v1000_cdev.owner = THIS_MODULE; - v1000_cdev.ops = &v1000_fops; - if ((ret = cdev_add(&v1000_cdev, device_number, 1))) { - device_destroy(cl, device_number); - class_destroy(cl); - unregister_chrdev_region(device_number, 1); - printk(KERN_ALERT "cdev_add() failed[%d]!\n", ret); - goto exit_after_error; - } - printk(KERN_INFO "[v1000] Char device added into the kernel\n"); - - return 0; - -exit_after_error: - printk(KERN_ALERT "[v1000] Module loading failed!\n" ); - return ret; -} - -static void v1000_exit(void) // __exit -{ - cdev_del(&v1000_cdev); - device_destroy(cl, device_number); - class_destroy(cl); - unregister_chrdev_region(device_number, 1); - printk(KERN_INFO "[v1000] module unloaded\n"); -} - -module_init(v1000_init); -module_exit(v1000_exit); - -MODULE_VERSION("0.0.1"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Vincenzo Maffione"); -MODULE_DESCRIPTION("Host kernel accelerator for e1000-paravirt"); -//MODULE_ALIAS_MISCDEV(VHOST_NET_MINOR); -MODULE_ALIAS("devname:v1000"); diff --git a/private/LINUX/vhost-port/paravirt.h b/private/LINUX/vhost-port/paravirt.h deleted file mode 100644 index e8c49cb0b..000000000 --- a/private/LINUX/vhost-port/paravirt.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2013 Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef NET_PARAVIRT_H -#define NET_PARAVIRT_H - -/* - Support for virtio-like communication between host (H) and guest (G) NICs. - - The guest allocates the shared Communication Status Block (csb) and - write its physical address at CSBAL and CSBAH (data is little endian). - csb->csb_on enables the mode. If disabled, the device acts a regular one. - - Notifications for tx and rx are exchanged without vm exits - if possible. In particular (only mentioning csb mode below), - the following actions are performed. In the description below, - "double check" means verifying again the condition that caused - the previous action, and reverting the action if the condition has - changed. The condition typically depends on a variable set by the - other party, and the double check is done to avoid races. E.g. - - // start with A=0 - again: - // do something - if ( cond(C) ) { // C is written by the other side - A = 1; - // barrier - if ( !cond(C) ) { - A = 0; - goto again; - } - } - - TX: start from idle: - H starts with host_need_txkick=1 when the I/O thread bh is idle. Upon new - transmissions, G always updates guest_tdt. If host_need_txkick == 1, - G also writes to the TDT, which acts as a kick to H (so pending - writes are always dispatched to H as soon as possible.) - - TX: active state: - On the kick (TDT write) H sets host_need_txkick == 0 (if not - done already by G), and starts an I/O thread trying to consume - packets from TDH to guest_tdt, periodically refreshing host_tdh - and TDH. When host_tdh == guest_tdt, H sets host_need_txkick=1, - and then does the "double check" for race avoidance. - - TX: G runs out of buffers - XXX there are two mechanisms, one boolean (using guest_need_txkick) - and one with a threshold (using guest_txkick_at). They are mutually - exclusive. - BOOLEAN: when G has no space, it sets guest_need_txkick=1 and does - the double check. If H finds guest_need_txkick== 1 on a write - to TDH, it also generates an interrupt. - THRESHOLD: G sets guest_txkick_at to the TDH value for which it - wants to receive an interrupt. When H detects that TDH moves - across guest_txkick_at, it generates an interrupt. - This second mechanism reduces the number of interrupts and - TDT writes on the transmit side when the host is too slow. - - RX: start from idle - G starts with guest_need_rxkick = 1 when the receive ring is empty. - As packets arrive, H updates host_rdh (and RDH) and also generates an - interrupt when guest_need_rxkick == 1 (so incoming packets are - always reported to G as soon as possible, apart from interrupt - moderation delays). It also tracks guest_rdt for new buffers. - - RX: active state - As the interrupt arrives, G sets guest_need_rxkick = 0 and starts - draining packets from the receive ring, while updating guest_rdt - When G runs out of packets it sets guest_need_rxkick=1 and does the - double check. - - RX: H runs out of buffers - XXX there are two mechanisms, one boolean (using host_need_rxkick) - and one with a threshold (using host_xxkick_at). They are mutually - exclusive. - BOOLEAN: when H has no space, it sets host_need_rxkick=1 and does the - double check. If G finds host_need_rxkick==1 on updating guest_rdt, - it also writes to RDT causing a kick to H. - THRESHOLD: H sets host_rxkick_at to the RDT value for which it wants - to receive a kick. When G detects that guest_rdt moves across - host_rxkick_at, it writes to RDT thus generates a kick. - This second mechanism reduces the number of kicks and - RDT writes on the receive side when the guest is too slow and - would free only a few buffers at a time. - - */ -struct paravirt_csb { - /* XXX revise the layout to minimize cache bounces. - * Usage is described as follows: - * [GH][RW][+-0] guest/host reads/writes frequently/rarely/almost never - */ - /* these are (mostly) written by the guest */ - uint32_t guest_tdt; /* GW+ HR+ pkt to transmit */ - uint32_t guest_need_txkick; /* GW- HR+ G ran out of tx bufs, request kick */ - uint32_t guest_need_rxkick; /* GW- HR+ G ran out of rx pkts, request kick */ - uint32_t guest_csb_on; /* GW- HR+ enable paravirtual mode */ - uint32_t guest_rdt; /* GW+ HR+ rx buffers available */ - uint32_t guest_txkick_at; /* GW- HR+ tx ring pos. where G expects an intr */ - uint32_t guest_use_msix; /* GW0 HR0 guest uses MSI-X interrupts. */ - uint32_t pad[9]; - - /* these are (mostly) written by the host */ - uint32_t host_tdh; /* GR0 HW- shadow register, mostly unused */ - uint32_t host_need_txkick; /* GR+ HW- start the iothread */ - uint32_t host_txcycles_lim; /* GW- HR- how much to spin before sleep. - * set by the guest */ - uint32_t host_txcycles; /* GR0 HW- counter, but no need to be exported */ - uint32_t host_rdh; /* GR0 HW- shadow register, mostly unused */ - uint32_t host_need_rxkick; /* GR+ HW- flush rx queued packets */ - uint32_t host_isr; /* GR* HW* shadow copy of ISR */ - uint32_t host_rxkick_at; /* GR+ HW- rx ring pos where H expects a kick */ - uint32_t vnet_ring_high; /* Vnet ring physical address high. */ - uint32_t vnet_ring_low; /* Vnet ring physical address low. */ -}; - -#define NET_PARAVIRT_CSB_SIZE 4096 -#define NET_PARAVIRT_NONE (~((uint32_t)0)) - -#ifdef QEMU_PCI_H - -/* - * API functions only available within QEMU - */ - -void paravirt_configure_csb(struct paravirt_csb** csb, uint32_t csbbal, - uint32_t csbbah, QEMUBH* tx_bh, AddressSpace *as); - -#endif /* QEMU_PCI_H */ - -#endif /* NET_PARAVIRT_H */ diff --git a/private/LINUX/vhost-port/test.c b/private/LINUX/vhost-port/test.c deleted file mode 100644 index 41da38f4e..000000000 --- a/private/LINUX/vhost-port/test.c +++ /dev/null @@ -1,682 +0,0 @@ -#include "buildpkt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifndef u16 -#define u16 uint16_t -#endif -#include /* struct virtio_net_hdr */ - -#include "tun_alloc.h" -#include "paravirt.h" -#include "v1000_user.h" - - -/* ========================== Useful macros =============================== */ -typedef unsigned char bool; -#define false 0 -#define true 1 - -/* GCC compiler barrier (from Wikipedia). */ -#define compiler_barrier() do { \ - asm volatile("" ::: "memory"); \ - } while (0) -/* ======================================================================= */ - - -#define RATE /* Enable rating & statistics. */ -bool check_rx_payload = 1; -bool use_resamplefd = 0; -bool tx_context_descriptor = 1; - - - -/* The e1000 TX and RX descriptor rings. */ -#define NUM_DESCRIPTORS 256 -static struct e1000_tx_desc tx_desc_mem[NUM_DESCRIPTORS]; -static struct e1000_rx_desc rx_desc_mem[NUM_DESCRIPTORS]; - -/* TX and RX vnet-hdr rings. The first NUM_DESCRIPTORS are for - transmission, while the others are for reception. */ -static struct virtio_net_hdr vnet_hdr_rings[2*NUM_DESCRIPTORS]; - -/* The packet buffers. The first TX_SKBUFFS are for transmission, - while the others are for reception. */ -#define NUM_SKBUFFS 1000 -#define NUM_TX_SKBUFFS (NUM_SKBUFFS/2) -#define NUM_RX_SKBUFFS (NUM_SKBUFFS-NUM_TX_SKBUFFS) -static struct pkt skbuffs[NUM_SKBUFFS]; -static int skb_tx = 0; -static int skb_rx = 0; -#define ETH_FRAME_SIZE 490U -#define ETH_FRAME_SIZE_STR "490" -#define MAX_NUM_FRAGS 9 - -/* Fake physical base addresses. Please make sure they - don't overlap. */ -#define CSB_PHY 15000000 -#define TXRING_PHY 22000000 -#define RXRING_PHY 68000000 -#define VNET_RING_PHY 101000000 -#define SKBUFFS_PHY 258000000 - - -/* The communication status block. */ -static struct paravirt_csb csb_mem; - - -/* V1000 configuration. */ -struct V1000Config config; - -/* Flag to stop sender and receiver threads. */ -static int stop = 0; - -/* Create a new eventfd. */ -static void new_eventfd(uint32_t * fdp) -{ - int efd; - int initval = 0; - int flags = 0; - - if ((efd = eventfd(initval, flags)) < 0) { - perror("eventfd()\n"); - exit(EXIT_FAILURE); - } - *fdp = (uint32_t)efd; -} - -/* Set the ring parameters. */ -static void configure_ring(struct V1000RingConfig * rc, uint64_t phy, bool physical, uint64_t hdr_phy, void * hdr_virt) -{ - rc->phy = phy; - if (physical) - rc->hdr.phy = hdr_phy; - else - rc->hdr.virt = hdr_virt; - rc->num = NUM_DESCRIPTORS; - new_eventfd(&rc->ioeventfd); - new_eventfd(&rc->irqfd); - if (use_resamplefd) - new_eventfd(&rc->resamplefd); - else - rc->resamplefd = ~0U; -} - -/* Set a row of the translation table. */ -static void configure_table(struct V1000Config * cfg, unsigned idx, uint64_t phy, uint64_t length, void * virt) -{ - if (idx >= MAX_TRANSLATION_ELEMENTS) { - printf("idx too big (%d)\n", idx); - exit(EXIT_FAILURE); - } - - cfg->tr.table[idx].phy = phy; - cfg->tr.table[idx].length = length; - cfg->tr.table[idx].virt = virt; -} - -/* Configure the v1000 device. */ -static void configure(int vfd, const char * si, const char * ri, - struct V1000Config * cfg) -{ - char tapname[IFNAMSIZ]; - int n; - int tfd; - - configure_ring(&cfg->tx_ring, TXRING_PHY, false, 0, &vnet_hdr_rings); - configure_ring(&cfg->rx_ring, RXRING_PHY, true, VNET_RING_PHY, NULL); - - cfg->rxbuf_size = sizeof(struct pkt); - - cfg->csb_phy = CSB_PHY; - - memset(&cfg->tr, 0, sizeof(struct V1000Translation)); - configure_table(cfg, 0, cfg->tx_ring.phy, - cfg->tx_ring.num * sizeof(struct e1000_tx_desc), - &tx_desc_mem[0]); - configure_table(cfg, 1, cfg->rx_ring.phy, - cfg->rx_ring.num * sizeof(struct e1000_rx_desc), - &rx_desc_mem[0]); - configure_table(cfg, 2, SKBUFFS_PHY, NUM_SKBUFFS * sizeof(struct pkt), - &skbuffs[0]); - configure_table(cfg, 3, cfg->csb_phy, NET_PARAVIRT_CSB_SIZE, &csb_mem); - configure_table(cfg, 4, cfg->rx_ring.hdr.phy, - cfg->rx_ring.num * sizeof(struct virtio_net_hdr), - &vnet_hdr_rings[cfg->tx_ring.num]); - cfg->tr.num = 5; - - strcpy(tapname, "tap"); - strcpy(tapname + 3, ri); - tfd = tun_alloc(tapname, IFF_TAP | IFF_NO_PI | IFF_VNET_HDR); - if (tfd < 0) { - perror("tun_alloc()\n"); - exit(EXIT_FAILURE); - } - cfg->tapfd = tfd; - - /* Flush the configuration to the v1000 device. */ - n = write(vfd, cfg, sizeof(struct V1000Config)); - if (n != sizeof(struct V1000Config)) { - perror("v1000 configuration failed!\n"); - printf("write returned %d\n", n); - exit(EXIT_FAILURE); - } -} - -/* Closes all the file descriptors opened. */ -static void cleanup(int vfd, struct V1000Config * cfg) -{ - close(cfg->tx_ring.ioeventfd); - close(cfg->tx_ring.irqfd); - if (use_resamplefd) - close(cfg->tx_ring.resamplefd); - close(cfg->rx_ring.ioeventfd); - close(cfg->rx_ring.irqfd); - if (use_resamplefd) - close(cfg->rx_ring.resamplefd); - close(cfg->tapfd); - close(vfd); -} - -/* CSB initialization. */ -static void csb_init(struct paravirt_csb * csb) -{ - csb->guest_tdt = 0; - csb->guest_need_txkick = 0; - csb->guest_need_rxkick = 1; - csb->guest_csb_on = 1; - csb->guest_rdt = 0; - csb->guest_txkick_at = ~0; - csb->host_tdh = 0; - csb->host_need_txkick = 1; - csb->host_txcycles_lim = 1; - csb->host_txcycles = 0; - csb->host_rdh = 0; - csb->host_need_rxkick = 1; - csb->host_isr = 0; - csb->host_rxkick_at = 0; - csb->vnet_ring_high = 0; //XXX - csb->vnet_ring_low = 0; //XXX -} - -/* Prefill all the TX frames. */ -static void build_tx_frames(const char * si, const char * ri, - struct pkt * frames, int num) -{ -#define NUM_ARGS 10 - char * argv[NUM_ARGS]; - char argc; - uint32_t i; - - memset(frames, 0, num * sizeof(struct pkt)); - - /* Some memory for the string arguments. */ - for (i=0; iguest_tdt; - /* We need space for MAX_NUM_FRAGS and a context descriptor. */ - if (tx_descriptors_avail(tdt, ntc) < MAX_NUM_FRAGS+1) { - //printf("TX ring full\n"); - csb->guest_need_txkick = 1; - compiler_barrier(); - /* Doublecheck. */ - ntc = clean_used_tx_descriptors(tx_desc, ntc); - if (tx_descriptors_avail(tdt, ntc) >= MAX_NUM_FRAGS+1) - goto more_used; - if (read(cfg->tx_ring.irqfd, &event, sizeof(event)) - != sizeof(event)) { - perror("read(tx_ring.irqfd)\n"); - exit(EXIT_FAILURE); - } -more_used: - csb->guest_need_txkick = 0; - compiler_barrier(); - continue; - } - - /* Insert a context descriptor. */ - if (tx_context_descriptor) { - txc_desc[tdt].lower_setup.ip_config = 0; - txc_desc[tdt].upper_setup.tcp_fields.tucss = sizeof(frame->eh) + sizeof(frame->ip); /* 34 */ - txc_desc[tdt].upper_setup.tcp_fields.tucso = txc_desc[tdt].upper_setup.tcp_fields.tucss + 6; - txc_desc[tdt].upper_setup.tcp_fields.tucse = 0; /* Checksum up to the end of the frame. */ - txc_desc[tdt].cmd_and_length = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C - | E1000_TXD_CMD_RS; /* TODO remove this flag when implement next-to-watch */ - txc_desc[tdt].tcp_seg_setup.data = 0; - if (++tdt == NUM_DESCRIPTORS) - tdt = 0; - } - - /* Insert a new frame in the ring, using as many TX descriptors - as needed. */ - offset = 0; - frag_size = ETH_FRAME_SIZE / frags; - if (frag_size > 0xffff) { - printf("Fragment too big (%d)\n", frag_size); - return NULL; - } - while (offset < ETH_FRAME_SIZE) { - tx_desc[tdt].upper.data = 0; - tx_desc[tdt].lower.data = E1000_TXD_DTYP_D | E1000_TXD_CMD_DEXT - | E1000_TXD_CMD_RS; /* TODO remove this flag when implement next-to-watch */ - if (ETH_FRAME_SIZE - offset <= frag_size) { - frag_size = ETH_FRAME_SIZE - offset; - tx_desc[tdt].lower.data |= E1000_TXD_CMD_EOP - | E1000_TXD_CMD_RS; - } - /* Request the NIC to insert a TCP/UDP checksum by setting - the proper bit in the POPTS field of the first data - descriptor packet. */ - if (tx_context_descriptor && offset == 0) - tx_desc[tdt].upper.data |= ((E1000_TXD_POPTS_TXSM) << 8); - - tx_desc[tdt].buffer_addr = SKBUFFS_PHY + skb_tx - * sizeof(struct pkt) + offset; - tx_desc[tdt].lower.data |= frag_size; - offset += frag_size; - //printf("[tdt=%u]: phy=%lu, lower.data=%u\n", tdt, tx_desc[tdt].buffer_addr, tx_desc[tdt].lower.data); - if (++tdt == NUM_DESCRIPTORS) - tdt = 0; - } - rate_txpkts++; - if (++skb_tx == NUM_TX_SKBUFFS) - skb_tx = 0; - - compiler_barrier(); - - /* Kick the v1000 tx frontend (if is the case. */ - csb->guest_tdt = tdt; - if (csb->host_need_txkick) { - write(cfg->tx_ring.ioeventfd, &event, sizeof(event)); - rate_txkicks++; - //printf("TX kick\n"); - } - /*printf("ntc=%d, tdt=%d\n", ntc, tdt); - printf("txpkts=%d, txkicks=%d\n", rate_txpkts, rate_txkicks);*/ - } - - return NULL; -} - -struct sgvec { - uint64_t phy; - uint64_t len; -}; - -/* Prepare new available RX descriptors. */ -static uint32_t prepare_rx_descriptors(volatile struct e1000_rx_desc* desc, - uint32_t idx, int num) -{ - while (num) { - desc[idx].buffer_addr = SKBUFFS_PHY + - (NUM_TX_SKBUFFS + skb_rx) * sizeof(struct pkt); - desc[idx].length = 0; - desc[idx].csum = 0; - desc[idx].status = 0; - desc[idx].errors = 0; - desc[idx].special = 0; - if (++idx == NUM_DESCRIPTORS) - idx = 0; - if (++skb_rx == NUM_RX_SKBUFFS) - skb_rx = 0; - num--; - } - - return idx; -} - -static int check_rx_header(volatile struct virtio_net_hdr * hdr) -{ - return hdr->flags || hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE || - hdr->hdr_len || hdr->gso_size || hdr->csum_start || - hdr->csum_offset; -} - -static void print_hex(const char * name, unsigned char * d, int size) -{ - int i; - - printf("%s: ", name); - for (i=0; i= sizeof(p->eh)) - print_hex("ethernet", (unsigned char *)&p->eh, sizeof(p->eh)); - if (len >= sizeof(p->eh) + sizeof(p->ip)) - print_hex("ip", (unsigned char *)&p->ip, sizeof(p->ip)); - if (len >= sizeof(p->eh) + sizeof(p->ip) + sizeof(p->udp)) { - print_hex("udp", (unsigned char *)&p->udp, sizeof(p->udp)); - print_hex("body", (unsigned char *)&p->body, len - - (sizeof(p->eh) + sizeof(p->ip) + sizeof(p->udp))); - } - printf("\n"); -} - -static int check_received_packet(struct sgvec * sg, int sgcnt) -{ - struct pkt packet; - struct pkt * p = &packet; - uint32_t * d; - int i; - int offset = 0; - int hdrlen = sizeof(p->eh) + sizeof(p->ip) + sizeof(p->udp); - - for (i=0; irx_ring.irqfd, &event, sizeof(event)) - != sizeof(event)) { - perror("read(tx_ring.irqfd)\n"); - exit(EXIT_FAILURE); - } - rate_rxintrs++; -again: - /* Disable notifications. */ - csb->guest_need_rxkick = 0; - compiler_barrier(); - - /* Receive and clean used descriptors. */ - while (rx_desc[ntr].status & E1000_RXD_STAT_DD) { - //printf("Received packet [len=%u,ntr=%u,rdt=%u]\n", rx_desc[ntr].length, ntr, csb->guest_rdt); - if (sgcnt == MAX_NUM_FRAGS) { - /* If this happens, there is a bug in the kernel code. */ - printf("BUG: oversized RX descriptors chain.\n"); - sgcnt = 0; /* Force to 0 to avoid buffer overflow. */ - } - if (!sgcnt) { - /* First frame fragment. */ - if (check_rx_header(rx_hdr + ntr)) { - printf("Bad viritio-net header\n"); - } - } - sg[sgcnt].phy = rx_desc[ntr].buffer_addr; - sg[sgcnt].len = rx_desc[ntr].length; - sgcnt++; - if (rx_desc[ntr].status & E1000_RXD_STAT_EOP) { - sg[sgcnt-1].len -= 4; /* Remove FSC/CRC. */ - check_received_packet(&sg[0], sgcnt); - rate_rxpkts++; - sgcnt = 0; -#ifdef RATE - if (rate_rxpkts == overflow) { - /* Rating report. */ - gettimeofday(&te, NULL); - usecs = (te.tv_sec - tb.tv_sec) * 1000000 + - te.tv_usec - tb.tv_usec; - printf("RX: %3.6f Mpps\n", rate_rxpkts/((double)usecs)); - printf("RXINTR: %3.6f Mpps\n", rate_rxintrs/((double)usecs)); - printf("\n"); - rate_rxpkts = rate_rxintrs = 0; - if (usecs < RATE_LB_US) - overflow *= 2; - else if (usecs > RATE_UB_US) - overflow /= 2; - gettimeofday(&tb, NULL); - } -#endif /* RATE */ - } - rx_desc[ntr].status = 0; - csb->guest_rdt = prepare_rx_descriptors(rx_desc, csb->guest_rdt, 1); - compiler_barrier(); - if (csb->host_rxkick_at == ntr) { - write(cfg->rx_ring.ioeventfd, &event, sizeof(event)); - rate_rxkicks++; - //printf("RX kick\n"); - } - if (++ntr == NUM_DESCRIPTORS) - ntr = 0; - } - - /* Reenable notifications. */ - csb->guest_need_rxkick = 1; - compiler_barrier(); - /* Doublecheck. */ - if (rx_desc[ntr].status & E1000_RXD_STAT_DD) { - goto again; - } - } - - return NULL; -} - -void usage() -{ - printf("CMD INDEX [s {INDEX,H}] [r]\n"); - exit(EXIT_FAILURE); -} - -int main(int argc, char ** argv) -{ - pthread_t sender_thread; - pthread_t receiver_thread; - const char * ri; - const char * si; - int enable_sender = 0; - int enable_receiver = 0; - int vfd; - int c; - - /* Program input parsing. */ - if (argc < 2) - usage(); - ri = argv[1]; - si = NULL; - for (c=2; c -#include -#include -#include -#include - -#include "tun_alloc.h" - - -int tun_alloc(char *dev, int flags) { - - struct ifreq ifr; - int fd, err; - char *clonedev = "/dev/net/tun"; - - /* Arguments taken by the function: - * - * char *dev: the name of an interface (or '\0'). MUST have enough - * space to hold the interface name if '\0' is passed - * int flags: interface flags (eg, IFF_TUN etc.) - */ - - /* open the clone device */ - if( (fd = open(clonedev, O_RDWR)) < 0 ) { - perror( "open(/dev/net/tun)" ); - return fd; - } - - /* preparation of the struct ifr, of type "struct ifreq" */ - memset(&ifr, 0, sizeof(ifr)); - - ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ - - if (*dev) { - /* if a device name was specified, put it in the structure; otherwise, - * the kernel will try to allocate the "next" device of the - * specified type */ - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - } - - /* try to create the device */ - //err = ioctl(fd, 0x400454ca, (void *) &ifr); - err = ioctl(fd, TUNSETIFF, (void *) &ifr); - if( err < 0 ) { - perror( "ioctl(TUNSETIFF)" ); - close(fd); - return err; - } - - /* if the operation was successful, write back the name of the - * interface to the variable "dev", so the caller can know - * it. Note that the caller MUST reserve space in *dev (see calling - * code below) */ - strcpy(dev, ifr.ifr_name); - - /* this is the special file descriptor that the caller will use to talk - * with the virtual interface */ - return fd; -} diff --git a/private/LINUX/vhost-port/tun_alloc.h b/private/LINUX/vhost-port/tun_alloc.h deleted file mode 100644 index 664094e46..000000000 --- a/private/LINUX/vhost-port/tun_alloc.h +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -int tun_alloc( char *dev, int flags ); - -/* SHELL COMMANDS - per creare ed eliminare interfacce TUN/TAP persistenti (iproute2) - ip tuntap add mode tun name tun0 - ip tuntap add mode tun name tun1 - - per assegnare indirizzi IP alle interfacce - ip link set tun0 up - ip link set tun1 up - ip addr add 10.0.0.1/24 dev tun0 - ip addr add 10.0.0.2/24 dev tun1 - - bridging (non serve in questo caso) - brctl addbr br0 - brctl addif br0 tun0 - brctl addif br0 tun1 - ip addr del 10.0.0.1/24 dev tun0 - ip addr del 10.0.0.2/24 dev tun1 - ip link set br0 up - ip addr add 10.0.0.1/24 dev br0 - ... -*/ diff --git a/private/LINUX/vhost-port/v1000.c b/private/LINUX/vhost-port/v1000.c deleted file mode 100644 index cccd7c4f4..000000000 --- a/private/LINUX/vhost-port/v1000.c +++ /dev/null @@ -1,335 +0,0 @@ -/* Copyright (C) 2009 Red Hat, Inc. - * Copyright (C) 2006 Rusty Russell IBM Corporation - * - * Author: Michael S. Tsirkin - * - * Inspiration, some code, and most witty comments come from - * Documentation/virtual/lguest/lguest.c, by Rusty Russell - * - * This work is licensed under the terms of the GNU GPL, version 2. - * - * Generic code for virtio server in host kernel. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "v1000.h" - - -static void v1000_poll_func(struct file *file, wait_queue_head_t *wqh, - poll_table *pt) -{ - struct v1000_poll *poll; - - poll = container_of(pt, struct v1000_poll, table); - poll->wqh = wqh; - add_wait_queue(wqh, &poll->wait); -} - -static int v1000_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync, - void *key) -{ - struct v1000_poll *poll = container_of(wait, struct v1000_poll, wait); - - //printk("%p.v1000_poll_wakeup(), %lu, %lu\n",poll,(unsigned long)key, poll->mask); - if (!((unsigned long)key & poll->mask)) - return 0; - - v1000_poll_queue(poll); - return 0; -} - -void v1000_work_init(struct v1000_work *work, v1000_work_fn_t fn) -{ - INIT_LIST_HEAD(&work->node); - work->fn = fn; - init_waitqueue_head(&work->done); - work->flushing = 0; - work->queue_seq = work->done_seq = 0; -} - -/* Init poll structure */ -void v1000_poll_init(struct v1000_poll *poll, v1000_work_fn_t fn, - unsigned long mask, struct v1000_dev *dev) -{ - init_waitqueue_func_entry(&poll->wait, v1000_poll_wakeup); - init_poll_funcptr(&poll->table, v1000_poll_func); - poll->mask = mask; - poll->dev = dev; - poll->wqh = NULL; - - v1000_work_init(&poll->work, fn); -} - -/* Start polling a file. We add ourselves to file's wait queue. The caller must - * keep a reference to a file until after v1000_poll_stop is called. */ -int v1000_poll_start(struct v1000_poll *poll, struct file *file) -{ - unsigned long mask; - int ret = 0; - - if (poll->wqh) - return 0; - - mask = file->f_op->poll(file, &poll->table); - if (mask) - v1000_poll_wakeup(&poll->wait, 0, 0, (void *)mask); - if (mask & POLLERR) { - if (poll->wqh) - remove_wait_queue(poll->wqh, &poll->wait); - ret = -EINVAL; - } - printk("%p.poll_start()\n", poll); - return ret; -} - -/* Stop polling a file. After this function returns, it becomes safe to drop the - * file reference. You must also flush afterwards. */ -void v1000_poll_stop(struct v1000_poll *poll) -{ - if (poll->wqh) { - remove_wait_queue(poll->wqh, &poll->wait); - poll->wqh = NULL; - } - printk("%p.poll_stop()\n", poll); -} - -static bool v1000_work_seq_done(struct v1000_dev *dev, struct v1000_work *work, - unsigned seq) -{ - int left; - - spin_lock_irq(&dev->work_lock); - left = seq - work->done_seq; - spin_unlock_irq(&dev->work_lock); - return left <= 0; -} - -static void v1000_work_flush(struct v1000_dev *dev, struct v1000_work *work) -{ - unsigned seq; - int flushing; - - spin_lock_irq(&dev->work_lock); - seq = work->queue_seq; - work->flushing++; - spin_unlock_irq(&dev->work_lock); - wait_event(work->done, v1000_work_seq_done(dev, work, seq)); - spin_lock_irq(&dev->work_lock); - flushing = --work->flushing; - spin_unlock_irq(&dev->work_lock); - BUG_ON(flushing < 0); -} - -/* Flush any work that has been scheduled. When calling this, don't hold any - * locks that are also used by the callback. */ -void v1000_poll_flush(struct v1000_poll *poll) -{ - v1000_work_flush(poll->dev, &poll->work); -} - -void v1000_work_queue(struct v1000_dev *dev, struct v1000_work *work) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->work_lock, flags); - if (list_empty(&work->node)) { - list_add_tail(&work->node, &dev->work_list); - work->queue_seq++; - wake_up_process(dev->worker); - } - spin_unlock_irqrestore(&dev->work_lock, flags); -} - -void v1000_poll_queue(struct v1000_poll *poll) -{ - v1000_work_queue(poll->dev, &poll->work); -} - -static void v1000_vr_reset(struct v1000_dev *dev, - struct v1000_ring *vr) -{ - vr->private_data = NULL; - vr->kick = NULL; - vr->call_ctx = NULL; - vr->call = NULL; -} - -static int v1000_worker(void *data) -{ - struct v1000_dev *dev = data; - struct v1000_work *work = NULL; - unsigned uninitialized_var(seq); - mm_segment_t oldfs = get_fs(); - - set_fs(USER_DS); - use_mm(dev->mm); - - for (;;) { - /* mb paired w/ kthread_stop */ - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irq(&dev->work_lock); - if (work) { - work->done_seq = seq; - if (work->flushing) - wake_up_all(&work->done); - } - - if (kthread_should_stop()) { - spin_unlock_irq(&dev->work_lock); - __set_current_state(TASK_RUNNING); - break; - } - if (!list_empty(&dev->work_list)) { - work = list_first_entry(&dev->work_list, - struct v1000_work, node); - list_del_init(&work->node); - seq = work->queue_seq; - } else - work = NULL; - spin_unlock_irq(&dev->work_lock); - - if (work) { - __set_current_state(TASK_RUNNING); - work->fn(work); - if (need_resched()) - schedule(); - } else - schedule(); - - } - unuse_mm(dev->mm); - set_fs(oldfs); - return 0; -} - -long v1000_dev_init(struct v1000_dev * dev, struct v1000_ring * tx_ring, - struct v1000_ring * rx_ring) -{ - int i; - - dev->rings[0] = dev->tx_ring = tx_ring; - dev->rings[1] = dev->rx_ring = rx_ring; - - mutex_init(&dev->mutex); - dev->memory = NULL; - dev->mm = NULL; - spin_lock_init(&dev->work_lock); - INIT_LIST_HEAD(&dev->work_list); - dev->worker = NULL; - - for (i=0; i<2; i++) { - dev->rings[i]->dev = dev; - mutex_init(&dev->rings[i]->mutex); - v1000_vr_reset(dev, dev->rings[i]); - if (dev->rings[i]->handle_kick) - v1000_poll_init(&dev->rings[i]->poll, - dev->rings[i]->handle_kick, POLLIN, dev); - } - - return 0; -} - -/* Caller should have device mutex */ -long v1000_dev_check_owner(struct v1000_dev *dev) -{ - /* Are you the owner? If not, I don't think you mean to do that */ - return dev->mm == current->mm ? 0 : -EPERM; -} - -/* Caller should have device mutex */ -long v1000_dev_set_owner(struct v1000_dev *dev) -{ - struct task_struct *worker; - int err; - - /* Is there an owner already? */ - if (dev->mm) { - err = -EBUSY; - goto err_mm; - } - - /* No owner, become one */ - dev->mm = get_task_mm(current); - worker = kthread_create(v1000_worker, dev, "v1000-%d", current->pid); - if (IS_ERR(worker)) { - err = PTR_ERR(worker); - goto err_worker; - } - - dev->worker = worker; - wake_up_process(worker); /* avoid contributing to loadavg */ - - - return 0; -err_worker: - if (dev->mm) - mmput(dev->mm); - dev->mm = NULL; -err_mm: - return err; -} - -void v1000_dev_stop(struct v1000_dev *dev) -{ - int i; - - for (i = 0; i<2; i++) { - if (dev->rings[i]->kick && dev->rings[i]->handle_kick) { - v1000_poll_stop(&dev->rings[i]->poll); - v1000_poll_flush(&dev->rings[i]->poll); - } - } -} - -/* Caller should have device mutex if and only if locked is set */ -void v1000_dev_cleanup(struct v1000_dev *dev) -{ - int i; - - for (i = 0; i<2; i++) { - if (dev->rings[i]->kick) - fput(dev->rings[i]->kick); - if (dev->rings[i]->call_ctx) - eventfd_ctx_put(dev->rings[i]->call_ctx); - if (dev->rings[i]->call) - fput(dev->rings[i]->call); - v1000_vr_reset(dev, dev->rings[i]); - } - /* No one will access memory at this point */ - kfree(rcu_dereference_protected(dev->memory, - false == - lockdep_is_held(&dev->mutex))); - RCU_INIT_POINTER(dev->memory, NULL); - WARN_ON(!list_empty(&dev->work_list)); - if (dev->worker) { - kthread_stop(dev->worker); - dev->worker = NULL; - } - if (dev->mm) - mmput(dev->mm); - dev->mm = NULL; -} - -/* This actually signals the guest, using eventfd. */ -void vhost_signal(struct v1000_dev *dev, struct v1000_ring *vr) -{ - /* Signal the Guest tell them we used something up. */ - if (vr->call_ctx) - eventfd_signal(vr->call_ctx, 1); -} - diff --git a/private/LINUX/vhost-port/v1000.h b/private/LINUX/vhost-port/v1000.h deleted file mode 100644 index 185ea14b6..000000000 --- a/private/LINUX/vhost-port/v1000.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _VHOST_H -#define _VHOST_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -struct v1000_work; -typedef void (*v1000_work_fn_t)(struct v1000_work *work); - -struct v1000_work { - struct list_head node; - v1000_work_fn_t fn; - wait_queue_head_t done; - int flushing; - unsigned queue_seq; - unsigned done_seq; -}; - -/* Poll a file (eventfd or socket) */ -/* Note: there's nothing vhost specific about this structure. */ -struct v1000_poll { - poll_table table; - wait_queue_head_t *wqh; - wait_queue_t wait; - struct v1000_work work; - unsigned long mask; - struct v1000_dev *dev; -}; - -void v1000_work_init(struct v1000_work *work, v1000_work_fn_t fn); -void v1000_work_queue(struct v1000_dev *dev, struct v1000_work *work); - -void v1000_poll_init(struct v1000_poll *poll, v1000_work_fn_t fn, - unsigned long mask, struct v1000_dev *dev); -int v1000_poll_start(struct v1000_poll *poll, struct file *file); -void v1000_poll_stop(struct v1000_poll *poll); -void v1000_poll_flush(struct v1000_poll *poll); -void v1000_poll_queue(struct v1000_poll *poll); - -struct writeback_info { - uint8_t * addr; - uint8_t value; -}; - -struct v1000_ring; - -/* The v1000_ring structure describes a queue attached to a device. */ -struct v1000_ring { - struct v1000_dev *dev; - - struct mutex mutex; - struct file *kick; - struct file *call; - struct eventfd_ctx *call_ctx; - struct file *resample; - struct eventfd_ctx *resample_ctx; - - struct v1000_poll poll; - - /* The routine to call when the Guest pings us, or timeout. */ - v1000_work_fn_t handle_kick; - - struct iovec iov[UIO_MAXIOV]; - - struct writeback_info wb[UIO_MAXIOV]; - - /* Protected by virtual ring mutex. */ - void *private_data; -}; - -struct v1000_dev { - /* Readers use RCU to access memory table pointer - * log base pointer and features. - * Writers use mutex below.*/ - struct V1000Translation __rcu *memory; - struct mm_struct *mm; - struct mutex mutex; - struct v1000_ring * tx_ring; - struct v1000_ring * rx_ring; - struct v1000_ring * rings[2]; - spinlock_t work_lock; - struct list_head work_list; - struct task_struct *worker; -}; - -long v1000_dev_init(struct v1000_dev *, struct v1000_ring *, struct v1000_ring *); -void v1000_dev_cleanup(struct v1000_dev *); -void v1000_dev_stop(struct v1000_dev *); -int v1000_vr_access_ok(struct v1000_ring *vr); -long v1000_dev_set_owner(struct v1000_dev *dev); - - -#include "v1000_user.h" - -#endif diff --git a/private/LINUX/vhost-port/v1000_user.h b/private/LINUX/vhost-port/v1000_user.h deleted file mode 100644 index 0407f4e5d..000000000 --- a/private/LINUX/vhost-port/v1000_user.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __V1000__USER__HH -#define __V1000__USER__HH - - -struct V1000TranslationElem { - uint64_t phy; - uint64_t length; - void * virt; -}; - -struct V1000Translation { -#define MAX_TRANSLATION_ELEMENTS 64 - struct V1000TranslationElem table[MAX_TRANSLATION_ELEMENTS]; - unsigned num; -}; - -struct V1000RingConfig { - uint64_t phy; - union { - uint64_t phy; /* For the RX ring. */ - void * virt; /* For the TX ring. */ - } hdr; - uint32_t num; - uint32_t ioeventfd; - uint32_t irqfd; - uint32_t resamplefd; -}; - -struct V1000Config { - struct V1000RingConfig tx_ring; - struct V1000RingConfig rx_ring; - uint32_t rxbuf_size; /* RX buffer size. */ - uint64_t csb_phy; /* CSB physical address. */ - uint32_t tapfd; /* Backend file descriptor. */ - struct V1000Translation tr; -}; - - -#include "e1000_regs.h" - - -#endif diff --git a/private/LINUX/vhost-port/vhost-code-tracking.txt b/private/LINUX/vhost-port/vhost-code-tracking.txt deleted file mode 100644 index 726edd4d9..000000000 --- a/private/LINUX/vhost-port/vhost-code-tracking.txt +++ /dev/null @@ -1,7 +0,0 @@ -# These are linux commit identifiers -# - 'root' is the commit from which I did the original porting. -# - 'last-included' is the last commit that the current v1000 -# is synchronized with. - -root:46aa92d1ba162b4b3d6b7102440e459d4e4ee255 -last-included:f7c6be404d8fa52c54ff931390aab01e5c7654d6 diff --git a/private/LINUX/wip-patches/diff--mellanox--30300--30800 b/private/LINUX/wip-patches/diff--mellanox--30300--30800 deleted file mode 100644 index 9cb61aa5d..000000000 --- a/private/LINUX/wip-patches/diff--mellanox--30300--30800 +++ /dev/null @@ -1,145 +0,0 @@ -diff -urp --exclude '*.o' --exclude '*.cmd' --exclude '*mod.c' drivers/net/ethernet/mellanox/mlx4/en_netdev.c ./mellanox/mlx4/en_netdev.c ---- drivers/net/ethernet/mellanox/mlx4/en_netdev.c 2012-09-11 20:50:55.982624673 -0700 -+++ ./mellanox/mlx4/en_netdev.c 2012-09-27 00:05:22.703523430 -0700 -@@ -48,6 +48,39 @@ - #include "mlx4_en.h" - #include "en_port.h" - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+/* -+ * This driver is split in multiple small files. -+ * The main device descriptor has type struct mlx4_en_priv *priv; -+ * and we attach to the device in mlx4_en_init_netdev() -+ * (do port numbers start from 1 ?) -+ * -+ * The reconfig routine is in mlx4_en_start_port() (also here) -+ * which is called on a mlx4_en_restart() (watchdog), open and set-mtu. -+ * -+ * priv->num_frags ?? -+ * DS_SIZE ?? -+ * apparently each rx desc is followed by frag.descriptors -+ * and the rx desc is rounded up to a power of 2. -+ * -+ * Receive code is in en_rx.c -+ * priv->rx_ring_num number of rx rings -+ * rxr = prov->rx_ring[ring_ind] rx ring descriptor -+ * rxr->size number of slots -+ * rxr->prod producer -+ * probably written into a mmio reg at *rxr->wqres.db.db -+ * trimmed to 16 bits. -+ * -+ * Rx init routine: -+ * mlx4_en_activate_rx_rings() -+ * mlx4_en_init_rx_desc() -+ * Transmit code is in en_tx.c -+ */ -+ -+#define NETMAP_MLX4_MAIN -+#include /* extern stuff */ -+#endif /* CONFIG_NETMAP */ -+ - int mlx4_en_setup_tc(struct net_device *dev, u8 up) - { - if (up != MLX4_EN_NUM_UP) -@@ -1042,6 +1075,9 @@ int mlx4_en_start_port(struct net_device - /* Set initial ownership of all Tx TXBBs to SW (1) */ - for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) - *((u32 *) (tx_ring->buf + j)) = 0xffffffff; -+#ifdef DEV_NETMAP -+ mlx4_netmap_tx_config(priv, i); -+#endif /* DEV_NETMAP */ - ++tx_index; - } - -@@ -1639,6 +1675,9 @@ int mlx4_en_init_netdev(struct mlx4_en_d - en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); - - queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); -+#ifdef DEV_NETMAP -+ mlx4_netmap_attach(priv); -+#endif /* DEV_NETMAP */ - return 0; - - out: ---- drivers/net/ethernet/mellanox/mlx4/en_rx.c 2012-09-11 20:50:55.982624673 -0700 -+++ ./mellanox/mlx4/en_rx.c 2012-09-27 00:13:16.099550954 -0700 -@@ -41,6 +41,9 @@ - - #include "mlx4_en.h" - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+#include -+#endif /* !DEV_NETMAP */ - - static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv, - struct mlx4_en_rx_desc *rx_desc, -@@ -365,9 +368,16 @@ int mlx4_en_activate_rx_rings(struct mlx - ring = &priv->rx_ring[ring_ind]; - - ring->size_mask = ring->actual_size - 1; -+#ifdef DEV_NETMAP -+ if (nm_native_on(NA(priv->dev))) { -+ int saved_cons = ring->cons; -+ mlx4_en_free_rx_buf(priv, ring); -+ ring->cons = saved_cons; -+ mlx4_netmap_rx_config(priv, ring_ind); -+ } -+#endif /* DEV_NETMAP */ - mlx4_en_update_rx_prod_db(ring); - } -- - return 0; - - err_buffers: -@@ -402,6 +412,11 @@ void mlx4_en_destroy_rx_ring(struct mlx4 - void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring) - { -+#ifdef DEV_NETMAP -+ if (nm_native_on(NA(priv->dev))) -+ ND("netmap mode, rx buf already freed"); -+ else -+#endif /* DEV_NETMAP */ - mlx4_en_free_rx_buf(priv, ring); - if (ring->stride <= TXBB_SIZE) - ring->buf -= TXBB_SIZE; -@@ -718,6 +739,11 @@ int mlx4_en_poll_rx_cq(struct napi_struc - struct mlx4_en_priv *priv = netdev_priv(dev); - int done; - -+#ifdef DEV_NETMAP -+ if (netmap_rx_irq(cq->dev, cq->ring, &done)) { -+ ND("rx_irq %d for netmap, budget %d done %d", cq->ring, budget, done); -+ } else -+#endif /* DEV_NETMAP */ - done = mlx4_en_process_rx_cq(dev, cq, budget); - - /* If we used up all the quota - we're probably not done yet... */ ---- drivers/net/ethernet/mellanox/mlx4/en_tx.c 2012-09-11 20:50:55.982624673 -0700 -+++ ./mellanox/mlx4/en_tx.c 2012-09-27 00:05:22.713523348 -0700 -@@ -55,6 +55,10 @@ MODULE_PARM_DESC(inline_thold, "threshol - - static u32 hashrnd __read_mostly; - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+#include /* extern stuff */ -+#endif /* CONFIG_NETMAP */ -+ - int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 size, - u16 stride) -@@ -396,6 +400,13 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq) - - if (!spin_trylock(&ring->comp_lock)) - return; -+#ifdef DEV_NETMAP -+ /* XXX should be integrated with appropriate lock_wrapper manner? */ -+ if (netmap_tx_irq(cq->dev, cq->ring)) { -+ ND(5, "wakeup queue %d", cq->ring); -+ spin_unlock(&ring->comp_lock); -+ return; -+ } -+#endif /* DEV_NETMAP */ - mlx4_en_process_tx_cq(cq->dev, cq); - mod_timer(&cq->timer, jiffies + 1); - spin_unlock(&ring->comp_lock); diff --git a/private/LINUX/wip-patches/diff--mlx4--20630--30200 b/private/LINUX/wip-patches/diff--mlx4--20630--30200 deleted file mode 100644 index 86383bb8f..000000000 --- a/private/LINUX/wip-patches/diff--mlx4--20630--30200 +++ /dev/null @@ -1,163 +0,0 @@ -diff -urp --exclude '*.o' --exclude '*.cmd' --exclude '*mod.c' drivers/net/ethernet/mellanox/mlx4/en_netdev.c ./mellanox/mlx4/en_netdev.c ---- drivers/net/ethernet/mellanox/mlx4/en_netdev.c 2012-09-11 20:50:55.982624673 -0700 -+++ ./mlx4/en_netdev.c 2012-09-27 00:05:22.703523430 -0700 -@@ -48,6 +48,39 @@ - #include "mlx4_en.h" - #include "en_port.h" - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+/* -+ * This driver is split in multiple small files. -+ * The main device descriptor has type struct mlx4_en_priv *priv; -+ * and we attach to the device in mlx4_en_init_netdev() -+ * (do port numbers start from 1 ?) -+ * -+ * The reconfig routine is in mlx4_en_start_port() (also here) -+ * which is called on a mlx4_en_restart() (watchdog), open and set-mtu. -+ * -+ * priv->num_frags ?? -+ * DS_SIZE ?? -+ * apparently each rx desc is followed by frag.descriptors -+ * and the rx desc is rounded up to a power of 2. -+ * -+ * Receive code is in en_rx.c -+ * priv->rx_ring_num number of rx rings -+ * rxr = prov->rx_ring[ring_ind] rx ring descriptor -+ * rxr->size number of slots -+ * rxr->prod producer -+ * probably written into a mmio reg at *rxr->wqres.db.db -+ * trimmed to 16 bits. -+ * -+ * Rx init routine: -+ * mlx4_en_activate_rx_rings() -+ * mlx4_en_init_rx_desc() -+ * Transmit code is in en_tx.c -+ */ -+ -+#define NETMAP_MLX4_MAIN -+#include /* extern stuff */ -+#endif /* CONFIG_NETMAP */ -+ - int mlx4_en_setup_tc(struct net_device *dev, u8 up) - { - if (up != MLX4_EN_NUM_UP) -@@ -1042,6 +1075,9 @@ int mlx4_en_start_port(struct net_device - /* Set initial ownership of all Tx TXBBs to SW (1) */ - for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) - *((u32 *) (tx_ring->buf + j)) = 0xffffffff; -+#ifdef DEV_NETMAP -+ mlx4_netmap_tx_config(priv, i); -+#endif /* DEV_NETMAP */ - ++tx_index; - } - -@@ -1639,6 +1675,9 @@ int mlx4_en_init_netdev(struct mlx4_en_d - en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); - - queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); -+#ifdef DEV_NETMAP -+ mlx4_netmap_attach(priv); -+#endif /* DEV_NETMAP */ - return 0; - - out: ---- drivers/net/ethernet/mellanox/mlx4/en_rx.c 2012-09-11 20:50:55.982624673 -0700 -+++ ./mlx4/en_rx.c 2012-09-27 00:13:16.099550954 -0700 -@@ -41,6 +41,9 @@ - - #include "mlx4_en.h" - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+#include -+#endif /* !DEV_NETMAP */ - - static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv, - struct mlx4_en_rx_desc *rx_desc, -@@ -365,9 +368,16 @@ int mlx4_en_activate_rx_rings(struct mlx - ring = &priv->rx_ring[ring_ind]; - - ring->size_mask = ring->actual_size - 1; -+#ifdef DEV_NETMAP -+ if (nm_native_on(NA(priv->dev))) { -+ int saved_cons = ring->cons; -+ mlx4_en_free_rx_buf(priv, ring); -+ ring->cons = saved_cons; -+ mlx4_netmap_rx_config(priv, ring_ind); -+ } -+#endif /* DEV_NETMAP */ - mlx4_en_update_rx_prod_db(ring); - } -- - return 0; - - err_buffers: -@@ -402,6 +412,11 @@ void mlx4_en_destroy_rx_ring(struct mlx4 - void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_rx_ring *ring) - { -+#ifdef DEV_NETMAP -+ if (nm_native_on(NA(priv->dev))) -+ ND("netmap mode, rx buf already freed"); -+ else -+#endif /* DEV_NETMAP */ - mlx4_en_free_rx_buf(priv, ring); - if (ring->stride <= TXBB_SIZE) - ring->buf -= TXBB_SIZE; -@@ -692,6 +707,12 @@ out: - wmb(); /* ensure HW sees CQ consumer before we post new buffers */ - ring->cons = mcq->cons_index; - ring->prod += polled; /* Polled descriptors were realocated in place */ -+ -+ ND(5, "set_ci %d 0x%p val %d prod_db 0x%p val %d", -+ cq->ring, -+ mcq->set_ci_db, mcq->cons_index & 0xffffff, -+ ring->wqres.db.db, ring->prod & 0xffff); -+ - mlx4_en_update_rx_prod_db(ring); - ring->csum_ok += csum_ok; - ring->csum_none += csum_none; -@@ -718,6 +739,13 @@ int mlx4_en_poll_rx_cq(struct napi_struc - struct mlx4_en_priv *priv = netdev_priv(dev); - int done; - -+#ifdef DEV_NETMAP -+ static int cnt = 0; -+ ND(5,"XXXXXX-------XXXXXXXXXXX-------- poll-rx-cq %d count %d", (int)cq->ring, cnt++); -+ if (netmap_rx_irq(cq->dev, cq->ring, &done)) { -+ ND("rx_irq %d for netmap, budget %d done %d", cq->ring, budget, done); -+ } else -+#endif /* DEV_NETMAP */ - done = mlx4_en_process_rx_cq(dev, cq, budget); - - /* If we used up all the quota - we're probably not done yet... */ ---- drivers/net/ethernet/mellanox/mlx4/en_tx.c 2012-09-11 20:50:55.982624673 -0700 -+++ ./mlx4/en_tx.c 2012-09-27 00:05:22.713523348 -0700 -@@ -55,6 +55,10 @@ MODULE_PARM_DESC(inline_thold, "threshol - - static u32 hashrnd __read_mostly; - -+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) -+#include /* extern stuff */ -+#endif /* CONFIG_NETMAP */ -+ - int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 size, - u16 stride) -@@ -396,6 +400,17 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq) - - if (!spin_trylock(&ring->comp_lock)) - return; -+#ifdef DEV_NETMAP // XXX unlock and return should be in the 'if' branch -+ static int cnt = 0; -+ ND(5,"XXXXXX-------XXXXXXXXXXX-------- tx-irq %d count %d", (int)cq->ring, cnt++); -+ if (netmap_tx_irq(cq->dev, cq->ring)) { -+ ND(5, "wakeup queue %d", cq->ring); -+ } else { -+ RD(5, "XXXXXXXXX tx_irq %d unexpected, ignoring", cq->ring); -+ } -+ spin_unlock(&ring->comp_lock); -+ return; -+#endif /* DEV_NETMAP */ - mlx4_en_process_tx_cq(cq->dev, cq); - mod_timer(&cq->timer, jiffies + 1); - spin_unlock(&ring->comp_lock); diff --git a/private/NOTES b/private/NOTES deleted file mode 100644 index 6b05cfcfd..000000000 --- a/private/NOTES +++ /dev/null @@ -1,1193 +0,0 @@ ---- IMPORTANT DEVELOPMENT NOTES FOR NETMAP --- - -COMMIT ORDER: -- when producing code that must go upstream follow this sequence: - + commit and push on gitlab:master - + checkout github:master - + merge from gitlab:master - + remove any file in private (git rm private/*) - + commit and push on github:master - -The files in this directory should not go into github. - -=============== - -OLDER NOTES - -20140128 -- generic on FreeBSD panics on lo0 when doing output - -20121227 -- netmap-epair.diff - attempt to build a driver for epair - -20121227 -- netmap-nfe.diff - partial diff to support nfe - -20121026 broadcom on 2.6.xx -- missing cnic_if.h (used by bnx2x) - ---- status and other development notes --- -20120824 devfs_get_cdevpriv() - curthread struct thread sys/proc.h - ->td_fpop struct file - ->f_cdevpriv struct cdev_privdata sys/fs/devfs/devfs_int.h - ->cdpd_data void * - - in mmap: - dev struct cdev, sys/conf.h -20120802 http://www.asciiflow.com/ ascii art - -20120724 barelli svn+ssh://27148317-unipi@onelab3.iet.unipi.it/usr/home/PPM10/27148317/thesis - -20120528 NM_BRIDGE - error on initialization order for locks. - Not a problem on linux, but it is on FreeBSD with witnesses. - -20120524 virtual bridging - -get_ifp lookup the fake bridge interface - returns the object with a reference - -netmap_if_new() allocates the software rings - -na->nm_register() puts the interface in netmap mode - in our case, attach to an (existing) bridge - - -20120503 interrupt dispatching - apic_vector.S::call lapic_handle_intr - `-> intr_execute_handlers() - `-> kern_intr.c::intr_event_handle() - `-> if ih_filter --> call filter - or if filter returns FILTER_SCHEDULE_THREAD - `-> schedule thread to execute handler - - in the lem driver, the filter is lem_irq_fast() which - calls taskqueue_enqueue to run lem_handle_rxtx. - In qemu it takes between 70 and 210k cycles (20..60us) - to schedule the task. - On the test machine, at least 10k ticks corresponding - to about 3us before the task runs (rarely we have 3k ticks). - -20120505 -- immediate operation for output and input - OUT: we get the mbuf, need to copy into the nm_buf and - kick the output queue. If the queue is idle we should - operate immediately, otherwise schedule a deferred - interrupt (txintr ?) and act on it. - -20120504 -- latency between filter and task - on the emulator (3.4GHz machine) up to 130k cycles, min 70k - on the i7-870 @2.93G the min is 3k cycles, more often 13k - and several 30k spikes. - - -20120503 -- prefetch and the like -+ added userspace flags to pkt-gen to enable various - prefetch and copies. - pkt-gen -o 1 prefetch send source - pkt-gen -o 2 access (not implemented) - pkt-gen -o 4 pkt_copy - takes from a static buffer and writes to buffers - spread in memory. The write buffer should absorb - the operation - pkt-gen -o 8 memcpy() -+ added dev.netmap.copy to test with in-kernel copies - dev.netmap.copy=1 bcopy - dev.netmap.copy=2 bcopy (later) - dev.netmap.copy=3 memcpy (later) - dev.netmap.copy=4 access (maybe ignored ?) - dev.netmap.copy=5 only prefetch - -+ test with different packet lengths (intr=3000) - 2048 - 2048 - 64 - 2048 - 128 - - - ---- buf_size: 2048-128, intr=3k, 4 cores at 900 mhz ---- - -- options=0 -- -- options=1 -- -- options=4 -- - nm.copy len=60 len=64 len=60 len=64 len=60 len=64 - 0 14.78 14.20 13.78 13.80 9.46 9.47 - 1 4.35 8.17* 4.29 7.88 3.75 6.25 - 2 4.71 7.75* 4.62 8.14* 4.01 6.42 - 3 2.85 2.85 2.81 2.75 2.57 2.57 - 4 11.70 11.70 12.35 12.35 8.78 8.78 - 5 13.98 14.00 13.04 13.04 9.11 9.11 - - ---- buf_size: 2048-64, intr=3k, 4 cores at 900 mhz ---- - -- options=0 -- -- options=1 -- -- options=4 -- - nm.copy len=60 len=64 len=60 len=64 len=60 len=64 - 0 14.78 14.20 13.72 13.70 9.45 9.44 - 1 4.35 7.68* 4.22 7.74 3.92 6.33 - 2 4.70 7.79 4.68 8.04* 4.11 6.52 - 3 2.85 2.74 2.80 2.75 2.56 2.55 - 4 12.31* 11.83* 12.31 12.28 8.78 8.78 - 5 13.94 13.93 12.96 12.98 9.03 9.09 - - ---- buf_size: 2048, intr=3k, 4 cores at 900 mhz ---- - -- options=0 -- -- options=1 -- -- options=4 -- - nm.copy len=60 len=64 len=60 len=64 len=60 len=64 - 0 14.20 8.81 8.84 - 1 6.90 3.78 6.08 - 2 7.82 3.98 6.16 - 3 2.73 2.44 2.58 - 4 12.40 12.36 8.33 8.32 - 5 14.20 8.87 8.67 - -------------- -20120419 netsend statistics (with various breakpoints) -sysctl dev.ix.0.enable_aim=0 -sysctl dev.ix.0.queue0.interrupt_rate=5000 -sysctl dev.ix.0.fc=0 -sysctl net.inet.drop ... - -call tree -send() -sendto() ----- within the kernel ------ R/W = lock, T= tail call, C = normall call, -kern/uipc_syscalls.c :: sys_sendto() -kern/uipc_syscalls.c :: sendit() -kern/uipc_syscalls.c :: kern_sendit() -kern/uipc_socket.c :: sosend() - so->so_proto->pr_usrreqs->pru_sosend = sosend_dgram -kern/uipc_socket.c :: sosend_dgram() - so->so_proto->pr_usrreqs->pru_send = udp_send -netinet/udp_usrreq.c :: udp_send() -netinet/udp_usrreq.c :: udp_output() -netinet/ip_output.c :: ip_output() - ifp->if_output = ether_output -net/if_ethersubr.c :: ether_output() - memcpy() or arpresolve() - 3 memcpy for MAC header - pf_find_mtag() and csum_flags - -net/if_ethersubr.c :: ether_output_frame() - check ether_ipfw - call ifp->if_transmit - ifp->if_transmit = ixgbe_mq_start - -dev/ixgbe/ixgbe.c :: ixgbe_mq_start() - IXGBE_TX_TRYLOCK() - ixgbe_mq_start_locked() - IXGBE_TX_UNLOCK() - -dev/ixgbe/ixgbe.c :: ixgbe_mq_start_locked() - drbr_needs_enqueue() 30ns aka buf_ring_empty - for (;;) { - ixgbe_xmit() - drbr_dequeue() - } - -dev/ixgbe/ixgbe.c :: ixgbe_xmit() - huge stack (32 descriptors) - bus_dmamap_load_mbuf_sg() - ixgbe_tso_setup() or ixgbe_tx_ctx_setup() - loop on descriptors - IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(txr->me), i); - -... drbr_dequeue() uses sys/sys/buf_ring.h - - - BREAK CLOCK SIZE TC NSEC KPPS - 0 2934 18 HPET 1289 775 - p5556 2934 18 HPET 8 118M - 20 2934 18 HPET 107 103 107 103 103 103 103 107 107 - 20x4 2934 18 HPET 107 - 21x4 2934 18 HPET 111 - 22x4 2934 18 HPET 111 same as 21 - 23x4 2934 18 HPET 112-115 - 24x4 2934 18 HPET 117-121 - 25x4 2934 18 HPET 135-141 - 40x4 2934 18 HPET 144-150 - 41x4 2934 18 HPET 157-167 insensitive to length - allocation m_uiotombuf() -> uma_zalloc(zone_mbuf) - uma_zalloc(): - critical_enter() - cache->uc_allocs++; - 42x4 2934 18 HPET 266-270 - 42x4 2934 180 HPET 297 - 42x4 2934 1080 HPET 312 - 51x4 2934 1080 HPET 412 - 52x4 2934 18 HPET 1282 (!XXX slower than 1080) - 52 2934 1080 HPET 515 - 56x4 2934 1080 HPET 1290 - 52x4 2934 1080 HPET 1325 (1256 in other tests) - - -20120417 netsend statistics (with various breakpoints) - tests on i7-870 at 2934 - - BREAK CLOCK SIZE TC NSEC KPPS - 20 2934 18 TSC-low 9786 - 20 2934 1418 TSC-low 9786 - 20 2933 18 TSC-low 8970 8651 alternate - 20 2933 1418 TSC-low 8970 - 20 900 18 TSC-low 2704 - 20 900 18 HPET 2685 2590 alternate - - nosend 2934 18 HPET 119000 i7-870 no send (drop port) - nosendx4 2934 18 HPET 118200 i7-870 no send (drop port) - 20 2934 18 HPET 9783 sys_sendto() - 20 2934 18 HPET 9634 send() - 20x4 2934 18 HPET 9606 send() four threads - 20 2934 18 HPET 104 9602 9267 alternate - 21 2934 18 HPET 111 8982 - 22 2934 18 HPET 9006 alt 8710 - 23 2934 18 HPET 8906 - 24 2934 18 HPET 117 8502 alt 8238 - 25 2934 18 HPET 136 7347 - - 40 2934 18 HPET 144 6903 to 10.0.0.1 - 40x4 2934 18 HPET 144 6720 to 10.0.0.1 - 41 2934 18 HPET 156 6404 to 10.0.0.1 down to 6017 - 41x4 2934 18 HPET 156 6423 to 10.0.0.1 down to 6017 - --- 41-42 is m_uiotombuf() - uiomove() - sys/kern/subr_uio.c::uiomove_faultflag(cp, n, uio, 0) - involves copyin in - /home/luigi/FreeBSD/head/sys/amd64/amd64/support.S: - 42 2934 18 HPET 279 3577 to 10.0.0.1 down to 3544 - 42x4 2934 18 HPET 279 3725 to 10.0.0.1 down to 3544 - 43 2934 18 HPET 283 3522 to 10.0.0.1 down to 3544 - - 30 2934 18 HPET 292 3418 to 10.0.0.1 - 31 2934 18 HPET 340 2936 - - 50 2934 18 HPET 361 2765 to 10.0.0.1 - 50x4 2934 18 HPET 361 2802 to 10.0.0.1 - 51 2934 18 HPET 2635 to 10.0.0.1 - 51x4 2934 18 HPET 2689 to 10.0.0.1 - 52 2934 18 HPET 477 2093 to 10.0.0.1 - 52x4 2934 18 HPET 775 to 10.0.0.1 - --- 52-53 is the pfil call - 53 2934 18 HPET 613 to 10.0.0.1 (not here ?) - 54 2934 18 HPET 2090 to 10.0.0.1 also 2031 2046 ... - 54x4 2934 18 HPET 783 to 10.0.0.1 also 2031 2046 ... - 55 2934 18 HPET 534 1871 to 10.0.0.1 - 55x2 2934 18 HPET 1555 to 10.0.0.1 two threads - 55x4 2934 18 HPET 770 to 10.0.0.1 four threads - - 0 2934 18 HPET 968 1032 to 127.0.0.1 - 0 2934 18 HPET 622 to 10.0.0.1 (via ix0) - 0x2 2934 18 HPET 450 to 10.0.0.1 (via ix0) - 0x4 2934 18 HPET 351 to 10.0.0.1 (via ix0) - 0 2934 18 HPET 322 to 10.0.0.1 (and netmap-bridge) - -20120416 XXX BUG - em lock issue in em_netmap_init(), try to remove the - callback to shut down handlers - -20120407 sendto and other functions - -Measure netsend (and sendto() ) on various machines and dropping -the packet at different places in the stack. -sysctl kern.ipc.drop_send=N picks the place where packets are dropped -Tests run using tools/tools/netrate/netsend - -CONFIG QEMU LE-2300 i7-3400 - i7-3400 -l=18, no send 18.9 86.4 211 -l=18, 1 thread, pipe drop .0436 1.400 -l=1400, 1 thread, pipe drop .0393 1.300 -l=18, 2 thread, pipe drop .943 -l=1400, 2 thread, pipe drop .857 -l=18, 5 thread, pipe drop .51 -l=1400, 5 thread, pipe drop .50 - - -20120407 syscall path -lib/libc/net/Symbol.map - defines a few symbols that the linker is supposed to export - -lib/libc/net/send.c - send() calls _sendto() - -./libc/include/namespace.h:#define sendto _sendto - -lib/libc/sys/Symbol.map - FBSDprivate_1.0 _sendto, __sys_sendto - -the threading library defines them -./libthr/thread/thr_syscalls.c - ssize_t - __sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t, - socklen_t tl) - { - struct pthread *curthread = _get_curthread(); - ssize_t ret; - - _thr_cancel_enter(curthread); - ret = __sys_sendto(s, m, l, f, t, tl); - _thr_cancel_leave(curthread, ret <= 0); - return (ret); - } - - -head/sys/kern/syscall.master -; Processed to created init_sysent.c, syscalls.c and syscall.h. - -lib/libc/i386/SYS.h -#define SYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); \ - ENTRY(__CONCAT(__sys_,x)); \ - .weak CNAME(x); \ - .set CNAME(x),CNAME(__CONCAT(__sys_,x)); \ - .weak CNAME(__CONCAT(_,x)); \ - .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \ - mov __CONCAT($SYS_,x),%eax; KERNCALL; jb 2b - -#define RSYSCALL(x) SYSCALL(x); ret; END(__CONCAT(__sys_,x)) - -#define PSEUDO(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); \ - ENTRY(__CONCAT(__sys_,x)); \ - .weak CNAME(__CONCAT(_,x)); \ - .set CNAME(__CONCAT(_,x)),CNAME(__CONCAT(__sys_,x)); \ - mov __CONCAT($SYS_,x),%eax; KERNCALL; jb 2b; ret; \ - END(__CONCAT(__sys_,x)) - -/* gas messes up offset -- although we don't currently need it, do for BCS */ -#define LCALL(x,y) .byte 0x9a ; .long y; .word x - -#define KERNCALL int $0x80 - -The main syscall in lib/libc/i386/sys/syscall.S - -ENTRY(syscall) - pop %ecx /* rta */ - pop %eax /* syscall number */ - push %ecx - KERNCALL - push %ecx /* need to push a word to keep stack frame intact - upon return; the word must be the return address. */ - jb 1f - ret -1: - PIC_PROLOGUE - jmp PIC_PLT(HIDENAME(cerror)) - - - --------------- -20120313 unetstack and linux netqueue - http://www.ioremap.net/archive/unetstack/ - http://www.dnull.com/Alpine/ - userspace stack - -20120306 receive speed - - ixgbe seems to have some rx losses when used with receive - interrupt mitigation. Symptoms are the card is missing ~0.2% - of the incoming traffic. - As a workaround, set by setting dev.netmap.netmap_no_pendintr=1 - makes the receiver not lose packets. - -20120306 behaviour with one tx queue - report: - 0 5.678 - 1 11.13 - 3 11.53 - 7 11.85 - 15 12.10 - 255 12.40 - Increasing the interrupt rate marginally improves the - behaviour but never better than 12.48Mpps. - Increasing the report frequency does not seem to help - (actually, it harms) - -Setting TXDCTL.PTHRESH and HTHRESH improves the rate. - - Using dd for the status reporting does not seem to work - it - requires the use of RS on every descriptor, which slows down - the card. - TXDCTL.WTHRESH - - Options: a) TDH is updated late, check the bits - b) the descriptor read is delayed. - -# $Id$ - -20120128 select/usleep comparison FreeBSD Linux OSX - -select | Iterations/second -timeout | FBSD | Linux | OSX -usec | 9.0 | Vbox | 10.6 ---------+-------+-------+---------- - 1 500 15.0k 150k - 10 500 12.9k 65k - 50 500 8.6k 15k - 100 500 6.0k 7.5k - 500 500 1744 1620 - 1000 500 922 880 - 1500 331 629 613 - 2000 331 477 470 - - -20120112 RELENG_8 and RELENG_9 - Original code committed in HEAD r227614 - svn diff -r 227613:227614 svn+ssh://svn.freebsd.org/base/head - New files: - share/man/man4/netmap.4 - sys/dev/netmap/ - sys/net/netmap.h - sys/net/netmap_user.h - tools/tools/netmap/ - Patches: (sys/conf done in 227845) see netmap-conf.diff - share/man/man4/Makefile - sys/conf/NOTES - sys/conf/files - sys/conf/options - - Driver changes (done later) - sys/dev/e1000/if_igb.c - sys/dev/e1000/if_lem.c - sys/dev/e1000/if_em.c - sys/dev/re/if_re.c - sys/dev/ixgbe/ixgbe.c - -20111207 lr performance tests - - ixgbe, RELENG_8 picobsd, no IPFW, no INVARIANTS, no i586 - software LRO even on 82599 - - default latency is 16us, l=0 means no interrupt mitigation. - lro is the software implementation of lro, - hwlro is the hardware one (on 82599) - - Summary: - - - hardware checksum seems to help a lot on the tx side - but practically useless on the receive side. - - - with default interrupt mitigation, setting - HWCSUM and TSO on the sender is really disruptive; - (while it seems to help a bit with l=0) - - - lro helps a lot on the receive side. - - - the software lro on the transmit side is detrimental, - not sure why (acks collapsed too much ?) - Disabling it on pure acks - The sw version is actually pretty good., but on the tx side - the software version kills performance. - it really starves - - Peak - Tput transmitter receiver - ======= ======================= ======================== - 4975 -csum,-tso,-lro -csum,-tso,-lro - 5050 -csum,-tso,-lro, w 100 -csum,-tso,-lro - - 5350 -csum,-tso,-lro +csum,-tso,+lro - 5500 -csum,-tso,-lro, w 100 +csum,-tso,+lro - 6000 -csum,-tso,-lro, w 150 +csum,-tso,+lro - 6000 -csum,-tso,-lro, w 200 +csum,-tso,+lro - - 8000 csum,-tso,-lro +csum,-tso,+lro - 3950 csum,-tso,+lro +csum,-tso,+lro - - 3144 -csum,tso,-lro +csum,-tso,+lro - 1600 csum,tso,-lro +csum,-tso,+lro - 2600 csum,tso,-lro -csum,-tso,-lro - 5200 -csum,tso,-lro -csum,-tso,-lro - - 9400 csum,tso,-lro,l=0 +csum,-tso,hwlro - 8400 -csum,tso,-lro,l=0 +csum,-tso,hwlro - 7700 csum,tso,-lro,l=0 +csum,-tso,-lro (6.3 to 7.7) - - 8000 csum,-tso,lro, w 100 +csum,-tso,hwlro - 7500 csum,-tso,lro, w 1000 +csum,-tso,hwlro cache effect ? - -20111107 lr - forked version for the release - -20111021 - cache and memory latencies for various architectures - http://arstechnica.com/gadgets/news/2011/10/can-amd-survive-bulldozers-disappointing-debut.ars - - Similarly, the cache and main memory latencies are longer than - they are for K10 (four cycles compared to three for level 1 - cache; 21 cycles compared to 14 or 15 for level 2; 65 compared - to 55 or 59 for level 3; and 195 versus 182 or 157 cycles for - main memory). K10's latencies were already worse overall than - Sandy Bridge's (which boasts 4, 11, 25, and 148 cycle latencies, - from level 1 through to main memory), and Bulldozer makes them - worse still. - - -20111003 - New measures: RX throughput vs burst size - Take new RX throughput measures, varying the number of hardware queues - and the value of the flag enabling the fast path for the poll handler. - - During these experiments we measured the throughput based on the - reception of 64+4 bytes packets - - 4 que 4 que 1 que - 1 thr 1 thr 1 thr - 1 cor 1 cor 1 cor - burst fast slow fast - ===== ===== ===== ===== - 1 2.11 0.30 2.37 - 2 4.09 0.60 4.56 - 4 7.70 1.20 8.32 - 8 13.55 2.34 14.20 - 16 14.20 4.60 14.20 - 32 14.20 8.01 14.20 - 64 14.20 14.20 14.20 - 1024 14.20 14.20 14.20 - - It seems the throughput obtained with the poll fast path is 7x the one - obtained with the slow one; that is confirmed by the fact that we need - a burst equal to 8 to obtain a throughput comparable with the fast - poll and unitary burst. - - -20111003 - New measures: TX throughput vs burst size - Take new TX throughput measures varying the number of hardware queues - and the size of burst; like in the previous update, both adaptive - interrupt moderation and maximum interrupt rate have been left to its - default value. - XXX much better values checking TDH only when avail == 0 - - 4 que 2 que 1 que - 1 thr 1 thr 1 thr - burst 1 cor 1 cor 1 cor - ===== ===== ===== ===== - 1 1.05 0.89 0.77 - 2 1.81 1.71 1.53 - 4 3.51 3.41 2.92 - 8 6.58 6.38 5.90 - 16 11.60 11.22 10.41 - 32 14.88 14.88 12.49 - 1024 12.49 - - -20111003 - New measures: throughput vs clock speed - Take new TX throughput measures varying the number of threads/hardware - queues; adaptive interrupt moderation was kept active and maximum - interrupt rate was left to its default value. - - All the following measures are relative to the Intel 10 Gbe adapter. - - 4 que 4 que 2 que 2 que 1 que - 4 thr 1 thr 2 thr 1 thr 1 thr - freq 4 cor 1 cor 2 cor 1 cor 1 cor - ==== ===== ===== ===== ===== ===== - 150 5.31 2.17 2.88 1.81 1.70 - 300 10.13 4.57 5.88 3.97 3.49 - 450 14.88 7.46 8.04* 6.35 5.13 - 600 10.87 11.54 8.65 6.92 - 750 13.64 14.55 10.67 8.98 - 900 14.88 14.88 12.51 11.67 - 1050 14.00 12.60 - 1200 14.88 12.60 - 2934 12.60 - - -20110926 - New throughput measures. - Given the introduction of a couple of debugging features which caused - some slowdown in terms of TX and RX throughput, we decided to opt-out - such features with pre-processor defines, and take again throughput - measurements (here we report TX results only): - - cpu=150MHz queues=4 cores=1 threads=1 throughput= 2.17 Mpps - cpu=300MHz queues=4 cores=1 threads=1 throughput= 4.57 Mpps - cpu=450MHz queues=4 cores=1 threads=1 throughput= 7.53 Mpps - cpu=600MHz queues=4 cores=1 threads=1 throughput= 10.88 Mpps - cpu=750MHz queues=4 cores=1 threads=1 throughput= 13.62 Mpps - cpu=900MHz queues=4 cores=1 threads=1 throughput= 14.84 Mpps - - cpu=150MHz queues=4 cores=4 threads=4 throughput= 5.35 Mpps - cpu=300MHz queues=4 cores=4 threads=4 throughput= 9.75 Mpps - cpu=450MHz queues=4 cores=4 threads=4 throughput= 14.88 Mpps - - We did not measured the throughput with 2 cores and 2 queues, because - at the moment we are interested in not having introduced slow - operations; a more complete set of data will be taken next week. - - There is always the super-linear trend which needs to be explained. - - -20110921 - More latency experiments with different hosts and tx rages - - Here is the summary of the results collected while measuring the RTT - between two hosts: - - 1 experiment - - hosts: BSD - BSD - - CPU freq: 2800 MHz - - packet size: 98 bytes - - transmit rates: 100 Hz, 1 KHz, 10 KHz - 100) 0.024/0.031/0.042/0.002 ms - 1000) 0.024/0.030/0.042/0.001 ms - 10000) 0.013/0.015/0.043/0.001 ms - - 2 experiment - - hosts: BSD - Linux - - CPU freq: 2800 MHz - - packet size: 98 bytes - - transmit rates: 100 Hz, 1 KHz, 10 KHz - 100) 0.036/0.078/0.091/0.003 ms - 1000) 0.057/0.078/0.090/0.002 ms - 10000) 0.013/0.022/0.092/0.005 ms - - 3 experiment - - hosts: BSD - BSD w/ netmap bridge - - CPU freq: 2800 MHz - - packet size: 98 bytes - - transmit rates: 100 Hz, 1 KHz, 10 KHz - 100) 0.055/0.065/0.073/0.003 ms - 1000) 0.041/0.060/0.076/0.002 ms - 10000) 0.026/0.033/0.133/0.007 ms - - Considerations: - - above 1 Khz of transmit frequency all measured times are way below - data collected at lower freqs; we don't know why, probably the - application is entering in *flood* mode and timestamps are no more - reliable. More investigation is needed. - - using the netmap bridge with high TX rates, we get high values of - RTT for the first packets; afterwards the average decreases. Again, - more investigation is needed. - - Additional information can be found: - - stats/ping-bsd-bsd-100-2800 - - stats/ping-bsd-bsd-1k-2800 - - stats/ping-bsd-bsd-10k-2800 - - stats/ping-bsd-linux-100-2800 - - stats/ping-bsd-linux-1k-2800 - - stats/ping-bsd-linux-10k-2800 - - stats/ping-bsd-netmap-100-2800 - - stats/ping-bsd-netmap-1k-2800 - - stats/ping-bsd-netmap-10k-2800 - -20110920 - RTT break up measures - Using a patched version of `ping' we have been able to break up - measured RTT into small chunks, each one associated to a specific - network operation. - - The following is the summary of the measures taken on a machine with - two interfaces in loopback, and interrupt latency reduced as much as - possible, and an high transmit rate: - - ~ 6 us to move a message between userspace and kernel: we expected - a smaller time, but maybe we are taking the userspace timestamp to - early - - ~ 11.7 us measures the time between A notifying the NIC of the packet - to send, and B schedule the interrupt routine - - ~ 0.4 us between interrupt and rxeof: we expected this value, given - that the function call is one of the first operation executed - inside the interrupt service routine - - ~ 5 us the latency introduced by the receiver processing the ICMP - message - - ~ 11.9 us measures the time between B notifying the NIC of the packet - to send, and A schedule the interrupt routine; as we expected, this - value is kind of equal to delta #2. - - ~ 0.4 us between interrupt and rxeof - - ~ 20 us to traverse the network stack and reach userspace - - Hence: - - from userspace to userspace: ~50 us - - from userspace to kernelspace: ~30 us which is what we get from - standard ping. - - For the whole data set collected, have a look: - - stats/patchedping-c1000-i0005-s68-2800-bulklat - - stats/patchedping-c1000-i0005-s68-2800-lowlat - - stats/patchedping-c1000-i0005-s68-2800-zerolat - - -20110916 - More tests on ping latency (Linux) with a varying transmit rate. - We took the measures again varying the transmit rate to investigate the - origin of this high RTT. An higher transmit size does not produces - better results (they are kind of stable); on the other hand, increasing - the transmit rate: - - - hosts: Linux->Linux - - command: ping -c 100000 -i 0.0001 -s [56, 200, 400, 800, 1200, 1450] - 56) min/avg/max: 0.022/0.033/0.123 - 200) min/avg/max: 0.027/0.035/0.146 - 400) min/avg/max: 0.020/0.035/0.145 - 800) min/avg/max: 0.029/0.034/0.136 - 1200) min/avg/max: 0.032/0.042/0.148 - 1450) min/avg/max: 0.032/0.052/0.143 - - This time, collected data seem to be more reasonable than before: - moreover this suggests that interrupt mitigation (still active on - Linux) is more effective under *heavy* work load. - - -20110915 - Test ping latency with different hosts and packet sizes - 1 experiment - - hosts: BSD->BSD - - command: ping -c 1000 -i 0.005 -s [56, 200, 400, 800, 1200, 1450] - 56) min/avg/max: 0.049/0.050/0.055 - 200) min/avg/max: 0.049/0.050/0.055 - 400) min/avg/max: 0.049/0.050/0.055 - 800) min/avg/max: 0.051/0.052/0.056 - 1200) min/avg/max: 0.051/0.052/0.057 - 1450) min/avg/max: 0.052/0.053/0.057 - - 2 experiment - - hosts: BSD->Linux - - command: ping -c 1000 -i 0.005 -s [56, 200, 400, 800, 1200, 1450] - 56) min/avg/max: 0.073/0.085/0.091 - 200) min/avg/max: 0.057/0.086/0.091 - 400) min/avg/max: 0.059/0.087/0.093 - 800) min/avg/max: 0.063/0.089/0.095 - 1200) min/avg/max: 0.082/0.092/0.097 - 1450) min/avg/max: 0.078/0.093/0.101 - - 3 experiment - - hosts: Linux->BSD - - command: ping -c 1000 -i 0.006 -s [56, 200, 400, 800, 1200, 1450] - * transmit rate has been increased to prevent icmp mitigation on - the RX side: maybe there is a syctl to disable it * - 56) min/avg/max: 0.070/0.074/0.083 - 200) min/avg/max: 0.070/0.074/0.087 - 400) min/avg/max: 0.070/0.074/0.082 - 800) min/avg/max: 0.071/0.075/0.084 - 1200) min/avg/max: 0.071/0.075/0.088 - 1450) min/avg/max: 0.071/0.075/0.086 - - 4 experiment - - hosts: Linux->Linux - - command: ping -c 1000 -i 0.005 -s [56, 200, 400, 800, 1200, 1450] - 56) min/avg/max: 0.060/0.102/0.123 - 200) min/avg/max: 0.065/0.106/0.140 - 400) min/avg/max: 0.062/0.107/0.140 - 800) min/avg/max: 0.068/0.113/0.150 - 1200) min/avg/max: 0.075/0.113/0.157 - 1450) min/avg/max: 0.083/0.117/0.140 - - Collected values are still to high. - - -20110915 - Interrupt mitigation study - Disabling `ixgbe' adaptive interrupt moderation, and varying - max_interrupt_rate, we used `vmstat - i' to measure the number of - received interrupts to find out whether such setting gets correctly - honored by device driver or not. - - All the experiment have been taken on the receiver side (on the - transmit one, we had `pkt-gen' sending wire-limit traffic) - - 1 legacy driver, low interrupt latency - - max_intr_rate: 62500 - - duration: 6.73 s - - interrupts before: ~106289 - - interrupts after: ~212437 - - interrupts per second: ~15772 - - 2 pkt-gen (RX), low interrupt latency - - max_intr_rate: 62500 - - duration: 6.73 s - - interrupts before: ~212515 - - interrupts after: ~315407 - - interrupts per second: ~15288 - - 3 legacy driver, high interrupt latency - - max_intr_rate: 6666 - - duration: 6.73s - - interrupts before: ~172 - - interrupts after: ~108285 - - interrupts per second: ~16064 - how is this possible? should this value be under 6666? Does this - count the number of received interrupts, or the number of served - ones? - - 4 pkt-gen (RX), high interrupt latency - - max_intr_rate: 6666 - - duration: 6.73s - - interrupts before: ~68450 - - interrupts after: ~136538 - - interrupts per second: ~10115 - why we are still counting more interrupts than configured limit? - why we are getting less interrupts than before? - - These are measures that need to be investigated more. - - -20110914 - Latency tests (part 2) - In these tests we wanted to measure the RTT deltas with different - packet sizes and different OSes. In particular we sent packets of 64, - 98 and 132 bytes (`ping -s 56/90/124') and we tested all the possible - configurations of sender / receiver hosting different OSes (FreeBSD and - Linux) - - Size 10 Gbe 1 Gbe - ====== ====== ===== - - 64 B 33 us 57 us - FreeBSD-FreeBSD 98 B 37 us 58 us - 132 B 38 us 60 us - - 64 B 88 us 132 us - FreeBSD-Linux 98 B 90 us 140 us - 132 B 92 us 150 us - - 64 B 110 us 153 us - Linux-FreeBSD 98 B 112 us 169 us - 132 B 113 us 178 us - - 64 B 169 us 182 us - Linux-Linux 98 B 170 us 185 us - 132 B 176 us 188 us - - Collected measures are likely to be wrong: why a ping on a Linux - machine takes so long? We are better off taking again the measures and - fix some ping variables like for example the message interval. - - -20110913 - Latency tests (part 1) - In these tests we measured the latency measured by the `ping' - application; we repeated the tests using the standard driver, then - enabling NIC off-loading features, and finally disabling interrupt - mitigation. In the end, we tried to use the brige application (built on - top of netmap) which links hardware with stack queues. - - OS: FreeBSD 9.0 beta - Kernel: head (r225462) - - NIC: Intel 10Gbe (82599) - Setup: ping - - standard rxcsum no intr netmap - txcsum mitigation bridge - ======== ======= ========== ======= - 35 usec 35 usec 35 usec 65 usec - - - NIC: Intel 1Gbe (PCH_D_HV_DM) - Setup: ping - - standard rxcsum no intr netmap - txcsum mitigation bridge - ======== ======= ========== ======= - 57 usec 57 usec / 183 usec - - -20110909 - Transmission performance - OS: FreeBSD 9.0 beta - Kernel: head (r225380) - - NIC: Intel 10Gbe (82599) - Setup: netsend throughput varying cpu freq and number of instances - - freq 1 instance 2 instances 4 instances - ==== ========== =========== =========== - 2934 725 Kpps 1.21 Mpps 1.64 Mpps - 1467 372 Kpps 640 Kpps 808 Kpps - 750 202 Kpps 344 Kpps 432 Kpps - 150 36.7 Kpps 63.2 Kpps 80.9 Kpps - - NIC: Intel 1Gbe (82572EI_COPPER) - Setup: pkt-gen - - freq(MHz) throughput (Mpps) - ======== ================= - 150 1.13 - 2934 1.13 - - NIC: Intel 1Gbe (82574L) - Setup: pkt-gen - - freq(MHz) throughput (Mpps) - ======== ================= - 150 1.13 - 2934 1.13 - - -20110908 - Transmission performance - - OS: FreeBSD 9.0 beta - Kernel: head (r225380) - - NIC: Intel 10Gbe (82599) - Setup: pkt-gen, 4 queues, 1 thread, 1 core, 64 bytes - - freq (MHz) throughput (Mpps) - ========= ================= - 150 2.18 - 450 7.10 - 750 13.93 - 900 14.88 - - NIC: Intel 10Gbe (82599) - Setup: pkt-gen, 4 queues, 4 threads, 4 cores, 64 bytes - - freq (MHz) throughput (Mpps) - ========= ================= - 150 5.32 - 300 9.42 - 450 14.20 - 600 14.88 - - NIC: Intel 1Gbe (PCH_D_HV_DM) - Setup: pkt-gen - - freq(MHz) throughput (Mpps) - ======== ================= - 150 1.39 - 2934 1.39 - - NIC: Intel 1Gbe (ICH10_D_BM_LM) - Setup: pkt-gen - - freq(MHz) throughput (Mpps) - ======== ================= - 150 1.13 - - -20110902 - kevent / kqueue userspace example - - Monitor changes to the /tmp/foo file and print messages whenever - it is deleted, modified or their attributes change. The program - finishes when the file being monitoring is deleted. - - 1 Call kqueue(2) to create a new kernel event queue. The - descriptor it returns will be later used by kevent(2). - - 2 Open the file to monitor and keep its descriptor around. We'll - need this to attach an event monitor to it. - - 3 Initialize a vector of struct kevent elements that describes - the changes to monitor. Since we are only monitoring a single - file, we need a one-element vector. This vector is filled up - with calls to the EV_SET macro. This macro takes: the - descriptor of the kqueue, the descriptor of the file to - monitor (ident), the filter to apply to it, several flags and - optional arguments to the filter. - - 4 Call the kevent(2) function. This system call takes the list - of changes to monitor we constructed before and does not - return until at least one event is received (or when an - associated timeout is exhausted). The function returns the - number of changes received and stores information about them - in another vector of struct kevent elements (we'll only get - notifications of one event at a time, hence we don't use - a vector, but a simple variable). - - 5 Interpret the results. If kevent(2) returned a number greater - than 0, we have to inspect the output vector and see which - events were received. Each filter has its semantics about the - results. For example, we are using the EVFILT_VNODE filter, - which takes a list of conditions to monitor in the fflags - field and modifies it to include only the conditions that - triggered the filter. - - - And now the code: - -#include -#include -#include -#include -#include - -int -main(void) -{ - int f, kq, nev; - struct kevent change; - struct kevent event; - - kq = kqueue(); - if (kq == -1) - perror("kqueue"); - - f = open("/tmp/foo", O_RDONLY); - if (f == -1) - perror("open"); - - EV_SET(&change, f, EVFILT_VNODE, - EV_ADD | EV_ENABLE | EV_ONESHOT, - NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, - 0, 0); - - for (;;) { - nev = kevent(kq, &change, 1, &event, 1, NULL); - if (nev == -1) - perror("kevent"); - else if (nev > 0) { - if (event.fflags & NOTE_DELETE) { - printf("File deleted\n"); - break; - } - if (event.fflags & NOTE_EXTEND || - event.fflags & NOTE_WRITE) - printf("File modified\n"); - if (event.fflags & NOTE_ATTRIB) - printf("File attributes modified\n"); - } - } - - close(kq); - close(f); - return EXIT_SUCCESS; -} - - - Source: http://blog.julipedia.org/2004/10/example-of-kqueue.html - Documentation: http://people.freebsd.org/~jlemon/papers/kqueue.pdf - - -20110826 - kqueue support - - kevent() introduction - - A client program of the kevent system should: - - use kqueue() to creates a new kernel event queue; - - use kevent() to register, change or check events. - - One of the main difference with the poll() implementation - in kernel space is that kevent() require the kernel to - store some information state. This work is done by the - kqueue() function, that allocates a new kqueue object - into the kernel. - - Each event is identified by the tuple and - can be selected by a filter. A filter is declared - by a filterops structure, and should define at least three - hooks: attach, detach and filter. - - The user application calls the kevent() function with a - list of events. For each event the kernel calls the - kqueue_register() function that lookup its queues and if - there is no match - i) calls the "attach" hook and - ii) add the event on its kqueue. - - The "filter" hook is called each time a data structure - is modified. This means that the .f_filter function should - be placed where new data are read/write. The filter execution - check the filter conditions and possibly add the event to the - kernel active kqueue. - - Example of devices using kevents are: - net/bpf.c net/if_tap.c net/if_tun.c - - The function executed for each event is the netmap_kqfilter() - function, that is declared to the netmap_cdevsw structure. - See the netmap_kqfilter() comments into the netmap.c file - for mode details on its implementation. - -20110811 - kqueue support - The method to implement is defined in sys/sys/conf.h - d_kqfilter_t *d_kqfilter; - one that implements it is sys/kern/kern_tty.c - -2011.06.28 WORKING RELEASE (8943) - -2011.06.27 luigi - -Notes on reset, reinit etc. - - Ring reset can be asynchronous wrt userland. Right now - - RX RING - if there were no pending buffers passed up (keep a - copy of cur and avail in the kring ?) then the op is not - critical - - Otherwise we should try to preserve the range from - cur to cur+avail -- not sure how. - - TX RING: - If the reset does not change hwcur then there is no problem. - Otherwise we should preserve the old hwcur and move the - range of buffers that we get on the next write. - - If the reset does not change hwcur, there is no need - to change cur either. Otherwise we need to set the flag - and throw away part of the content. But this decision - must be taken in the driver which knows the correct - values for cur and avail. - - So, perhaps the callback should be in two steps, one - that returns slot, another one that fixes the flags - at the end. If the reset is harmless, no problem. - If it changes things, then set the flag, throw away stuff - at the next syscall and clear the flag. - -2011.06.21 luigi - - version 0.3 - - + the diffs for RELENG_8 are out of date. - - + revising the netmap_poll implementation, the new method - is generally a lot more efficient than the old one - especially for small bursts, as it avoids some useless function - calls. There is still some issue on the handling of NR_REINIT - which needs to be investigated; - - + the 're' driver seems to have problems receiving. - The machine stalls. - - + started an initial implementation of a bridge in testpcap. - More or less works but seems to lose control when the link goes - down. - - + Bridging performance (Mpps, l=64 until we remove CRCSTRIP) - - burst old new new testpcap (XXX NO) - poll no_ts do_ts (with ts) - - 1 0.21 9.59 8.57 0.75 - 2 0.41 10.05 8.96 1.37 - 16 2.55 4.86 - 1024 10.61 10.66 9.42 7.50 - - - + RX performance, em on PCI bus: 740Kpps (?) - ---------------------------------------------------------- - -2011.06.22 marta - - svn rev. 8912 - - + Bridging and pcap performance (Mpps, l=64) - freq 2934 - bridge no_timestamp=0 - - burst bridge pcap note - 1 9.5 - - 2 9.9 - - 5 10.02 - - 10 10.1 - - 20 10.1 - oscilla 10.3 - 50 10.1 - oscilla 10.3 - 70 10.4 - oscilla - - freq 2934 - bridge no_timestamp=1 - burst bridge pcap note - 1 9.9 777 - 2 10.6 1.3 - 5 11.07 2.6 - 10 11.1 3.7 - 20 11.2 4.8 - 50 11.2 5.7 - - freq 1200 - bridge no_timestamp=0 - - burst bridge pcap note - 1 3.6 - - 2 3.9 - - 5 4.04 - - 10 4.08 - oscilla 4.1 - 20 4.01 - oscilla - 50 4.01 - - - freq 1200 - bridge no_timestamp=1 - burst bridge pcap note - 1 3.8 317 - 2 4.04 592 - 5 4.1 1.2 - 10 4.25 1.95 - 20 4.25 2.7 - 50 4.30 3.5 diff --git a/private/OSX/README b/private/OSX/README deleted file mode 100644 index b16dd11c7..000000000 --- a/private/OSX/README +++ /dev/null @@ -1,7 +0,0 @@ -# $Id$ -# -# 20120614 - -Attempt to build an OSX module using the instructions at -http://unixjunkie.blogspot.com/2006/12/kernel-extension-by-hand.html - diff --git a/private/OSX/netmap.kext/Contents/Info.plist b/private/OSX/netmap.kext/Contents/Info.plist deleted file mode 100644 index d9e6ae4c7..000000000 --- a/private/OSX/netmap.kext/Contents/Info.plist +++ /dev/null @@ -1,35 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - netmap_osx - CFBundleIdentifier - it.unipi.iet.netmap_osx - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - netmap_osx - CFBundlePackageType - KEXT - CFBundleShortVersionString - 1.0.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0.0 - OSBundleLibraries - - com.apple.kpi.bsd - 9.0.0 - com.apple.kpi.libkern - 9.0.0 - com.apple.kpi.mach - 9.0.0 - com.apple.kpi.unsupported - 9.0.0 - - - diff --git a/private/OSX/netmap.kext/Contents/MacOS/Makefile b/private/OSX/netmap.kext/Contents/MacOS/Makefile deleted file mode 100644 index 2c7990df1..000000000 --- a/private/OSX/netmap.kext/Contents/MacOS/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -SRC= netmap_osx.c netmap.c -NM_BASE = ../../../../sys -VPATH = .:../../../../sys/dev/netmap -CFLAGS = -static -fno-builtin -nostdlib -lkmod -r -mlong-branch -CFLAGS += -I/System/Library/Frameworks/Kernel.framework/Headers -CFLAGS += -I$(NM_BASE) -I. -I$(NM_BASE)/dev/netmap -CFLAGS += -include osx_glue.h -CFLAGS += -Wall -netmap_osx: $(SRC) diff --git a/private/OSX/netmap.kext/Contents/MacOS/netmap_osx.c b/private/OSX/netmap.kext/Contents/MacOS/netmap_osx.c deleted file mode 100644 index 0866aea6c..000000000 --- a/private/OSX/netmap.kext/Contents/MacOS/netmap_osx.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * OSX wrapper for netmap module - */ -#include -#include - -kern_return_t netmap_kext_Start(kmod_info_t *ki, void *d) { - printf("Hello, World!\n"); - return KERN_SUCCESS; -} - -kern_return_t netmap_kext_Stop(kmod_info_t *ki, void *d) { - printf("Goodbye, World!\n"); - return KERN_SUCCESS; -} - -extern kern_return_t _start(kmod_info_t *ki, void *data); -extern kern_return_t _stop(kmod_info_t *ki, void *data); - -KMOD_EXPLICIT_DECL(it.unipi.iet.netmap_osx, "1.0.0", _start, _stop) -__private_extern__ kmod_start_func_t *_realmain = netmap_kext_Start; -__private_extern__ kmod_stop_func_t *_antimain = netmap_kext_Stop; -__private_extern__ int _kext_apple_cc = __APPLE_CC__; diff --git a/private/OSX/netmap.kext/Contents/MacOS/osx_glue.h b/private/OSX/netmap.kext/Contents/MacOS/osx_glue.h deleted file mode 100644 index 2c013f2cd..000000000 --- a/private/OSX/netmap.kext/Contents/MacOS/osx_glue.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * glue to compile netmap under FreeBSD - * - * Headers are in - * /System/Library/Frameworks/Kernel.framework/Headers/ - */ -#ifndef OSX_GLUE_H -#define OSX_GLUE_H -#define __FBSDID(x) -#include -#include -#include -#include -#define TUNABLE_INT(name, ptr) - -#include // lock -#include // IOlock -#include // struct selinfo -struct selinfo { // private in the kernel - char dummy[128]; -}; -#include -#include - -/* XXX some types i don't find in OSX */ -typedef void * vm_paddr_t; -struct mbuf; // XXX -struct ifnet; - - -// #include -#include -#include -#include /* BIOCIMMEDIATE */ -//#include -#include -#include -// #include /* bus_dmamap_* */ - - -#endif /* OSX_GLUE_H */ diff --git a/private/README b/private/README deleted file mode 100644 index fe6ab9133..000000000 --- a/private/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains files (often stale and incorrect) -not meant for distribution. They are not needed for using -netmap and should not be used. diff --git a/private/extra/20130220-bsd-em-head.diff b/private/extra/20130220-bsd-em-head.diff deleted file mode 100644 index db850df0f..000000000 --- a/private/extra/20130220-bsd-em-head.diff +++ /dev/null @@ -1,825 +0,0 @@ -Index: sys/dev/e1000/if_em.c -=================================================================== ---- sys/dev/e1000/if_em.c (revision 246924) -+++ sys/dev/e1000/if_em.c (working copy) -@@ -32,6 +32,9 @@ - ******************************************************************************/ - /*$FreeBSD$*/ - -+#define MITIGATION -+#define PARAVIRT /* enable virtio-like synchronization */ -+ - #ifdef HAVE_KERNEL_OPTION_HEADERS - #include "opt_device_polling.h" - #include "opt_inet.h" -@@ -336,6 +339,9 @@ - - static SYSCTL_NODE(_hw, OID_AUTO, em, CTLFLAG_RD, 0, "EM driver parameters"); - -+#define MAX_INTS_PER_SEC 8000 -+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) -+ - static int em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); - static int em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); - TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); -@@ -356,8 +362,8 @@ - &em_rx_abs_int_delay_dflt, 0, - "Default receive interrupt delay limit in usecs"); - --static int em_rxd = EM_DEFAULT_RXD; --static int em_txd = EM_DEFAULT_TXD; -+static int em_rxd = 8*EM_DEFAULT_RXD; -+static int em_txd = 8*EM_DEFAULT_TXD; - TUNABLE_INT("hw.em.rxd", &em_rxd); - TUNABLE_INT("hw.em.txd", &em_txd); - SYSCTL_INT(_hw_em, OID_AUTO, rxd, CTLFLAG_RDTUN, &em_rxd, 0, -@@ -510,6 +516,47 @@ - goto err_pci; - } - -+#ifdef PARAVIRT -+ if (adapter->hw.subsystem_device_id == E1000_PARA_SUBDEV) { -+ uint64_t bus_addr; -+ int tsize; -+ -+ device_printf(dev, "paravirt support on dev %p\n", adapter); -+ tsize = 4096; // XXX one page for the csb -+ if (em_dma_malloc(adapter, tsize, &adapter->csb_mem, BUS_DMA_NOWAIT)) { -+ device_printf(dev, "Unable to allocate csb memory\n"); -+ error = ENOMEM; -+ goto err_pci; -+ } -+ /* Setup the Base of the CSB */ -+ adapter->csb = (struct e1000_csb *)adapter->csb_mem.dma_vaddr; -+ /* force the first kick */ -+ adapter->csb->host_need_txkick = 1; /* txring empty */ -+ adapter->csb->guest_need_rxkick = 1; /* no rx packets */ -+ bus_addr = adapter->csb_mem.dma_paddr; -+ em_set_sysctl_value(adapter, "csb_on", -+ "enable paravirt.", &adapter->csb->guest_csb_on, 0); -+ em_set_sysctl_value(adapter, "txc_lim", -+ "txc_lim", &adapter->csb->host_txcycles_lim, 1); -+ /* some stats */ -+#define PA_SC(name, var, val) \ -+ em_set_sysctl_value(adapter, name, name, var, val) -+ PA_SC("host_need_txkick",&adapter->csb->host_need_txkick, 1); -+ PA_SC("host_need_rxkick",&adapter->csb->host_need_rxkick, 1); -+ PA_SC("guest_need_txkick",&adapter->csb->guest_need_txkick, 0); -+ PA_SC("guest_need_rxkick",&adapter->csb->guest_need_rxkick, 1); -+ PA_SC("tdt_reg_count",&adapter->tdt_reg_count, 0); -+ PA_SC("tdt_csb_count",&adapter->tdt_csb_count, 0); -+ PA_SC("tdt_int_count",&adapter->tdt_int_count, 0); -+ PA_SC("guest_need_kick_count",&adapter->guest_need_kick_count, 0); -+ /* tell the host where the block is */ -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAH, -+ (u32)(bus_addr >> 32)); -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAL, -+ (u32)bus_addr); -+ } -+#endif /* PARAVIRT */ -+ - /* - ** For ICH8 and family we need to - ** map the flash memory, and this -@@ -563,12 +610,25 @@ - &adapter->tx_abs_int_delay, - E1000_REGISTER(hw, E1000_TADV), - em_tx_abs_int_delay_dflt); -+ em_add_int_delay_sysctl(adapter, "itr", -+ "interrupt delay limit in usecs/4", -+ &adapter->tx_itr, -+ E1000_REGISTER(&adapter->hw, E1000_ITR), -+ DEFAULT_ITR); - - /* Sysctl for limiting the amount of work done in the taskqueue */ - em_set_sysctl_value(adapter, "rx_processing_limit", - "max number of rx packets to process", &adapter->rx_process_limit, - em_rx_process_limit); - -+#ifdef MITIGATION -+ /* Sysctls to control mitigation */ -+ em_set_sysctl_value(adapter, "mit_enable", -+ "driver TDT mitigation", &adapter->mit_enable, 0); -+ em_set_sysctl_value(adapter, "rx_retries", -+ "driver rx retries", &adapter->rx_retries, 0); -+#endif /* MITIGATION */ -+ - /* - * Validate number of transmit and receive descriptors. It - * must not exceed hardware maximum, and must be multiple -@@ -663,7 +723,7 @@ - device_printf(dev, - "The EEPROM Checksum Is Not Valid\n"); - error = EIO; -- goto err_late; -+ // XXX goto err_late; - } - } - -@@ -741,6 +801,10 @@ - if (adapter->ifp != NULL) - if_free(adapter->ifp); - err_pci: -+#ifdef PARAVIRT -+ if (adapter->csb) -+ em_dma_free(adapter, &adapter->csb_mem); -+#endif /* PARAVIRT */ - em_free_pci_resources(adapter); - free(adapter->mta, M_DEVBUF); - EM_CORE_LOCK_DESTROY(adapter); -@@ -788,6 +852,12 @@ - - e1000_phy_hw_reset(&adapter->hw); - -+#ifdef PARAVIRT -+ if (adapter->csb) { -+ em_dma_free(adapter, &adapter->csb_mem); -+ adapter->csb = NULL; -+ } -+#endif /* PARAVIRT */ - em_release_manageability(adapter); - em_release_hw_control(adapter); - -@@ -942,6 +1012,16 @@ - em_txeof(txr); - if (txr->tx_avail < EM_MAX_SCATTER) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; -+#ifdef PARAVIRT -+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE && adapter->csb && -+ adapter->csb->guest_csb_on && !adapter->csb->guest_need_txkick) { -+ adapter->csb->guest_need_txkick = 1; -+ adapter->guest_need_kick_count++; -+ // XXX memory barrier -+ em_txeof(txr); // XXX possibly clear IFF_DRV_OACTIVE -+ } -+#endif /* PARAVIRT */ -+ - return (err); - } - -@@ -2098,6 +2178,35 @@ - */ - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -+ -+#ifdef PARAVIRT -+ if (adapter->csb) { -+ adapter->csb->guest_tdt = i; -+ /* XXX memory barrier ? */ -+ if (adapter->csb->guest_csb_on && -+ !adapter->csb->host_need_txkick) { -+ if (txr->tx_avail <= 64) {// XXX -+ em_txeof(txr); -+ } -+ adapter->tdt_csb_count++; -+ return (0); -+ } -+ } -+#endif /* PARAVIRT */ -+ -+#ifdef MITIGATION -+ if (adapter->mit_enable) { -+ if (adapter->shadow_tdt & MIT_PENDING_INT) { -+ /* signal intr and data pending */ -+ adapter->shadow_tdt = MIT_PENDING_TDT | (i & 0xffff); -+ return (0); -+ } else { -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } -+ } -+ adapter->tdt_reg_count++; -+#endif /* MITIGATION */ -+ - E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), i); - - return (0); -@@ -2255,6 +2364,17 @@ - taskqueue_enqueue(txr->tq, &txr->tx_task); - } - -+#if 0 // def PARAVIRT -+ /* recover space if needed */ -+ if (adapter->csb && adapter->csb->guest_csb_on && -+ (adapter->watchdog_check == TRUE) && -+ (ticks - adapter->watchdog_time > EM_WATCHDOG) && -+ (txr->tx_avail != adapter->num_tx_desc) ) { -+ em_txeof(txr); -+ /* XXX should also recover from stalls ? */ -+ } -+#endif /* PARAVIRT */ -+ - adapter->pause_frames = 0; - callout_reset(&adapter->timer, hz, em_local_timer, adapter); - #ifndef DEVICE_POLLING -@@ -3877,6 +3997,17 @@ - - txr->next_to_clean = first; - -+#ifdef MITIGATION -+ if ((adapter->shadow_tdt & MIT_PENDING_TDT) == MIT_PENDING_TDT) { -+ /* a tdt write is pending, do it */ -+ E1000_WRITE_REG(&adapter->hw, E1000_TDT(txr->me), -+ 0xffff & adapter->shadow_tdt); -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } else { -+ adapter->shadow_tdt = 0; // disable -+ } -+#endif /* MITIGATION */ -+ - /* - ** Watchdog calculation, we know there's - ** work outstanding or the first return -@@ -3975,6 +4106,14 @@ - ** Update the tail pointer only if, - ** and as far as we have refreshed. - */ -+#ifdef PARAVIRT // XXX fix for multiqueue -+ if (cleaned) { -+ adapter->csb->guest_rdt = rxr->next_to_refresh; -+ if (adapter->csb->guest_csb_on && -+ !adapter->csb->host_need_rxkick) -+ return; -+ } -+#endif /* PARAVIRT */ - if (cleaned) - E1000_WRITE_REG(&adapter->hw, - E1000_RDT(rxr->me), rxr->next_to_refresh); -@@ -4246,8 +4385,6 @@ - * Enable receive unit. - * - **********************************************************************/ --#define MAX_INTS_PER_SEC 8000 --#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) - - static void - em_initialize_receive_unit(struct adapter *adapter) -@@ -4306,6 +4443,7 @@ - E1000_WRITE_REG(hw, E1000_RDTR, 0x20); - - for (int i = 0; i < adapter->num_queues; i++, rxr++) { -+ int t = adapter->num_rx_desc - 1; - /* Setup the Base and Length of the Rx Descriptor Ring */ - bus_addr = rxr->rxdma.dma_paddr; - E1000_WRITE_REG(hw, E1000_RDLEN(i), -@@ -4324,12 +4462,14 @@ - if (ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_adapter *na = NA(adapter->ifp); - struct netmap_kring *kring = &na->rx_rings[i]; -- int t = na->num_rx_desc - 1 - kring->nr_hwavail; -+ t = na->num_rx_desc - 1 - kring->nr_hwavail; -+ } -+#endif /* DEV_NETMAP */ - -- E1000_WRITE_REG(hw, E1000_RDT(i), t); -- } else --#endif /* DEV_NETMAP */ -- E1000_WRITE_REG(hw, E1000_RDT(i), adapter->num_rx_desc - 1); -+#ifdef PARAVIRT -+ adapter->csb->guest_rdt = t; -+#endif /* PARAVIRT */ -+ E1000_WRITE_REG(hw, E1000_RDT(i), t); - } - - /* Set PTHRESH for improved jumbo performance */ -@@ -4402,7 +4542,11 @@ - int i, processed, rxdone = 0; - bool eop; - struct e1000_rx_desc *cur; -+ int retries; - -+#ifdef PARAVIRT -+ adapter->csb->guest_need_rxkick = 0; -+#endif /* PARAVIRT */ - EM_RX_LOCK(rxr); - - #ifdef DEV_NETMAP -@@ -4419,6 +4563,7 @@ - } - #endif /* DEV_NETMAP */ - -+ retries = 0; - for (i = rxr->next_to_check, processed = 0; count != 0;) { - - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) -@@ -4431,8 +4576,21 @@ - status = cur->status; - mp = sendmp = NULL; - -- if ((status & E1000_RXD_STAT_DD) == 0) -+ if ((status & E1000_RXD_STAT_DD) == 0) { -+ if (++retries <= adapter->rx_retries) { -+ continue; -+ } -+#ifdef PARAVIRT -+ if (adapter->csb->guest_need_rxkick == 0) { -+ adapter->csb->guest_need_rxkick = 1; -+ continue; -+ } -+#endif /* PARAVIRT */ - break; -+ } -+#ifdef PARAVIRT -+ adapter->csb->guest_need_rxkick = 0; -+#endif /* PARAVIRT */ - - len = le16toh(cur->length); - eop = (status & E1000_RXD_STAT_EOP) != 0; -@@ -5614,6 +5772,8 @@ - return (EINVAL); - info->value = usecs; - ticks = EM_USECS_TO_TICKS(usecs); -+ if (info->offset == E1000_ITR) /* units are 256ns here */ -+ ticks *= 4; - - adapter = info->adapter; - -Index: sys/dev/e1000/if_em.h -=================================================================== ---- sys/dev/e1000/if_em.h (revision 246924) -+++ sys/dev/e1000/if_em.h (working copy) -@@ -271,6 +271,28 @@ - int value; /* Current value in usecs */ - }; - -+#ifdef PARAVIRT -+#define E1000_PARA_SUBDEV 0x1101 /* special id */ -+#define E1000_CSBAL 0x02830 /* csb physical address */ -+#define E1000_CSBAH 0x02834 -+struct e1000_csb { /* comm. block */ -+ uint32_t guest_tdt; /* signals from guest */ -+ uint32_t guest_need_txkick; /* out of tx bufs */ -+ uint32_t guest_need_rxkick; /* out of rx bufs */ -+ uint32_t guest_csb_on; /* mode enabled on the guest */ -+ uint32_t guest_rdt; /* signals from guest */ -+ uint32_t pad[11]; /* to 64 bytes */ -+ -+ uint32_t host_tdh; /* mirror tdh, unused */ -+ uint32_t host_need_txkick; /* enable mode */ -+ uint32_t host_txcycles_lim; /* cycles before stop bh */ -+ uint32_t host_txcycles; /* current bh cycles */ -+ uint32_t host_rdh; /* mirror rdh, unused */ -+ uint32_t host_need_rxkick; /* ??? */ -+ -+}; -+#endif /* PARAVIRT */ -+ - /* - * The transmit ring, one per tx queue - */ -@@ -429,6 +451,7 @@ - struct em_int_delay_info tx_abs_int_delay; - struct em_int_delay_info rx_int_delay; - struct em_int_delay_info rx_abs_int_delay; -+ struct em_int_delay_info tx_itr; - - /* Misc stats maintained by the driver */ - unsigned long dropped_pkts; -@@ -440,6 +463,24 @@ - unsigned long watchdog_events; - unsigned long link_irq; - -+#ifdef MITIGATION -+ /* 0 = idle; 1xxxx int-pending; 3xxxx int + d pending + tdt */ -+#define MIT_PENDING_INT 0x10000 /* pending interrupt */ -+#define MIT_PENDING_TDT 0x30000 /* both intr and tdt write are pending */ -+ uint32_t shadow_tdt; -+ uint32_t mit_enable; -+ uint32_t rx_retries; /* optimize rx loop */ -+#endif /* MITIGATION */ -+ -+#ifdef PARAVIRT -+ struct em_dma_alloc csb_mem; /* phys address */ -+ struct e1000_csb *csb; /* virtual addr */ -+ uint32_t tdt_csb_count;// XXX stat -+ uint32_t tdt_reg_count;// XXX stat -+ uint32_t tdt_int_count;// XXX stat -+ uint32_t guest_need_kick_count;// XXX stat -+#endif /* PARAVIRT */ -+ - struct e1000_hw_stats stats; - }; - -Index: sys/dev/e1000/if_lem.c -=================================================================== ---- sys/dev/e1000/if_lem.c (revision 246924) -+++ sys/dev/e1000/if_lem.c (working copy) -@@ -32,6 +32,9 @@ - ******************************************************************************/ - /*$FreeBSD$*/ - -+#define MITIGATION -+#define PARAVIRT /* enable virtio-like synchronization */ -+ - #ifdef HAVE_KERNEL_OPTION_HEADERS - #include "opt_device_polling.h" - #include "opt_inet.h" -@@ -281,12 +284,15 @@ - #define EM_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) - #define EM_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) - -+#define MAX_INTS_PER_SEC 8000 -+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) -+ - static int lem_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); - static int lem_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); - static int lem_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); - static int lem_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); --static int lem_rxd = EM_DEFAULT_RXD; --static int lem_txd = EM_DEFAULT_TXD; -+static int lem_rxd = 8*EM_DEFAULT_RXD; -+static int lem_txd = 8*EM_DEFAULT_TXD; - static int lem_smart_pwr_down = FALSE; - - /* Controls whether promiscuous also shows bad packets */ -@@ -442,6 +448,11 @@ - &adapter->tx_abs_int_delay, - E1000_REGISTER(&adapter->hw, E1000_TADV), - lem_tx_abs_int_delay_dflt); -+ lem_add_int_delay_sysctl(adapter, "itr", -+ "interrupt delay limit in usecs/4", -+ &adapter->tx_itr, -+ E1000_REGISTER(&adapter->hw, E1000_ITR), -+ DEFAULT_ITR); - } - - /* Sysctls for limiting the amount of work done in the taskqueue */ -@@ -449,6 +460,14 @@ - "max number of rx packets to process", &adapter->rx_process_limit, - lem_rx_process_limit); - -+#ifdef MITIGATION -+ /* Sysctls to control mitigation */ -+ lem_add_rx_process_limit(adapter, "mit_enable", -+ "driver TDT mitigation", &adapter->mit_enable, 0); -+ lem_add_rx_process_limit(adapter, "rx_retries", -+ "driver rx retries", &adapter->rx_retries, 0); -+#endif /* MITIGATION */ -+ - /* Sysctl for setting the interface flow control */ - lem_set_flow_cntrl(adapter, "flow_control", - "flow control setting", -@@ -506,6 +525,46 @@ - */ - adapter->hw.mac.report_tx_early = 1; - -+#ifdef PARAVIRT -+ if (adapter->hw.subsystem_device_id == E1000_PARA_SUBDEV) { -+ uint64_t bus_addr; -+ -+ device_printf(dev, "paravirt support on dev %p\n", adapter); -+ tsize = 4096; // XXX one page for the csb -+ if (lem_dma_malloc(adapter, tsize, &adapter->csb_mem, BUS_DMA_NOWAIT)) { -+ device_printf(dev, "Unable to allocate csb memory\n"); -+ error = ENOMEM; -+ goto err_csb; -+ } -+ /* Setup the Base of the CSB */ -+ adapter->csb = (struct e1000_csb *)adapter->csb_mem.dma_vaddr; -+ /* force the first kick */ -+ adapter->csb->host_need_txkick = 1; /* txring empty */ -+ adapter->csb->guest_need_rxkick = 1; /* no rx packets */ -+ bus_addr = adapter->csb_mem.dma_paddr; -+ lem_add_rx_process_limit(adapter, "csb_on", -+ "enable paravirt.", &adapter->csb->guest_csb_on, 0); -+ lem_add_rx_process_limit(adapter, "txc_lim", -+ "txc_lim", &adapter->csb->host_txcycles_lim, 1); -+ /* some stats */ -+#define PA_SC(name, var, val) \ -+ lem_add_rx_process_limit(adapter, name, name, var, val) -+ PA_SC("host_need_txkick",&adapter->csb->host_need_txkick, 1); -+ PA_SC("host_need_rxkick",&adapter->csb->host_need_rxkick, 1); -+ PA_SC("guest_need_txkick",&adapter->csb->guest_need_txkick, 0); -+ PA_SC("guest_need_rxkick",&adapter->csb->guest_need_rxkick, 1); -+ PA_SC("tdt_reg_count",&adapter->tdt_reg_count, 0); -+ PA_SC("tdt_csb_count",&adapter->tdt_csb_count, 0); -+ PA_SC("tdt_int_count",&adapter->tdt_int_count, 0); -+ PA_SC("guest_need_kick_count",&adapter->guest_need_kick_count, 0); -+ /* tell the host where the block is */ -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAH, -+ (u32)(bus_addr >> 32)); -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAL, -+ (u32)bus_addr); -+ } -+#endif /* PARAVIRT */ -+ - tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc), - EM_DBA_ALIGN); - -@@ -664,6 +723,11 @@ - err_rx_desc: - lem_dma_free(adapter, &adapter->txdma); - err_tx_desc: -+#ifdef PARAVIRT -+ lem_dma_free(adapter, &adapter->csb_mem); -+err_csb: -+#endif /* PARAVIRT */ -+ - err_pci: - if (adapter->ifp != NULL) - if_free(adapter->ifp); -@@ -751,6 +815,12 @@ - adapter->rx_desc_base = NULL; - } - -+#ifdef PARAVIRT -+ if (adapter->csb) { -+ lem_dma_free(adapter, &adapter->csb_mem); -+ adapter->csb = NULL; -+ } -+#endif /* PARAVIRT */ - lem_release_hw_control(adapter); - free(adapter->mta, M_DEVBUF); - EM_TX_LOCK_DESTROY(adapter); -@@ -860,6 +930,15 @@ - } - if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; -+#ifdef PARAVIRT -+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE && adapter->csb && -+ adapter->csb->guest_csb_on && !adapter->csb->guest_need_txkick) { -+ adapter->csb->guest_need_txkick = 1; -+ adapter->guest_need_kick_count++; -+ // XXX memory barrier -+ lem_txeof(adapter); // XXX possibly clear IFF_DRV_OACTIVE -+ } -+#endif /* PARAVIRT */ - - return; - } -@@ -1300,6 +1379,7 @@ - lem_rxeof(adapter, -1, NULL); - - EM_TX_LOCK(adapter); -+ adapter->tdt_int_count++; - lem_txeof(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) -@@ -1337,12 +1417,17 @@ - - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { -- lem_rxeof(adapter, adapter->rx_process_limit, NULL); -+ bool more = lem_rxeof(adapter, adapter->rx_process_limit, NULL); - EM_TX_LOCK(adapter); -+ adapter->tdt_int_count++; - lem_txeof(adapter); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - lem_start_locked(ifp); - EM_TX_UNLOCK(adapter); -+ if (more) { -+ taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); -+ return; -+ } - } - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) -@@ -1702,6 +1787,35 @@ - */ - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -+ -+#ifdef PARAVIRT -+ if (adapter->csb) { -+ adapter->csb->guest_tdt = i; -+ /* XXX memory barrier ? */ -+ if (adapter->csb->guest_csb_on && -+ !adapter->csb->host_need_txkick) { -+ if (adapter->num_tx_desc_avail <= 64) {// XXX -+ lem_txeof(adapter); -+ } -+ adapter->tdt_csb_count++; -+ return (0); -+ } -+ } -+#endif /* PARAVIRT */ -+ -+#ifdef MITIGATION -+ if (adapter->mit_enable) { -+ if (adapter->shadow_tdt & MIT_PENDING_INT) { -+ /* signal intr and data pending */ -+ adapter->shadow_tdt = MIT_PENDING_TDT | (i & 0xffff); -+ return (0); -+ } else { -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } -+ } -+ adapter->tdt_reg_count++; -+#endif /* MITIGATION */ -+ - if (adapter->hw.mac.type == e1000_82547 && - adapter->link_duplex == HALF_DUPLEX) - lem_82547_move_tail(adapter); -@@ -1957,6 +2071,16 @@ - - lem_smartspeed(adapter); - -+#ifdef PARAVIRT -+ /* recover space if needed */ -+ if (adapter->csb && adapter->csb->guest_csb_on && -+ (adapter->watchdog_check == TRUE) && -+ (ticks - adapter->watchdog_time > EM_WATCHDOG) && -+ (adapter->num_tx_desc_avail != adapter->num_tx_desc) ) { -+ lem_txeof(adapter); -+ /* XXX should also recover from stalls ? */ -+ } -+#endif /* PARAVIRT */ - /* - * We check the watchdog: the time since - * the last TX descriptor was cleaned. -@@ -3027,6 +3151,16 @@ - adapter->next_tx_to_clean = first; - adapter->num_tx_desc_avail = num_avail; - -+#ifdef MITIGATION -+ if ((adapter->shadow_tdt & MIT_PENDING_TDT) == MIT_PENDING_TDT) { -+ /* a tdt write is pending, do it */ -+ E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), -+ 0xffff & adapter->shadow_tdt); -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } else { -+ adapter->shadow_tdt = 0; // disable -+ } -+#endif /* MITIGATION */ - /* - * If we have enough room, clear IFF_DRV_OACTIVE to - * tell the stack that it is OK to send packets. -@@ -3034,6 +3168,12 @@ - */ - if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; -+#ifdef PARAVIRT -+ if (adapter->csb) { -+ adapter->csb->guest_need_txkick = 0; -+ // XXX memory barrier -+ } -+#endif /* PARAVIRT */ - if (adapter->num_tx_desc_avail == adapter->num_tx_desc) { - adapter->watchdog_check = FALSE; - return; -@@ -3246,8 +3386,6 @@ - * Enable receive unit. - * - **********************************************************************/ --#define MAX_INTS_PER_SEC 8000 --#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) - - static void - lem_initialize_receive_unit(struct adapter *adapter) -@@ -3347,9 +3485,16 @@ - - if (t >= na->num_rx_desc) - t -= na->num_rx_desc; -+#ifdef PARAVIRT -+ adapter->csb->guest_rdt = t; -+#endif /* PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), t); -- } else -+ return; -+ } - #endif /* DEV_NETMAP */ -+#ifdef PARAVIRT -+ adapter->csb->guest_rdt = adapter->num_rx_desc - 1; -+#endif /* PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1); - - return; -@@ -3426,7 +3571,12 @@ - u16 len, desc_len, prev_len_adj; - int i, rx_sent = 0; - struct e1000_rx_desc *current_desc; -+ int retries; - -+#ifdef PARAVIRT -+ ND("clear guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ adapter->csb->guest_need_rxkick = 0; -+#endif /* PARAVIRT */ - EM_RX_LOCK(adapter); - i = adapter->next_rx_desc_to_check; - current_desc = &adapter->rx_desc_base[i]; -@@ -3443,19 +3593,39 @@ - } - #endif /* DEV_NETMAP */ - -+#if 0 // XXX optimization ? - if (!((current_desc->status) & E1000_RXD_STAT_DD)) { - if (done != NULL) - *done = rx_sent; - EM_RX_UNLOCK(adapter); - return (FALSE); - } -+#endif /* 0 */ - -+ retries = 0; - while (count != 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) { - struct mbuf *m = NULL; - - status = current_desc->status; -- if ((status & E1000_RXD_STAT_DD) == 0) -+ if ((status & E1000_RXD_STAT_DD) == 0) { -+ if (++retries <= adapter->rx_retries) { -+ continue; -+ } -+#ifdef PARAVIRT -+ if (adapter->csb->guest_need_rxkick == 0) { -+ ND("set guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ adapter->csb->guest_need_rxkick = 1; -+ continue; -+ } -+#endif /* PARAVIRT */ - break; -+ } -+#ifdef PARAVIRT -+ if (adapter->csb->guest_need_rxkick) -+ ND("clear again guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ adapter->csb->guest_need_rxkick = 0; -+#endif /* PARAVIRT */ -+ retries = 0; - - mp = adapter->rx_buffer_area[i].m_head; - /* -@@ -3599,6 +3769,10 @@ - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - if (--i < 0) - i = adapter->num_rx_desc - 1; -+#ifdef PARAVIRT -+ adapter->csb->guest_rdt = i; -+ if (!adapter->csb->guest_csb_on || adapter->csb->host_need_rxkick) -+#endif /* PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); - if (done != NULL) - *done = rx_sent; -@@ -4588,6 +4762,8 @@ - return (EINVAL); - info->value = usecs; - ticks = EM_USECS_TO_TICKS(usecs); -+ if (info->offset == E1000_ITR) /* units are 256ns here */ -+ ticks *= 4; - - adapter = info->adapter; - -Index: sys/dev/e1000/if_lem.h -=================================================================== ---- sys/dev/e1000/if_lem.h (revision 246924) -+++ sys/dev/e1000/if_lem.h (working copy) -@@ -265,6 +265,28 @@ - #define PICOSECS_PER_TICK 20833 - #define TSYNC_PORT 319 /* UDP port for the protocol */ - -+#ifdef PARAVIRT -+#define E1000_PARA_SUBDEV 0x1101 /* special id */ -+#define E1000_CSBAL 0x02830 /* csb physical address */ -+#define E1000_CSBAH 0x02834 -+struct e1000_csb { /* comm. block */ -+ uint32_t guest_tdt; /* signals from guest */ -+ uint32_t guest_need_txkick; /* out of tx bufs */ -+ uint32_t guest_need_rxkick; /* out of rx bufs */ -+ uint32_t guest_csb_on; /* mode enabled on the guest */ -+ uint32_t guest_rdt; /* signals from guest */ -+ uint32_t pad[11]; /* to 64 bytes */ -+ -+ uint32_t host_tdh; /* mirror tdh, unused */ -+ uint32_t host_need_txkick; /* enable mode */ -+ uint32_t host_txcycles_lim; /* cycles before stop bh */ -+ uint32_t host_txcycles; /* current bh cycles */ -+ uint32_t host_rdh; /* mirror rdh, unused */ -+ uint32_t host_need_rxkick; /* ??? */ -+ -+}; -+#endif /* PARAVIRT */ -+ - /* - * Bus dma allocation structure used by - * e1000_dma_malloc and e1000_dma_free. -@@ -363,6 +385,7 @@ - struct em_int_delay_info tx_abs_int_delay; - struct em_int_delay_info rx_int_delay; - struct em_int_delay_info rx_abs_int_delay; -+ struct em_int_delay_info tx_itr; - - /* - * Transmit definitions -@@ -436,7 +459,24 @@ - boolean_t pcix_82544; - boolean_t in_detach; - -+#ifdef MITIGATION -+ /* 0 = idle; 1xxxx int-pending; 3xxxx int + d pending + tdt */ -+#define MIT_PENDING_INT 0x10000 /* pending interrupt */ -+#define MIT_PENDING_TDT 0x30000 /* both intr and tdt write are pending */ -+ uint32_t shadow_tdt; -+ uint32_t mit_enable; -+ uint32_t rx_retries; /* optimize rx loop */ -+#endif /* MITIGATION */ - -+#ifdef PARAVIRT -+ struct em_dma_alloc csb_mem; /* phys address */ -+ struct e1000_csb *csb; /* virtual addr */ -+ uint32_t tdt_csb_count;// XXX stat -+ uint32_t tdt_reg_count;// XXX stat -+ uint32_t tdt_int_count;// XXX stat -+ uint32_t guest_need_kick_count;// XXX stat -+#endif /* PARAVIRT */ -+ - struct e1000_hw_stats stats; - }; - diff --git a/private/extra/20130222-bsd-em-head.diff b/private/extra/20130222-bsd-em-head.diff deleted file mode 100644 index b8eb40bc5..000000000 --- a/private/extra/20130222-bsd-em-head.diff +++ /dev/null @@ -1,546 +0,0 @@ -Index: head/release/picobsd/floppy.tree/etc/ttys -=================================================================== ---- head/release/picobsd/floppy.tree/etc/ttys (revision 247068) -+++ head/release/picobsd/floppy.tree/etc/ttys (working copy) -@@ -8,6 +8,7 @@ - # This entry needed for asking password when init goes to single-user mode - # If you want to be asked for password, change "secure" to "insecure" here - #console none unknown off secure -+console "/usr/libexec/getty std.9600" vt100 on secure - vga none xterm off secure - # - ttyv0 "/usr/libexec/getty Pc" xterm on secure -Index: head/sys/dev/e1000/if_em.h -=================================================================== ---- head/sys/dev/e1000/if_em.h (revision 247068) -+++ head/sys/dev/e1000/if_em.h (working copy) -@@ -271,6 +271,28 @@ - int value; /* Current value in usecs */ - }; - -+#ifdef PARAVIRT -+#define E1000_PARA_SUBDEV 0x1101 /* special id */ -+#define E1000_CSBAL 0x02830 /* csb physical address */ -+#define E1000_CSBAH 0x02834 -+struct e1000_csb { /* comm. block */ -+ uint32_t guest_tdt; /* signals from guest */ -+ uint32_t guest_need_txkick; /* out of tx bufs */ -+ uint32_t guest_need_rxkick; /* out of rx bufs */ -+ uint32_t guest_csb_on; /* mode enabled on the guest */ -+ uint32_t guest_rdt; /* signals from guest */ -+ uint32_t pad[11]; /* to 64 bytes */ -+ -+ uint32_t host_tdh; /* mirror tdh, unused */ -+ uint32_t host_need_txkick; /* enable mode */ -+ uint32_t host_txcycles_lim; /* cycles before stop bh */ -+ uint32_t host_txcycles; /* current bh cycles */ -+ uint32_t host_rdh; /* mirror rdh, unused */ -+ uint32_t host_need_rxkick; /* ??? */ -+ -+}; -+#endif /* PARAVIRT */ -+ - /* - * The transmit ring, one per tx queue - */ -@@ -429,6 +451,7 @@ - struct em_int_delay_info tx_abs_int_delay; - struct em_int_delay_info rx_int_delay; - struct em_int_delay_info rx_abs_int_delay; -+ struct em_int_delay_info tx_itr; - - /* Misc stats maintained by the driver */ - unsigned long dropped_pkts; -@@ -440,6 +463,24 @@ - unsigned long watchdog_events; - unsigned long link_irq; - -+#ifdef MITIGATION -+ /* 0 = idle; 1xxxx int-pending; 3xxxx int + d pending + tdt */ -+#define MIT_PENDING_INT 0x10000 /* pending interrupt */ -+#define MIT_PENDING_TDT 0x30000 /* both intr and tdt write are pending */ -+ uint32_t shadow_tdt; -+ uint32_t mit_enable; -+ uint32_t rx_retries; /* optimize rx loop */ -+#endif /* MITIGATION */ -+ -+#ifdef PARAVIRT -+ struct em_dma_alloc csb_mem; /* phys address */ -+ struct e1000_csb *csb; /* virtual addr */ -+ uint32_t tdt_csb_count;// XXX stat -+ uint32_t tdt_reg_count;// XXX stat -+ uint32_t tdt_int_count;// XXX stat -+ uint32_t guest_need_kick_count;// XXX stat -+#endif /* PARAVIRT */ -+ - struct e1000_hw_stats stats; - }; - -Index: head/sys/dev/e1000/if_lem.c -=================================================================== ---- head/sys/dev/e1000/if_lem.c (revision 247068) -+++ head/sys/dev/e1000/if_lem.c (working copy) -@@ -32,6 +32,9 @@ - ******************************************************************************/ - /*$FreeBSD$*/ - -+#define LEM_SEND_COMBINING -+#define LEM_PARAVIRT /* enable virtio-like synchronization */ -+ - #ifdef HAVE_KERNEL_OPTION_HEADERS - #include "opt_device_polling.h" - #include "opt_inet.h" -@@ -281,12 +284,15 @@ - #define EM_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) - #define EM_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) - -+#define MAX_INTS_PER_SEC 8000 -+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) -+ - static int lem_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); - static int lem_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); - static int lem_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); - static int lem_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); --static int lem_rxd = EM_DEFAULT_RXD; --static int lem_txd = EM_DEFAULT_TXD; -+static int lem_rxd = 8*EM_DEFAULT_RXD; -+static int lem_txd = 8*EM_DEFAULT_TXD; - static int lem_smart_pwr_down = FALSE; - - /* Controls whether promiscuous also shows bad packets */ -@@ -442,6 +448,11 @@ - &adapter->tx_abs_int_delay, - E1000_REGISTER(&adapter->hw, E1000_TADV), - lem_tx_abs_int_delay_dflt); -+ lem_add_int_delay_sysctl(adapter, "itr", -+ "interrupt delay limit in usecs/4", -+ &adapter->tx_itr, -+ E1000_REGISTER(&adapter->hw, E1000_ITR), -+ DEFAULT_ITR); - } - - /* Sysctls for limiting the amount of work done in the taskqueue */ -@@ -449,6 +460,14 @@ - "max number of rx packets to process", &adapter->rx_process_limit, - lem_rx_process_limit); - -+#ifdef LEM_SEND_COMBINING -+ /* Sysctls to control mitigation */ -+ lem_add_rx_process_limit(adapter, "tx_sc", -+ "tx send combining", &adapter->tx_sc_on, 0); -+ lem_add_rx_process_limit(adapter, "rx_retries", -+ "driver rx retries", &adapter->rx_retries, 0); -+#endif /* LEM_SEND_COMBINING */ -+ - /* Sysctl for setting the interface flow control */ - lem_set_flow_cntrl(adapter, "flow_control", - "flow control setting", -@@ -506,6 +525,46 @@ - */ - adapter->hw.mac.report_tx_early = 1; - -+#ifdef LEM_PARAVIRT -+ if (adapter->hw.subsystem_device_id == E1000_PARA_SUBDEV) { -+ uint64_t bus_addr; -+ -+ device_printf(dev, "paravirt support on dev %p\n", adapter); -+ tsize = 4096; // XXX one page for the csb -+ if (lem_dma_malloc(adapter, tsize, &adapter->csb_mem, BUS_DMA_NOWAIT)) { -+ device_printf(dev, "Unable to allocate csb memory\n"); -+ error = ENOMEM; -+ goto err_csb; -+ } -+ /* Setup the Base of the CSB */ -+ adapter->csb = (struct e1000_csb *)adapter->csb_mem.dma_vaddr; -+ /* force the first kick */ -+ adapter->csb->host_need_txkick = 1; /* txring empty */ -+ adapter->csb->guest_need_rxkick = 1; /* no rx packets */ -+ bus_addr = adapter->csb_mem.dma_paddr; -+ lem_add_rx_process_limit(adapter, "csb_on", -+ "enable paravirt.", &adapter->csb->guest_csb_on, 0); -+ lem_add_rx_process_limit(adapter, "txc_lim", -+ "txc_lim", &adapter->csb->host_txcycles_lim, 1); -+ /* some stats */ -+#define PA_SC(name, var, val) \ -+ lem_add_rx_process_limit(adapter, name, name, var, val) -+ PA_SC("host_need_txkick",&adapter->csb->host_need_txkick, 1); -+ PA_SC("host_need_rxkick",&adapter->csb->host_need_rxkick, 1); -+ PA_SC("guest_need_txkick",&adapter->csb->guest_need_txkick, 0); -+ PA_SC("guest_need_rxkick",&adapter->csb->guest_need_rxkick, 1); -+ PA_SC("tdt_reg_count",&adapter->tdt_reg_count, 0); -+ PA_SC("tdt_csb_count",&adapter->tdt_csb_count, 0); -+ PA_SC("tdt_int_count",&adapter->tdt_int_count, 0); -+ PA_SC("guest_need_kick_count",&adapter->guest_need_kick_count, 0); -+ /* tell the host where the block is */ -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAH, -+ (u32)(bus_addr >> 32)); -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAL, -+ (u32)bus_addr); -+ } -+#endif /* LEM_PARAVIRT */ -+ - tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc), - EM_DBA_ALIGN); - -@@ -664,6 +723,11 @@ - err_rx_desc: - lem_dma_free(adapter, &adapter->txdma); - err_tx_desc: -+#ifdef LEM_PARAVIRT -+ lem_dma_free(adapter, &adapter->csb_mem); -+err_csb: -+#endif /* LEM_PARAVIRT */ -+ - err_pci: - if (adapter->ifp != NULL) - if_free(adapter->ifp); -@@ -751,6 +815,12 @@ - adapter->rx_desc_base = NULL; - } - -+#ifdef LEM_PARAVIRT -+ if (adapter->csb) { -+ lem_dma_free(adapter, &adapter->csb_mem); -+ adapter->csb = NULL; -+ } -+#endif /* LEM_PARAVIRT */ - lem_release_hw_control(adapter); - free(adapter->mta, M_DEVBUF); - EM_TX_LOCK_DESTROY(adapter); -@@ -860,6 +930,15 @@ - } - if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; -+#ifdef LEM_PARAVIRT -+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE && adapter->csb && -+ adapter->csb->guest_csb_on && !adapter->csb->guest_need_txkick) { -+ adapter->csb->guest_need_txkick = 1; -+ adapter->guest_need_kick_count++; -+ // XXX memory barrier -+ lem_txeof(adapter); // XXX possibly clear IFF_DRV_OACTIVE -+ } -+#endif /* LEM_PARAVIRT */ - - return; - } -@@ -1300,6 +1379,7 @@ - lem_rxeof(adapter, -1, NULL); - - EM_TX_LOCK(adapter); -+ adapter->tdt_int_count++; - lem_txeof(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) -@@ -1337,12 +1417,17 @@ - - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { -- lem_rxeof(adapter, adapter->rx_process_limit, NULL); -+ bool more = lem_rxeof(adapter, adapter->rx_process_limit, NULL); - EM_TX_LOCK(adapter); -+ adapter->tdt_int_count++; - lem_txeof(adapter); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - lem_start_locked(ifp); - EM_TX_UNLOCK(adapter); -+ if (more) { -+ taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); -+ return; -+ } - } - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) -@@ -1702,6 +1787,35 @@ - */ - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -+ -+#ifdef LEM_PARAVIRT -+ if (adapter->csb) { -+ adapter->csb->guest_tdt = i; -+ /* XXX memory barrier ? */ -+ if (adapter->csb->guest_csb_on && -+ !adapter->csb->host_need_txkick) { -+ if (adapter->num_tx_desc_avail <= 64) {// XXX -+ lem_txeof(adapter); -+ } -+ adapter->tdt_csb_count++; -+ return (0); -+ } -+ } -+#endif /* LEM_PARAVIRT */ -+ -+#ifdef LEM_SEND_COMBINING -+ if (adapter->tx_sc_on) { -+ if (adapter->shadow_tdt & MIT_PENDING_INT) { -+ /* signal intr and data pending */ -+ adapter->shadow_tdt = MIT_PENDING_TDT | (i & 0xffff); -+ return (0); -+ } else { -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } -+ } -+ adapter->tdt_reg_count++; -+#endif /* LEM_SEND_COMBINING */ -+ - if (adapter->hw.mac.type == e1000_82547 && - adapter->link_duplex == HALF_DUPLEX) - lem_82547_move_tail(adapter); -@@ -1957,6 +2071,16 @@ - - lem_smartspeed(adapter); - -+#ifdef LEM_PARAVIRT -+ /* recover space if needed */ -+ if (adapter->csb && adapter->csb->guest_csb_on && -+ (adapter->watchdog_check == TRUE) && -+ (ticks - adapter->watchdog_time > EM_WATCHDOG) && -+ (adapter->num_tx_desc_avail != adapter->num_tx_desc) ) { -+ lem_txeof(adapter); -+ /* XXX should also recover from stalls ? */ -+ } -+#endif /* LEM_PARAVIRT */ - /* - * We check the watchdog: the time since - * the last TX descriptor was cleaned. -@@ -3027,6 +3151,16 @@ - adapter->next_tx_to_clean = first; - adapter->num_tx_desc_avail = num_avail; - -+#ifdef LEM_SEND_COMBINING -+ if ((adapter->shadow_tdt & MIT_PENDING_TDT) == MIT_PENDING_TDT) { -+ /* a tdt write is pending, do it */ -+ E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), -+ 0xffff & adapter->shadow_tdt); -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } else { -+ adapter->shadow_tdt = 0; // disable -+ } -+#endif /* LEM_SEND_COMBINING */ - /* - * If we have enough room, clear IFF_DRV_OACTIVE to - * tell the stack that it is OK to send packets. -@@ -3034,6 +3168,12 @@ - */ - if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; -+#ifdef LEM_LEM_PARAVIRT -+ if (adapter->csb) { -+ adapter->csb->guest_need_txkick = 0; -+ // XXX memory barrier -+ } -+#endif /* LEM_LEM_PARAVIRT */ - if (adapter->num_tx_desc_avail == adapter->num_tx_desc) { - adapter->watchdog_check = FALSE; - return; -@@ -3246,8 +3386,6 @@ - * Enable receive unit. - * - **********************************************************************/ --#define MAX_INTS_PER_SEC 8000 --#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) - - static void - lem_initialize_receive_unit(struct adapter *adapter) -@@ -3347,9 +3485,16 @@ - - if (t >= na->num_rx_desc) - t -= na->num_rx_desc; -+#ifdef LEM_PARAVIRT -+ adapter->csb->guest_rdt = t; -+#endif /* LEM_PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), t); -- } else -+ return; -+ } - #endif /* DEV_NETMAP */ -+#ifdef LEM_PARAVIRT -+ adapter->csb->guest_rdt = adapter->num_rx_desc - 1; -+#endif /* LEM_PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), adapter->num_rx_desc - 1); - - return; -@@ -3426,7 +3571,12 @@ - u16 len, desc_len, prev_len_adj; - int i, rx_sent = 0; - struct e1000_rx_desc *current_desc; -+ int retries; - -+#ifdef LEM_PARAVIRT -+ ND("clear guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ adapter->csb->guest_need_rxkick = 0; -+#endif /* LEM_PARAVIRT */ - EM_RX_LOCK(adapter); - i = adapter->next_rx_desc_to_check; - current_desc = &adapter->rx_desc_base[i]; -@@ -3443,19 +3593,39 @@ - } - #endif /* DEV_NETMAP */ - -+#if 0 // XXX optimization ? - if (!((current_desc->status) & E1000_RXD_STAT_DD)) { - if (done != NULL) - *done = rx_sent; - EM_RX_UNLOCK(adapter); - return (FALSE); - } -+#endif /* 0 */ - -+ retries = 0; - while (count != 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) { - struct mbuf *m = NULL; - - status = current_desc->status; -- if ((status & E1000_RXD_STAT_DD) == 0) -+ if ((status & E1000_RXD_STAT_DD) == 0) { -+ if (++retries <= adapter->rx_retries) { -+ continue; -+ } -+#ifdef LEM_PARAVIRT -+ if (adapter->csb->guest_need_rxkick == 0) { -+ ND("set guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ adapter->csb->guest_need_rxkick = 1; -+ continue; -+ } -+#endif /* LEM_PARAVIRT */ - break; -+ } -+#ifdef LEM_PARAVIRT -+ if (adapter->csb->guest_need_rxkick) -+ ND("clear again guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ adapter->csb->guest_need_rxkick = 0; -+#endif /* LEM_PARAVIRT */ -+ retries = 0; - - mp = adapter->rx_buffer_area[i].m_head; - /* -@@ -3599,6 +3769,10 @@ - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - if (--i < 0) - i = adapter->num_rx_desc - 1; -+#ifdef LEM_PARAVIRT -+ adapter->csb->guest_rdt = i; -+ if (!adapter->csb->guest_csb_on || adapter->csb->host_need_rxkick) -+#endif /* LEM_PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); - if (done != NULL) - *done = rx_sent; -@@ -4584,6 +4758,8 @@ - return (EINVAL); - info->value = usecs; - ticks = EM_USECS_TO_TICKS(usecs); -+ if (info->offset == E1000_ITR) /* units are 256ns here */ -+ ticks *= 4; - - adapter = info->adapter; - -Index: head/sys/dev/e1000/if_lem.h -=================================================================== ---- head/sys/dev/e1000/if_lem.h (revision 247068) -+++ head/sys/dev/e1000/if_lem.h (working copy) -@@ -265,6 +265,28 @@ - #define PICOSECS_PER_TICK 20833 - #define TSYNC_PORT 319 /* UDP port for the protocol */ - -+#ifdef PARAVIRT -+#define E1000_PARA_SUBDEV 0x1101 /* special id */ -+#define E1000_CSBAL 0x02830 /* csb physical address */ -+#define E1000_CSBAH 0x02834 -+struct e1000_csb { /* comm. block */ -+ uint32_t guest_tdt; /* signals from guest */ -+ uint32_t guest_need_txkick; /* out of tx bufs */ -+ uint32_t guest_need_rxkick; /* out of rx bufs */ -+ uint32_t guest_csb_on; /* mode enabled on the guest */ -+ uint32_t guest_rdt; /* signals from guest */ -+ uint32_t pad[11]; /* to 64 bytes */ -+ -+ uint32_t host_tdh; /* mirror tdh, unused */ -+ uint32_t host_need_txkick; /* enable mode */ -+ uint32_t host_txcycles_lim; /* cycles before stop bh */ -+ uint32_t host_txcycles; /* current bh cycles */ -+ uint32_t host_rdh; /* mirror rdh, unused */ -+ uint32_t host_need_rxkick; /* ??? */ -+ -+}; -+#endif /* PARAVIRT */ -+ - /* - * Bus dma allocation structure used by - * e1000_dma_malloc and e1000_dma_free. -@@ -363,6 +385,7 @@ - struct em_int_delay_info tx_abs_int_delay; - struct em_int_delay_info rx_int_delay; - struct em_int_delay_info rx_abs_int_delay; -+ struct em_int_delay_info tx_itr; - - /* - * Transmit definitions -@@ -436,7 +459,24 @@ - boolean_t pcix_82544; - boolean_t in_detach; - -+#ifdef LEM_SEND_COMBINING -+ /* 0 = idle; 1xxxx int-pending; 3xxxx int + d pending + tdt */ -+#define MIT_PENDING_INT 0x10000 /* pending interrupt */ -+#define MIT_PENDING_TDT 0x30000 /* both intr and tdt write are pending */ -+ uint32_t shadow_tdt; -+ uint32_t tx_sc_on; -+ uint32_t rx_retries; /* optimize rx loop */ -+#endif /* LEM_SEND_COMBINING */ - -+#ifdef LEM_PARAVIRT -+ struct em_dma_alloc csb_mem; /* phys address */ -+ struct e1000_csb *csb; /* virtual addr */ -+ uint32_t tdt_csb_count;// XXX stat -+ uint32_t tdt_reg_count;// XXX stat -+ uint32_t tdt_int_count;// XXX stat -+ uint32_t guest_need_kick_count;// XXX stat -+#endif /* LEM_PARAVIRT */ -+ - struct e1000_hw_stats stats; - }; - -Index: head/tools/tools/netrate/netsend/netsend.c -=================================================================== ---- head/tools/tools/netrate/netsend/netsend.c (revision 247068) -+++ head/tools/tools/netrate/netsend/netsend.c (working copy) -@@ -49,6 +49,7 @@ - int ipv6; - struct timespec interval; - int port, port_max; -+ int burst; - long duration; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; -@@ -164,8 +165,8 @@ - * calls, but also make sure there is at least one every - * some 100 packets. - */ -- if ((long)ns < minres_ns/100) -- gettimeofday_cycles = 100; -+ if ((long)ns < minres_ns/a->burst) -+ gettimeofday_cycles = a->burst; - else - gettimeofday_cycles = minres_ns/ns; - fprintf(stderr, -@@ -288,7 +289,7 @@ - - bzero(&a, sizeof(a)); - -- if (argc != 6) -+ if (argc < 6) - usage(); - - memset(&hints, 0, sizeof(hints)); -@@ -360,6 +361,11 @@ - if (a.duration < 0 || *dummy != '\0') - usage(); - -+ if (argc > 6) -+ a.burst = strtoul(argv[6], NULL, 0); -+ if (a.burst < 1 || a.burst > 10000) -+ a.burst = 100; -+ - a.packet = malloc(payloadsize); - if (a.packet == NULL) { - perror("malloc"); diff --git a/private/extra/20130224-qemu-head.diff b/private/extra/20130224-qemu-head.diff deleted file mode 100644 index ddb6841b0..000000000 --- a/private/extra/20130224-qemu-head.diff +++ /dev/null @@ -1,1499 +0,0 @@ -diff --git a/configure b/configure -index dcaa67c..55ef412 100755 ---- a/configure -+++ b/configure -@@ -146,6 +146,7 @@ curl="" - curses="" - docs="" - fdt="" -+netmap="" - nptl="" - pixman="" - sdl="" -@@ -740,6 +741,10 @@ for opt do - ;; - --enable-vde) vde="yes" - ;; -+ --disable-netmap) netmap="no" -+ ;; -+ --enable-netmap) netmap="yes" -+ ;; - --disable-xen) xen="no" - ;; - --enable-xen) xen="yes" -@@ -1117,6 +1122,8 @@ echo " --disable-uuid disable uuid support" - echo " --enable-uuid enable uuid support" - echo " --disable-vde disable support for vde network" - echo " --enable-vde enable support for vde network" -+echo " --disable-netmap disable support for netmap network" -+echo " --enable-netmap enable support for netmap network" - echo " --disable-linux-aio disable Linux AIO support" - echo " --enable-linux-aio enable Linux AIO support" - echo " --disable-cap-ng disable libcap-ng support" -@@ -1939,6 +1946,26 @@ EOF - fi - - ########################################## -+# netmap headers probe -+if test "$netmap" != "no" ; then -+ cat > $TMPC << EOF -+#include -+#include -+#include -+#include -+int main(void) { return 0; } -+EOF -+ if compile_prog "" "" ; then -+ netmap=yes -+ else -+ if test "$netmap" = "yes" ; then -+ feature_not_found "netmap" -+ fi -+ netmap=no -+ fi -+fi -+ -+########################################## - # libcap-ng library probe - if test "$cap_ng" != "no" ; then - cap_libs="-lcap-ng" -@@ -3364,6 +3391,7 @@ echo "NPTL support $nptl" - echo "GUEST_BASE $guest_base" - echo "PIE $pie" - echo "vde support $vde" -+echo "netmap support $netmap" - echo "Linux AIO support $linux_aio" - echo "ATTR/XATTR support $attr" - echo "Install blobs $blobs" -@@ -3489,6 +3517,9 @@ fi - if test "$vde" = "yes" ; then - echo "CONFIG_VDE=y" >> $config_host_mak - fi -+if test "$netmap" = "yes" ; then -+ echo "CONFIG_NETMAP=y" >> $config_host_mak -+fi - if test "$cap_ng" = "yes" ; then - echo "CONFIG_LIBCAP=y" >> $config_host_mak - fi -diff --git a/exec.c b/exec.c -index a41bcb8..e6ef820 100644 ---- a/exec.c -+++ b/exec.c -@@ -2059,6 +2059,35 @@ static void cpu_notify_map_clients(void) - } - } - -+/* Helper function returning the contiguous segment containing -+ * a guest physical address (gpaddr). -+ * Return 0 if not existing, otherwise the segment covers the -+ * guest physical region *gpa_low .. *gpa_high - 1, and the -+ * guest-physical to host-virtual mapping is obtained as -+ * host_virtual_addr = gp_addr + *g2h_ofs -+ */ -+int address_space_mappable(AddressSpace *as, hwaddr gp_addr, -+ uint64_t *gpa_lo, uint64_t *gpa_hi, uint64_t *g2h_ofs) -+{ -+ AddressSpaceDispatch *d = as->dispatch; -+ MemoryRegionSection *section; -+ RAMBlock *block; -+ -+ section = phys_page_find(d, gp_addr >> TARGET_PAGE_BITS); -+ if (memory_region_is_ram(section->mr) && !section->readonly) { -+ QTAILQ_FOREACH(block, &ram_list.blocks, next) { -+ if (gp_addr - block->offset < block->length) { -+ *gpa_lo = block->offset; -+ *gpa_hi = block->offset + block->length; -+ *g2h_ofs = (uint64_t)block->host - block->offset; -+ return 1; -+ } -+ } -+ } -+ *gpa_lo = *gpa_hi = *g2h_ofs = 0; -+ return 0; /* cannot map */ -+} -+ - /* Map a physical memory region into a host virtual address. - * May map a subset of the requested range, given by and returned in *plen. - * May return NULL if resources needed to perform the mapping are exhausted. -diff --git a/hw/e1000.c b/hw/e1000.c -index d6fe815..16ae5de 100644 ---- a/hw/e1000.c -+++ b/hw/e1000.c -@@ -35,6 +35,59 @@ - - #include "e1000_hw.h" - -+#define MAP_RING /* map the buffers instead of pci_dma_rw() */ -+#define PARAVIRT /* use paravirtualized driver */ -+ -+#ifdef PARAVIRT -+/* -+ Support for virtio-like communication. -+ 1. the VMM advertises virtio-like synchronization setting -+ the subvendor id set to 0x1101 (E1000_PARA_SUBDEV) -+ -+ 2. the guest allocates the shared command status block (csb) and -+ write its physical address at CSBAL and CSBAH (offsets -+ 0x2830 and 0x2834, data is little endian). -+ csb->csb_on enables the mode. If disabled, the device is a -+ regular e1000. -+ -+ 3. notifications for tx and rx are exchanged without vm exits -+ if possible. In particular (only mentioning csb mode below): -+ -+ TX: host sets host_need_txkick=1 when the I/O thread bh is idle. -+ Guest updates guest_tdt and returns if host_need_txkick == 0, -+ otherwise dues a regular write to the TDT. -+ If the txring runs dry, guest sets guest_need_txkick and retries -+ to recover buffers. -+ Host reacts to writes to the TDT by clearing host_need_txkick -+ and scheduling a thread to do the reads. -+ The thread is kept active until there are packets (with a -+ configurable number of retries). Eventually it sets -+ host_need_txkick=1, does a final check for packets and blocks. -+ An interrupt is generated if guest_need_txkick == 1. -+ -+ */ -+#define E1000_PARA_SUBDEV 0x1101 -+#define E1000_CSBAL 0x02830 /* addresses for the csb */ -+#define E1000_CSBAH 0x02834 -+struct e1000_csb { -+ /* these are written by the guest */ -+ uint32_t guest_tdt; /* pkt to transmit */ -+ uint32_t guest_need_txkick; /* ran out of tx bufs, request kick */ -+ uint32_t guest_need_rxkick; /* ran out of rx pkts, request kick ? */ -+ uint32_t guest_csb_on; /* enable paravirtual mode */ -+ uint32_t guest_rdt; /* rx buffers available */ -+ uint32_t pad[11]; -+ -+ /* these are (mostly) written by the host */ -+ uint32_t host_tdh; /* shadow registea, mostly unused */ -+ uint32_t host_need_txkick; /* start the iothread */ -+ uint32_t host_txcycles_lim; /* how much to spin before sleep */ -+ uint32_t host_txcycles; /* counter, but no need to be exported */ -+ uint32_t host_rdh; /* shadow register, mostly unused */ -+ uint32_t host_need_rxkick; /* ??? */ -+}; -+#endif /* PARAVIRT */ -+ - #define E1000_DEBUG - - #ifdef E1000_DEBUG -@@ -72,7 +125,9 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); - * E1000_DEV_ID_82544GC_COPPER appears to work; not well tested - * Others never tested - */ --enum { E1000_DEVID = E1000_DEV_ID_82540EM }; -+enum { E1000_DEVID = E1000_DEV_ID_82540EM }; // microwire -+//enum { E1000_DEVID = E1000_DEV_ID_82573L }; // eeprom eerd -+// enum { E1000_DEVID = E1000_DEV_ID_82571EB_COPPER }; // eeprom eerd - - /* - * May need to specify additional MAC-to-PHY entries -- -@@ -84,6 +139,18 @@ enum { - /* default to E1000_DEV_ID_82540EM */ 0xc20 - }; - -+/* -+ * map a guest region into a host region -+ * if the pointer is within the region, ofs gives the displacement. -+ * valid = 0 means we should try to map it. -+ */ -+struct guest_memreg_map { -+ int valid; -+ uint64_t lo; -+ uint64_t hi; -+ uint64_t ofs; -+}; -+ - typedef struct E1000State_st { - PCIDevice dev; - NICState *nic; -@@ -131,6 +198,28 @@ typedef struct E1000State_st { - } eecd_state; - - QEMUTimer *autoneg_timer; -+ QEMUTimer *mit_timer; /* handle for the timer */ -+ uint32_t mit_timer_on; /* mitigation timer active */ -+ uint32_t mit_cause; /* pending interrupt cause */ -+ uint32_t mit_on; /* mitigation enable */ -+ -+ /* when the rxq becomes full, disable input until half empty */ -+ uint32_t rxbufs, txbufs, rxq_full; -+#ifdef MAP_RING -+ /* used for map ring */ -+ uint64_t txring_phi, rxring_phi; /* phisical address */ -+ struct e1000_tx_desc *txring; -+ struct e1000_rx_desc *rxring; -+ struct guest_memreg_map mbufs; -+#endif /* MAP_RING */ -+ -+#ifdef PARAVIRT -+ /* used for the communication block */ -+ struct e1000_csb *csb; -+ QEMUBH *tx_bh; -+ uint32_t tx_count; /* written in last round */ -+ QEMUBH *rx_bh; -+#endif /* PARAVIRT */ - } E1000State; - - #define defreg(x) x = (E1000_##x>>2) -@@ -146,8 +235,50 @@ enum { - defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), - defreg(RA), defreg(MTA), defreg(CRCERRS),defreg(VFTA), - defreg(VET), -+ defreg(RDTR), defreg(RADV), defreg(TADV), defreg(ITR), -+#ifdef PARAVIRT -+ defreg(CSBAL), defreg(CSBAH), -+#endif /* PARAVIRT */ - }; - -+#ifdef MAP_RING -+/* -+ * try to extract an mbuf region -+ */ -+static const uint8_t *map_mbufs(E1000State *s, hwaddr addr) -+{ -+ struct guest_memreg_map *mb = &s->mbufs; -+ uint64_t a = addr; -+ DMAContext *dma; -+ -+ for (;;) { -+ if (mb->valid && a >= mb->lo && a < mb->hi) { -+ return (const uint8_t *)(a + mb->ofs); -+ } -+ dma = pci_dma_context(&s->dev); -+ mb->valid = 1; -+ -+ D("mapping %p is unset", (void *)addr); -+ if (dma_has_iommu(dma)) { -+ D("iommu range, cannot set"); -+ break; -+ } -+ if (!address_space_mappable(dma->as, addr, -+ &mb->lo, &mb->hi, &mb->ofs)) { -+ D("not mappable, cannot set"); -+ break; -+ } -+ D("segment [%p .. %p] delta %p", -+ (void *)mb->lo, (void *)mb->hi, (void *)mb->ofs); -+ -+ D("mapping txring correct %p computed %p", -+ s->txring, (void *)(s->txring_phi + mb->ofs)); -+ } -+ mb->hi = mb->lo = 0; /* empty mapping */ -+ return NULL; -+} -+#endif /* MAP_RING */ -+ - static void - e1000_link_down(E1000State *s) - { -@@ -378,12 +509,12 @@ set_eecd(E1000State *s, int index, uint32_t val) - s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS | - E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ); - if (!(E1000_EECD_CS & val)) // CS inactive; nothing to do -- return; -+ return; - if (E1000_EECD_CS & (val ^ oldval)) { // CS rise edge; reset state -- s->eecd_state.val_in = 0; -- s->eecd_state.bitnum_in = 0; -- s->eecd_state.bitnum_out = 0; -- s->eecd_state.reading = 0; -+ s->eecd_state.val_in = 0; -+ s->eecd_state.bitnum_in = 0; -+ s->eecd_state.bitnum_out = 0; -+ s->eecd_state.reading = 0; - } - if (!(E1000_EECD_SK & (val ^ oldval))) // no clock edge - return; -@@ -543,7 +674,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) - uint32_t txd_lower = le32_to_cpu(dp->lower.data); - uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D); - unsigned int split_size = txd_lower & 0xffff, bytes, sz, op; -- unsigned int msh = 0xfffff, hdr = 0; -+ unsigned int hdr = 0; - uint64_t addr; - struct e1000_context_desc *xp = (struct e1000_context_desc *)dp; - struct e1000_tx *tp = &s->tx; -@@ -575,7 +706,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) - } - tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; - } else { -- // legacy descriptor -+ /* legacy descriptor, max len 16288 bytes */ - tp->cptse = 0; - } - -@@ -587,11 +718,30 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) - cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2), - le16_to_cpu(dp->upper.fields.special)); - } -- -+ - addr = le64_to_cpu(dp->buffer_addr); -+ -+#ifdef MAP_RING -+ if (!tp->tse && !tp->cptse && tp->size == 0 && -+ !tp->vlan_needed && !tp->sum_needed && -+ (txd_lower & E1000_TXD_CMD_EOP)) { -+ const uint8_t *x = map_mbufs(s, addr); -+ if (x) { -+ /* XXX optimization for netmap */ -+ e1000_send_packet(s, x, split_size); -+ tp->tso_frames = 0; -+ tp->sum_needed = 0; -+ tp->vlan_needed = 0; -+ tp->size = 0; -+ tp->cptse = 0; -+ return ; -+ } -+ } -+#endif /* MAP_RING */ -+ - if (tp->tse && tp->cptse) { - hdr = tp->hdr_len; -- msh = hdr + tp->mss; -+ unsigned int msh = hdr + tp->mss; - do { - bytes = split_size; - if (tp->size + bytes > msh) -@@ -639,12 +789,16 @@ txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp) - txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) & - ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU); - dp->upper.data = cpu_to_le32(txd_upper); -+#ifdef MAP_RING -+ s->txring[s->mac_reg[TDH]].upper = dp->upper; -+#else /* !MAP_RING */ - pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp), - &dp->upper, sizeof(dp->upper)); -+#endif /* !MAP_RING */ - return E1000_ICR_TXDW; - } - --static uint64_t tx_desc_base(E1000State *s) -+static inline uint64_t tx_desc_base(E1000State *s) - { - uint64_t bah = s->mac_reg[TDBAH]; - uint64_t bal = s->mac_reg[TDBAL] & ~0xf; -@@ -652,6 +806,73 @@ static uint64_t tx_desc_base(E1000State *s) - return (bah << 32) + bal; - } - -+/* helper function, 0 means the value is not set */ -+static inline void -+mit_update_delay(uint32_t *curr, uint32_t value) -+{ -+ if (value && (*curr == 0 || value < *curr)) { -+ *curr = value; -+ } -+} -+ -+/* -+ * If necessary, rearm the timer and post an interrupt. -+ * Called at the end of tx/rx routines (mit_timer_on == 0), -+ * and when the timer fires (mit_timer_on == 1). -+ * We provide a partial implementation of interrupt mitigation, -+ * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for -+ * RADV and TADV, 256ns units for ITR). RDTR is only used to enable RADV; -+ * relative timers based on TIDV and RDTR are not implemented. -+ */ -+static void -+mit_rearm_and_int(void *opaque) -+{ -+ E1000State *s = opaque; -+ uint32_t mit_delay = 0; -+ -+ /* -+ * Clear the flag. It is only set when the callback fires, -+ * and we need to clear it anyways. -+ */ -+ s->mit_timer_on = 0; -+ if (s->mit_cause == 0) { /* no events pending, we are done */ -+ return; -+ } -+ /* -+ * Compute the next mitigation delay according to pending interrupts -+ * and the current values of RADV (provided RDTR!=0), TADV and ITR. -+ * Then rearm the timer. -+ */ -+ if (s->mit_cause & (E1000_ICR_TXQE | E1000_ICR_TXDW)) { -+ mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4); -+ } -+ if (s->mac_reg[RDTR] && (s->mit_cause & E1000_ICS_RXT0)) { -+ mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4); -+ } -+ mit_update_delay(&mit_delay, s->mac_reg[ITR]); -+ -+ if (mit_delay) { -+ s->mit_timer_on = 1; -+ qemu_mod_timer(s->mit_timer, -+ qemu_get_clock_ns(vm_clock) + mit_delay * 256); -+ } -+ -+ set_ics(s, 0, s->mit_cause); -+ s->mit_cause = 0; -+} -+ -+static void -+mit_set_ics(E1000State *s, uint32_t cause) -+{ -+ if (s->mit_on == 0) { -+ set_ics(s, 0, cause); -+ return; -+ } -+ s->mit_cause |= cause; -+ if (!s->mit_timer_on) -+ mit_rearm_and_int(s); -+} -+ - static void - start_xmit(E1000State *s) - { -@@ -664,10 +885,56 @@ start_xmit(E1000State *s) - return; - } - -+#ifdef MAP_RING -+ base = tx_desc_base(s); -+ if (base != s->txring_phi) { -+ hwaddr desclen = s->mac_reg[TDLEN]; -+ s->txring_phi = base; -+ s->txring = address_space_map(pci_dma_context(&s->dev)->as, -+ base, &desclen, 0 /* is_write */); -+ D("region size is %ld", desclen); -+ } -+#endif /* MAP_RING */ -+ -+#ifdef PARAVIRT -+ /* hlim prevents staying here for too long */ -+ uint32_t hlim = s->mac_reg[TDLEN] / sizeof(desc) / 2; -+ uint32_t csb_mode = s->csb && s->csb->guest_csb_on; -+ s->tx_count = 0; -+ for (;;) { -+ if (csb_mode) { -+ if (s->mac_reg[TDH] == s->mac_reg[TDT]) { -+ /* we ran dry, exchange some notifications */ -+ smp_mb(); /* read from guest ? */ -+ s->mac_reg[TDT] = s->csb->guest_tdt; -+ tdh_start = s->csb->host_tdh = s->mac_reg[TDH]; -+ } -+ if (s->tx_count > hlim || s->mac_reg[TDH] == s->mac_reg[TDT]) { -+ /* still dry, we are done */ -+ s->csb->host_tdh = s->mac_reg[TDH]; -+ if (s->tx_count > 50) { -+ ND("sent %d in this iteration", s->tx_count); -+ } -+ smp_mb(); -+ if (s->csb->guest_need_txkick) { -+ mit_set_ics(s, cause); -+ } -+ return; -+ } -+ } else if (s->mac_reg[TDH] == s->mac_reg[TDT]) { -+ break; -+ } -+ s->tx_count++; -+#else /* !PARAVIRT */ - while (s->mac_reg[TDH] != s->mac_reg[TDT]) { -+#endif /* PARAVIRT */ -+#ifdef MAP_RING -+ desc = s->txring[s->mac_reg[TDH]]; -+#else /* !MAP_RING */ - base = tx_desc_base(s) + - sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; - pci_dma_read(&s->dev, base, &desc, sizeof(desc)); -+#endif /* MAP_RING */ - - DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH], - (void *)(intptr_t)desc.buffer_addr, desc.lower.data, -@@ -689,7 +956,7 @@ start_xmit(E1000State *s) - break; - } - } -- set_ics(s, 0, cause); -+ mit_set_ics(s, cause); - } - - static int -@@ -764,6 +1031,34 @@ e1000_set_link_status(NetClientState *nc) - static bool e1000_has_rxbufs(E1000State *s, size_t total_size) - { - int bufs; -+#ifdef PARAVIRT -+again: -+ if (s->csb && s->csb->guest_csb_on) { -+ smp_mb(); -+ s->mac_reg[RDT] = s->csb->guest_rdt; -+ } -+ bufs = s->mac_reg[RDT] - s->mac_reg[RDH]; -+ -+ if (bufs < 0) { -+ bufs += s->rxbufs; -+ } -+#if 0 -+ if (s->rxq_full && bufs < s->rxbufs / 2) { -+ return false; /* hysteresis */ -+ } -+#endif -+ s->rxq_full = (total_size > bufs * s->rxbuf_size); -+ if (s->csb && s->csb->guest_csb_on) { -+ if (!s->rxq_full) { -+ s->csb->host_need_rxkick = 0; -+ } else if (!s->csb->host_need_rxkick) { -+ s->csb->host_need_rxkick = 1; -+ goto again; -+ } -+ } -+ return !s->rxq_full; -+#else /* !PARAVIRT */ -+ - /* Fast-path short packets */ - if (total_size <= s->rxbuf_size) { - return s->mac_reg[RDH] != s->mac_reg[RDT]; -@@ -777,6 +1072,7 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size) - return false; - } - return total_size <= bufs * s->rxbuf_size; -+#endif /* !PARAVIRT */ - } - - static int -@@ -788,7 +1084,7 @@ e1000_can_receive(NetClientState *nc) - (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1); - } - --static uint64_t rx_desc_base(E1000State *s) -+static inline uint64_t rx_desc_base(E1000State *s) - { - uint64_t bah = s->mac_reg[RDBAH]; - uint64_t bal = s->mac_reg[RDBAL] & ~0xf; -@@ -846,6 +1142,13 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) - size -= 4; - } - -+#ifdef PARAVIRT -+ if (s->csb && s->csb->guest_csb_on) { -+ smp_mb(); -+ s->mac_reg[RDT] = s->csb->guest_rdt; -+ } -+#endif /* PARAVIRT */ -+ - rdh_start = s->mac_reg[RDH]; - desc_offset = 0; - total_size = size + fcs_len(s); -@@ -853,13 +1156,26 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) - set_ics(s, 0, E1000_ICS_RXO); - return -1; - } -+#ifdef MAP_RING -+ base = rx_desc_base(s); -+ if (base != s->rxring_phi) { -+ hwaddr desclen = s->mac_reg[RDLEN]; -+ s->rxring_phi = base; -+ s->rxring = address_space_map(pci_dma_context(&s->dev)->as, -+ base, &desclen, 0 /* is_write */); -+ } -+#endif /* MAP_RING */ - do { - desc_size = total_size - desc_offset; - if (desc_size > s->rxbuf_size) { - desc_size = s->rxbuf_size; - } - base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH]; -+#ifdef MAP_RING -+ desc = s->rxring[s->mac_reg[RDH]]; -+#else /* !MAP_RING */ - pci_dma_read(&s->dev, base, &desc, sizeof(desc)); -+#endif /* !MAP_RING */ - desc.special = vlan_special; - desc.status |= (vlan_status | E1000_RXD_STAT_DD); - if (desc.buffer_addr) { -@@ -883,7 +1199,12 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) - } else { // as per intel docs; skip descriptors with null buf addr - DBGOUT(RX, "Null RX descriptor!!\n"); - } -+#ifdef MAP_RING -+ s->rxring[s->mac_reg[RDH]] = desc; -+ /* XXX a barrier ? */ -+#else - pci_dma_write(&s->dev, base, &desc, sizeof(desc)); -+#endif /* !MAP_RING */ - - if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) - s->mac_reg[RDH] = 0; -@@ -914,7 +1235,16 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) - s->rxbuf_min_shift) - n |= E1000_ICS_RXDMT0; - -- set_ics(s, 0, n); -+#ifdef PARAVIRT -+ // XXX in csb mode, if the guest does not need kick, we are done. -+ if (s->csb && s->csb->guest_csb_on) { -+ if (!s->csb->guest_need_rxkick) { -+ ND("guest_need_rxkick off, not kicking"); -+ return size; -+ } -+ } -+#endif /* PARAVIRT */ -+ mit_set_ics(s, n); - - return size; - } -@@ -960,6 +1290,49 @@ mac_writereg(E1000State *s, int index, uint32_t val) - s->mac_reg[index] = val; - } - -+ -+#ifdef PARAVIRT -+static void -+set_32bit(E1000State *s, int index, uint32_t val) -+{ -+ s->mac_reg[index] = val; -+ if (index == CSBAH || index == CSBAL) { -+ hwaddr desclen = 4096; -+ hwaddr base = ((uint64_t)s->mac_reg[CSBAH] << 32) | s->mac_reg[CSBAL]; -+ s->csb = address_space_map(pci_dma_context(&s->dev)->as, -+ base, &desclen, 0 /* is_write */); -+ } -+} -+ -+static void -+e1000_tx_bh(void *opaque) -+{ -+ E1000State *s = opaque; -+ struct e1000_csb *csb = s->csb; -+ -+ ND("starting tdt %d sent %d in prev.round ", csb->guest_tdt, s->tx_count); -+ s->mac_reg[TDT] = csb->guest_tdt; -+ start_xmit(s); -+ csb->host_txcycles = (s->tx_count > 0) ? 0 : csb->host_txcycles+1; -+ if (csb->host_txcycles >= csb->host_txcycles_lim) { -+ /* prepare to sleep, with race avoidance */ -+ csb->host_txcycles = 0; -+ csb->host_need_txkick = 1; -+ ND("tx bh going to sleep, set txkick"); -+ smp_mb(); -+ /* XXX read tdt */ -+ s->mac_reg[TDT] = csb->guest_tdt; -+ if (s->mac_reg[TDH] != s->mac_reg[TDT]) { -+ ND("tx bh race avoidance, clear txkick"); -+ csb->host_need_txkick = 0; -+ } -+ } -+ if (csb->host_need_txkick == 0) { -+ qemu_bh_schedule(s->tx_bh); -+ } -+} -+#endif /* PARAVIRT */ -+ - static void - set_rdt(E1000State *s, int index, uint32_t val) - { -@@ -979,6 +1352,12 @@ static void - set_dlen(E1000State *s, int index, uint32_t val) - { - s->mac_reg[index] = val & 0xfff80; -+ if (index == RDLEN) { -+ s->rxbufs = s->mac_reg[index] / sizeof(struct e1000_rx_desc); -+ s->rxq_full = 0; -+ } else { -+ s->txbufs = s->mac_reg[index] / sizeof(struct e1000_tx_desc); -+ } - } - - static void -@@ -986,6 +1365,16 @@ set_tctl(E1000State *s, int index, uint32_t val) - { - s->mac_reg[index] = val; - s->mac_reg[TDT] &= 0xffff; -+#ifdef PARAVIRT -+ if (s->csb && s->csb->guest_csb_on) { -+ ND("kick accepted tdt %d guest-tdt %d", -+ s->mac_reg[TDT], s->csb->guest_tdt); -+ s->csb->host_need_txkick = 0; /* XXX could be done by the guest */ -+ smp_mb(); /* XXX do we care ? */ -+ qemu_bh_schedule(s->tx_bh); -+ return; -+ } -+#endif /* PARAVIRT */ - start_xmit(s); - } - -@@ -1019,6 +1408,10 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = { - getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS), - getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL), - getreg(TDLEN), getreg(RDLEN), -+ getreg(RDTR), getreg(RADV), getreg(TADV), getreg(ITR), -+#ifdef PARAVIRT -+ getreg(CSBAL), getreg(CSBAH), -+#endif /* PARAVIRT */ - - [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4, - [GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4, -@@ -1035,6 +1428,11 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = { - putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC), - putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH), - putreg(RDBAL), putreg(LEDCTL), putreg(VET), -+#ifdef PARAVIRT -+ [CSBAL] = set_32bit, [CSBAH] = set_32bit, -+#endif /* PARAVIRT */ -+ [RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit, -+ [ITR] = set_16bit, - [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl, - [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics, - [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt, -@@ -1332,6 +1730,13 @@ static int pci_e1000_init(PCIDevice *pci_dev) - - d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d); - -+ d->mit_cause = 0; -+ d->mit_timer_on = 0; -+ d->mit_timer = qemu_new_timer_ns(vm_clock, mit_rearm_and_int, d); -+ -+#ifdef PARAVIRT -+ d->tx_bh = qemu_bh_new(e1000_tx_bh, d); -+#endif /* PARAVIRT */ - return 0; - } - -@@ -1343,6 +1748,7 @@ static void qdev_e1000_reset(DeviceState *dev) - - static Property e1000_properties[] = { - DEFINE_NIC_PROPERTIES(E1000State, conf), -+ DEFINE_PROP_UINT32("mit_on", E1000State, mit_on, 5), - DEFINE_PROP_END_OF_LIST(), - }; - -@@ -1356,6 +1762,9 @@ static void e1000_class_init(ObjectClass *klass, void *data) - k->romfile = "pxe-e1000.rom"; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = E1000_DEVID; -+#ifdef PARAVIRT -+ k->subsystem_id = E1000_PARA_SUBDEV; -+#endif /* PARAVIRT */ - k->revision = 0x03; - k->class_id = PCI_CLASS_NETWORK_ETHERNET; - dc->desc = "Intel Gigabit Ethernet"; -diff --git a/hw/virtio-net.c b/hw/virtio-net.c -index 573c669..5389088 100644 ---- a/hw/virtio-net.c -+++ b/hw/virtio-net.c -@@ -21,6 +21,8 @@ - #include "virtio-net.h" - #include "vhost_net.h" - -+#define VIRTIO_Q_SLOTS 256 // 256 -+ - #define VIRTIO_NET_VM_VERSION 11 - - #define MAC_TABLE_ENTRIES 64 -@@ -49,6 +51,7 @@ typedef struct VirtIONet - NICState *nic; - uint32_t tx_timeout; - int32_t tx_burst; -+ int32_t tx_retries; // XXX lr - uint32_t has_vnet_hdr; - size_t host_hdr_len; - size_t guest_hdr_len; -@@ -1062,7 +1065,10 @@ static void virtio_net_tx_bh(void *opaque) - - /* If we flush a full burst of packets, assume there are - * more coming and immediately reschedule */ -- if (ret >= n->tx_burst) { -+ if (ret == 0) -+ n->tx_retries++; -+ // if (ret >= n->tx_burst) { -+ if (n->tx_retries < 20) { - qemu_bh_schedule(q->tx_bh); - q->tx_waiting = 1; - return; -@@ -1076,6 +1082,8 @@ static void virtio_net_tx_bh(void *opaque) - virtio_queue_set_notification(q->tx_vq, 0); - qemu_bh_schedule(q->tx_bh); - q->tx_waiting = 1; -+ } else { -+ n->tx_retries = 0; - } - } - -@@ -1091,16 +1099,16 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl) - } - - for (i = 1; i < max; i++) { -- n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx); -+ n->vqs[i].rx_vq = virtio_add_queue(vdev, VIRTIO_Q_SLOTS, virtio_net_handle_rx); - if (n->vqs[i].tx_timer) { - n->vqs[i].tx_vq = -- virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); -+ virtio_add_queue(vdev, VIRTIO_Q_SLOTS, virtio_net_handle_tx_timer); - n->vqs[i].tx_timer = qemu_new_timer_ns(vm_clock, - virtio_net_tx_timer, - &n->vqs[i]); - } else { - n->vqs[i].tx_vq = -- virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh); -+ virtio_add_queue(vdev, VIRTIO_Q_SLOTS, virtio_net_handle_tx_bh); - n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]); - } - -@@ -1326,7 +1334,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, - n->vdev.set_status = virtio_net_set_status; - n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask; - n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending; -- n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); -+ n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, VIRTIO_Q_SLOTS, virtio_net_handle_rx); - n->max_queues = conf->queues; - n->curr_queues = 1; - n->vqs[0].n = n; -@@ -1340,12 +1348,12 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, - } - - if (net->tx && !strcmp(net->tx, "timer")) { -- n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256, -+ n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, VIRTIO_Q_SLOTS, - virtio_net_handle_tx_timer); - n->vqs[0].tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer, - &n->vqs[0]); - } else { -- n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256, -+ n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, VIRTIO_Q_SLOTS, - virtio_net_handle_tx_bh); - n->vqs[0].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[0]); - } -diff --git a/include/exec/memory.h b/include/exec/memory.h -index 2322732..c8f68de 100644 ---- a/include/exec/memory.h -+++ b/include/exec/memory.h -@@ -833,6 +833,23 @@ void address_space_init(AddressSpace *as, MemoryRegion *root); - void address_space_destroy(AddressSpace *as); - - /** -+ * address_space_mappable: return region containing a guest address. -+ * -+ * If the guest physical address is mappable in host virtual memory, -+ * the function returns the containing region for which the -+ * mapping is valid, and the offset to be added to the gpa -+ * to generate a host virtual address. -+ * -+ * @as: #AddressSpace to be accessed -+ * @addr: address within that address space -+ * @lo: pointer to the initial address in the range -+ * @hi: pointer after the final address in the range -+ * @ofs: pointer to the delta between the two addresses -+ */ -+int address_space_mappable(AddressSpace *as, hwaddr addr, uint64_t *lo, -+ uint64_t *hi, uint64_t *ofs); -+ -+/** - * address_space_rw: read from or write to an address space. - * - * @as: #AddressSpace to be accessed -diff --git a/include/net/net.h b/include/net/net.h -index 43a045e..20d3f22 100644 ---- a/include/net/net.h -+++ b/include/net/net.h -@@ -11,6 +11,33 @@ - - #define MAX_QUEUE_NUM 1024 - -+#ifndef ND -+#define ND(fd, ...) /* debugging */ -+#define D(format, ...) \ -+ do { \ -+ struct timeval __xxts; \ -+ gettimeofday(&__xxts, NULL); \ -+ printf("%03d.%06d %s [%d] " format "\n", \ -+ (int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \ -+ __func__, __LINE__, ##__VA_ARGS__); \ -+ } while (0) -+ -+/* rate limited, lps indicates how many per second */ -+#define RD(lps, format, ...) \ -+ do { \ -+ static int t0, __cnt; \ -+ struct timeval __xxts; \ -+ gettimeofday(&__xxts, NULL); \ -+ if (t0 != __xxts.tv_sec) { \ -+ t0 = __xxts.tv_sec; \ -+ __cnt = 0; \ -+ } \ -+ if (__cnt++ < lps) { \ -+ D(format, ##__VA_ARGS__); \ -+ } \ -+ } while (0) -+#endif -+ - struct MACAddr { - uint8_t a[6]; - }; -diff --git a/net/Makefile.objs b/net/Makefile.objs -index a08cd14..8cb9f2f 100644 ---- a/net/Makefile.objs -+++ b/net/Makefile.objs -@@ -10,3 +10,4 @@ common-obj-$(CONFIG_AIX) += tap-aix.o - common-obj-$(CONFIG_HAIKU) += tap-haiku.o - common-obj-$(CONFIG_SLIRP) += slirp.o - common-obj-$(CONFIG_VDE) += vde.o -+common-obj-$(CONFIG_NETMAP) += netmap.o -diff --git a/net/clients.h b/net/clients.h -index 7793294..952d076 100644 ---- a/net/clients.h -+++ b/net/clients.h -@@ -52,4 +52,8 @@ int net_init_vde(const NetClientOptions *opts, const char *name, - NetClientState *peer); - #endif - -+#ifdef CONFIG_NETMAP -+int net_init_netmap(const NetClientOptions *opts, const char *name, -+ NetClientState *peer); -+#endif - #endif /* QEMU_NET_CLIENTS_H */ -diff --git a/net/hub.c b/net/hub.c -index a24c9d1..df32074 100644 ---- a/net/hub.c -+++ b/net/hub.c -@@ -338,3 +338,17 @@ void net_hub_check_clients(void) - } - } - } -+ -+bool net_hub_flush(NetClientState *nc) -+{ -+ NetHubPort *port; -+ NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc); -+ int ret = 0; -+ -+ QLIST_FOREACH(port, &source_port->hub->ports, next) { -+ if (port != source_port) { -+ ret += qemu_net_queue_flush(port->nc.send_queue); -+ } -+ } -+ return ret ? true : false; -+} -diff --git a/net/hub.h b/net/hub.h -index 583ada8..a625eff 100644 ---- a/net/hub.h -+++ b/net/hub.h -@@ -21,5 +21,6 @@ NetClientState *net_hub_add_port(int hub_id, const char *name); - NetClientState *net_hub_find_client_by_name(int hub_id, const char *name); - void net_hub_info(Monitor *mon); - void net_hub_check_clients(void); -+bool net_hub_flush(NetClientState *nc); - - #endif /* NET_HUB_H */ -diff --git a/net/net.c b/net/net.c -index be03a8d..3dceb29 100644 ---- a/net/net.c -+++ b/net/net.c -@@ -441,6 +441,12 @@ void qemu_flush_queued_packets(NetClientState *nc) - { - nc->receive_disabled = 0; - -+ if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { -+ if (net_hub_flush(nc->peer)) { -+ qemu_notify_event(); -+ } -+ return; -+ } - if (qemu_net_queue_flush(nc->send_queue)) { - /* We emptied the queue successfully, signal to the IO thread to repoll - * the file descriptor (for tap, for example). -@@ -480,7 +486,8 @@ ssize_t qemu_send_packet_async(NetClientState *sender, - - void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) - { -- qemu_send_packet_async(nc, buf, size, NULL); -+ qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_NONE, -+ buf, size, NULL); - } - - ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) -@@ -723,6 +730,9 @@ static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])( - [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge, - #endif - [NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport, -+#ifdef CONFIG_NETMAP -+ [NET_CLIENT_OPTIONS_KIND_NETMAP] = net_init_netmap, -+#endif - }; - - -diff --git a/net/netmap.c b/net/netmap.c -new file mode 100644 -index 0000000..794a7f4 ---- /dev/null -+++ b/net/netmap.c -@@ -0,0 +1,364 @@ -+/* -+ * netmap access for qemu -+ * -+ * Copyright (c) 2012-2013 Luigi Rizzo -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "config-host.h" -+ -+/* note paths are different for -head and 1.3 */ -+#include "net/net.h" -+#include "clients.h" -+#include "sysemu/sysemu.h" -+#include "qemu-common.h" -+#include "qemu/error-report.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef ND -+#define ND(fd, ...) /* debugging */ -+#define D(format, ...) \ -+ do { \ -+ struct timeval __xxts; \ -+ gettimeofday(&__xxts, NULL); \ -+ printf("%03d.%06d %s [%d] " format "\n", \ -+ (int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \ -+ __func__, __LINE__, ##__VA_ARGS__); \ -+ } while (0) -+ -+/* rate limited, lps indicates how many per second */ -+#define RD(lps, format, ...) \ -+ do { \ -+ static int t0, __cnt; \ -+ struct timeval __xxts; \ -+ gettimeofday(&__xxts, NULL); \ -+ if (t0 != __xxts.tv_sec) { \ -+ t0 = __xxts.tv_sec; \ -+ __cnt = 0; \ -+ } \ -+ if (__cnt++ < lps) { \ -+ D(format, ##__VA_ARGS__); \ -+ } \ -+ } while (0) -+#endif -+ -+ -+/* -+ * private netmap device info -+ */ -+struct netmap_state { -+ int fd; -+ int memsize; -+ void *mem; -+ struct netmap_if *nifp; -+ struct netmap_ring *rx; -+ struct netmap_ring *tx; -+ char fdname[128]; /* normally /dev/netmap */ -+ char ifname[128]; /* maybe the nmreq here ? */ -+}; -+ -+struct nm_state { -+ NetClientState nc; -+ struct netmap_state me; -+ unsigned int read_poll; -+ unsigned int write_poll; -+}; -+ -+#ifndef __FreeBSD__ -+#define pkt_copy bcopy -+#else -+/* a fast copy routine only for multiples of 64 bytes, non overlapped. */ -+static inline void -+pkt_copy(const void *_src, void *_dst, int l) -+{ -+ const uint64_t *src = _src; -+ uint64_t *dst = _dst; -+#define likely(x) __builtin_expect(!!(x), 1) -+#define unlikely(x) __builtin_expect(!!(x), 0) -+ if (unlikely(l >= 1024)) { -+ bcopy(src, dst, l); -+ return; -+ } -+ for (; l > 0; l -= 64) { -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ } -+} -+#endif /* __FreeBSD__ */ -+ -+ -+/* -+ * open a netmap device. We assume there is only one queue -+ * (which is the case for the VALE bridge). -+ */ -+static int netmap_open(struct netmap_state *me) -+{ -+ int fd, err; -+ size_t l; -+ struct nmreq req; -+ -+ me->fd = fd = open(me->fdname, O_RDWR); -+ if (fd < 0) { -+ error_report("Unable to open netmap device '%s'", me->fdname); -+ return -1; -+ } -+ bzero(&req, sizeof(req)); -+ pstrcpy(req.nr_name, sizeof(req.nr_name), me->ifname); -+ req.nr_ringid = 0; -+ req.nr_version = NETMAP_API; -+ err = ioctl(fd, NIOCGINFO, &req); -+ if (err) { -+ error_report("cannot get info on %s", me->ifname); -+ goto error; -+ } -+ l = me->memsize = req.nr_memsize; -+ err = ioctl(fd, NIOCREGIF, &req); -+ if (err) { -+ error_report("Unable to register %s", me->ifname); -+ goto error; -+ } -+ -+ me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); -+ if (me->mem == MAP_FAILED) { -+ error_report("Unable to mmap"); -+ me->mem = NULL; -+ goto error; -+ } -+ -+ me->nifp = NETMAP_IF(me->mem, req.nr_offset); -+ me->tx = NETMAP_TXRING(me->nifp, 0); -+ me->rx = NETMAP_RXRING(me->nifp, 0); -+ return 0; -+ -+error: -+ close(me->fd); -+ return -1; -+} -+ -+/* XXX do we need the can-send routine ? */ -+static int netmap_can_send(void *opaque) -+{ -+ struct nm_state *s = opaque; -+ -+ return qemu_can_send_packet(&s->nc); -+} -+ -+static void netmap_send(void *opaque); -+static void netmap_writable(void *opaque); -+ -+/* -+ * set the handlers for the device -+ */ -+static void netmap_update_fd_handler(struct nm_state *s) -+{ -+ qemu_set_fd_handler2(s->me.fd, -+ s->read_poll ? netmap_can_send : NULL, -+ s->read_poll ? netmap_send : NULL, -+ s->write_poll ? netmap_writable : NULL, -+ s); -+} -+ -+/* update the read handler */ -+static void netmap_read_poll(struct nm_state *s, bool enable) -+{ -+ if (s->read_poll != enable) { /* do nothing if not changed */ -+ s->read_poll = enable; -+ netmap_update_fd_handler(s); -+ } -+} -+ -+/* update the write handler */ -+static void netmap_write_poll(struct nm_state *s, bool enable) -+{ -+ if (s->write_poll != enable) { -+ s->write_poll = enable; -+ netmap_update_fd_handler(s); -+ } -+} -+ -+static void netmap_poll(NetClientState *nc, bool enable) -+{ -+ struct nm_state *s = DO_UPCAST(struct nm_state, nc, nc); -+ -+ if (s->read_poll != enable || s->write_poll != enable) { -+ s->read_poll = enable; -+ s->read_poll = enable; -+ netmap_update_fd_handler(s); -+ } -+} -+ -+/* -+ * the fd_write() callback, invoked if the fd is marked as -+ * writable after a poll. Reset the handler and flush any -+ * buffered packets. -+ */ -+static void netmap_writable(void *opaque) -+{ -+ struct nm_state *s = opaque; -+ -+ netmap_write_poll(s, false); -+ qemu_flush_queued_packets(&s->nc); -+} -+ -+/* -+ * new data guest --> backend -+ */ -+static ssize_t netmap_receive_raw(NetClientState *nc, -+ const uint8_t *buf, size_t size) -+{ -+ struct nm_state *s = DO_UPCAST(struct nm_state, nc, nc); -+ struct netmap_ring *ring = s->me.tx; -+ -+ if (size > ring->nr_buf_size) { -+ RD(5, "drop packet of size %d > %d", (int)size, ring->nr_buf_size); -+ return size; -+ } -+ -+ if (ring) { -+ /* request an early notification to avoid running dry */ -+ if (ring->avail < ring->num_slots / 2 && s->write_poll == false) { -+ netmap_write_poll(s, true); -+ } -+ if (ring->avail == 0) { /* cannot write */ -+ return 0; -+ } -+ uint32_t i = ring->cur; -+ uint32_t idx = ring->slot[i].buf_idx; -+ uint8_t *dst = (uint8_t *)NETMAP_BUF(ring, idx); -+ -+ ring->slot[i].len = size; -+ pkt_copy(buf, dst, size); -+ ring->cur = NETMAP_RING_NEXT(ring, i); -+ ring->avail--; -+ } -+ return size; -+} -+ -+/* complete a previous send (backend --> guest), enable the fd_read callback */ -+static void netmap_send_completed(NetClientState *nc, ssize_t len) -+{ -+ struct nm_state *s = DO_UPCAST(struct nm_state, nc, nc); -+ -+ netmap_read_poll(s, true); -+} -+ -+/* -+ * netmap_send: backend -> guest -+ * there is traffic available from the network, try to send it up. -+ */ -+static void netmap_send(void *opaque) -+{ -+ struct nm_state *s = opaque; -+ struct netmap_ring *ring = s->me.rx; -+ -+ /* only check ring->avail, let the packet be queued -+ * with qemu_send_packet_async() if needed -+ * XXX until we fix the propagation on the bridge we need to stop early -+ */ -+ while (ring->avail > 0 && qemu_can_send_packet(&s->nc)) { -+ uint32_t i = ring->cur; -+ uint32_t idx = ring->slot[i].buf_idx; -+ uint8_t *src = (u_char *)NETMAP_BUF(ring, idx); -+ int size = ring->slot[i].len; -+ -+ ring->cur = NETMAP_RING_NEXT(ring, i); -+ ring->avail--; -+ size = qemu_send_packet_async(&s->nc, src, size, netmap_send_completed); -+ if (size == 0) { -+ /* the guest does not receive anymore. Packet is queued, stop -+ * reading from the backend until netmap_send_completed() -+ */ -+ netmap_read_poll(s, false); -+ return; -+ } -+ } -+ netmap_read_poll(s, true); /* probably useless. */ -+} -+ -+ -+/* flush and close */ -+static void netmap_cleanup(NetClientState *nc) -+{ -+ struct nm_state *s = DO_UPCAST(struct nm_state, nc, nc); -+ -+ qemu_purge_queued_packets(nc); -+ -+ netmap_poll(nc, false); -+ munmap(s->me.mem, s->me.memsize); -+ close(s->me.fd); -+ -+ s->me.fd = -1; -+} -+ -+ -+ -+/* fd support */ -+ -+static NetClientInfo net_netmap_info = { -+ .type = NET_CLIENT_OPTIONS_KIND_NETMAP, -+ .size = sizeof(struct nm_state), -+ .receive = netmap_receive_raw, -+#if 0 /* not implemented */ -+ .receive_raw = netmap_receive_raw, -+ .receive_iov = netmap_receive_iov, -+#endif -+ .poll = netmap_poll, -+ .cleanup = netmap_cleanup, -+}; -+ -+/* the external calls */ -+ -+/* -+ * ... -net netmap,ifname="..." -+ */ -+int net_init_netmap(const NetClientOptions *opts, -+ const char *name, NetClientState *peer) -+{ -+ const NetdevNetmapOptions *netmap_opts = opts->netmap; -+ NetClientState *nc; -+ struct netmap_state me; -+ struct nm_state *s; -+ -+ pstrcpy(me.fdname, sizeof(me.fdname), name ? name : "/dev/netmap"); -+ /* set default name for the port if not supplied */ -+ pstrcpy(me.ifname, sizeof(me.ifname), -+ netmap_opts->has_ifname ? netmap_opts->ifname : "vale0"); -+ if (netmap_open(&me)) { -+ return -1; -+ } -+ /* create the object -- XXX use name or ifname ? */ -+ nc = qemu_new_net_client(&net_netmap_info, peer, "netmap", name); -+ s = DO_UPCAST(struct nm_state, nc, nc); -+ s->me = me; -+ netmap_read_poll(s, true); /* initially only poll for reads. */ -+ -+ return 0; -+} -diff --git a/net/queue.c b/net/queue.c -index 6eaf5b6..859d02a 100644 ---- a/net/queue.c -+++ b/net/queue.c -@@ -50,6 +50,8 @@ struct NetPacket { - - struct NetQueue { - void *opaque; -+ uint32_t nq_maxlen; -+ uint32_t nq_count; - - QTAILQ_HEAD(packets, NetPacket) packets; - -@@ -63,6 +65,8 @@ NetQueue *qemu_new_net_queue(void *opaque) - queue = g_malloc0(sizeof(NetQueue)); - - queue->opaque = opaque; -+ queue->nq_maxlen = 10000; -+ queue->nq_count = 0; - - QTAILQ_INIT(&queue->packets); - -@@ -92,6 +96,9 @@ static void qemu_net_queue_append(NetQueue *queue, - { - NetPacket *packet; - -+ if (queue->nq_count >= queue->nq_maxlen && !sent_cb) { -+ return; /* drop if queue full and no callback */ -+ } - packet = g_malloc(sizeof(NetPacket) + size); - packet->sender = sender; - packet->flags = flags; -@@ -99,6 +106,7 @@ static void qemu_net_queue_append(NetQueue *queue, - packet->sent_cb = sent_cb; - memcpy(packet->data, buf, size); - -+ queue->nq_count++; - QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); - } - -@@ -113,6 +121,9 @@ static void qemu_net_queue_append_iov(NetQueue *queue, - size_t max_len = 0; - int i; - -+ if (queue->nq_count >= queue->nq_maxlen && !sent_cb) { -+ return; /* drop if queue full and no callback */ -+ } - for (i = 0; i < iovcnt; i++) { - max_len += iov[i].iov_len; - } -@@ -130,6 +141,7 @@ static void qemu_net_queue_append_iov(NetQueue *queue, - packet->size += len; - } - -+ queue->nq_count++; - QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); - } - -@@ -220,6 +232,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) - QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { - if (packet->sender == from) { - QTAILQ_REMOVE(&queue->packets, packet, entry); -+ queue->nq_count--; - g_free(packet); - } - } -@@ -233,6 +246,7 @@ bool qemu_net_queue_flush(NetQueue *queue) - - packet = QTAILQ_FIRST(&queue->packets); - QTAILQ_REMOVE(&queue->packets, packet, entry); -+ queue->nq_count--; - - ret = qemu_net_queue_deliver(queue, - packet->sender, -@@ -240,6 +254,7 @@ bool qemu_net_queue_flush(NetQueue *queue) - packet->data, - packet->size); - if (ret == 0) { -+ queue->nq_count++; - QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); - return false; - } -diff --git a/qapi-schema.json b/qapi-schema.json -index cd7ea25..b6316e1 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -2641,6 +2641,11 @@ - 'data': { - 'hubid': 'int32' } } - -+{ 'type': 'NetdevNetmapOptions', -+ 'data': { -+ '*ifname': 'str' } } -+ -+ - ## - # @NetClientOptions - # -@@ -2658,7 +2663,8 @@ - 'vde': 'NetdevVdeOptions', - 'dump': 'NetdevDumpOptions', - 'bridge': 'NetdevBridgeOptions', -- 'hubport': 'NetdevHubPortOptions' } } -+ 'hubport': 'NetdevHubPortOptions', -+ 'netmap': 'NetdevNetmapOptions' } } - - ## - # @NetLegacy diff --git a/private/extra/20140109-click.diff b/private/extra/20140109-click.diff deleted file mode 100644 index cac7aecbf..000000000 --- a/private/extra/20140109-click.diff +++ /dev/null @@ -1,309 +0,0 @@ -diff --git a/elements/userlevel/fromdevice.cc b/elements/userlevel/fromdevice.cc -index 3da8dab..26f4299 100644 ---- a/elements/userlevel/fromdevice.cc -+++ b/elements/userlevel/fromdevice.cc -@@ -471,15 +471,16 @@ FromDevice::netmap_dispatch() - struct netmap_ring *ring = NETMAP_RXRING(_netmap.nifp, ri); - //click_chatter("netmap dispatch %s %u %u %u %u", _ifname.c_str(), ri, ring->cur, ring->reserved, ring->avail); - -- while (ring->reserved > 0 && NetmapInfo::refill(ring)) -+ while (ring->head != ring->cur && _netmap.refill(ring)) - /* click_chatter("Refilled") */; - -- if (ring->avail == 0) -+ if (nm_ring_empty(ring)) - continue; - -- int nzcopy = (int) (ring->num_slots / 2) - (int) ring->reserved; -+ // we let at most half a ring of zerocopy packets -+ int nzcopy = (int)(ring->num_slots / 2) - NetmapInfo::reserved(ring); - -- while (n != _burst && ring->avail > 0) { -+ while (n != _burst && !nm_ring_empty(ring)) { - unsigned cur = ring->cur; - unsigned buf_idx = ring->slot[cur].buf_idx; - if (buf_idx < 2) -@@ -488,16 +489,15 @@ FromDevice::netmap_dispatch() - - WritablePacket *p; - if (nzcopy > 0) { -- p = Packet::make(buf, ring->slot[cur].len, NetmapInfo::buffer_destructor); -- ++ring->reserved; -+ p = Packet::make(buf, ring->slot[cur].len, NetmapInfo::buffer_destructor, (void *)&_netmap); - --nzcopy; -- } else { -+ } else { // copy and release the buffer at ring->head - p = Packet::make(_headroom, buf, ring->slot[cur].len, 0); -- unsigned res1idx = NETMAP_RING_FIRST_RESERVED(ring); -- ring->slot[res1idx].buf_idx = buf_idx; -+ ring->slot[ring->head].buf_idx = buf_idx; -+ ring->slot[ring->head].flags = NS_BUF_CHANGED; -+ ring->head = nm_ring_next(ring, ring->head); - } -- ring->cur = NETMAP_RING_NEXT(ring, ring->cur); -- --ring->avail; -+ ring->cur = nm_ring_next(ring, cur); - ++n; - - emit_packet(p, 0, ring->ts); -diff --git a/elements/userlevel/netmapinfo.cc b/elements/userlevel/netmapinfo.cc -index ca591f6..2dacebd 100644 ---- a/elements/userlevel/netmapinfo.cc -+++ b/elements/userlevel/netmapinfo.cc -@@ -28,11 +28,6 @@ - CLICK_DECLS - - static Spinlock netmap_memory_lock; --static void *netmap_memory = MAP_FAILED; --static size_t netmap_memory_size; --static uint32_t netmap_memory_users; -- --unsigned char *NetmapInfo::buffers; - - int - NetmapInfo::ring::open(const String &ifname, -@@ -54,32 +49,23 @@ NetmapInfo::ring::open(const String &ifname, - req.nr_version = NETMAP_API; - #endif - int r; -- if ((r = ioctl(fd, NIOCGINFO, &req))) { -- initial_errh->error("netmap %s: %s", ifname.c_str(), strerror(errno)); -+ if ((r = ioctl(fd, NIOCREGIF, &req))) { -+ errh->error("netmap register %s: %s", ifname.c_str(), strerror(errno)); - error: - close(fd); - return -1; - } -- size_t memsize = req.nr_memsize; -- -- if ((r = ioctl(fd, NIOCREGIF, &req))) { -- errh->error("netmap register %s: %s", ifname.c_str(), strerror(errno)); -- goto error; -- } - - netmap_memory_lock.acquire(); -- if (netmap_memory == MAP_FAILED) { -- netmap_memory_size = memsize; -- netmap_memory = mmap(0, netmap_memory_size, PROT_WRITE | PROT_READ, -+ buffers = 0; -+ memsize = req.nr_memsize; -+ mem = (char *)mmap(0, memsize, PROT_WRITE | PROT_READ, - MAP_SHARED, fd, 0); -- if (netmap_memory == MAP_FAILED) { -- errh->error("netmap allocate %s: %s", ifname.c_str(), strerror(errno)); -- netmap_memory_lock.release(); -- goto error; -- } -+ if (mem == MAP_FAILED) { -+ errh->error("netmap allocate %s: %s", ifname.c_str(), strerror(errno)); -+ netmap_memory_lock.release(); -+ goto error; - } -- mem = (char *) netmap_memory; -- ++netmap_memory_users; - netmap_memory_lock.release(); - - nifp = NETMAP_IF(mem, req.nr_offset); -@@ -110,12 +96,11 @@ void - NetmapInfo::ring::close(int fd) - { - netmap_memory_lock.acquire(); -- if (--netmap_memory_users <= 0 && netmap_memory != MAP_FAILED) { -- munmap(netmap_memory, netmap_memory_size); -- netmap_memory = MAP_FAILED; -+ if (mem != MAP_FAILED) { -+ munmap(mem, memsize); -+ mem = (char *)MAP_FAILED; - } - netmap_memory_lock.release(); -- ioctl(fd, NIOCUNREGIF, (struct nmreq *) 0); - ::close(fd); - } - -diff --git a/elements/userlevel/netmapinfo.hh b/elements/userlevel/netmapinfo.hh -index be8acae..d436f51 100644 ---- a/elements/userlevel/netmapinfo.hh -+++ b/elements/userlevel/netmapinfo.hh -@@ -12,36 +12,47 @@ class NetmapInfo { public: - - struct ring { - char *mem; -+ size_t memsize; - unsigned ring_begin; - unsigned ring_end; - struct netmap_if *nifp; -+ unsigned char *buffers; // XXX released bufs, not thread safe - - int open(const String &ifname, - bool always_error, ErrorHandler *errh); - void initialize_rings_rx(int timestamp); - void initialize_rings_tx(); - void close(int fd); -+ // XXX return a buffer to the ring -+ bool refill(struct netmap_ring *ring) { -+ if (buffers) { -+ unsigned char *buf = buffers; -+ buffers = *reinterpret_cast(buffers); -+ unsigned res1idx = ring->head; -+ ring->slot[res1idx].buf_idx = NETMAP_BUF_IDX(ring, (char *) buf); -+ ring->slot[res1idx].flags |= NS_BUF_CHANGED; -+ ring->head = nm_ring_next(ring, res1idx); -+ return true; -+ } else -+ return false; -+ } - }; - -- static unsigned char *buffers; // XXX not thread safe - static bool is_netmap_buffer(Packet *p) { - return p->buffer_destructor() == buffer_destructor; - } -- static void buffer_destructor(unsigned char *buf, size_t) { -- *reinterpret_cast(buf) = buffers; -- buffers = buf; -+ static void buffer_destructor(unsigned char *buf, size_t, void *arg) { -+ struct ring *ring = reinterpret_cast(arg); -+ *reinterpret_cast(buf) = ring->buffers; -+ ring->buffers = buf; - } -- static bool refill(struct netmap_ring *ring) { -- if (buffers) { -- unsigned char *buf = buffers; -- buffers = *reinterpret_cast(buffers); -- unsigned res1idx = NETMAP_RING_FIRST_RESERVED(ring); -- ring->slot[res1idx].buf_idx = NETMAP_BUF_IDX(ring, (char *) buf); -- ring->slot[res1idx].flags |= NS_BUF_CHANGED; -- --ring->reserved; -- return true; -- } else -- return false; -+ -+ // return number of reserved buffers -+ static int reserved(struct netmap_ring *ring) { -+ int ret = ring->cur - ring->head; -+ if (ret < 0) -+ ret += ring->num_slots; -+ return ret; - } - - }; -diff --git a/elements/userlevel/todevice.cc b/elements/userlevel/todevice.cc -index 31fa72b..cdd7da2 100644 ---- a/elements/userlevel/todevice.cc -+++ b/elements/userlevel/todevice.cc -@@ -285,7 +285,7 @@ ToDevice::netmap_send_packet(Packet *p) - { - for (unsigned ri = _netmap.ring_begin; ri != _netmap.ring_end; ++ri) { - struct netmap_ring *ring = NETMAP_TXRING(_netmap.nifp, ri); -- if (ring->avail == 0) -+ if (nm_ring_empty(ring)) - continue; - unsigned cur = ring->cur; - unsigned buf_idx = ring->slot[cur].buf_idx; -@@ -295,17 +295,17 @@ ToDevice::netmap_send_packet(Packet *p) - uint32_t p_length = p->length(); - if (NetmapInfo::is_netmap_buffer(p) - && !p->shared() && p->buffer() == p->data() -+ && (char *)p->buffer() >= _netmap.mem && (char *)p->buffer() < _netmap.mem + _netmap.memsize - && noutputs() == 0) { - ring->slot[cur].buf_idx = NETMAP_BUF_IDX(ring, (char *) p->buffer()); - ring->slot[cur].flags |= NS_BUF_CHANGED; -- NetmapInfo::buffer_destructor(buf, 0); -+ NetmapInfo::buffer_destructor(buf, 0, (void *)&_netmap); - p->reset_buffer(); - } else - memcpy(buf, p->data(), p_length); - ring->slot[cur].len = p_length; - __asm__ volatile("" : : : "memory"); -- ring->cur = NETMAP_RING_NEXT(ring, cur); -- ring->avail--; -+ ring->head = ring->cur = nm_ring_next(ring, cur); - return 0; - } - errno = ENOBUFS; -diff --git a/include/click/packet.hh b/include/click/packet.hh -index 165a6d3..d03a819 100644 ---- a/include/click/packet.hh -+++ b/include/click/packet.hh -@@ -58,9 +58,10 @@ class Packet { public: - static inline Packet *make(struct mbuf *mbuf) CLICK_WARN_UNUSED_RESULT; - #endif - #if CLICK_USERLEVEL -- typedef void (*buffer_destructor_type)(unsigned char *buf, size_t sz); -+ typedef void (*buffer_destructor_type)(unsigned char *buf, size_t sz, void *arg); - static WritablePacket *make(unsigned char *data, uint32_t length, -- buffer_destructor_type buffer_destructor) CLICK_WARN_UNUSED_RESULT; -+ buffer_destructor_type buffer_destructor, -+ void *arg) CLICK_WARN_UNUSED_RESULT; - #endif - - static void static_cleanup(); -@@ -724,6 +725,7 @@ class Packet { public: - unsigned char *_end; /* one beyond end of allocated buffer */ - # if CLICK_USERLEVEL - buffer_destructor_type _destructor; -+ void *_destructor_arg; - # endif - # if CLICK_BSDMODULE - struct mbuf *_m; -diff --git a/lib/fromfile.cc b/lib/fromfile.cc -index 8827455..4b691d7 100644 ---- a/lib/fromfile.cc -+++ b/lib/fromfile.cc -@@ -118,7 +118,7 @@ FromFile::warning(ErrorHandler *errh, const char *format, ...) const - - #ifdef ALLOW_MMAP - static void --munmap_destructor(unsigned char *data, size_t amount) -+munmap_destructor(unsigned char *data, size_t amount, void *arg) - { - if (munmap((caddr_t)data, amount) < 0) - click_chatter("FromFile: munmap: %s", strerror(errno)); -@@ -156,7 +156,7 @@ FromFile::read_buffer_mmap(ErrorHandler *errh) - if (mmap_data == MAP_FAILED) - return error(errh, "mmap: %s", strerror(errno)); - -- _data_packet = Packet::make((unsigned char *)mmap_data, _len, munmap_destructor); -+ _data_packet = Packet::make((unsigned char *)mmap_data, _len, munmap_destructor, 0); - _buffer = _data_packet->data(); - _file_offset = _mmap_off; - _mmap_off += _len; -diff --git a/lib/packet.cc b/lib/packet.cc -index 65c35c0..3e048d7 100644 ---- a/lib/packet.cc -+++ b/lib/packet.cc -@@ -212,7 +212,7 @@ Packet::~Packet() - _data_packet->kill(); - # if CLICK_USERLEVEL - else if (_head && _destructor) -- _destructor(_head, _end - _head); -+ _destructor(_head, _end - _head, _destructor_arg); - else - delete[] _head; - # elif CLICK_BSDMODULE -@@ -552,7 +552,7 @@ Packet::make(uint32_t headroom, const void *data, - * null. */ - WritablePacket * - Packet::make(unsigned char *data, uint32_t length, -- buffer_destructor_type destructor) -+ buffer_destructor_type destructor, void *arg) - { - # if HAVE_CLICK_PACKET_POOL - WritablePacket *p = WritablePacket::pool_allocate(false); -@@ -564,6 +564,7 @@ Packet::make(unsigned char *data, uint32_t length, - p->_head = p->_data = data; - p->_tail = p->_end = data + length; - p->_destructor = destructor; -+ p->_destructor_arg = arg; - } - return p; - } -@@ -735,7 +736,7 @@ Packet::expensive_uniqueify(int32_t extra_headroom, int32_t extra_tailroom, - _data_packet->kill(); - # if CLICK_USERLEVEL - else if (_destructor) -- _destructor(old_head, old_end - old_head); -+ _destructor(old_head, old_end - old_head, _destructor_arg); - else - delete[] old_head; - _destructor = 0; diff --git a/private/extra/README b/private/extra/README deleted file mode 100644 index 3fb551511..000000000 --- a/private/extra/README +++ /dev/null @@ -1,8 +0,0 @@ -Extra files related to netmap and qemu - - -bsd-lem-mitigation.diff - extensions to the interrupt mitigation for qemu - -qemu-1.2.0-e1000-mitigation.diff - emulation of interrupt mitigation registers diff --git a/private/extra/bro-netmap.diff b/private/extra/bro-netmap.diff deleted file mode 100644 index 207e6412c..000000000 --- a/private/extra/bro-netmap.diff +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/src/PktSrc.cc b/src/PktSrc.cc -index 9d6bce6..e8f59dd 100644 ---- a/src/PktSrc.cc -+++ b/src/PktSrc.cc -@@ -11,6 +11,26 @@ - #include "Net.h" - #include "Sessions.h" - -+#define HAVE_NETMAP -+ -+#ifdef HAVE_NETMAP -+ -+// Compile in netmap support. If the interface name starts with -+// "netmap:" or "vale" we use a netmap fd instead of pcap, and bind -+// one or all rings depending on NETMAP_RING_ID environment variable. -+// -+// For a test run you can use the vale switch, -+// pkt-gen -i vale1:b -f tx -R ..rate_in_pps -+// and launch bro like this -+/* -+ -+BROPATH=`./bro-path-dev` ./src/bro -i vale1:a -b -e 'global l=0; event p(){local s=net_stats(); local c=s$pkts_recvd;print c-l;l=c; schedule 1 sec {p()};} event bro_init(){event p();}' -+ -+ */ -+#define NETMAP_WITH_LIBS -+#include -+ -+#endif /* HAVE_NETMAP */ - - // ### This needs auto-confing. - #ifdef HAVE_PCAP_INT_H -@@ -75,7 +95,14 @@ int PktSrc::ExtractNextPacket() - return 0; - } - -+#ifdef HAVE_NETMAP -+ // in netmap mode call netmap equivalent of pcap_next() -+ if (IS_NETMAP_DESC(pd)) -+ data = last_data = nm_nextpkt((struct nm_desc *)pd, -+ (struct nm_pkthdr *)&hdr); -+ else -+#endif /* HAVE_NETMAP */ - data = last_data = pcap_next(pd, &hdr); - - if ( data && (hdr.len == 0 || hdr.caplen == 0) ) - { -@@ -407,6 +435,11 @@ void PktSrc::Close() - { - if ( pd ) - { -+#ifdef HAVE_NETMAP -+ if (IS_NETMAP_DESC(pd)) -+ nm_close((struct nm_desc *)pd); -+ else -+#endif /* HAVE_NETMAP */ - pcap_close(pd); - pd = 0; - closed = true; -@@ -443,6 +476,14 @@ void PktSrc::Statistics(Stats* s) - else - { - struct pcap_stat pstat; -+#ifdef HAVE_NETMAP -+ if (IS_NETMAP_DESC(pd)) -+ { -+ s->dropped = stats.dropped; -+ s->link = stats.received; -+ } -+ else -+#endif /* HAVE_NETMAP */ - if ( pcap_stats(pd, &pstat) < 0 ) - { - reporter->Error("problem getting packet filter statistics: %s", -@@ -482,6 +523,21 @@ PktInterfaceSrc::PktInterfaceSrc(const char* arg_interface, const char* filter, - - interface = copy_string(arg_interface); - -+#ifdef HAVE_NETMAP -+ pd = (pcap_t *)nm_open(interface, getenv("NETMAP_RING_ID"), 0, 0); -+ // netmap interfaces are named netmap:* or vale* -+ // If pd == 0 && errno == 0 "interface" is not a valid -+ // netmap interface name, so we fall through to pcap -+ if (pd || errno > 0) -+ { -+ if (pd) -+ selectable_fd = NETMAP_FD(pd); -+ else -+ closed = true; -+ return; -+ } -+#endif /* HAVE_NETMAP */ -+ - // Determine network and netmask. - uint32 net; - if ( pcap_lookupnet(interface, &net, &netmask, tmp_errbuf) < 0 ) diff --git a/private/extra/bsd-lem-intr_latency.diff b/private/extra/bsd-lem-intr_latency.diff deleted file mode 100644 index 8440829d8..000000000 --- a/private/extra/bsd-lem-intr_latency.diff +++ /dev/null @@ -1,33 +0,0 @@ -Index: /home/luigi/FreeBSD/head/sys/dev/e1000/if_lem.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/dev/e1000/if_lem.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/dev/e1000/if_lem.c (working copy) -@@ -318,6 +318,10 @@ - - #ifdef DEV_NETMAP /* see ixgbe.c for details */ - #include -+uint64_t tsc_irq_start, tsc_irq_end, tsc_irq_delta; -+SYSCTL_DECL(_dev_netmap); -+SYSCTL_UQUAD(_dev_netmap, OID_AUTO, delta, -+ CTLFLAG_RD, &tsc_irq_delta, 0, ""); - #endif /* DEV_NETMAP */ - - /********************************************************************* -@@ -1335,7 +1339,8 @@ - struct adapter *adapter = context; - struct ifnet *ifp = adapter->ifp; - -- -+ tsc_irq_end = rdtsc(); -+ tsc_irq_delta = tsc_irq_end - tsc_irq_start; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - lem_rxeof(adapter, adapter->rx_process_limit, NULL); - EM_TX_LOCK(adapter); -@@ -1362,6 +1367,7 @@ - u32 reg_icr; - - ifp = adapter->ifp; -+ tsc_irq_start = rdtsc(); - - reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); - diff --git a/private/extra/e1000-paravirt.diff b/private/extra/e1000-paravirt.diff deleted file mode 100644 index 7bdc1aab4..000000000 --- a/private/extra/e1000-paravirt.diff +++ /dev/null @@ -1,396 +0,0 @@ -Index: sys/dev/e1000/if_lem.c -=================================================================== ---- sys/dev/e1000/if_lem.c (revision 257831) -+++ sys/dev/e1000/if_lem.c (working copy) -@@ -32,6 +32,10 @@ - ******************************************************************************/ - /*$FreeBSD$*/ - -+#define BATCH_DISPATCH -+#define NIC_SEND_COMBINING -+#define NIC_PARAVIRT /* enable virtio-like synchronization */ -+ - #include "opt_inet.h" - #include "opt_inet6.h" - -@@ -290,8 +294,8 @@ - static int lem_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); - static int lem_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); - static int lem_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); --static int lem_rxd = EM_DEFAULT_RXD; --static int lem_txd = EM_DEFAULT_TXD; -+static int lem_rxd = 8* EM_DEFAULT_RXD; -+static int lem_txd = 8* EM_DEFAULT_TXD; - static int lem_smart_pwr_down = FALSE; - - /* Controls whether promiscuous also shows bad packets */ -@@ -459,6 +463,20 @@ - "max number of rx packets to process", &adapter->rx_process_limit, - lem_rx_process_limit); - -+#ifdef NIC_SEND_COMBINING -+ /* Sysctls to control mitigation */ -+ lem_add_rx_process_limit(adapter, "sc_enable", -+ "driver TDT mitigation", &adapter->sc_enable, 0); -+#endif /* NIC_SEND_COMBINING */ -+#ifdef BATCH_DISPATCH -+ lem_add_rx_process_limit(adapter, "batch_enable", -+ "driver rx batch", &adapter->batch_enable, 0); -+#endif /* BATCH_DISPATCH */ -+#ifdef NIC_PARAVIRT -+ lem_add_rx_process_limit(adapter, "rx_retries", -+ "driver rx retries", &adapter->rx_retries, 0); -+#endif /* NIC_PARAVIRT */ -+ - /* Sysctl for setting the interface flow control */ - lem_set_flow_cntrl(adapter, "flow_control", - "flow control setting", -@@ -516,6 +534,49 @@ - */ - adapter->hw.mac.report_tx_early = 1; - -+#ifdef NIC_PARAVIRT -+ device_printf(dev, "driver supports paravirt, subdev 0x%x\n", -+ adapter->hw.subsystem_device_id); -+ if (adapter->hw.subsystem_device_id == E1000_PARA_SUBDEV) { -+ uint64_t bus_addr; -+ -+ device_printf(dev, "paravirt support on dev %p\n", adapter); -+ tsize = 4096; // XXX one page for the csb -+ if (lem_dma_malloc(adapter, tsize, &adapter->csb_mem, BUS_DMA_NOWAIT)) { -+ device_printf(dev, "Unable to allocate csb memory\n"); -+ error = ENOMEM; -+ goto err_csb; -+ } -+ /* Setup the Base of the CSB */ -+ adapter->csb = (struct paravirt_csb *)adapter->csb_mem.dma_vaddr; -+ /* force the first kick */ -+ adapter->csb->host_need_txkick = 1; /* txring empty */ -+ adapter->csb->guest_need_rxkick = 1; /* no rx packets */ -+ bus_addr = adapter->csb_mem.dma_paddr; -+ lem_add_rx_process_limit(adapter, "csb_on", -+ "enable paravirt.", &adapter->csb->guest_csb_on, 0); -+ lem_add_rx_process_limit(adapter, "txc_lim", -+ "txc_lim", &adapter->csb->host_txcycles_lim, 1); -+ -+ /* some stats */ -+#define PA_SC(name, var, val) \ -+ lem_add_rx_process_limit(adapter, name, name, var, val) -+ PA_SC("host_need_txkick",&adapter->csb->host_need_txkick, 1); -+ PA_SC("host_rxkick_at",&adapter->csb->host_rxkick_at, ~0); -+ PA_SC("guest_need_txkick",&adapter->csb->guest_need_txkick, 0); -+ PA_SC("guest_need_rxkick",&adapter->csb->guest_need_rxkick, 1); -+ PA_SC("tdt_reg_count",&adapter->tdt_reg_count, 0); -+ PA_SC("tdt_csb_count",&adapter->tdt_csb_count, 0); -+ PA_SC("tdt_int_count",&adapter->tdt_int_count, 0); -+ PA_SC("guest_need_kick_count",&adapter->guest_need_kick_count, 0); -+ /* tell the host where the block is */ -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAH, -+ (u32)(bus_addr >> 32)); -+ E1000_WRITE_REG(&adapter->hw, E1000_CSBAL, -+ (u32)bus_addr); -+ } -+#endif /* NIC_PARAVIRT */ -+ - tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc), - EM_DBA_ALIGN); - -@@ -674,6 +735,11 @@ - err_rx_desc: - lem_dma_free(adapter, &adapter->txdma); - err_tx_desc: -+#ifdef NIC_PARAVIRT -+ lem_dma_free(adapter, &adapter->csb_mem); -+err_csb: -+#endif /* NIC_PARAVIRT */ -+ - err_pci: - if (adapter->ifp != NULL) - if_free(adapter->ifp); -@@ -761,6 +827,12 @@ - adapter->rx_desc_base = NULL; - } - -+#ifdef NIC_PARAVIRT -+ if (adapter->csb) { -+ lem_dma_free(adapter, &adapter->csb_mem); -+ adapter->csb = NULL; -+ } -+#endif /* NIC_PARAVIRT */ - lem_release_hw_control(adapter); - free(adapter->mta, M_DEVBUF); - EM_TX_LOCK_DESTROY(adapter); -@@ -870,6 +942,15 @@ - } - if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) - ifp->if_drv_flags |= IFF_DRV_OACTIVE; -+#ifdef NIC_PARAVIRT -+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE && adapter->csb && -+ adapter->csb->guest_csb_on && !adapter->csb->guest_need_txkick) { -+ adapter->csb->guest_need_txkick = 1; -+ adapter->guest_need_kick_count++; -+ // XXX memory barrier -+ lem_txeof(adapter); // XXX possibly clear IFF_DRV_OACTIVE -+ } -+#endif /* NIC_PARAVIRT */ - - return; - } -@@ -1310,6 +1391,9 @@ - lem_rxeof(adapter, -1, NULL); - - EM_TX_LOCK(adapter); -+#ifdef NIC_PARAVIRT -+ adapter->tdt_int_count++; -+#endif /* NIC_PARAVIRT */ - lem_txeof(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) -@@ -1349,6 +1433,9 @@ - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - bool more = lem_rxeof(adapter, adapter->rx_process_limit, NULL); - EM_TX_LOCK(adapter); -+#ifdef NIC_PARAVIRT -+ adapter->tdt_int_count++; -+#endif /* NIC_PARAVIRT */ - lem_txeof(adapter); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - lem_start_locked(ifp); -@@ -1716,6 +1803,41 @@ - */ - bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -+ -+#ifdef NIC_PARAVIRT -+ if (adapter->csb) { -+ adapter->csb->guest_tdt = i; -+ /* XXX memory barrier ? */ -+ if (adapter->csb->guest_csb_on && -+ !adapter->csb->host_need_txkick) { -+ /* XXX maybe useless -+ * clean the ring. maybe do it before ? -+ * maybe a little bit of histeresys ? -+ */ -+ if (adapter->num_tx_desc_avail <= 64) {// XXX -+ lem_txeof(adapter); -+ } -+ adapter->tdt_csb_count++; -+ return (0); -+ } -+ } -+#endif /* NIC_PARAVIRT */ -+ -+#ifdef NIC_SEND_COMBINING -+ if (adapter->sc_enable) { -+ if (adapter->shadow_tdt & MIT_PENDING_INT) { -+ /* signal intr and data pending */ -+ adapter->shadow_tdt = MIT_PENDING_TDT | (i & 0xffff); -+ return (0); -+ } else { -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } -+ } -+#endif /* NIC_SEND_COMBINING */ -+#ifdef NIC_PARAVIRT -+ adapter->tdt_reg_count++; -+#endif /* NIC_PARAVIRT */ -+ - if (adapter->hw.mac.type == e1000_82547 && - adapter->link_duplex == HALF_DUPLEX) - lem_82547_move_tail(adapter); -@@ -1996,6 +2118,20 @@ - - lem_smartspeed(adapter); - -+#ifdef NIC_PARAVIRT -+ /* recover space if needed */ -+ if (adapter->csb && adapter->csb->guest_csb_on && -+ (adapter->watchdog_check == TRUE) && -+ (ticks - adapter->watchdog_time > EM_WATCHDOG) && -+ (adapter->num_tx_desc_avail != adapter->num_tx_desc) ) { -+ lem_txeof(adapter); -+ /* -+ * lem_txeof() normally (except when space in the queue -+ * runs low XXX) cleans watchdog_check so that -+ * we do not hung. -+ */ -+ } -+#endif /* NIC_PARAVIRT */ - /* - * We check the watchdog: the time since - * the last TX descriptor was cleaned. -@@ -3056,6 +3192,16 @@ - adapter->next_tx_to_clean = first; - adapter->num_tx_desc_avail = num_avail; - -+#ifdef NIC_SEND_COMBINING -+ if ((adapter->shadow_tdt & MIT_PENDING_TDT) == MIT_PENDING_TDT) { -+ /* a tdt write is pending, do it */ -+ E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), -+ 0xffff & adapter->shadow_tdt); -+ adapter->shadow_tdt = MIT_PENDING_INT; -+ } else { -+ adapter->shadow_tdt = 0; // disable -+ } -+#endif /* NIC_SEND_COMBINING */ - /* - * If we have enough room, clear IFF_DRV_OACTIVE to - * tell the stack that it is OK to send packets. -@@ -3063,6 +3209,12 @@ - */ - if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; -+#ifdef NIC_PARAVIRT -+ if (adapter->csb) { // XXX also csb_on ? -+ adapter->csb->guest_need_txkick = 0; -+ // XXX memory barrier -+ } -+#endif /* NIC_PARAVIRT */ - if (adapter->num_tx_desc_avail == adapter->num_tx_desc) { - adapter->watchdog_check = FALSE; - return; -@@ -3369,6 +3521,10 @@ - if (ifp->if_capenable & IFCAP_NETMAP) - rctl -= NA(adapter->ifp)->rx_rings[0].nr_hwavail; - #endif /* DEV_NETMAP */ -+#ifdef NIC_PARAVIRT -+ if (adapter->csb) -+ adapter->csb->guest_rdt = rctl; -+#endif /* NIC_PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), rctl); - - return; -@@ -3446,7 +3602,21 @@ - int i, rx_sent = 0; - struct e1000_rx_desc *current_desc; - -+#ifdef BATCH_DISPATCH -+ struct mbuf *mh = NULL, *mt = NULL; -+#endif /* BATCH_DISPATCH */ -+#ifdef NIC_PARAVIRT -+ int retries = 0; -+ struct paravirt_csb* csb = adapter->csb; -+ int csb_mode = csb && csb->guest_csb_on; -+ -+ ND("clear guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ if (csb_mode && csb->guest_need_rxkick) -+ csb->guest_need_rxkick = 0; -+#endif /* NIC_PARAVIRT */ - EM_RX_LOCK(adapter); -+ -+batch_again: - i = adapter->next_rx_desc_to_check; - current_desc = &adapter->rx_desc_base[i]; - bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, -@@ -3459,19 +3629,45 @@ - } - #endif /* DEV_NETMAP */ - -+#if 0 // XXX optimization ? - if (!((current_desc->status) & E1000_RXD_STAT_DD)) { - if (done != NULL) - *done = rx_sent; - EM_RX_UNLOCK(adapter); - return (FALSE); - } -+#endif /* 0 */ - - while (count != 0 && ifp->if_drv_flags & IFF_DRV_RUNNING) { - struct mbuf *m = NULL; - - status = current_desc->status; -- if ((status & E1000_RXD_STAT_DD) == 0) -+ if ((status & E1000_RXD_STAT_DD) == 0) { -+#ifdef NIC_PARAVIRT -+ if (csb_mode) { -+ /* buffer not ready yet. Retry a few times before giving up */ -+ if (++retries <= adapter->rx_retries) { -+ continue; -+ } -+ if (csb->guest_need_rxkick == 0) { -+ ND("set guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ csb->guest_need_rxkick = 1; -+ // XXX memory barrier, status volatile ? -+ continue; /* double check */ -+ } -+ } -+ /* no buffer ready, give up */ -+#endif /* NIC_PARAVIRT */ - break; -+ } -+#ifdef NIC_PARAVIRT -+ if (csb_mode) { -+ if (csb->guest_need_rxkick) -+ ND("clear again guest_rxkick at %d", adapter->next_rx_desc_to_check); -+ csb->guest_need_rxkick = 0; -+ retries = 0; -+ } -+#endif /* NIC_PARAVIRT */ - - mp = adapter->rx_buffer_area[i].m_head; - /* -@@ -3596,11 +3792,36 @@ - bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - -+#ifdef NIC_PARAVIRT -+ if (csb_mode) { -+ /* the buffer at i has been already replaced by lem_get_buf() -+ * so it is safe to set guest_rdt = i and possibly send a kick. -+ * XXX see if we can optimize it later. -+ */ -+ csb->guest_rdt = i; -+ // XXX memory barrier -+ if (i == csb->host_rxkick_at) -+ E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); -+ } -+#endif /* NIC_PARAVIRT */ - /* Advance our pointers to the next descriptor. */ - if (++i == adapter->num_rx_desc) - i = 0; - /* Call into the stack */ - if (m != NULL) { -+#ifdef BATCH_DISPATCH -+ if (adapter->batch_enable) { -+ if (mh == NULL) -+ mh = mt = m; -+ else -+ mt->m_nextpkt = m; -+ mt = m; -+ m->m_nextpkt = NULL; -+ rx_sent++; -+ current_desc = &adapter->rx_desc_base[i]; -+ continue; -+ } -+#endif /* BATCH_DISPATCH */ - adapter->next_rx_desc_to_check = i; - EM_RX_UNLOCK(adapter); - (*ifp->if_input)(ifp, m); -@@ -3611,10 +3832,27 @@ - current_desc = &adapter->rx_desc_base[i]; - } - adapter->next_rx_desc_to_check = i; -+#ifdef BATCH_DISPATCH -+ if (mh) { -+ EM_RX_UNLOCK(adapter); -+ while ( (mt = mh) != NULL) { -+ mh = mh->m_nextpkt; -+ mt->m_nextpkt = NULL; -+ (*ifp->if_input)(ifp, mt); -+ } -+ EM_RX_LOCK(adapter); -+ i = adapter->next_rx_desc_to_check; /* in case of interrupts */ -+ if (count > 0) -+ goto batch_again; -+ } -+#endif /* BATCH_DISPATCH */ - - /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ - if (--i < 0) - i = adapter->num_rx_desc - 1; -+#ifdef NIC_PARAVIRT -+ if (!csb_mode) /* filter out writes */ -+#endif /* NIC_PARAVIRT */ - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); - if (done != NULL) - *done = rx_sent; diff --git a/private/extra/libpcap-netmap.diff b/private/extra/libpcap-netmap.diff deleted file mode 100644 index cd6c38973..000000000 --- a/private/extra/libpcap-netmap.diff +++ /dev/null @@ -1,389 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 9995458..c670d66 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -83,7 +83,7 @@ YACC = @V_YACC@ - @rm -f $@ - $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c - --PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ -+PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ @NETMAP_SRC@ - FSRC = fad-@V_FINDALLDEVS@.c - SSRC = @SSRC@ - CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c etherent.c \ -@@ -313,6 +313,7 @@ EXTRA_DIST = \ - pcap-namedb.h \ - pcap-netfilter-linux.c \ - pcap-netfilter-linux.h \ -+ pcap-netmap.c \ - pcap-nit.c \ - pcap-null.c \ - pcap-pf.c \ -diff --git a/config.h.in b/config.h.in -index c6bc68e..09c8557 100644 ---- a/config.h.in -+++ b/config.h.in -@@ -268,6 +268,9 @@ - /* target host supports netfilter sniffing */ - #undef PCAP_SUPPORT_NETFILTER - -+/* target host supports netmap */ -+#undef PCAP_SUPPORT_NETMAP -+ - /* target host supports USB sniffing */ - #undef PCAP_SUPPORT_USB - -diff --git a/configure b/configure -index be87668..a8d0cae 100755 ---- a/configure -+++ b/configure -@@ -626,6 +626,8 @@ INSTALL_PROGRAM - DBUS_SRC - PCAP_SUPPORT_DBUS - PKGCONFIG -+NETMAP_SRC -+PCAP_SUPPORT_NETMAP - CAN_SRC - PCAP_SUPPORT_CAN - CANUSB_SRC -@@ -747,6 +749,7 @@ enable_shared - enable_bluetooth - enable_canusb - enable_can -+enable_netmap - enable_dbus - ' - ac_precious_vars='build_alias -@@ -1385,6 +1388,8 @@ Optional Features: - available] - --enable-can enable CAN support [default=yes, if support - available] -+ --enable-netmap enable netmap support [default=yes, if support -+ available] - --enable-dbus enable D-Bus capture support [default=yes, if - support available] - -@@ -8148,6 +8153,39 @@ $as_echo "$as_me: no CAN sniffing support implemented for $host_os" >&6;} - - fi - -+# Check whether --enable-netmap was given. -+if test "${enable_netmap+set}" = set; then : -+ enableval=$enable_netmap; -+else -+ enable_netmap=yes -+fi -+ -+ -+if test "x$enable_netmap" != "xno" ; then -+ case "$host_os" in -+ *) -+ ac_fn_c_check_header_compile "$LINENO" "net/netmap_user.h" "ac_cv_header_net_netmap_user_h" "#include -+ -+" -+if test "x$ac_cv_header_net_netmap_user_h" = xyes; then : -+ -+$as_echo "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h -+ -+ NETMAP_SRC=pcap-netmap.c -+ { $as_echo "$as_me:${as_lineno-$LINENO}: netmap is supported" >&5 -+$as_echo "$as_me: netmap is supported" >&6;} -+else -+ { $as_echo "$as_me:${as_lineno-$LINENO}: netmap is not supported" >&5 -+$as_echo "$as_me: netmap is not supported" >&6;} -+fi -+ -+ -+ ;; -+ esac -+ -+ -+fi -+ - # Check whether --enable-dbus was given. - if test "${enable_dbus+set}" = set; then : - enableval=$enable_dbus; -diff --git a/configure.in b/configure.in -index f0aa2c5..55464ba 100644 ---- a/configure.in -+++ b/configure.in -@@ -1550,6 +1550,28 @@ if test "x$enable_can" != "xno" ; then - AC_SUBST(CAN_SRC) - fi - -+AC_ARG_ENABLE([netmap], -+[AC_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])], -+ [], -+ [enable_netmap=yes]) -+ -+if test "x$enable_netmap" != "xno" ; then -+ dnl check for netmap support -+ case "$host_os" in -+ *) -+ AC_CHECK_HEADER(net/netmap_user.h, -+ [ AC_DEFINE(PCAP_SUPPORT_NETMAP, 1, [target host supports netmap]) -+ NETMAP_SRC=pcap-netmap.c -+ AC_MSG_NOTICE(netmap is supported)], -+ AC_MSG_NOTICE(netmap is not supported), -+ [#include ] -+ ) -+ ;; -+ esac -+ AC_SUBST(PCAP_SUPPORT_NETMAP) -+ AC_SUBST(NETMAP_SRC) -+fi -+ - AC_ARG_ENABLE([dbus], - [AC_HELP_STRING([--enable-dbus],[enable D-Bus capture support @<:@default=yes, if support available@:>@])], - [], -diff --git a/inet.c b/inet.c -index c699658..d132507 100644 ---- a/inet.c -+++ b/inet.c -@@ -883,6 +883,10 @@ pcap_lookupnet(device, netp, maskp, errbuf) - #ifdef PCAP_SUPPORT_USB - || strstr(device, "usbmon") != NULL - #endif -+#ifdef PCAP_SUPPORT_NETMAP -+ || !strncmp(device, "netmap:", 7) -+ || !strncmp(device, "vale", 4) -+#endif - #ifdef HAVE_SNF_API - || strstr(device, "snf") != NULL - #endif -diff --git a/pcap-netmap.c b/pcap-netmap.c -new file mode 100644 -index 0000000..2568c2f ---- /dev/null -+++ b/pcap-netmap.c -@@ -0,0 +1,205 @@ -+/* -+ * Copyright 2014 Universita` di Pisa -+ * -+ * packet filter subroutines for netmap -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define NETMAP_WITH_LIBS -+#include -+ -+#include "pcap-int.h" -+ -+#if defined (linux) -+/* On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh. -+ * remap to IFF_PROMISC on linux -+ */ -+#define IFF_PPROMISC IFF_PROMISC -+#define ifr_flagshigh ifr_flags -+#endif /* linux */ -+ -+struct pcap_netmap { -+ struct nm_desc *d; /* pointer returned by nm_open() */ -+ pcap_handler cb; /* callback and argument */ -+ u_char *cb_arg; -+ int must_clear_promisc; /* flag */ -+ uint64_t rx_pkts; /* count of packets received before the filter */ -+}; -+ -+static int -+pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps) -+{ -+ struct pcap_netmap *pn = p->priv; -+ -+ ps->ps_recv = pn->rx_pkts; -+ ps->ps_drop = 0; -+ ps->ps_ifdrop = 0; -+ return 0; -+} -+ -+static void -+pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf) -+{ -+ pcap_t *p = (pcap_t *)arg; -+ struct pcap_netmap *pn = p->priv; -+ -+ ++pn->rx_pkts; -+ if (bpf_filter(p->fcode.bf_insns, buf, h->len, h->caplen)) -+ pn->cb(pn->cb_arg, h, buf); -+} -+ -+static int -+pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user) -+{ -+ int ret; -+ struct pcap_netmap *pn = p->priv; -+ struct nm_desc *d = pn->d; -+ struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 }; -+ -+ pn->cb = cb; -+ pn->cb_arg = user; -+ -+ for (;;) { -+ if (p->break_loop) { -+ p->break_loop = 0; -+ return PCAP_ERROR_BREAK; -+ } -+ /* nm_dispatch won't run forever */ -+ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p); -+ if (ret != 0) -+ break; -+ poll(&pfd, 1, p->opt.timeout); -+ } -+ return ret; -+} -+ -+/* XXX need to check the NIOCTXSYNC/poll */ -+static int -+pcap_netmap_inject(pcap_t *p, const void *buf, size_t size) -+{ -+ struct nm_desc *d = ((struct pcap_netmap *)p->priv)->d; -+ -+ return nm_inject(d, buf, size); -+} -+ -+static int -+pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags) -+{ -+ struct pcap_netmap *pn = p->priv; -+ struct nm_desc *d = pn->d; -+ struct ifreq ifr; -+ int error, fd = d->fd; -+ -+#ifdef linux -+ fd = socket(AF_INET, SOCK_DGRAM, 0); -+ if (fd < 0) { -+ fprintf(stderr, "Error: cannot get device control socket.\n"); -+ return -1; -+ } -+#endif /* linux */ -+ bzero(&ifr, sizeof(ifr)); -+ strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name)); -+ switch (what) { -+ case SIOCSIFFLAGS: -+ ifr.ifr_flags = *if_flags; -+ ifr.ifr_flagshigh = *if_flags >> 16; -+ break; -+ } -+ error = ioctl(fd, what, &ifr); -+ fprintf(stderr, "%s %s ioctl 0x%lx returns %d\n", __FUNCTION__, -+ d->req.nr_name, what, error); -+ if (error) -+ return -1; -+ switch (what) { -+ case SIOCGIFFLAGS: -+ *if_flags = ifr.ifr_flags | (ifr.ifr_flagshigh << 16); -+ } -+ return 0; -+} -+ -+static void -+pcap_netmap_close(pcap_t *p) -+{ -+ struct pcap_netmap *pn = p->priv; -+ struct nm_desc *d = pn->d; -+ uint32_t if_flags = 0; -+ -+ if (pn->must_clear_promisc) { -+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ -+ if (if_flags & IFF_PPROMISC) { -+ if_flags &= ~IFF_PPROMISC; -+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); -+ } -+ } -+ nm_close(d); -+} -+ -+static int -+pcap_netmap_activate(pcap_t *p) -+{ -+ struct pcap_netmap *pn = p->priv; -+ struct nm_desc *d = nm_open(p->opt.source, NULL, 0, NULL); -+ uint32_t if_flags = 0; -+ -+ if (d == NULL) { -+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, -+ "netmap open: cannot access %s: %s\n", -+ p->opt.source, pcap_strerror(errno)); -+ goto bad; -+ } -+ fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n", -+ __FUNCTION__, p->opt.source, d, d->fd, d->first_rx_ring, d->last_rx_ring); -+ pn->d = d; -+ p->fd = d->fd; -+ if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) { -+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ -+ if (!(if_flags & IFF_PPROMISC)) { -+ pn->must_clear_promisc = 1; -+ if_flags |= IFF_PPROMISC; -+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags); -+ } -+ } -+ p->linktype = DLT_EN10MB; -+ p->selectable_fd = p->fd; -+ p->read_op = pcap_netmap_dispatch; -+ p->inject_op = pcap_netmap_inject, -+ p->setfilter_op = install_bpf_program; -+ p->setdirection_op = NULL; -+ p->set_datalink_op = NULL; -+ p->getnonblock_op = pcap_getnonblock_fd; -+ p->setnonblock_op = pcap_setnonblock_fd; -+ p->stats_op = pcap_netmap_stats; -+ p->cleanup_op = pcap_netmap_close; -+ return (0); -+ -+ bad: -+ pcap_cleanup_live_common(p); -+ return (PCAP_ERROR); -+} -+ -+pcap_t * -+pcap_netmap_create(const char *device, char *ebuf, int *is_ours) -+{ -+ pcap_t *p; -+ -+ *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4)); -+ if (! *is_ours) -+ return NULL; -+ p = pcap_create_common(device, ebuf, sizeof (struct pcap_netmap)); -+ if (p == NULL) -+ return (NULL); -+ p->activate_op = pcap_netmap_activate; -+ return (p); -+} -diff --git a/pcap.c b/pcap.c -index b2b5da6..beda714 100644 ---- a/pcap.c -+++ b/pcap.c -@@ -104,6 +104,10 @@ - #include "pcap-dbus.h" - #endif - -+#ifdef PCAP_SUPPORT_NETMAP -+pcap_t* pcap_netmap_create(const char *device, char *ebuf, int *is_ours); -+#endif -+ - int - pcap_not_initialized(pcap_t *pcap _U_) - { -@@ -307,6 +311,9 @@ struct capture_source_type { - int (*findalldevs_op)(pcap_if_t **, char *); - pcap_t *(*create_op)(const char *, char *, int *); - } capture_source_types[] = { -+#ifdef PCAP_SUPPORT_NETMAP -+ { NULL, pcap_netmap_create }, -+#endif - #ifdef HAVE_DAG_API - { dag_findalldevs, dag_create }, - #endif diff --git a/private/extra/netreceive.c b/private/extra/netreceive.c deleted file mode 100644 index 80be69374..000000000 --- a/private/extra/netreceive.c +++ /dev/null @@ -1,264 +0,0 @@ -/*- - * Copyright (c) 2004 Robert N. M. Watson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include -#include - -#include -#include /* getaddrinfo */ - -#include - -#include -#include -#include -#include /* close */ - -#define MAXSOCK 20 - -#include -#include -#include /* clock_getres() */ - -static int round_to(int n, int l) -{ - return ((n + l - 1)/l)*l; -} - -/* - * Each socket uses multiple threads so the receiver is - * more efficient. A collector thread runs the stats. - */ -struct td_desc { - pthread_t td_id; - uint64_t count; /* rx counter */ - int fd; - char *buf; - int buflen; -}; - -static void -usage(void) -{ - - fprintf(stderr, "netreceive port [nthreads]\n"); - exit(-1); -} - -static __inline void -timespec_add(struct timespec *tsa, struct timespec *tsb) -{ - - tsa->tv_sec += tsb->tv_sec; - tsa->tv_nsec += tsb->tv_nsec; - if (tsa->tv_nsec >= 1000000000) { - tsa->tv_sec++; - tsa->tv_nsec -= 1000000000; - } -} - -static __inline void -timespec_sub(struct timespec *tsa, struct timespec *tsb) -{ - - tsa->tv_sec -= tsb->tv_sec; - tsa->tv_nsec -= tsb->tv_nsec; - if (tsa->tv_nsec < 0) { - tsa->tv_sec--; - tsa->tv_nsec += 1000000000; - } -} - -static void * -rx_body(void *data) -{ - struct td_desc *t = data; - struct pollfd fds; - int y; - - fds.fd = t->fd; - fds.events = POLLIN; - - for (;;) { - if (poll(&fds, 1, -1) < 0) - perror("poll on thread"); - if (!(fds.revents & POLLIN)) - continue; - for (;;) { - y = recv(t->fd, t->buf, t->buflen, MSG_DONTWAIT); - if (y < 0) - break; - t->count++; - } - } - return NULL; -} - -int -make_threads(struct td_desc **tp, int *s, int nsock, int nthreads) -{ - int i, si, nt = nsock * nthreads; - int lb = round_to(nt * sizeof (struct td_desc *), 64); - int td_len = round_to(sizeof(struct td_desc), 64); // cache align - char *m = calloc(1, lb + td_len * nt); - - printf("td len %d -> %d\n", (int)sizeof(struct td_desc) , td_len); - /* pointers plus the structs */ - if (m == NULL) { - perror("no room for pointers!"); - exit(1); - } - tp = (struct td_desc **)m; - m += lb; /* skip the pointers */ - for (si = i = 0; i < nt; i++, m += td_len) { - tp[i] = (struct td_desc *)m; - tp[i]->fd = s[si]; - if (++si == nsock) - si = 0; - if (pthread_create(&tp[i]->td_id, NULL, rx_body, tp[i])) { - perror("unable to create thread"); - exit(1); - } - } -} - -int -main_thread(struct td_desc **tp, int nsock, int nthreads) -{ - uint64_t c0, c1; - struct timespec now, then, delta; - /* now the parent collects and prints results */ - c0 = c1 = 0; - clock_gettime(CLOCK_REALTIME, &then); - fprintf(stderr, "start at %ld.%09ld\n", then.tv_sec, then.tv_nsec); - while (1) { - int i, nt = nsock * nthreads; - int64_t dn; - uint64_t pps; - - if (poll(NULL, 0, 500) < 0) - perror("poll"); - c0 = 0; - for (i = 0; i < nt; i++) { - c0 += tp[i]->count; - } - dn = c0 - c1; - clock_gettime(CLOCK_REALTIME, &now); - delta = now; - timespec_sub(&delta, &then); - then = now; - pps = dn; - pps = (pps * 1000000000) / (delta.tv_sec*1000000000 + delta.tv_nsec + 1); - fprintf(stderr, "%d pkts in %ld.%09ld ns %ld pps\n", - (int)dn, delta.tv_sec, delta.tv_nsec, (long)pps); - c1 = c0; - } -} - -int -main(int argc, char *argv[]) -{ - struct addrinfo hints, *res, *res0; - char *dummy, *packet; - int port; - int error, v, nthreads = 1; - struct td_desc **tp; - const char *cause = NULL; - int s[MAXSOCK]; - int nsock; - - if (argc < 2) - usage(); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; - - port = strtoul(argv[1], &dummy, 10); - if (port < 1 || port > 65535 || *dummy != '\0') - usage(); - if (argc > 2) - nthreads = strtoul(argv[2], &dummy, 10); - if (nthreads < 1 || nthreads > 64) - usage(); - - packet = malloc(65536); - if (packet == NULL) { - perror("malloc"); - return (-1); - } - bzero(packet, 65536); - - error = getaddrinfo(NULL, argv[1], &hints, &res0); - if (error) { - perror(gai_strerror(error)); - return (-1); - /*NOTREACHED*/ - } - - nsock = 0; - for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) { - s[nsock] = socket(res->ai_family, res->ai_socktype, - res->ai_protocol); - if (s[nsock] < 0) { - cause = "socket"; - continue; - } - - v = 128 * 1024; - if (setsockopt(s[nsock], SOL_SOCKET, SO_RCVBUF, &v, sizeof(v)) < 0) { - cause = "SO_RCVBUF"; - close(s[nsock]); - continue; - } - if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) { - cause = "bind"; - close(s[nsock]); - continue; - } - (void) listen(s[nsock], 5); - nsock++; - } - if (nsock == 0) { - perror(cause); - return (-1); - /*NOTREACHED*/ - } - - printf("netreceive %d sockets x %d threads listening on UDP port %d\n", - nsock, nthreads, (u_short)port); - - make_threads(tp, s, nsock, nthreads); - main_thread(tp, nsock, nthreads); - - /*NOTREACHED*/ - freeaddrinfo(res0); -} diff --git a/private/extra/paravirt.h b/private/extra/paravirt.h deleted file mode 100644 index e8c49cb0b..000000000 --- a/private/extra/paravirt.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2013 Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef NET_PARAVIRT_H -#define NET_PARAVIRT_H - -/* - Support for virtio-like communication between host (H) and guest (G) NICs. - - The guest allocates the shared Communication Status Block (csb) and - write its physical address at CSBAL and CSBAH (data is little endian). - csb->csb_on enables the mode. If disabled, the device acts a regular one. - - Notifications for tx and rx are exchanged without vm exits - if possible. In particular (only mentioning csb mode below), - the following actions are performed. In the description below, - "double check" means verifying again the condition that caused - the previous action, and reverting the action if the condition has - changed. The condition typically depends on a variable set by the - other party, and the double check is done to avoid races. E.g. - - // start with A=0 - again: - // do something - if ( cond(C) ) { // C is written by the other side - A = 1; - // barrier - if ( !cond(C) ) { - A = 0; - goto again; - } - } - - TX: start from idle: - H starts with host_need_txkick=1 when the I/O thread bh is idle. Upon new - transmissions, G always updates guest_tdt. If host_need_txkick == 1, - G also writes to the TDT, which acts as a kick to H (so pending - writes are always dispatched to H as soon as possible.) - - TX: active state: - On the kick (TDT write) H sets host_need_txkick == 0 (if not - done already by G), and starts an I/O thread trying to consume - packets from TDH to guest_tdt, periodically refreshing host_tdh - and TDH. When host_tdh == guest_tdt, H sets host_need_txkick=1, - and then does the "double check" for race avoidance. - - TX: G runs out of buffers - XXX there are two mechanisms, one boolean (using guest_need_txkick) - and one with a threshold (using guest_txkick_at). They are mutually - exclusive. - BOOLEAN: when G has no space, it sets guest_need_txkick=1 and does - the double check. If H finds guest_need_txkick== 1 on a write - to TDH, it also generates an interrupt. - THRESHOLD: G sets guest_txkick_at to the TDH value for which it - wants to receive an interrupt. When H detects that TDH moves - across guest_txkick_at, it generates an interrupt. - This second mechanism reduces the number of interrupts and - TDT writes on the transmit side when the host is too slow. - - RX: start from idle - G starts with guest_need_rxkick = 1 when the receive ring is empty. - As packets arrive, H updates host_rdh (and RDH) and also generates an - interrupt when guest_need_rxkick == 1 (so incoming packets are - always reported to G as soon as possible, apart from interrupt - moderation delays). It also tracks guest_rdt for new buffers. - - RX: active state - As the interrupt arrives, G sets guest_need_rxkick = 0 and starts - draining packets from the receive ring, while updating guest_rdt - When G runs out of packets it sets guest_need_rxkick=1 and does the - double check. - - RX: H runs out of buffers - XXX there are two mechanisms, one boolean (using host_need_rxkick) - and one with a threshold (using host_xxkick_at). They are mutually - exclusive. - BOOLEAN: when H has no space, it sets host_need_rxkick=1 and does the - double check. If G finds host_need_rxkick==1 on updating guest_rdt, - it also writes to RDT causing a kick to H. - THRESHOLD: H sets host_rxkick_at to the RDT value for which it wants - to receive a kick. When G detects that guest_rdt moves across - host_rxkick_at, it writes to RDT thus generates a kick. - This second mechanism reduces the number of kicks and - RDT writes on the receive side when the guest is too slow and - would free only a few buffers at a time. - - */ -struct paravirt_csb { - /* XXX revise the layout to minimize cache bounces. - * Usage is described as follows: - * [GH][RW][+-0] guest/host reads/writes frequently/rarely/almost never - */ - /* these are (mostly) written by the guest */ - uint32_t guest_tdt; /* GW+ HR+ pkt to transmit */ - uint32_t guest_need_txkick; /* GW- HR+ G ran out of tx bufs, request kick */ - uint32_t guest_need_rxkick; /* GW- HR+ G ran out of rx pkts, request kick */ - uint32_t guest_csb_on; /* GW- HR+ enable paravirtual mode */ - uint32_t guest_rdt; /* GW+ HR+ rx buffers available */ - uint32_t guest_txkick_at; /* GW- HR+ tx ring pos. where G expects an intr */ - uint32_t guest_use_msix; /* GW0 HR0 guest uses MSI-X interrupts. */ - uint32_t pad[9]; - - /* these are (mostly) written by the host */ - uint32_t host_tdh; /* GR0 HW- shadow register, mostly unused */ - uint32_t host_need_txkick; /* GR+ HW- start the iothread */ - uint32_t host_txcycles_lim; /* GW- HR- how much to spin before sleep. - * set by the guest */ - uint32_t host_txcycles; /* GR0 HW- counter, but no need to be exported */ - uint32_t host_rdh; /* GR0 HW- shadow register, mostly unused */ - uint32_t host_need_rxkick; /* GR+ HW- flush rx queued packets */ - uint32_t host_isr; /* GR* HW* shadow copy of ISR */ - uint32_t host_rxkick_at; /* GR+ HW- rx ring pos where H expects a kick */ - uint32_t vnet_ring_high; /* Vnet ring physical address high. */ - uint32_t vnet_ring_low; /* Vnet ring physical address low. */ -}; - -#define NET_PARAVIRT_CSB_SIZE 4096 -#define NET_PARAVIRT_NONE (~((uint32_t)0)) - -#ifdef QEMU_PCI_H - -/* - * API functions only available within QEMU - */ - -void paravirt_configure_csb(struct paravirt_csb** csb, uint32_t csbbal, - uint32_t csbbah, QEMUBH* tx_bh, AddressSpace *as); - -#endif /* QEMU_PCI_H */ - -#endif /* NET_PARAVIRT_H */ diff --git a/private/extra/python/Makefile b/private/extra/python/Makefile deleted file mode 100644 index 5bd9092f0..000000000 --- a/private/extra/python/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -PYTHON=python2 - - -build: always - $(PYTHON) setup.py build - -install: build - sudo $(PYTHON) setup.py install - -clean: - rm -rf build - -always: diff --git a/private/extra/python/README b/private/extra/python/README deleted file mode 100644 index c7e871b08..000000000 --- a/private/extra/python/README +++ /dev/null @@ -1,100 +0,0 @@ -========================= PYTHON BINDINGS FOR NETMAP ========================== - -The extra/python directory contains a C extension module that makes -it possible to use netmap from the Python (2.7 versions) programming -language. - - -(1) **************************** How to compile it **************************** - - cd extra/python - make - - -(2) ************ How to (compile and) install it in your system *************** - - cd extra/python - make install - - -(3) How to use it with python - - >>> import netmap - >>> # your code here - >>> ... - - -(4) ************************ Python classes for netmap ************************ - - The netmap extension module exports three Python classes that represent - the netmap memory layout: - (4.1) netmap.NetmapInterface - represents a "netmap_if" struct - (4.2) netmap.NetmapRing - represents a "netmap_ring" struct - (4.3) netmap.NetmapSlot - represents a "netmap_slot" struct - - The struct fields are **directly** read/write accessible (e.g. you are - accessing the real netmap memory) through the class members. - - You can issue - - >>> help(netmap.NetmapRing) - - or - - >>> help(r) # "r" is a reference to a netmap.NetmapRing instance - - to see the documentation (members and methods) of the specified class. - - The other two classes available in the netmap extension module - (netmap.Netmap and netmap.NetmapDesc) are intended to create, manage - and contain the netmap memory layout representation. - Each instance of such classes is intended to manage a network - interface. - - (4.5) netmap.Netmap - Apart from containing the netmap memory - layout (once the NIOCREGIF is done), it is basically a - wrapper for a "nmreq" struct, and can therefore be used - to access the whole netmap API. - Its constructor doesn't take any arguments, and allows the - user to use the ioctl netmap interface (NIOCREGIF, - NIOCGINFO, ...). - - Example: - >>> import netmap - >>> n=netmap.Netmap() - >>> n.open() # open the netmap device - >>> n.if_name = 'eth0' - >>> n.register() # registers all the hw rings of "eth0" - >>> # access n.interface, n.transmit_rings, n.receive_rings - >>> n.close() - - See help(netmap.Netmap) for reference. - - (4.6) netmap.NetmapDesc - This class is even simpler than - netmap.Netmap(), in that you don't have to separately - create the object, open the device and register, but you - can do these three operation with the constructor only. - Apart from this, you can use the nm_open() extended - interface names to specify what kind of registration you - desire (in fact the C backend for this class is nm_open()). - - Example: - >>> import netmap - >>> d=netmap.NetmapDesc('netmap:enp1s0f1*') - >>> # access d.interface, d.transmit_rings, d.receive_rings - - - -(5) ****************************** More examples ****************************** - - You can find some examples in extra/python: - - (5.1) pktgen.py - A minimalistic packet generator using the Python netmap - bindings. - - (5.2) pktman.py - A configurable packet generator/receiver. Run - - $ python pktman.py -h - - to see the available options. - diff --git a/private/extra/python/netmap.c b/private/extra/python/netmap.c deleted file mode 100644 index 693bd6f3f..000000000 --- a/private/extra/python/netmap.c +++ /dev/null @@ -1,345 +0,0 @@ -#include - -#include /* IFNAMSIZ */ -#include -#include - -#include "netmap_classes.h" - - -/* ############## Data and functions useful to all the classes ############# */ -PyObject *NetmapError; - -PyObject * -string_get(PyObject *str) -{ - Py_INCREF(str); - - return str; -} - -int -string_set(PyObject **str, PyObject *value) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the attribute"); - return -1; - } - - if (!PyString_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "The attribute value must be a string"); - return -1; - } - - Py_DECREF(*str); - Py_INCREF(value); - *str = value; - - return 0; -} - -/* @flags: contains the bits we want to pretty-print - @str: where to print - @avail: length of @str - @values: array of all the possible flags - @strings: array of names associated to each flag - @items: length of @values and @strings -*/ -void -netmap_flags_pretty(unsigned int flags, char *str, int avail, - unsigned int *values, const char **strings, int items) -{ - int ret; - int i; - - for (i = 0; avail && i < items; i++) { - if (flags & values[i]) { - ret = snprintf(str, avail, "[%s],", strings[i]); - if (ret < 0) { - *str = '\0'; - return; - } - str += ret; - avail -= ret; - } - } - - *str = '\0'; -} - -static unsigned int nr_flags_values[] = { NR_MONITOR_TX, NR_MONITOR_RX }; -static const char *nr_flags_strings[] = { "MonitorTx", "MonitorRx" }; -static unsigned int nr_poll_values[] = { NETMAP_NO_TX_POLL, - NETMAP_DO_RX_POLL }; -static const char *nr_poll_strings[] = { "NoTxPoll", "DoRxPoll" }; - -/* Pretty print nr_ringid and nr_flags. */ -void -ringid_pretty_print(uint32_t nr_ringid, uint32_t nr_flags, - char *ringid, int rsz, char *flags, int fsz) -{ - unsigned int idx; - int nr, nf; - - idx = nr_ringid & NETMAP_RING_MASK; - - if ((nr_flags & NR_REG_MASK) == (uint32_t)NR_REG_DEFAULT) { - /* Legacy 'ringid' API. */ - unsigned int ringflags = nr_ringid & ~NETMAP_RING_MASK - & ~NETMAP_NO_TX_POLL & ~NETMAP_DO_RX_POLL; - - switch (ringflags) { - case 0: - nr = sprintf(ringid, "[0x%04X] all hardware rings ", - nr_ringid); - break; - case NETMAP_HW_RING: - nr = sprintf(ringid, "[0x%04X] hardware rings pair %u ", - nr_ringid, idx); - break; - case NETMAP_SW_RING: - nr = sprintf(ringid, "[0x%04X] host rings pair ", nr_ringid); - break; - default: - nr = sprintf(ringid, "[0x%04X] ***UNKNOWN*** ", nr_ringid); - } - - sprintf(flags, "[0x%08X] Legacy ringid", nr_flags); - } else { - /* New 'ringid' API. */ - nr = sprintf(ringid, "[0x%04X] %u ", nr_ringid, idx); - - switch (nr_flags & NR_REG_MASK) { - case NR_REG_ALL_NIC: - nf = sprintf(flags, "[0x%08X] all hardware rings ", nr_flags); - break; - case NR_REG_SW: - nf = sprintf(flags, "[0x%08X] host ring pair ", nr_flags); - break; - case NR_REG_NIC_SW: - nf = sprintf(flags, "[0x%08X] all hardware and host rings ", - nr_flags); - break; - case NR_REG_ONE_NIC: - nf = sprintf(flags, "[0x%08X] an hardware rings pair ", - nr_flags); - break; - case NR_REG_PIPE_MASTER: - nf = sprintf(flags, "[0x%08X] a master pipe rings pair ", - nr_flags); - break; - case NR_REG_PIPE_SLAVE: - nf = sprintf(flags, "[0x%08X] a slave pipe rings pair ", - nr_flags); - break; - default: - nf = sprintf(flags, "[0x%08X] ***UNKNOWN*** ", nr_flags); - } - if (nf > 0) { - netmap_flags_pretty(nr_flags, flags + nf, fsz - nf, - nr_flags_values, nr_flags_strings, - sizeof(nr_flags_values) / sizeof(nr_flags_values[0])); - } - } - - if (nr > 0) { - netmap_flags_pretty(nr_ringid, ringid + nr, rsz - nr, - nr_poll_values, nr_poll_strings, - sizeof(nr_poll_values) / sizeof(nr_poll_values[0])); - } -} - - -/*########################### Module functions ############################*/ -static PyObject * -netmap_hello(PyObject *self, PyObject *args) -{ - const char *msg; - - if (!PyArg_ParseTuple(args, "s", &msg)) { - return NULL; - } - - return Py_BuildValue("s", msg); -} - -static PyMethodDef netmap_functions[] = { - { "hello", (PyCFunction)netmap_hello, METH_VARARGS, NULL }, - { NULL, NULL, 0, NULL } -}; - -#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ -#define PyMODINIT_FUNC void -#endif - -/* An integer constant visible from Python. */ -struct NetmapConst { - const char *name; - long value; -}; - -static struct NetmapConst netmap_constants[] = { - { - .name = "AllHwRings", - .value = 0, - }, - { - .name = "HwRing", - .value = NETMAP_HW_RING, - }, - { - .name = "SwRing", - .value = NETMAP_SW_RING, - }, - { - .name = "NoTxPoll", - .value = NETMAP_NO_TX_POLL, - }, - { - .name = "DoRxPoll", - .value = NETMAP_DO_RX_POLL, - }, - /* Add 'nmreq.flags' constants to the module. */ - { - .name = "RegDefault", - .value = NR_REG_DEFAULT, - }, - { - .name = "RegAllNic", - .value = NR_REG_ALL_NIC, - }, - { - .name = "RegSw", - .value = NR_REG_SW, - }, - { - .name = "RegNicSw", - .value = NR_REG_NIC_SW, - }, - { - .name = "RegOneNic", - .value = NR_REG_ONE_NIC, - }, - { - .name = "RegPipeMaster", - .value = NR_REG_PIPE_MASTER, - }, - { - .name = "RegPipeSlave", - .value = NR_REG_PIPE_SLAVE, - }, - { - .name = "RegMonitorTx", - .value = NR_MONITOR_TX, - }, - { - .name = "RegMonitorRx", - .value = NR_MONITOR_RX, - }, - /* Add 'netmap_rings.flags' constants to the module. */ - { - .name = "NrTimestamp", - .value = NR_TIMESTAMP, - }, - { - .name = "NrForward", - .value = NR_FORWARD, - }, - /* Add 'netmap_slot.flags' constants to the module. */ - { - .name = "NsBufChanged", - .value = NS_BUF_CHANGED, - }, - { - .name = "NsReport", - .value = NS_REPORT, - }, - { - .name = "NsForward", - .value = NS_FORWARD, - }, - { - .name = "NsNoLearn", - .value = NS_NO_LEARN, - }, - { - .name = "NsIndirect", - .value = NS_INDIRECT, - }, - { - .name = "NsMorefrag", - .value = NS_MOREFRAG, - }, - /* Add bridge management commands. */ - { - .name = "BdgAttach", - .value = NETMAP_BDG_ATTACH, - }, - { - .name = "BdgDetach", - .value = NETMAP_BDG_DETACH, - }, - { - .name = "BdgList", - .value = NETMAP_BDG_LIST, - }, - { - .name = "BdgVnetHdr", - .value = NETMAP_BDG_VNET_HDR, - }, - { - .name = "BdgHost", - .value = NETMAP_BDG_HOST, - } -}; - - -/*############################### Module init #############################*/ -PyMODINIT_FUNC -initnetmap() -{ - PyObject *module; - int i; - - /* Initialize Netmap***Type. */ - if (PyType_Ready(&NetmapManagerType) < 0) - return; - if (PyType_Ready(&NetmapInterfaceType) < 0) - return; - if (PyType_Ready(&NetmapRingType) < 0) - return; - if (PyType_Ready(&NetmapSlotType) < 0) - return; - if (PyType_Ready(&NetmapDescType) < 0) - return; - - /* Create the python module. */ - module = Py_InitModule3("netmap", netmap_functions, - "Netmap bindings for Python."); - - /* Add the Netmap***Type to the module. */ - Py_INCREF(&NetmapManagerType); - PyModule_AddObject(module, "Netmap", (PyObject *)&NetmapManagerType); - Py_INCREF(&NetmapInterfaceType); - PyModule_AddObject(module, "NetmapInterface", - (PyObject *)&NetmapInterfaceType); - Py_INCREF(&NetmapRingType); - PyModule_AddObject(module, "NetmapRing", (PyObject *)&NetmapRingType); - Py_INCREF(&NetmapSlotType); - PyModule_AddObject(module, "NetmapSlot", (PyObject *)&NetmapSlotType); - Py_INCREF(&NetmapDescType); - PyModule_AddObject(module, "NetmapDesc", (PyObject *)&NetmapDescType); - - /* Add the NetmapError to the module. */ - NetmapError = PyErr_NewException("netmap.error", NULL, NULL); - Py_INCREF(NetmapError); - PyModule_AddObject(module, "error", NetmapError); - - /* Add some integer constants to the module. */ - for (i = 0; i < sizeof(netmap_constants)/sizeof(struct NetmapConst); i++) { - PyModule_AddIntConstant(module, netmap_constants[i].name, - netmap_constants[i].value); - } -} - diff --git a/private/extra/python/netmap_classes.h b/private/extra/python/netmap_classes.h deleted file mode 100644 index 9f0736445..000000000 --- a/private/extra/python/netmap_classes.h +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include - - -extern PyObject *NetmapError; - -/* Utilities implemented in netmap.c. */ -PyObject *string_get(PyObject *str); -int string_set(PyObject **str, PyObject *value); -void netmap_flags_pretty(unsigned int flags, char *str, int avail, - unsigned int *values, const char **strings, int items); -void ringid_pretty_print(uint32_t nr_ringid, uint32_t nr_flags, - char *ringid, int rsz, char *flags, int fsz); - - -/* Netmap memory representation. */ -typedef struct { - PyObject *interface; - PyObject *transmit_rings; - PyObject *receive_rings; - -} NetmapMemory; - -void NetmapMemory_dealloc(NetmapMemory *memory); -void NetmapMemory_new(NetmapMemory *memory); -int NetmapMemory_setup(NetmapMemory *memory, struct netmap_if *nifp, - int num_tx_rings, int num_rx_rings); -void NetmapMemory_destroy(NetmapMemory *memory); - -/* - * Main class of the netmap module, managing - * a netmap port. - */ -typedef struct { - PyObject_HEAD - PyObject *dev_name; /* Netmap device name. */ - - PyObject *if_name; - struct nmreq nmreq; /* The netmap request we are wrapping. */ - - /* Netmap memory representation. */ - NetmapMemory memory; - - /* Internal variables. */ - int _state; -#define INVALID_FD (-1) - int _fd; /* Netmap device file descriptor. */ - void *_memaddr; /* Netmap memory-mapped area. */ -} NetmapManager; - -extern PyTypeObject NetmapManagerType; - - -/* - * A simpler alternative to the NetmapManager class, which makes use of the - * nm_open()/nm_close() API. - */ -typedef struct { - PyObject_HEAD - - struct nm_desc *nmd; /* The netmap descriptor object we are wrapping. */ - - /* Netmap memory representation. */ - NetmapMemory memory; -} NetmapDesc; - -extern PyTypeObject NetmapDescType; - - -/* Class wrapper for the netmap_if struct. */ -typedef struct { - PyObject_HEAD - - struct netmap_if *_nifp; /* Address of struct netmap_if. */ -} NetmapInterface; - -extern PyTypeObject NetmapInterfaceType; - -int NetmapInterface_build(NetmapInterface *self, void *addr); -void NetmapInterface_destroy(NetmapInterface *self); - - -/* Class wrapper for the netmap_ring struct. */ -typedef struct { - PyObject_HEAD - PyObject *slots; - - struct netmap_ring *_ring; /* Address of struct netmap_ring. */ -} NetmapRing; - -extern PyTypeObject NetmapRingType; - -int NetmapRing_build(NetmapRing *self, void *addr); -void NetmapRing_destroy(NetmapRing *self); - - -/* Class wrapper for the netmap_slot struct. */ -typedef struct { - PyObject_HEAD - PyObject *memoryview; - - Py_buffer _view; - struct netmap_slot *_slot; /* Address of struct netmap_slot. */ -} NetmapSlot; - -extern PyTypeObject NetmapSlotType; - -int NetmapSlot_build(NetmapSlot *slot, void *addr, void *buf); -void NetmapSlot_destroy(NetmapSlot *slot); diff --git a/private/extra/python/netmap_desc.c b/private/extra/python/netmap_desc.c deleted file mode 100644 index f6058270d..000000000 --- a/private/extra/python/netmap_desc.c +++ /dev/null @@ -1,247 +0,0 @@ -#include "netmap_classes.h" - -#include -#include /* open() */ -#include /* ioctl() */ -#include /* mmap() */ -#include /* IFNAMSIZ */ -#include -#include -#define NETMAP_WITH_LIBS -#include - - -/* Destructor method for NetmapDescType. */ -static void -NetmapDesc_dealloc(NetmapDesc* self) -{ - NetmapMemory_dealloc(&self->memory); - - if (self->nmd) { - nm_close(self->nmd); - } - self->ob_type->tp_free((PyObject*)self); -} - -/* Netmap.__new__() is the constructor. */ -static PyObject * -NetmapDesc_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NetmapDesc *self; - - self = (NetmapDesc *)type->tp_alloc(type, 0); - if (self == NULL) { - return NULL; - } - - self->nmd = NULL; - NetmapMemory_new(&self->memory); - - return (PyObject *)self; -} - -/* Netmap.__init__(), may be called many times, or not called at all. */ -static int -NetmapDesc_init(NetmapDesc *self, PyObject *args, PyObject *kwds) -{ - PyObject *dev_name = NULL; - static char *kwlist[] = {"ifname", "flags", NULL}; - const char *ifname; - unsigned long flags; - int ret; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|k", kwlist, - &ifname, &flags)) { - return -1; - } - - /* Open the netmap device and register an interface. */ - self->nmd = nm_open(ifname, NULL, flags, NULL); - if (self->nmd == NULL) { - PyErr_SetString(NetmapError, "nm_open() failed"); - return -1; - } - - /* Setup the netmap memory layout. The +1 are here to take into account - the host rings. */ - ret = NetmapMemory_setup(&self->memory, self->nmd->nifp, - self->nmd->req.nr_tx_rings + 1, - self->nmd->req.nr_rx_rings + 1); - - return ret; -} - -static PyObject * -NetmapDesc_repr(NetmapDesc *self) -{ - PyObject *result; - char ringid[128]; - char flags[128]; - - ringid_pretty_print(self->nmd->req.nr_ringid, self->nmd->req.nr_flags, - ringid, sizeof(ringid), flags, sizeof(flags)); - - result = PyString_FromFormat( - "if_name: '%s'\n" - "ringid: '%s'\n" - "flags: '%s'\n", - self->nmd->req.nr_name, ringid, flags); - - return result; -} - - -static PyMemberDef NetmapDesc_members[] = { - {NULL} /* Sentinel */ -}; - - -/*########################## set/get methods #######################*/ - -#define NETMAP_MANAGER_DEFINE_GETSET(obj) \ -static PyObject * \ -NetmapDesc_##obj##_get(NetmapDesc *self, void *closure) \ -{ \ - if (self->memory.obj == NULL) { \ - Py_RETURN_NONE; \ - } \ - Py_INCREF(self->memory.obj); \ - return self->memory.obj; \ -} \ - \ -static int \ -NetmapDesc_##obj##_set(NetmapDesc *self, PyObject *value, \ - void *closure) \ -{ \ - if (value == NULL) { \ - PyErr_SetString(PyExc_TypeError, "Cannot delete the attribute"); \ - } else { \ - PyErr_SetString(PyExc_TypeError, "Cannot modify the attribute"); \ - } \ - return -1; \ -} - -NETMAP_MANAGER_DEFINE_GETSET(interface); -NETMAP_MANAGER_DEFINE_GETSET(transmit_rings); -NETMAP_MANAGER_DEFINE_GETSET(receive_rings); - -#define NETMAP_MANAGER_DECLARE_GETSET(obj, desc) \ - {#obj, \ - (getter)NetmapDesc_##obj##_get, \ - (setter)NetmapDesc_##obj##_set, \ - desc, \ - NULL} - - -static PyGetSetDef NetmapDesc_getseters[] = { - NETMAP_MANAGER_DECLARE_GETSET(interface, "NetmapInterface object"), - NETMAP_MANAGER_DECLARE_GETSET(transmit_rings, - "List of NetmapRing objects (Tx)"), - NETMAP_MANAGER_DECLARE_GETSET(receive_rings, - "List of NetmapRing objects (Rx)"), - {NULL} /* Sentinel */ -}; - - -/*########################## NetmapDesc methods ########################*/ - -static PyObject * -NetmapDesc_xxsync(NetmapDesc *self, int iocmd) -{ - int ret; - - /* Issue the request to the netmap device. */ - ret = ioctl(self->nmd->fd, iocmd, NULL); - if (ret) { - PyErr_SetFromErrno(NetmapError); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -NetmapDesc_txsync(NetmapDesc *self) -{ - return NetmapDesc_xxsync(self, NIOCTXSYNC); -} - -static PyObject * -NetmapDesc_rxsync(NetmapDesc *self) -{ - return NetmapDesc_xxsync(self, NIOCRXSYNC); -} - -static PyObject * -NetmapDesc_getfd(NetmapDesc *self) -{ - return Py_BuildValue("i", self->nmd->fd); -} - -static PyObject * -NetmapDesc_getringid(NetmapDesc *self) -{ - return Py_BuildValue("kk", self->nmd->req.nr_ringid, - self->nmd->req.nr_flags); -} - -/* A container for the netmap methods. */ -static PyMethodDef NetmapDesc_methods[] = { - {"txsync", (PyCFunction)NetmapDesc_txsync, METH_NOARGS, - "Do a txsync on the registered rings" - }, - {"rxsync", (PyCFunction)NetmapDesc_rxsync, METH_NOARGS, - "Do a rxsync on the registered rings" - }, - {"getfd", (PyCFunction)NetmapDesc_getfd, METH_NOARGS, - "Get the file descriptor of the open netmap device" - }, - {"getringid", (PyCFunction)NetmapDesc_getringid, METH_NOARGS, - "Get the nr_ringid and nr_flags of the registered interface" - }, - {NULL} /* Sentinel */ -}; - -/* Definition exported to netmap.c. */ -PyTypeObject NetmapDescType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "netmap.NetmapDesc", /*tp_name*/ - sizeof(NetmapDesc), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NetmapDesc_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NetmapDesc_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "Netmap descriptor object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NetmapDesc_methods, /* tp_methods */ - NetmapDesc_members, /* tp_members */ - NetmapDesc_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)NetmapDesc_init, /* tp_init */ - 0, /* tp_alloc */ - NetmapDesc_new, /* tp_new */ -}; - diff --git a/private/extra/python/netmap_interface.c b/private/extra/python/netmap_interface.c deleted file mode 100644 index e0a812444..000000000 --- a/private/extra/python/netmap_interface.c +++ /dev/null @@ -1,225 +0,0 @@ -#include "netmap_classes.h" - -#include - - -static void -NetmapInterface_dealloc(NetmapInterface* self) -{ - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -NetmapInterface_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NetmapInterface *self; - - self = (NetmapInterface *)type->tp_alloc(type, 0); - if (self != NULL) { - self->_nifp = NULL; - } - - return (PyObject *)self; -} - -static PyObject * -NetmapInterface_repr(NetmapInterface *self) -{ - PyObject *result; - struct netmap_if *nifp = self->_nifp; - - if (nifp == NULL) { - return Py_BuildValue("s", "Invalid NetmapInterface"); - } - - result = PyString_FromFormat( - "name: '%s'\n" - "version: %u\n" - "flags: 0x%08x\n" - "tx_rings: %u\n" - "rx_rings: %u\n" - "bufs_head: %u\n" - "spare1[0]: 0x%08x\n" - "spare1[1]: 0x%08x\n" - "spare1[2]: 0x%08x\n" - "spare1[3]: 0x%08x\n" - "spare1[4]: 0x%08x\n", - nifp->ni_name, - nifp->ni_version, - nifp->ni_flags, - nifp->ni_tx_rings, - nifp->ni_rx_rings, - nifp->ni_bufs_head, - nifp->ni_spare1[0], - nifp->ni_spare1[1], - nifp->ni_spare1[2], - nifp->ni_spare1[3], - nifp->ni_spare1[4] - ); - - return result; -} - - -static PyMemberDef NetmapInterface_members[] = { - {NULL} -}; - -int -NetmapInterface_build(NetmapInterface *self, void *addr) -{ - self->_nifp = addr; - - return 0; -} - -void -NetmapInterface_destroy(NetmapInterface *self) -{ - self->_nifp = NULL; -} - -/*########################## set/get methods #######################*/ - -static PyObject * -NetmapInterface_name_get(NetmapInterface *self, void *closure) -{ - if (!self->_nifp) { - /* This cannot happen for NetmapInterface object created by - a NetmapManager object, but may happen for standalone - NetmapInterface objects. */ - Py_RETURN_NONE; - } - - return Py_BuildValue("s", self->_nifp->ni_name); -} - -static int -NetmapInterface_name_set(NetmapInterface *self, PyObject *value, void *closure) -{ - const char *str; - size_t len; - - if (!self->_nifp) { - /* See comment in NetmapInterface_name_get(). */ - PyErr_SetString(PyExc_TypeError, "Attribute not available"); - return -1; - } - - str = PyString_AsString(value); - if (str == NULL) { - return -1; - } - - len = PyString_Size(value); - if (len > IFNAMSIZ-1) { - len = IFNAMSIZ-1; - } - memcpy(self->_nifp->ni_name, str, len); - self->_nifp->ni_name[len] = '\0'; - - return 0; -} - -#define DEFINE_NETMAP_INTERFACE_U32_GETSET(x) \ -static PyObject * \ -NetmapInterface_##x##_get(NetmapInterface *self, void *closure) \ -{ \ - if (!self->_nifp) { \ - Py_RETURN_NONE; \ - } \ - return Py_BuildValue("I", self->_nifp->ni_##x); \ -} \ - \ -static int \ -NetmapInterface_##x##_set(NetmapInterface *self, PyObject *value, \ - void *closure) \ -{ \ - long x; \ - if (!self->_nifp) { \ - PyErr_SetString(PyExc_TypeError, "Attribute not available"); \ - return -1; \ - } \ - x = PyInt_AsLong(value); \ - if (x == -1 && PyErr_Occurred()) { \ - return -1; \ - } \ - /* Override the 'const' specifier. */ \ - *((uint32_t *)&self->_nifp->ni_##x) = (uint32_t)x; \ - return 0; \ -} - -DEFINE_NETMAP_INTERFACE_U32_GETSET(version); -DEFINE_NETMAP_INTERFACE_U32_GETSET(flags); -DEFINE_NETMAP_INTERFACE_U32_GETSET(tx_rings); -DEFINE_NETMAP_INTERFACE_U32_GETSET(rx_rings); -DEFINE_NETMAP_INTERFACE_U32_GETSET(bufs_head); - -#define DECLARE_NETMAP_INTERFACE_U32_GETSETERS(x) \ - {#x, \ - (getter)NetmapInterface_##x##_get, \ - (setter)NetmapInterface_##x##_set, \ - "netmap interface " #x " field", \ - NULL} - -static PyGetSetDef NetmapInterface_getseters[] = { - {"name", - (getter)NetmapInterface_name_get, (setter)NetmapInterface_name_set, - "netmap interface name field", - NULL}, - DECLARE_NETMAP_INTERFACE_U32_GETSETERS(version), - DECLARE_NETMAP_INTERFACE_U32_GETSETERS(flags), - DECLARE_NETMAP_INTERFACE_U32_GETSETERS(tx_rings), - DECLARE_NETMAP_INTERFACE_U32_GETSETERS(rx_rings), - DECLARE_NETMAP_INTERFACE_U32_GETSETERS(bufs_head), - {NULL} /* Sentinel */ -}; - - -static PyMethodDef NetmapInterface_methods[] = { - {NULL} -}; - -/* Definition exported to netmap.c. */ -PyTypeObject NetmapInterfaceType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "netmap.NetmapInterface", /*tp_name*/ - sizeof(NetmapInterface), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NetmapInterface_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NetmapInterface_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "Netmap interface object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NetmapInterface_methods, /* tp_methods */ - NetmapInterface_members, /* tp_members */ - NetmapInterface_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - NetmapInterface_new, /* tp_new */ -}; - diff --git a/private/extra/python/netmap_manager.c b/private/extra/python/netmap_manager.c deleted file mode 100644 index 9bb202607..000000000 --- a/private/extra/python/netmap_manager.c +++ /dev/null @@ -1,582 +0,0 @@ -#include "netmap_classes.h" - -#include -#include /* open() */ -#include /* ioctl() */ -#include /* mmap() */ -#include /* IFNAMSIZ */ -#include -#include - - -enum { - MANAGER_CLOSED = 0, - MANAGER_OPENED = 1, - MANAGER_REGISTERED = 2 -}; - -/* Destructor method for NetmapManagerType. */ -static void -NetmapManager_dealloc(NetmapManager* self) -{ - /* The 'X' is necessary only here: In all the other places, because of - our getters/setters we are sure that PyObject* members cannot be NULL. - */ - Py_XDECREF(self->dev_name); - Py_XDECREF(self->if_name); - NetmapMemory_dealloc(&self->memory); - self->ob_type->tp_free((PyObject*)self); -} - -/* Netmap.__new__() is the constructor. */ -static PyObject * -NetmapManager_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NetmapManager *self; - - self = (NetmapManager *)type->tp_alloc(type, 0); - if (self == NULL) { - return NULL; - } - - /* Init with defaults. */ - self->dev_name = PyString_FromString("/dev/netmap"); - if (self->dev_name == NULL) { - Py_DECREF(self); - return NULL; - } - - self->if_name = PyString_FromString(""); - if (self->if_name == NULL) { - Py_DECREF(self); - return NULL; - } - - memset(&self->nmreq, 0, sizeof(self->nmreq)); - self->nmreq.nr_version = NETMAP_API; - self->nmreq.nr_flags = NR_REG_DEFAULT; /* Legacy 'ringid'. */ - self->nmreq.nr_ringid = 0; /* Bind all physical rings. */ - - NetmapMemory_new(&self->memory); - - self->_state = MANAGER_CLOSED; - self->_fd = INVALID_FD; - self->_memaddr = NULL; - - return (PyObject *)self; -} - -/* Netmap.__init__(), may be called many times, or not called at all. */ -static int -NetmapManager_init(NetmapManager *self, PyObject *args, PyObject *kwds) -{ - PyObject *dev_name = NULL; - static char *kwlist[] = {"dev_name", "version", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|SI", kwlist, - &dev_name, &self->nmreq.nr_version)) { - return -1; - } - - if (dev_name) { - PyObject *tmp; - - /* Safe reference. */ - tmp = self->dev_name; - Py_INCREF(dev_name); - self->dev_name = dev_name; - Py_XDECREF(tmp); - } - - return 0; -} - -static PyObject * -NetmapManager_repr(NetmapManager *self) -{ - PyObject *result; - char ringid[128]; - char flags[128]; - char cmd[64]; - struct nmreq *req = &self->nmreq; - - /* Fills in the 'ringid' and 'flags' string buffers. */ - ringid_pretty_print(req->nr_ringid, req->nr_flags, ringid, - sizeof(ringid), flags, sizeof(flags)); - - switch (req->nr_cmd) { - case 0: - sprintf(cmd, "None"); - break; - case NETMAP_BDG_ATTACH: - sprintf(cmd, "Bridge attach"); - break; - case NETMAP_BDG_DETACH: - sprintf(cmd, "Bridge detach"); - break; - case NETMAP_BDG_REGOPS: - sprintf(cmd, "Bridge lookup register"); - break; - case NETMAP_BDG_LIST: - sprintf(cmd, "Bridge list"); - break; - case NETMAP_BDG_VNET_HDR: - sprintf(cmd, "Bridge set virtio-net header length"); - break; - } - - result = PyString_FromFormat( - "dev_name: '%s'\n" - "if_name: '%s'\n" - "version: %d\n" - "memsize: %u KiB\n" - "offset: %u\n" - "tx_slots: %d\n" - "rx_slots: %d\n" - "tx_rings: %d\n" - "rx_rings: %d\n" - "ringid: %s\n" - "cmd: [%d] %s\n" - "arg1: %d\n" - "arg2: %d\n" - "arg3: %d\n" - "flags: %s\n" - "spare2: %d\n", - PyString_AsString(self->dev_name), - PyString_AsString(self->if_name), req->nr_version, - req->nr_memsize / 1024, req->nr_offset, - req->nr_tx_slots, req->nr_rx_slots, - req->nr_tx_rings, req->nr_rx_rings, - ringid, req->nr_cmd, cmd, req->nr_arg1, - req->nr_arg2, req->nr_arg3, flags, req->spare2[0] - ); - - return result; -} - - -/* A container for Netmap attributes where set/get methods are - managed automatically. */ -static PyMemberDef NetmapManager_members[] = { - {"version", T_UINT, offsetof(NetmapManager, nmreq.nr_version), 0, - "netmap API version"}, - {"tx_slots", T_UINT, offsetof(NetmapManager, nmreq.nr_tx_slots), 0, - "number of TX slots in each ring"}, - {"rx_slots", T_UINT, offsetof(NetmapManager, nmreq.nr_rx_slots), 0, - "number of RX slots in each ring"}, - {"tx_rings", T_USHORT, offsetof(NetmapManager, nmreq.nr_tx_rings), 0, - "number of TX rings"}, - {"rx_rings", T_USHORT, offsetof(NetmapManager, nmreq.nr_rx_rings), 0, - "number of RX rings"}, - {"ringid", T_USHORT, offsetof(NetmapManager, nmreq.nr_ringid), 0, - "identifies which rings to tie to"}, - {"cmd", T_USHORT, offsetof(NetmapManager, nmreq.nr_cmd), 0, - "cmd"}, - {"arg1", T_USHORT, offsetof(NetmapManager, nmreq.nr_arg1), 0, - "arg1 field"}, - {"arg2", T_USHORT, offsetof(NetmapManager, nmreq.nr_arg2), 0, - "arg2 field"}, - {"arg3", T_UINT, offsetof(NetmapManager, nmreq.nr_arg3), 0, - "arg3 field"}, - {"flags", T_UINT, offsetof(NetmapManager, nmreq.nr_flags), 0, - "flags"}, - {"spare2", T_UINT, offsetof(NetmapManager, nmreq.spare2[0]), 0, - "spare2 field"}, - {NULL} /* Sentinel */ -}; - - -/*########################## set/get methods #######################*/ - -static PyObject * -NetmapManager_dev_name_get(NetmapManager *self, void *closure) -{ - return string_get(self->dev_name); -} - -static int -NetmapManager_dev_name_set(NetmapManager *self, PyObject *value, void *closure) -{ - return string_set(&self->dev_name, value); -} - -static PyObject * -NetmapManager_if_name_get(NetmapManager *self, void *closure) -{ - return string_get(self->if_name); -} - -static int -NetmapManager_if_name_set(NetmapManager *self, PyObject *value, void *closure) -{ - return string_set(&self->if_name, value); -} - -#define NETMAP_MANAGER_DEFINE_GETSET(obj) \ -static PyObject * \ -NetmapManager_##obj##_get(NetmapManager *self, void *closure) \ -{ \ - if (self->memory.obj == NULL) { \ - Py_RETURN_NONE; \ - } \ - Py_INCREF(self->memory.obj); \ - return self->memory.obj; \ -} \ - \ -static int \ -NetmapManager_##obj##_set(NetmapManager *self, PyObject *value, \ - void *closure) \ -{ \ - if (value == NULL) { \ - PyErr_SetString(PyExc_TypeError, "Cannot delete the attribute"); \ - } else { \ - PyErr_SetString(PyExc_TypeError, "Cannot modify the attribute"); \ - } \ - return -1; \ -} - -NETMAP_MANAGER_DEFINE_GETSET(interface); -NETMAP_MANAGER_DEFINE_GETSET(transmit_rings); -NETMAP_MANAGER_DEFINE_GETSET(receive_rings); - -#define NETMAP_MANAGER_DECLARE_GETSET(obj, desc) \ - {#obj, \ - (getter)NetmapManager_##obj##_get, \ - (setter)NetmapManager_##obj##_set, \ - desc, \ - NULL} - - -static PyGetSetDef NetmapManager_getseters[] = { - {"dev_name", - (getter)NetmapManager_dev_name_get, (setter)NetmapManager_dev_name_set, - "netmap device name", - NULL}, - {"if_name", - (getter)NetmapManager_if_name_get, (setter)NetmapManager_if_name_set, - "interface name", - NULL}, - NETMAP_MANAGER_DECLARE_GETSET(interface, "NetmapInterface object"), - NETMAP_MANAGER_DECLARE_GETSET(transmit_rings, - "List of NetmapRing objects (Tx)"), - NETMAP_MANAGER_DECLARE_GETSET(receive_rings, - "List of NetmapRing objects (Rx)"), - {NULL} /* Sentinel */ -}; - -static void -NetmapManager_destroy(NetmapManager *self) -{ - NetmapMemory_destroy(&self->memory); -} - - -/*########################## NetmapManager methods ########################*/ - -static PyObject * -NetmapManager_open(NetmapManager* self) -{ - const char *dev_name; - int fd; - - dev_name = PyString_AsString(self->dev_name); - if (dev_name == NULL) { - return NULL; - } - - if (self->_state != MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Cannot open netmap device twice"); - return NULL; - } - - fd = open(dev_name, O_RDWR); - if (fd < 0) { - PyErr_SetFromErrno(NetmapError); - return NULL; - } - self->_fd = fd; - self->_state = MANAGER_OPENED; - - Py_RETURN_NONE; -} - -static PyObject * -NetmapManager_close(NetmapManager* self) -{ - int ret; - - if (self->_state == MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Netmap device is not opened"); - return NULL; - } - - if (self->_memaddr) { - munmap(self->_memaddr, self->nmreq.nr_memsize); - self->_memaddr = NULL; - self->nmreq.nr_memsize = 0; - } - - ret = close(self->_fd); - if (ret) { - PyErr_SetFromErrno(NetmapError); - return NULL; - } - self->_fd = INVALID_FD; - self->_state = MANAGER_CLOSED; - - NetmapManager_destroy(self); - - Py_RETURN_NONE; -} - -static int -NetmapManager_ioctl(NetmapManager *self, int iocmd) -{ - struct nmreq req; - const char *if_name; - int ret; - - if_name = PyString_AsString(self->if_name); - if (if_name == NULL) { - return -1; - } - - /* Prepare the netmap request ioctl argument. */ - memcpy(&req, &self->nmreq, sizeof(req)); - strncpy(req.nr_name, if_name, IFNAMSIZ); - - /* Issue the request to the netmap device. */ - ret = ioctl(self->_fd, iocmd, &req); - if (ret) { - PyErr_SetFromErrno(NetmapError); - return -1; - } - - /* Request writeback. */ - memcpy(&self->nmreq, &req, sizeof(req)); - - return 0; -} - -static PyObject * -NetmapManager_register(NetmapManager *self) -{ - NetmapInterface *interface; - NetmapRing *ring; - PyObject *list; - int ret; - int i; - - if (self->_state != MANAGER_OPENED) { - if (self->_state == MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Netmap device is not opened"); - } else if (self->_state == MANAGER_REGISTERED) { - PyErr_SetString(NetmapError, - "Netmap interface already registered"); - } - return NULL; - } - - /* Issue a NIOCREGIF command. */ - ret = NetmapManager_ioctl(self, NIOCREGIF); - if (ret == -1) { - return NULL; - } - - /* Map netmap memory area. */ - self->_memaddr = mmap(0, self->nmreq.nr_memsize, - PROT_WRITE | PROT_READ, - MAP_SHARED, self->_fd, 0); - if (self->_memaddr == MAP_FAILED) { - self->_memaddr = NULL; - PyErr_SetFromErrno(NetmapError); - return NULL; - } - - /* Setup the Python data structures corresponding to the netmap memory layout. - The +1 are here to take into account the host rings. */ - ret = NetmapMemory_setup(&self->memory, NETMAP_IF(self->_memaddr, - self->nmreq.nr_offset), self->nmreq.nr_tx_rings + 1, - self->nmreq.nr_rx_rings + 1); - if (ret) { - return NULL; - } - - self->_state = MANAGER_REGISTERED; - - Py_RETURN_NONE; -} - -static PyObject * -NetmapManager_xxsync(NetmapManager *self, int iocmd) -{ - int ret; - - if (self->_state == MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Netmap device is not opened"); - return NULL; - } - - if (self->_state == MANAGER_OPENED) { - PyErr_SetString(NetmapError, "Netmap interface is not registered"); - return NULL; - } - - /* Issue the request to the netmap device. */ - ret = ioctl(self->_fd, iocmd, NULL); - if (ret) { - PyErr_SetFromErrno(NetmapError); - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -NetmapManager_txsync(NetmapManager *self) -{ - return NetmapManager_xxsync(self, NIOCTXSYNC); -} - -static PyObject * -NetmapManager_rxsync(NetmapManager *self) -{ - return NetmapManager_xxsync(self, NIOCRXSYNC); -} - -static PyObject * -NetmapManager_getfd(NetmapManager *self) -{ - if (self->_state == MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Netmap device is not opened"); - return NULL; - } - - return Py_BuildValue("i", self->_fd); -} - -static PyObject * -NetmapManager_getinfo(NetmapManager *self) -{ - int ret; - - if (self->_state == MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Netmap device is not opened"); - return NULL; - } - - /* Issue a NIOCGINFO command. */ - ret = NetmapManager_ioctl(self, NIOCGINFO); - if (ret == -1) { - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject * -NetmapManager_clear(NetmapManager *self) -{ - memset(&self->nmreq, 0, sizeof(self->nmreq)); - self->nmreq.nr_version = NETMAP_API; - self->nmreq.nr_flags = NR_REG_DEFAULT; /* Legacy 'ringid'. */ - self->nmreq.nr_ringid = 0; /* Bind all physical rings. */ - - Py_RETURN_NONE; -} - -static PyObject * -NetmapManager_regif(NetmapManager *self) -{ - int ret; - - if (self->_state == MANAGER_CLOSED) { - PyErr_SetString(NetmapError, "Netmap device is not opened"); - return NULL; - } - - /* Issue a NIOCGREGIF command. */ - ret = NetmapManager_ioctl(self, NIOCREGIF); - if (ret == -1) { - return NULL; - } - - Py_RETURN_NONE; -} - -/* A container for the netmap methods. */ -static PyMethodDef NetmapManager_methods[] = { - {"open", (PyCFunction)NetmapManager_open, METH_NOARGS, - "Open the netmap device" - }, - {"close", (PyCFunction)NetmapManager_close, METH_NOARGS, - "Close the netmap device" - }, - {"register", (PyCFunction)NetmapManager_register, METH_NOARGS, - "Register an interface with netmap" - }, - {"txsync", (PyCFunction)NetmapManager_txsync, METH_NOARGS, - "Do a txsync on the registered rings" - }, - {"rxsync", (PyCFunction)NetmapManager_rxsync, METH_NOARGS, - "Do a rxsync on the registered rings" - }, - {"getfd", (PyCFunction)NetmapManager_getfd, METH_NOARGS, - "Get the file descriptor of the open netmap device" - }, - {"getinfo", (PyCFunction)NetmapManager_getinfo, METH_NOARGS, - "Ask netmap for interface info" - }, - {"clear", (PyCFunction)NetmapManager_clear, METH_NOARGS, - "Reset some netmap request fields to their default values" - }, - {"regif", (PyCFunction)NetmapManager_regif, METH_NOARGS, - "Issue a NIOCREGIF command to the netmap device (can be used to issue " - "NETMAP_BDG_ATTACH and similar commands)" - }, - {NULL} /* Sentinel */ -}; - -/* Definition exported to netmap.c. */ -PyTypeObject NetmapManagerType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "netmap.Netmap", /*tp_name*/ - sizeof(NetmapManager), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NetmapManager_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NetmapManager_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "Netmap manager object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NetmapManager_methods, /* tp_methods */ - NetmapManager_members, /* tp_members */ - NetmapManager_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)NetmapManager_init, /* tp_init */ - 0, /* tp_alloc */ - NetmapManager_new, /* tp_new */ -}; - diff --git a/private/extra/python/netmap_memory.c b/private/extra/python/netmap_memory.c deleted file mode 100644 index b1ab7a9f8..000000000 --- a/private/extra/python/netmap_memory.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "netmap_classes.h" - -#include -#include /* IFNAMSIZ */ -#include -#include - - -void -NetmapMemory_dealloc(NetmapMemory *memory) -{ - Py_XDECREF(memory->interface); - Py_XDECREF(memory->transmit_rings); - Py_XDECREF(memory->receive_rings); -} - -void -NetmapMemory_new(NetmapMemory *memory) -{ - memory->interface = NULL; - memory->transmit_rings = memory->receive_rings = NULL; -} - -int -NetmapMemory_setup(NetmapMemory *memory, struct netmap_if *nifp, - int num_tx_rings, int num_rx_rings) -{ - NetmapInterface *interface; - NetmapRing *ring; - PyObject *list; - int ret; - int i; - - /* Initialize the 'interface' child object. */ - memory->interface = PyObject_CallObject((PyObject *)&NetmapInterfaceType, - NULL); - if (!memory->interface) { - return -1; - } - interface = (NetmapInterface *)memory->interface; - NetmapInterface_build(interface, nifp); - - /* Initialize the 'transmit_rings' child object. */ - list = PyList_New(num_tx_rings); - if (!list) { - return -1; - } - memory->transmit_rings = list; - for (i = 0; i < num_tx_rings; i++) { - ring = (NetmapRing *)PyObject_CallObject((PyObject *)&NetmapRingType, - NULL); - if (!ring) { - return -1; - } - ret = NetmapRing_build(ring, NETMAP_TXRING(nifp, i)); - if (ret) { - return -1; - } - ret = PyList_SetItem(list, i, (PyObject *)ring); - if (ret) { - return -1; - } - } - - /* Initialize the 'receive_rings' child object. */ - list = PyList_New(num_rx_rings); - if (!list) { - return -1; - } - memory->receive_rings = list; - for (i = 0; i < num_rx_rings; i++) { - ring = (NetmapRing *)PyObject_CallObject((PyObject *)&NetmapRingType, - NULL); - if (!ring) { - return -1; - } - ret = NetmapRing_build(ring, NETMAP_RXRING(nifp, i)); - if (ret) { - return -1; - } - ret = PyList_SetItem(list, i, (PyObject *)ring); - if (ret) { - return -1; - } - } - - return 0; -} - -void -NetmapMemory_destroy(NetmapMemory *memory) -{ - NetmapRing *ring; - int n; - int i; - - if (memory->interface) { - NetmapInterface_destroy((NetmapInterface *)memory->interface); - Py_DECREF(memory->interface); - memory->interface = NULL; - } - - if (memory->transmit_rings) { - n = PyList_Size(memory->transmit_rings); - for (i = 0; i < n; i++) { - ring = (NetmapRing *)PyList_GetItem(memory->transmit_rings, i); - if (ring) { - NetmapRing_destroy(ring); - } - } - Py_DECREF(memory->transmit_rings); - memory->transmit_rings = NULL; - } - - if (memory->receive_rings) { - n = PyList_Size(memory->receive_rings); - for (i = 0; i < n; i++) { - ring = (NetmapRing *)PyList_GetItem(memory->receive_rings, i); - if (ring) { - NetmapRing_destroy(ring); - } - } - Py_DECREF(memory->receive_rings); - memory->receive_rings = NULL; - } -} diff --git a/private/extra/python/netmap_ring.c b/private/extra/python/netmap_ring.c deleted file mode 100644 index 9295ab57c..000000000 --- a/private/extra/python/netmap_ring.c +++ /dev/null @@ -1,338 +0,0 @@ -#include "netmap_classes.h" - -#include - -#include -#include -#include - - -static void -NetmapRing_dealloc(NetmapRing* self) -{ - Py_XDECREF(self->slots); - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -NetmapRing_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NetmapRing *self; - - self = (NetmapRing *)type->tp_alloc(type, 0); - if (self != NULL) { - self->_ring = NULL; - self->slots = NULL; - } - - return (PyObject *)self; -} - -/* Static data for flags pretty printing. */ -static unsigned int nr_flag_values[] = {NR_TIMESTAMP, NR_FORWARD}; -static const char *nr_flag_strings[] = {"NrTimestamp", "NrForward"}; - -static PyObject * -NetmapRing_repr(NetmapRing *self) -{ - PyObject *result; - struct netmap_ring *ring= self->_ring; - char flags[256]; - - if (ring == NULL) { - return Py_BuildValue("s", "Invalid NetmapRing"); - } - - netmap_flags_pretty(ring->flags, flags, sizeof(flags), nr_flag_values, - nr_flag_strings, - sizeof(nr_flag_values)/sizeof(*nr_flag_values)); - - result = PyString_FromFormat( - "buf_ofs: 0x%016x\n" - "num_slots: %u\n" - "nr_buf_size: %u\n" - "ringid: %u\n" - "dir: %u\n" - "head: %u\n" - "cur: %u\n" - "tail: %u\n" - "flags: [0x%08x] %s\n" - "tv_sec: %u\n" - "tv_usec: %u\n" - /* TODO sem */, - ring->buf_ofs, - ring->num_slots, - ring->nr_buf_size, - ring->ringid, - ring->dir, - ring->head, - ring->cur, - ring->tail, - ring->flags, - flags, - ring->ts.tv_sec, - ring->ts.tv_usec - ); - - return result; -} - -int -NetmapRing_build(NetmapRing *self, void *addr) -{ - NetmapSlot *slot; - PyObject *list; - int ret; - int i; - int n; - - if (self->_ring) { - PyErr_SetString(NetmapError, "Internal error: cannot connect" - " a ring twice"); - return -1; - } - - /* Init the pointer to the netmap_ring struct. */ - self->_ring = addr; - n = self->_ring->num_slots; - - /* Create and populate the list of netmap slots. */ - list = PyList_New(n); - if (!list) { - return -1; - } - self->slots = list; - - for (i = 0; i < n; i++) { - slot = (NetmapSlot *)PyObject_CallObject((PyObject *)&NetmapSlotType, - NULL); - if (!slot) { - return -1; - } - ret = NetmapSlot_build(slot, &self->_ring->slot[i], - NETMAP_BUF(self->_ring, - self->_ring->slot[i].buf_idx)); - if (ret == -1) { - return -1; - } - - ret = PyList_SetItem(list, i, (PyObject *)slot); - if (ret == -1) { - return -1; - } - } - - return 0; -} - -void -NetmapRing_destroy(NetmapRing *self) -{ - self->_ring = NULL; - - if (self->slots) { - NetmapSlot *slot; - int n; - int i; - - n = PyList_Size(self->slots); - for (i = 0; i < n; i++) { - slot = (NetmapSlot *)PyList_GetItem(self->slots, i); - if (slot) { - NetmapSlot_destroy(slot); - } - } - Py_DECREF(self->slots); - self->slots = NULL; - } -} - -static PyMemberDef NetmapRing_members[] = { - {NULL} -}; - - -/*########################## set/get methods #######################*/ - -static PyObject * -NetmapRing_slots_get(NetmapRing *self, void *closure) -{ - if (self->slots == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(self->slots); - - return self->slots; -} - -static int -NetmapRing_slots_set(NetmapRing *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the attribute"); - } else { - PyErr_SetString(PyExc_TypeError, "Cannot modify the attribute"); - } - - return -1; -} - -#define DEFINE_NETMAP_RING_GETSET(field, type, format) \ -static PyObject * \ -NetmapRing_##field##_get(NetmapRing *self, void *closure) \ -{ \ - if (!self->_ring) { \ - Py_RETURN_NONE; \ - } \ - return Py_BuildValue(format, self->_ring->field); \ -} \ - \ -static int \ -NetmapRing_##field##_set(NetmapRing *self, PyObject *value, void *closure) \ -{ \ - long x; \ - if (!self->_ring) { \ - PyErr_SetString(PyExc_TypeError, "Attribute not available"); \ - return -1; \ - } \ - x = PyInt_AsLong(value); \ - if (x == -1 && PyErr_Occurred()) { \ - return -1; \ - } \ - /* Override the 'const' specifier. */ \ - *((type *)&self->_ring->field) = (type)x; \ - return 0; \ -} - -#define DEFINE_NETMAP_RING_GETSET_TV(field) \ -static PyObject * \ -NetmapRing_##field##_get(NetmapRing *self, void *closure) \ -{ \ - if (!self->_ring) { \ - Py_RETURN_NONE; \ - } \ - return Py_BuildValue("I", self->_ring->ts.field); \ -} \ - \ -static int \ -NetmapRing_##field##_set(NetmapRing *self, PyObject *value, void *closure) \ -{ \ - long x; \ - if (!self->_ring) { \ - PyErr_SetString(PyExc_TypeError, "Attribute not available"); \ - return -1; \ - } \ - x = PyInt_AsLong(value); \ - if (x == -1 && PyErr_Occurred()) { \ - return -1; \ - } \ - /* Override the 'const' specifier. */ \ - *((uint32_t *)&self->_ring->ts.field) = (uint32_t)x; \ - return 0; \ -} - -DEFINE_NETMAP_RING_GETSET(num_slots, uint32_t, "I"); -DEFINE_NETMAP_RING_GETSET(nr_buf_size, uint32_t, "I"); -DEFINE_NETMAP_RING_GETSET(ringid, uint16_t, "I"); -DEFINE_NETMAP_RING_GETSET(dir, uint16_t, "I"); -DEFINE_NETMAP_RING_GETSET(head, uint32_t, "I"); -DEFINE_NETMAP_RING_GETSET(cur, uint32_t, "I"); -DEFINE_NETMAP_RING_GETSET(tail, uint32_t, "I"); -DEFINE_NETMAP_RING_GETSET(flags, uint32_t, "I"); -DEFINE_NETMAP_RING_GETSET_TV(tv_sec); -DEFINE_NETMAP_RING_GETSET_TV(tv_usec); - -#define DECLARE_NETMAP_RING_GETSETERS(field) \ - {#field, \ - (getter)NetmapRing_##field##_get, (setter)NetmapRing_##field##_set, \ - "netmap ring " #field " field", \ - NULL} - -static PyGetSetDef NetmapRing_getseters[] = { - DECLARE_NETMAP_RING_GETSETERS(num_slots), - DECLARE_NETMAP_RING_GETSETERS(nr_buf_size), - DECLARE_NETMAP_RING_GETSETERS(ringid), - DECLARE_NETMAP_RING_GETSETERS(dir), - DECLARE_NETMAP_RING_GETSETERS(head), - DECLARE_NETMAP_RING_GETSETERS(cur), - DECLARE_NETMAP_RING_GETSETERS(tail), - DECLARE_NETMAP_RING_GETSETERS(flags), - DECLARE_NETMAP_RING_GETSETERS(tv_sec), - DECLARE_NETMAP_RING_GETSETERS(tv_usec), - {"slots", - (getter)NetmapRing_slots_get, (setter)NetmapRing_slots_set, - "netmap ring slots", - NULL}, - {NULL} /* Sentinel */ -}; - - -static PyObject* -NetmapRing_space(NetmapRing *self) -{ - return Py_BuildValue("i", nm_ring_space(self->_ring)); -} - -static PyObject* -NetmapRing_empty(NetmapRing *self) -{ - if (nm_ring_empty(self->_ring)) { - Py_RETURN_TRUE; - } - - Py_RETURN_FALSE; -} - -static PyMethodDef NetmapRing_methods[] = { - {"space", (PyCFunction)NetmapRing_space, METH_NOARGS, - "Return the number of available ring slots" - }, - {"empty", (PyCFunction)NetmapRing_empty, METH_NOARGS, - "Returns True if the ring is empty (no available slots)" - }, - {NULL} -}; - -/* Definition exported to netmap.c. */ -PyTypeObject NetmapRingType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "netmap.NetmapRing", /*tp_name*/ - sizeof(NetmapRing), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NetmapRing_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NetmapRing_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Netmap interface object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NetmapRing_methods, /* tp_methods */ - NetmapRing_members, /* tp_members */ - NetmapRing_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - NetmapRing_new, /* tp_new */ -}; - diff --git a/private/extra/python/netmap_slot.c b/private/extra/python/netmap_slot.c deleted file mode 100644 index 58946eeb5..000000000 --- a/private/extra/python/netmap_slot.c +++ /dev/null @@ -1,240 +0,0 @@ -#include "netmap_classes.h" - -#include - - -static void -NetmapSlot_dealloc(NetmapSlot* self) -{ - if (self->_view.buf) { - /* XXX Should I free this? I hope self->memoryview - doesn't do it again in its destructor. */ - free(self->_view.shape); - } - Py_XDECREF(self->memoryview); - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject * -NetmapSlot_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NetmapSlot *self; - - self = (NetmapSlot *)type->tp_alloc(type, 0); - if (self != NULL) { - self->_slot = NULL; - self->memoryview = NULL; - memset(&self->_view, 0, sizeof(Py_buffer)); - } - - return (PyObject *)self; -} - -/* Static data for flags pretty printing. */ -static unsigned int ns_flag_values[] = {NS_BUF_CHANGED, NS_REPORT, - NS_FORWARD, NS_NO_LEARN, - NS_INDIRECT, NS_MOREFRAG}; - -static const char *ns_flag_strings[] = {"NsBufChanged", "NsReport", - "NsForward", "NsNoLearn", - "NsIndirect", "NsMorefrag"}; - -static PyObject * -NetmapSlot_repr(NetmapSlot *self) -{ - PyObject *result; - struct netmap_slot *slot = self->_slot; - char flags[256]; - - if (slot == NULL) { - return Py_BuildValue("s", "Invalid NetmapSlot"); - } - - netmap_flags_pretty(slot->flags, flags, sizeof(flags), ns_flag_values, - ns_flag_strings, - sizeof(ns_flag_values)/sizeof(*ns_flag_values)); - - result = PyString_FromFormat( - "buf_idx: %u\n" - "len: %u\n" - "flags: [0x%04x] %s\n" - "ptr: 0x%016x\n", - slot->buf_idx, - slot->len, - slot->flags, - flags, - slot->ptr - ); - - return result; -} - - -static PyMemberDef NetmapSlot_members[] = { - {NULL} -}; - -int -NetmapSlot_build(NetmapSlot *self, void *addr, void *buf) -{ - /* Init the pointer. */ - self->_slot = (struct netmap_slot *)addr; - - /* Populate a Py_buffer struct, which represents a C memory - buffer. */ - memset(&self->_view, 0, sizeof(Py_buffer)); - self->_view.buf = buf; - self->_view.len = self->_slot->len; - self->_view.format = "B"; - self->_view.ndim = 1; - self->_view.shape = malloc(1 * sizeof (Py_ssize_t)); - self->_view.shape[0] = self->_slot->len; - self->_view.itemsize = 1; - - /* Expose the C buffer through a 'memoryview' Python object, - so that Python code can directly access the C buffer. */ - self->memoryview = PyMemoryView_FromBuffer(&self->_view); - if (!self->memoryview) { - return -1; - } - - return 0; -} - -void -NetmapSlot_destroy(NetmapSlot *self) -{ - self->_slot = NULL; - - if (self->_view.buf) { - free(self->_view.shape); - memset(&self->_view, 0, sizeof(Py_buffer)); - } - -/* TODO should destroy self->memoryview */ -} - -/*########################## set/get methods #######################*/ - -static PyObject * -NetmapSlot_memoryview_get(NetmapSlot *self, void *closure) -{ - if (self->memoryview == NULL) { - Py_RETURN_NONE; - } - Py_INCREF(self->memoryview); - - return self->memoryview; -} - -static int -NetmapSlot_memoryview_set(NetmapSlot *self, PyObject *value, void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the attribute"); - } else { - PyErr_SetString(PyExc_TypeError, "Cannot modify the attribute"); - } - - return -1; -} - -#define DEFINE_NETMAP_SLOT_GETSET(field, type, format) \ -static PyObject * \ -NetmapSlot_##field##_get(NetmapSlot *self, void *closure) \ -{ \ - if (!self->_slot) { \ - Py_RETURN_NONE; \ - } \ - return Py_BuildValue(format, self->_slot->field); \ -} \ - \ -static int \ -NetmapSlot_##field##_set(NetmapSlot *self, PyObject *value, void *closure) \ -{ \ - long x; \ - if (!self->_slot) { \ - PyErr_SetString(PyExc_TypeError, "Attribute not available"); \ - return -1; \ - } \ - x = PyInt_AsLong(value); \ - if (x == -1 && PyErr_Occurred()) { \ - return -1; \ - } \ - /* Override the 'const' specifier. */ \ - *((type *)&self->_slot->field) = (type)x; \ - return 0; \ -} - -DEFINE_NETMAP_SLOT_GETSET(buf_idx, uint32_t, "I"); -DEFINE_NETMAP_SLOT_GETSET(len, uint16_t, "I"); -DEFINE_NETMAP_SLOT_GETSET(flags, uint16_t, "I"); -DEFINE_NETMAP_SLOT_GETSET(ptr, uint64_t, "k"); - - -#define DECLARE_NETMAP_SLOT_GETSETERS(field) \ - {#field, \ - (getter)NetmapSlot_##field##_get, (setter)NetmapSlot_##field##_set, \ - "netmap ring " #field " field", \ - NULL} - -static PyGetSetDef NetmapSlot_getseters[] = { - DECLARE_NETMAP_SLOT_GETSETERS(buf_idx), - DECLARE_NETMAP_SLOT_GETSETERS(len), - DECLARE_NETMAP_SLOT_GETSETERS(flags), - DECLARE_NETMAP_SLOT_GETSETERS(ptr), - {"buf", - (getter)NetmapSlot_memoryview_get, (setter)NetmapSlot_memoryview_set, - "netmap buffer memoryview", - NULL}, - {NULL} /* Sentinel */ -}; - - -static PyMethodDef NetmapSlot_methods[] = { - {NULL} -}; - -/* Definition exported to netmap.c. */ -PyTypeObject NetmapSlotType = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "netmap.NetmapSlot", /*tp_name*/ - sizeof(NetmapSlot), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NetmapSlot_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NetmapSlot_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Netmap interface object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NetmapSlot_methods, /* tp_methods */ - NetmapSlot_members, /* tp_members */ - NetmapSlot_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - NetmapSlot_new, /* tp_new */ -}; - diff --git a/private/extra/python/pktgen.py b/private/extra/python/pktgen.py deleted file mode 100644 index 0d944f7d5..000000000 --- a/private/extra/python/pktgen.py +++ /dev/null @@ -1,61 +0,0 @@ -import netmap -import time -import struct -import select - - -def build_packet(): - fmt = '!6s6sH' + '46s' - return struct.pack(fmt, '\xff'*6, '\x00'*6, 0x0800, '\x00'*50) - - -############################## MAIN ########################### -pkt = build_packet() - -# open the netmap device and register an interface -nm = netmap.Netmap() -nm.open() -nfd = nm.getfd() -nm.if_name = 'enp1s0f1' -nm.register() -time.sleep(1) - -# fill in the netmap slots and netmap buffers for tx ring 0 -txr = nm.transmit_rings[0] -num_slots = txr.num_slots -for i in range(num_slots): - txr.slots[i].buf[0:len(pkt)] = pkt - txr.slots[i].len = len(pkt) - - -# transmit at maximum speed until Ctr-C is pressed -cnt = 0 # packet counter -batch = 256 -poller = select.poll() -poller.register(nfd, select.POLLOUT) -t_start = time.time() -try: - cur = txr.cur - while 1: - ready_list = poller.poll(2) - if len(ready_list) == 0: - print "Timeout occurred" - break; - n = txr.tail - cur # avail - if n < 0: - n += num_slots - if n > batch: - n = batch - cur += n - if cur >= num_slots: - cur -= num_slots - txr.cur = txr.head = cur # lazy update txr.cur and txr.head - nm.txsync() - cnt += n -except KeyboardInterrupt: - pass -t_end = time.time() - -print "\nPackets sent: %s, Avg rate %s Kpps" % (cnt, 0.001 * cnt / (t_end - t_start)) - -nm.close() diff --git a/private/extra/python/pktman.py b/private/extra/python/pktman.py deleted file mode 100644 index 9d8aa7ff7..000000000 --- a/private/extra/python/pktman.py +++ /dev/null @@ -1,292 +0,0 @@ -import netmap # our module -import time # time measurements -import select # poll() -import argparse # program argument parsing -import multiprocessing # thread management -import re - -# import scapy suppressing the initial WARNING message -import logging -logging.getLogger("scapy.runtime").setLevel(logging.ERROR) -from scapy.all import Ether, IP, UDP # packet forgery - - -def help_quit(parser): - print "" - parser.print_help() - quit() - - -def build_packet(args, parser): - src = args.src.split(':') - dst = args.dst.split(':') - - # create the payload - base = "Hello from Python" - header_len = 14 + 20 + 8 - data = base * ((args.length-header_len)/len(base) + 1) - data = data[0:args.length-header_len] - - scap = Ether(src = args.srcmac, dst = args.dstmac) - scap = scap / IP(src = src[0], dst = dst[0]) - scap = scap / UDP(sport = int(src[1]), dport = int(dst[1])) - scap = scap / data - - try: - # checksum is computed when calling str(scap), e.g. when the packet is - # assembled - ret = str(scap) - except: - print "Packet parameters are invalid\n" - help_quit(parser) - - if args.dump: - scap.show2() - - return ret - - -def transmit(idx, suffix, args, parser, queue): - # use nm_open() to open the netmap device and register an interface - # using an extended interface name - nmd = netmap.NetmapDesc(args.interface + suffix) - time.sleep(args.wait_link) - - # build the packet that will be transmitted - pkt = build_packet(args, parser) - - # fill in the netmap slots and netmap buffers for tx ring 0 - txr = nmd.transmit_rings[idx] - num_slots = txr.num_slots - for i in range(num_slots): - txr.slots[i].buf[0:len(pkt)] = pkt - txr.slots[i].len = len(pkt) - - # transmit at maximum speed until Ctr-C is pressed - cnt = 0 # packet counter - batch = args.batch - poller = select.poll() - poller.register(nmd.getfd(), select.POLLOUT) - t_start = time.time() - try: - cur = txr.cur - while 1: - ready_list = poller.poll(2) - if len(ready_list) == 0: - print "Timeout occurred" - break; - n = txr.tail - cur # avail - if n < 0: - n += num_slots - if n > batch: - n = batch - cur += n - if cur >= num_slots: - cur -= num_slots - txr.cur = txr.head = cur # lazy update txr.cur and txr.head - nmd.txsync() - cnt += n - except KeyboardInterrupt: - # report the result to the main process - queue.put([cnt, time.time() - t_start]) - pass - - -def receive(idx, suffix, args, parser, queue): - # use nm_open() to open the netmap device and register an interface - # using an extended interface name - nmd = netmap.NetmapDesc(args.interface + suffix) - time.sleep(args.wait_link) - - # select the right ring - rxr = nmd.receive_rings[idx] - num_slots = rxr.num_slots - - cnt = 0 # packet counter - poller = select.poll() - poller.register(nmd.getfd(), select.POLLIN) - - # wait for the first packet - try: - poller.poll() - except KeyboardInterrupt: - # report the result to the main process - queue.put([cnt, None]) - return - - # receive (throwing away everything) until Ctr-C is pressed - t_start = time.time() - try: - cur = rxr.cur - while 1: - ready_list = poller.poll() - if len(ready_list) == 0: - print "Timeout occurred" - break; - n = rxr.tail - cur # avail - if n < 0: - n += num_slots - cur += n - if cur >= num_slots: - cur -= num_slots - rxr.cur = rxr.head = cur # lazy update rxr.cur and rxr.head - cnt += n - except KeyboardInterrupt: - # report the result to the main process - queue.put([cnt, time.time() - t_start]) - pass - - -# How many netmap ring couples has 'ifname'? -def netmap_max_rings(ifname): - if ifname.startswith('netmap:'): - ifname = ifname[7:] - - nm = netmap.Netmap() - nm.open() - nm.if_name = ifname - nm.getinfo() - - return nm.tx_rings - -# extract the (nr_ringid, nr_flags) specified by the extended -# interface name (nm_open() ifname) -def netmap_get_ringid(ifname_ext): - nmd = netmap.NetmapDesc(ifname_ext) - - return nmd.getringid() - -def netmap_remove_ifname_suffix(ifname_ext): - m = re.match(r'\w+:\w+', ifname_ext) - if m == None: - return None - - return m.group(0) - - -############################## MAIN ########################### - -if __name__ == '__main__': - - # functions implemented by this program - handler = dict(); - handler['tx'] = transmit - handler['rx'] = receive - - # program arguments - parser = argparse.ArgumentParser(description = 'Send and receive packet using the netmap API') - parser.add_argument('-i', '--interface', help = 'the interface to register with netmap; ' - 'can be in the form netmap:[] or [], where ' - 'OSNAME is the O.S. name for a network interface (e.g. "eth0"), ' - ' is a valid VALE port name (e.g. "vale18:2") and is an ' - 'optional extension suffix, specified using the nm_open() syntax ' - '(e.g. "^", "-5", "{44", ...)', - required = True) - parser.add_argument('-f', '--function', help = 'the function to perform', - choices = ['tx', 'rx'], default = 'rx') - parser.add_argument('-b', '--batchsize', help = 'number of packets to send with each TXSYNC ' - 'operation', type=int, default = 512, dest = 'batch') - parser.add_argument('-l', '--length', help = 'lenght of the ethernet frame sent', - type = int, default = 60) - parser.add_argument('-D', '--dstmac', help = 'destination MAC of tx packets', - default = 'ff:ff:ff:ff:ff:ff') - parser.add_argument('-S', '--srcmac', help = 'source MAC of tx packets', - default = '00:00:00:00:00:00') - parser.add_argument('-d', '--dst', help = 'destination IP address and UDP port of tx packets', - default = '10.0.0.2:54322', metavar = 'IP:PORT') - parser.add_argument('-s', '--src', help = 'source IP address and UDP port of tx packets', - default = '10.0.0.1:54321', metavar = 'IP:PORT') - parser.add_argument('-w', '--wait-link', help = 'time to wait for the link before starting ' - 'transmit/receive operations (in seconds)', type = int, default = 1) - parser.add_argument('-X', '--dump', help = 'dump the packet', action = 'store_true') - parser.add_argument('-p', '--threads', help = 'number of threads to used for tx/rx ' - 'operations', type = int, default = 1) - # parse the input - args = parser.parse_args() - # print args - - # bound checking - if args.length < 60: - print 'Invalid packet length\n' - help_quit(parser) - - if args.threads < 1: - print 'Invalid number of threads\n' - help_quit(parser) - - try: - # compute 'ifname' removing the suffix from the extended name - # specified by the user - ifname = netmap_remove_ifname_suffix(args.interface) - if ifname == None: - print 'Invalid ifname "%s"' % (args.interface, ) - help_quit(parser) - - # compute 'max_couples', which is the number of tx/rx rings couples to be registered - # according to 'args.interface' - nr_ringid, nr_flags = netmap_get_ringid(args.interface) - if nr_flags in [netmap.RegAllNic, netmap.RegNicSw]: - # ask netmap for the number of available couples - max_couples = netmap_max_rings(args.interface) - suffix_required = True - ringid_offset = 0 - else: - # all the others netmap.Reg* specifies just one couple of rings - max_couples = 1 - suffix_required = False - ringid_offset = nr_ringid - if args.threads > max_couples: - print 'You cannot use more than %s (tx,rx) rings couples with "%s"' % (max_couples, args.interface) - help_quit(parser) - except netmap.error as e: - print e - quit() - - jobs = [] # array of worker processes - queues = [] # array of queues for IPC - for i in range(args.threads): - queue = multiprocessing.Queue() - queues.append(queue) - - # 'i_off' contains the ring idx on which the process below will operate - i_off = i + ringid_offset - # it may also be necessary to add an extension suffix to the interface - # name specified by the user - if suffix_required: - suffix = '-' + str(i_off) - else: - suffix = '' - - # create a new process that will execute the user-selected handler function, - # with the arguments specified by the 'args' tuple - job = multiprocessing.Process(name = 'worker-' + str(i), - target = handler[args.function], - args = (i_off, suffix, args, parser, queue)) - job.deamon = True # ensure work termination - jobs.append(job) - - # start all the workers - for i in range(len(jobs)): - jobs[i].start() - - # Wait for the user pressing Ctrl-C - try: - while 1: - time.sleep(1000) - except KeyboardInterrupt: - pass - - # collect and print the result returned by the workers - tot_rate = 0.0 - for i in range(len(jobs)): - result = queues[i].get() - jobs[i].join() - delta = result[1] - cnt = result[0] - if delta == None: - rate = None - else: - rate = 0.001 * cnt / delta - tot_rate += rate - print '[%d] Packets processed: %s, Avg rate %s Kpps' % (i, cnt, rate) - print 'Total rate: %s' % (tot_rate, ) diff --git a/private/extra/python/setup.py b/private/extra/python/setup.py deleted file mode 100644 index 9a761a650..000000000 --- a/private/extra/python/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -import glob -from distutils.core import setup, Extension - - -netmap_bindings_module = Extension('netmap', - include_dirs = ['../../sys'], - sources = glob.glob('*.c')) - -setup(name = 'NetmapBindings', - version = '11.0', - description = 'python bindings for netmap', - author = 'Vincenzo Maffione', - author_email = 'v.maffione@gmail.com', - url = 'http://info.iet.unipi.it/~luigi/netmap/', - ext_modules = [netmap_bindings_module]) diff --git a/private/extra/python/test.py b/private/extra/python/test.py deleted file mode 100644 index 772505f68..000000000 --- a/private/extra/python/test.py +++ /dev/null @@ -1,14 +0,0 @@ -import netmap - - -# see 'help(netmap)' for documentation -n = netmap.Netmap() -print n -n.open() -n.if_name = 'enp1s0f1' -n.ringid = netmap.HwRing | 3 -n.arg3 = 2 -n.register() -print n -print n.interface -n.close() diff --git a/private/extra/qemu-1.2.0-e1000-mitigation.diff b/private/extra/qemu-1.2.0-e1000-mitigation.diff deleted file mode 100644 index fb93039e9..000000000 --- a/private/extra/qemu-1.2.0-e1000-mitigation.diff +++ /dev/null @@ -1,157 +0,0 @@ -diff -urp ../work-qemu-1.2.0-prod/hw/e1000.c ./hw/e1000.c ---- ../work-qemu-1.2.0-prod/hw/e1000.c 2012-09-05 07:03:06.000000000 -0700 -+++ ./hw/e1000.c 2012-12-01 14:03:17.798698762 -0800 -@@ -24,6 +24,7 @@ - * License along with this library; if not, see . - */ - -+#define MITIGATION - - #include "hw.h" - #include "pci.h" -@@ -127,6 +128,11 @@ typedef struct E1000State_st { - } eecd_state; - - QEMUTimer *autoneg_timer; -+#ifdef MITIGATION -+ QEMUTimer *mit_timer; // handle for the timer -+ uint32_t mit_timer_on; // mitigation timer active -+ uint32_t mit_cause; // pending interrupt cause -+#endif /* MITIGATION */ - } E1000State; - - #define defreg(x) x = (E1000_##x>>2) -@@ -142,6 +148,9 @@ enum { - defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), - defreg(RA), defreg(MTA), defreg(CRCERRS),defreg(VFTA), - defreg(VET), -+#ifdef MITIGATION -+ defreg(RDTR), defreg(RADV), defreg(TADV), defreg(ITR), -+#endif /* MITIGATION */ - }; - - static void -@@ -626,6 +635,66 @@ static uint64_t tx_desc_base(E1000State - return (bah << 32) + bal; - } - -+#ifdef MITIGATION -+/* helper function, 0 means the value is not set */ -+static inline void -+mit_update_delay(uint32_t *cur, uint32_t value) -+{ -+ if (value && (*cur == 0 || value < *cur)) -+ *cur = value; -+} -+ -+/* -+ * If necessary, rearm the timer and post an interrupt. -+ * Called at the end of tx/rx routines (mit_timer_on == 0), -+ * and when the timer fires (mit_timer_on == 1). -+ * We provide a partial implementation of interrupt mitigation, -+ * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for -+ * RADV and TADV, 256ns units for ITR). RDTR is only used to enable RADV; -+ * relative timers based on TIDV and RDTR are not implemented. -+ */ -+static void -+mit_rearm_and_int(void *opaque) -+{ -+ E1000State *s = opaque; -+ uint32_t mit_delay = 0; -+ -+ /* -+ * Clear the flag. It is only set when the callback fires, -+ * and we need to clear it anyways. -+ */ -+ s->mit_timer_on = 0; -+ if (s->mit_cause == 0) /* no events pending, we are done */ -+ return; -+ /* -+ * Compute the next mitigation delay according to pending interrupts -+ * and the current values of RADV (provided RDTR!=0), TADV and ITR. -+ * Then rearm the timer. -+ */ -+ if (s->mit_cause & (E1000_ICR_TXQE | E1000_ICR_TXDW)) -+ mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4); -+ if (s->mac_reg[RDTR] && (s->mit_cause & E1000_ICS_RXT0)) -+ mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4); -+ mit_update_delay(&mit_delay, s->mac_reg[ITR]); -+ -+ if (likely(mit_delay)) { -+ s->mit_timer_on = 1; -+ qemu_mod_timer(s->mit_timer, -+ qemu_get_clock_ns(vm_clock) + mit_delay * 256); -+ } -+ set_ics(s, 0, s->mit_cause); -+ s->mit_cause = 0; -+} -+ -+static void -+mit_set_ics(E1000State *s, uint32_t cause) -+{ -+ s->mit_cause |= cause; -+ if (!s->mit_timer_on) -+ mit_rearm_and_int(s); -+} -+#endif /* MITIGATION */ -+ - static void - start_xmit(E1000State *s) - { -@@ -663,7 +732,11 @@ start_xmit(E1000State *s) - break; - } - } -+#ifdef MITIGATION -+ mit_set_ics(s, cause); -+#else /* !MITIGATION */ - set_ics(s, 0, cause); -+#endif /* !MITIGATION */ - } - - static int -@@ -875,7 +948,11 @@ e1000_receive(NetClientState *nc, const - s->rxbuf_min_shift) - n |= E1000_ICS_RXDMT0; - -+#ifdef MITIGATION -+ mit_set_ics(s, n); -+#else /* !MITIGATION */ - set_ics(s, 0, n); -+#endif /* !MITIGATION */ - - return size; - } -@@ -978,6 +1055,9 @@ static uint32_t (*macreg_readops[])(E100 - getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS), - getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL), - getreg(TDLEN), getreg(RDLEN), -+#ifdef MITIGATION -+ getreg(RDTR), getreg(RADV), getreg(TADV), getreg(ITR), -+#endif /* MITIGATION */ - - [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4, - [GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4, -@@ -994,6 +1074,10 @@ static void (*macreg_writeops[])(E1000St - putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC), - putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH), - putreg(RDBAL), putreg(LEDCTL), putreg(VET), -+#ifdef MITIGATION -+ [RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit, -+ [ITR] = set_16bit, -+#endif /* MITIGATION */ - [TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl, - [TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics, - [TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt, -@@ -1253,6 +1337,11 @@ static int pci_e1000_init(PCIDevice *pci - add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); - - d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d); -+#ifdef MITIGATION -+ d->mit_cause = 0; -+ d->mit_timer_on = 0; -+ d->mit_timer = qemu_new_timer_ns(vm_clock, mit_rearm_and_int, d); -+#endif /* MITIGATION */ - - return 0; - } diff --git a/private/extra/tstmp.diff b/private/extra/tstmp.diff deleted file mode 100644 index 4f7df15b9..000000000 --- a/private/extra/tstmp.diff +++ /dev/null @@ -1,146 +0,0 @@ -Index: dev/netmap/netmap.c -=================================================================== ---- dev/netmap/netmap.c (revision 258360) -+++ dev/netmap/netmap.c (working copy) -@@ -2656,6 +2656,7 @@ - */ - for (i = priv->np_qfirst; want_rx && i < lim_rx; i++) { - kring = &na->rx_rings[i]; -+ TSTMP(1, i, kring->ring->cur, kring->ring->avail,0,0); - if (kring->ring->avail > 0) { - revents |= want_rx; - want_rx = 0; /* also breaks the loop */ -@@ -2663,6 +2664,7 @@ - } - for (i = priv->np_qfirst; want_tx && i < lim_tx; i++) { - kring = &na->tx_rings[i]; -+ TSTMP(2, i, kring->ring->cur, kring->ring->avail,0,0); - if (kring->ring->avail > 0) { - revents |= want_tx; - want_tx = 0; /* also breaks the loop */ -@@ -2705,6 +2707,7 @@ - revents |= POLLERR; - - /* Check avail/call selrecord only if called with POLLOUT */ -+ TSTMP(2, i, kring->ring->cur, kring->ring->avail,0,1); - if (want_tx) { - if (kring->ring->avail > 0) { - /* stop at the first ring. We don't risk -Index: kern/subr_smp.c -=================================================================== ---- kern/subr_smp.c (revision 258360) -+++ kern/subr_smp.c (working copy) -@@ -132,7 +132,63 @@ - } - SYSINIT(cpu_mp_setmaxid, SI_SUB_TUNABLES, SI_ORDER_FIRST, mp_setmaxid, NULL); - -+#ifdef KERN_TIMESTAMP - /* -+ * allocate 1M entries, 32 bytes each. -+ * We then split it among available CPUs. -+ */ -+#define KERN_TIMESTAMP_SIZE (1<<20) -+struct ktstmp_buf_t { uint32_t d[8]; }; -+/* write positions in the buffer */ -+static int ktstmp_index[MAXCPU]; -+ -+/* the buffers */ -+static struct ktstmp_buf_t ktstmp_buf[KERN_TIMESTAMP_SIZE]; -+static int ktstmp_range; -+ -+SYSCTL_NODE(_kern, OID_AUTO, ts, CTLFLAG_RD, 0, "TS buffers"); -+SYSCTL_OPAQUE(_kern_ts, OID_AUTO, idx, CTLFLAG_RD, ktstmp_index, -+ sizeof(ktstmp_index), "LU", "Timestamp indexes"); -+ -+SYSCTL_OPAQUE(_kern_ts, OID_AUTO, data, CTLFLAG_RD, ktstmp_buf, -+ sizeof(ktstmp_buf), "LU", "Timestamp buffers"); -+ -+void _TSTMP(uint32_t p[8]) -+{ -+ int i, pos; -+ i = curcpu; -+ pos = ktstmp_index[i]++; -+ if (pos == ktstmp_range - 1) -+ ktstmp_index[i] = 0; -+ ktstmp_buf[pos + ktstmp_range * i] = *(struct ktstmp_buf_t *)p; -+} -+ -+static void -+tstmp_init(void *dummy) -+{ -+ int i; -+ -+ ktstmp_range = KERN_TIMESTAMP_SIZE / mp_ncpus; -+ -+ for (i = 0; i < mp_ncpus; i++) { -+ struct sysctl_oid *tree; -+ char namebuf[4]; -+ snprintf(namebuf, sizeof(namebuf), "%d", i); -+printf("added child %d\n", i); -+ tree = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_kern_ts), -+ OID_AUTO, namebuf, CTLFLAG_RD, NULL, "Id"); -+ SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tree), OID_AUTO, "idx", -+ CTLFLAG_RD, &ktstmp_index[i], 1, "I-th index"); -+ SYSCTL_ADD_OPAQUE(NULL, SYSCTL_CHILDREN(tree), OID_AUTO, "data", -+ CTLFLAG_RD, &ktstmp_buf[i*ktstmp_range], -+ sizeof(struct ktstmp_buf_t) * ktstmp_range, -+ "LU", "I-th buffer"); -+ } -+} -+SYSINIT(cpu_mp_ts, SI_SUB_CPU, SI_ORDER_ANY, tstmp_init, NULL); -+#endif /* KERN_TIMESTAMP */ -+ -+/* - * Call the MD SMP initialization code. - */ - static void -Index: sys/param.h -=================================================================== ---- sys/param.h (revision 258360) -+++ sys/param.h (working copy) -@@ -344,4 +344,45 @@ - */ - #define __PAST_END(array, offset) (((__typeof__(*(array)) *)(array))[offset]) - -+#ifdef _KERNEL -+ -+/* -+ * We put here the definition of two debugging macros/function which -+ * are very convenient to have available. -+ * TSTMP(a,b,c,d,e,f) can be used to timestamp kernel events with the TSC, -+ * and export them to userland through a sysctl tree debug.timestamp, -+ * which holds one circular buffer per cpu. Events are 32 bytes each, -+ * formatted as TSC; LINE; a; b; c; d; e; f (all 32-bit arguments). -+ * They can be retrieved with something like -+ -+ sysctl -b kern.ts.data | \ -+ hexdump -e '"%15u %15u 0x%08x 0x%08x 0x%08x 0x%08x0x%08x 0x%08x\n"' -+ -+ * The following sysctl variables are used -+ * kern.ts.idx opaque array of MAXCPU indexes -+ * kern.ts.data opaque array of all records -+ * kern.ts.I.idx integer - the next index for cpu I -+ * kern.ts.I.data opaque array of records for cpu I -+ * -+ * The buffer is preallocated (1M entries or so) and statically divided -+ * in blocks, one for each CPUs ( sysctl kern.smp.cpus ). -+ * The dump will report first entries for CPU0, then 1 and so on. -+ * The actual TSTMP code is in kern/subr_smp.c -+ * -+ * The macros must be enabled with "options KERN_TIMESTAMP" in the kernel -+ * config file, otherwise they default to an empty block. -+ */ -+ -+#define KERN_TIMESTAMP -+#ifdef KERN_TIMESTAMP -+extern void _TSTMP(uint32_t p[8]); -+#define TSTMP(a, b, c, d, e, f) do { \ -+ uint32_t p[8] = { __LINE__, rdtsc(), a, b, c, d, e, f}; \ -+ _TSTMP(p); } while (0) -+ -+#else /* !KERN_TIMESTAMP */ -+#define TSTMP(a, b, c, d, e, f) do {} while (0) -+#endif /* !KERN_TIMESTAMP */ -+#endif /* _KERNEL */ -+ - #endif /* _SYS_PARAM_H_ */ diff --git a/private/extra/wireshark-netmap.diff b/private/extra/wireshark-netmap.diff deleted file mode 100644 index 424087da4..000000000 --- a/private/extra/wireshark-netmap.diff +++ /dev/null @@ -1,83 +0,0 @@ -diff -urp ../wireshark-1.11.2/dumpcap.c ./dumpcap.c ---- ../wireshark-1.11.2/dumpcap.c 2013-11-09 09:07:55.000000000 -0800 -+++ ./dumpcap.c 2013-12-04 13:46:02.009528218 -0800 -@@ -23,6 +23,8 @@ - - #include "config.h" - -+#define HAVE_NETMAP -+ - #include - #include /* for exit() */ - #include -@@ -418,6 +420,12 @@ static void report_cfilter_error(capture - - #define MSG_MAX_LENGTH 4096 - -+#ifdef HAVE_NETMAP -+#define NETMAP_WITH_LIBS -+#include -+#endif /* HAVE_NETMAP */ -+ -+ - /* Copied from pcapio.c pcapng_write_interface_statistics_block()*/ - static guint64 - create_timestamp(void) { -@@ -708,6 +716,15 @@ open_capture_device(interface_options *i - "pcap_open() returned %p.", (void *)pcap_h); - } else - #endif -+ -+#ifdef HAVE_NETMAP -+ if ((pcap_h = (pcap_t *)nm_open(interface_opts->name, -+ getenv("NETMAP_RING_ID"), 0, 0)) || errno > 0 ) { -+ printf("--- opening netmap %s gives %p\n", interface_opts->name, pcap_h); -+ /* can return NULL if valid name but error setting netmap */ -+ return pcap_h; -+ } else -+#endif /* HAVE_NETMAP */ - { - /* - * If we're not opening a remote device, use pcap_create() and -@@ -2740,6 +2757,11 @@ capture_loop_open_input(capture_options - - /* XXX - will this work for tshark? */ - #ifdef MUST_DO_SELECT -+#ifdef HAVE_NETMAP -+ if (IS_NETMAP_DESC(pcap_opts->pcap_h)) { -+ pcap_opts->pcap_fd = NETMAP_FD(pcap_opts->pcap_h); -+ } else -+#endif /* HAVE_NETMAP */ - if (!pcap_opts->from_cap_pipe) { - #ifdef HAVE_PCAP_GET_SELECTABLE_FD - pcap_opts->pcap_fd = pcap_get_selectable_fd(pcap_opts->pcap_h); -@@ -2823,6 +2845,12 @@ capture_loop_init_filter(pcap_t *pcap_h, - - /* capture filters only work on real interfaces */ - if (cfilter && !from_cap_pipe) { -+#ifdef HAVE_NETMAP -+ if (IS_NETMAP_DESC(pcap_h)) { -+ printf("no filters on netmap\n"); -+ return INITFILTER_NO_ERROR; // pretend ok -+ } -+#endif /* HAVE_NETMAP */ - /* A capture filter was specified; set it up. */ - if (!compile_capture_filter(name, pcap_h, &fcode, cfilter)) { - /* Treat this specially - our caller might try to compile this -@@ -3089,6 +3117,16 @@ capture_loop_dispatch(loop_data *ld, - * processing immediately, rather than processing all packets - * in a batch before quitting. - */ -+#ifdef HAVE_NETMAP -+ if (IS_NETMAP_DESC(pcap_opts->pcap_h)) { -+ pcap_handler cb = use_threads ? -+ capture_loop_queue_packet_cb : -+ capture_loop_write_packet_cb ; -+ // printf("dispatch to netmap\n"); -+ inpkts = nm_dispatch((struct nm_desc *)(pcap_opts->pcap_h), -+ 1, (nm_cb_t)cb, (u_char *)pcap_opts); -+ } else -+#endif /* HAVE_NETMAP */ - if (use_threads) { - inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_queue_packet_cb, (u_char *)pcap_opts); - } else { diff --git a/private/netmap-drop-2.diff b/private/netmap-drop-2.diff deleted file mode 100644 index 91ea6d4c6..000000000 --- a/private/netmap-drop-2.diff +++ /dev/null @@ -1,435 +0,0 @@ -Index: /home/luigi/FreeBSD/head/sys/netinet/udp_usrreq.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/netinet/udp_usrreq.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/netinet/udp_usrreq.c (working copy) -@@ -941,6 +941,7 @@ - #define UH_WLOCKED 2 - #define UH_RLOCKED 1 - #define UH_UNLOCKED 0 -+extern int netmap_drop; // XXX - static int - udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *td) -@@ -956,6 +957,7 @@ - int unlock_udbinfo; - u_char tos; - -+ if (netmap_drop == 32) { m_freem(m); if (control) m_freem(control); return 0; } // XXX drop - /* - * udp_output() may need to temporarily bind or connect the current - * inpcb. As such, we don't know up front whether we will need the -@@ -1082,10 +1084,12 @@ - error = EINVAL; - goto release; - } -+ if (netmap_drop == 33) { error = 0; goto release; } // XXX drop - error = in_pcbbind_setup(inp, (struct sockaddr *)&src, - &laddr.s_addr, &lport, td->td_ucred); - if (error) - goto release; -+ if (netmap_drop == 34) { error = 0; goto release; } // XXX drop - } - - /* -@@ -1107,9 +1111,11 @@ - * Jail may rewrite the destination address, so let it do - * that before we use it. - */ -+ if (netmap_drop == 35) { error = 0; goto release; } // XXX drop - error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); - if (error) - goto release; -+ if (netmap_drop == 36) { error = 0; goto release; } // XXX drop - - /* - * If a local address or port hasn't yet been selected, or if -@@ -1170,6 +1176,7 @@ - } - } - -+ if (netmap_drop == 37) { error = 0; goto release; } // XXX drop - /* - * Calculate data length and get a mbuf for UDP, IP, and possible - * link-layer headers. Immediate slide the data pointer back forward -@@ -1240,6 +1247,7 @@ - INP_HASH_WUNLOCK(&V_udbinfo); - else if (unlock_udbinfo == UH_RLOCKED) - INP_HASH_RUNLOCK(&V_udbinfo); -+ if (netmap_drop == 31) { error = 0; goto release; } // XXX - error = ip_output(m, inp->inp_options, NULL, ipflags, - inp->inp_moptions, inp); - if (unlock_udbinfo == UH_WLOCKED) -@@ -1585,6 +1593,7 @@ - { - struct inpcb *inp; - -+ if (netmap_drop == 30) { m_freem(m); if (control) m_freem(control); return 0; } // XXX - inp = sotoinpcb(so); - KASSERT(inp != NULL, ("udp_send: inp == NULL")); - return (udp_output(inp, m, addr, control, td)); -Index: /home/luigi/FreeBSD/head/sys/netinet/ip_output.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/netinet/ip_output.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/netinet/ip_output.c (working copy) -@@ -98,7 +98,7 @@ - - extern int in_mcast_loop; - extern struct protosw inetsw[]; -- -+extern int netmap_drop; - /* - * IP output. The packet in mbuf chain m contains a skeletal IP - * header (with len, off, ttl, proto, tos, src, dst). -@@ -135,6 +135,7 @@ - #endif - M_ASSERTPKTHDR(m); - -+ if (netmap_drop == 50) {goto bad; } // XXX - if (inp != NULL) { - INP_LOCK_ASSERT(inp); - M_SETFIB(m, inp->inp_inc.inc_fibnum); -@@ -164,6 +165,7 @@ - flow_to_route(fle, ro); - } - #endif -+ if (netmap_drop == 51) {goto bad; } // XXX - - if (opt) { - int len = 0; -@@ -303,6 +305,7 @@ - else - isbroadcast = in_broadcast(dst->sin_addr, ifp); - } -+ if (netmap_drop == 56) {goto bad; } // XXX - /* - * Calculate MTU. If we have a route that is up, use that, - * otherwise use the interface's MTU. -@@ -474,6 +477,7 @@ - } - - sendit: -+ if (netmap_drop == 52) {goto bad; } // XXX - #ifdef IPSEC - switch(ip_ipsec_output(&m, inp, &flags, &error)) { - case 1: -@@ -501,6 +505,7 @@ - if (!PFIL_HOOKED(&V_inet_pfil_hook)) - goto passout; - -+ if (netmap_drop == 53) {goto bad; } // XXX - /* Run through list of hooks for output packets. */ - odst.s_addr = ip->ip_dst.s_addr; - error = pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, inp); -@@ -570,6 +575,7 @@ - } - - passout: -+ if (netmap_drop == 54) {goto bad; } // XXX - /* 127/8 must not appear on wire - RFC1122. */ - if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || - (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { -@@ -628,6 +634,7 @@ - * to avoid confusing lower layers. - */ - m->m_flags &= ~(M_PROTOFLAGS); -+ if (netmap_drop == 55) {goto bad; } // XXX - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, ro); - goto done; -Index: /home/luigi/FreeBSD/head/sys/kern/uipc_mbuf.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/kern/uipc_mbuf.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/kern/uipc_mbuf.c (working copy) -@@ -84,6 +84,33 @@ - &m_defragrandomfailures, 0, ""); - #endif - -+int copydata_flags; -+SYSCTL_DECL(_dev_netmap); -+SYSCTL_INT(_dev_netmap, OID_AUTO, copy_flags, CTLFLAG_RW, ©data_flags, 0, ""); -+ -+static inline void -+pkt_copy(void *_src, void *_dst, int l) -+{ -+ uint64_t *src = _src; -+ uint64_t *dst = _dst; -+#define likely(x) __builtin_expect(!!(x), 1) -+#define unlikely(x) __builtin_expect(!!(x), 0) -+ if (unlikely(l >= 1024)) { -+ bcopy(src, dst, l); -+ return; -+ } -+ for (; l > 0; l-=64) { -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ *dst++ = *src++; -+ } -+} -+ - /* - * Allocate a given length worth of mbufs and/or clusters (whatever fits - * best) and return a pointer to the top of the allocated chain. If an -@@ -807,6 +834,10 @@ - - KASSERT(off >= 0, ("m_copydata, negative off %d", off)); - KASSERT(len >= 0, ("m_copydata, negative len %d", len)); -+if (copydata_flags && off == 0 && m->m_next == NULL) { -+ pkt_copy(mtod(m, caddr_t), cp, len); -+ return; -+} - while (off > 0) { - KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain")); - if (off < m->m_len) -Index: /home/luigi/FreeBSD/head/sys/kern/uipc_syscalls.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/kern/uipc_syscalls.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/kern/uipc_syscalls.c (working copy) -@@ -678,6 +678,7 @@ - return (error); - } - -+extern int netmap_drop; // XXX - static int - sendit(td, s, mp, flags) - struct thread *td; -@@ -694,6 +695,7 @@ - return (ECAPMODE); - #endif - -+ if (netmap_drop == 21) return 0; // XXX - if (mp->msg_name != NULL) { - error = getsockaddr(&to, mp->msg_name, mp->msg_namelen); - if (error) { -@@ -704,6 +706,7 @@ - } else { - to = NULL; - } -+ if (netmap_drop == 22) { error = 0; goto bad; } // XXX - - if (mp->msg_control) { - if (mp->msg_controllen < sizeof(struct cmsghdr) -@@ -733,6 +736,7 @@ - control = NULL; - } - -+ if (netmap_drop == 23) {error =0; goto bad; } // XXX - error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE); - - bad: -@@ -765,6 +769,7 @@ - rights = CAP_WRITE; - if (mp->msg_name != NULL) - rights |= CAP_CONNECT; -+ if (netmap_drop == 24) { return 0; } // XXX - error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL); - if (error) - return (error); -@@ -805,6 +810,7 @@ - ktruio = cloneuio(&auio); - #endif - len = auio.uio_resid; -+ if (netmap_drop == 25) { error = 0; goto bad; } // XXX - error = sosend(so, mp->msg_name, &auio, 0, control, flags, td); - if (error) { - if (auio.uio_resid != len && (error == ERESTART || -@@ -847,6 +853,7 @@ - struct iovec aiov; - int error; - -+ if (netmap_drop == 20) return 0; - msg.msg_name = uap->to; - msg.msg_namelen = uap->tolen; - msg.msg_iov = &aiov; -Index: /home/luigi/FreeBSD/head/sys/dev/ixgbe/ixgbe.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/dev/ixgbe/ixgbe.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/dev/ixgbe/ixgbe.c (working copy) -@@ -338,6 +338,7 @@ - * that extend the standard driver. - */ - #include -+extern int netmap_flags, netmap_drop; // XXX - #endif /* DEV_NETMAP */ - - /********************************************************************* -@@ -796,11 +797,14 @@ - struct tx_ring *txr; - int i = 0, err = 0; - -+ if (netmap_drop == 90) {m_freem(m); return 0; } // XXX - /* Which queue to use */ -+ if (netmap_flags & 4 && !(m->m_flags & M_FLOWID)) printf("%s %d no flowid curcpu %d\n", __func__, __LINE__, curcpu); - if ((m->m_flags & M_FLOWID) != 0) - i = m->m_pkthdr.flowid % adapter->num_queues; - else - i = curcpu % adapter->num_queues; -+ if (netmap_flags & 32) i = 0; // XXX - - txr = &adapter->tx_rings[i]; - que = &adapter->queues[i]; -@@ -809,6 +813,7 @@ - err = ixgbe_mq_start_locked(ifp, txr, m); - IXGBE_TX_UNLOCK(txr); - } else { -+ if (netmap_drop == 92) {m_freem(m); return 0; } // XXX - err = drbr_enqueue(ifp, txr->br, m); - taskqueue_enqueue(que->tq, &txr->txq_task); - } -@@ -842,6 +847,7 @@ - - /* Process the queue */ - while (next != NULL) { -+ if (netmap_drop == 91) {m_freem(next); err = 0; goto cont; } // XXX - if ((err = ixgbe_xmit(txr, &next)) != 0) { - if (next != NULL) - err = drbr_enqueue(ifp, txr->br, next); -@@ -854,6 +860,7 @@ - break; - if (txr->tx_avail < IXGBE_TX_OP_THRESHOLD) - ixgbe_txeof(txr); -+cont: // XXX - next = drbr_dequeue(ifp, txr->br); - } - -@@ -1764,6 +1771,7 @@ - txbuf = &txr->tx_buffers[first]; - map = txbuf->map; - -+ if (netmap_drop == 93) {m_freem(m_head); return 0; } // XXX - /* - * Map the packet for DMA. - */ -@@ -1800,6 +1808,7 @@ - return (error); - } - } -+ if (netmap_drop == 94) {m_freem(*m_headp); return 0; } // XXX - - /* Make certain there are enough descriptors */ - if (nsegs > txr->tx_avail - 2) { -Index: /home/luigi/FreeBSD/head/sys/net/pfil.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/net/pfil.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/net/pfil.c (working copy) -@@ -64,6 +64,8 @@ - VNET_DEFINE(struct rmlock, pfil_lock); - #define V_pfil_lock VNET(pfil_lock) - -+extern int netmap_drop; -+ - /* - * pfil_run_hooks() runs the specified packet filter hooks. - */ -@@ -75,8 +77,18 @@ - struct packet_filter_hook *pfh; - struct mbuf *m = *mp; - int rv = 0; -- -+if (netmap_drop == 70) return 0; -+ - PFIL_RLOCK(ph, &rmpt); -+if (netmap_drop == 71) { -+ int num=0, act=0; -+ for (pfh = pfil_hook_get(dir, ph); pfh != NULL; -+ pfh = TAILQ_NEXT(pfh, pfil_link)) { -+ num++; -+ if (pfh->pfil_func != NULL) act++; -+ } -+ printf("dir %d total %d active %d\n", dir, num, act); -+} - KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0")); - for (pfh = pfil_hook_get(dir, ph); pfh != NULL; - pfh = TAILQ_NEXT(pfh, pfil_link)) { -Index: /home/luigi/FreeBSD/head/sys/net/if_ethersubr.c -=================================================================== ---- /home/luigi/FreeBSD/head/sys/net/if_ethersubr.c (revision 244673) -+++ /home/luigi/FreeBSD/head/sys/net/if_ethersubr.c (working copy) -@@ -141,6 +141,14 @@ - - #define senderr(e) do { error = (e); goto bad;} while (0) - -+#if defined(INET) || defined(INET6) -+int -+ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared); -+static VNET_DEFINE(int, ether_ipfw); -+#define V_ether_ipfw VNET(ether_ipfw) -+#endif -+ -+extern int netmap_flags, netmap_drop; // XXX - /* - * Ethernet output routine. - * Encapsulate a packet of type family for the local net. -@@ -161,6 +169,7 @@ - int loop_copy = 1; - int hlen; /* link layer header length */ - -+ if (netmap_drop == 80) { error = 0; goto bad; } // XXX - if (ro != NULL) { - if (!(m->m_flags & (M_BCAST | M_MCAST))) - lle = ro->ro_lle; -@@ -183,6 +192,7 @@ - switch (dst->sa_family) { - #ifdef INET - case AF_INET: -+if (netmap_flags & 8 && lle == NULL) printf("%s %d ro %p rt0 %p no lle\n", __FUNCTION__, __LINE__, ro, rt0); - if (lle != NULL && (lle->la_flags & LLE_VALID)) - memcpy(edst, &lle->ll_addr.mac16, sizeof(edst)); - else -@@ -309,6 +319,7 @@ - return (if_simloop(ifp, m, dst->sa_family, 0)); - } - -+ if (netmap_drop == 81) { error = 0; goto bad; } // XXX - /* - * Add local net header. If no space in first mbuf, - * allocate another. -@@ -317,9 +328,12 @@ - if (m == NULL) - senderr(ENOBUFS); - eh = mtod(m, struct ether_header *); -+ if (netmap_drop == 87) { error = 0; goto bad; } // XXX - (void)memcpy(&eh->ether_type, &type, - sizeof(eh->ether_type)); -+ if (netmap_drop == 88) { error = 0; goto bad; } // XXX - (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); -+ if (netmap_drop == 89) { error = 0; goto bad; } // XXX - if (hdrcmplt) - (void)memcpy(eh->ether_shost, esrc, - sizeof(eh->ether_shost)); -@@ -327,6 +341,7 @@ - (void)memcpy(eh->ether_shost, IF_LLADDR(ifp), - sizeof(eh->ether_shost)); - -+ if (netmap_drop == 82) { error = 0; goto bad; } // XXX - /* - * If a simplex interface, and the packet is being sent to our - * Ethernet address or a broadcast address, loopback a copy. -@@ -379,6 +394,7 @@ - } - } - -+ if (netmap_drop == 83) { error = 0; goto bad; } // XXX - /* - * Bridges require special output handling. - */ -@@ -406,6 +422,7 @@ - return (0); - } - -+ if (netmap_drop == 84) { error = 0; goto bad; } // XXX - /* Continue with link-layer output */ - return ether_output_frame(ifp, m); - } -@@ -431,6 +448,7 @@ - return (0); - } - -+ if (netmap_drop == 85) { m_freem(m); return 0; } // XXX - /* - * Queue message on interface, update output statistics if - * successful, and start output if interface not yet active. diff --git a/private/qemu/PICOBSD b/private/qemu/PICOBSD deleted file mode 100644 index 713493120..000000000 --- a/private/qemu/PICOBSD +++ /dev/null @@ -1,154 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/PICOBSD 201065 2009-12-27 22:34:31Z luigi $ -# A configuration file to run tests on qemu. -# We disable SMP because it does not work well with qemu, and set HZ=1000 -# to avoid it being overridden. -# -# Line starting with #PicoBSD contains PicoBSD build parameters -#marker def_sz init MFS_inodes floppy_inodes -#PicoBSD 26000 init 8192 32768 -options MD_ROOT_SIZE=26000 # same as def_sz - -hints "PICOBSD.hints" - -# values accessible through getenv() -# env "PICOBSD.env" - -#cpu I486_CPU -#cpu I586_CPU -cpu I686_CPU -ident PICOBSD - -options SMP -device acpi # more frequencies ? -device apic # kern_et ? -device cpufreq - -option INVARIANTS -option INVARIANT_SUPPORT -options SCHED_ULE # mandatory to have one scheduler -options PREEMPTION -#options MATH_EMULATE #Support for x87 emulation -options INET #InterNETworking -options INET6 -options FFS #Berkeley Fast Filesystem -#options BOOTP #Use BOOTP to obtain IP address/hostname -options MD_ROOT #MD is a potential root device - -#options NFS #Network Filesystem -#options NFS_ROOT #NFS usable as root device, NFS required - -#options MSDOSFS #MSDOS Filesystem -#options CD9660 #ISO 9660 Filesystem -#options CD9660_ROOT #CD-ROM usable as root, CD9660 required -#options DEVFS #Device Filesystem -#options PROCFS #Process filesystem -options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] - -options KDB -options DDB - -options IPFIREWALL -options IPFIREWALL_DEFAULT_TO_ACCEPT -options IPDIVERT # divert (for natd) - -# Support for bridging and bandwidth limiting -options DUMMYNET -options IPFIREWALL_NAT -options LIBALIAS -device if_bridge -# Running with less than 1000 seems to give poor timing on -# qemu, so we set HZ explicitly. -options HZ=1000 - -device random # used by ssh -device pci - -# Floppy drives -device fdc - -# ATA and ATAPI devices -#device ata -#device atadisk # ATA disk drives -#device atapicd # ATAPI CDROM drives -#options ATA_STATIC_ID #Static device numbering - -# atkbdc0 controls both the keyboard and the PS/2 mouse -device atkbdc # At keyboard controller -device atkbd -#device psm # do we need the mouse ?? - -device vga # VGA screen - -# syscons is the default console driver, resembling an SCO console -device sc - -# Serial (COM) ports -device uart - -# Audio support -#device pcm - -# PCCARD (PCMCIA) support -#device card # pccard bus -#device pcic # PCMCIA bridge - -# Parallel port -#device ppc -#device ppbus # Parallel port bus (required) -#device lpt # Printer -#device plip # TCP/IP over parallel -#device ppi # Parallel port interface device - -# -# The following Ethernet NICs are all PCI devices. -# -device miibus -device ixgbe -device oce -device cxgbe # chelsio -device firmware # needed for chelsio ? -device em -device bge -#device fxp # Intel EtherExpress PRO/100B (82557, 82558) -device nfe # nVidia nForce MCP on-board Ethernet -#device xl # 3Com -device rl # RealTek 8129/8139 -device re # RealTek 8139C+/8169/8169S/8110S -device sis # National/SiS -device dc # DEC/Intel 21143 and various workalikes -device ed - -device loop # Network loopback -device ether # Ethernet support -device tun # Packet tunnel. -device pty # Pseudo-ttys (telnet etc) -device md # Memory "disks" -#device gif 4 # IPv6 and IPv4 tunneling -#device faith 1 # IPv6-to-IPv4 relaying (translation) -device tap - -#-- usb support -device uhci # UHCI PCI->USB interface -device ohci # OHCI PCI->USB interface -device ehci # EHCI PCI->USB interface (USB 2.0) -device usb -device uhid # "Human Interface Devices" -device ukbd # Keyboard -device scbus -device da -device umass # Disks/Mass storage - Requires scbus and da -device ums # Mouse - - -device kbdmux -options KBD_INSTALL_CDEV - -#options VIMAGE - -#options DEVICE_POLLING - -# The `bpf' device enables the Berkeley Packet Filter. -# Be aware of the administrative consequences of enabling this! -device bpf # Berkeley packet filter -device netmap diff --git a/private/qemu/PICOBSD.amd64 b/private/qemu/PICOBSD.amd64 deleted file mode 100644 index 02d7678e6..000000000 --- a/private/qemu/PICOBSD.amd64 +++ /dev/null @@ -1,193 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/PICOBSD 201065 2009-12-27 22:34:31Z luigi $ -# A configuration file to run tests on qemu. -# This file is specific for AMD64 -# -# Line starting with #PicoBSD contains PicoBSD build parameters -#marker def_sz init MFS_inodes floppy_inodes -#PicoBSD 48000 init 8192 32768 -options MD_ROOT_SIZE=48000 # same as def_sz - -hints "PICOBSD.hints" - -# values accessible through getenv() -#env "PICOBSD.env" -#maxusers 10000 # large tables - -cpu HAMMER # I686_CPU -ident PICOBSD - -options NO_SWAPPING - -# compile with unnamed unions -makeoptions COPTFLAGS="-fms-extensions" - -#makeoptions "CCOPTS=-O3 -Wall -Werror" -#makeoptions COPTFLAGS="-O2 -Wall" # -Werror -#makeoptions CWARNFLAGS="-Wunused -Wuninitialized -Wno-pointer-sign -Wredundant-decls -fformat-extensions" -# clang may require more e.g. -Wno-tautological-compare - -#makeoptions WARNS=5 -options SMP -device acpi # more frequencies ? -# device apic # not for amd64 -device cpufreq - -#option INVARIANTS -#option INVARIANT_SUPPORT -#options WITNESS - -# XXX i find that SCHED_4BSD+PREEMPTION seems to work better. -#options SCHED_ULE # mandatory to have one scheduler -options SCHED_4BSD # mandatory to have one scheduler -options PREEMPTION -#options MATH_EMULATE #Support for x87 emulation -options INET #InterNETworking -#options INET6 -options FFS #Berkeley Fast Filesystem -#options BOOTP #Use BOOTP to obtain IP address/hostname -options MD_ROOT #MD is a potential root device - -#options NFS #Network Filesystem -#options NFS_ROOT #NFS usable as root device, NFS required - -#options MSDOSFS #MSDOS Filesystem -#options CD9660 #ISO 9660 Filesystem -#options CD9660_ROOT #CD-ROM usable as root, CD9660 required -#options DEVFS #Device Filesystem -#options PROCFS #Process filesystem -options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] - -options HWPMC_HOOKS -device hwpmc - -options KDB -options DDB - -#--- for fast networking, remove ipfw -options IPFIREWALL -options IPFIREWALL_DEFAULT_TO_ACCEPT -#options IPDIVERT # divert (for natd) - -# Support for bridging and bandwidth limiting -options DUMMYNET -#options IPFIREWALL_NAT -#options LIBALIAS -#device if_bridge - -# Running with less than 1000 seems to give poor timing on -# qemu, so we set HZ explicitly. -options HZ=4000 # XXX use 4000 for good polling - -device random # used by ssh -device pci - -# Floppy drives -device fdc - -# ATA and ATAPI devices -#device ata -#device atadisk # ATA disk drives -#device atapicd # ATAPI CDROM drives -#options ATA_STATIC_ID #Static device numbering - -# atkbdc0 controls both the keyboard and the PS/2 mouse -device atkbdc # At keyboard controller -device atkbd -#device psm # do we need the mouse ?? - -device vga # VGA screen - -# syscons is the default console driver, resembling an SCO console -device sc - -# Serial (COM) ports -device uart - -# Audio support -#device pcm - -# PCCARD (PCMCIA) support -#device card # pccard bus -#device pcic # PCMCIA bridge - -# -# The following Ethernet NICs are all PCI devices. -# -device miibus -#device ofed -#device mlx4ib -# device ipoib -#device sdp -#device mlxen -#device mthca - -device ixgbe -#device bxe # broadcom 10G -#device oce # emulex -#device sfxge # solarflare -#device cxgbe # chelsio -device firmware # needed for chelsio ? -device em -device igb -device bge -#device fxp # Intel EtherExpress PRO/100B (82557, 82558) -device nfe # nVidia nForce MCP on-board Ethernet -#device xl # 3Com -device rl # RealTek 8129/8139 -device re # RealTek 8139C+/8169/8169S/8110S -device sis # National/SiS -device dc # DEC/Intel 21143 and various workalikes -device ed - -device loop # Network loopback -device ether # Ethernet support -device tun # Packet tunnel. -device pty # Pseudo-ttys (telnet etc) -device md # Memory "disks" -#device gif 4 # IPv6 and IPv4 tunneling -#device faith 1 # IPv6-to-IPv4 relaying (translation) -device tap - -#-- usb support -device uhci # UHCI PCI->USB interface -device ohci # OHCI PCI->USB interface -device ehci # EHCI PCI->USB interface (USB 2.0) -device usb -device uhid # "Human Interface Devices" -device ukbd # Keyboard -device scbus -device da -device umass # Disks/Mass storage - Requires scbus and da -device ums # Mouse -#device hwpmc # not good as compiled in. - -device virtio #XXX for virtio -device virtio_pci -device vtnet #XXX for virtio - -device kbdmux -options KBD_INSTALL_CDEV - -#options VIMAGE - -# The `bpf' device enables the Berkeley Packet Filter. -# Be aware of the administrative consequences of enabling this! -device bpf # Berkeley packet filter -device netmap -options DEVICE_POLLING -options FLOWTABLE - -# options NETLINK - -#--- diskless support - -options NFSCL -#options BOOTP # compile relevant files (also need NFSCL or NFSCLIENT) -#options NFS_ROOT # compile nfs_diskless.c -#options BOOTP_NFSROOT # request root name from server ? -#options BOOTP_COMPAT # accept replies from 0.0.0.0 (ip_input.c) -#options BOOTP_WIRED_TO=fxp0 - -# BOOTP_NO_DHCP only bootp -# BOOTP_FORCE_DHCP only dhcp diff --git a/private/qemu/PICOBSD.arm b/private/qemu/PICOBSD.arm deleted file mode 100644 index 227b85d55..000000000 --- a/private/qemu/PICOBSD.arm +++ /dev/null @@ -1,141 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/PICOBSD 201065 2009-12-27 22:34:31Z luigi $ -# A configuration file to run tests on qemu. -# We disable SMP because it does not work well with qemu, and set HZ=1000 -# to avoid it being overridden. -# -# Line starting with #PicoBSD contains PicoBSD build parameters -#marker def_sz init MFS_inodes floppy_inodes -#PicoBSD 26000 init 8192 32768 -options MD_ROOT_SIZE=26000 # same as def_sz - -hints "PICOBSD.hints" - -# values accessible through getenv() -# env "PICOBSD.env" - -#cpu I486_CPU -#cpu I586_CPU -cpu CPU_ARM9E -makeoptions CONF_CFLAGS="-march=armv5te" - -ident PICOBSD - -options SMP -#device acpi # more frequencies ? -device cpufreq - -option INVARIANTS -option INVARIANT_SUPPORT -options SCHED_ULE # mandatory to have one scheduler -options PREEMPTION -#options MATH_EMULATE #Support for x87 emulation -options INET #InterNETworking -options INET6 -options FFS #Berkeley Fast Filesystem -#options BOOTP #Use BOOTP to obtain IP address/hostname -options MD_ROOT #MD is a potential root device - -#options NFS #Network Filesystem -#options NFS_ROOT #NFS usable as root device, NFS required - -#options MSDOSFS #MSDOS Filesystem -#options CD9660 #ISO 9660 Filesystem -#options CD9660_ROOT #CD-ROM usable as root, CD9660 required -#options DEVFS #Device Filesystem -#options PROCFS #Process filesystem -options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] - -options KDB -options DDB - -options IPFIREWALL -options IPFIREWALL_DEFAULT_TO_ACCEPT -options IPDIVERT # divert (for natd) - -# Support for bridging and bandwidth limiting -options DUMMYNET -options IPFIREWALL_NAT -options LIBALIAS -device if_bridge -# Running with less than 1000 seems to give poor timing on -# qemu, so we set HZ explicitly. -options HZ=1000 - -device random # used by ssh -device pci - -# ATA and ATAPI devices -#device ata -#device atadisk # ATA disk drives -#device atapicd # ATAPI CDROM drives -#options ATA_STATIC_ID #Static device numbering - -# Serial (COM) ports -device uart - -# Audio support -#device pcm - -# PCCARD (PCMCIA) support -#device card # pccard bus -#device pcic # PCMCIA bridge - -# Parallel port -#device ppc -#device ppbus # Parallel port bus (required) -#device lpt # Printer -#device plip # TCP/IP over parallel -#device ppi # Parallel port interface device - -# -# The following Ethernet NICs are all PCI devices. -# -device miibus -device ixgbe -device cxgbe # chelsio -device sfxge # solarflare -device firmware # needed for chelsio ? -device em -device bge -#device fxp # Intel EtherExpress PRO/100B (82557, 82558) -#device xl # 3Com -device rl # RealTek 8129/8139 -device re # RealTek 8139C+/8169/8169S/8110S -device sis # National/SiS -device dc # DEC/Intel 21143 and various workalikes -device ed - -device loop # Network loopback -device ether # Ethernet support -device tun # Packet tunnel. -device pty # Pseudo-ttys (telnet etc) -device md # Memory "disks" -#device gif 4 # IPv6 and IPv4 tunneling -#device faith 1 # IPv6-to-IPv4 relaying (translation) -device tap - -#-- usb support -device uhci # UHCI PCI->USB interface -device ohci # OHCI PCI->USB interface -device ehci # EHCI PCI->USB interface (USB 2.0) -device usb -device uhid # "Human Interface Devices" -device ukbd # Keyboard -device scbus -device da -device umass # Disks/Mass storage - Requires scbus and da -device ums # Mouse - - -device kbdmux -options KBD_INSTALL_CDEV - -#options VIMAGE - -#options DEVICE_POLLING - -# The `bpf' device enables the Berkeley Packet Filter. -# Be aware of the administrative consequences of enabling this! -device bpf # Berkeley packet filter -#device netmap diff --git a/private/qemu/PICOBSD.hints b/private/qemu/PICOBSD.hints deleted file mode 100644 index cdb038ba4..000000000 --- a/private/qemu/PICOBSD.hints +++ /dev/null @@ -1,39 +0,0 @@ -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/PICOBSD.hints 201065 2009-12-27 22:34:31Z luigi $ -hint.fdc.0.at="isa" -hint.fdc.0.port="0x3F0" -hint.fdc.0.irq="6" -hint.fdc.0.drq="2" -hint.fd.0.at="fdc0" -hint.fd.0.drive="0" -hint.ata.0.at="isa" -hint.ata.0.port="0x1F0" -hint.ata.0.irq="14" -hint.ata.1.at="isa" -hint.ata.1.port="0x170" -hint.ata.1.irq="15" -hint.atkbdc.0.at="isa" -hint.atkbdc.0.port="0x060" -hint.atkbd.0.at="atkbdc" -hint.atkbd.0.irq="1" -hint.psm.0.at="atkbdc" -hint.psm.0.irq="12" -hint.vga.0.at="isa" -hint.sc.0.at="isa" -hint.npx.0.at="nexus" -hint.npx.0.port="0x0F0" -hint.npx.0.irq="13" -hint.uart.0.at="isa" -hint.uart.0.port="0x3F8" -hint.uart.0.flags="0x10" -hint.uart.0.irq="4" -hint.uart.1.at="isa" -hint.uart.1.port="0x2F8" -hint.uart.1.irq="3" -hint.ed.0.at="isa" -hint.ed.0.port="0x280" -hint.ed.0.irq="5" -hint.ed.0.maddr="0xd8000" -hint.ed.1.at="isa" -hint.ed.1.port="0x300" -hint.ed.1.irq="5" -hint.ed.1.maddr="0xd0000" diff --git a/private/qemu/config b/private/qemu/config deleted file mode 100644 index 9dd9f5965..000000000 --- a/private/qemu/config +++ /dev/null @@ -1,71 +0,0 @@ -# configuration for picobsd build script. -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/config 201065 2009-12-27 22:34:31Z luigi $ -# it should only contain variable definitions -- it is sourced -# by the shell much like rc.conf* files - -fd_size="24000" - -# You can use it e.g. in a local configuration file by writing -# -# do_copyfiles_user() { -# local dst=$1 -# find_progs nvi sed less grep -# cp -p ${u_progs} ${dst}/bin -# cp -p ${u_libs} ${dst}/lib -# mkdir -p ${dst}/libexec -# find_progs ld-elf.so.1 -# cp -p ${u_progs} ${dst}/libexec -# } -#copy_files=" -#" -do_copyfiles_user() { - local dst=$1 - log "--- called do_copyfiles_user" - - mkdir -p ${dst}/usr/lib - - find_progs -L / /usr/bin/ssh /usr/bin/scp /usr/sbin/sshd - cp -p ${u_progs} ${dst}/bin - # logverbose "Libraries for ssh etc: ${u_libs}" - cp -p ${u_libs} ${dst}/usr/local/lib - - find_progs -L / -P /usr/local/bin trafshow netperf netserver screen - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/local/lib - - - # XXX change this to head/tools/tools/netmap - #local d=/usr/ports-luigi/netmap-release/examples - local d=/usr/home/luigi/qemu-misc/netmap-release/examples - find_progs -L / -P $d pkt-gen bridge poll vale-ctl testlock click # pingd - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/lib - cp -p $d/testmod/test.ko ${dst} # XXX - cp -rp /tmp/boot/modules ${dst} # XXX - - find_progs -L / /tmp/click /tmp/kipfw /tmp/uipfw /tmp/ovs-vswitchd /tmp/ovs-dpctl /tmp/ovs-ofctl /tmp/ovs-dpctl - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/lib - -# find_progs -L /usr/local/lib -P /usr/local/bin tcpreplay -# cp -p ${u_progs} ${dst}/bin -# cp -p ${u_libs} ${dst}/usr/lib - -# cp -p /tmp/tcpreplay ${dst}/root - cp -p /tmp/nltest ${dst}/bin - cp -p /tmp/ovsbsd.ko ${dst}/root - cp -p /tmp/netsend /tmp/netreceive ${dst}/bin - cp -p /tmp/if_vtnet.ko ${dst}/bin -# cp -p /tmp/a.pcap ${dst}/root -# cp -p /tmp/open_key/* ${dst}/root - - cp -p /tmp/openvswitch.ko {dst}/root - - if [ ${TARGET_ARCH} = amd64 ]; then - cp -p /usr/lib/libssh.so.5 /lib/libmd.so.5 ${dst}/usr/lib # need the old one - #find_progs -L $d /tmp/bridge - #cp -p ${u_progs} ${dst}/bin - #cp -p ${u_libs} ${dst}/usr/lib - else - fi -} diff --git a/private/qemu/crunch.conf b/private/qemu/crunch.conf deleted file mode 100644 index 12a6c8e44..000000000 --- a/private/qemu/crunch.conf +++ /dev/null @@ -1,245 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/crunch.conf 201065 2009-12-27 22:34:31Z luigi $ -# -# Configuration file for "qemu" images.. -# -# Depending on your needs, you will almost surely need to -# add/remove/change programs according to your needs. -# Remember that some programs require matching kernel options to -# enable device drivers etc. -# -# To figure out how much space is used by each program, do -# -# size build_dir-bridge/crunch/*lo -# -# Remember that programs require libraries, which add up to the -# total size. The final binary is build_dir-bridge/mfs.tree/stand/crunch -# and you can check which libraries it uses with -# -# ldd build_dir-bridge/mfs.tree/stand/crunch - -# crunchgen configuration to build the crunched binary, see "man crunchgen" -# We need to specify generic build options, the places where to look -# for sources, and the list of program and libraries we want to put -# in the crunched binary. -# -# NOTE: the string "/usr/src" below will be automatically replaced with -# the path set in the 'build' script. - -# Default build options. Basically tell the Makefiles -# that to use the most compact possible version of the code. - -buildopts -DWITHOUT_PAM -DRELEASE_CRUNCH -DPPP_NO_NETGRAPH -buildopts -DTRACEROUTE_NO_IPSEC # -DNO_INET6 -buildopts -DWITHOUT_IPX -buildopts -DWITHOUT_CASPER -# buildopts -DWITHOUT_AUDIT MK_AUDIT=no # login uses lbsm - -# Directories where to look for sources of various binaries. -# @__CWD__@ is a magic keyword in the picobsd's (Makefile.conf) -# which is replaced with the directory with the picobsd configuration -# corresponding to your image. This way you can have custom sources -# in that directory overriding system programs. - -srcdirs @__CWD__@/src - -# Some programs are especially written for PicoBSD and reside in -# release/picobsd/tinyware. -# Put this entry near the head of the list to override standard binaries. - -srcdirs /usr/src/release/picobsd/tinyware - -# Other standard locations for sources. -# If a program uses its own source directory, add - -srcdirs /usr/src/bin -srcdirs /usr/src/sbin/i386 -srcdirs /usr/src/sbin -srcdirs /usr/src/usr.bin -srcdirs /usr/src/gnu/usr.bin -srcdirs /usr/src/usr.sbin -srcdirs /usr/src/libexec -srcdirs /usr/src/secure/usr.bin -srcdirs /usr/src/secure/usr.sbin - -# For programs that reside in different places, the best option -# is to use the command "special XXX srcdir YYY" where XXX is the -# program name and YYY is the directory path. -# "special XXX ..." can be used to specify more options, see again -# the crunchgen manpage. - -#--- Basic configuraton -# init is always necessary (unless you have a replacement, oinit) -progs init -progs kenv - -# fsck is almost always necessary, unless you have everything on the -# image and use 'tar' or something similar to read/write raw blocks -# from the floppy. - -progs fsck - -progs nc # netcat -progs dd # -# ifconfig is needed if you want to configure interfaces. -progs ifconfig - -# You will also need a shell and a bunch of utilities. -# The standard shell is not that large, but you need many -# external programs. In fact most of them do not take much space -# as they merely issue a system call, and print the result. -# For a more compact version of shell and utilities, you could -# try busybox, however most system management commands in busybox -# will not work as they use linux-specific interfaces. - -progs sh -ln sh -sh - -# the small utilities -progs echo -progs pwd mkdir rmdir -progs chmod chown -ln chown chgrp -progs mv ln cp rm ls -progs cat tail tee -progs test -ln test [ -progs shutdown halt - -progs less -ln less more -progs mount -progs minigzip -ln minigzip gzip -progs kill -progs df -progs ps -progs ns # this is the picobsd version -ln ns netstat -progs vm -progs hostname -progs login -progs getty -progs stty -progs w -progs msg -progs nice -ln msg dmesg -progs reboot - -progs sysctl -progs swapon -progs pwd_mkdb -progs umount -progs du -progs passwd - -progs route - -# If you want to run natd, remember the alias library -progs natd -libs_so -lalias # natd -progs tcpdump -special tcpdump srcdir /usr/src/usr.sbin/tcpdump/tcpdump -libs_so -lpcap # used by tcpdump -libs_so -lcrypto # used by tcpdump with inet6 - -# ppp is rather large. Note that as of Jan.01, RELEASE_CRUNCH -# makes ppp not use libalias, so you cannot have aliasing. -#progs ppp - -# You need an editor. ee is relatively small, though there are -# smaller ones. vi is much larger. -# The editor also usually need a curses library. -progs ee - -progs arp - -progs vmstat iostat sleep -# these require libgeom -# progs bsdlabel fdisk mdconfig - -progs kldload kldunload kldstat -progs kldxref -#progs grep -#buildopts -DMK_BSD_GREP=1 -progs hexdump - -libs_so -lgnuregex -lbz2 -# dhclient-script requires 'sed' -progs dhclient -progs sed -progs date -progs time -progs ping -progs ping6 -progs tar - -progs top -progs pciconf - -#progs routed -progs ipfw -progs traceroute -progs mdmfs -ln mdmfs mount_mfs -# Various filesystem support -- remember to enable the kernel parts -# progs mount_msdosfs -progs mount_nfs -# progs mount_cd9660 -ln mount_nfs nfs -ln mount_cd9660 cd9660 -#progs newfs -#ln newfs mount_mfs -# ln mount_msdosfs msdos -progs uname - -progs vi - -progs jail jexec jls - -progs pmcstat - -# progs ld-elf.so.1 - -#progs pmcstat -#libs_so -lpmc -# For a small ssh client/server use dropbear - -# Now the libraries -libs_so -lc # the C library -libs_so -ll # used by sh (really ?) -libs_so -lufs # used by mount -### ncurses is needed on HEAD as of 2013-09 -libs_so -lncurses -libs_so -lncursesw # for wide char support as of 266157 -libs_so -lpam # -lbsm # full login -lradius -ltacplus -lopie -libs_so -lm -libs_so -ledit -lutil -libs_so -lcrypt -libs_so -lkvm -libs_so -lpmc # pmcstat -libs_so -lelf # pmcstat -libs_so -lz -libs_so -lbsdxml -libs_so -lsbuf -libs_so -ljail # used by ifconfig -libs_so -lulog -libs_so -lipsec -lmd -libs_so -larchive -lbz2 -libs_so -llzma # added after 207840 -libs_so -ldevstat -lmemstat -# libs_so -lxo #-- only on HEAD - -# -#--- ssh support -# progs ssh -# progs sshd -# progs scp -# -# libs_so -lssh -# libs_so -lwrap -# libs_so -lpam -# libs_so -lgssapi -# libs_so -lkrb5 # ssh ? -# libs_so -lcapsicum -lnv diff --git a/private/qemu/crunch.conf.amd64 b/private/qemu/crunch.conf.amd64 deleted file mode 100644 index d847e473f..000000000 --- a/private/qemu/crunch.conf.amd64 +++ /dev/null @@ -1,209 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/crunch.conf 201065 2009-12-27 22:34:31Z luigi $ -# -# Configuration file for "qemu" images.. -# -# Depending on your needs, you will almost surely need to -# add/remove/change programs according to your needs. -# Remember that some programs require matching kernel options to -# enable device drivers etc. -# -# To figure out how much space is used by each program, do -# -# size build_dir-bridge/crunch/*lo -# -# Remember that programs require libraries, which add up to the -# total size. The final binary is build_dir-bridge/mfs.tree/stand/crunch -# and you can check which libraries it uses with -# -# ldd build_dir-bridge/mfs.tree/stand/crunch - -# crunchgen configuration to build the crunched binary, see "man crunchgen" -# We need to specify generic build options, the places where to look -# for sources, and the list of program and libraries we want to put -# in the crunched binary. -# -# NOTE: the string "/usr/src" below will be automatically replaced with -# the path set in the 'build' script. - -# Default build options. Basically tell the Makefiles -# that to use the most compact possible version of the code. - -buildopts -DWITHOUT_PAM -DRELEASE_CRUNCH -DPPP_NO_NETGRAPH -buildopts -DTRACEROUTE_NO_IPSEC # -DNO_INET6 -buildopts -DWITHOUT_IPX - -# Directories where to look for sources of various binaries. -# @__CWD__@ is a magic keyword in the picobsd's (Makefile.conf) -# which is replaced with the directory with the picobsd configuration -# corresponding to your image. This way you can have custom sources -# in that directory overriding system programs. - -srcdirs @__CWD__@/src - -# Some programs are especially written for PicoBSD and reside in -# release/picobsd/tinyware. -# Put this entry near the head of the list to override standard binaries. - -srcdirs /usr/src/release/picobsd/tinyware - -# Other standard locations for sources. -# If a program uses its own source directory, add - -srcdirs /usr/src/bin -srcdirs /usr/src/sbin/amd64 -srcdirs /usr/src/sbin -srcdirs /usr/src/usr.bin -srcdirs /usr/src/gnu/usr.bin -srcdirs /usr/src/usr.sbin -srcdirs /usr/src/libexec - -# For programs that reside in different places, the best option -# is to use the command "special XXX srcdir YYY" where XXX is the -# program name and YYY is the directory path. -# "special XXX ..." can be used to specify more options, see again -# the crunchgen manpage. - -#--- Basic configuraton -# init is always necessary (unless you have a replacement, oinit) -progs init - -# fsck is almost always necessary, unless you have everything on the -# image and use 'tar' or something similar to read/write raw blocks -# from the floppy. - -progs fsck - -# ifconfig is needed if you want to configure interfaces. -progs ifconfig - -# You will also need a shell and a bunch of utilities. -# The standard shell is not that large, but you need many -# external programs. In fact most of them do not take much space -# as they merely issue a system call, and print the result. -# For a more compact version of shell and utilities, you could -# try busybox, however most system management commands in busybox -# will not work as they use linux-specific interfaces. - -progs sh -ln sh -sh - -# the small utilities -progs echo -progs pwd mkdir rmdir -progs chmod chown -ln chown chgrp -progs mv ln cp rm ls -progs cat tail tee -progs test -ln test [ - -progs less -ln less more -progs mount -progs minigzip -ln minigzip gzip -progs kill -progs df -progs ps -progs ns # this is the picobsd version -ln ns netstat -progs vm -progs hostname -progs login -progs getty -progs stty -progs w -progs msg -ln msg dmesg -progs reboot - -progs sysctl -progs swapon -progs pwd_mkdb -progs umount -progs du -progs passwd - -progs route - -# If you want to run natd, remember the alias library -# progs natd -# libs_so -lalias # natd -progs tcpdump -special tcpdump srcdir /usr/src/usr.sbin/tcpdump/tcpdump -libs_so -lpcap # used by tcpdump -libs_so -lcrypto # used by tcpdump with inet6 - -# ppp is rather large. Note that as of Jan.01, RELEASE_CRUNCH -# makes ppp not use libalias, so you cannot have aliasing. -#progs ppp - -# You need an editor. ee is relatively small, though there are -# smaller ones. vi is much larger. -# The editor also usually need a curses library. -progs ee - -progs arp - -# these require libgeom -# progs bsdlabel fdisk mdconfig - -progs kldload kldunload kldstat -# progs kldxref -progs grep -# libs_so -lgnuregex -lbz2 -# dhclient-script requires 'sed' -progs dhclient -progs sed -progs date -progs time -progs ping -progs ping6 -progs tar - -progs top -progs pciconf - -#progs routed -progs ipfw -progs traceroute -progs mdmfs -ln mdmfs mount_mfs -# Various filesystem support -- remember to enable the kernel parts -# progs mount_msdosfs -progs mount_nfs -# progs mount_cd9660 -ln mount_nfs nfs -ln mount_cd9660 cd9660 -#progs newfs -#ln newfs mount_mfs -# ln mount_msdosfs msdos - -#progs jail jexec jls - -srcdirs /home/luigi/FreeBSD/pico9/qemu64 -progs bridge # - - -# For a small ssh client/server use dropbear -# progs ssh scp sshd srcdir /usr/src/crypto/openssh - -# Now the libraries -libs_so -lc # the C library -# libs_so -ll # used by sh (really ?) -# libs_so -lufs # used by mount -### ee uses ncurses but as a dependency -#libs_so -lncurses -libs_so -lm -libs_so -ledit -lutil -libs_so -lcrypt -libs_so -lkvm -libs_so -lz -libs_so -lbsdxml -libs_so -lsbuf -libs_so -ljail # used by ifconfig -libs_so -lulog -libs_so -lipsec -lmd -libs_so -larchive -lbz2 -libs_so -llzma # added after 207840 diff --git a/private/qemu/floppy.tree.exclude b/private/qemu/floppy.tree.exclude deleted file mode 100644 index adfc6cc75..000000000 --- a/private/qemu/floppy.tree.exclude +++ /dev/null @@ -1,2 +0,0 @@ -etc/snmpd.conf -etc/ppp diff --git a/private/qemu/floppy.tree/boot/loader.conf b/private/qemu/floppy.tree/boot/loader.conf deleted file mode 100644 index e2ba5ae67..000000000 --- a/private/qemu/floppy.tree/boot/loader.conf +++ /dev/null @@ -1,2 +0,0 @@ -kern.ipc.nmbclusters=128000 -luigi.test=1 diff --git a/private/qemu/floppy.tree/etc/motd b/private/qemu/floppy.tree/etc/motd deleted file mode 100644 index eb55bf34c..000000000 --- a/private/qemu/floppy.tree/etc/motd +++ /dev/null @@ -1,12 +0,0 @@ - - -============================================================== - - )\_)\ Welcome to PicoBSD, netmap demo image - (o,o) - __ \~/ Root password is "setup" - -->====\ - ~~ d d see http://info.iet.unipi.it/~luigi/netmap/ - -============================================================== -K diff --git a/private/qemu/floppy.tree/etc/rc.conf.defaults b/private/qemu/floppy.tree/etc/rc.conf.defaults deleted file mode 100644 index 70e3767ad..000000000 --- a/private/qemu/floppy.tree/etc/rc.conf.defaults +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -# $FreeBSD: head/release/picobsd/floppy.tree/etc/rc.conf.defaults 91949 2002-03-09 18:27:02Z luigi $ -# -# rc.conf for picobsd. This is sourced from /etc/rc1, and is supposed to -# contain only shell functions that are used later in /etc/rc1. - -# set default values for variables. Boolean values should be either -# NO or YES -- other values are not guaranteed to work. - -rc_conf_set_defaults() { -hostname="" # Should not need to set it -syslogd_enable="NO" -pccard_enable="NO" -swapfile="" # name of swapfile if aux swapfile desired. - -# Network interface configurations: ifconfig_${interface}[_aliasNN] -ifconfig_lo0="inet 127.0.0.1" # default loopback device configuration. -#ifconfig_lo0_alias0="inet 127.0.0.254 netmask 0xffffffff" # Sample alias entry. - -### Network daemons options: they are only run if present. -sshd_enable="YES" # if present... -inetd_enable="YES" # Run the network daemon dispatcher (or NO) -inetd_flags="" # Optional flags to inetd -snmpd_enable="NO" # Run the SNMP daemon (or NO) -snmpd_flags="-C -c /etc/snmpd.conf" # Optional flags to snmpd - -### Network routing options: ### -defaultrouter="NO" # Set to default gateway (or NO). -static_routes="" # Set to static route list (or leave empty). -gateway_enable="NO" # Set to YES if this host will be a gateway. -arpproxy_all="" # replaces obsolete kernel option ARP_PROXYALL. -default_mask="0xffffff00" - -### Other network features -firewall_enable="NO" -firewall_quiet="NO" # be quiet if set. -firewall_type="" # Standard types or absolute pathname. -tcp_extensions="NO" # Allow RFC1323 & RFC1644 extensions (or NO). - -### Overrides for some files in /etc. Leave empty if no override, -### set variable (remember to use multiple lines) to override content. - -host_conf="hosts -bind" -resolv_conf="" -} - -# Try to identify the system by using the MAC address and name of the -# first ethernet interface, made available as $main_eth $main_if -find_system_id() { - main_ether="" - for main_if in `ifconfig -l` ; do - set `ifconfig $main_if` - while [ "$1" != "" ] ; do - if [ $1 = "ether" ] ; then - main_ether=$2 - break 2 - else - shift - fi - done - done -} - -# the following lets the user specify a name and ip for his system -read_address() { - ## XXX disabled - hostname=default - return # - - echo "Please enter a hostname and IP address for your system $main_ether" - read hostname the_ip - if [ "${hostname}" != "" ] ; then - echo "# $main_ether $hostname" >> /etc/hosts - echo "$the_ip $hostname" >> /etc/hosts - else - hostname=default - fi -} - -# set "ether" using $1 (interface name) as search key -get_ether() { - local key - key=$1 - ether="" - set `ifconfig ${key}` - while [ "$1" != "" ] ; do - if [ "$1" = "ether" ] ; then - ether=$2 - break - else - shift - fi - done -} - -# read content from /etc/hosts into a couple of arrays -# (needed later in fetch_hostname) -read_hosts() { - local i a b c key junk - i="" - while read a b c junk ; do - if [ "$a" = "#ethertable" ] ; then - i=0 - elif [ "$i" != "" -a "$a" = "#" -a "$b" != "" ] ; then - eval eth_${i}=$b - eval eth_host_${i}=$c - i=$(($i+1)) - fi - done < /etc/hosts -} - -# set ${hostname} using $1 (MAC address) as search key in /etc/hosts -# Returns empty value if $1 is empty -fetch_hostname() { - local i b key - hostname="" - [ "$1" = "" ] && return - key=$1 - i=0 - b="x" - [ "${eth_0}" = "" ] && read_hosts # fill cache. - while [ "$b" != "" -a "${hostname}" = "" ] ; do - eval b=\${eth_${i}} - case X${key} in - X${b} ) # so we can use wildcards - eval hostname=\${eth_host_${i}} - break - ;; - esac - i=$(($i+1)) - done - echo "fetch_hostname for <${key}> returns <${hostname}>" -} - -# sets "mask" using $1 (netmask name) as the search key in /etc/networks -fetch_mask() { - local a b key junk - key=$1 # search key, typically hostname-netmask - mask="" - while read a b junk; do # key mask otherstuff - case X${key} in - X${a} ) # The X is so we can use wildcards in ${a} - mask=$b - break - ;; - esac - done < /etc/networks - if [ "${mask}" = "" ] ; then - mask=${default_mask} - fi - echo "fetch_mask for <${key}> returns <${mask}>" -} - -# set hostname, and ifconfig_${main_if} (whose MAC is ${main_ether}) -# if not found, read from console -set_main_interface() { - if [ -z "${hostname}" ] ; then - if [ -z "${main_ether}" ] ; then - echo "No ethernets found, using localhost" - hostname=localhost - return - fi - fetch_hostname ${main_ether} - fi - - [ -z "${hostname}" -o "${hostname}" = "." ] && read_address - - fetch_mask ${hostname}-netmask - - eval ifconfig_${main_if}=\" \${hostname} netmask \${mask}\" - network_interfaces=`ifconfig -l` -} - -# set ifconfig_${interface} for all other interfaces -set_all_interfaces() { - local i ether hostname mask - - for i in `ifconfig -l` ; do - if [ "$i" != "${main_if}" ] ; then - get_ether $i - fetch_hostname ${ether} - fetch_mask ${hostname}-netmask - [ -n "${ether}" -a -n "${hostname}" ] && \ - eval ifconfig_${i}=\" \${hostname} netmask \${mask}\" - fi - done -} diff --git a/private/qemu/floppy.tree/root/.profile b/private/qemu/floppy.tree/root/.profile deleted file mode 100644 index 9fe78f2f8..000000000 --- a/private/qemu/floppy.tree/root/.profile +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -export PATH=/stand:/bin:/usr/bin:/usr/local/bin -export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib -# -./test f1 diff --git a/private/qemu/floppy.tree/root/bri b/private/qemu/floppy.tree/root/bri deleted file mode 100644 index cdccf3c7b..000000000 --- a/private/qemu/floppy.tree/root/bri +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -# 20130610 lr -# test code for vale switch -(pkt-gen -i vale0 -f rx -W &); pkt-gen -i vale1 -f tx -b 128 diff --git a/private/qemu/floppy.tree/root/bri.click b/private/qemu/floppy.tree/root/bri.click deleted file mode 100644 index 00f51fe9e..000000000 --- a/private/qemu/floppy.tree/root/bri.click +++ /dev/null @@ -1,19 +0,0 @@ -// -// $Id$ -// -// A sample test configuration for click -// -// -// create a switch - -sw :: EtherSwitch; - -// two input devices - -c0 :: FromDevice(ix0, BURST 30, PROMISC true); -c1 :: FromDevice(ix1, BURST 30, PROMISC true); - -// and now pass packets around - -c0[0] -> [0]sw[0] -> Queue(10000) -> ToDevice(ix0); -c1[0] -> [1]sw[1] -> Queue(10000) -> ToDevice(ix1); diff --git a/private/qemu/floppy.tree/root/rates b/private/qemu/floppy.tree/root/rates deleted file mode 100644 index 3158e38eb..000000000 --- a/private/qemu/floppy.tree/root/rates +++ /dev/null @@ -1,2 +0,0 @@ -I80211b_11M - diff --git a/private/qemu/floppy.tree/root/start_test b/private/qemu/floppy.tree/root/start_test deleted file mode 100644 index b4f267f27..000000000 --- a/private/qemu/floppy.tree/root/start_test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -sysctl dev.cpu.0.freq=1200 -sysctl dev.cpu.0.freq=2934 -sysctl dev.ix.0.flow_control=0 -sysctl dev.ix.1.flow_control=0 -ifconfig ix0 up -ifconfig ix1 up diff --git a/private/qemu/floppy.tree/root/t1.ck b/private/qemu/floppy.tree/root/t1.ck deleted file mode 100644 index ac143f0ff..000000000 --- a/private/qemu/floppy.tree/root/t1.ck +++ /dev/null @@ -1,11 +0,0 @@ -// test1.ck -s :: InfiniteSource(LENGTH 64, BURST 1, NOTS true) -// -> q :: Queue -// -> c :: Counter - -> d :: Discard(BURST 1); - -DriverManager( - wait 1s, write s.active false, - //print "done $(d.count) packets $(q.drops) drops in 1s" - print "done $(d.count) packets drops in 1s" -); diff --git a/private/qemu/floppy.tree/root/t2.ck b/private/qemu/floppy.tree/root/t2.ck deleted file mode 100644 index c39325ef3..000000000 --- a/private/qemu/floppy.tree/root/t2.ck +++ /dev/null @@ -1,14 +0,0 @@ -// test1.ck -FromDevice(ix0, BURST 100) -> Discard; - -s :: FromDevice(ix1, BURST 100) -> Queue -> ToDevice(ix0, BURST 100); - -DriverManager( - set a 0, - label x, - wait 1s, - set b $(s.count), - print "done $(sub $b $a) packets in 1s", - set a $b, - goto x 1 -); diff --git a/private/qemu/floppy.tree/root/test b/private/qemu/floppy.tree/root/test deleted file mode 100755 index 0f316b53b..000000000 --- a/private/qemu/floppy.tree/root/test +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh - -f1() { # default setting - sysctl kern.timecounter.hardware=TSC-low - ifconfig em0 -rxcsum -txcsum - return - ifconfig ed2 delete - dhclient ed2 - sysctl net.inet.ip.fw.verbose=1 -} - -# test tables -f2() { - ipfw table 2 add 22 2000 - ipfw table 2 add 53 3000 - ipfw table 2 add 80 4000 - ipfw table 2 add 127.0.0.1 5000 - ipfw table 2 list -} - -f3() { - ipfw -q flush - ipfw add 100 count log out - ipfw add 200 skipto tablearg lookup dst-port 2 - ipfw add 300 skipto tablearg lookup dst-ip 2 - ipfw add 1000 allow ip from any to any - ipfw add 2000 allow ip from any to any - ipfw add 3000 allow ip from any to any - ipfw add 4000 allow ip from any to any - ipfw add 5000 allow ip from any to any -} - -f4() { - ipfw -q flush - echo > /etc/libalias.conf - sysctl net.inet.ip.fw.verbose=1 - ipfw add 100 divert natd log ip from any to any - ipfw add 100 count ip from any to any - ipfw add 200 count ip from any to any - natd -v -interface ed2 & -} - -f5() { - ipfw pipe 10 config bw 80kbit/s - ipfw add 100 pipe 10 ip from any to any - ipfw pipe show -} - -# test queues -f6() { - ipfw pipe 1 config bw 400kbit/s queue 30 - #ipfw pipe 2 config bw 180kbit/s - #ipfw pipe 3 config delay 30ms queue 100kbytes - ipfw queue 11 config sched 1 weight 1 - ipfw queue 12 config sched 1 weight 2 - ipfw queue 14 config sched 1 weight 4 - ipfw queue 18 config sched 1 weight 8 - ipfw -q flush - ipfw add 100 queue 11 src-ip 0&3 // low bits 00 - ipfw add 100 queue 12 src-ip 1&3 // low bits 01 - ipfw add 100 queue 14 src-ip 2&3 // low bits 10 - ipfw add 100 queue 18 src-ip 3&3 // low bits 11 -} - -# jail test -f7() { -jail -c -nXX vnet path=/ host.hostname=test.me persist=true command=/bin/sh -} - -f8() { - ipfw add 100 queue tablearg lookup dscp 1 - ipfw queue 10 config sched 5 mask queue - ipfw queue 20 config sched 5 mask queue - ipfw queue 30 config sched 5 mask queue - ipfw pipe 5 config bw 80Kbit/s - # ipfw table 1 add 0 10 - ipfw table 1 add 1 20 - ipfw table 1 add 2 30 - ipfw table 1 list -} - -case $1 in - f[0-9]*) $* ;; -esac diff --git a/private/qemu/floppy.tree/test b/private/qemu/floppy.tree/test deleted file mode 100755 index dcc1b646c..000000000 --- a/private/qemu/floppy.tree/test +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -f1() { - sysctl kern.timecounter.hardware=i8254 - ifconfig ed2 delete - dhclient ed2 - sysctl net.inet.ip.fw.verbose=1 -} - -init() { - local a=$1 - [ "x$a" = "x" ] && a=10.0.0.2 - echo "prepare for tests with netsend" - ifconfig ix0 $1 - sysctl dev.ix.0.enable_aim=0 - sysctl dev.ix.0.queue0.interrupt_rate=5000 - sysctl dev.ix.0.fc=0 - sysctl dev.cpu.0.freq=2934 - sysctl dev.netmap.drop - sysctl net.inet.icmp.icmplim=0 - echo netsend 10.0.0.1 5555 18 0 5 -} - -run_test() { # port num len breakpoint - local i ports=$1 - shift - echo "### break $3 cores $1 len $2" - sysctl dev.netmap.drop=$3 - for i in $1; do (netsend 10.0.0.1 $ports $2 0 5 &) ; done -} - -batch() { # ports len breakpoint - local i ports=$1 len=$2 bp=$3 - for i in 1 2 3 4; do - run_test $ports 0 $len $bp 2>&1 | grep -E "###|time/|send rate" - done - for i in 1 2 3 4; do - run_test $ports "0 1 2 3" $len $bp 2>&1 | grep -E "###|time/|send rate" - done -} - -go() { # ports len breakpoints - local i ports=$1 len=$2 - shift; shift - for i in $* ; do - batch $ports $len $i - done -} - -case $1 in - *) $* ;; -esac diff --git a/private/qemu/run b/private/qemu/run deleted file mode 100755 index a7907191e..000000000 --- a/private/qemu/run +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/sh -# build or run a picobsd instance -PLATFORM=amd64 - -#--- qemu options -QEMU_DIR=/usr/ports-luigi/qemu-netmap/work-head/qemu-1.2.2/x86_64-softmmu/ - -# location of the linux version -QEMU_DIR=/home/luigi/qemu-misc/qemu/x86_64-softmmu/ -BHYVE_DIR=/home/luigi/qemu-misc/bhyve/ - -# location of the freebsd version ? -# QEMU_DIR=/usr/home/luigi/qemu-misc/qemu-head/x86_64-softmmu/ - -[ "$QEMU_PORT" = "" ] && QEMU_PORT=4444 # monitoring port -NET1=" -device e1000,netdev=base -netdev user,id=base" -QEMU_OPTS="-m 1024 -smp 2 " - - -arch= -while [ x"$1" != x ] ; do - case "$1" in - -app) - APP=$2 - shift - ;; - - -j) - PARALLEL="-j 4" - ;; - - -targ*|-arch*) - arch="--arch $2" - PLATFORM=$2 - shift - ;; - - -kern*) - KERNCONF=$2 - shift - ;; - - -nomod*) - export NO_MODULES=yes - ;; - - -clean) - unset NO_CLEAN - ;; - - -depend) - unset NO_KERNELDEPEND - ;; - - ### qemu flags - -nonet) - # NET1=" -net nic,model=e1000-paravirt -net netmap,ifname=valeQE1" - NET1=" $NET1 -device e1000-paravirt" - ;; - -vale) - # NET1=" -net nic,model=e1000-paravirt -net netmap,ifname=valeQE1" - NET1=" $NET1 -device e1000-paravirt,netdev=n -netdev netmap,id=n,ifname=valeQE1" - ;; - -npipe) - # NET1=" -net nic,model=e1000-paravirt -net netmap,ifname=valeQE1" - NET1=" $NET1 -device e1000-paravirt,netdev=n -netdev netmap,id=n,ifname=valeXX:QE1{01" - ;; - - -vale2) - # NET1=" -net nic,model=e1000-paravirt -net netmap,ifname=valeQE1" - NET1=" $NET1 -device e1000,netdev=n -netdev netmap,id=n,ifname=valeQE2" - QEMU_PORT=4445 - ;; - -npipe) - # NET1=" -net nic,model=e1000-paravirt -net netmap,ifname=valeQE1" - NET1=" $NET1 -device e1000,netdev=n -netdev netmap,id=n,ifname=vale:xx{1" - QEMU_PORT=4446 - ;; - -sdl) - VIDEO=" " - ;; - - -vnc) - VIDEO="-vnc :0" - ;; - - -hd*) - hda=$2 - shift - ;; - - -q11) # qemu 11 - QEMU_DIR=/usr/ports/emulators/qemu/work/qemu-0.11.1/x86_64-softmmu/ - ;; - - - *) - break - ;; - - esac - shift -done -# cmd image root - -[ "$VIDEO" = "" ] && VIDEO="-curses -monitor tcp::$QEMU_PORT,server,nowait" - -QEMU_OPTS="$QEMU_OPTS $NET1 $NET2" - -cmd=$1 -pico=$2 -root=$3 -{ shift; shift; shift ; } || echo "ignoring errors" - -QEMU=${QEMU_DIR}qemu-system-x86_64 -[ -f "$hda" ] || hda=build_dir-$pico-$PLATFORM/picobsd.bin -echo "--- $cmd $pico on tree $root" -case "$cmd" in - init) - ../$root/release/picobsd/build/picobsd --src ../$root -n -v \ - $arch --init ${PARALLEL} - ;; - build|bld) - ../$root/release/picobsd/build/picobsd --src ../$root -n -v $pico - #$arch $pico - ;; - run) - $QEMU $QEMU_OPTS $VIDEO -hda $hda $* - ;; - - bhyve) - # COM2="-l com2,/dev/nmdm1A" - echo sudo bhyveload -m 512 -d $hda vm1 - # -h /tmp/diskless - sudo bhyveload -m 512 -d $hda vm1 - sudo ifconfig tap0 up - sudo ${BHYVE_DIR}bhyve -c 1 -s 0,hostbridge \ - -s 2,virtio-net,vale0 \ - -s 3,virtio-net,null \ - -s 4,virtio-net,tap0,mac=00:a0:98:fa:cc:10 \ - -s 30,lpc -l com1,/dev/nmdm0A $COM2 \ - -s 10,ahci-hd,$hda -A -H -P -m 512 vm1 - sudo bhyvectl --destroy --vm=vm1 - ;; - - diskless) # on bhyve - sudo bhyveload -m 512 -h /tmp/diskless vm1 - sudo ifconfig tap0 up - sudo ${BHYVE_DIR}bhyve -c 1 -s 0,hostbridge \ - -s 1,virtio-net,tap0,mac=00:a0:98:fa:cc:10 \ - -s 2,virtio-net,vale0 \ - -s 3,virtio-net,null \ - -s 30,lpc -l com1,/dev/nmdm0A $COM2 \ - -A -H -P -m 512 vm1 - sudo bhyvectl --destroy --vm=vm1 - ;; -esac - diff --git a/private/sys/dev/netmap/cxgbe_netmap.h b/private/sys/dev/netmap/cxgbe_netmap.h deleted file mode 100644 index 73ee8ea61..000000000 --- a/private/sys/dev/netmap/cxgbe_netmap.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2014 Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * $FreeBSD$ - * - * netmap modifications for cxgbe - -20120120 -t4_sge seems to be the main file for processing. - -the device has several queues - iq ingress queue (messages posted ?) - fl freelist queue - -buffers are in sd->cl - -interrupts are serviced by t4_intr*() which does a atomic_cmpset_int() -to run only one instance of the driver (service_iq()) and -then clears the flag at the end. -The dispatches in there makes a list (iql) of postponed work. - -Handlers are cpl_handler[] per packet type. - received packets are t4_eth_rx() - -the main transmit routine is t4_main.c :: cxgbe_transmit() - which ends into t4_sge.c :: t4_eth_tx() - and eventually write_txpkt_wr() - -refill_fl() is called under lock -X_RSPD_TYPE_FLBUF is a data packet, perhaps - */ - -#include -#include -// #include -// #include /* vtophys ? */ -#include - -static int cxgbe_netmap_reg(struct ifnet *, int onoff); -static int cxgbe_netmap_txsync(void *, u_int, int); -static int cxgbe_netmap_rxsync(void *, u_int, int); -static void cxgbe_netmap_lock_wrapper(void *, int, u_int); - - -SYSCTL_NODE(_dev, OID_AUTO, cxgbe, CTLFLAG_RW, 0, "cxgbe card"); - -static void -cxgbe_netmap_attach(struct port_info *pi) -{ - struct netmap_adapter na; - - bzero(&na, sizeof(na)); - - na.ifp = pi->ifp; - na.na_flags = NAF_BDG_MAYSLEEP; - na.num_tx_desc = 0; // qsize pi->num_tx_desc; - na.num_rx_desc = 0; // XXX qsize pi->num_rx_desc; - na.nm_txsync = cxgbe_netmap_txsync; - na.nm_rxsync = cxgbe_netmap_rxsync; - na.nm_register = cxgbe_netmap_reg; - /* - * adapter->rx_mbuf_sz is set by SIOCSETMTU, but in netmap mode - * we allocate the buffers on the first register. So we must - * disallow a SIOCSETMTU in netmap mode - */ - na.num_tx_rings = na->num_rx_rings = pi->ntxq; - na.buff_size = NETMAP_BUF_SIZE; - netmap_attach(&na); -} - - -/* - * support for netmap register/unregisted. We are already under core lock. - * only called on the first init or the last unregister. - */ -static int -cxgbe_netmap_reg(struct netmap_adapter *na, int onoff) -{ - struct ifnet *ifp = na->ifp; - struct adapter *adapter = ifp->if_softc; - -#if 0 - cxgbe_disable_intr(adapter); - - /* Tell the stack that the interface is no longer active */ - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - - if (onoff) { - nm_set_native_flags(na); - } else { - nm_clear_native_flags(na); - } - cxgbe_init_locked(adapter); /* also enables intr */ -#endif - return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); -} - - -/* - * Reconcile kernel and user view of the transmit ring. - */ -static int -cxgbe_netmap_txsync(struct netmap_kring *kring, int flags) -{ -#if 0 - // see ixgbe_netmap.h -#endif - return 0; -} - - -/* - * Reconcile kernel and user view of the receive ring. - */ -static int -cxgbe_netmap_rxsync(struct netmap_kring *kring, int flags) -{ -#if 0 - // see ixgbe_netmap.h -#endif - return 0; -} diff --git a/private/sys/dev/netmap/if_bge_netmap.h b/private/sys/dev/netmap/if_bge_netmap.h deleted file mode 100644 index fc98eb1ae..000000000 --- a/private/sys/dev/netmap/if_bge_netmap.h +++ /dev/null @@ -1,360 +0,0 @@ -/*- - * (C) 2014 Luigi Rizzo - Universita` di Pisa - * - * BSD copyright - * - * $FreeBSD$ - * - * netmap support for if_bge.c - * see ixgbe_netmap.h for details on the structure of the - * various functions. - */ - -#include -#include -#include -#include /* vtophys ? */ -#include - - -/* - * support for netmap register/unregisted. We are already under core lock. - * only called on the first register or the last unregister. - */ -static int -bge_netmap_reg(struct netmap_adapter *na, int onoff) -{ - struct ifnet *ifp = na->ifp; - struct bge_softc *adapter = ifp->if_softc; - - BGE_LOCK(adapter); - /* Tell the stack that the interface is no longer active */ - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - - bge_stop(adapter); - - if (onoff) { - na_set_native_flags(na); - } else { - na_clear_native_flags(na); - } - bge_init_locked(adapter); /* also enables intr */ - BGE_UNLOCK(adapter); - return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); -} - - -/* - * Reconcile kernel and user view of the transmit ring. - */ -static int -bge_netmap_txsync(struct netmap_kring *kring, int flags) -{ - struct netmap_adapter *na = kring->na; - struct ifnet *ifp = na->ifp; - struct bge_softc *sc = ifp; - struct netmap_ring *ring = kring->ring; - int delta, j, k, l, lim = kring->nkr_num_slots - 1; - u_int nm_i; - u_int nic_i; - u_int const head = kring->rhead; - - /* bge_tx_cons_idx is the equivalent of TDH on intel cards, - * i.e. the index of the tx frame most recently completed. - */ - l = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx; - - /* Sync the TX descriptor list */ - bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag, - sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_POSTWRITE); - - /* record completed transmissions */ - delta = l - sc->bge_tx_saved_considx; - if (delta < 0) /* wrap around */ - delta += BGE_TX_RING_CNT; - if (delta > 0) { /* some tx completed */ - sc->bge_tx_saved_considx = l; - sc->bge_txcnt -= delta; - kring->nr_hwtail += delta; - if (kring->nr_hwtail > lim) - kring->nr_hwtail -= lim + 1; - } - - /* update tail pointer */ - XXX ring->tail = ... - - j = kring->nr_hwcur; - if (j != k) { /* we have new packets to send */ - bus_dmamap_t *txmap = sc->bge_cdata.bge_tx_dmamap; - int n = 0; - - l = sc->bge_tx_prodidx; - while (j != k) { - struct netmap_slot *slot = &ring->slot[j]; - struct bge_tx_bd *d = &sc->bge_ldata.bge_tx_ring[l]; - void *addr = NMB(na, slot); - int len = slot->len; - - NM_CHECK_ADDR_LEN(addr, len); - - if (slot->flags & NS_BUF_CHANGED) { - uint64_t paddr = vtophys(addr); - d->bge_addr.bge_addr_lo = BGE_ADDR_LO(paddr); - d->bge_addr.bge_addr_hi = BGE_ADDR_HI(paddr); - /* buffer has changed, unload and reload map */ - netmap_reload_map(sc->bge_cdata.bge_tx_mtag, - txmap[l], addr, na->buff_size); - slot->flags &= ~NS_BUF_CHANGED; - } - slot->flags &= ~NS_REPORT; - d->bge_len = len; - d->bge_flags = BGE_TXBDFLAG_END; - bus_dmamap_sync(sc->bge_cdata.bge_tx_mtag, - txmap[l], BUS_DMASYNC_PREWRITE); - j = nm_next(j, lim); - l = nm_next(l, lim); - n++; - } - kring->nr_hwcur = k; /* the saved ring->cur */ - sc->bge_tx_prodidx = l; - ring->tail = ... - - /* now repeat the last part of bge_start_locked() */ - bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag, - sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE); - /* Transmit. */ - bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, l); - /* 5700 b2 errata */ - if (sc->bge_chiprev == BGE_CHIPREV_5700_BX) - bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, l); - sc->bge_timer = 5; - } - return 0; -} - - -/* - * Reconcile kernel and user view of the receive ring. - * In bge, the rx ring is initialized by setting the ring size - * bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, BGE_STD_RX_RING_CNT - 1); - * and the receiver always starts from 0. - * sc->bge_rx_saved_considx starts from 0 and is the place from - * which the driver reads incoming packets. - * sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx is the - * next (free) receive buffer where the hardware will put incoming packets. - * - * sc->bge_rx_saved_considx is maintained in software and represents XXX - * - * After a successful rxeof we do - * sc->bge_rx_saved_considx = rx_cons; - * ^---- effectively becomes rx_prod_idx - * - * bge_writembx(sc, BGE_MBX_RX_CONS0_LO, sc->bge_rx_saved_considx); - * ^--- we have freed some descriptors - * - * bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, (sc->bge_std + - * BGE_STD_RX_RING_CNT - 1) % BGE_STD_RX_RING_CNT); - * ^---- we have freed some buffers - */ -static int -bge_netmap_rxsync(struct netmap_kring *kring, int flags) -{ - struct netmap_adapter *na = kring->na; - struct ifnet *ifp = na->ifp; - struct bge_softc *sc = a; - struct netmap_ring *ring = kring->ring; - int j, k, n, lim = kring->nkr_num_slots - 1; - u_int const head = kring->rhead; - uint32_t end; - - /* XXX check sync modes */ - bus_dmamap_sync(sc->bge_cdata.bge_rx_return_ring_tag, - sc->bge_cdata.bge_rx_return_ring_map, BUS_DMASYNC_POSTREAD); - bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag, - sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_POSTWRITE); - - l = sc->bge_rx_saved_considx; - nm_i = kring->nkr_hwtail; - nic_i = netmap_idx_k2n(kring, nm_i); - /* - * First part: import newly received packets - * - /* bge_rx_prod_idx is the same as RDH on intel cards -- the next - * (empty) buffer to be used for receptions. - * To decide when to stop we rely on bge_rx_prod_idx - * and not on the flags in the frame descriptors. - */ - end = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx; - if (nic_i != end) { - for (n = 0; nic_i != end; n++) { - struct bge_rx_bd *cur_rx; - uint32_t len; - - cur_rx = &sc->bge_ldata.bge_rx_return_ring[l]; - len = cur_rx->bge_len - ETHER_CRC_LEN; - kring->ring->slot[nm_i].len = len; - kring->ring->slot[nm_i].flags = kring->nkr_slot_flags; - /* sync was in bge_newbuf() */ - bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag, - sc->bge_cdata.bge_rx_std_dmamap[l], - BUS_DMASYNC_POSTREAD); - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - } - sc->bge_rx_saved_considx = end; - bge_writembx(sc, BGE_MBX_RX_CONS0_LO, end); - sc->bge_ifp->if_ipackets += n; - kring->nr_hwtail = nm_i; - } - - /* - * Second part: skip past packets that userspace has released. - */ - nm_i = kring->nr_hwcur; - if (nm_i != head) { - n = 0; - nic_i = netmap_idx_k2n(kring, nm_i); - while (nm_i != head) { - struct netmap_slot *slot = &ring->slot[nm_i]; - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - struct bge_rx_bd *r = &sc->bge_ldata.bge_rx_std_ring[nic_i]; - if (addr == netmap_buffer_base) /* bad buf */ - goto ring_reset; - - r->bge_addr.bge_addr_lo = BGE_ADDR_LO(paddr); - r->bge_addr.bge_addr_hi = BGE_ADDR_HI(paddr); - if (slot->flags & NS_BUF_CHANGED) { - netmap_reload_map(sc->bge_cdata.bge_rx_mtag, - sc->bge_cdata.bge_rx_std_dmamap[nic_i], - addr); - slot->flags &= ~NS_BUF_CHANGED; - } - r->bge_flags = BGE_RXBDFLAG_END; - r->bge_len = na->buff_size; - r->bge_idx = nic_i; - bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag, - sc->bge_cdata.bge_rx_std_dmamap[nic_i], - BUS_DMASYNC_PREREAD); - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - n++; - } - kring->nr_hwcur = head; - /* Flush the RX DMA ring */ - - bus_dmamap_sync(sc->bge_cdata.bge_rx_return_ring_tag, - sc->bge_cdata.bge_rx_return_ring_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - } - // nm_rxsync_finalize(kring, resvd); XXX what is resvd? - return 0; -} - - -static void -bge_netmap_tx_init(struct bge_softc *sc) -{ - struct bge_tx_bd *d = sc->bge_ldata.bge_tx_ring; - int i; - struct netmap_adapter *na = NA(sc->bge_ifp); - struct netmap_slot *slot; - - slot = netmap_reset(na, NR_TX, 0, 0); - /* slot is NULL if we are not in native netmap mode */ - if (!slot) - return; - /* in native netmap mode, overwrite addresses and maps */ - for (i = 0; i < BGE_TX_RING_CNT; i++) { - /* - * the first time, ``slot`` points the first slot of - * the ring; the reset might have introduced some kind - * of offset between the kernel and userspace view of - * the ring; for these reasons, we use l to point - * to the slot linked to the i-th descriptor. - */ - void *addr; - uint64_t paddr; - struct netmap_kring *kring = &na->tx_rings[0]; - int l = i + kring->nkr_hwofs; - if (l >= sc->rl_ldata.rl_tx_desc_cnt) - l -= sc->rl_ldata.rl_tx_desc_cnt; - - addr = NMB(na, slot + l); - paddr = vtophys(addr); - d[i].bge_addr.bge_addr_lo = BGE_ADDR_LO(paddr); - d[i].bge_addr.bge_addr_hi = BGE_ADDR_HI(paddr); - netmap_load_map(na, sc->bge_cdata.bge_tx_mtag, - sc->bge_cdata.bge_tx_dmamap[i], - addr, na->buff_size); - } -} - - -static void -bge_netmap_rx_init(struct bge_softc *sc) -{ - /* slot is NULL if we are not in netmap mode */ - struct netmap_adapter *na = NA(sc->bge_ifp); - struct netmap_slot *slot; - struct bge_rx_bd *r = sc->bge_ldata.bge_rx_std_ring; - int i; - - slot = netmap_reset(na, NR_RX, 0, 0); - if (!slot) - return; // not in native mode - - for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { - /* - * the first time, ``slot`` points the first slot of - * the ring; the reset might have introduced some kind - * of offset between the kernel and userspace view of - * the ring; for these reasons, we use l to point - * to the slot linked to the i-th descriptor. - */ - void *addr; - uint64_t paddr; - struct netmap_kring *kring = &na->rx_rings[0]; - int l = i + kring->nkr_hwofs; - if (l >= sc->rl_ldata.rl_rx_desc_cnt) - l -= sc->rl_ldata.rl_rx_desc_cnt; - - addr = NMB(na, slot + l); - paddr = vtophys(addr); - r[i].bge_addr.bge_addr_lo = BGE_ADDR_LO(paddr); - r[i].bge_addr.bge_addr_hi = BGE_ADDR_HI(paddr); - r[i].bge_flags = BGE_RXBDFLAG_END; - r[i].bge_len = na->buff_size; - r[i].bge_idx = i; - /* - * userspace knows that hwcur->hwtail slots were ready - * before the reset, so we need to leave some slots - * unavailable to the driver. - */ - D("incomplete driver: don't know how to reserve slots"); - - netmap_reload_map(na, sc->bge_cdata.bge_rx_mtag, - sc->bge_cdata.bge_rx_std_dmamap[i], - addr, na->buff_size); - } -} - -static void -bge_netmap_attach(struct bge_softc *sc) -{ - struct netmap_adapter na; - - bzero(&na, sizeof(na)); - - na.ifp = sc->bge_ifp; - na.na_flags = NAF_BDG_MAYSLEEP; - na.num_tx_desc = BGE_TX_RING_CNT; - na.num_rx_desc = BGE_STD_RX_RING_CNT; - na.nm_txsync = bge_netmap_txsync; - na.nm_rxsync = bge_netmap_rxsync; - na.nm_register = bge_netmap_reg; - na.num_tx_rings = na.num_rx_rings = 1; - netmap_attach(&na); -} -/* end of file */ diff --git a/private/sys/dev/netmap/if_sfxge_netmap.h b/private/sys/dev/netmap/if_sfxge_netmap.h deleted file mode 100644 index b40df54ac..000000000 --- a/private/sys/dev/netmap/if_sfxge_netmap.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2014 Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * $FreeBSD: head/sys/dev/netmap/ixgbe_netmap.h 232238 2012-02-27 19:05:01Z luigi $ - * - * netmap modifications for sfxge - -init: -interrupt: - sfxge_ev: sfxge_ev_qpoll() - in turn calls common/efx_ev.c efx_ev_qpoll() - the queue contains handlers which are interleaved, - The specific drivers are - efx_ev_rx 0 - then call eec_rx() or sfxge_ev_rx - efx_ev_tx 2 - then call eec_tx() or sfxge_ev_tx - plus some generic events. - efx_ev_driver 5 - efx_ev_global 6 - efx_ev_drv_gen 7 - efx_ev_mcdi 0xc - -The receive ring seems to be circular, SFXGE_NDESCS in both rx and tx. - struct sfxge_rxq *rxq; - struct sfxge_rx_sw_desc *rx_desc; - - id = rxq->pending modulo SFXGE_NDESCS - the descriptor is rxq->queue[id] - -each slot has size efx_qword_t (8 bytes with all overlays) - -The card is reset through sfxge_schedule_reset() - -Global lock: - sx_xlock(&sc->softc_lock); - - */ - -#include -#include -/* - * Some drivers may need the following headers. Others - * already include them by default - -#include -#include - - */ -#include - -static void sfxge_stop(struct sfxge_softc *sc); -static int sfxge_start(struct sfxge_softc *sc); -void sfxge_tx_qlist_post(struct sfxge_txq *txq); - - -static int -sfxge_netmap_init_buffers(struct sfxge_softc *sc) -{ - struct netmap_adapter *na = NA(sc->ifnet); - struct netmap_slot *slot; - int i, l, n, max_avail; - void *addr; - uint64_t paddr; - - slot = netmap_reset(na, NR_TX, 0, 0); - if (!slot) - return 0; - // tx rings, see - // sfxge_tx_qinit() - return 0; -} - - -/* - * Register/unregister. We are already under core lock. - * Only called on the first register or the last unregister. - */ -static int -sfxge_netmap_reg(struct netmap_adapter *na, int onoff) -{ - struct ifnet *ifp = na->ifp; - struct sfxge_softc *sc = ifp->if_softc; - int error = 0; - - SFXGE_LOCK(sc); - sfxge_stop(sc); - - /* Tell the stack that the interface is no longer active */ - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - - if (onoff) { - nm_set_native_flags(na); - } else { - nm_clear_native_flags(na); - } - sfxge_start(sc); /* also enables intr */ - SFXGE_UNLOCK(sc); - return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1); -} - - -/* - * Reconcile kernel and user view of the transmit ring. - */ -static int -sfxge_netmap_txsync(struct netmap_kring *kring, int flags) -{ - struct netmap_adapter *na = kring->na; - struct ifnet *ifp = na->ifp; - struct netmap_ring *ring = kring->ring; - u_int nm_i; /* index into the netmap ring */ - u_int nic_i; /* index into the NIC ring */ - u_int n; - u_int const lim = kring->nkr_num_slots - 1; - u_int const head = kring->rhead; - int reclaim_tx; - - struct sfxge_softc *sc = ifp->if_softc; - struct sfxge_txq *txr = sc->txq[kring->ring_id]; - -// bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, -// BUS_DMASYNC_POSTREAD); - - /* - * First part: process new packets to send. - */ - nm_i = kring->nr_hwcur; - if (nm_i != head) { /* we have new packets to send */ - nic_i = netmap_idx_k2n(kring, nm_i); /* NIC index */ - for (n = 0; nm_i != head ; n++) { - struct netmap_slot *slot = &ring->slot[j]; - u_int len = slot->len; - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - efx_buffer_t *desc; - - NM_CHECK_ADDR_LEN(addr, len); - - if (slot->flags & NS_BUF_CHANGED) { - /* buffer has changed, unload and reload map */ - netmap_reload_map(txr->packet_dma_tag, - txr->stmp[nic_i].map, addr); - slot->flags &= ~NS_BUF_CHANGED; - } - slot->flags &= ~NS_REPORT; - /* - * Fill the slot in the NIC ring. - * In this driver we need to rewrite the buffer - * address in the NIC ring. Other drivers do not - * need this. - * Use legacy descriptor, it is faster. - */ - desc->eb_addr = paddr; - desc->eb_size = len; - desc->eb_eop = 1; - txr->n_pend_desc = 1; - sfxge_tx_qlist_post(txr); - - /* make sure changes to the buffer are synced */ - bus_dmamap_sync(txr->packet_dma_tag, - txr->stmp[nic_i].map, BUS_DMASYNC_PREWRITE); - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - - } - kring->nr_hwcur = head; - - /* synchronize the NIC ring */ -// bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, -// BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - /* (re)start the transmitter up to slot l (excluded) */ -// IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(txr->me), l); - } - - /* - * Reclaim buffers for completed transmissions. - */ - if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) { - // XXX todo: add txeof body to reclaim buffers - if (txr->pending != txr->completed) { - n = (txr->pending > txr->completed) ? - txr->pending - txr->completed : - txr->pending - txr->completed + SFXGE_NDESCS; - txr->completed = txr->pending; - kring->nr_hwtail += n; - if (kring->nr_hwtail > lim) - kring->nr_hwtail -= lim + 1; - } - } - - - return 0; -} - - -/* - * Reconcile kernel and user view of the receive ring. - */ -static int -sfxge_netmap_rxsync(struct netmap_kring *kring, int flags) -{ - struct netmap_adapter *na = kring->na; - struct ifnet *ifp = na->ifp; - struct sfxge_softc *sc = ifp->if_softc; - struct sfxge_rxq *rxq = sc->rxq[kring->ring_id]; - struct sfxge_evq *evq = sc->evq[kring->ring_id]; - struct netmap_ring *ring = kring->ring; - u_int j, l, n, lim = kring->nkr_num_slots - 1; - int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; - u_int k = nm_rx_prologue(kring, &resvd); - - if (k > lim) - return netmap_ring_reinit(kring); - - /* XXX check sync modes */ -// bus_dmamap_sync(rxq->rxdma.dma_tag, rxq->rxdma.dma_map, -// BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - /* - * First part, import newly received packets into the netmap ring. - */ - nic_i = rxq->completed; - nm_i = netmap_idx_n2k(kring, nic_i); - - if (netmap_no_pendintr || force_update) { - uint16_t slot_flags = kring->nkr_slot_flags; - - // see sfxge_rx_qcomplete() - - for (n = 0; l != rxq->pending ; n++) { - struct sfxge_rx_sw_desc *rx_desc = &rxq->queue[nic_i]; - ring->slot[nm_i].len = - rx_desc->size - sc->rx_prefix_size; - ring->slot[nm_i].flags = slot_flags; -// bus_dmamap_sync(rxq->ptag, -// rxq->rx_buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD); - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - } - if (n) { /* update the state variables */ -// rxq->completed = nic_i; - kring->nr_hwtail = nm_i; - } - kring->nr_kflags &= ~NKR_PENDINTR; - } - - /* - * Second part: skip past packets that userspace has released. - */ - nm_i = kring->nr_hwcur; - if (nm_i != head) { - nic_i = netmap_idx_k2n(kring, nm_i); - for (n = 0; nm_i != head; n++) { - struct netmap_slot *slot = &ring->slot[nm_i]; - uint64_t paddr; - void *addr = PNMB(na, slot, &paddr); - - if (addr == netmap_buffer_base) /* bad buf */ - goto ring_reset; - - if (slot->flags & NS_BUF_CHANGED) { - //netmap_reload_map(rxq->ptag, rxbuf->pmap, addr); - slot->flags &= ~NS_BUF_CHANGED; - } -// curr->wb.upper.status_error = 0; -// curr->read.pkt_addr = htole64(paddr); -// bus_dmamap_sync(rxq->ptag, rxbuf->pmap, -// BUS_DMASYNC_PREREAD); - nm_i = nm_next(nm_i, lim); - nic_i = nm_next(nic_i, lim); - } - kring->nr_hwcur = head; -// bus_dmamap_sync(rxq->rxdma.dma_tag, rxq->rxdma.dma_map, -// BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - /* IMPORTANT: we must leave one free slot in the ring, - * so move l back by one unit - */ - nic_i = nm_prev(nic_i, lim); - //IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(rxr->me), nic_i); - } - - return 0; - -ring_reset: - return netmap_ring_reinit(kring); -} - - -/* - * The attach routine, called near the end of ixgbe_attach(), - * fills the parameters for netmap_attach() and calls it. - * It cannot fail, in the worst case (such as no memory) - * netmap mode will be disabled and the driver will only - * operate in standard mode. - */ -static void -sfxge_netmap_attach(struct sfxge_softc *sc) -{ - struct netmap_adapter na; - - bzero(&na, sizeof(na)); - - na.ifp = sc->ifnet; - na.na_flags = NAF_BDG_MAYSLEEP; - na.num_tx_desc = SFXGE_NDESCS; - na.num_rx_desc = SFXGE_NDESCS; - na.nm_txsync = sfxge_netmap_txsync; - na.nm_rxsync = sfxge_netmap_rxsync; - na.nm_register = sfxge_netmap_reg; - na.num_tx_rings = SFXGE_TXQ_NTYPES + SFXGE_RX_SCALE_MAX; - na.num_rx_rings = SFXGE_RX_SCALE_MAX; - netmap_attach(&na); -} - -/* end of file */ diff --git a/private/test/Makefile b/private/test/Makefile deleted file mode 100644 index 9b7e7623b..000000000 --- a/private/test/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -PROGS= interrupt_stats -NO_MAN= -CLEANFILES=$(PROGS) - -CFLAGS += -Werror -Wall -I../sys -CFLAGS += -Wextra - -.include - -all: $(PROGS) diff --git a/private/test/arp-daemon.c b/private/test/arp-daemon.c deleted file mode 100644 index a38c6636c..000000000 --- a/private/test/arp-daemon.c +++ /dev/null @@ -1,355 +0,0 @@ -#include -#include -#include -#include /* strcmp */ -#include /* open */ -#include /* close */ - -#include /* le64toh */ -#include /* PROT_* */ -#include /* ioctl */ -#include -#include -#include /* sockaddr.. */ -#include /* ntohs */ - -#include /* ifreq */ -#include -#include -#include - -#include /* sockaddr_in */ - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -struct arp { - u_short htype; - u_short ptype; - u_char hlen; - u_char plen; - u_short oper; - u_char sha[6]; - u_char spa[4]; - u_char tha[6]; - u_char tpa[4]; -}; - - -static int -get_ip(const char *ifname, struct in_addr *ip) -{ - int s; - struct ifreq ifreq; - - strcpy(ifreq.ifr_name, ifname); - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return (1); - - if (ioctl(s, SIOCGIFADDR, &ifreq) == -1) { - close(s); - return (1); - } - - close(s); - - bcopy(&((struct sockaddr_in *)(&ifreq.ifr_addr))->sin_addr, ip, 4); - - return (0); -} - - -static void -create_ether(void *pkt, u_char *shost, u_char *dhost) -{ - struct ether_header *eh = (struct ether_header *) pkt; - - memcpy(eh->ether_shost, shost, 6); - memcpy(eh->ether_dhost, dhost, 6); - eh->ether_type = htons(ETHERTYPE_ARP); -} - - -static void -create_arp(void *pkt, u_char *sha, struct in_addr *spa, u_char *tha, - struct in_addr *tpa, int oper) -{ - struct arp *arp; - - arp = (struct arp *) pkt; - arp->htype = htons(1); /* Ethernet */ - arp->ptype = htons(ETHERTYPE_IP); - arp->hlen = 6; - arp->plen = 4; - arp->oper = htons(oper); - memcpy(arp->sha, sha, 6); - memcpy(arp->spa, spa, 4); - if (oper == 2) - memcpy(arp->tha, tha, 6); - memcpy(arp->tpa, tpa, 4); -} - - -static int -process_rings(struct netmap_ring *rxring, struct netmap_ring *txring, - struct in_addr *spa, u_char *shost, int limit) -{ - struct ether_header *eh; - struct arp *arp; - void *rxpkt, *txpkt; - int j, k, m = 0; - - j = rxring->nr_cur; /* RX */ - k = txring->nr_cur; /* TX */ - // XXX not sure the condition is correct - while (rxring->nr_avail > 0 && - txring->nr_avail > 0 && - (m != limit)) { - rxpkt = NETMAP_RING_PACKET(rxring, j); - eh = (struct ether_header *) rxpkt; - if (ntohs(eh->ether_type) != ETHERTYPE_ARP) - goto next; - - arp = (struct arp *) &eh[1]; - if (ntohs(arp->htype) != 1 || - ntohs(arp->ptype) != ETHERTYPE_IP || - arp->hlen != 6 || arp->plen != 4 || - ntohs(arp->oper) != 1 /* request */ || - memcmp(arp->tpa, spa, arp->plen) != 0) - goto next; - - txpkt = NETMAP_RING_PACKET(txring, k); - create_ether(txpkt, shost, arp->sha); - create_arp(txpkt + sizeof(struct ether_header), - shost, (struct in_addr *) arp->tpa, - arp->sha, (struct in_addr *) arp->spa, - 2); - NETMAP_RING_SLOTS(txring)[j].plen = 42; - - txring->nr_avail--; - - m++; - -next: - j = nm_ring_next(rxring, j); - rxring->nr_cur = j; - - k = nm_ring_next(txring, k); - txring->nr_cur = k; - } - - return (m); -} - - -static int -process_interface(struct netmap_if *nifp, struct in_addr *spa, u_char *shost, - int limit) -{ - struct netmap_ring *rxring, *txring; - int j, k, m = 0; - - for (int i = 0; i < nifp->ni_num_queues; i++) { - txring = NETMAP_TX_RING(nifp, i); - if (txring->nr_avail == 0) - continue; - - j = k = 0; - while (j < nifp->ni_num_queues && - k < nifp->ni_num_queues && - (m != limit)) { - rxring = NETMAP_RX_RING(nifp, j); - txring = NETMAP_TX_RING(nifp, k); - - if (rxring->nr_avail == 0) { - j++; - continue; - } - - if (txring->nr_avail == 0) { - k++; - continue; - } - - m += process_rings(rxring, txring, spa, shost, - limit - m); - } - } - return (m); -} - - -static void -print_output(int processed, int total, double delta) -{ - - double pps = processed / delta; - char units[4] = { '\0', 'K', 'M', 'G' }; - int punit = 0; - - while (pps >= 1000) { - pps /= 1000; - punit += 1; - } - - printf("Processed %d of %d requests in %.2f seconds.\n", - processed, total, delta); - printf("Speed: %.2f%cpps. Packet loss: %.2f%%.\n", - pps, units[punit], (total - processed) * 100.0 / total); -} - - -int -main(int arc, char **argv) -{ - int fd, err; - struct nmreq ifreq; - struct netmap_if *nifp; - struct in_addr spa; - void *tmp_addr; - struct pollfd fds[1]; - u_char shost[6]; - int sent = 0, n, burst; - struct timeval tic, toc; - double delta; - - if (arc != 4) { - printf("Usage: %s \n", argv[0]); - return (1); - } - - - /* retrieve ip address. */ - if (get_ip(argv[1], &spa)) { - printf("Unable to retrieve IP address.\n"); - return(1); - } - - /* setup netmap interface. */ - if ((fd = open("/dev/netmap", O_RDWR)) == -1) { - printf("Unable to open \"/dev/netmap\".\n"); - return (1); - } - - strcpy(ifreq.nr_name, argv[1]); - if ((ioctl(fd, NIOCREGIF, &ifreq)) == -1) { - printf("Unable to register \"%s\" interface.\n", argv[1]); - err = 1; - goto close; - } - - tmp_addr = (struct netmap_d *) mmap(0, ifreq.nr_memsize, - PROT_WRITE | PROT_READ, - MAP_SHARED, fd, 0); - if (tmp_addr == MAP_FAILED) { - printf("Unable to mmap.\n"); - err = 1; - goto close; - } - nifp = NETMAP_IF(tmp_addr, ifreq.nr_offset); - - /* retrieve mac address. */ - { - struct ifreq x; - bzero(&x, sizeof(x)); - strncpy(x.ifr_name, argv[1], sizeof(x.ifr_name)); - if ((ioctl(fd, SIOCGIFADDR, &x)) == -1) { - printf("Unable to retrieve MAC address.\n"); - err = 1; - goto unmap; - } - bcopy(&x.ifr_addr.sa_data, shost, 6); - } - - /* how many packets to wait for. */ - n = atoi(argv[2]); - - /* packets burst size. */ - burst = atoi(argv[3]); - - /* setup poll(2) machanism. */ - memset(fds, 0, sizeof(fds)); - fds[0].fd = fd; - fds[0].events = (POLLIN); - - /* Sleep to give the registered interface some to time to - bootstrap. */ - printf("Sleeping 5 secs..\n"); - sleep(5); - - /* wait for the first packet. */ - if (poll(fds, 1, INFTIM) <= 0) { - printf("poll <= 0\n"); - goto unmap; - } - - /* main loop */ - gettimeofday(&tic, NULL); - while (1) { - struct netmap_ring *txring; - int limit, m, done; - - /* Invoke the poll(2) mechanism. - Wait at most 1 second before quitting. */ - if (poll(fds, 1, 1 * 1000) <= 0) { - gettimeofday(&toc, NULL); - toc.tv_sec -= 1; - delta = toc.tv_sec - tic.tv_sec + - (toc.tv_usec - tic.tv_usec) / 1000000.0; - print_output(sent, n, delta); - break; - } - - if (fds[0].revents & POLLIN) { - fds[0].events &= ~POLLIN; - fds[0].events |= POLLOUT; - } - - if (fds[0].revents & POLLOUT) { - limit = MIN(burst, n - sent); - - m = process_interface(nifp, &spa, shost, limit); - sent += m; - - /* re-enable POLLIN on input. */ - fds[0].events |= POLLIN; - ioctl(fd, NIOCSYNCRX, NULL); - - /* disable POLLOUT on output. */ - fds[0].events &= ~POLLOUT; - ioctl(fd, NIOCSYNCTX, NULL); - } - - /* All the responses have benn sent. - Wait all the TX queues to be emtpy. */ - if (sent == n) { - /* wait all the TX queues to be empty. */ - done = 0; - while (!done) { - done = 1; - for (int i = 0; i < nifp->ni_num_queues; i++) { - txring = NETMAP_TX_RING(nifp, i); - if (NETMAP_TX_RING_EMPTY(txring)) - continue; - - done = 0; - ioctl(fds[0].fd, NIOCSYNCTX, NULL); - break; - } - } - gettimeofday(&toc, NULL); - delta = toc.tv_sec - tic.tv_sec + - (toc.tv_usec - tic.tv_usec) / 1000000.0; - print_output(sent, n, delta); - break; - } - } - - ioctl(fd, NIOCUNREGIF, &ifreq); - -unmap: - munmap(tmp_addr, ifreq.nr_memsize); -close: - close(fd); - - return (err); -} diff --git a/private/test/arp-request.c b/private/test/arp-request.c deleted file mode 100644 index 7f06913fd..000000000 --- a/private/test/arp-request.c +++ /dev/null @@ -1,337 +0,0 @@ -#include -#include -#include -#include /* strcmp */ -#include /* open */ -#include /* close */ -#include /* sigsuspend */ - -#include /* le64toh */ -#include /* PROT_* */ -#include /* ioctl */ -#include -#include -#include /* sockaddr.. */ -#include /* ntohs */ - -#include /* ifreq */ -#include -#include -#include - -#include /* sockaddr_in */ - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - - -struct arp { - u_short htype; - u_short ptype; - u_char hlen; - u_char plen; - u_short oper; - u_char sha[6]; - u_char spa[4]; - u_char tha[6]; - u_char tpa[4]; -}; - - -static int -get_ip(const char *ifname, struct in_addr *ip) -{ - int s; - struct ifreq ifreq; - - strcpy(ifreq.ifr_name, ifname); - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return (1); - - if (ioctl(s, SIOCGIFADDR, &ifreq) == -1) { - close(s); - return (1); - } - - close(s); - - bcopy(&((struct sockaddr_in *)(&ifreq.ifr_addr))->sin_addr, ip, 4); - - return (0); -} - - -static void -create_ether(void *pkt, u_char *shost, u_char *dhost) -{ - struct ether_header *eh = (struct ether_header *) pkt; - - memcpy(eh->ether_shost, shost, 6); - memcpy(eh->ether_dhost, dhost, 6); - eh->ether_type = htons(ETHERTYPE_ARP); -} - - -static void -create_arp(void *pkt, u_char *sha, struct in_addr *spa, u_char *tha, - struct in_addr *tpa, int oper) -{ - struct arp *arp; - - arp = (struct arp *) pkt; - arp->htype = htons(1); /* Ethernet */ - arp->ptype = htons(ETHERTYPE_IP); - arp->hlen = 6; - arp->plen = 4; - arp->oper = htons(oper); - memcpy(arp->sha, sha, 6); - memcpy(arp->spa, spa, 4); - if (oper == 2) - memcpy(arp->tha, tha, 6); - memcpy(arp->tpa, tpa, 4); -} - - -static int -send_request(struct netmap_ring *ring, u_char *shost, u_char *dhost, - struct in_addr *spa, struct in_addr *tpa, int limit) -{ - struct ether_header *eh; - struct arp *arp; - void *pkt; - int j, m = 0; - - j = ring->nr_cur; - while(ring->nr_avail > 0 && (m != limit)) { - pkt = NETMAP_RING_PACKET(ring, j); - - eh = (struct ether_header *) pkt; - create_ether(pkt, shost, dhost); - - arp = (struct arp *) &eh[1]; - create_arp(arp, shost, spa, dhost, tpa, 1); - - NETMAP_RING_SLOTS(ring)[j].plen = 42; - - ring->nr_avail--; - - j = nm_ring_next(ring, j); - m++; - } - ring->nr_cur = j; - - return (m); -} - - -static int -receive_reply(struct netmap_ring *ring, struct in_addr *me, int limit, - int *received) -{ - struct ether_header *eh; - struct arp *arp; - void *pkt; - int j, m = 0; - - j = ring->nr_cur; - while (ring->nr_avail > 0 && (m != limit)) { - pkt = NETMAP_RING_PACKET(ring, j); - - m++; - - eh = (struct ether_header *) pkt; - if (ntohs(eh->ether_type) != ETHERTYPE_ARP) - goto next; - - arp = (struct arp *) &eh[1]; - if (ntohs(arp->htype) != 1 || - ntohs(arp->ptype) != ETHERTYPE_IP || - arp->hlen != 6 || arp->plen != 4 || - ntohs(arp->oper) != 2 /* response */ || - memcmp(arp->tpa, me, arp->plen) != 0) - goto next; - - (*received)++; -next: - j = NETMAP_RING_NEXT(ring, j); - ring->nr_cur = j; - } - - return (m); -} - - -static void -print_output(int received, int sent, double delta) -{ - - double pps = received / delta; - char units[4] = { '\0', 'K', 'M', 'G' }; - int punit = 0; - - while (pps >= 1000) { - pps /= 1000; - punit += 1; - } - - printf("Received %d of %d responses in %.2f seconds.\n", - received, sent, delta); - printf("Speed: %.2f%cpps. Packet loss: %.2f%%.\n", - pps, units[punit], (sent - received) * 100.0 / sent); -} - - -int -main(int arc, char **argv) -{ - int fd, err; - struct ifreq ifreq; - struct netmap_if *nifp; - struct in_addr spa, tpa; - void *tmp_addr; - struct pollfd fds[1]; - u_char shost[6], dhost[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - int sent = 0, received = 0, n, burst; - struct timeval tic, toc; - double delta; - - if (arc != 5) { - printf("Usage: %s \n", argv[0]); - return (1); - } - - /* retrieve source ip address. */ - if (get_ip(argv[1], &spa)) { - printf("Unable to retrieve source IP address.\n"); - return(1); - } - - /* retrieve destination ip address. */ - if (inet_aton(argv[2], &tpa) == 0) { - printf("Unable to parse destination IP address.\n"); - return(1); - } - - - /* setup netmap interface. */ - if ((fd = open("/dev/netmap", O_RDWR)) == -1) { - printf("Unable to open \"/dev/netmap\".\n"); - return (1); - } - - tmp_addr = (struct netmap_d *) mmap(0, NETMAP_MEMORY_SIZE, - PROT_WRITE | PROT_READ, - MAP_SHARED, fd, 0); - if (tmp_addr == MAP_FAILED) { - printf("Unable to mmap.\n"); - err = 1; - goto close; - } - - strcpy(ifreq.ifr_name, argv[1]); - if ((ioctl(fd, NIOCREGIF, &ifreq)) == -1) { - printf("Unable to register \"%s\" interface.\n", argv[1]); - err = 1; - goto unmap; - } - nifp = NETMAP_IF(tmp_addr, ifreq.ifr_data); - - /* retrieve mac address. */ - if ((ioctl(fd, SIOCGIFADDR, &ifreq)) == -1) { - printf("Unable to retrieve MAC address.\n"); - err = 1; - goto unmap; - } - bcopy(&ifreq.ifr_addr.sa_data, shost, 6); - - /* how many packets. */ - n = atoi(argv[3]); - - /* packets burst size. */ - burst = atoi(argv[4]); - - /* setup poll(2) machanism. */ - memset(fds, 0, sizeof(fds)); - fds[0].fd = fd; - fds[0].events = (POLLOUT | POLLIN); - - /* Sleep to give the registered interface some to time to - bootstrap. */ - printf("Sleeping 5 secs..\n"); - sleep(5); - - /* main loop */ - gettimeofday(&tic, NULL); - while (1) { - struct netmap_ring *txring, *rxring; - int limit, m; - - /* Invoke the poll(2) mechanism. - Wait at most 1 second before quitting. */ - if (poll(fds, 1, 1 * 1000) <= 0) { - gettimeofday(&toc, NULL); - toc.tv_sec -= 1; - delta = toc.tv_sec - tic.tv_sec + - (toc.tv_usec - tic.tv_usec) / 1000000.0; - print_output(received, sent, delta); - break; - } - - - /* Process received packets. */ - if (fds[0].revents & POLLIN) { - limit = MIN(burst, n - received); - for (int i = 0; i < nifp->ni_num_queues; i++) { - rxring = NETMAP_RX_RING(nifp, i); - if (rxring->nr_avail == 0) - continue; - - m = receive_reply(rxring, &spa, - limit, &received); - limit -= m; - if (limit == 0) - break; - } - ioctl(fds[0].fd, NIOCSYNCRX, NULL); - } - - if (fds[0].revents & POLLOUT) { - limit = MIN(burst, n - sent); - for (int i = 0; i < nifp->ni_num_queues; i++) { - txring = NETMAP_TX_RING(nifp, i); - if (txring->nr_avail == 0) - continue; - - m = send_request(txring, shost, dhost, - &spa, &tpa, limit); - sent += m; - limit -= m; - if (limit == 0) - break; - } - ioctl(fds[0].fd, NIOCSYNCTX, NULL); - - /* disable WR polling when done. */ - if (sent == n) - fds[0].events &= ~POLLOUT; - } - - /* All the responses have been received correctly. */ - if (received == n) { - gettimeofday(&toc, NULL); - delta = toc.tv_sec - tic.tv_sec + - (toc.tv_usec - tic.tv_usec) / 1000000.0; - print_output(received, sent, delta); - break; - } - - } - - ioctl(fd, NIOCUNREGIF, &ifreq); - -unmap: - munmap(tmp_addr, NETMAP_MEMORY_SIZE); -close: - close(fd); - - return (err); -} diff --git a/private/test/interrupt_stats.c b/private/test/interrupt_stats.c deleted file mode 100644 index f7bd42029..000000000 --- a/private/test/interrupt_stats.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -#include -#include -#include /* sysctl* */ -#include /* selinfo */ -#include /* sockaddr */ -#include -#include /* bus_addr_t */ -#include /* dma*tag */ - -#include - -#include -#include - - -int -main(int argc, char **argv) -{ - struct stats statz; - size_t slen; - char cmd[256]; - int i; - - if (argc < 2) { - fprintf(stderr, "Usage: %s driver" - "\n" - "supported drivers: lem, ixgbe\n" - "", - argv[0]); - return 1; - } - - snprintf(cmd, sizeof(cmd), "dev.%s.stats", argv[1]); - - slen = sizeof(statz); - if (sysctlbyname(cmd, &statz, &slen, NULL, 0)) { - warn("unable to read %s", cmd); - return 1; - } - - for (i = 0; i < NETMAP_MAX_STATS; i++) - fprintf(stdout, "%llu %u %u\n", - statz.statsdata[i].tsc, - statz.statsdata[i].unit, - statz.statsdata[i].queue); - return 0; -} diff --git a/private/test/lro.html b/private/test/lro.html deleted file mode 100644 index bf7d66ca6..000000000 --- a/private/test/lro.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - diff --git a/private/test/nest.c b/private/test/nest.c deleted file mode 100644 index b08cb6ef9..000000000 --- a/private/test/nest.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -int f_0(int x) -{ - return x + 1; -} - -int f_100(int x); -int main(int ac, char *av[]) -{ - int i, cnt, lim = atoi(av[1]); - volatile uint64_t res; - for (cnt = 0; cnt < lim; cnt++) { - uint64_t n = 0; - for (n = 0; n < 1000000; n++) - n += f_100(n); - res = n; - } -} - diff --git a/private/test/netmap_drop.diff b/private/test/netmap_drop.diff deleted file mode 100644 index 68a377de6..000000000 --- a/private/test/netmap_drop.diff +++ /dev/null @@ -1,567 +0,0 @@ -Index: head/sys/netinet/udp_usrreq.c -=================================================================== ---- head/sys/netinet/udp_usrreq.c (revision 234237) -+++ head/sys/netinet/udp_usrreq.c (working copy) -@@ -943,6 +943,7 @@ - #define UH_WLOCKED 2 - #define UH_RLOCKED 1 - #define UH_UNLOCKED 0 -+extern int netmap_drop; // XXX - static int - udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *td) -@@ -957,6 +958,7 @@ - u_short fport, lport; - int unlock_udbinfo; - -+ if (netmap_drop == 32) { m_freem(m); if (control) m_freem(control); return 0; } // XXX drop - /* - * udp_output() may need to temporarily bind or connect the current - * inpcb. As such, we don't know up front whether we will need the -@@ -1072,10 +1074,12 @@ - error = EINVAL; - goto release; - } -+ if (netmap_drop == 33) { error = 0; goto release; } // XXX drop - error = in_pcbbind_setup(inp, (struct sockaddr *)&src, - &laddr.s_addr, &lport, td->td_ucred); - if (error) - goto release; -+ if (netmap_drop == 34) { error = 0; goto release; } // XXX drop - } - - /* -@@ -1097,9 +1101,11 @@ - * Jail may rewrite the destination address, so let it do - * that before we use it. - */ -+ if (netmap_drop == 35) { error = 0; goto release; } // XXX drop - error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); - if (error) - goto release; -+ if (netmap_drop == 36) { error = 0; goto release; } // XXX drop - - /* - * If a local address or port hasn't yet been selected, or if -@@ -1160,6 +1166,7 @@ - } - } - -+ if (netmap_drop == 37) { error = 0; goto release; } // XXX drop - /* - * Calculate data length and get a mbuf for UDP, IP, and possible - * link-layer headers. Immediate slide the data pointer back forward -@@ -1230,6 +1237,7 @@ - INP_HASH_WUNLOCK(&V_udbinfo); - else if (unlock_udbinfo == UH_RLOCKED) - INP_HASH_RUNLOCK(&V_udbinfo); -+ if (netmap_drop == 31) { error = 0; goto release; } // XXX - error = ip_output(m, inp->inp_options, NULL, ipflags, - inp->inp_moptions, inp); - if (unlock_udbinfo == UH_WLOCKED) -@@ -1575,6 +1583,7 @@ - { - struct inpcb *inp; - -+ if (netmap_drop == 30) { m_freem(m); if (control) m_freem(control); return 0; } // XXX - inp = sotoinpcb(so); - KASSERT(inp != NULL, ("udp_send: inp == NULL")); - return (udp_output(inp, m, addr, control, td)); -Index: head/sys/netinet/ip_output.c -=================================================================== ---- head/sys/netinet/ip_output.c (revision 234237) -+++ head/sys/netinet/ip_output.c (working copy) -@@ -98,7 +98,7 @@ - - extern int in_mcast_loop; - extern struct protosw inetsw[]; -- -+extern int netmap_drop; - /* - * IP output. The packet in mbuf chain m contains a skeletal IP - * header (with len, off, ttl, proto, tos, src, dst). -@@ -134,6 +134,7 @@ - #endif - M_ASSERTPKTHDR(m); - -+ if (netmap_drop == 50) {goto bad; } // XXX - if (inp != NULL) { - INP_LOCK_ASSERT(inp); - M_SETFIB(m, inp->inp_inc.inc_fibnum); -@@ -164,6 +165,7 @@ - } - #endif - } -+ if (netmap_drop == 51) {goto bad; } // XXX - - if (opt) { - int len = 0; -@@ -305,6 +307,7 @@ - else - isbroadcast = in_broadcast(dst->sin_addr, ifp); - } -+ if (netmap_drop == 56) {goto bad; } // XXX - /* - * Calculate MTU. If we have a route that is up, use that, - * otherwise use the interface's MTU. -@@ -476,6 +479,7 @@ - } - - sendit: -+ if (netmap_drop == 52) {goto bad; } // XXX - #ifdef IPSEC - switch(ip_ipsec_output(&m, inp, &flags, &error)) { - case 1: -@@ -503,6 +507,7 @@ - if (!PFIL_HOOKED(&V_inet_pfil_hook)) - goto passout; - -+ if (netmap_drop == 53) {goto bad; } // XXX - /* Run through list of hooks for output packets. */ - odst.s_addr = ip->ip_dst.s_addr; - error = pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, inp); -@@ -568,6 +573,7 @@ - #endif /* IPFIREWALL_FORWARD */ - - passout: -+ if (netmap_drop == 54) {goto bad; } // XXX - /* 127/8 must not appear on wire - RFC1122. */ - if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || - (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { -@@ -628,6 +634,7 @@ - * to avoid confusing lower layers. - */ - m->m_flags &= ~(M_PROTOFLAGS); -+ if (netmap_drop == 55) {goto bad; } // XXX - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, ro); - goto done; -Index: head/sys/kern/uipc_syscalls.c -=================================================================== ---- head/sys/kern/uipc_syscalls.c (revision 234237) -+++ head/sys/kern/uipc_syscalls.c (working copy) -@@ -680,6 +680,7 @@ - return (error); - } - -+extern int netmap_drop; // XXX - static int - sendit(td, s, mp, flags) - struct thread *td; -@@ -696,6 +697,7 @@ - return (ECAPMODE); - #endif - -+ if (netmap_drop == 21) return 0; // XXX - if (mp->msg_name != NULL) { - error = getsockaddr(&to, mp->msg_name, mp->msg_namelen); - if (error) { -@@ -706,6 +708,7 @@ - } else { - to = NULL; - } -+ if (netmap_drop == 22) { error = 0; goto bad; } // XXX - - if (mp->msg_control) { - if (mp->msg_controllen < sizeof(struct cmsghdr) -@@ -735,6 +738,7 @@ - control = NULL; - } - -+ if (netmap_drop == 23) {error =0; goto bad; } // XXX - error = kern_sendit(td, s, mp, flags, control, UIO_USERSPACE); - - bad: -@@ -767,6 +771,7 @@ - rights = CAP_WRITE; - if (mp->msg_name != NULL) - rights |= CAP_CONNECT; -+ if (netmap_drop == 24) { return 0; } // XXX - error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL); - if (error) - return (error); -@@ -807,6 +812,7 @@ - ktruio = cloneuio(&auio); - #endif - len = auio.uio_resid; -+ if (netmap_drop == 25) { error = 0; goto bad; } // XXX - error = sosend(so, mp->msg_name, &auio, 0, control, flags, td); - if (error) { - if (auio.uio_resid != len && (error == ERESTART || -@@ -849,6 +855,7 @@ - struct iovec aiov; - int error; - -+ if (netmap_drop == 20) return 0; - msg.msg_name = uap->to; - msg.msg_namelen = uap->tolen; - msg.msg_iov = &aiov; -Index: head/sys/kern/uipc_socket.c -=================================================================== ---- head/sys/kern/uipc_socket.c (revision 234237) -+++ head/sys/kern/uipc_socket.c (working copy) -@@ -853,6 +853,7 @@ - return (error); - } - -+extern int netmap_drop; // XXX - #ifdef ZERO_COPY_SOCKETS - struct so_zerocopy_stats{ - int size_ok; -@@ -995,6 +996,7 @@ - int atomic = sosendallatonce(so) || top; - #endif - -+ if (netmap_drop == 40) {error = 0; goto out;} // XXX - KASSERT(so->so_type == SOCK_DGRAM, ("sodgram_send: !SOCK_DGRAM")); - KASSERT(so->so_proto->pr_flags & PR_ATOMIC, - ("sodgram_send: !PR_ATOMIC")); -@@ -1071,6 +1073,7 @@ - error = EMSGSIZE; - goto out; - } -+ if (netmap_drop == 41) {error = 0; goto out;} // XXX - if (uio == NULL) { - resid = 0; - if (flags & MSG_EOR) -@@ -1096,6 +1099,7 @@ - #endif - resid = uio->uio_resid; - } -+ if (netmap_drop == 42) {error = 0; goto out;} // XXX - KASSERT(resid == 0, ("sosend_dgram: resid != 0")); - /* - * XXXRW: Frobbing SO_DONTROUTE here is even worse without sblock -@@ -1106,6 +1110,7 @@ - so->so_options |= SO_DONTROUTE; - SOCK_UNLOCK(so); - } -+ if (netmap_drop == 43) {error = 0; goto out;} // XXX - /* - * XXX all the SBS_CANTSENDMORE checks previously done could be out - * of date. We could have recieved a reset packet in an interrupt or -Index: head/sys/dev/netmap/netmap.c -=================================================================== ---- head/sys/dev/netmap/netmap.c (revision 234288) -+++ head/sys/dev/netmap/netmap.c (working copy) -@@ -115,7 +115,100 @@ - SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, - CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets."); - -+/* -+ * debugging support to analyse syscall behaviour -+ * netmap_drop is the point where to drop - -+ Path is: -+ -+ ./libthr/thread/thr_syscalls.c -+ lib/libc/i386/SYS.h -+ lib/libc/i386/sys/syscall.S -+ -+ head/sys/kern/syscall.master -+ ; Processed to created init_sysent.c, syscalls.c and syscall.h. -+ sys/kern/uipc_syscalls.c::sys_sendto() -+ sendit() -+ kern_sendit() -+ sosend() -+ sys/kern/uipc_socket.c::sosend() -+ so->so_proto->pr_usrreqs->pru_sosend(...) -+ sys/netinet/udp_usrreq.c::udp_usrreqs { } -+ .pru_sosend = sosend_dgram, -+ .pru_send = udp_send, -+ .pru_soreceive = soreceive_dgram, -+ sys/kern/uipc_socket.c::sosend_dgram() -+ m_uiotombuf() -+ (*so->so_proto->pr_usrreqs->pru_send) -+ sys/netinet/udp_usrreq.c::udp_send() -+ sotoinpcb(so); -+ udp_output() -+ INP_RLOCK(inp); -+ INP_HASH_RLOCK(&V_udbinfo); -+ fill udp and ip headers -+ ip_output() -+ -+ 30 udp_send() before udp_output -+ 31 udp_output before ip_output -+ 32 udp_output beginning -+ 33 before in_pcbbind_setup -+ 34 after in_pcbbind_setup -+ 35 before prison_remote_ip4 -+ 36 after prison_remote_ip4 -+ 37 before computing udp -+ -+ 20 beginning of sys_sendto -+ 21 beginning of sendit -+ 22 sendit after getsockaddr -+ 23 before kern_sendit -+ 24 kern_sendit before getsock_cap() -+ 25 kern_sendit before sosend() -+ -+ 40 sosend_dgram beginning -+ 41 sosend_dgram after sbspace -+ 42 sosend_dgram after m_uiotombuf -+ 43 sosend_dgram after SO_DONTROUTE -+ 44 sosend_dgram after pru_send (useless) -+ -+ 50 ip_output beginning -+ 51 ip_output after flowtable -+ 52 ip_output at sendit -+ 53 ip_output after pfil_hooked -+ 54 ip_output at passout -+ 55 ip_output before if_output -+ 56 ip_output after rtalloc etc. -+ -+ 60 uiomove print -+ -+ 70 pfil.c:: pfil_run_hooks beginning -+ 71 print number of pfil entries -+ -+ 80 ether_output start -+ 81 ether_output after first switch -+ 82 ether_output after M_PREPEND -+ 83 ether_output after simloop -+ 84 ether_output after carp and netgraph -+ 85 ether_output_frame before if_transmit() -+ -+ 90 ixgbe_mq_start (if_transmit) beginning -+ 91 ixgbe_mq_start_locked before ixgbe_xmit -+ -+FLAGS: -+ 1 disable ETHER_BPF_MTAP -+ 2 disable drbr stats update -+ 4 -+ 8 -+ 16 -+ 32 -+ 64 -+ 128 -+ */ -+int netmap_drop = 0; -+int netmap_flags = 0; /* debug flags */ -+ -+SYSCTL_INT(_dev_netmap, OID_AUTO, drop, CTLFLAG_RW, &netmap_drop, 0 , ""); -+SYSCTL_INT(_dev_netmap, OID_AUTO, flags, CTLFLAG_RW, &netmap_flags, 0 , ""); -+ - /*------------- memory allocator -----------------*/ - #ifdef NETMAP_MEM2 - #include "netmap_mem2.c" -@@ -1067,7 +1160,8 @@ - kring->nr_hwcur + kring->nr_hwavail, len); - na->nm_lock(ifp, NETMAP_CORE_LOCK, 0); - if (kring->nr_hwavail >= lim) { -- D("stack ring %s full\n", ifp->if_xname); -+ if (netmap_verbose) -+ D("stack ring %s full\n", ifp->if_xname); - goto done; /* no space */ - } - if (len > NETMAP_BUF_SIZE) { -@@ -1263,7 +1357,7 @@ - netmap_loader(__unused struct module *module, int event, __unused void *arg) - { - int error = 0; -- -+D("sizeof int %d", sizeof(int)); - switch (event) { - case MOD_LOAD: - error = netmap_init(); -Index: head/sys/dev/ixgbe/ixgbe.c -=================================================================== ---- head/sys/dev/ixgbe/ixgbe.c (revision 234237) -+++ head/sys/dev/ixgbe/ixgbe.c (working copy) -@@ -322,10 +322,11 @@ - * be a reference on how to implement netmap support in a driver. - * Additional comments are in ixgbe_netmap.h . - * -- * contains functions for netmap support -+ * contains functions for netmap support - * that extend the standard driver. - */ - #include -+extern int netmap_flags, netmap_drop; // XXX - #endif /* DEV_NETMAP */ - - /********************************************************************* -@@ -797,20 +798,28 @@ - struct tx_ring *txr; - int i = 0, err = 0; - -+ if (netmap_drop == 90) {m_freem(m); return 0; } // XXX - /* Which queue to use */ -+ if (netmap_flags & 4 && !(m->m_flags & M_FLOWID)) printf("%s %d no flowid curcpu %d\n", __func__, __LINE__, curcpu); - if ((m->m_flags & M_FLOWID) != 0) - i = m->m_pkthdr.flowid % adapter->num_queues; - else - i = curcpu % adapter->num_queues; -+ if (netmap_flags & 32) i = 0; // XXX - - txr = &adapter->tx_rings[i]; - que = &adapter->queues[i]; - -+ /* -+ * using IXGBE_TX_TRYLOCK() saves about 100ns/pkt: even if -+ * contentions are infrequent, when they happen we lose a lot. -+ */ - if (((txr->queue_status & IXGBE_QUEUE_DEPLETED) == 0) && - IXGBE_TX_TRYLOCK(txr)) { - err = ixgbe_mq_start_locked(ifp, txr, m); - IXGBE_TX_UNLOCK(txr); - } else { -+ if (netmap_drop == 92) {m_freem(m); return 0; } // XXX - err = drbr_enqueue(ifp, txr->br, m); - taskqueue_enqueue(que->tq, &que->que_task); - } -@@ -845,6 +854,7 @@ - - /* Process the queue */ - while (next != NULL) { -+ if (netmap_drop == 91) {m_freem(next); err = 0; goto cont; } // XXX - if ((err = ixgbe_xmit(txr, &next)) != 0) { - if (next != NULL) - err = drbr_enqueue(ifp, txr->br, next); -@@ -862,6 +872,7 @@ - txr->queue_status |= IXGBE_QUEUE_DEPLETED; - break; - } -+cont: // XXX - next = drbr_dequeue(ifp, txr->br); - } - -@@ -1712,6 +1723,7 @@ - txbuf = &txr->tx_buffers[first]; - map = txbuf->map; - -+ if (netmap_drop == 93) {m_freem(m_head); return 0; } // XXX - /* - * Map the packet for DMA. - */ -@@ -1752,6 +1764,7 @@ - *m_headp = NULL; - return (error); - } -+ if (netmap_drop == 94) {m_freem(*m_headp); return 0; } // XXX - - /* Make certain there are enough descriptors */ - if (nsegs > txr->tx_avail - 2) { -@@ -1785,6 +1798,7 @@ - #endif - - #ifdef IXGBE_FDIR -+----- - /* Do the flow director magic */ - if ((txr->atr_sample) && (!adapter->fdir_reinit)) { - ++txr->atr_count; -Index: head/sys/net/pfil.c -=================================================================== ---- head/sys/net/pfil.c (revision 234237) -+++ head/sys/net/pfil.c (working copy) -@@ -62,6 +62,8 @@ - VNET_DEFINE(struct pfilheadhead, pfil_head_list); - #define V_pfil_head_list VNET(pfil_head_list) - -+extern int netmap_drop; -+ - /* - * pfil_run_hooks() runs the specified packet filter hooks. - */ -@@ -73,8 +75,18 @@ - struct packet_filter_hook *pfh; - struct mbuf *m = *mp; - int rv = 0; -- -+if (netmap_drop == 70) return 0; -+ - PFIL_RLOCK(ph, &rmpt); -+if (netmap_drop == 71) { -+ int num=0, act=0; -+ for (pfh = pfil_hook_get(dir, ph); pfh != NULL; -+ pfh = TAILQ_NEXT(pfh, pfil_link)) { -+ num++; -+ if (pfh->pfil_func != NULL) act++; -+ } -+ printf("dir %d total %d active %d\n", dir, num, act); -+} - KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0")); - for (pfh = pfil_hook_get(dir, ph); pfh != NULL; - pfh = TAILQ_NEXT(pfh, pfil_link)) { -Index: head/sys/net/if_ethersubr.c -=================================================================== ---- head/sys/net/if_ethersubr.c (revision 234237) -+++ head/sys/net/if_ethersubr.c (working copy) -@@ -148,7 +148,7 @@ - #define V_ether_ipfw VNET(ether_ipfw) - #endif - -- -+extern int netmap_flags, netmap_drop; // XXX - /* - * Ethernet output routine. - * Encapsulate a packet of type family for the local net. -@@ -169,6 +169,7 @@ - int loop_copy = 1; - int hlen; /* link layer header length */ - -+ if (netmap_drop == 80) { error = 0; goto bad; } // XXX - if (ro != NULL) { - if (!(m->m_flags & (M_BCAST | M_MCAST))) - lle = ro->ro_lle; -@@ -191,6 +192,7 @@ - switch (dst->sa_family) { - #ifdef INET - case AF_INET: -+if (netmap_flags & 8 && lle == NULL) printf("%s %d ro %p rt0 %p no lle\n", __FUNCTION__, __LINE__, ro, rt0); - if (lle != NULL && (lle->la_flags & LLE_VALID)) - memcpy(edst, &lle->ll_addr.mac16, sizeof(edst)); - else -@@ -317,6 +319,7 @@ - return (if_simloop(ifp, m, dst->sa_family, 0)); - } - -+ if (netmap_drop == 81) { error = 0; goto bad; } // XXX - /* - * Add local net header. If no space in first mbuf, - * allocate another. -@@ -325,9 +328,12 @@ - if (m == NULL) - senderr(ENOBUFS); - eh = mtod(m, struct ether_header *); -+ if (netmap_drop == 87) { error = 0; goto bad; } // XXX - (void)memcpy(&eh->ether_type, &type, - sizeof(eh->ether_type)); -+ if (netmap_drop == 88) { error = 0; goto bad; } // XXX - (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); -+ if (netmap_drop == 89) { error = 0; goto bad; } // XXX - if (hdrcmplt) - (void)memcpy(eh->ether_shost, esrc, - sizeof(eh->ether_shost)); -@@ -335,6 +341,7 @@ - (void)memcpy(eh->ether_shost, IF_LLADDR(ifp), - sizeof(eh->ether_shost)); - -+ if (netmap_drop == 82) { error = 0; goto bad; } // XXX - /* - * If a simplex interface, and the packet is being sent to our - * Ethernet address or a broadcast address, loopback a copy. -@@ -387,6 +394,7 @@ - } - } - -+ if (netmap_drop == 83) { error = 0; goto bad; } // XXX - /* - * Bridges require special output handling. - */ -@@ -414,6 +422,7 @@ - return (0); - } - -+ if (netmap_drop == 84) { error = 0; goto bad; } // XXX - /* Continue with link-layer output */ - return ether_output_frame(ifp, m); - } -@@ -440,6 +449,7 @@ - } - #endif - -+ if (netmap_drop == 85) { m_freem(m); return 0; } // XXX - /* - * Queue message on interface, update output statistics if - * successful, and start output if interface not yet active. diff --git a/private/test/test-nest b/private/test/test-nest deleted file mode 100644 index f8bb585c4..000000000 --- a/private/test/test-nest +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# -# test the nesting of calls in C -LIM=100 -build1() { # build one entry, - local i=0 j - local dst=nest_f1.c - rm -f $dst - while [ $i -lt $LIM ] ; do - j=$(( $i + 1 )) - echo "int f_$j(int x) { x = f_$i(x + 2); return x + 3; }" >> $dst - i=$j - done -} - -build100() { # build many entries - rm -rf test100 - mkdir test100 - local i=0 j - while [ $i -lt $LIM ] ; do - j=$(( $i + 1 )) - echo "int f_$i(int); int f_$j(int x) { x = f_$i(x + 2); return x + 3; }" > test100/f$j.c - i=$j - done -} -build1 -build100 diff --git a/private/test/test_device.c b/private/test/test_device.c deleted file mode 100644 index 268933da9..000000000 --- a/private/test/test_device.c +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include -#include -#include /* strcmp */ -#include /* open */ -#include /* close */ - -#include /* PROT_* */ -#include /* ioctl */ -#include /* LIST_* */ -#include -#include -#include -#include /* sockaddr.. */ - -#include -#include /* ifreq */ -#include -#include - -#include "testnetmap.h" -#include "test_device.h" - - -#ifdef VERBOSE -#undef VERBOSE -#endif -#define VERBOSE 1 - - - -int -netmap_open(void) -{ - int fd; - - fd = open("/dev/netmap", O_RDWR); - ASSERT(fd != -1); - - return (fd); -} - - -void -netmap_close(int fd) -{ - int ret; - - ret = close(fd); - ASSERT(ret != -1); -} - - -void * -netmap_mmap(int fd, int l) -{ - void *tmp_addr; - - tmp_addr = mmap(0, l, PROT_WRITE | PROT_READ, - MAP_SHARED, fd, 0); - ASSERT(tmp_addr != MAP_FAILED); - - return (tmp_addr); -} - - -static void -test_netmap_open_close(void) -{ - int fd, fd1; - - fd = netmap_open(); - fd1 = netmap_open(); - - netmap_close(fd1); - netmap_close(fd); - - SUCCESS(); -} - - -static void -test_netmap_ioctl(const char *ifname) -{ - int fd, fd1; - struct nmreq ifreq; - - fd = netmap_open(); - fd1 = netmap_open(); - - strcpy(ifreq.nr_name, "fu0"); - /* unable to register unexistent interface */ - ASSERT(ioctl(fd, NIOCREGIF, &ifreq) == -1); - - strcpy(ifreq.nr_name, ifname); - ASSERT(ioctl(fd, NIOCREGIF, &ifreq) != -1); - /* unable to register multiple interfaces */ - ASSERT(ioctl(fd, NIOCREGIF, &ifreq) == -1); - /* register the same interface on different fds. */ - ASSERT(ioctl(fd1, NIOCREGIF, &ifreq) != -1); - - /* check if the driver support userspace synchronization. */ - ASSERT(ioctl(fd, NIOCTXSYNC, &ifreq) != -1); - ASSERT(ioctl(fd, NIOCRXSYNC, &ifreq) != -1); - - ASSERT(ioctl(fd1, NIOCUNREGIF, &ifreq) != -1); - ASSERT(ioctl(fd, NIOCUNREGIF, &ifreq) != -1); - /* unable to unregister an interface twice */ - ASSERT(ioctl(fd, NIOCUNREGIF, &ifreq) == -1); - - netmap_close(fd1); - netmap_close(fd); - - SUCCESS(); -} - - -static void -test_netmap_mmap(const char *ifname) -{ - int fd; - void *tmp_addr; - struct nmreq ifreq; - int l; - - fd = netmap_open(); - strcpy(ifreq.nr_name, ifname); - ASSERT(ioctl(fd, NIOCREGIF, &ifreq) != -1); - l = ifreq.nr_memsize; - - tmp_addr = netmap_mmap(fd, l); - ASSERT(munmap(tmp_addr, 1024) != -1); - - ASSERT(ioctl(fd, NIOCUNREGIF, &ifreq) != -1); - netmap_close(fd); - - SUCCESS(); -} - - -static void -test_netmap_poll(const char *ifname) -{ - int fd, ret; - struct ifreq ifreq; - struct pollfd fds[1]; - - fd = netmap_open(); - - memset(fds, 0, sizeof(fds)); - fds[0].fd = fd; - - /* no registered interface: POLLERR */ - ASSERT(poll(fds, 1, INFTIM) == 1); - ASSERT(fds[0].revents & POLLERR); - - strcpy(ifreq.ifr_name, ifname); - ASSERT(ioctl(fd, NIOCREGIF, &ifreq) != -1); - - /* noone is sending packets, so we cannot read: timeout */ - fds[0].events = (POLLIN | POLLRDNORM); - ASSERT((ret = poll(fds, 1, 1000)) != -1); - if (ret > 0) - ASSERT(fds[0].revents & POLLIN && - fds[0].revents & POLLRDNORM); - - /* the ring is empty, if we want to write we can do it. */ - fds[0].events = (POLLOUT | POLLWRNORM); - ASSERT((ret = poll(fds, 1, 1000)) != -1); - if (ret > 0) - ASSERT(fds[0].revents & POLLOUT && - fds[0].revents & POLLWRNORM); - - ASSERT(ioctl(fd, NIOCUNREGIF, &ifreq) != -1); - netmap_close(fd); - - SUCCESS(); -} - - -void -test_device(const char *ifname) -{ - test_netmap_open_close(); - - test_netmap_ioctl(ifname); - - test_netmap_mmap(ifname); - - test_netmap_poll(ifname); -} diff --git a/private/test/test_device.h b/private/test/test_device.h deleted file mode 100644 index 34538dc57..000000000 --- a/private/test/test_device.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _NETMAP_TEST_DEVICE_H -#define _NETMAP_TEST_DEVICE_H - -#include - - -int netmap_open(void); -void netmap_close(int fd); -void netmap_ioctl(int fd, u_long cmd, caddr_t data); -void *netmap_mmap(int fd, int l); - -#endif /* _NETMAP_TEST_DEVICE_H */ diff --git a/private/test/test_speed.c b/private/test/test_speed.c deleted file mode 100644 index cfd10b567..000000000 --- a/private/test/test_speed.c +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include -#include - -#include /* ioctl */ -#include /* LIST_* */ -#include -#include /* sockaddr .. */ - -#include /* IFNAMSIZ */ -#include -#include - -#include "testnetmap.h" -#include "test_speed.h" -#include "test_device.h" - -#define ITERATIONS 100000 - - -static struct timing_method t_methods[] = { - { "gettimeofday()", TIMING_GTD, 0 }, - /*{ "clock_gettime(CLOCK_REALTIME)", TIMING_CGT, CLOCK_REALTIME },*/ - /*{ "clock_gettime(CLOCK_REALTIME_PRECISE)", TIMING_CGT, CLOCK_REALTIME_PRECISE },*/ - /*{ "clock_gettime(CLOCK_REALTIME_FAST)", TIMING_CGT, CLOCK_REALTIME_FAST },*/ - /*{ "clock_gettime(CLOCK_MONOTONIC)", TIMING_CGT, CLOCK_MONOTONIC },*/ - /*{ "clock_gettime(CLOCK_MONOTONIC_PRECISE)", TIMING_CGT, CLOCK_MONOTONIC_PRECISE },*/ - /*{ "clock_gettime(CLOCK_MONOTONIC_FAST)", TIMING_CGT, CLOCK_MONOTONIC_FAST },*/ - { "", 0, 0 } -}; - - -static void -test_ioctl_speed(const char *ifname) -{ - int fd, i; - double ravg = 0; - struct nmreq req; - struct netmap_if *nifp; - void *tmp_addr; - - fd = netmap_open(); - tmp_addr = netmap_mmap(fd, 1024 /* XXX */); - - strcpy(req.nr_name, ifname); - /* single queue sync. */ - req.nr_ringid = 0 | NETMAP_HW_RING; - ASSERT(ioctl(fd, NIOCREGIF, &req) != -1); - nifp = NETMAP_IF(tmp_addr, req.nr_offset); - - /* multi-queue sync: default configuration */ - i = 0; - while (strcmp("", t_methods[i].label) != 0) { - TIMEIT(t_methods[i].type, t_methods[i].clock_id, - ioctl(fd, NIOCRXSYNC, NULL), ravg, ITERATIONS); - SUCCESSF(": NIOCRXSYNC: multi: %0.6f usec.\n", ravg); - TIMEIT(t_methods[i].type, t_methods[i].clock_id, - ioctl(fd, NIOCTXSYNC, NULL), ravg, ITERATIONS); - SUCCESSF(": NIOCTXSYNC: multi: %0.6f usec.\n", ravg); - i++; - } - - i = 0; - while (strcmp("", t_methods[i].label) != 0) { - TIMEIT(t_methods[i].type, t_methods[i].clock_id, - ioctl(fd, NIOCRXSYNC, NULL), ravg, ITERATIONS); - SUCCESSF(": NIOCRXSYNC: single: %0.6f usec.\n", ravg); - TIMEIT(t_methods[i].type, t_methods[i].clock_id, - ioctl(fd, NIOCTXSYNC, NULL), ravg, ITERATIONS); - SUCCESSF(": NIOCTXSYNC: single: %0.6f usec.\n", ravg); - i++; - } - - ASSERT(ioctl(fd, NIOCUNREGIF, &req) != -1); - - netmap_close(fd); -} - -void -test_speed(const char *ifname) -{ - test_ioctl_speed(ifname); -} diff --git a/private/test/test_speed.h b/private/test/test_speed.h deleted file mode 100644 index e0a4870fb..000000000 --- a/private/test/test_speed.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _NETMAP_TEST_SPEED_H -#define _NETMAP_TEST_SPEED_H - -#include - -/* Enumerate describing the type of method to use for timimng */ -enum timing_type { - TIMING_GTD, /* gettimeofday(2) */ - TIMING_CGT /* clock_gettime(2) */ -}; - -/* Descriptor of timing methods */ -struct timing_method { - char label[128]; /* label/message associated with the method */ - enum timing_type type; /* type of timing method */ - clockid_t clock_id; /* clock identifier used with clock_gettime() */ -}; - - -#define RESULTS(label, value) \ - SUCCESSF(": %0.6f usec\t%s\n", (value), (label)); - -#define TIMEIT(type, clock, x, ravg, n) \ - do { \ - switch ((type)) { \ - case TIMING_GTD: \ - TIMEIT_GTD(x, ravg, n); \ - break; \ - \ - case TIMING_CGT: \ - TIMEIT_CGT(clock, x, ravg, n); \ - break; \ - \ - default: \ - break; \ - } \ - } while (0) - -#define TIMEIT_GTD(x, ravg, n) \ - do { \ - int _i; \ - double _tmp; \ - struct timeval _start, _end; \ - \ - gettimeofday(&_start, NULL); \ - for (_i = 0; _i < (n); _i++) \ - x; \ - gettimeofday(&_end, NULL); \ - _tmp = (_end.tv_usec - _start.tv_usec) + \ - 1000000 * (_end.tv_sec - _start.tv_sec);\ - (ravg) = _tmp / (double) (n); \ - } while (0) - -#define TIMEIT_CGT(clock, x, ravg, n) \ - do { \ - int _i; \ - double _tmp; \ - struct timespec _start, _end; \ - clock_gettime((clock), &_start); \ - for (_i = 0; _i < (n); _i++) \ - x; \ - clock_gettime((clock), &_end); \ - _tmp = (_end.tv_nsec - _start.tv_nsec) / (double) 1000 +\ - 1000000 * (_end.tv_sec - _start.tv_sec); \ - (ravg) = _tmp / (double) (n); \ - } while (0) - -#endif /* _NETMAP_TEST_SPEED_H */ diff --git a/private/test/test_userspace.c b/private/test/test_userspace.c deleted file mode 100644 index 46a636ce7..000000000 --- a/private/test/test_userspace.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include /* strcmp */ -#include /* open */ -#include /* close */ -#include /* sigsuspend */ - -#include /* PROT_* */ -#include /* ioctl */ -#include -#include -#include /* sockaddr.. */ -#include /* ntohs */ - -#include -#include -#include /* ifreq */ -#include -#include - -#include "testnetmap.h" -#include "test_device.h" -#include "test_userspace.h" - - -#ifdef VERBOSE -#undef VERBOSE -#endif -#define VERBOSE 1 - - -void -test_userspace(const char *ifname) -{ - int fd; - void *tmp_addr; - struct nmreq ifreq; - struct netmap_if *nifp; - int l; - - fd = netmap_open(); - - - strcpy(ifreq.nr_name, ifname); - ASSERT(ioctl(fd, NIOCREGIF, &ifreq) != -1); - l = ifreq.nr_memsize; - tmp_addr = netmap_mmap(fd, l); - nifp = NETMAP_IF(tmp_addr, ifreq.nr_offset); - - PRINT_NIF(nifp); - - ASSERT(ioctl(fd, NIOCUNREGIF, &ifreq) != -1); - ASSERT(munmap(tmp_addr, l) != -1); - netmap_close(fd); - - SUCCESS(); -} diff --git a/private/test/test_userspace.h b/private/test/test_userspace.h deleted file mode 100644 index 066967ddd..000000000 --- a/private/test/test_userspace.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef _NETMAP_TEST_USERSPACE_H_ - - -/* - * Print the ring. - * - * @d netmap descriptor pointer. - * @n netmap_if descriptor pointer. - * @r netmap_ring descriptor pointer. - * @t name of the ring field ([tx,rx]_rings). - * @nd number of descriptors inside the ring. - * @ds size of each descriptor. - * - * Print only the slots containing data. - * Example: - * head: 10 - * tail: 8 - */ -#define PRINT_NIF_RING(d, n, r, t, nd, ds) \ -do { \ - printf("head: %d\n" \ - "tail: %d\n" \ - "", \ - (r)->head, \ - (r)->tail \ - ); \ -} while (0) - - -/* - * Print the i-th transmit ring. - * - * @d netmap descriptor pointer. - * @n netmap_if descriptor pointer. - * @i index of the ring. - */ -#define PRINT_NIF_TX_RING(d, n, i) \ - PRINT_NIF_RING(d, n, NETMAP_TXRING(n, i), \ - tx_rings, (n)->num_tx_descs, (n)->tx_desc_size) - - -/* - * Print the i-th receive ring. - * - * @d netmap descriptor pointer. - * @n netmap_if descriptor pointer. - * @i index of the ring. - */ -#define PRINT_NIF_RX_RING(d, n, i) \ - PRINT_NIF_RING(d, n, NETMAP_RX_RING(d, n, i), \ - rx_rings, (n)->num_rx_descs, (n)->rx_desc_size) - - -/* - * Print a netmap interface descriptor. - * - * @n netmap_if descriptor. - * - * Example: - * netmap-interface: - * ----------------- - * Name: em0 # queues: 1 - */ -#define PRINT_NIF(n) \ -do { \ - printf("netmap-interface:\n" \ - "-----------------\n" \ - "Name: %s #queues: %d #desc-per-que: %d\n" \ - "", \ - (n)->ni_name, \ - (n)->ni_num_queues, \ - NETMAP_TXRING(n, 0)->num_slots \ - ); \ -} while (0) - - - -/* - * Print an ethernet address. - * - * A colon symbol is added between each character, and a new-line - * character is put at the end. - * Example: - * 08:00:27:3d:43:fd - */ -#define PRINT_ETH_ADDR(addr) \ -do { \ - int _i; \ - u_char *_ptr; \ - \ - _ptr = (addr); \ - _i = ETHER_ADDR_LEN; \ - do { \ - printf("%s%02x", \ - (_i == ETHER_ADDR_LEN) ? "" : ":", \ - *_ptr++); \ - } while (--_i > 0); \ - printf("\n"); \ -} while (0) - -/* - * Print an Ethernet header. - * - * Example: - * Ethernet header: - * ---------------- - * Type: 0800 - * Source: 08:00:27:3d:43:fd - * Destination: ff:ff:ff:ff:ff:ff - */ -#define PRINT_ETH_PKT(eh) \ -do { \ - printf("Ethernet header:\n"); \ - printf("----------------\n"); \ - printf("Type: %04x\n", ntohs((eh)->ether_type)); \ - printf("Source Address: "); \ - PRINT_ETH_ADDR((eh)->ether_shost); \ - printf("Destination Address: "); \ - PRINT_ETH_ADDR((eh)->ether_dhost); \ -} while (0) - - -/* - * Print an Arp packet. - * - * Example: - * Arp header: - * ----------- - * htype: 0001 ptype: 0800 - * hlen: 6 plen: 4 - * oper: 1 - * sha: 52:54:00:12:34:56 - * spa: 10.0.2.222 - * tha: 00:00:00:00:00:00 - * tpa: 10.0.2.15 - */ -#define PRINT_ARP_PKT(arp) \ -do { \ - printf("Arp header:\n"); \ - printf("-----------\n"); \ - printf("htype: %04x\tptype: %04x\n", \ - ntohs(arp->htype), ntohs(arp->ptype)); \ - printf("hlen: %u\tplen: %u\n", arp->hlen, arp->plen); \ - printf("oper: %d\n", ntohs(arp->oper)); \ - printf("sha: "); \ - PRINT_ETH_ADDR(arp->sha); \ - printf("spa: %s\n", inet_ntoa(*(struct in_addr *) arp->spa)); \ - printf("tha: "); \ - PRINT_ETH_ADDR(arp->tha); \ - printf("tpa: %s\n", inet_ntoa(*(struct in_addr *) arp->tpa)); \ -} while (0) - - -/* - * Print an IP header. - * - * Example: - * Ip header: - * ---------- - * Length: 54 - * Source: 192.168.0.1 - * Destination: 192.168.0.22 - */ -#define PRINT_IP_PKT(ip) \ -do { \ - printf("Ip header:\n"); \ - printf("----------\n"); \ - printf("Length: %u\n", ntohs((ip)->ip_len)); \ - printf("Source Address: %s\n", inet_ntoa((ip)->ip_src)); \ - printf("Destination Address: %s\n", \ - inet_ntoa((ip)->ip_dst)); \ -} while (0) - - -#endif /* _NETMAP_TEST_USERSPACE_H_ */ diff --git a/private/test/testnetmap.c b/private/test/testnetmap.c deleted file mode 100644 index 4fec538aa..000000000 --- a/private/test/testnetmap.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -#include "testnetmap.h" - - -int -main(int argc, char **argv) -{ - if (argc != 2) { - printf("Usage: %s \n", argv[0]); - return (1); - } - - - test_device(argv[1]); - - test_userspace(argv[1]); - - test_speed(argv[1]); - - return (0); -} diff --git a/private/test/testnetmap.h b/private/test/testnetmap.h deleted file mode 100644 index 3f2aef1a1..000000000 --- a/private/test/testnetmap.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _NETMAP_TEST_H_ -#define _NETMAP_TEST_H_ - -#include -#include /* exit */ - -#define VERBOSE 1 - -#define ASSERT(x) \ - do { \ - if (!(x)) { \ - printf("In function '%s':\n", __func__); \ - printf("%s:%d: fail: " #x ": %s\n", \ - __FILE__, __LINE__, strerror(errno)); \ - exit(1); \ - } \ - } while (0) - -#define SUCCESSF(...) \ - do { \ - if (VERBOSE) { \ - printf("Success: %s", __func__); \ - printf(__VA_ARGS__); \ - } \ - } while (0) - -#define SUCCESS() SUCCESSF("\n") - - -void test_device(const char *ifname); -void test_speed(const char *ifname); -void test_userspace(const char *ifname); - -#endif /* _NETMAP_TEST_H_ */ diff --git a/private/tools/luigi.sh b/private/tools/luigi.sh deleted file mode 100644 index c362aa2a2..000000000 --- a/private/tools/luigi.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh -# -# commands to sync the files in netmap -# sh ... --netmap netmap_tree --src bsd_tree [diff|patch|revert] - -# MYFILES is the list of kernel files modified -FREEBSD_TREE=${HOME}/FreeBSD/head -NETMAP_TREE=/usr/ports-luigi/netmap-release -MY_FILES="\ - conf/NOTES conf/files conf/options \ - dev/e1000/if_igb.c dev/e1000/if_lem.c dev/e1000/if_em.c \ - dev/re/if_re.c \ - dev/bge/if_bge.c \ - dev/ixgbe/ixgbe.c \ - " - -while [ true ] ; do - case $1 in - --netmap) # netmap tree - NETMAP_TREE=$2; - shift - ;; - --src) # FreeBSD tree - FREEBSD_TREE=$2 - shift - ;; - --dry) # dry run - DRY=-C - ;; - --h*) # help - echo "sh ... --netmap netmap_tree --src bsd_tree [diff|patch|revert] " - exit 0 - ;; - - diff) # compute diffs - (cd $FREEBSD_TREE/sys; svn diff $MY_FILES) - ;; - revert) # remove additional files - (cd $FREEBSD_TREE/sys; svn revert $MY_FILES; \ - rm dev/netmap; rm net/netmap*) - ;; - patch) # compute diffs - in=$2 - [ x"$in" = x ] && in=$NETMAP_TREE/head-netmap.diff - (cd $FREEBSD_TREE/sys; patch ${DRY} < $in ; \ - ln -s $NETMAP_TREE/sys/dev/netmap dev/netmap; \ - ln -s $NETMAP_TREE/sys/net/netmap.h net/netmap.h; \ - ln -s $NETMAP_TREE/sys/net/netmap_user.h net/netmap_user.h; \ - ) - ;; - *) - break; - esac - shift; -done diff --git a/private/tools/qemu/PICOBSD b/private/tools/qemu/PICOBSD deleted file mode 100644 index d57913e60..000000000 --- a/private/tools/qemu/PICOBSD +++ /dev/null @@ -1,154 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/PICOBSD 201065 2009-12-27 22:34:31Z luigi $ -# A configuration file to run tests on qemu. -# We disable SMP because it does not work well with qemu, and set HZ=1000 -# to avoid it being overridden. -# -# Line starting with #PicoBSD contains PicoBSD build parameters -#marker def_sz init MFS_inodes floppy_inodes -#PicoBSD 26000 init 8192 32768 -options MD_ROOT_SIZE=26000 # same as def_sz - -hints "PICOBSD.hints" - -# values accessible through getenv() -# env "PICOBSD.env" - -#cpu I486_CPU -#cpu I586_CPU -cpu I686_CPU -ident PICOBSD - -options SMP -device acpi # more frequencies ? -device apic # kern_et ? -device cpufreq - -option INVARIANTS -option INVARIANT_SUPPORT -options SCHED_ULE # mandatory to have one scheduler -options PREEMPTION -#options MATH_EMULATE #Support for x87 emulation -options INET #InterNETworking -options INET6 -options FFS #Berkeley Fast Filesystem -#options BOOTP #Use BOOTP to obtain IP address/hostname -options MD_ROOT #MD is a potential root device - -#options NFS #Network Filesystem -#options NFS_ROOT #NFS usable as root device, NFS required - -#options MSDOSFS #MSDOS Filesystem -#options CD9660 #ISO 9660 Filesystem -#options CD9660_ROOT #CD-ROM usable as root, CD9660 required -#options DEVFS #Device Filesystem -#options PROCFS #Process filesystem -options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] - -options KDB -options DDB - -options IPFIREWALL -options IPFIREWALL_DEFAULT_TO_ACCEPT -options IPDIVERT # divert (for natd) - -# Support for bridging and bandwidth limiting -options DUMMYNET -options IPFIREWALL_NAT -options LIBALIAS -device if_bridge -# Running with less than 1000 seems to give poor timing on -# qemu, so we set HZ explicitly. -options HZ=1000 - -device random # used by ssh -device pci - -# Floppy drives -device fdc - -# ATA and ATAPI devices -#device ata -#device atadisk # ATA disk drives -#device atapicd # ATAPI CDROM drives -#options ATA_STATIC_ID #Static device numbering - -# atkbdc0 controls both the keyboard and the PS/2 mouse -device atkbdc # At keyboard controller -device atkbd -#device psm # do we need the mouse ?? - -device vga # VGA screen - -# syscons is the default console driver, resembling an SCO console -device sc - -# Serial (COM) ports -device uart - -# Audio support -#device pcm - -# PCCARD (PCMCIA) support -#device card # pccard bus -#device pcic # PCMCIA bridge - -# Parallel port -#device ppc -#device ppbus # Parallel port bus (required) -#device lpt # Printer -#device plip # TCP/IP over parallel -#device ppi # Parallel port interface device - -# -# The following Ethernet NICs are all PCI devices. -# -device miibus -device ixgbe -device cxgbe # chelsio -device firmware # needed for chelsio ? - -device em -device bge -#device fxp # Intel EtherExpress PRO/100B (82557, 82558) -device nfe # nVidia nForce MCP on-board Ethernet -#device xl # 3Com -device rl # RealTek 8129/8139 -device re # RealTek 8139C+/8169/8169S/8110S -device sis # National/SiS -device dc # DEC/Intel 21143 and various workalikes -device ed - -device loop # Network loopback -device ether # Ethernet support -device tun # Packet tunnel. -device pty # Pseudo-ttys (telnet etc) -device md # Memory "disks" -#device gif 4 # IPv6 and IPv4 tunneling -#device faith 1 # IPv6-to-IPv4 relaying (translation) -device tap - -#-- usb support -device uhci # UHCI PCI->USB interface -device ohci # OHCI PCI->USB interface -device ehci # EHCI PCI->USB interface (USB 2.0) -device usb -device uhid # "Human Interface Devices" -device ukbd # Keyboard -device scbus -device da -device umass # Disks/Mass storage - Requires scbus and da -device ums # Mouse - - -device kbdmux -options KBD_INSTALL_CDEV - -#options VIMAGE - -#options DEVICE_POLLING - -# The `bpf' device enables the Berkeley Packet Filter. -# Be aware of the administrative consequences of enabling this! -device bpf # Berkeley packet filter -device netmap diff --git a/private/tools/qemu/PICOBSD.hints b/private/tools/qemu/PICOBSD.hints deleted file mode 100644 index cdb038ba4..000000000 --- a/private/tools/qemu/PICOBSD.hints +++ /dev/null @@ -1,39 +0,0 @@ -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/PICOBSD.hints 201065 2009-12-27 22:34:31Z luigi $ -hint.fdc.0.at="isa" -hint.fdc.0.port="0x3F0" -hint.fdc.0.irq="6" -hint.fdc.0.drq="2" -hint.fd.0.at="fdc0" -hint.fd.0.drive="0" -hint.ata.0.at="isa" -hint.ata.0.port="0x1F0" -hint.ata.0.irq="14" -hint.ata.1.at="isa" -hint.ata.1.port="0x170" -hint.ata.1.irq="15" -hint.atkbdc.0.at="isa" -hint.atkbdc.0.port="0x060" -hint.atkbd.0.at="atkbdc" -hint.atkbd.0.irq="1" -hint.psm.0.at="atkbdc" -hint.psm.0.irq="12" -hint.vga.0.at="isa" -hint.sc.0.at="isa" -hint.npx.0.at="nexus" -hint.npx.0.port="0x0F0" -hint.npx.0.irq="13" -hint.uart.0.at="isa" -hint.uart.0.port="0x3F8" -hint.uart.0.flags="0x10" -hint.uart.0.irq="4" -hint.uart.1.at="isa" -hint.uart.1.port="0x2F8" -hint.uart.1.irq="3" -hint.ed.0.at="isa" -hint.ed.0.port="0x280" -hint.ed.0.irq="5" -hint.ed.0.maddr="0xd8000" -hint.ed.1.at="isa" -hint.ed.1.port="0x300" -hint.ed.1.irq="5" -hint.ed.1.maddr="0xd0000" diff --git a/private/tools/qemu/config b/private/tools/qemu/config deleted file mode 100644 index da5ac7538..000000000 --- a/private/tools/qemu/config +++ /dev/null @@ -1,68 +0,0 @@ -# configuration for picobsd build script. -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/config 201065 2009-12-27 22:34:31Z luigi $ -# it should only contain variable definitions -- it is sourced -# by the shell much like rc.conf* files - -fd_size="12000" - -# You can use it e.g. in a local configuration file by writing -# -# do_copyfiles_user() { -# local dst=$1 -# find_progs nvi sed less grep -# cp -p ${u_progs} ${dst}/bin -# cp -p ${u_libs} ${dst}/lib -# mkdir -p ${dst}/libexec -# find_progs ld-elf.so.1 -# cp -p ${u_progs} ${dst}/libexec -# } -#copy_files=" -#" -do_copyfiles_user() { - local dst=$1 - log "--- called do_copyfiles_user" - - mkdir -p ${dst}/usr/lib - - find_progs -L / -P /usr/ports/security/dropbear/work/dropbear-0.52 \ - dbclient dropbear - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/lib - - find_progs -L / /usr/bin/ssh /usr/bin/scp /usr/sbin/sshd - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/lib - - #find_progs -L / -P /usr/local/bin trafshow - #cp -p ${u_progs} ${dst}/bin - #cp -p ${u_libs} ${dst}/usr/lib - - local d=/home/matteo/workspace/netmap/v2/netmap-v2/examples - find_progs -L / -P $d pkt-gen pkt-gen-pcap bridge pingd - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/lib - - local d=/home/matteo/workspace/netmap/v2/netmap-v2/test - find_progs -L / -P $d interrupt_stats - cp -p ${u_progs} ${dst}/bin - cp -p ${u_libs} ${dst}/usr/lib - - #find_progs -L $d -P $d libnetmap.so - #cp -p ${u_progs} ${dst}/bin/libpcap.so.7 - - -# find_progs -L $d /tmp/click -# cp -p ${u_progs} ${dst}/bin -# cp -p ${u_libs} ${dst}/usr/lib - -# find_progs -L /usr/local/lib -P /usr/local/bin tcpreplay -# cp -p ${u_progs} ${dst}/bin -# cp -p ${u_libs} ${dst}/usr/lib - - cp -p /usr/bin/vi ${dst}/bin/vi - -# cp -p /tmp/tcpreplay ${dst}/root -# cp -p /tmp/netsend ${dst}/bin -# cp -p /tmp/a.pcap ${dst}/root -# cp -p /tmp/open_key/* ${dst}/root -} diff --git a/private/tools/qemu/crunch.conf b/private/tools/qemu/crunch.conf deleted file mode 100644 index 77179efb4..000000000 --- a/private/tools/qemu/crunch.conf +++ /dev/null @@ -1,209 +0,0 @@ -# -# $FreeBSD: user/luigi/ipfw3-head/release/picobsd/qemu/crunch.conf 201065 2009-12-27 22:34:31Z luigi $ -# -# Configuration file for "qemu" images.. -# -# Depending on your needs, you will almost surely need to -# add/remove/change programs according to your needs. -# Remember that some programs require matching kernel options to -# enable device drivers etc. -# -# To figure out how much space is used by each program, do -# -# size build_dir-bridge/crunch/*lo -# -# Remember that programs require libraries, which add up to the -# total size. The final binary is build_dir-bridge/mfs.tree/stand/crunch -# and you can check which libraries it uses with -# -# ldd build_dir-bridge/mfs.tree/stand/crunch - -# crunchgen configuration to build the crunched binary, see "man crunchgen" -# We need to specify generic build options, the places where to look -# for sources, and the list of program and libraries we want to put -# in the crunched binary. -# -# NOTE: the string "/usr/src" below will be automatically replaced with -# the path set in the 'build' script. - -# Default build options. Basically tell the Makefiles -# that to use the most compact possible version of the code. - -buildopts -DNO_PAM -DRELEASE_CRUNCH -DPPP_NO_NETGRAPH -buildopts -DTRACEROUTE_NO_IPSEC # -DNO_INET6 -buildopts -DWITHOUT_IPX - -# Directories where to look for sources of various binaries. -# @__CWD__@ is a magic keyword in the picobsd's (Makefile.conf) -# which is replaced with the directory with the picobsd configuration -# corresponding to your image. This way you can have custom sources -# in that directory overriding system programs. - -srcdirs @__CWD__@/src - -# Some programs are especially written for PicoBSD and reside in -# release/picobsd/tinyware. -# Put this entry near the head of the list to override standard binaries. - -srcdirs /usr/src/release/picobsd/tinyware - -# Other standard locations for sources. -# If a program uses its own source directory, add - -srcdirs /usr/src/bin -srcdirs /usr/src/sbin/i386 -srcdirs /usr/src/sbin -srcdirs /usr/src/usr.bin -srcdirs /usr/src/gnu/usr.bin -srcdirs /usr/src/usr.sbin -srcdirs /usr/src/libexec - -# For programs that reside in different places, the best option -# is to use the command "special XXX srcdir YYY" where XXX is the -# program name and YYY is the directory path. -# "special XXX ..." can be used to specify more options, see again -# the crunchgen manpage. - -#--- Basic configuraton -# init is always necessary (unless you have a replacement, oinit) -progs init - -# fsck is almost always necessary, unless you have everything on the -# image and use 'tar' or something similar to read/write raw blocks -# from the floppy. - -progs fsck - -# ifconfig is needed if you want to configure interfaces. -progs ifconfig - -# You will also need a shell and a bunch of utilities. -# The standard shell is not that large, but you need many -# external programs. In fact most of them do not take much space -# as they merely issue a system call, and print the result. -# For a more compact version of shell and utilities, you could -# try busybox, however most system management commands in busybox -# will not work as they use linux-specific interfaces. - -progs sh -ln sh -sh - -# the small utilities -progs echo -progs pwd mkdir rmdir -progs chmod chown -ln chown chgrp -progs mv ln cp rm ls -progs cat tail tee -progs test -ln test [ - -progs less -ln less more -progs mount -progs minigzip -ln minigzip gzip -progs kill -progs df -progs ps -progs ns # this is the picobsd version -ln ns netstat -progs vm -progs hostname -progs login -progs getty -progs stty -progs w -progs msg -ln msg dmesg -progs reboot - -progs sysctl -progs swapon -progs pwd_mkdb -progs umount -progs du -progs passwd - -progs route - -# If you want to run natd, remember the alias library -progs natd -libs_so -lalias # natd -progs tcpdump -special tcpdump srcdir /usr/src/usr.sbin/tcpdump/tcpdump -libs_so -lpcap # used by tcpdump -libs_so -lcrypto # used by tcpdump with inet6 - -# ppp is rather large. Note that as of Jan.01, RELEASE_CRUNCH -# makes ppp not use libalias, so you cannot have aliasing. -#progs ppp - -# You need an editor. ee is relatively small, though there are -# smaller ones. vi is much larger. -# The editor also usually need a curses library. -progs ee - -progs arp - -# these require libgeom -# progs bsdlabel fdisk mdconfig - -progs kldload kldunload kldstat -progs kldxref -progs grep -libs_so -lgnuregex -lbz2 -# dhclient-script requires 'sed' -progs dhclient -progs sed -progs date -progs time -progs ping -progs ping6 -progs tar - -progs top -progs pciconf - -#progs routed -progs ipfw -progs traceroute -progs mdmfs -ln mdmfs mount_mfs -# Various filesystem support -- remember to enable the kernel parts -# progs mount_msdosfs -progs mount_nfs -# progs mount_cd9660 -ln mount_nfs nfs -ln mount_cd9660 cd9660 -#progs newfs -#ln newfs mount_mfs -# ln mount_msdosfs msdos - -progs jail jexec jls - -# For a small ssh client/server use dropbear - -# Now the libraries -libs_so -lc # the C library -libs_so -ll # used by sh (really ?) -libs_so -lufs # used by mount -### ee uses ncurses but as a dependency -#libs_so -lncurses -libs_so -lm -libs_so -ledit -lutil -libs_so -lcrypt -libs_so -lkvm -libs_so -lz -libs_so -lbsdxml -libs_so -lsbuf -libs_so -ljail # used by ifconfig -libs_so -lulog -libs_so -lipsec -lmd -libs_so -larchive -lbz2 -libs_so -llzma # added after 207840 - -progs vmstat -libs_so -lmemstat -libs_so -ldevstat -progs cpuset diff --git a/private/tools/qemu/floppy.tree.exclude b/private/tools/qemu/floppy.tree.exclude deleted file mode 100644 index adfc6cc75..000000000 --- a/private/tools/qemu/floppy.tree.exclude +++ /dev/null @@ -1,2 +0,0 @@ -etc/snmpd.conf -etc/ppp diff --git a/private/tools/qemu/floppy.tree/etc/motd b/private/tools/qemu/floppy.tree/etc/motd deleted file mode 100644 index 91d66f5e0..000000000 --- a/private/tools/qemu/floppy.tree/etc/motd +++ /dev/null @@ -1,9 +0,0 @@ -============================================================== - - )\_)\ Welcome to PicoBSD, netmap demo image - (o,o) - __ \~/ Root password is "setup" - -->====\ - ~~ d d see http://info.iet.unipi.it/~luigi/netmap/ - -============================================================== diff --git a/private/tools/qemu/floppy.tree/etc/rc.conf.defaults b/private/tools/qemu/floppy.tree/etc/rc.conf.defaults deleted file mode 100644 index 70e3767ad..000000000 --- a/private/tools/qemu/floppy.tree/etc/rc.conf.defaults +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -# $FreeBSD: head/release/picobsd/floppy.tree/etc/rc.conf.defaults 91949 2002-03-09 18:27:02Z luigi $ -# -# rc.conf for picobsd. This is sourced from /etc/rc1, and is supposed to -# contain only shell functions that are used later in /etc/rc1. - -# set default values for variables. Boolean values should be either -# NO or YES -- other values are not guaranteed to work. - -rc_conf_set_defaults() { -hostname="" # Should not need to set it -syslogd_enable="NO" -pccard_enable="NO" -swapfile="" # name of swapfile if aux swapfile desired. - -# Network interface configurations: ifconfig_${interface}[_aliasNN] -ifconfig_lo0="inet 127.0.0.1" # default loopback device configuration. -#ifconfig_lo0_alias0="inet 127.0.0.254 netmask 0xffffffff" # Sample alias entry. - -### Network daemons options: they are only run if present. -sshd_enable="YES" # if present... -inetd_enable="YES" # Run the network daemon dispatcher (or NO) -inetd_flags="" # Optional flags to inetd -snmpd_enable="NO" # Run the SNMP daemon (or NO) -snmpd_flags="-C -c /etc/snmpd.conf" # Optional flags to snmpd - -### Network routing options: ### -defaultrouter="NO" # Set to default gateway (or NO). -static_routes="" # Set to static route list (or leave empty). -gateway_enable="NO" # Set to YES if this host will be a gateway. -arpproxy_all="" # replaces obsolete kernel option ARP_PROXYALL. -default_mask="0xffffff00" - -### Other network features -firewall_enable="NO" -firewall_quiet="NO" # be quiet if set. -firewall_type="" # Standard types or absolute pathname. -tcp_extensions="NO" # Allow RFC1323 & RFC1644 extensions (or NO). - -### Overrides for some files in /etc. Leave empty if no override, -### set variable (remember to use multiple lines) to override content. - -host_conf="hosts -bind" -resolv_conf="" -} - -# Try to identify the system by using the MAC address and name of the -# first ethernet interface, made available as $main_eth $main_if -find_system_id() { - main_ether="" - for main_if in `ifconfig -l` ; do - set `ifconfig $main_if` - while [ "$1" != "" ] ; do - if [ $1 = "ether" ] ; then - main_ether=$2 - break 2 - else - shift - fi - done - done -} - -# the following lets the user specify a name and ip for his system -read_address() { - ## XXX disabled - hostname=default - return # - - echo "Please enter a hostname and IP address for your system $main_ether" - read hostname the_ip - if [ "${hostname}" != "" ] ; then - echo "# $main_ether $hostname" >> /etc/hosts - echo "$the_ip $hostname" >> /etc/hosts - else - hostname=default - fi -} - -# set "ether" using $1 (interface name) as search key -get_ether() { - local key - key=$1 - ether="" - set `ifconfig ${key}` - while [ "$1" != "" ] ; do - if [ "$1" = "ether" ] ; then - ether=$2 - break - else - shift - fi - done -} - -# read content from /etc/hosts into a couple of arrays -# (needed later in fetch_hostname) -read_hosts() { - local i a b c key junk - i="" - while read a b c junk ; do - if [ "$a" = "#ethertable" ] ; then - i=0 - elif [ "$i" != "" -a "$a" = "#" -a "$b" != "" ] ; then - eval eth_${i}=$b - eval eth_host_${i}=$c - i=$(($i+1)) - fi - done < /etc/hosts -} - -# set ${hostname} using $1 (MAC address) as search key in /etc/hosts -# Returns empty value if $1 is empty -fetch_hostname() { - local i b key - hostname="" - [ "$1" = "" ] && return - key=$1 - i=0 - b="x" - [ "${eth_0}" = "" ] && read_hosts # fill cache. - while [ "$b" != "" -a "${hostname}" = "" ] ; do - eval b=\${eth_${i}} - case X${key} in - X${b} ) # so we can use wildcards - eval hostname=\${eth_host_${i}} - break - ;; - esac - i=$(($i+1)) - done - echo "fetch_hostname for <${key}> returns <${hostname}>" -} - -# sets "mask" using $1 (netmask name) as the search key in /etc/networks -fetch_mask() { - local a b key junk - key=$1 # search key, typically hostname-netmask - mask="" - while read a b junk; do # key mask otherstuff - case X${key} in - X${a} ) # The X is so we can use wildcards in ${a} - mask=$b - break - ;; - esac - done < /etc/networks - if [ "${mask}" = "" ] ; then - mask=${default_mask} - fi - echo "fetch_mask for <${key}> returns <${mask}>" -} - -# set hostname, and ifconfig_${main_if} (whose MAC is ${main_ether}) -# if not found, read from console -set_main_interface() { - if [ -z "${hostname}" ] ; then - if [ -z "${main_ether}" ] ; then - echo "No ethernets found, using localhost" - hostname=localhost - return - fi - fetch_hostname ${main_ether} - fi - - [ -z "${hostname}" -o "${hostname}" = "." ] && read_address - - fetch_mask ${hostname}-netmask - - eval ifconfig_${main_if}=\" \${hostname} netmask \${mask}\" - network_interfaces=`ifconfig -l` -} - -# set ifconfig_${interface} for all other interfaces -set_all_interfaces() { - local i ether hostname mask - - for i in `ifconfig -l` ; do - if [ "$i" != "${main_if}" ] ; then - get_ether $i - fetch_hostname ${ether} - fetch_mask ${hostname}-netmask - [ -n "${ether}" -a -n "${hostname}" ] && \ - eval ifconfig_${i}=\" \${hostname} netmask \${mask}\" - fi - done -} diff --git a/private/tools/qemu/floppy.tree/etc/sysctl.conf b/private/tools/qemu/floppy.tree/etc/sysctl.conf deleted file mode 100644 index 295d78558..000000000 --- a/private/tools/qemu/floppy.tree/etc/sysctl.conf +++ /dev/null @@ -1 +0,0 @@ -net.inet.icmp.icmplim=0 diff --git a/private/tools/qemu/floppy.tree/root/.profile b/private/tools/qemu/floppy.tree/root/.profile deleted file mode 100644 index eea8e2439..000000000 --- a/private/tools/qemu/floppy.tree/root/.profile +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -./test f1 diff --git a/private/tools/qemu/floppy.tree/root/bri.click b/private/tools/qemu/floppy.tree/root/bri.click deleted file mode 100644 index 00f51fe9e..000000000 --- a/private/tools/qemu/floppy.tree/root/bri.click +++ /dev/null @@ -1,19 +0,0 @@ -// -// $Id$ -// -// A sample test configuration for click -// -// -// create a switch - -sw :: EtherSwitch; - -// two input devices - -c0 :: FromDevice(ix0, BURST 30, PROMISC true); -c1 :: FromDevice(ix1, BURST 30, PROMISC true); - -// and now pass packets around - -c0[0] -> [0]sw[0] -> Queue(10000) -> ToDevice(ix0); -c1[0] -> [1]sw[1] -> Queue(10000) -> ToDevice(ix1); diff --git a/private/tools/qemu/floppy.tree/root/rates b/private/tools/qemu/floppy.tree/root/rates deleted file mode 100644 index 3158e38eb..000000000 --- a/private/tools/qemu/floppy.tree/root/rates +++ /dev/null @@ -1,2 +0,0 @@ -I80211b_11M - diff --git a/private/tools/qemu/floppy.tree/root/start_test b/private/tools/qemu/floppy.tree/root/start_test deleted file mode 100644 index b4f267f27..000000000 --- a/private/tools/qemu/floppy.tree/root/start_test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -sysctl dev.cpu.0.freq=1200 -sysctl dev.cpu.0.freq=2934 -sysctl dev.ix.0.flow_control=0 -sysctl dev.ix.1.flow_control=0 -ifconfig ix0 up -ifconfig ix1 up diff --git a/private/tools/qemu/floppy.tree/root/t1.ck b/private/tools/qemu/floppy.tree/root/t1.ck deleted file mode 100644 index ac143f0ff..000000000 --- a/private/tools/qemu/floppy.tree/root/t1.ck +++ /dev/null @@ -1,11 +0,0 @@ -// test1.ck -s :: InfiniteSource(LENGTH 64, BURST 1, NOTS true) -// -> q :: Queue -// -> c :: Counter - -> d :: Discard(BURST 1); - -DriverManager( - wait 1s, write s.active false, - //print "done $(d.count) packets $(q.drops) drops in 1s" - print "done $(d.count) packets drops in 1s" -); diff --git a/private/tools/qemu/floppy.tree/root/t2.ck b/private/tools/qemu/floppy.tree/root/t2.ck deleted file mode 100644 index c39325ef3..000000000 --- a/private/tools/qemu/floppy.tree/root/t2.ck +++ /dev/null @@ -1,14 +0,0 @@ -// test1.ck -FromDevice(ix0, BURST 100) -> Discard; - -s :: FromDevice(ix1, BURST 100) -> Queue -> ToDevice(ix0, BURST 100); - -DriverManager( - set a 0, - label x, - wait 1s, - set b $(s.count), - print "done $(sub $b $a) packets in 1s", - set a $b, - goto x 1 -); diff --git a/private/tools/qemu/floppy.tree/root/test b/private/tools/qemu/floppy.tree/root/test deleted file mode 100755 index 146fac520..000000000 --- a/private/tools/qemu/floppy.tree/root/test +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/sh - -f1() { # default setting - sysctl kern.timecounter.hardware=PIIX - return - ifconfig ed2 delete - dhclient ed2 - sysctl net.inet.ip.fw.verbose=1 -} - -# test tables -f2() { - ipfw table 2 add 22 2000 - ipfw table 2 add 53 3000 - ipfw table 2 add 80 4000 - ipfw table 2 add 127.0.0.1 5000 - ipfw table 2 list -} - -f3() { - ipfw -q flush - ipfw add 100 count log out - ipfw add 200 skipto tablearg lookup dst-port 2 - ipfw add 300 skipto tablearg lookup dst-ip 2 - ipfw add 1000 allow ip from any to any - ipfw add 2000 allow ip from any to any - ipfw add 3000 allow ip from any to any - ipfw add 4000 allow ip from any to any - ipfw add 5000 allow ip from any to any -} - -f4() { - ipfw -q flush - echo > /etc/libalias.conf - sysctl net.inet.ip.fw.verbose=1 - ipfw add 100 divert natd log ip from any to any - ipfw add 100 count ip from any to any - ipfw add 200 count ip from any to any - natd -v -interface ed2 & -} - -f5() { - ipfw pipe 10 config bw 80kbit/s - ipfw add 100 pipe 10 ip from any to any - ipfw pipe show -} - -# test queues -f6() { - ipfw pipe 1 config bw 400kbit/s queue 30 - #ipfw pipe 2 config bw 180kbit/s - #ipfw pipe 3 config delay 30ms queue 100kbytes - ipfw queue 11 config sched 1 weight 1 - ipfw queue 12 config sched 1 weight 2 - ipfw queue 14 config sched 1 weight 4 - ipfw queue 18 config sched 1 weight 8 - ipfw -q flush - ipfw add 100 queue 11 src-ip 0&3 // low bits 00 - ipfw add 100 queue 12 src-ip 1&3 // low bits 01 - ipfw add 100 queue 14 src-ip 2&3 // low bits 10 - ipfw add 100 queue 18 src-ip 3&3 // low bits 11 -} - -# jail test -f7() { -jail -c -nXX vnet path=/ host.hostname=test.me persist=true command=/bin/sh -} - -f8() { - ipfw add 100 queue tablearg lookup dscp 1 - ipfw queue 10 config sched 5 mask queue - ipfw queue 20 config sched 5 mask queue - ipfw queue 30 config sched 5 mask queue - ipfw pipe 5 config bw 80Kbit/s - # ipfw table 1 add 0 10 - ipfw table 1 add 1 20 - ipfw table 1 add 2 30 - ipfw table 1 list -} - -case $1 in - f[0-9]*) $* ;; -esac diff --git a/private/tools/qemu/floppy.tree/root/test_coarse.sh b/private/tools/qemu/floppy.tree/root/test_coarse.sh deleted file mode 100644 index 21d4dce7c..000000000 --- a/private/tools/qemu/floppy.tree/root/test_coarse.sh +++ /dev/null @@ -1,35 +0,0 @@ -#info -INFO=131.114.58.84 -OL5=131.114.59.241 - -# -# test per vedere l'andamento degli ack su download da info -# la wmem non influisce, ma ne tengo nota -#echo "4096 16384 65536" > /proc/sys/net/ipv4/tcp_wmem -#./ipfw/ipfw pipe 1 config coarse rates queue 800KBytes -#./ipfw/ipfw add 1 pipe 1 all from $INFO to $OL5 src-port 80 -#./ipfw/ipfw add 2 pipe 1 all from $OL5 to $INFO dst-port 80 - -# -# test per vedere l'andamento degli ack su download da info -# la wmem non influisce, ma ne tengo nota -# PRIORITA' AGLI ACK -#echo "4096 16384 65536" > /proc/sys/net/ipv4/tcp_wmem -#./ipfw/ipfw pipe 1 config coarse rates queue 800KBytes -#./ipfw/ipfw queue 1 config pipe 1 weight 1 -#./ipfw/ipfw queue 2 config pipe 1 weight 10 -#./ipfw/ipfw add 1 queue 1 all from $INFO to $OL5 src-port 80 -#./ipfw/ipfw add 2 queue 2 all from $OL5 to $INFO dst-port 80 - -#ifconfig lo mtu 1500 -#./ipfw/ipfw pipe 1 config coarse rates -#./ipfw/ipfw add 1 pipe 1 all from 131.114.59.241 to 131.114.59.241 dst-port 80 in -#./ipfw/ipfw add 2 pipe 1 all from 131.114.59.241 to 131.114.59.241 src-port 80 out - -# the default mtu for loopback is 16k, use 1500 instead -ifconfig lo mtu 1500 -# configure the pipe and the rules -./ipfw/ipfw pipe 1 config coarse rates -./ipfw/ipfw add 1 pipe 1 all from any to 127.0.0.1 dst-port 80 in -./ipfw/ipfw add 2 pipe 1 all from any to 127.0.0.1 src-port 80 out - diff --git a/private/tools/qemu/floppy.tree/test b/private/tools/qemu/floppy.tree/test deleted file mode 100755 index d1a3fcc05..000000000 --- a/private/tools/qemu/floppy.tree/test +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -f1() { - sysctl kern.timecounter.hardware=i8254 - ifconfig ed2 delete - dhclient ed2 - sysctl net.inet.ip.fw.verbose=1 -} - -f2() { - ipfw table 2 add 22 2000 - ipfw table 2 add 53 3000 - ipfw table 2 add 80 4000 - ipfw table 2 add 127.0.0.1 5000 - ipfw table 2 list -} - -f3() { - ipfw -q flush - ipfw add 100 count log out - ipfw add 200 skipto tablearg lookup dst-port 2 - ipfw add 300 skipto tablearg lookup dst-ip 2 - ipfw add 1000 allow ip from any to any - ipfw add 2000 allow ip from any to any - ipfw add 3000 allow ip from any to any - ipfw add 4000 allow ip from any to any - ipfw add 5000 allow ip from any to any -} - -f4() { - ipfw -q flush - echo > /etc/libalias.conf - sysctl net.inet.ip.fw.verbose=1 - ipfw add 100 divert natd log ip from any to any - ipfw add 100 count ip from any to any - ipfw add 200 count ip from any to any - natd -v -interface ed2 & -} - -case $1 in - f[0-9]*) $* ;; -esac diff --git a/private/vale.4 b/private/vale.4 deleted file mode 100644 index c254ba57f..000000000 --- a/private/vale.4 +++ /dev/null @@ -1,253 +0,0 @@ -.\" Copyright (c) 2012-2014 Luigi Rizzo, Universita` di Pisa -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" This document is derived in part from the enet man page (enet.4) -.\" distributed with 4.3BSD Unix. -.\" -.\" $FreeBSD: head/share/man/man4/vale.4 228017 2011-11-27 06:55:57Z gjb $ -.\" -.Dd July 27, 2012 -.Dt VALE 4 -.Os -.Sh NAME -.Nm vale -.Nd a very fast Virtual Local Ethernet using the netmap API -.Sh SYNOPSIS -.Cd device netmap -.Sh DESCRIPTION -.Nm -is a feature of the -.Nm netmap -module that implements multiple Virtual switches that can -be used to interconnect netmap clients, including traffic -sources and sinks, packet forwarders, userspace firewalls, -and so on. -.Pp -.Nm -is implemented completely in software, and is extremely fast. -On a modern machine it can move almost 20 Million packets per -second (Mpps) per core with small frames, and about 70 Gbit/s -with 1500 byte frames. -.Pp -.Sh OPERATION -.Nm -dynamically creates switches and ports as client connect -to it using the -.Xr netmap 4 -API. -.Pp -.Nm -ports are named -.Pa vale[bdg:][port] -where -.Pa vale -is the prefix indicating a VALE switch rather than a standard interface, -.Pa bdg -indicates a specific switch (the colon is a separator), -and -.Pa port -indicates a port within the switch. -Bridge and ports names are arbitrary strings, the only -constraint being that the full name must fit within 16 -characters. -.Pp -.Nm -ports can be physical network interfaces that support -.Xr netmap 4 -API -by specifying the interface name for -.Pa [port]. -See -.Nm OPERATION -section in -.Xr netmap 4 -for details of the naming rule. -.Pp -Physical interfaces are attached using -.Pa NIOCGREGIF -command of -.Pa ioctl(), -and -.Pa NETMAP_BDG_ATTACH -at -.Em nr_cmd -field in -.Em struct nmreq . -The corresponding host stack can also be attached to the bridge, specifying -.Pa NETMAP_BDG_HOST -in -.Em nr_arg1 . -To detach the interface from the bridge, -.Pa NETMAP_BDG_DETACH -is used instead of NETMAP_BDG_ATTACH. -The host stack is also detached from the bridge at the same -time if it has been attached. -.Pp -Physical interfaces are treated as system configuration; -they are kept being attached even after the configuring process dies, -and detached by any process. -.Pp -Once a physical interface is attached, this interface is no longer -available to be directly accessed by netmap clients (user processes) or to be -attached by another bridge. -On the other hand, when any netmap client holds the physical interface, -this interface cannot be attached to a bridge. -.Pp -.Pa NETMAP_BDG_LIST -subcommand in nr_cmd of -.Em struct nmreq -is used to obtain bridge and port -information. There are two modes of how it works; -If any -.Em nr_name -starting from non '\\0' is provided, -.Pa ioctl() -returning -indicates the position of -the named interface. -This position is represented by an index of the bridge and the port, and -put in -.Em nr_arg1 -and -.Em nr_arg2 -fields, respectively. If the named interface does not exist, -.Pa ioctl() -returns -.Pa EINVAL . -.Pp -If -.Em nr_name -starting from '\\0' is provided, -.Pa ioctl() -returning indicates the -first existing interface on and after the position specified in -.Em nr_arg1 -and -.Em nr_arg2. -If the caller specified a port index greater than the highest -index of the ports, it is recognized as port index 0 of the -next bridge -( -.Em nr_arg1 -+ 1, -.Em nr_arg2 -= 0). -.Pa ioctl() -returns -.Pa EINVAL -if the given position is higher than that of -any existing interface. -On successful return of -.Pa ioctl() , -the interface name is also stored in -.Em nr_name . -.Pa NETMAP_BDG_LIST -is always used with -.Pa NIOCGINFO -command of -.Pa ioctl() -.Pp -Below is an example of printing all the existing ports walking through -all the bridges. - -.Bd -literal -compact -struct nmreq nmr; -int fd = open("/dev/netmap", O_RDWR); - -bzero(&nmr, sizeof(nmr)); -nmr.nr_version = NETMAP_API; -nmr.nr_cmd = NETMAP_BDG_LIST; -nmr.nr_arg1 = nmr.nr_arg2 = 0; /* start from bridge:0 port:0 */ -for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) { - D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2, - nmr.nr_name); - nmr.nr_name[0] = '\\0'; -} -.Ed -.Pp -See -.Xr netmap 4 -for details on the API. -.Ss LIMITS -.Nm -currently supports up to 8 switches, 254 ports per switch, -1024 buffers per port. These hard limits will be -changed to sysctl variables in future releases. -.Pp -Attaching the host stack to the bridge imposes significant performance -degradation when many packets are forwarded to the host stack by either -unicast or broadcast. -This is because every single packet going to the host stack causes mbuf -allocation in the same thread context as one forwarding packets. -.Pp -.Sh SYSCTL VARIABLES -.Nm -uses the following sysctl variables to control operation: -.Bl -tag -width 12 -.It dev.netmap.bridge -The maximum number of packets processed internally -in each iteration. -Defaults to 1024, use lower values to trade latency -with throughput. -.Pp -.It dev.netmap.verbose -Set to non-zero values to enable in-kernel diagnostics. -.El -.Pp -.Sh EXAMPLES -Create one switch, with a traffic generator connected to one -port, and a netmap-enabled tcpdump instance on another port: -.Bd -literal -offset indent -tcpdump -ni vale-a:1 & -pkt-gen -i vale-a:0 -f tx & -.Ed -.Pp -Create two switches, -each connected to two qemu machines on different ports. -.Bd -literal -offset indent -qemu -net nic -net netmap,ifname=vale-1:a ... & -qemu -net nic -net netmap,ifname=vale-1:b ... & -qemu -net nic -net netmap,ifname=vale-2:c ... & -qemu -net nic -net netmap,ifname=vale-2:d ... & -.Ed -.Sh SEE ALSO -.Xr netmap 4 -.Pp -.Xr http://info.iet.unipi.it/~luigi/vale/ -.Pp -Luigi Rizzo, Giuseppe Lettieri: VALE, a switched ethernet for virtual machines, -June 2012, http://info.iet.unipi.it/~luigi/vale/ -.Sh AUTHORS -.An -nosplit -The -.Nm -switch has been designed and implemented in 2012 by -.An Luigi Rizzo -and -.An Giuseppe Lettieri -at the Universita` di Pisa. -.Pp -.Nm -has been funded by the European Commission within FP7 Projects -CHANGE (257422) and OPENLAB (287581). From f87dec11fe08fb0fe6cacc7fe139574b6c10cd0f Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 7 Apr 2017 10:11:38 +0200 Subject: [PATCH 0052/2207] archlinux: align PKGBUILD --- LINUX/archlinux/PKGBUILD | 67 ++++++++++++---------------------- LINUX/archlinux/netmap.install | 3 +- 2 files changed, 25 insertions(+), 45 deletions(-) diff --git a/LINUX/archlinux/PKGBUILD b/LINUX/archlinux/PKGBUILD index 7694796df..20b3033d5 100644 --- a/LINUX/archlinux/PKGBUILD +++ b/LINUX/archlinux/PKGBUILD @@ -3,15 +3,15 @@ # Maintainer: Vincenzo Maffione pkgname=netmap -pkgver=r1324.519c07f +pkgver=r2392.86312f06 pkgrel=1 -pkgdesc="Netmap is a framework for high speed network packet I/O." +pkgdesc="A framework for high speed network packet I/O, using kernel bypass" arch=('any') url="http://info.iet.unipi.it/~luigi/netmap" license=('BSD') groups=() -depends=('linux' 'glibc') -makedepends=('git' 'sed' 'gzip' 'linux-headers' 'abs' 'pacman' 'xmlto' 'docbook-xsl') +depends=('glibc') +makedepends=('git' 'sed' 'gzip' 'linux-headers' 'abs' 'pacman' 'xmlto' 'docbook-xsl' 'patch' 'bc') provides=() conflicts=() replaces=() @@ -20,7 +20,7 @@ options=() install="netmap.install" source=("netmap.install" "git+https://github.com/luigirizzo/netmap") noextract=() -md5sums=("9f936e9fdd86c8a18babdc5848812f92" "SKIP") +md5sums=("62cbf2409535cf25cb4a185d4fa21525" "SKIP") pkgver() { cd "$srcdir/${pkgname%-git}" @@ -61,49 +61,30 @@ build() { # kernel sources downloaded in the previous steps to copy the NIC # drivers. Note however that the kernel modules are built against the # running kernel, and not against the downloaded sources. - msg "Starting to build netmap" - cd "$srcdir/netmap/LINUX" - ./configure --kernel-sources=$NESTEDDIR/src/linux-$KMAJVER + # We need to use --no-ext-drivers to make sure netmap does not + # download (Intel) drivers sources from the internet, we want to use the + # drivers sources provided by the Arch linux package. + # We also build and install the patched drivers with a "-netmap" suffix, + # so that they can be modprobed without conflicts/ambiguity with the + # unpatched drivers + msg "Starting to build netmap and netmap applications" + cd "$srcdir/netmap" + msg "PREFIX=$pkgdir/usr/local" + msg "INSTALL-MOD-PATH=$pkgdir" + ./configure --kernel-sources=$NESTEDDIR/src/linux-$KMAJVER \ + --no-ext-drivers \ + --driver-suffix="_netmap" \ + --install-mod-path="$pkgdir/usr" \ + --prefix="$pkgdir/usr/local" make || return 1 - # Build pkt-gen and vale-ctl - cd "$srcdir/netmap/examples" - make clean # amend for existing .o - make pkt-gen vale-ctl || return 1 msg "Build complete" } package() { - # Compute the version numbers of the running kernel - KVER1=$(uname -r) - KVER2=$(uname -r | sed 's/\.[0-9]\+-[0-9]\+//') - - # Install the netmap module into the extramodules-VERSION directory - mkdir -p "$pkgdir/usr/lib/modules/extramodules-${KVER2}" - cp "$srcdir/netmap/LINUX/netmap.ko" "$pkgdir/usr/lib/modules/extramodules-${KVER2}" - - # Install pkt-gen and valectl into /usr/bin - mkdir -p "$pkgdir/usr/bin" - cp "$srcdir/netmap/examples/pkt-gen" "$pkgdir/usr/bin" - cp "$srcdir/netmap/examples/vale-ctl" "$pkgdir/usr/bin" - - # Install the netmap public headers - mkdir -p "$pkgdir/usr/include/net" - cp "$srcdir/netmap/sys/net/netmap.h" "$srcdir/netmap/sys/net/netmap_user.h" "$pkgdir/usr/include/net" - - # Install the netmap man page - mkdir -p "$pkgdir/usr/share/man/man4" - cp "$srcdir/netmap/share/man/man4/netmap.4" "$pkgdir/usr/share/man/man4" - gzip "$pkgdir/usr/share/man/man4/netmap.4" - - #Find and install the modified NIC drivers - cd "$srcdir/netmap/LINUX" - DRIVERS=$(find . -name "*.ko" -and ! -name "netmap.ko") - if [ -n "$DRIVERS" ]; then - mkdir -p "$pkgdir/usr/lib/modules/extramodules-${KVER2}/netmap-drivers" - cp --parent $DRIVERS "$pkgdir/usr/lib/modules/extramodules-${KVER2}/netmap-drivers" - cd "$pkgdir/usr/lib/modules/extramodules-${KVER2}/netmap-drivers" - find . -name "*.ko" -exec sh -c "mv {} \$(echo {} | sed 's|\.ko|_netmap\.ko|g')" \; - fi + cd "$srcdir/netmap" + # Install netmap module, patched drivers modules, applications, headers + # and the man page + make install } # vim:set ts=2 sw=2 et: diff --git a/LINUX/archlinux/netmap.install b/LINUX/archlinux/netmap.install index 501b912e1..2959495e5 100644 --- a/LINUX/archlinux/netmap.install +++ b/LINUX/archlinux/netmap.install @@ -1,8 +1,7 @@ post_common() { depmod -a KVER2=$(uname -r | sed 's/\.[0-9]\+-[0-9]\+//') - echo ">>> Netmap patched NIC drivers have been installed into" - echo ">>> /lib/modules/extramodules-${KVER2}/netmap-drivers, with" + echo ">>> Netmap patched NIC drivers have been installed with" echo ">>> a '_netmap.ko' suffix, so that they don't replace the" echo ">>> official ones provided by the linux package." echo ">>> You should therefore manually unload the official ones and" From 58a8abb2ba3d0289b0985f2710620b6d31140426 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 7 Apr 2017 15:42:42 +0200 Subject: [PATCH 0053/2207] netmap(4): fix typo in sample code --- share/man/man4/netmap.4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4 index 726180800..3b586c953 100644 --- a/share/man/man4/netmap.4 +++ b/share/man/man4/netmap.4 @@ -1016,7 +1016,7 @@ void receiver(void) for (;;) { poll(&fds, 1, -1); while ( (buf = nm_nextpkt(d, &h)) ) - consume_pkt(buf, h->len); + consume_pkt(buf, h.len); } nm_close(d); } From 16d21aa09d4eacc43214762f505a72695d452fa1 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 10 Apr 2017 12:34:45 +0200 Subject: [PATCH 0054/2207] linux: e1000e: fix init_buffers routine to support *X_ONLY modes Fixes #287. --- LINUX/if_e1000e_netmap.h | 55 ++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h index 8afefe34f..e6dea798f 100644 --- a/LINUX/if_e1000e_netmap.h +++ b/LINUX/if_e1000e_netmap.h @@ -322,35 +322,40 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter) int i, si; uint64_t paddr; + if (!nm_native_on(na)) + return 0; + slot = netmap_reset(na, NR_RX, 0, 0); - if (!slot) - return 0; // not in netmap native mode - - adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc; - for (i = 0; i < rxr->count; i++) { - // XXX the skb check and cleanup can go away - struct e1000_buffer *bi = &rxr->buffer_info[i]; - si = netmap_idx_n2k(&na->rx_rings[0], i); - PNMB(na, slot + si, &paddr); - if (bi->skb) - D("rx buf %d was set", i); - bi->skb = NULL; // XXX leak if set - // netmap_load_map(...) - E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr); + if (slot) { + /* initialize the RX ring for netmap mode */ + adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc; + for (i = 0; i < rxr->count; i++) { + // XXX the skb check and cleanup can go away + struct e1000_buffer *bi = &rxr->buffer_info[i]; + si = netmap_idx_n2k(&na->rx_rings[0], i); + PNMB(na, slot + si, &paddr); + if (bi->skb) + D("rx buf %d was set", i); + bi->skb = NULL; // XXX leak if set + // netmap_load_map(...) + E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr); + } + rxr->next_to_use = 0; + /* preserve buffers already made available to clients */ + i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]); + wmb(); /* Force memory writes to complete */ + NM_WR_RX_TAIL(i); } - rxr->next_to_use = 0; - /* preserve buffers already made available to clients */ - i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]); - wmb(); /* Force memory writes to complete */ - NM_WR_RX_TAIL(i); - /* now initialize the tx ring */ slot = netmap_reset(na, NR_TX, 0, 0); - for (i = 0; i < na->num_tx_desc; i++) { - si = netmap_idx_n2k(&na->tx_rings[0], i); - PNMB(na, slot + si, &paddr); - // netmap_load_map(...) - E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr); + if (slot) { + /* initialize the tx ring for netmap mode */ + for (i = 0; i < na->num_tx_desc; i++) { + si = netmap_idx_n2k(&na->tx_rings[0], i); + PNMB(na, slot + si, &paddr); + // netmap_load_map(...) + E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr); + } } return 1; } From 6b4689851dfd0cb9b4207a0878d36418e143a381 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 12 Apr 2017 12:31:47 +0200 Subject: [PATCH 0055/2207] linux/config: disable EXT_DRIVERS when -e is not specified --- LINUX/scripts/np | 2 ++ 1 file changed, 2 insertions(+) diff --git a/LINUX/scripts/np b/LINUX/scripts/np index 437493dba..22127ed03 100755 --- a/LINUX/scripts/np +++ b/LINUX/scripts/np @@ -597,6 +597,8 @@ if [ "$1" = -e ]; then fi EXTDRV=1 shift +else + EXT_DRIVERS= fi COMMAND=$1; shift case $COMMAND in From 6e211aedf32f6a99fc8bf03a831706f81f184b1d Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 12 Apr 2017 12:32:24 +0200 Subject: [PATCH 0056/2207] linux/ixgbevf: check for array of pointers to rings --- LINUX/configure | 15 +++++++++++++++ LINUX/ixgbe_netmap_linux.h | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/LINUX/configure b/LINUX/configure index fd4bc36d5..dcd1bbd38 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1466,6 +1466,21 @@ EOF EOF fi # ixgbe + if drv enabled ixgbevf; then + + add_file_exists_check ixgbevf/ixgbevf.h true "drv_source_error ixgbevf" + + # array of rings or array of poiners to rings? + add_test 'define IXGBEVF_PTR_ARRAY' <tx_ring[0]; + } +EOF + fi + if drv enabled virtio_net.c; then add_file_exists_check virtio_net.c true "drv_source_error virtio_net.c" diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h index 2bf57b016..995055109 100644 --- a/LINUX/ixgbe_netmap_linux.h +++ b/LINUX/ixgbe_netmap_linux.h @@ -149,8 +149,13 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_ #define NM_IXGBE_RDT(ring_nr) IXGBE_VFRDT(ring_nr) #define NM_IXGBE_TX_DESC(_1, _2) IXGBEVF_TX_DESC(_1, _2) #define NM_IXGBE_RX_DESC(_1, _2) IXGBEVF_RX_DESC(_1, _2) +#ifdef NETMAP_LINUX_IXGBEVF_PTR_ARRAY #define NM_IXGBE_TX_RING(a, r) ((a)->tx_ring[(r)]) #define NM_IXGBE_RX_RING(a, r) ((a)->rx_ring[(r)]) +#else +#define NM_IXGBE_TX_RING(a, r) (&(a)->tx_ring[(r)]) +#define NM_IXGBE_RX_RING(a, r) (&(a)->rx_ring[(r)]) +#endif /* NETMAP_LINUX_IXGBE_PTR_ARRAY */ #define NM_IXGBE_ADAPTER ixgbevf_adapter #define NM_IXGBE_RESETTING __IXGBEVF_RESETTING #define NM_IXGBE_DOWN(adapter) ixgbevf_down(adapter) From 59fe58d7b074a13a9f6b4b6231d5b0d734e14cc3 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 12 Apr 2017 13:34:10 +0200 Subject: [PATCH 0057/2207] linux/ixgbevf: check for ixgbe-named macros --- LINUX/configure | 11 +++++++++++ LINUX/ixgbe_netmap_linux.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/LINUX/configure b/LINUX/configure index dcd1bbd38..5c9c5204e 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1470,6 +1470,17 @@ EOF add_file_exists_check ixgbevf/ixgbevf.h true "drv_source_error ixgbevf" + # IXGBEVF_* or IXGBE_*? + add_test true 'define IXGBEVF_IXGBE_MACROS' <tx_ring[(r)]) #define NM_IXGBE_RX_RING(a, r) ((a)->rx_ring[(r)]) From e00b69cd4339ee7494d44e7447f431f580c6961a Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 12 Apr 2017 14:38:33 +0200 Subject: [PATCH 0058/2207] linux/ixgbevf: patches for the vanilla driver --- .../vanilla--ixgbevf--20622--30500 | 120 ++++++++++++++++++ .../vanilla--ixgbevf--30500--30600 | 117 +++++++++++++++++ .../vanilla--ixgbevf--30600--30700 | 118 +++++++++++++++++ .../vanilla--ixgbevf--30700--30d00 | 118 +++++++++++++++++ .../vanilla--ixgbevf--30d00--30e00 | 118 +++++++++++++++++ .../vanilla--ixgbevf--30e00--30f00 | 110 ++++++++++++++++ .../vanilla--ixgbevf--30f00--31200 | 109 ++++++++++++++++ .../vanilla--ixgbevf--31200--31300 | 109 ++++++++++++++++ .../vanilla--ixgbevf--31300--40000 | 108 ++++++++++++++++ .../vanilla--ixgbevf--40000--40900 | 108 ++++++++++++++++ .../vanilla--ixgbevf--40900--99999 | 108 ++++++++++++++++ 11 files changed, 1243 insertions(+) create mode 100644 LINUX/final-patches/vanilla--ixgbevf--20622--30500 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30500--30600 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30600--30700 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30700--30d00 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30f00--31200 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--31200--31300 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--31300--40000 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--40000--40900 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--40900--99999 diff --git a/LINUX/final-patches/vanilla--ixgbevf--20622--30500 b/LINUX/final-patches/vanilla--ixgbevf--20622--30500 new file mode 100644 index 000000000..2db37ac3e --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--20622--30500 @@ -0,0 +1,120 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 0cd6202..acc1f94 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -209,6 +209,24 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure +@@ -224,6 +242,20 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter, + unsigned int i, eop, count = 0; + unsigned int total_bytes = 0, total_packets = 0; + ++ if (test_bit(__IXGBEVF_DOWN, &adapter->state)) ++ return true; ++ ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); +@@ -507,6 +539,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED); ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1289,6 +1331,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter, + } + + /** ++} ++ + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure + * +@@ -1320,6 +1364,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) + txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, i); ++#endif /* DEV_NETMAP */ + } + } + +@@ -1582,6 +1629,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) + ixgbevf_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; ++#ifdef DEV_NETMAP ++ if (!ixgbe_netmap_configure_rx_ring(adapter, i)) ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(adapter, ring, ring->count); + ring->next_to_use = ring->count - 1; + writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail); +@@ -3485,6 +3535,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + hw_dbg(hw, "LRO is disabled \n"); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3516,6 +3571,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 b/LINUX/final-patches/vanilla--ixgbevf--30500--30600 new file mode 100644 index 000000000..24ad625de --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--30500--30600 @@ -0,0 +1,117 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 41e3225..16a7107 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -186,6 +186,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure +@@ -204,6 +222,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); +@@ -474,6 +503,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED); ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1265,6 +1304,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter, + } + + /** ++} ++ + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure + * +@@ -1296,6 +1337,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) + txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, i); ++#endif /* DEV_NETMAP */ + } + } + +@@ -1532,6 +1576,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) + ixgbevf_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; ++#ifdef DEV_NETMAP ++ if (!ixgbe_netmap_configure_rx_ring(adapter, i)) ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(adapter, ring, ring->count); + ring->next_to_use = ring->count - 1; + writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail); +@@ -3463,6 +3510,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + hw_dbg(hw, "LRO is disabled\n"); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3494,6 +3546,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 b/LINUX/final-patches/vanilla--ixgbevf--30600--30700 new file mode 100644 index 000000000..265748988 --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--30600--30700 @@ -0,0 +1,118 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 60ef645..7f6efe8 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -196,6 +214,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBEVF_TX_DESC(tx_ring, eop); +@@ -397,6 +426,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED); ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBEVF_RX_DESC(rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1009,6 +1048,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter) + } + + /** ++} ++ + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure + * +@@ -1040,6 +1081,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) + txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, i); ++#endif /* DEV_NETMAP */ + } + } + +@@ -1242,6 +1286,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) + ixgbevf_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, i)) ++ continue; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(adapter, ring, + IXGBE_DESC_UNUSED(ring)); + } +@@ -3127,6 +3175,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3158,6 +3211,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 new file mode 100644 index 000000000..95bbaf738 --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 @@ -0,0 +1,118 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index de1ad50..31ac551 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -196,6 +214,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + i = tx_ring->next_to_clean; + eop = tx_ring->tx_buffer_info[i].next_to_watch; + eop_desc = IXGBEVF_TX_DESC(tx_ring, eop); +@@ -397,6 +426,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED); ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBEVF_RX_DESC(rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -996,6 +1035,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter) + } + + /** ++} ++ + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure + * +@@ -1027,6 +1068,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) + txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, i); ++#endif /* DEV_NETMAP */ + } + } + +@@ -1266,6 +1310,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) + ixgbevf_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, i)) ++ continue; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(adapter, ring, + IXGBE_DESC_UNUSED(ring)); + } +@@ -3243,6 +3291,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3275,6 +3328,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 new file mode 100644 index 000000000..ef22eda7f --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 @@ -0,0 +1,118 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 92ef4cb..1141b53 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -193,6 +211,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + i = tx_ring->next_to_clean; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + eop_desc = tx_buffer_info->next_to_watch; +@@ -434,6 +463,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBEVF_RX_DESC(rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1087,6 +1126,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter) + } + + /** ++} ++ + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure + * +@@ -1118,6 +1159,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter) + txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, i); ++#endif /* DEV_NETMAP */ + } + } + +@@ -1379,6 +1423,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter) + ixgbevf_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) { + struct ixgbevf_ring *ring = &adapter->rx_ring[i]; ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, i)) ++ continue; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(adapter, ring, + ixgbevf_desc_unused(ring)); + } +@@ -3545,6 +3593,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3577,6 +3630,11 @@ static void ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 new file mode 100644 index 000000000..6273ad298 --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 @@ -0,0 +1,110 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 9df2898..f49ce78 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -175,6 +175,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -193,6 +211,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -448,6 +478,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBEVF_RX_DESC(rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1161,6 +1201,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + pr_err("Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -1330,6 +1373,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -3538,6 +3585,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3570,6 +3622,11 @@ static void ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_DOWN, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 new file mode 100644 index 000000000..3dd0fe086 --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 @@ -0,0 +1,109 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index d0799e8..002646d 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -237,6 +255,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -492,6 +522,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBEVF_RX_DESC(rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1208,6 +1248,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + pr_err("Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -1381,6 +1424,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -3601,6 +3648,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + cards_found++; + return 0; + +@@ -3634,6 +3686,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_REMOVING, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 b/LINUX/final-patches/vanilla--ixgbevf--31200--31300 new file mode 100644 index 000000000..963df03f7 --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--31200--31300 @@ -0,0 +1,109 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 030a219..75ac799 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -237,6 +255,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -492,6 +522,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + i = rx_ring->next_to_clean; + rx_desc = IXGBEVF_RX_DESC(rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); +@@ -1208,6 +1248,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + pr_err("Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -1381,6 +1424,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -3598,6 +3645,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + hw_dbg(hw, "MAC: %d\n", hw->mac.type); + + hw_dbg(hw, "Intel(R) 82599 Virtual Function\n"); ++ ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -3630,6 +3682,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + set_bit(__IXGBEVF_REMOVING, &adapter->state); + + del_timer_sync(&adapter->watchdog_timer); diff --git a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 b/LINUX/final-patches/vanilla--ixgbevf--31300--40000 new file mode 100644 index 000000000..cd92598af --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--31300--40000 @@ -0,0 +1,108 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 38c7a0b..ffeb57e 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -208,6 +208,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, + + static void ixgbevf_tx_timeout(struct net_device *netdev); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -226,6 +244,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -806,6 +836,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + u16 cleaned_count = ixgbevf_desc_unused(rx_ring); + struct sk_buff *skb = rx_ring->skb; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + while (likely(total_rx_packets < budget)) { + union ixgbe_adv_rx_desc *rx_desc; + +@@ -1488,6 +1528,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + pr_err("Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -1624,6 +1667,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -3877,6 +3924,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + break; + } + ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -3914,6 +3965,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) + if (!netdev) + return; + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + adapter = netdev_priv(netdev); + + set_bit(__IXGBEVF_REMOVING, &adapter->state); diff --git a/LINUX/final-patches/vanilla--ixgbevf--40000--40900 b/LINUX/final-patches/vanilla--ixgbevf--40000--40900 new file mode 100644 index 000000000..0b418b278 --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--40000--40900 @@ -0,0 +1,108 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 4186981..54e0ac2 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -283,6 +283,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) + ixgbevf_tx_timeout_reset(adapter); + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -301,6 +319,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -912,6 +942,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + u16 cleaned_count = ixgbevf_desc_unused(rx_ring); + struct sk_buff *skb = rx_ring->skb; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + while (likely(total_rx_packets < budget)) { + union ixgbe_adv_rx_desc *rx_desc; + +@@ -1594,6 +1634,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + pr_err("Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -1763,6 +1806,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -4064,6 +4111,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + break; + } + ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -4101,6 +4152,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) + if (!netdev) + return; + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + adapter = netdev_priv(netdev); + + set_bit(__IXGBEVF_REMOVING, &adapter->state); diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--99999 b/LINUX/final-patches/vanilla--ixgbevf--40900--99999 new file mode 100644 index 000000000..509202c7b --- /dev/null +++ b/LINUX/final-patches/vanilla--ixgbevf--40900--99999 @@ -0,0 +1,108 @@ +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index cbf70fe..1212ce6 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) + ixgbevf_tx_timeout_reset(adapter); + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif ++ + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: board private structure +@@ -313,6 +331,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -929,6 +959,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + u16 cleaned_count = ixgbevf_desc_unused(rx_ring); + struct sk_buff *skb = rx_ring->skb; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + while (likely(total_rx_packets < budget)) { + union ixgbe_adv_rx_desc *rx_desc; + +@@ -1613,6 +1653,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -1791,6 +1834,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -4152,6 +4199,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + break; + } + ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -4189,6 +4240,10 @@ static void ixgbevf_remove(struct pci_dev *pdev) + if (!netdev) + return; + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + adapter = netdev_priv(netdev); + + set_bit(__IXGBEVF_REMOVING, &adapter->state); From bc2edc44c9122eb465e29e6095f001cd1da699f0 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 11:37:55 +0200 Subject: [PATCH 0059/2207] expose netmap_attach_ext() to allow for per-na private tailroom --- LINUX/netmap_linux.c | 1 + sys/dev/netmap/netmap.c | 24 +++++++++++++----------- sys/dev/netmap/netmap_kern.h | 1 + 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index f737e483b..513b9c9ec 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -2194,6 +2194,7 @@ module_exit(linux_netmap_fini); /* export certain symbols to other modules */ EXPORT_SYMBOL(netmap_attach); /* driver attach routines */ +EXPORT_SYMBOL(netmap_attach_ext); #ifdef WITH_PTNETMAP_GUEST EXPORT_SYMBOL(netmap_pt_guest_attach); /* ptnetmap driver attach routine */ EXPORT_SYMBOL(netmap_pt_guest_rxsync); /* ptnetmap generic rxsync */ diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 73a52afcf..68ad7603b 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2886,22 +2886,24 @@ netmap_hw_dtor(struct netmap_adapter *na) /* - * Allocate a ``netmap_adapter`` object, and initialize it from the + * Allocate a netmap_adapter object, and initialize it from the * 'arg' passed by the driver on attach. - * We allocate a block of memory with room for a struct netmap_adapter - * plus two sets of N+2 struct netmap_kring (where N is the number - * of hardware rings): - * krings 0..N-1 are for the hardware queues. - * kring N is for the host stack queue - * kring N+1 is only used for the selinfo for all queues. // XXX still true ? + * We allocate a block of memory of 'size' bytes, which has room + * for struct netmap_adapter plus additional room private to + * the caller. * Return 0 on success, ENOMEM otherwise. */ -static int -_netmap_attach(struct netmap_adapter *arg, size_t size) +int +netmap_attach_ext(struct netmap_adapter *arg, size_t size) { struct netmap_hw_adapter *hwna = NULL; struct ifnet *ifp = NULL; + if (size < sizeof(struct netmap_adapter)) { + D("Invalid netmap adapter size %u", size); + return EINVAL; + } + if (arg == NULL || arg->ifp == NULL) goto fail; ifp = arg->ifp; @@ -2960,7 +2962,7 @@ _netmap_attach(struct netmap_adapter *arg, size_t size) int netmap_attach(struct netmap_adapter *arg) { - return _netmap_attach(arg, sizeof(struct netmap_hw_adapter)); + return netmap_attach_ext(arg, sizeof(struct netmap_hw_adapter)); } @@ -2978,7 +2980,7 @@ netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb, if (arg->nm_mem == NULL) return ENOMEM; arg->na_flags |= NAF_MEM_OWNER; - error = _netmap_attach(arg, sizeof(struct netmap_pt_guest_adapter)); + error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter)); if (error) return error; diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index a22d91f41..66d2cd9f4 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -1173,6 +1173,7 @@ static __inline void nm_kr_start(struct netmap_kring *kr) * virtual ports (vale, pipes, monitor) */ int netmap_attach(struct netmap_adapter *); +int netmap_attach_ext(struct netmap_adapter *, size_t size); void netmap_detach(struct ifnet *); int netmap_transmit(struct ifnet *, struct mbuf *); struct netmap_slot *netmap_reset(struct netmap_adapter *na, From bb2a39ece669b92329e7e0711bf49d8a82e64c92 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 11:44:10 +0200 Subject: [PATCH 0060/2207] netmap_pt: move netmap_pt_guest_attach to netmap_pt.c --- sys/dev/netmap/netmap.c | 39 +------------------------------------- sys/dev/netmap/netmap_pt.c | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 68ad7603b..ae8b56675 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2900,7 +2900,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size) struct ifnet *ifp = NULL; if (size < sizeof(struct netmap_adapter)) { - D("Invalid netmap adapter size %u", size); + D("Invalid netmap adapter size %d", (int)size); return EINVAL; } @@ -2966,43 +2966,6 @@ netmap_attach(struct netmap_adapter *arg) } -#ifdef WITH_PTNETMAP_GUEST -int -netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb, - unsigned int nifp_offset, unsigned int memid) -{ - struct netmap_pt_guest_adapter *ptna; - struct ifnet *ifp = arg ? arg->ifp : NULL; - int error; - - /* get allocator */ - arg->nm_mem = netmap_mem_pt_guest_new(ifp, nifp_offset, memid); - if (arg->nm_mem == NULL) - return ENOMEM; - arg->na_flags |= NAF_MEM_OWNER; - error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter)); - if (error) - return error; - - /* get the netmap_pt_guest_adapter */ - ptna = (struct netmap_pt_guest_adapter *) NA(ifp); - ptna->csb = csb; - - /* Initialize a separate pass-through netmap adapter that is going to - * be used by the ptnet driver only, and so never exposed to netmap - * applications. We only need a subset of the available fields. */ - memset(&ptna->dr, 0, sizeof(ptna->dr)); - ptna->dr.up.ifp = ifp; - ptna->dr.up.nm_mem = netmap_mem_get(ptna->hwup.up.nm_mem); - ptna->dr.up.nm_config = ptna->hwup.up.nm_config; - - ptna->backend_regifs = 0; - - return 0; -} -#endif /* WITH_PTNETMAP_GUEST */ - - void NM_DBG(netmap_adapter_get)(struct netmap_adapter *na) { diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 8b5c7edfa..e4d8e7f95 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -1450,4 +1450,38 @@ ptnet_nm_dtor(struct netmap_adapter *na) netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp); } +int +netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb, + unsigned int nifp_offset, unsigned int memid) +{ + struct netmap_pt_guest_adapter *ptna; + struct ifnet *ifp = arg ? arg->ifp : NULL; + int error; + + /* get allocator */ + arg->nm_mem = netmap_mem_pt_guest_new(ifp, nifp_offset, memid); + if (arg->nm_mem == NULL) + return ENOMEM; + arg->na_flags |= NAF_MEM_OWNER; + error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter)); + if (error) + return error; + + /* get the netmap_pt_guest_adapter */ + ptna = (struct netmap_pt_guest_adapter *) NA(ifp); + ptna->csb = csb; + + /* Initialize a separate pass-through netmap adapter that is going to + * be used by the ptnet driver only, and so never exposed to netmap + * applications. We only need a subset of the available fields. */ + memset(&ptna->dr, 0, sizeof(ptna->dr)); + ptna->dr.up.ifp = ifp; + ptna->dr.up.nm_mem = netmap_mem_get(ptna->hwup.up.nm_mem); + ptna->dr.up.nm_config = ptna->hwup.up.nm_config; + + ptna->backend_regifs = 0; + + return 0; +} + #endif /* WITH_PTNETMAP_GUEST */ From 436e35786f0cf1d2d9345f98628e6887a9cd98fd Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 12:25:29 +0200 Subject: [PATCH 0061/2207] linux: virtio-net: allocate per-na shared RX/TX vnet headers --- LINUX/virtio_netmap.h | 61 ++++++++++++++++++----------------------- sys/dev/netmap/netmap.c | 2 +- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index e2af8e0ca..c148ed69a 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -173,6 +173,12 @@ virtio_netmap_init_sgs(struct virtnet_info *vi) #endif /* VIRTIO_NOTIFY */ +struct netmap_virtio_adapter { + struct netmap_hw_adapter hwna; /* base class */ + struct virtio_net_hdr_mrg_rxbuf shared_rxvhdr ____cacheline_aligned_in_smp; + struct virtio_net_hdr_mrg_rxbuf shared_txvhdr ____cacheline_aligned_in_smp; +}; + static void virtio_netmap_clean_used_rings(struct virtnet_info *vi, struct netmap_adapter *na) @@ -271,13 +277,11 @@ virtio_netmap_set_kring_mode(struct netmap_adapter *na, int mode) } -static struct virtio_net_hdr_mrg_rxbuf *shared_tx_vnet_hdr; -static struct virtio_net_hdr_mrg_rxbuf *shared_rx_vnet_hdr; - /* Register and unregister. */ static int virtio_netmap_reg(struct netmap_adapter *na, int onoff) { + struct netmap_virtio_adapter *vna = (struct netmap_virtio_adapter *)na; struct ifnet *ifp = na->ifp; struct virtnet_info *vi = netdev_priv(ifp); bool was_up = false; @@ -306,22 +310,8 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) /* TX shared virtio-net header must be zeroed because its * content is exposed to the host. RX shared virtio-net * header is zeroed only for security reasons. */ - BUG_ON(shared_tx_vnet_hdr); - BUG_ON(shared_rx_vnet_hdr); - shared_tx_vnet_hdr = kzalloc(sizeof(*shared_tx_vnet_hdr), - GFP_KERNEL); - if (!shared_tx_vnet_hdr) { - D("Failed to allocate TX shared vnet header"); - return ENOMEM; - } - shared_rx_vnet_hdr = kzalloc(sizeof(*shared_rx_vnet_hdr), - GFP_KERNEL); - if (!shared_rx_vnet_hdr) { - kfree(shared_tx_vnet_hdr); - shared_tx_vnet_hdr = NULL; - D("Failed to allocate RX shared vnet header"); - return ENOMEM; - } + memset(&vna->shared_txvhdr, 0, sizeof(vna->shared_txvhdr)); + memset(&vna->shared_rxvhdr, 0, sizeof(vna->shared_rxvhdr)); /* Get and free any used buffers. This is necessary * before calling free_unused_bufs(), that uses @@ -366,11 +356,6 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) virtio_netmap_clean_used_rings(vi, na); virtio_netmap_reclaim_unused(vi); - - kfree(shared_tx_vnet_hdr); - shared_tx_vnet_hdr = NULL; - kfree(shared_rx_vnet_hdr); - shared_rx_vnet_hdr = NULL; } if (was_up) { @@ -397,12 +382,13 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) /* device-specific */ COMPAT_DECL_SG + struct netmap_virtio_adapter *vna = (struct netmap_virtio_adapter *)na; struct virtnet_info *vi = netdev_priv(ifp); struct virtqueue *vq = GET_TX_VQ(vi, ring_nr); struct scatterlist *sg = GET_TX_SG(vi, ring_nr); size_t vnet_hdr_len = vi->mergeable_rx_bufs ? - sizeof(*shared_tx_vnet_hdr) : - sizeof(shared_tx_vnet_hdr->hdr); + sizeof(vna->shared_txvhdr) : + sizeof(vna->shared_txvhdr.hdr); struct netmap_adapter *token; int nospace = 0; @@ -447,7 +433,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) /* Initialize the scatterlist and expose it to * the hypervisor. */ COMPAT_INIT_SG(sg); - sg_set_buf(sg, shared_tx_vnet_hdr, vnet_hdr_len); + sg_set_buf(sg, &vna->shared_txvhdr, vnet_hdr_len); sg_set_buf(sg + 1, addr, len); nospace = virtqueue_add_outbuf(vq, sg, 2, na, GFP_ATOMIC); if (nospace) { @@ -495,12 +481,13 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags) /* device-specific */ COMPAT_DECL_SG + struct netmap_virtio_adapter *vna = (struct netmap_virtio_adapter *)na; struct virtnet_info *vi = netdev_priv(ifp); struct virtqueue *vq = GET_RX_VQ(vi, ring_nr); struct scatterlist *sg = GET_RX_SG(vi, ring_nr); size_t vnet_hdr_len = vi->mergeable_rx_bufs ? - sizeof(*shared_rx_vnet_hdr) : - sizeof(shared_rx_vnet_hdr->hdr); + sizeof(vna->shared_rxvhdr) : + sizeof(vna->shared_rxvhdr.hdr); /* XXX netif_carrier_ok ? */ @@ -575,7 +562,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags) /* Initialize the scatterlist and expose it to * the hypervisor. */ COMPAT_INIT_SG(sg); - sg_set_buf(sg, shared_rx_vnet_hdr, vnet_hdr_len); + sg_set_buf(sg, &vna->shared_rxvhdr, vnet_hdr_len); sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na)); nospace = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC); if (nospace) { @@ -611,9 +598,10 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) { struct ifnet *ifp = vi->dev; struct netmap_adapter* na = NA(ifp); + struct netmap_virtio_adapter *vna = (struct netmap_virtio_adapter *)na; size_t vnet_hdr_len = vi->mergeable_rx_bufs ? - sizeof(*shared_rx_vnet_hdr) : - sizeof(shared_rx_vnet_hdr->hdr); + sizeof(vna->shared_rxvhdr) : + sizeof(vna->shared_rxvhdr.hdr); unsigned int r; if (!nm_native_on(na)) @@ -643,7 +631,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) slot = &ring->slot[i]; addr = NMB(na, slot); COMPAT_INIT_SG(sg); - sg_set_buf(sg, shared_rx_vnet_hdr, vnet_hdr_len); + sg_set_buf(sg, &vna->shared_rxvhdr, vnet_hdr_len); sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na)); err = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC); if (err < 0) { @@ -689,6 +677,7 @@ static void virtio_netmap_attach(struct virtnet_info *vi) { struct netmap_adapter na; /* temporary container of methods */ + int ret; bzero(&na, sizeof(na)); @@ -701,7 +690,11 @@ virtio_netmap_attach(struct virtnet_info *vi) na.nm_rxsync = virtio_netmap_rxsync; na.nm_config = virtio_netmap_config; - netmap_attach(&na); + ret = netmap_attach_ext(&na, sizeof(struct netmap_virtio_adapter)); + if (ret) { + D("Failed to attach virtio-net interface"); + return; + } D("virtio attached txq=%d, txd=%d rxq=%d, rxd=%d", na.num_tx_rings, na.num_tx_desc, diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index ae8b56675..61953cb0e 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2899,7 +2899,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size) struct netmap_hw_adapter *hwna = NULL; struct ifnet *ifp = NULL; - if (size < sizeof(struct netmap_adapter)) { + if (size < sizeof(struct netmap_hw_adapter)) { D("Invalid netmap adapter size %d", (int)size); return EINVAL; } From 1499f7c598f7c54483c17b8db2861a27e79fe13f Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 15:08:49 +0200 Subject: [PATCH 0062/2207] linux: virtio-net: fix logic in init_buffers routine --- LINUX/virtio_netmap.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index c148ed69a..5e0282ddc 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -606,6 +606,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) if (!nm_native_on(na)) return 0; + for (r = 0; r < na->num_rx_rings; r++) { COMPAT_DECL_SG struct netmap_ring *ring = na->rx_rings[r].ring; @@ -617,8 +618,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) slot = netmap_reset(na, NR_RX, r, 0); if (!slot) { - D("strange, null netmap ring %d", r); - return 0; + continue; } /* Add up to na>-num_rx_desc-1 buffers to this RX virtqueue. @@ -647,7 +647,6 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) D("added %d inbufs on queue %d", i, r); virtqueue_kick(vq); } - return 1; } From d6e0d995209eadad96287268afeca9e817000f19 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 16:37:24 +0200 Subject: [PATCH 0063/2207] linux: virtio-net: fix wrong processing of kring pending mode --- LINUX/virtio_netmap.h | 51 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index 5e0282ddc..2bf213397 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -254,29 +254,6 @@ virtio_netmap_reclaim_unused(struct virtnet_info *vi) } } -/* Set or clear nr_pending_mode and nr_mode for all the rings, independently - * of the specific user request. This is necessary for now because the - * virtio-net driver patches do not support single-queue mode (modifications - * would be needed to free_unused_bufs() free_receive_bufs()).*/ -static void -virtio_netmap_set_kring_mode(struct netmap_adapter *na, int mode) -{ - int i; - - for (i = 0; i < DEV_NUM_TX_QUEUES(na->ifp); i++) { - struct netmap_kring *kring = &na->tx_rings[i]; - - kring->nr_pending_mode = kring->nr_mode = mode; - } - - for (i = 0; i < DEV_NUM_RX_QUEUES(na->ifp); i++) { - struct netmap_kring *kring = &na->rx_rings[i]; - - kring->nr_pending_mode = kring->nr_mode = mode; - } - -} - /* Register and unregister. */ static int virtio_netmap_reg(struct netmap_adapter *na, int onoff) @@ -286,6 +263,8 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) struct virtnet_info *vi = netdev_priv(ifp); bool was_up = false; int error = 0; + enum txrx t; + int i; if (na == NULL) return EINVAL; @@ -297,6 +276,12 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) return 0; } + /* Set or clear nr_pending_mode and nr_mode for all the rings, independently + * of the specific user request. This is necessary for now because the + * virtio-net driver patches do not support single-queue mode (modifications + * would be needed to free_unused_bufs() free_receive_bufs()).*/ + // TODO + /* It's important to make sure each virtnet_close() matches * a virtnet_open(), otherwise a napi_disable() is not matched by * a napi_enable(), which results in a deadlock. */ @@ -345,11 +330,27 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) rtnl_lock(); /* enable netmap mode */ - virtio_netmap_set_kring_mode(na, NKR_NETMAP_ON); + for_rx_tx(t) { + for (i = 0; i <= nma_get_nrings(na, t); i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_on(kring)) { + kring->nr_mode = NKR_NETMAP_ON; + } + } + } nm_set_native_flags(na); } else { nm_clear_native_flags(na); - virtio_netmap_set_kring_mode(na, NKR_NETMAP_OFF); + for_rx_tx(t) { + for (i = 0; i <= nma_get_nrings(na, t); i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_off(kring)) { + kring->nr_mode = NKR_NETMAP_OFF; + } + } + } /* Get and free any used buffer. This is necessary * before calling virtqueue_detach_unused_buf(). */ From 91cd1e21e94eeb36e10bcdd403d460bdd1d90e50 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 16:53:08 +0200 Subject: [PATCH 0064/2207] bridge: fix Makefile --- apps/bridge/GNUmakefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/bridge/GNUmakefile b/apps/bridge/GNUmakefile index 4e76fe3bb..a6c63e99d 100644 --- a/apps/bridge/GNUmakefile +++ b/apps/bridge/GNUmakefile @@ -1,6 +1,6 @@ # For multiple programs using a single source file each, # we can just define 'progs' and create custom targets. -PROGS = bridge +PROGS = bridge bridge-b LIBNETMAP = CLEANFILES = $(PROGS) *.o @@ -31,3 +31,8 @@ install: $(PROGS:%=install-%) install-%: install -D $* $(DESTDIR)/$(PREFIX)/bin/$* + +bridge-b: bridge-b.o + +bridge-b.o: bridge.c + $(CC) $(CFLAGS) -DBUSYWAIT -c $^ -o $@ From 12322eb9874ee1b084b4f8c627c664199a47c339 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 17:40:28 +0200 Subject: [PATCH 0065/2207] linux: virtio: prevent user from opening only a subset of the hw rings This is not supported by the current virtio-net patch. --- LINUX/virtio_netmap.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index 2bf213397..a8c78b121 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -276,11 +276,31 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff) return 0; } - /* Set or clear nr_pending_mode and nr_mode for all the rings, independently - * of the specific user request. This is necessary for now because the - * virtio-net driver patches do not support single-queue mode (modifications - * would be needed to free_unused_bufs() free_receive_bufs()).*/ - // TODO + /* These virtio-net driver patches do not support single-queue mode + * (modifications would be needed to free_unused_bufs() + * free_receive_bufs()). As a result, we fail here if we detect + * the user is trying to open only a subset of the rings. */ + if (onoff) { + int hwrings_pending = 0; + int hwrings = nma_get_nrings(na, NR_TX) + + nma_get_nrings(na, NR_RX); + + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t); i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_on(kring)) { + hwrings_pending ++; + } + } + } + + if (!(hwrings_pending == 0 || hwrings_pending == hwrings)) { + D("virtio-net native adapter can only open " + "all RX and TX hw rings"); + return EINVAL; + } + } /* It's important to make sure each virtnet_close() matches * a virtnet_open(), otherwise a napi_disable() is not matched by From ebdd77f6f802fad17b3de3a238e2767096b24e08 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 13 Apr 2017 18:06:40 +0200 Subject: [PATCH 0066/2207] bridge: minor cosmetic changes --- apps/bridge/bridge.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c index b419777b4..b53b60e1b 100644 --- a/apps/bridge/bridge.c +++ b/apps/bridge/bridge.c @@ -285,18 +285,16 @@ main(int argc, char **argv) n0 = pkt_queued(pa, 0); n1 = pkt_queued(pb, 0); #if defined(_WIN32) || defined(BUSYWAIT) - if (n0){ + if (n0) { ioctl(pollfd[1].fd, NIOCTXSYNC, NULL); pollfd[1].revents = POLLOUT; - } - else { + } else { ioctl(pollfd[0].fd, NIOCRXSYNC, NULL); } - if (n1){ + if (n1) { ioctl(pollfd[0].fd, NIOCTXSYNC, NULL); pollfd[0].revents = POLLOUT; - } - else { + } else { ioctl(pollfd[1].fd, NIOCRXSYNC, NULL); } ret = 1; @@ -340,16 +338,15 @@ main(int argc, char **argv) D("error on fd1, rx [%d,%d,%d)", rx->head, rx->cur, rx->tail); } - if (pollfd[0].revents & POLLOUT) { + if (pollfd[0].revents & POLLOUT) move(pb, pa, burst); - } - if (pollfd[1].revents & POLLOUT) { + + if (pollfd[1].revents & POLLOUT) move(pa, pb, burst); - } + /* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here, * kernel will txsync on next poll(). */ } - D("exiting"); nm_close(pb); nm_close(pa); From 3d060c31678c90e6ad77d25e0c4490d4b3d347ec Mon Sep 17 00:00:00 2001 From: Gerard Spivey Date: Sun, 16 Apr 2017 04:24:27 -0400 Subject: [PATCH 0067/2207] Fix typo in Linux Configure Script Linux Configure script has a typo in the help text. "destir" should be "destdir" --- LINUX/configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINUX/configure b/LINUX/configure index 5c9c5204e..55c48d93e 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -304,7 +304,7 @@ Available options: --cc= C compiler to be used for the apps [$cc] --ld= linker to be used for the apps [$ld] --prefix= install path for the apps [$prefix] - --destir= destination dir for the apps [$DESTDIR] + --destdir= destination dir for the apps [$DESTDIR] --show-drivers print the list of available drivers and exit --show-ext-drivers print the list of available external drivers and exit From 92c5401cc5a4c2a93b696399ee408d56b54e21d7 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 19 Apr 2017 10:38:37 +0200 Subject: [PATCH 0068/2207] linux/i40e: intel 2.0.23 driver --- LINUX/default-config.mak.in_ | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index f26cb206b..b310b32b0 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -17,4 +17,5 @@ e1000e@cflags := -fno-pie $(call enabled_intel_driver,e1000e,3.3.5.3) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(call enabled_intel_driver,igb,5.3.5.4) -$(call enabled_intel_driver,i40e,2.0.19) +$(call enabled_intel_driver,i40e,2.0.23) +i40e@patch := patches/intel--i40e--2.0.19 From 4bd5e7768f9c505b689823b7d12066563cf55850 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 21 Apr 2017 11:07:50 +0200 Subject: [PATCH 0069/2207] generic: use "emulated" term within logs --- LINUX/README | 14 +++++++------- sys/dev/netmap/netmap_generic.c | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/LINUX/README b/LINUX/README index 492ecd122..0a929f621 100644 --- a/LINUX/README +++ b/LINUX/README @@ -87,9 +87,9 @@ features, namely: in copy and zero-copy modes, without stopping traffic). - generic (*): the generic driver that is used to access - NICs without native netmap support (at reduced - performance). + generic (*): the generic (a.k.a. emulated) netmap adapter that is + used to access NICs without native netmap support (at + reduced performance). ptnetmap-guest: netmap passthrough support for guests (including the ptnet driver). @@ -106,10 +106,10 @@ features, namely: NIC drivers -------------- - The generic driver can be used to open in netmap mode any NIC for which - the host OS already supplies a driver. The optimal performance, however, - is only obtained with netmap-enabled NIC drivers. The configure script - implements two methods to obtain the netmap-enabled drivers: + The emulated (generic) adapter can be used to open in netmap mode any NIC + for which the host OS already supplies a driver. The optimal performance, + however, is only obtained with netmap-enabled NIC drivers. The configure + script implements two methods to obtain the netmap-enabled drivers: 1. patching the native drivers that come with your kernel; 2. patching NIC-vendors out-of-tree drivers selected by us. diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c index 5969427a8..d9d97559e 100644 --- a/sys/dev/netmap/netmap_generic.c +++ b/sys/dev/netmap/netmap_generic.c @@ -305,7 +305,7 @@ void generic_rate(int txp, int txs, int txi, int rxp, int rxs, int rxi) #endif /* !RATE */ -/* =============== GENERIC NETMAP ADAPTER SUPPORT ================= */ +/* ========== GENERIC (EMULATED) NETMAP ADAPTER SUPPORT ============= */ /* * Wrapper used by the generic adapter layer to notify @@ -335,7 +335,6 @@ generic_netmap_unregister(struct netmap_adapter *na) int i, r; if (na->active_fds == 0) { - D("Generic adapter %p goes off", na); rtnl_lock(); na->na_flags &= ~NAF_NETMAP_ON; @@ -351,14 +350,14 @@ generic_netmap_unregister(struct netmap_adapter *na) for_each_rx_kring_h(r, kring, na) { if (nm_kring_pending_off(kring)) { - D("RX ring %d of generic adapter %p goes off", r, na); + D("Emulated adapter: ring '%s' deactivated", kring->name); kring->nr_mode = NKR_NETMAP_OFF; } } for_each_tx_kring_h(r, kring, na) { if (nm_kring_pending_off(kring)) { kring->nr_mode = NKR_NETMAP_OFF; - D("TX ring %d of generic adapter %p goes off", r, na); + D("Emulated adapter: ring '%s' deactivated", kring->name); } } @@ -415,6 +414,7 @@ generic_netmap_unregister(struct netmap_adapter *na) del_timer(&rate_ctx.timer); } #endif + D("Emulated adapter for %s deactivated", na->name); } return 0; @@ -439,7 +439,7 @@ generic_netmap_register(struct netmap_adapter *na, int enable) } if (na->active_fds == 0) { - D("Generic adapter %p goes on", na); + D("Emulated adapter for %s activated", na->name); /* Do all memory allocations when (na->active_fds == 0), to * simplify error management. */ @@ -484,14 +484,14 @@ generic_netmap_register(struct netmap_adapter *na, int enable) for_each_rx_kring_h(r, kring, na) { if (nm_kring_pending_on(kring)) { - D("RX ring %d of generic adapter %p goes on", r, na); + D("Emulated adapter: ring '%s' activated", kring->name); kring->nr_mode = NKR_NETMAP_ON; } } for_each_tx_kring_h(r, kring, na) { if (nm_kring_pending_on(kring)) { - D("TX ring %d of generic adapter %p goes on", r, na); + D("Emulated adapter: ring '%s' activated", kring->name); kring->nr_mode = NKR_NETMAP_ON; } } @@ -1153,7 +1153,6 @@ generic_netmap_dtor(struct netmap_adapter *na) struct netmap_adapter *prev_na = gna->prev; if (prev_na != NULL) { - D("Released generic NA %p", gna); netmap_adapter_put(prev_na); if (nm_iszombie(na)) { /* @@ -1162,6 +1161,7 @@ generic_netmap_dtor(struct netmap_adapter *na) */ netmap_adapter_put(prev_na); } + D("Native netmap adapter %p restored", prev_na); } NM_ATTACH_NA(ifp, prev_na); /* @@ -1169,7 +1169,7 @@ generic_netmap_dtor(struct netmap_adapter *na) * overrides WNA(ifp) if na->ifp is not NULL. */ na->ifp = NULL; - D("Restored native NA %p", prev_na); + D("Emulated netmap adapter for %s destroyed", na->name); } /* @@ -1241,7 +1241,7 @@ generic_netmap_attach(struct ifnet *ifp) nm_os_generic_set_features(gna); - D("Created generic NA %p (prev %p)", gna, gna->prev); + D("Emulated adapter for %s created (prev was %p)", na->name, gna->prev); return retval; } From c4104bf8201dfa1aa20c2fbffb18c759542b6187 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 21 Apr 2017 19:58:39 +0200 Subject: [PATCH 0070/2207] LINUX: ptnet: use interface name for interrupt description string --- LINUX/netmap_ptnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c index 792361813..9d32d3273 100644 --- a/LINUX/netmap_ptnet.c +++ b/LINUX/netmap_ptnet.c @@ -788,7 +788,7 @@ ptnet_irqs_init(struct ptnet_info *pi) ptnet_tx_intr : ptnet_rx_intr; snprintf(pq->msix_name, sizeof(pq->msix_name), - "ptnet-%d", i); + "%s-%d", pi->netdev->name, i); ret = request_irq(pi->msix_entries[i].vector, handler, 0, pq->msix_name, pq); if (ret) { From 91ba4d2a4ee810096b05cfae7dffa431211de8f8 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Sun, 23 Apr 2017 12:12:45 +0200 Subject: [PATCH 0071/2207] linux/igb: fix check on igb_read_phy_reg return value --- LINUX/if_igb_netmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h index 2cc556a3c..3951a51a5 100644 --- a/LINUX/if_igb_netmap.h +++ b/LINUX/if_igb_netmap.h @@ -49,7 +49,7 @@ char netmap_igb_driver_name[] = "igb" NETMAP_LINUX_DRIVER_SUFFIX; static inline u16 nm_igb_read(struct igb_adapter *adapter, u32 offset) { u16 rv = 0; - if (igb_read_phy_reg(&adapter->hw, offset, &rv)) { + if (!igb_read_phy_reg(&adapter->hw, offset, &rv)) { RD(5, "%s: read failure at offset %x", adapter->netdev->name, offset); } From 1db74325ead0f8601b64e802fa84e8040c572569 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 26 Apr 2017 13:03:13 +0200 Subject: [PATCH 0072/2207] linux/igb: update intr intercept logic --- ...0100--99999 => vanilla--igb--40100--40400} | 0 .../final-patches/vanilla--igb--40400--99999 | 86 +++++++++++++++++++ 2 files changed, 86 insertions(+) rename LINUX/final-patches/{vanilla--igb--40100--99999 => vanilla--igb--40100--40400} (100%) create mode 100644 LINUX/final-patches/vanilla--igb--40400--99999 diff --git a/LINUX/final-patches/vanilla--igb--40100--99999 b/LINUX/final-patches/vanilla--igb--40100--40400 similarity index 100% rename from LINUX/final-patches/vanilla--igb--40100--99999 rename to LINUX/final-patches/vanilla--igb--40100--40400 diff --git a/LINUX/final-patches/vanilla--igb--40400--99999 b/LINUX/final-patches/vanilla--igb--40400--99999 new file mode 100644 index 000000000..f73685ad5 --- /dev/null +++ b/LINUX/final-patches/vanilla--igb--40400--99999 @@ -0,0 +1,86 @@ +diff --git a/igb/igb_main.c b/igb/igb_main.c +index ea7b098..ddb376e 100644 +--- a/igb/igb_main.c ++++ b/igb/igb_main.c +@@ -253,6 +253,10 @@ static int debug = -1; + module_param(debug, int, 0); + MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++#include ++#endif ++ + struct igb_reg_info { + u32 ofs; + char *name; +@@ -2540,6 +2544,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + /* carrier off reporting is important to ethtool even BEFORE open */ + netif_carrier_off(netdev); + ++#ifdef DEV_NETMAP ++ igb_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + #ifdef CONFIG_IGB_DCA + if (dca_add_requester(&pdev->dev) == 0) { + adapter->flags |= IGB_FLAG_DCA_ENABLED; +@@ -2809,6 +2817,10 @@ static void igb_remove(struct pci_dev *pdev) + wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE); + } + #endif ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. +@@ -3292,6 +3304,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter, + + txdctl |= E1000_TXDCTL_QUEUE_ENABLE; + wr32(E1000_TXDCTL(reg_idx), txdctl); ++#ifdef DEV_NETMAP ++ igb_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + /** +@@ -6409,6 +6424,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) + + if (test_bit(__IGB_DOWN, &adapter->state)) + return true; ++#ifdef DEV_NETMAP ++ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; /* cleaned ok */ ++#endif /* DEV_NETMAP */ + + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IGB_TX_DESC(tx_ring, i); +@@ -6916,6 +6935,15 @@ static int igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget) + unsigned int total_bytes = 0, total_packets = 0; + u16 cleaned_count = igb_desc_unused(rx_ring); + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ + while (likely(total_packets < budget)) { + union e1000_adv_rx_desc *rx_desc; + +@@ -7033,6 +7061,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count) + struct igb_rx_buffer *bi; + u16 i = rx_ring->next_to_use; + ++#ifdef DEV_NETMAP ++ if (igb_netmap_configure_rx_ring(rx_ring)) ++ return; ++#endif /* DEV_NETMAP */ ++ + /* nothing to do */ + if (!cleaned_count) + return; From f1a0bfda9a73865f42875294ea573dedf918e332 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 26 Apr 2017 14:14:14 +0200 Subject: [PATCH 0073/2207] linux/i40e: only set the i40e@patch var when i40e is external --- LINUX/default-config.mak.in_ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index b310b32b0..de08fd5c4 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -18,4 +18,4 @@ $(call enabled_intel_driver,e1000e,3.3.5.3) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(call enabled_intel_driver,igb,5.3.5.4) $(call enabled_intel_driver,i40e,2.0.23) -i40e@patch := patches/intel--i40e--2.0.19 +$(if $(filter i40e,$(E_DRIVERS)),i40e@patch := patches/intel--i40e--2.0.19) From c4ed4f0768e07b2649fb5588a44b30ba6daca774 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 26 Apr 2017 18:31:05 +0200 Subject: [PATCH 0074/2207] linux/igb: use the proper function to read TDH --- LINUX/configure | 10 +++++----- LINUX/if_igb_netmap.h | 22 ++++------------------ 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/LINUX/configure b/LINUX/configure index 55c48d93e..a8d9e3222 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1597,12 +1597,12 @@ EOF fi # i40e if drv enabled igb; then - add_test 'have IGB_PHY_OPS' <hw, offset, &rv)) { - RD(5, "%s: read failure at offset %x", - adapter->netdev->name, offset); - } - return rv; - -} +#ifdef NETMAP_LINUX_HAVE_IGB_RD32 +#define READ_TDH(_adapter, _txr) igb_rd32(&(_adapter)->hw, E1000_TDH((_txr)->reg_idx)) #elif defined(E1000_READ_REG) -static inline u16 nm_igb_read(struct igb_adapter *adapter, u32 offset) -{ - return E1000_READ_REG(&adapter->hw, offset); -} +#define READ_TDH(_adapter, _txr) E1000_READ_REG((_txr)->head) #else -#error "I don't know how to read registers in igb" +#define READ_TDH(_adapter, _txr) readl((_txr)->head) #endif #ifndef E1000_TX_DESC_ADV #define E1000_TX_DESC_ADV(_r, _i) IGB_TX_DESC(&(_r), _i) #define E1000_RX_DESC_ADV(_r, _i) IGB_RX_DESC(&(_r), _i) -#define READ_TDH(_adapter, _txr) nm_igb_read(_adapter, E1000_TDH((_txr)->reg_idx)) #else /* up to 3.2, approximately */ #define igb_tx_buffer igb_buffer #define tx_buffer_info buffer_info #define igb_rx_buffer igb_buffer #define rx_buffer_info buffer_info -#define READ_TDH(_adapter, _txr) readl((_txr)->head) #endif From ca46c526381fd43f9181f5d2d5ab3f2e521187f9 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Wed, 26 Apr 2017 18:58:16 +0200 Subject: [PATCH 0075/2207] linux/igb: use rd32 when available --- LINUX/if_igb_netmap.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h index 25776c1ca..f5cf65f25 100644 --- a/LINUX/if_igb_netmap.h +++ b/LINUX/if_igb_netmap.h @@ -48,7 +48,13 @@ char netmap_igb_driver_name[] = "igb" NETMAP_LINUX_DRIVER_SUFFIX; #ifdef NETMAP_LINUX_HAVE_IGB_RD32 #define READ_TDH(_adapter, _txr) igb_rd32(&(_adapter)->hw, E1000_TDH((_txr)->reg_idx)) #elif defined(E1000_READ_REG) -#define READ_TDH(_adapter, _txr) E1000_READ_REG((_txr)->head) +#define READ_TDH(_adapter, _txr) E1000_READ_REG(&(_adapter)->hw, E1000_TDH((_txr)->reg_idx)) +#elif defined rd32 +static inline u32 READ_TDH(struct igb_adapter *adapter, struct igb_ring *txr) +{ + struct e1000_hw *hw = &adapter->hw; + return rd32(E1000_TDH(txr->reg_idx)); +} #else #define READ_TDH(_adapter, _txr) readl((_txr)->head) #endif From caaf8e93aedfe78a38c046139927dfed374d9df0 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Thu, 27 Apr 2017 14:11:16 +0200 Subject: [PATCH 0076/2207] linux/config: add missing eval --- LINUX/default-config.mak.in_ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index de08fd5c4..c610c9dc1 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -18,4 +18,4 @@ $(call enabled_intel_driver,e1000e,3.3.5.3) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(call enabled_intel_driver,igb,5.3.5.4) $(call enabled_intel_driver,i40e,2.0.23) -$(if $(filter i40e,$(E_DRIVERS)),i40e@patch := patches/intel--i40e--2.0.19) +$(if $(filter i40e,$(E_DRIVERS)),$(eval i40e@patch := patches/intel--i40e--2.0.19)) From 029a25411d92f8d6fb6b9d4ad4c62e044d8cb80c Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 27 Apr 2017 22:44:37 +0200 Subject: [PATCH 0077/2207] pkt-gen: small clean-up --- apps/pkt-gen/pkt-gen.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index a70136706..c4ca9c252 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -187,9 +187,6 @@ const char *indirect_payload="netmap pkt-gen indirect payload\n" int verbose = 0; -#define SKIP_PAYLOAD 1 /* do not check payload. XXX unused */ - - #define VIRT_HDR_1 10 /* length of a base vnet-hdr */ #define VIRT_HDR_2 12 /* length of the extenede vnet-hdr */ #define VIRT_HDR_MAX VIRT_HDR_2 @@ -1198,7 +1195,6 @@ wait_time(struct timespec ts) * The payload (after UDP header, ofs 42) has a 4-byte sequence * followed by a struct timeval (or bintime?) */ -#define PAY_OFS 42 /* where in the pkt... */ static void * ping_body(void *data) @@ -2748,7 +2744,7 @@ main(int arc, char **argv) D("%d cpus is too high, have only %d cpus", g.cpus, i); usage(); } -D("running on %d cpus (have %d)", g.cpus, i); + D("running on %d cpus (have %d)", g.cpus, i); if (g.cpus == 0) g.cpus = i; From 238e273b3f9fa0eefb108c493fc270c62a21615b Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 27 Mar 2017 11:26:34 +0200 Subject: [PATCH 0078/2207] ptnetmap: add ptnetmap_worker sysctl --- sys/dev/netmap/netmap.c | 3 +++ sys/dev/netmap/netmap_kern.h | 1 + 2 files changed, 4 insertions(+) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 61953cb0e..9edd4cbd7 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -522,6 +522,8 @@ int netmap_generic_rings = 1; /* Non-zero if ptnet devices are allowed to use virtio-net headers. */ int ptnet_vnet_hdr = 1; +int ptnetmap_worker = 1; + /* * SYSCTL calls are grouped between SYSBEGIN and SYSEND to be emulated * in some other operating systems @@ -548,6 +550,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW, &netmap_generic_ SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW, &netmap_generic_rings, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW, &netmap_generic_txqdisc, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr, 0 , ""); +SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_worker, CTLFLAG_RW, &ptnetmap_worker, 0 , ""); SYSEND; diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 66d2cd9f4..6697fc8bf 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -1561,6 +1561,7 @@ extern int netmap_generic_mit; extern int netmap_generic_ringsize; extern int netmap_generic_rings; extern int netmap_generic_txqdisc; +extern int ptnetmap_worker; /* * NA returns a pointer to the struct netmap adapter from the ifp, From d10df9ad5b72ca229274582d8ec993f8dfcb32a7 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 12:38:06 +0200 Subject: [PATCH 0079/2207] linux: ptnetmap: simplify struct nm_kthread --- LINUX/netmap_linux.c | 123 +++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 68 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 513b9c9ec..8d1e6915d 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1270,8 +1270,15 @@ nm_os_ncpus(void) return nr_cpu_ids; } -/* kthread context */ -struct nm_kthread_ctx { +struct nm_kthread { + struct mm_struct *mm; /* to access guest memory */ + struct task_struct *worker; /* the kernel thread */ + + atomic_t scheduled; /* pending wake_up request */ + int attach_user; /* kthread attached to user_process */ + + int affinity; + /* files to exchange notifications */ struct file *ioevent_file; /* notification from guest */ struct file *irq_file; /* notification to guest (interrupt) */ @@ -1290,17 +1297,6 @@ struct nm_kthread_ctx { long type; }; -struct nm_kthread { - struct mm_struct *mm; - struct task_struct *worker; - - atomic_t scheduled; /* pending wake_up request */ - int attach_user; /* kthread attached to user_process */ - - struct nm_kthread_ctx worker_ctx; - int affinity; -}; - void inline nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) { @@ -1321,31 +1317,29 @@ nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) static void nm_kthread_poll_fn(struct file *file, wait_queue_head_t *wq_head, poll_table *pt) { - struct nm_kthread_ctx *ctx; + struct nm_kthread *nmk; - ctx = container_of(pt, struct nm_kthread_ctx, poll_table); - ctx->waitq_head = wq_head; - add_wait_queue(wq_head, &ctx->waitq); + nmk = container_of(pt, struct nm_kthread, poll_table); + nmk->waitq_head = wq_head; + add_wait_queue(wq_head, &nmk->waitq); } static int nm_kthread_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key) { - struct nm_kthread_ctx *ctx; struct nm_kthread *nmk; - ctx = container_of(wq, struct nm_kthread_ctx, waitq); - nmk = container_of(ctx, struct nm_kthread, worker_ctx); + nmk = container_of(wq, struct nm_kthread, waitq); nm_os_kthread_wakeup_worker(nmk); return 0; } static void inline -nm_kthread_worker_fn(struct nm_kthread_ctx *ctx) +nm_kthread_worker_fn(struct nm_kthread *nmk) { __set_current_state(TASK_RUNNING); - ctx->worker_fn(ctx->worker_private); /* run payload */ + nmk->worker_fn(nmk->worker_private); /* run payload */ if (need_resched()) schedule(); } @@ -1354,7 +1348,6 @@ static int nm_kthread_worker(void *data) { struct nm_kthread *nmk = data; - struct nm_kthread_ctx *ctx = &nmk->worker_ctx; int old_scheduled = atomic_read(&nmk->scheduled); int new_scheduled = old_scheduled; mm_segment_t oldfs = get_fs(); @@ -1365,12 +1358,12 @@ nm_kthread_worker(void *data) } while (!kthread_should_stop()) { - if (!ctx->ioevent_file) { + if (!nmk->ioevent_file) { /* * if ioevent_file is not defined, we don't have notification * mechanism and we continually execute worker_fn() */ - nm_kthread_worker_fn(ctx); + nm_kthread_worker_fn(nmk); } else { /* @@ -1386,7 +1379,7 @@ nm_kthread_worker(void *data) /* check if there is a pending notification */ if (likely(new_scheduled != old_scheduled)) { old_scheduled = new_scheduled; - nm_kthread_worker_fn(ctx); + nm_kthread_worker_fn(nmk); } else { schedule(); } @@ -1406,25 +1399,23 @@ nm_kthread_worker(void *data) void inline nm_os_kthread_send_irq(struct nm_kthread *nmk) { - if (nmk->worker_ctx.irq_ctx) - eventfd_signal(nmk->worker_ctx.irq_ctx, 1); + if (nmk->irq_ctx) + eventfd_signal(nmk->irq_ctx, 1); } static void nm_kthread_close_files(struct nm_kthread *nmk) { - struct nm_kthread_ctx *wctx = &nmk->worker_ctx; - - if (wctx->ioevent_file) { - fput(wctx->ioevent_file); - wctx->ioevent_file = NULL; + if (nmk->ioevent_file) { + fput(nmk->ioevent_file); + nmk->ioevent_file = NULL; } - if (wctx->irq_file) { - fput(wctx->irq_file); - wctx->irq_file = NULL; - eventfd_ctx_put(wctx->irq_ctx); - wctx->irq_ctx = NULL; + if (nmk->irq_file) { + fput(nmk->irq_file); + nmk->irq_file = NULL; + eventfd_ctx_put(nmk->irq_ctx); + nmk->irq_ctx = NULL; } } @@ -1432,11 +1423,10 @@ static int nm_kthread_open_files(struct nm_kthread *nmk, void *opaque) { struct file *file; - struct nm_kthread_ctx *wctx = &nmk->worker_ctx; struct ptnetmap_cfgentry_qemu *ring_cfg = opaque; - wctx->ioevent_file = NULL; - wctx->irq_file = NULL; + nmk->ioevent_file = NULL; + nmk->irq_file = NULL; if (!opaque) { return 0; @@ -1446,15 +1436,15 @@ nm_kthread_open_files(struct nm_kthread *nmk, void *opaque) file = eventfd_fget(ring_cfg->ioeventfd); if (IS_ERR(file)) goto err; - wctx->ioevent_file = file; + nmk->ioevent_file = file; } if (ring_cfg->irqfd) { file = eventfd_fget(ring_cfg->irqfd); if (IS_ERR(file)) goto err; - wctx->irq_file = file; - wctx->irq_ctx = eventfd_ctx_fileget(file); + nmk->irq_file = file; + nmk->irq_ctx = eventfd_ctx_fileget(file); } return 0; @@ -1465,37 +1455,37 @@ nm_kthread_open_files(struct nm_kthread *nmk, void *opaque) } static void -nm_kthread_init_poll(struct nm_kthread *nmk, struct nm_kthread_ctx *ctx) +nm_kthread_init_poll(struct nm_kthread *nmk) { - init_waitqueue_func_entry(&ctx->waitq, nm_kthread_poll_wakeup); - init_poll_funcptr(&ctx->poll_table, nm_kthread_poll_fn); + init_waitqueue_func_entry(&nmk->waitq, nm_kthread_poll_wakeup); + init_poll_funcptr(&nmk->poll_table, nm_kthread_poll_fn); } static int -nm_kthread_start_poll(struct nm_kthread_ctx *ctx, struct file *file) +nm_kthread_start_poll(struct nm_kthread *nmk) { unsigned long mask; int ret = 0; - if (ctx->waitq_head) + if (nmk->waitq_head) return 0; - mask = file->f_op->poll(file, &ctx->poll_table); + mask = nmk->ioevent_file->f_op->poll(nmk->ioevent_file, &nmk->poll_table); if (mask) - nm_kthread_poll_wakeup(&ctx->waitq, 0, 0, (void *)mask); + nm_kthread_poll_wakeup(&nmk->waitq, 0, 0, (void *)mask); if (mask & POLLERR) { - if (ctx->waitq_head) - remove_wait_queue(ctx->waitq_head, &ctx->waitq); + if (nmk->waitq_head) + remove_wait_queue(nmk->waitq_head, &nmk->waitq); ret = EINVAL; } return ret; } static void -nm_kthread_stop_poll(struct nm_kthread_ctx *ctx) +nm_kthread_stop_poll(struct nm_kthread *nmk) { - if (ctx->waitq_head) { - remove_wait_queue(ctx->waitq_head, &ctx->waitq); - ctx->waitq_head = NULL; + if (nmk->waitq_head) { + remove_wait_queue(nmk->waitq_head, &nmk->waitq); + nmk->waitq_head = NULL; } } @@ -1521,9 +1511,9 @@ nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, if (!nmk) return NULL; - nmk->worker_ctx.worker_fn = cfg->worker_fn; - nmk->worker_ctx.worker_private = cfg->worker_private; - nmk->worker_ctx.type = cfg->type; + nmk->worker_fn = cfg->worker_fn; + nmk->worker_private = cfg->worker_private; + nmk->type = cfg->type; atomic_set(&nmk->scheduled, 0); /* attach kthread to user process (ptnetmap) */ @@ -1534,7 +1524,7 @@ nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, if (error) goto err; - nm_kthread_init_poll(nmk, &nmk->worker_ctx); + nm_kthread_init_poll(nmk); return nmk; err: @@ -1558,9 +1548,7 @@ nm_os_kthread_start(struct nm_kthread *nmk) nmk->mm = get_task_mm(current); } - /* ToDo Make this able to pass arbitrary string (e.g., for 'nm_') from nmk */ - snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, - nmk->worker_ctx.type); + snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, nmk->type); nmk->worker = kthread_create(nm_kthread_worker, nmk, name); if (IS_ERR(nmk->worker)) { error = -PTR_ERR(nmk->worker); @@ -1570,9 +1558,8 @@ nm_os_kthread_start(struct nm_kthread *nmk) kthread_bind(nmk->worker, nmk->affinity); wake_up_process(nmk->worker); - if (nmk->worker_ctx.ioevent_file) { - error = nm_kthread_start_poll(&nmk->worker_ctx, - nmk->worker_ctx.ioevent_file); + if (nmk->ioevent_file) { + error = nm_kthread_start_poll(nmk); if (error) { goto err_kstop; } @@ -1596,7 +1583,7 @@ nm_os_kthread_stop(struct nm_kthread *nmk) return; } - nm_kthread_stop_poll(&nmk->worker_ctx); + nm_kthread_stop_poll(nmk); if (nmk->worker) { kthread_stop(nmk->worker); From 5f899e16310e019989a5aef95fd423e25d69810e Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 13:13:06 +0200 Subject: [PATCH 0080/2207] use nm_kctx prefix rather than nm_kthread refer to kernel context --- LINUX/netmap_linux.c | 78 ++++++++++++++++----------------- WINDOWS/netmap_windows.c | 14 +++--- sys/dev/netmap/netmap_freebsd.c | 42 +++++++++--------- sys/dev/netmap/netmap_kern.h | 22 +++++----- sys/dev/netmap/netmap_pt.c | 72 +++++++++++++++--------------- sys/dev/netmap/netmap_vale.c | 20 ++++----- 6 files changed, 124 insertions(+), 124 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 8d1e6915d..3f4f47155 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1270,7 +1270,7 @@ nm_os_ncpus(void) return nr_cpu_ids; } -struct nm_kthread { +struct nm_kctx { struct mm_struct *mm; /* to access guest memory */ struct task_struct *worker; /* the kernel thread */ @@ -1290,7 +1290,7 @@ struct nm_kthread { wait_queue_t waitq; /* worker function and parameter */ - nm_kthread_worker_fn_t worker_fn; + nm_kctx_worker_fn_t worker_fn; void *worker_private; /* integer to manage multiple worker contexts */ @@ -1298,7 +1298,7 @@ struct nm_kthread { }; void inline -nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) +nm_os_kctx_worker_wakeup(struct nm_kctx *nmk) { /* * There may be a race between FE and BE, @@ -1315,28 +1315,28 @@ nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) static void -nm_kthread_poll_fn(struct file *file, wait_queue_head_t *wq_head, poll_table *pt) +nm_kctx_poll_fn(struct file *file, wait_queue_head_t *wq_head, poll_table *pt) { - struct nm_kthread *nmk; + struct nm_kctx *nmk; - nmk = container_of(pt, struct nm_kthread, poll_table); + nmk = container_of(pt, struct nm_kctx, poll_table); nmk->waitq_head = wq_head; add_wait_queue(wq_head, &nmk->waitq); } static int -nm_kthread_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key) +nm_kctx_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key) { - struct nm_kthread *nmk; + struct nm_kctx *nmk; - nmk = container_of(wq, struct nm_kthread, waitq); - nm_os_kthread_wakeup_worker(nmk); + nmk = container_of(wq, struct nm_kctx, waitq); + nm_os_kctx_worker_wakeup(nmk); return 0; } static void inline -nm_kthread_worker_fn(struct nm_kthread *nmk) +nm_kctx_worker_fn(struct nm_kctx *nmk) { __set_current_state(TASK_RUNNING); nmk->worker_fn(nmk->worker_private); /* run payload */ @@ -1345,9 +1345,9 @@ nm_kthread_worker_fn(struct nm_kthread *nmk) } static int -nm_kthread_worker(void *data) +nm_kctx_worker(void *data) { - struct nm_kthread *nmk = data; + struct nm_kctx *nmk = data; int old_scheduled = atomic_read(&nmk->scheduled); int new_scheduled = old_scheduled; mm_segment_t oldfs = get_fs(); @@ -1363,7 +1363,7 @@ nm_kthread_worker(void *data) * if ioevent_file is not defined, we don't have notification * mechanism and we continually execute worker_fn() */ - nm_kthread_worker_fn(nmk); + nm_kctx_worker_fn(nmk); } else { /* @@ -1379,7 +1379,7 @@ nm_kthread_worker(void *data) /* check if there is a pending notification */ if (likely(new_scheduled != old_scheduled)) { old_scheduled = new_scheduled; - nm_kthread_worker_fn(nmk); + nm_kctx_worker_fn(nmk); } else { schedule(); } @@ -1397,14 +1397,14 @@ nm_kthread_worker(void *data) } void inline -nm_os_kthread_send_irq(struct nm_kthread *nmk) +nm_os_kctx_send_irq(struct nm_kctx *nmk) { if (nmk->irq_ctx) eventfd_signal(nmk->irq_ctx, 1); } static void -nm_kthread_close_files(struct nm_kthread *nmk) +nm_kctx_close_files(struct nm_kctx *nmk) { if (nmk->ioevent_file) { fput(nmk->ioevent_file); @@ -1420,7 +1420,7 @@ nm_kthread_close_files(struct nm_kthread *nmk) } static int -nm_kthread_open_files(struct nm_kthread *nmk, void *opaque) +nm_kctx_open_files(struct nm_kctx *nmk, void *opaque) { struct file *file; struct ptnetmap_cfgentry_qemu *ring_cfg = opaque; @@ -1450,19 +1450,19 @@ nm_kthread_open_files(struct nm_kthread *nmk, void *opaque) return 0; err: - nm_kthread_close_files(nmk); + nm_kctx_close_files(nmk); return -PTR_ERR(file); } static void -nm_kthread_init_poll(struct nm_kthread *nmk) +nm_kctx_init_poll(struct nm_kctx *nmk) { - init_waitqueue_func_entry(&nmk->waitq, nm_kthread_poll_wakeup); - init_poll_funcptr(&nmk->poll_table, nm_kthread_poll_fn); + init_waitqueue_func_entry(&nmk->waitq, nm_kctx_poll_wakeup); + init_poll_funcptr(&nmk->poll_table, nm_kctx_poll_fn); } static int -nm_kthread_start_poll(struct nm_kthread *nmk) +nm_kctx_start_poll(struct nm_kctx *nmk) { unsigned long mask; int ret = 0; @@ -1471,7 +1471,7 @@ nm_kthread_start_poll(struct nm_kthread *nmk) return 0; mask = nmk->ioevent_file->f_op->poll(nmk->ioevent_file, &nmk->poll_table); if (mask) - nm_kthread_poll_wakeup(&nmk->waitq, 0, 0, (void *)mask); + nm_kctx_poll_wakeup(&nmk->waitq, 0, 0, (void *)mask); if (mask & POLLERR) { if (nmk->waitq_head) remove_wait_queue(nmk->waitq_head, &nmk->waitq); @@ -1481,7 +1481,7 @@ nm_kthread_start_poll(struct nm_kthread *nmk) } static void -nm_kthread_stop_poll(struct nm_kthread *nmk) +nm_kctx_stop_poll(struct nm_kctx *nmk) { if (nmk->waitq_head) { remove_wait_queue(nmk->waitq_head, &nmk->waitq); @@ -1490,16 +1490,16 @@ nm_kthread_stop_poll(struct nm_kthread *nmk) } void -nm_os_kthread_set_affinity(struct nm_kthread *nmk, int affinity) +nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity) { nmk->affinity = affinity; } -struct nm_kthread * -nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, +struct nm_kctx * +nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, void *opaque) { - struct nm_kthread *nmk = NULL; + struct nm_kctx *nmk = NULL; int error; if (cfgtype != PTNETMAP_CFGTYPE_QEMU) { @@ -1520,11 +1520,11 @@ nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, nmk->attach_user = cfg->attach_user; /* open event fds */ - error = nm_kthread_open_files(nmk, opaque); + error = nm_kctx_open_files(nmk, opaque); if (error) goto err; - nm_kthread_init_poll(nmk); + nm_kctx_init_poll(nmk); return nmk; err: @@ -1534,7 +1534,7 @@ nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, } int -nm_os_kthread_start(struct nm_kthread *nmk) +nm_os_kctx_worker_start(struct nm_kctx *nmk) { int error = 0; char name[16]; @@ -1549,7 +1549,7 @@ nm_os_kthread_start(struct nm_kthread *nmk) } snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, nmk->type); - nmk->worker = kthread_create(nm_kthread_worker, nmk, name); + nmk->worker = kthread_create(nm_kctx_worker, nmk, name); if (IS_ERR(nmk->worker)) { error = -PTR_ERR(nmk->worker); goto err; @@ -1559,7 +1559,7 @@ nm_os_kthread_start(struct nm_kthread *nmk) wake_up_process(nmk->worker); if (nmk->ioevent_file) { - error = nm_kthread_start_poll(nmk); + error = nm_kctx_start_poll(nmk); if (error) { goto err_kstop; } @@ -1577,13 +1577,13 @@ nm_os_kthread_start(struct nm_kthread *nmk) } void -nm_os_kthread_stop(struct nm_kthread *nmk) +nm_os_kctx_worker_stop(struct nm_kctx *nmk) { if (!nmk->worker) { return; } - nm_kthread_stop_poll(nmk); + nm_kctx_stop_poll(nmk); if (nmk->worker) { kthread_stop(nmk->worker); @@ -1597,16 +1597,16 @@ nm_os_kthread_stop(struct nm_kthread *nmk) } void -nm_os_kthread_delete(struct nm_kthread *nmk) +nm_os_kctx_destroy(struct nm_kctx *nmk) { if (!nmk) return; if (nmk->worker) { - nm_os_kthread_stop(nmk); + nm_os_kctx_worker_stop(nmk); } - nm_kthread_close_files(nmk); + nm_kctx_close_files(nmk); kfree(nmk); } diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c index f5850d1be..8289d421a 100644 --- a/WINDOWS/netmap_windows.c +++ b/WINDOWS/netmap_windows.c @@ -1019,18 +1019,18 @@ nm_os_put_module(void) } -struct nm_kthread { +struct nm_kctx { int unused; /* To avoid compiler barfs */ }; void -nm_os_kthread_set_affinity(struct nm_kthread *nmk, int affinity) +nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity) { // TODO } -struct nm_kthread * -nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, +struct nm_kctx * +nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, void *opaque) { // TODO @@ -1038,21 +1038,21 @@ nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, } int -nm_os_kthread_start(struct nm_kthread *nmk) +nm_os_kctx_worker_start(struct nm_kctx *nmk) { // TODO return -1; } void -nm_os_kthread_stop(struct nm_kthread *nmk) +nm_os_kctx_worker_stop(struct nm_kctx *nmk) { // TODO } void -nm_os_kthread_delete(struct nm_kthread *nmk) +nm_os_kctx_destroy(struct nm_kctx *nmk) { // TODO } diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c index 047e990d4..904afb9e4 100644 --- a/sys/dev/netmap/netmap_freebsd.c +++ b/sys/dev/netmap/netmap_freebsd.c @@ -1002,32 +1002,32 @@ nm_os_ncpus(void) return mp_maxid + 1; } -struct nm_kthread_ctx { +struct nm_kctx_ctx { struct thread *user_td; /* thread user-space (kthread creator) to send ioctl */ struct ptnetmap_cfgentry_bhyve cfg; /* worker function and parameter */ - nm_kthread_worker_fn_t worker_fn; + nm_kctx_worker_fn_t worker_fn; void *worker_private; - struct nm_kthread *nmk; + struct nm_kctx *nmk; /* integer to manage multiple worker contexts (e.g., RX or TX on ptnetmap) */ long type; }; -struct nm_kthread { +struct nm_kctx { struct thread *worker; struct mtx worker_lock; uint64_t scheduled; /* pending wake_up request */ - struct nm_kthread_ctx worker_ctx; + struct nm_kctx_ctx worker_ctx; int run; /* used to stop kthread */ int attach_user; /* kthread attached to user_process */ int affinity; }; void inline -nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) +nm_os_kctx_worker_wakeup(struct nm_kctx *nmk) { /* * There may be a race between FE and BE, @@ -1047,9 +1047,9 @@ nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) } void inline -nm_os_kthread_send_irq(struct nm_kthread *nmk) +nm_os_kctx_send_irq(struct nm_kctx *nmk) { - struct nm_kthread_ctx *ctx = &nmk->worker_ctx; + struct nm_kctx_ctx *ctx = &nmk->worker_ctx; int err; if (ctx->user_td && ctx->cfg.ioctl_fd > 0) { @@ -1064,10 +1064,10 @@ nm_os_kthread_send_irq(struct nm_kthread *nmk) } static void -nm_kthread_worker(void *data) +nm_kctx_worker(void *data) { - struct nm_kthread *nmk = data; - struct nm_kthread_ctx *ctx = &nmk->worker_ctx; + struct nm_kctx *nmk = data; + struct nm_kctx_ctx *ctx = &nmk->worker_ctx; uint64_t old_scheduled = nmk->scheduled; if (nmk->affinity >= 0) { @@ -1119,16 +1119,16 @@ nm_kthread_worker(void *data) } void -nm_os_kthread_set_affinity(struct nm_kthread *nmk, int affinity) +nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity) { nmk->affinity = affinity; } -struct nm_kthread * -nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, +struct nm_kctx * +nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, void *opaque) { - struct nm_kthread *nmk = NULL; + struct nm_kctx *nmk = NULL; if (cfgtype != PTNETMAP_CFGTYPE_BHYVE) { D("Unsupported cfgtype %u", cfgtype); @@ -1157,7 +1157,7 @@ nm_os_kthread_create(struct nm_kthread_cfg *cfg, unsigned int cfgtype, } int -nm_os_kthread_start(struct nm_kthread *nmk) +nm_os_kctx_worker_start(struct nm_kctx *nmk) { struct proc *p = NULL; int error = 0; @@ -1175,7 +1175,7 @@ nm_os_kthread_start(struct nm_kthread *nmk) /* enable kthread main loop */ nmk->run = 1; /* create kthread */ - if((error = kthread_add(nm_kthread_worker, nmk, p, + if((error = kthread_add(nm_kctx_worker, nmk, p, &nmk->worker, RFNOWAIT /* to be checked */, 0, "nm-kthread-%ld", nmk->worker_ctx.type))) { goto err; @@ -1191,7 +1191,7 @@ nm_os_kthread_start(struct nm_kthread *nmk) } void -nm_os_kthread_stop(struct nm_kthread *nmk) +nm_os_kctx_worker_stop(struct nm_kctx *nmk) { if (!nmk->worker) { return; @@ -1201,18 +1201,18 @@ nm_os_kthread_stop(struct nm_kthread *nmk) /* wake up kthread if it sleeps */ kthread_resume(nmk->worker); - nm_os_kthread_wakeup_worker(nmk); + nm_os_kctx_worker_wakeup(nmk); nmk->worker = NULL; } void -nm_os_kthread_delete(struct nm_kthread *nmk) +nm_os_kctx_destroy(struct nm_kctx *nmk) { if (!nmk) return; if (nmk->worker) { - nm_os_kthread_stop(nmk); + nm_os_kctx_worker_stop(nmk); } memset(&nmk->worker_ctx.cfg, 0, sizeof(nmk->worker_ctx.cfg)); diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 6697fc8bf..2b3b18011 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -2039,26 +2039,26 @@ void nm_os_vi_init_index(void); /* * kernel thread routines */ -struct nm_kthread; /* OS-specific kthread - opaque */ -typedef void (*nm_kthread_worker_fn_t)(void *data); +struct nm_kctx; /* OS-specific kernel context - opaque */ +typedef void (*nm_kctx_worker_fn_t)(void *data); /* kthread configuration */ -struct nm_kthread_cfg { +struct nm_kctx_cfg { long type; /* kthread type/identifier */ - nm_kthread_worker_fn_t worker_fn; /* worker function */ + nm_kctx_worker_fn_t worker_fn; /* worker function */ void *worker_private;/* worker parameter */ int attach_user; /* attach kthread to user process */ }; /* kthread configuration */ -struct nm_kthread *nm_os_kthread_create(struct nm_kthread_cfg *cfg, +struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, void *opaque); -int nm_os_kthread_start(struct nm_kthread *); -void nm_os_kthread_stop(struct nm_kthread *); -void nm_os_kthread_delete(struct nm_kthread *); -void nm_os_kthread_wakeup_worker(struct nm_kthread *nmk); -void nm_os_kthread_send_irq(struct nm_kthread *); -void nm_os_kthread_set_affinity(struct nm_kthread *, int); +int nm_os_kctx_worker_start(struct nm_kctx *); +void nm_os_kctx_worker_stop(struct nm_kctx *); +void nm_os_kctx_destroy(struct nm_kctx *); +void nm_os_kctx_worker_wakeup(struct nm_kctx *nmk); +void nm_os_kctx_send_irq(struct nm_kctx *); +void nm_os_kctx_worker_setaff(struct nm_kctx *, int); u_int nm_os_ncpus(void); #ifdef WITH_PTNETMAP_HOST diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index e4d8e7f95..4ee8e93e0 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -170,7 +170,7 @@ rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail, struct ptnetmap_state { /* Kthreads. */ - struct nm_kthread **kthreads; + struct nm_kctx **kctxs; /* Shared memory with the guest (TX/RX) */ struct ptnet_ring __user *ptrings; @@ -234,7 +234,7 @@ ptnetmap_tx_handler(void *data) struct ptnet_ring __user *ptring; struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */ bool more_txspace = false; - struct nm_kthread *kth; + struct nm_kctx *kth; uint32_t num_slots; int batch; IFRATE(uint32_t pre_tail); @@ -259,7 +259,7 @@ ptnetmap_tx_handler(void *data) /* Get TX ptring pointer from the CSB. */ ptring = ptns->ptrings + kring->ring_id; - kth = ptns->kthreads[kring->ring_id]; + kth = ptns->kctxs[kring->ring_id]; num_slots = kring->nkr_num_slots; shadow_ring.head = kring->rhead; @@ -340,7 +340,7 @@ ptnetmap_tx_handler(void *data) if (more_txspace && ptring_intr_enabled(ptring)) { /* Disable guest kick to avoid sending unnecessary kicks */ ptring_intr_enable(ptring, 0); - nm_os_kthread_send_irq(kth); + nm_os_kctx_send_irq(kth); IFRATE(ptns->rate_ctx.new.htxk++); more_txspace = false; } @@ -385,7 +385,7 @@ ptnetmap_tx_handler(void *data) if (more_txspace && ptring_intr_enabled(ptring)) { ptring_intr_enable(ptring, 0); - nm_os_kthread_send_irq(kth); + nm_os_kctx_send_irq(kth); IFRATE(ptns->rate_ctx.new.htxk++); } } @@ -413,7 +413,7 @@ ptnetmap_rx_handler(void *data) struct ptnetmap_state *ptns = pth_na->ptns; struct ptnet_ring __user *ptring; struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */ - struct nm_kthread *kth; + struct nm_kctx *kth; uint32_t num_slots; int dry_cycles = 0; bool some_recvd = false; @@ -440,7 +440,7 @@ ptnetmap_rx_handler(void *data) /* Get RX ptring pointer from the CSB. */ ptring = ptns->ptrings + (pth_na->up.num_tx_rings + kring->ring_id); - kth = ptns->kthreads[pth_na->up.num_tx_rings + kring->ring_id]; + kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id]; num_slots = kring->nkr_num_slots; shadow_ring.head = kring->rhead; @@ -500,7 +500,7 @@ ptnetmap_rx_handler(void *data) if (some_recvd && ptring_intr_enabled(ptring)) { /* Disable guest kick to avoid sending unnecessary kicks */ ptring_intr_enable(ptring, 0); - nm_os_kthread_send_irq(kth); + nm_os_kctx_send_irq(kth); IFRATE(ptns->rate_ctx.new.hrxk++); some_recvd = false; } @@ -549,7 +549,7 @@ ptnetmap_rx_handler(void *data) /* Interrupt the guest if needed. */ if (some_recvd && ptring_intr_enabled(ptring)) { ptring_intr_enable(ptring, 0); - nm_os_kthread_send_irq(kth); + nm_os_kctx_send_irq(kth); IFRATE(ptns->rate_ctx.new.hrxk++); } } @@ -643,15 +643,15 @@ ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na) } /* - * Functions to create, start and stop the kthreads + * Functions to create kernel contexts, and start/stop the workers. */ static int -ptnetmap_create_kthreads(struct netmap_pt_host_adapter *pth_na, - struct ptnetmap_cfg *cfg) +ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na, + struct ptnetmap_cfg *cfg) { struct ptnetmap_state *ptns = pth_na->ptns; - struct nm_kthread_cfg nmk_cfg; + struct nm_kctx_cfg nmk_cfg; unsigned int num_rings; uint8_t *cfg_entries = (uint8_t *)(cfg + 1); int k; @@ -669,9 +669,9 @@ ptnetmap_create_kthreads(struct netmap_pt_host_adapter *pth_na, nmk_cfg.worker_fn = ptnetmap_rx_handler; } - ptns->kthreads[k] = nm_os_kthread_create(&nmk_cfg, + ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg, cfg->cfgtype, cfg_entries + k * cfg->entry_size); - if (ptns->kthreads[k] == NULL) { + if (ptns->kctxs[k] == NULL) { goto err; } } @@ -679,16 +679,16 @@ ptnetmap_create_kthreads(struct netmap_pt_host_adapter *pth_na, return 0; err: for (k = 0; k < num_rings; k++) { - if (ptns->kthreads[k]) { - nm_os_kthread_delete(ptns->kthreads[k]); - ptns->kthreads[k] = NULL; + if (ptns->kctxs[k]) { + nm_os_kctx_destroy(ptns->kctxs[k]); + ptns->kctxs[k] = NULL; } } return EFAULT; } static int -ptnetmap_start_kthreads(struct netmap_pt_host_adapter *pth_na) +ptnetmap_start_kctx_workers(struct netmap_pt_host_adapter *pth_na) { struct ptnetmap_state *ptns = pth_na->ptns; int num_rings; @@ -705,8 +705,8 @@ ptnetmap_start_kthreads(struct netmap_pt_host_adapter *pth_na) num_rings = ptns->pth_na->up.num_tx_rings + ptns->pth_na->up.num_rx_rings; for (k = 0; k < num_rings; k++) { - //nm_os_kthread_set_affinity(ptns->kthreads[k], xxx); - error = nm_os_kthread_start(ptns->kthreads[k]); + //nm_os_kctx_worker_setaff(ptns->kctxs[k], xxx); + error = nm_os_kctx_worker_start(ptns->kctxs[k]); if (error) { return error; } @@ -716,7 +716,7 @@ ptnetmap_start_kthreads(struct netmap_pt_host_adapter *pth_na) } static void -ptnetmap_stop_kthreads(struct netmap_pt_host_adapter *pth_na) +ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na) { struct ptnetmap_state *ptns = pth_na->ptns; int num_rings; @@ -732,7 +732,7 @@ ptnetmap_stop_kthreads(struct netmap_pt_host_adapter *pth_na) num_rings = ptns->pth_na->up.num_tx_rings + ptns->pth_na->up.num_rx_rings; for (k = 0; k < num_rings; k++) { - nm_os_kthread_stop(ptns->kthreads[k]); + nm_os_kctx_worker_stop(ptns->kctxs[k]); } } @@ -790,12 +790,12 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na, return EINVAL; } - ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kthreads)); + ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kctxs)); if (!ptns) { return ENOMEM; } - ptns->kthreads = (struct nm_kthread **)(ptns + 1); + ptns->kctxs = (struct nm_kctx **)(ptns + 1); ptns->stopped = true; /* Cross-link data structures. */ @@ -807,9 +807,9 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na, DBG(ptnetmap_print_configuration(cfg)); - /* Create kthreads */ - if ((ret = ptnetmap_create_kthreads(pth_na, cfg))) { - D("ERROR ptnetmap_create_kthreads()"); + /* Create kernel contexts. */ + if ((ret = ptnetmap_create_kctxs(pth_na, cfg))) { + D("ERROR ptnetmap_create_kctxs()"); goto err; } /* Copy krings state into the CSB for the guest initialization */ @@ -881,12 +881,12 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na) pth_na->up.tx_rings[i].save_notify = NULL; } - /* Delete kthreads. */ + /* Destroy kernel contexts. */ num_rings = ptns->pth_na->up.num_tx_rings + ptns->pth_na->up.num_rx_rings; for (i = 0; i < num_rings; i++) { - nm_os_kthread_delete(ptns->kthreads[i]); - ptns->kthreads[i] = NULL; + nm_os_kctx_destroy(ptns->kctxs[i]); + ptns->kctxs[i] = NULL; } IFRATE(del_timer(&ptns->rate_ctx.timer)); @@ -931,21 +931,21 @@ ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na) cfg = ptnetmap_read_cfg(nmr); if (!cfg) break; - /* Create ptnetmap state (kthreads, ...) and switch parent + /* Create ptnetmap state (kctxs, ...) and switch parent * adapter to ptnetmap mode. */ error = ptnetmap_create(pth_na, cfg); nm_os_free(cfg); if (error) break; /* Start kthreads. */ - error = ptnetmap_start_kthreads(pth_na); + error = ptnetmap_start_kctx_workers(pth_na); if (error) ptnetmap_delete(pth_na); break; case NETMAP_PT_HOST_DELETE: /* Stop kthreads. */ - ptnetmap_stop_kthreads(pth_na); + ptnetmap_stop_kctx_workers(pth_na); /* Switch parent adapter back to normal mode and destroy * ptnetmap state (kthreads, ...). */ ptnetmap_delete(pth_na); @@ -993,7 +993,7 @@ nm_pt_host_notify(struct netmap_kring *kring, int flags) ND(1, "RX backend irq"); IFRATE(ptns->rate_ctx.new.brxwu++); } - nm_os_kthread_wakeup_worker(ptns->kthreads[k]); + nm_os_kctx_worker_wakeup(ptns->kctxs[k]); return NM_IRQ_COMPLETED; } @@ -1135,7 +1135,7 @@ nm_pt_host_dtor(struct netmap_adapter *na) /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor * didn't do it. */ - ptnetmap_stop_kthreads(pth_na); + ptnetmap_stop_kctx_workers(pth_na); ptnetmap_delete(pth_na); parent->na_flags &= ~NAF_BUSY; diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index d8a252f8d..130b082f0 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -925,7 +925,7 @@ nm_bdg_ctl_detach(struct nmreq *nmr) struct nm_bdg_polling_state; struct nm_bdg_kthread { - struct nm_kthread *nmk; + struct nm_kctx *nmk; u_int qfirst; u_int qlast; struct nm_bdg_polling_state *bps; @@ -967,7 +967,7 @@ netmap_bwrap_polling(void *data) static int nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) { - struct nm_kthread_cfg kcfg; + struct nm_kctx_cfg kcfg; int i, j; bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus); @@ -989,24 +989,24 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) kcfg.type = i; kcfg.worker_private = t; - t->nmk = nm_os_kthread_create(&kcfg, 0, NULL); + t->nmk = nm_os_kctx_create(&kcfg, 0, NULL); if (t->nmk == NULL) { goto cleanup; } - nm_os_kthread_set_affinity(t->nmk, affinity); + nm_os_kctx_worker_setaff(t->nmk, affinity); } return 0; cleanup: for (j = 0; j < i; j++) { struct nm_bdg_kthread *t = bps->kthreads + i; - nm_os_kthread_delete(t->nmk); + nm_os_kctx_destroy(t->nmk); } nm_os_free(bps->kthreads); return EFAULT; } -/* a version of ptnetmap_start_kthreads() */ +/* A variant of ptnetmap_start_kthreads() */ static int nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) { @@ -1020,7 +1020,7 @@ nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) for (i = 0; i < bps->ncpus; i++) { struct nm_bdg_kthread *t = bps->kthreads + i; - error = nm_os_kthread_start(t->nmk); + error = nm_os_kctx_worker_start(t->nmk); if (error) { D("error in nm_kthread_start()"); goto cleanup; @@ -1031,7 +1031,7 @@ nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) cleanup: for (j = 0; j < i; j++) { struct nm_bdg_kthread *t = bps->kthreads + i; - nm_os_kthread_stop(t->nmk); + nm_os_kctx_worker_stop(t->nmk); } bps->stopped = true; return error; @@ -1047,8 +1047,8 @@ nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps) for (i = 0; i < bps->ncpus; i++) { struct nm_bdg_kthread *t = bps->kthreads + i; - nm_os_kthread_stop(t->nmk); - nm_os_kthread_delete(t->nmk); + nm_os_kctx_worker_stop(t->nmk); + nm_os_kctx_destroy(t->nmk); } bps->stopped = true; } From 2c74af356f3eebe2863b5a088b431a2f21f941d1 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 17:06:26 +0200 Subject: [PATCH 0081/2207] ptnetmap: add use_kthread parameter to kctx configuration --- sys/dev/netmap/netmap_kern.h | 9 +++++---- sys/dev/netmap/netmap_pt.c | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 2b3b18011..a5e823f57 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -2044,10 +2044,11 @@ typedef void (*nm_kctx_worker_fn_t)(void *data); /* kthread configuration */ struct nm_kctx_cfg { - long type; /* kthread type/identifier */ - nm_kctx_worker_fn_t worker_fn; /* worker function */ - void *worker_private;/* worker parameter */ - int attach_user; /* attach kthread to user process */ + long type; /* kthread type/identifier */ + nm_kctx_worker_fn_t worker_fn; /* worker function */ + void *worker_private;/* worker parameter */ + int attach_user; /* attach kthread to user process */ + int use_kthread; /* use a kthread for the context */ }; /* kthread configuration */ struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg, diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 4ee8e93e0..4b73e9adc 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -650,6 +650,7 @@ static int ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na, struct ptnetmap_cfg *cfg) { + int use_tx_kthreads = ptnetmap_worker; /* snapshot */ struct ptnetmap_state *ptns = pth_na->ptns; struct nm_kctx_cfg nmk_cfg; unsigned int num_rings; @@ -665,8 +666,10 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na, nmk_cfg.type = k; if (k < pth_na->up.num_tx_rings) { nmk_cfg.worker_fn = ptnetmap_tx_handler; + nmk_cfg.use_kthread = use_tx_kthreads; } else { nmk_cfg.worker_fn = ptnetmap_rx_handler; + nmk_cfg.use_kthread = 1; } ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg, From 5033cd0b566448bf21c869e150bd93fa6970a661 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 17:25:21 +0200 Subject: [PATCH 0082/2207] linux: fix indentation for ptnetmap code --- LINUX/netmap_linux.c | 638 ++++++++++++++++++++++--------------------- 1 file changed, 322 insertions(+), 316 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 3f4f47155..f6fc3b838 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1271,222 +1271,228 @@ nm_os_ncpus(void) } struct nm_kctx { - struct mm_struct *mm; /* to access guest memory */ - struct task_struct *worker; /* the kernel thread */ + struct mm_struct *mm; /* to access guest memory */ + struct task_struct *worker; /* the kernel thread */ - atomic_t scheduled; /* pending wake_up request */ - int attach_user; /* kthread attached to user_process */ + atomic_t scheduled; /* pending wake_up request */ + int attach_user; /* kthread attached to user_process */ - int affinity; + int affinity; - /* files to exchange notifications */ - struct file *ioevent_file; /* notification from guest */ - struct file *irq_file; /* notification to guest (interrupt) */ - struct eventfd_ctx *irq_ctx; + /* files to exchange notifications */ + struct file *ioevent_file; /* notification from guest */ + struct file *irq_file; /* notification to guest (interrupt) */ + struct eventfd_ctx *irq_ctx; - /* poll ioeventfd to receive notification from the guest */ - poll_table poll_table; - wait_queue_head_t *waitq_head; - wait_queue_t waitq; + /* poll ioeventfd to receive notification from the guest */ + poll_table poll_table; + wait_queue_head_t *waitq_head; + wait_queue_t waitq; - /* worker function and parameter */ - nm_kctx_worker_fn_t worker_fn; - void *worker_private; + /* worker function and parameter */ + nm_kctx_worker_fn_t worker_fn; + void *worker_private; - /* integer to manage multiple worker contexts */ - long type; + /* integer to manage multiple worker contexts */ + long type; }; void inline nm_os_kctx_worker_wakeup(struct nm_kctx *nmk) { - /* - * There may be a race between FE and BE, - * which call both this function, and worker kthread, - * that reads ptk->scheduled. - * - * For us it is not important the counter value, - * but simply that it has changed since the last - * time the kthread saw it. - */ - atomic_inc(&nmk->scheduled); - wake_up_process(nmk->worker); + /* + * There may be a race between FE and BE, + * which call both this function, and worker kthread, + * that reads ptk->scheduled. + * + * For us it is not important the counter value, + * but simply that it has changed since the last + * time the kthread saw it. + */ + atomic_inc(&nmk->scheduled); + wake_up_process(nmk->worker); } static void nm_kctx_poll_fn(struct file *file, wait_queue_head_t *wq_head, poll_table *pt) { - struct nm_kctx *nmk; + struct nm_kctx *nmk; - nmk = container_of(pt, struct nm_kctx, poll_table); - nmk->waitq_head = wq_head; - add_wait_queue(wq_head, &nmk->waitq); + nmk = container_of(pt, struct nm_kctx, poll_table); + nmk->waitq_head = wq_head; + add_wait_queue(wq_head, &nmk->waitq); } static int nm_kctx_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key) { - struct nm_kctx *nmk; + struct nm_kctx *nmk; - nmk = container_of(wq, struct nm_kctx, waitq); - nm_os_kctx_worker_wakeup(nmk); + nmk = container_of(wq, struct nm_kctx, waitq); + nm_os_kctx_worker_wakeup(nmk); - return 0; + return 0; } static void inline nm_kctx_worker_fn(struct nm_kctx *nmk) { - __set_current_state(TASK_RUNNING); - nmk->worker_fn(nmk->worker_private); /* run payload */ - if (need_resched()) - schedule(); + __set_current_state(TASK_RUNNING); + nmk->worker_fn(nmk->worker_private); /* run payload */ + if (need_resched()) + schedule(); } static int nm_kctx_worker(void *data) { - struct nm_kctx *nmk = data; - int old_scheduled = atomic_read(&nmk->scheduled); - int new_scheduled = old_scheduled; - mm_segment_t oldfs = get_fs(); + struct nm_kctx *nmk = data; + int old_scheduled = atomic_read(&nmk->scheduled); + int new_scheduled = old_scheduled; + mm_segment_t oldfs = get_fs(); - if (nmk->mm) { - set_fs(USER_DS); - use_mm(nmk->mm); - } + if (nmk->mm) { + set_fs(USER_DS); + use_mm(nmk->mm); + } - while (!kthread_should_stop()) { - if (!nmk->ioevent_file) { - /* - * if ioevent_file is not defined, we don't have notification - * mechanism and we continually execute worker_fn() - */ - nm_kctx_worker_fn(nmk); - - } else { - /* - * Set INTERRUPTIBLE state before to check if there is work. - * if wake_up() is called, although we have not seen the new - * counter value, the kthread state is set to RUNNING and - * after schedule() it is not moved off run queue. - */ - set_current_state(TASK_INTERRUPTIBLE); - - new_scheduled = atomic_read(&nmk->scheduled); - - /* check if there is a pending notification */ - if (likely(new_scheduled != old_scheduled)) { - old_scheduled = new_scheduled; - nm_kctx_worker_fn(nmk); - } else { - schedule(); - } - } - } + while (!kthread_should_stop()) { + if (!nmk->ioevent_file) { + /* + * if ioevent_file is not defined, we don't have + * notification mechanism and we continually + * execute worker_fn() + */ + nm_kctx_worker_fn(nmk); + + } else { + /* + * Set INTERRUPTIBLE state before to check if there + * is work. If wake_up() is called, although we have + * not seen the new counter value, the kthread state + * is set to RUNNING and after schedule() it is not + * moved off run queue. + */ + set_current_state(TASK_INTERRUPTIBLE); + + new_scheduled = atomic_read(&nmk->scheduled); + + /* check if there is a pending notification */ + if (likely(new_scheduled != old_scheduled)) { + old_scheduled = new_scheduled; + nm_kctx_worker_fn(nmk); + } else { + schedule(); + } + } + } - __set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); - if (nmk->mm) { - unuse_mm(nmk->mm); - } + if (nmk->mm) { + unuse_mm(nmk->mm); + } - set_fs(oldfs); - return 0; + set_fs(oldfs); + return 0; } void inline nm_os_kctx_send_irq(struct nm_kctx *nmk) { - if (nmk->irq_ctx) - eventfd_signal(nmk->irq_ctx, 1); + if (nmk->irq_ctx) { + eventfd_signal(nmk->irq_ctx, 1); + } } static void nm_kctx_close_files(struct nm_kctx *nmk) { - if (nmk->ioevent_file) { - fput(nmk->ioevent_file); - nmk->ioevent_file = NULL; - } + if (nmk->ioevent_file) { + fput(nmk->ioevent_file); + nmk->ioevent_file = NULL; + } - if (nmk->irq_file) { - fput(nmk->irq_file); - nmk->irq_file = NULL; - eventfd_ctx_put(nmk->irq_ctx); - nmk->irq_ctx = NULL; - } + if (nmk->irq_file) { + fput(nmk->irq_file); + nmk->irq_file = NULL; + eventfd_ctx_put(nmk->irq_ctx); + nmk->irq_ctx = NULL; + } } static int nm_kctx_open_files(struct nm_kctx *nmk, void *opaque) { - struct file *file; - struct ptnetmap_cfgentry_qemu *ring_cfg = opaque; + struct file *file; + struct ptnetmap_cfgentry_qemu *ring_cfg = opaque; - nmk->ioevent_file = NULL; - nmk->irq_file = NULL; + nmk->ioevent_file = NULL; + nmk->irq_file = NULL; - if (!opaque) { - return 0; - } + if (!opaque) { + return 0; + } - if (ring_cfg->ioeventfd) { - file = eventfd_fget(ring_cfg->ioeventfd); - if (IS_ERR(file)) - goto err; - nmk->ioevent_file = file; - } + if (ring_cfg->ioeventfd) { + file = eventfd_fget(ring_cfg->ioeventfd); + if (IS_ERR(file)) + goto err; + nmk->ioevent_file = file; + } - if (ring_cfg->irqfd) { - file = eventfd_fget(ring_cfg->irqfd); - if (IS_ERR(file)) - goto err; - nmk->irq_file = file; - nmk->irq_ctx = eventfd_ctx_fileget(file); - } + if (ring_cfg->irqfd) { + file = eventfd_fget(ring_cfg->irqfd); + if (IS_ERR(file)) + goto err; + nmk->irq_file = file; + nmk->irq_ctx = eventfd_ctx_fileget(file); + } - return 0; + return 0; err: - nm_kctx_close_files(nmk); - return -PTR_ERR(file); + nm_kctx_close_files(nmk); + return -PTR_ERR(file); } static void nm_kctx_init_poll(struct nm_kctx *nmk) { - init_waitqueue_func_entry(&nmk->waitq, nm_kctx_poll_wakeup); - init_poll_funcptr(&nmk->poll_table, nm_kctx_poll_fn); + init_waitqueue_func_entry(&nmk->waitq, nm_kctx_poll_wakeup); + init_poll_funcptr(&nmk->poll_table, nm_kctx_poll_fn); } static int nm_kctx_start_poll(struct nm_kctx *nmk) { - unsigned long mask; - int ret = 0; + unsigned long mask; + int ret = 0; - if (nmk->waitq_head) - return 0; - mask = nmk->ioevent_file->f_op->poll(nmk->ioevent_file, &nmk->poll_table); - if (mask) - nm_kctx_poll_wakeup(&nmk->waitq, 0, 0, (void *)mask); - if (mask & POLLERR) { - if (nmk->waitq_head) - remove_wait_queue(nmk->waitq_head, &nmk->waitq); - ret = EINVAL; - } - return ret; + if (nmk->waitq_head) + return 0; + + mask = nmk->ioevent_file->f_op->poll(nmk->ioevent_file, + &nmk->poll_table); + if (mask) + nm_kctx_poll_wakeup(&nmk->waitq, 0, 0, (void *)mask); + if (mask & POLLERR) { + if (nmk->waitq_head) + remove_wait_queue(nmk->waitq_head, &nmk->waitq); + ret = EINVAL; + } + + return ret; } static void nm_kctx_stop_poll(struct nm_kctx *nmk) { - if (nmk->waitq_head) { - remove_wait_queue(nmk->waitq_head, &nmk->waitq); - nmk->waitq_head = NULL; - } + if (nmk->waitq_head) { + remove_wait_queue(nmk->waitq_head, &nmk->waitq); + nmk->waitq_head = NULL; + } } void @@ -1499,116 +1505,116 @@ struct nm_kctx * nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, void *opaque) { - struct nm_kctx *nmk = NULL; - int error; + struct nm_kctx *nmk = NULL; + int error; - if (cfgtype != PTNETMAP_CFGTYPE_QEMU) { - D("Unsupported cfgtype %u", cfgtype); - return NULL; - } + if (cfgtype != PTNETMAP_CFGTYPE_QEMU) { + D("Unsupported cfgtype %u", cfgtype); + return NULL; + } - nmk = kzalloc(sizeof *nmk, GFP_KERNEL); - if (!nmk) - return NULL; + nmk = kzalloc(sizeof *nmk, GFP_KERNEL); + if (!nmk) + return NULL; - nmk->worker_fn = cfg->worker_fn; - nmk->worker_private = cfg->worker_private; - nmk->type = cfg->type; - atomic_set(&nmk->scheduled, 0); + nmk->worker_fn = cfg->worker_fn; + nmk->worker_private = cfg->worker_private; + nmk->type = cfg->type; + atomic_set(&nmk->scheduled, 0); - /* attach kthread to user process (ptnetmap) */ - nmk->attach_user = cfg->attach_user; + /* attach kthread to user process (ptnetmap) */ + nmk->attach_user = cfg->attach_user; - /* open event fds */ - error = nm_kctx_open_files(nmk, opaque); - if (error) - goto err; + /* open event fds */ + error = nm_kctx_open_files(nmk, opaque); + if (error) + goto err; - nm_kctx_init_poll(nmk); + nm_kctx_init_poll(nmk); - return nmk; + return nmk; err: - //XXX: set errno? - kfree(nmk); - return NULL; + kfree(nmk); + return NULL; } int nm_os_kctx_worker_start(struct nm_kctx *nmk) { - int error = 0; - char name[16]; + int error = 0; + char name[16]; - if (nmk->worker) { - return EBUSY; - } + if (nmk->worker) { + return EBUSY; + } - /* check if we want to attach kthread to user process */ - if (nmk->attach_user) { - nmk->mm = get_task_mm(current); - } + /* check if we want to attach kthread to user process */ + if (nmk->attach_user) { + nmk->mm = get_task_mm(current); + } - snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, nmk->type); - nmk->worker = kthread_create(nm_kctx_worker, nmk, name); - if (IS_ERR(nmk->worker)) { - error = -PTR_ERR(nmk->worker); - goto err; - } + snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, nmk->type); + nmk->worker = kthread_create(nm_kctx_worker, nmk, name); + if (IS_ERR(nmk->worker)) { + error = -PTR_ERR(nmk->worker); + goto err; + } - kthread_bind(nmk->worker, nmk->affinity); - wake_up_process(nmk->worker); + kthread_bind(nmk->worker, nmk->affinity); + wake_up_process(nmk->worker); - if (nmk->ioevent_file) { - error = nm_kctx_start_poll(nmk); - if (error) { - goto err_kstop; + if (nmk->ioevent_file) { + error = nm_kctx_start_poll(nmk); + if (error) { + goto err_kstop; + } } - } - return 0; + return 0; + err_kstop: - kthread_stop(nmk->worker); + kthread_stop(nmk->worker); err: - nmk->worker = NULL; - if (nmk->mm) - mmput(nmk->mm); - nmk->mm = NULL; - return error; + nmk->worker = NULL; + if (nmk->mm) + mmput(nmk->mm); + nmk->mm = NULL; + return error; } void nm_os_kctx_worker_stop(struct nm_kctx *nmk) { - if (!nmk->worker) { - return; - } + if (!nmk->worker) { + return; + } - nm_kctx_stop_poll(nmk); + nm_kctx_stop_poll(nmk); - if (nmk->worker) { - kthread_stop(nmk->worker); - nmk->worker = NULL; - } + if (nmk->worker) { + kthread_stop(nmk->worker); + nmk->worker = NULL; + } - if (nmk->mm) { - mmput(nmk->mm); - nmk->mm = NULL; - } + if (nmk->mm) { + mmput(nmk->mm); + nmk->mm = NULL; + } } void nm_os_kctx_destroy(struct nm_kctx *nmk) { - if (!nmk) - return; + if (!nmk) + return; - if (nmk->worker) { - nm_os_kctx_worker_stop(nmk); - } + if (nmk->worker) { + nm_os_kctx_worker_stop(nmk); + } - nm_kctx_close_files(nmk); + nm_kctx_close_files(nmk); - kfree(nmk); + kfree(nmk); } /* ##################### PTNETMAP SUPPORT ##################### */ @@ -1642,11 +1648,11 @@ MODULE_DEVICE_TABLE(pci, ptnetmap_guest_device_table); */ struct ptnetmap_memdev { - struct pci_dev *pdev; - void __iomem *pci_io; - void __iomem *pci_mem; - struct netmap_mem_d *nm_mem; - int bars; + struct pci_dev *pdev; + void __iomem *pci_io; + void __iomem *pci_mem; + struct netmap_mem_d *nm_mem; + int bars; }; /* @@ -1659,29 +1665,29 @@ int nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr, void **nm_addr, uint64_t *mem_size) { - struct pci_dev *pdev = ptn_dev->pdev; - phys_addr_t mem_paddr; - int err = 0; - - *mem_size = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMSIZE_HI); - *mem_size = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMSIZE_LO) | - (*mem_size << 32); - - D("=== BAR %d start %llx len %llx mem_size %lx ===", - PTNETMAP_MEM_PCI_BAR, - pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR), - pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR), - (unsigned long)(*mem_size)); - - /* map memory allocator */ - mem_paddr = pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR); - ptn_dev->pci_mem = *nm_addr = ioremap_cache(mem_paddr, *mem_size); - if (ptn_dev->pci_mem == NULL) { - err = -ENOMEM; - } - *nm_paddr = mem_paddr; + struct pci_dev *pdev = ptn_dev->pdev; + phys_addr_t mem_paddr; + int err = 0; + + *mem_size = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMSIZE_HI); + *mem_size = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMSIZE_LO) | + (*mem_size << 32); + + D("=== BAR %d start %llx len %llx mem_size %lx ===", + PTNETMAP_MEM_PCI_BAR, + pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR), + pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR), + (unsigned long)(*mem_size)); + + /* map memory allocator */ + mem_paddr = pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR); + ptn_dev->pci_mem = *nm_addr = ioremap_cache(mem_paddr, *mem_size); + if (ptn_dev->pci_mem == NULL) { + err = -ENOMEM; + } + *nm_paddr = mem_paddr; - return err; + return err; } uint32_t @@ -1696,10 +1702,10 @@ nm_os_pt_memdev_ioread(struct ptnetmap_memdev *ptn_dev, unsigned int reg) void nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *ptn_dev) { - if (ptn_dev->pci_mem) { - iounmap(ptn_dev->pci_mem); - ptn_dev->pci_mem = NULL; - } + if (ptn_dev->pci_mem) { + iounmap(ptn_dev->pci_mem); + ptn_dev->pci_mem = NULL; + } } /* @@ -1710,63 +1716,62 @@ nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *ptn_dev) static int ptnetmap_guest_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct ptnetmap_memdev *ptn_dev; - int bars, err; - uint16_t mem_id; - - if (id->device == PTNETMAP_PCI_NETIF_ID) { - /* Probe the ptnet device. */ - return ptnet_probe(pdev, id); - } - - /* Probe the memdev device. */ + struct ptnetmap_memdev *ptn_dev; + int bars, err; + uint16_t mem_id; - ptn_dev = kzalloc(sizeof(*ptn_dev), GFP_KERNEL); - if (ptn_dev == NULL) - return -ENOMEM; - - ptn_dev->pdev = pdev; - bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); - /* enable the device */ - err = pci_enable_device(pdev); /* XXX-ste: device_mem() */ - if (err) - goto err; + if (id->device == PTNETMAP_PCI_NETIF_ID) { + /* Probe the ptnet device. */ + return ptnet_probe(pdev, id); + } - err = pci_request_selected_regions(pdev, bars, PTNETMAP_MEMDEV_NAME); - if (err) - goto err_pci_reg; + /* Probe the memdev device. */ + ptn_dev = kzalloc(sizeof(*ptn_dev), GFP_KERNEL); + if (ptn_dev == NULL) + return -ENOMEM; - ptn_dev->pci_io = pci_iomap(pdev, PTNETMAP_IO_PCI_BAR, 0); - if (ptn_dev->pci_io == NULL) { - err = -ENOMEM; - goto err_iomap; - } - pci_set_drvdata(pdev, ptn_dev); - pci_set_master(pdev); /* XXX-ste: is needed??? */ + ptn_dev->pdev = pdev; + bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); + /* enable the device */ + err = pci_enable_device(pdev); + if (err) + goto err; + + err = pci_request_selected_regions(pdev, bars, PTNETMAP_MEMDEV_NAME); + if (err) + goto err_pci_reg; + + ptn_dev->pci_io = pci_iomap(pdev, PTNETMAP_IO_PCI_BAR, 0); + if (ptn_dev->pci_io == NULL) { + err = -ENOMEM; + goto err_iomap; + } + pci_set_drvdata(pdev, ptn_dev); + pci_set_master(pdev); /* XXX probably not needed */ - ptn_dev->bars = bars; - mem_id = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMID); + ptn_dev->bars = bars; + mem_id = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMID); - /* create guest allocator */ - ptn_dev->nm_mem = netmap_mem_pt_guest_attach(ptn_dev, mem_id); - if (ptn_dev->nm_mem == NULL) { - err = -ENOMEM; - goto err_nmd_attach; - } - netmap_mem_get(ptn_dev->nm_mem); + /* create guest allocator */ + ptn_dev->nm_mem = netmap_mem_pt_guest_attach(ptn_dev, mem_id); + if (ptn_dev->nm_mem == NULL) { + err = -ENOMEM; + goto err_nmd_attach; + } + netmap_mem_get(ptn_dev->nm_mem); - return 0; + return 0; err_nmd_attach: - pci_set_drvdata(pdev, NULL); - iounmap(ptn_dev->pci_io); + pci_set_drvdata(pdev, NULL); + iounmap(ptn_dev->pci_io); err_iomap: - pci_release_selected_regions(pdev, bars); + pci_release_selected_regions(pdev, bars); err_pci_reg: - pci_disable_device(pdev); + pci_disable_device(pdev); err: - kfree(ptn_dev); - return err; + kfree(ptn_dev); + return err; } /* @@ -1775,35 +1780,35 @@ ptnetmap_guest_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void ptnetmap_guest_remove(struct pci_dev *pdev) { - struct ptnetmap_memdev *ptn_dev = pci_get_drvdata(pdev); + struct ptnetmap_memdev *ptn_dev = pci_get_drvdata(pdev); - if (pdev->device == PTNETMAP_PCI_NETIF_ID) { - /* Remove the ptnet device. */ - return ptnet_remove(pdev); - } + if (pdev->device == PTNETMAP_PCI_NETIF_ID) { + /* Remove the ptnet device. */ + return ptnet_remove(pdev); + } - /* Remove the memdev device. */ + /* Remove the memdev device. */ - if (ptn_dev->nm_mem) { - netmap_mem_put(ptn_dev->nm_mem); - ptn_dev->nm_mem = NULL; - } - nm_os_pt_memdev_iounmap(ptn_dev); - pci_set_drvdata(pdev, NULL); - iounmap(ptn_dev->pci_io); - pci_release_selected_regions(pdev, ptn_dev->bars); - pci_disable_device(pdev); - kfree(ptn_dev); + if (ptn_dev->nm_mem) { + netmap_mem_put(ptn_dev->nm_mem); + ptn_dev->nm_mem = NULL; + } + nm_os_pt_memdev_iounmap(ptn_dev); + pci_set_drvdata(pdev, NULL); + iounmap(ptn_dev->pci_io); + pci_release_selected_regions(pdev, ptn_dev->bars); + pci_disable_device(pdev); + kfree(ptn_dev); } /* * pci driver information */ static struct pci_driver ptnetmap_guest_drivers = { - .name = "ptnetmap-guest-drivers", - .id_table = ptnetmap_guest_device_table, - .probe = ptnetmap_guest_probe, - .remove = ptnetmap_guest_remove, + .name = "ptnetmap-guest-drivers", + .id_table = ptnetmap_guest_device_table, + .probe = ptnetmap_guest_probe, + .remove = ptnetmap_guest_remove, }; /* @@ -1814,15 +1819,16 @@ static struct pci_driver ptnetmap_guest_drivers = { static int ptnetmap_guest_init(void) { - int ret; + int ret; - /* register pci driver */ - ret = pci_register_driver(&ptnetmap_guest_drivers); - if (ret < 0) { - D("Failed to register drivers"); - return ret; - } - return 0; + /* register pci driver */ + ret = pci_register_driver(&ptnetmap_guest_drivers); + if (ret < 0) { + D("Failed to register drivers"); + return ret; + } + + return 0; } /* @@ -1831,8 +1837,8 @@ ptnetmap_guest_init(void) void ptnetmap_guest_fini(void) { - /* unregister pci driver */ - pci_unregister_driver(&ptnetmap_guest_drivers); + /* unregister pci driver */ + pci_unregister_driver(&ptnetmap_guest_drivers); } #else /* !WITH_PTNETMAP_GUEST */ From 47f156ee3b9cfeb2ef242f9aca3a7841a6eff386 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 17:46:22 +0200 Subject: [PATCH 0083/2207] vale: set use_kthread to 1 for polling mode --- sys/dev/netmap/netmap_vale.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index 130b082f0..0160cfab3 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -976,6 +976,7 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) bzero(&kcfg, sizeof(kcfg)); kcfg.worker_fn = netmap_bwrap_polling; + kcfg.use_kthread = 1; for (i = 0; i < bps->ncpus; i++) { struct nm_bdg_kthread *t = bps->kthreads + i; int all = (bps->ncpus == 1 && bps->reg == NR_REG_ALL_NIC); From 3b8034e389cfd207b9cff64e680e8cc79d5540dd Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 17:49:20 +0200 Subject: [PATCH 0084/2207] linux: kctx: check for use_kthread before creating kernel worker --- LINUX/netmap_linux.c | 51 +++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index f6fc3b838..ad18eafb0 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1273,10 +1273,8 @@ nm_os_ncpus(void) struct nm_kctx { struct mm_struct *mm; /* to access guest memory */ struct task_struct *worker; /* the kernel thread */ - atomic_t scheduled; /* pending wake_up request */ int attach_user; /* kthread attached to user_process */ - int affinity; /* files to exchange notifications */ @@ -1295,6 +1293,9 @@ struct nm_kctx { /* integer to manage multiple worker contexts */ long type; + + /* does this kernel context use a kthread ? */ + int use_kthread; }; void inline @@ -1520,9 +1521,8 @@ nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, nmk->worker_fn = cfg->worker_fn; nmk->worker_private = cfg->worker_private; nmk->type = cfg->type; + nmk->use_kthread = cfg->use_kthread; atomic_set(&nmk->scheduled, 0); - - /* attach kthread to user process (ptnetmap) */ nmk->attach_user = cfg->attach_user; /* open event fds */ @@ -1542,53 +1542,56 @@ int nm_os_kctx_worker_start(struct nm_kctx *nmk) { int error = 0; - char name[16]; if (nmk->worker) { return EBUSY; } - /* check if we want to attach kthread to user process */ + /* Get caller's memory mapping if needed. */ if (nmk->attach_user) { nmk->mm = get_task_mm(current); } - snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, nmk->type); - nmk->worker = kthread_create(nm_kctx_worker, nmk, name); - if (IS_ERR(nmk->worker)) { - error = -PTR_ERR(nmk->worker); - goto err; - } + /* Run the context in a kernel thread, if needed. */ + if (nmk->use_kthread) { + char name[16]; - kthread_bind(nmk->worker, nmk->affinity); - wake_up_process(nmk->worker); + snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid, + nmk->type); + nmk->worker = kthread_create(nm_kctx_worker, nmk, name); + if (IS_ERR(nmk->worker)) { + error = -PTR_ERR(nmk->worker); + goto err; + } + + kthread_bind(nmk->worker, nmk->affinity); + wake_up_process(nmk->worker); + } if (nmk->ioevent_file) { error = nm_kctx_start_poll(nmk); if (error) { - goto err_kstop; + goto err; } } return 0; -err_kstop: - kthread_stop(nmk->worker); err: - nmk->worker = NULL; - if (nmk->mm) + if (nmk->worker) { + kthread_stop(nmk->worker); + nmk->worker = NULL; + } + if (nmk->mm) { mmput(nmk->mm); - nmk->mm = NULL; + nmk->mm = NULL; + } return error; } void nm_os_kctx_worker_stop(struct nm_kctx *nmk) { - if (!nmk->worker) { - return; - } - nm_kctx_stop_poll(nmk); if (nmk->worker) { From cf86ab3c66b7c700469cb43b5319f218633dcdd6 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 18:24:37 +0200 Subject: [PATCH 0085/2207] ptnetmap: ptnetmap_kring_dump: fix debug string --- sys/dev/netmap/netmap_pt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 4b73e9adc..e7e4903b3 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -186,11 +186,11 @@ struct ptnetmap_state { static inline void ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring) { - RD(1, "%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d \ - rtail: %d head: %d cur: %d tail: %d", - title, kring->name, kring->nr_hwcur, - kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail, - kring->ring->head, kring->ring->cur, kring->ring->tail); + D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d" + " rtail: %d head: %d cur: %d tail: %d", + title, kring->name, kring->nr_hwcur, + kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail, + kring->ring->head, kring->ring->cur, kring->ring->tail); } /* @@ -597,14 +597,14 @@ ptnetmap_print_configuration(struct ptnetmap_cfg *cfg) static int ptnetmap_kring_snapshot(struct netmap_kring *kring, struct ptnet_ring __user *ptring) { - if(CSB_WRITE(ptring, head, kring->rhead)) + if (CSB_WRITE(ptring, head, kring->rhead)) goto err; - if(CSB_WRITE(ptring, cur, kring->rcur)) + if (CSB_WRITE(ptring, cur, kring->rcur)) goto err; - if(CSB_WRITE(ptring, hwcur, kring->nr_hwcur)) + if (CSB_WRITE(ptring, hwcur, kring->nr_hwcur)) goto err; - if(CSB_WRITE(ptring, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail))) + if (CSB_WRITE(ptring, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail))) goto err; DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);) From 6e7de27e91f597a6b38b16c2c693ab678d67008e Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 18:44:24 +0200 Subject: [PATCH 0086/2207] linux: kctx: add basic support for use_kthread == 0 --- LINUX/netmap_linux.c | 20 ++++++++++++++++++-- sys/dev/netmap/netmap_freebsd.c | 4 ++-- sys/dev/netmap/netmap_kern.h | 2 +- sys/dev/netmap/netmap_pt.c | 8 +++++--- sys/dev/netmap/netmap_vale.c | 2 +- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index ad18eafb0..7fd25627a 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1301,6 +1301,13 @@ struct nm_kctx { void inline nm_os_kctx_worker_wakeup(struct nm_kctx *nmk) { + if (!nmk->worker) { + ND("test.send.interrupt %ld", nmk->type); + /* Propagate notification to the guest. */ + nm_os_kctx_send_irq(nmk); + return; + } + /* * There may be a race between FE and BE, * which call both this function, and worker kthread, @@ -1330,8 +1337,17 @@ nm_kctx_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key) { struct nm_kctx *nmk; + /* We received a kick on the ioevent_file. If there is a worker, + * wake it up, otherwise do the work here. */ + nmk = container_of(wq, struct nm_kctx, waitq); - nm_os_kctx_worker_wakeup(nmk); + if (nmk->worker) { + nm_os_kctx_worker_wakeup(nmk); + } else { + ND("test.run.work.start %ld", nmk->type); + nmk->worker_fn(nmk->worker_private, 0); + ND("test.run.work.end %ld", nmk->type); + } return 0; } @@ -1340,7 +1356,7 @@ static void inline nm_kctx_worker_fn(struct nm_kctx *nmk) { __set_current_state(TASK_RUNNING); - nmk->worker_fn(nmk->worker_private); /* run payload */ + nmk->worker_fn(nmk->worker_private, 1); /* work */ if (need_resched()) schedule(); } diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c index 904afb9e4..66d0637fd 100644 --- a/sys/dev/netmap/netmap_freebsd.c +++ b/sys/dev/netmap/netmap_freebsd.c @@ -1094,7 +1094,7 @@ nm_kctx_worker(void *data) * mechanism and we continually execute worker_fn() */ if (!ctx->cfg.wchan) { - ctx->worker_fn(ctx->worker_private); /* worker body */ + ctx->worker_fn(ctx->worker_private, 1); /* worker body */ } else { /* checks if there is a pending notification */ mtx_lock(&nmk->worker_lock); @@ -1102,7 +1102,7 @@ nm_kctx_worker(void *data) old_scheduled = nmk->scheduled; mtx_unlock(&nmk->worker_lock); - ctx->worker_fn(ctx->worker_private); /* worker body */ + ctx->worker_fn(ctx->worker_private, 1); /* worker body */ continue; } else if (nmk->run) { diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index a5e823f57..ec01e95d2 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -2040,7 +2040,7 @@ void nm_os_vi_init_index(void); * kernel thread routines */ struct nm_kctx; /* OS-specific kernel context - opaque */ -typedef void (*nm_kctx_worker_fn_t)(void *data); +typedef void (*nm_kctx_worker_fn_t)(void *data, int is_kthread); /* kthread configuration */ struct nm_kctx_cfg { diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index e7e4903b3..f61e8e9de 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -225,7 +225,7 @@ ptring_intr_enable(struct ptnet_ring __user *ptring, uint32_t val) /* Handle TX events: from the guest or from the backend */ static void -ptnetmap_tx_handler(void *data) +ptnetmap_tx_handler(void *data, int is_kthread) { struct netmap_kring *kring = data; struct netmap_pt_host_adapter *pth_na = @@ -354,7 +354,9 @@ ptnetmap_tx_handler(void *data) * go to sleep, waiting for a kick from the guest when new * new slots are ready for transmission. */ - usleep_range(1,1); + if (is_kthread) { + usleep_range(1,1); + } /* Reenable notifications. */ ptring_kick_enable(ptring, 1); /* Doublecheck. */ @@ -405,7 +407,7 @@ ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head) /* Handle RX events: from the guest or from the backend */ static void -ptnetmap_rx_handler(void *data) +ptnetmap_rx_handler(void *data, int is_kthread) { struct netmap_kring *kring = data; struct netmap_pt_host_adapter *pth_na = diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index 0160cfab3..1596552ed 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -944,7 +944,7 @@ struct nm_bdg_polling_state { }; static void -netmap_bwrap_polling(void *data) +netmap_bwrap_polling(void *data, int is_kthread) { struct nm_bdg_kthread *nbk = data; struct netmap_bwrap_adapter *bna; From 891f8bdf3a2a563c977e951e3bf86ff9ee4271a5 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 18:57:35 +0200 Subject: [PATCH 0087/2207] ptnetmap: tx_handler: never interrupt when use_thread == 0 --- sys/dev/netmap/netmap_pt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index f61e8e9de..5822e270c 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -337,7 +337,7 @@ ptnetmap_tx_handler(void *data, int is_kthread) #ifndef BUSY_WAIT /* Interrupt the guest if needed. */ - if (more_txspace && ptring_intr_enabled(ptring)) { + if (more_txspace && ptring_intr_enabled(ptring) && is_kthread) { /* Disable guest kick to avoid sending unnecessary kicks */ ptring_intr_enable(ptring, 0); nm_os_kctx_send_irq(kth); @@ -385,7 +385,7 @@ ptnetmap_tx_handler(void *data, int is_kthread) nm_kr_put(kring); - if (more_txspace && ptring_intr_enabled(ptring)) { + if (more_txspace && ptring_intr_enabled(ptring) && is_kthread) { ptring_intr_enable(ptring, 0); nm_os_kctx_send_irq(kth); IFRATE(ptns->rate_ctx.new.htxk++); From cf44bf8bc5abc294b82b2fd6d4f641da784f66b6 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 19:04:27 +0200 Subject: [PATCH 0088/2207] linux: fix debug logs with use_kthread == 0 --- LINUX/netmap_linux.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 7fd25627a..43ba120ae 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1302,7 +1302,7 @@ void inline nm_os_kctx_worker_wakeup(struct nm_kctx *nmk) { if (!nmk->worker) { - ND("test.send.interrupt %ld", nmk->type); + RD(1, "kctx interrupt %ld", nmk->type); /* Propagate notification to the guest. */ nm_os_kctx_send_irq(nmk); return; @@ -1344,9 +1344,7 @@ nm_kctx_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key) if (nmk->worker) { nm_os_kctx_worker_wakeup(nmk); } else { - ND("test.run.work.start %ld", nmk->type); nmk->worker_fn(nmk->worker_private, 0); - ND("test.run.work.end %ld", nmk->type); } return 0; From 3a664c3a74d6a82eec8f4a4052700d3b70938c01 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 28 Apr 2017 19:55:13 +0200 Subject: [PATCH 0089/2207] kctx: add notify function to decide when to propagate interrupt --- LINUX/netmap_linux.c | 14 +++++++++++--- sys/dev/netmap/netmap_kern.h | 2 ++ sys/dev/netmap/netmap_pt.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 43ba120ae..d08b614c3 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -1291,6 +1291,9 @@ struct nm_kctx { nm_kctx_worker_fn_t worker_fn; void *worker_private; + /* notify function, only needed when use_kthread == 0 */ + nm_kctx_notify_fn_t notify_fn; + /* integer to manage multiple worker contexts */ long type; @@ -1302,9 +1305,8 @@ void inline nm_os_kctx_worker_wakeup(struct nm_kctx *nmk) { if (!nmk->worker) { - RD(1, "kctx interrupt %ld", nmk->type); - /* Propagate notification to the guest. */ - nm_os_kctx_send_irq(nmk); + /* Propagate notification to the user. */ + nmk->notify_fn(nmk->worker_private); return; } @@ -1528,12 +1530,18 @@ nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype, return NULL; } + if (!cfg->use_kthread && cfg->notify_fn == NULL) { + D("Error: botify function missing with use_htead == 0"); + return NULL; + } + nmk = kzalloc(sizeof *nmk, GFP_KERNEL); if (!nmk) return NULL; nmk->worker_fn = cfg->worker_fn; nmk->worker_private = cfg->worker_private; + nmk->notify_fn = cfg->notify_fn; nmk->type = cfg->type; nmk->use_kthread = cfg->use_kthread; atomic_set(&nmk->scheduled, 0); diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index ec01e95d2..b09bc5445 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -2041,12 +2041,14 @@ void nm_os_vi_init_index(void); */ struct nm_kctx; /* OS-specific kernel context - opaque */ typedef void (*nm_kctx_worker_fn_t)(void *data, int is_kthread); +typedef void (*nm_kctx_notify_fn_t)(void *data); /* kthread configuration */ struct nm_kctx_cfg { long type; /* kthread type/identifier */ nm_kctx_worker_fn_t worker_fn; /* worker function */ void *worker_private;/* worker parameter */ + nm_kctx_notify_fn_t notify_fn; /* notify function */ int attach_user; /* attach kthread to user process */ int use_kthread; /* use a kthread for the context */ }; diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 5822e270c..3dbbe0592 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -392,6 +392,36 @@ ptnetmap_tx_handler(void *data, int is_kthread) } } +/* Called on backend nm_notify when there is no worker thread. */ +static void +ptnetmap_tx_nothread_notify(void *data) +{ + struct netmap_kring *kring = data; + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)kring->na->na_private; + struct ptnetmap_state *ptns = pth_na->ptns; + struct ptnet_ring __user *ptring; + + if (unlikely(!ptns)) { + D("ERROR ptnetmap state is NULL"); + return; + } + + if (unlikely(ptns->stopped)) { + D("backend netmap is being stopped"); + return; + } + + /* Get TX ptring pointer from the CSB. */ + ptring = ptns->ptrings + kring->ring_id; + if (ptring_intr_enabled(ptring)) { + ptring_intr_enable(ptring, 0); + nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]); + IFRATE(ptns->rate_ctx.new.htxk++); + RD(1, "%s interrupt", kring->name); + } +} + /* * We need RX kicks from the guest when (tail == head-1), where we wait * for the guest to refill. @@ -669,6 +699,7 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na, if (k < pth_na->up.num_tx_rings) { nmk_cfg.worker_fn = ptnetmap_tx_handler; nmk_cfg.use_kthread = use_tx_kthreads; + nmk_cfg.notify_fn = ptnetmap_tx_nothread_notify; } else { nmk_cfg.worker_fn = ptnetmap_rx_handler; nmk_cfg.use_kthread = 1; From 2bfb72fd98f957d499297a31aa6dec8efbdc9ae1 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 2 May 2017 11:13:25 +0200 Subject: [PATCH 0090/2207] linux/config: check for vma arg to page fault handler --- LINUX/configure | 11 +++++++++++ LINUX/netmap_linux.c | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/LINUX/configure b/LINUX/configure index a8d9e3222..bf65b7992 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1360,6 +1360,17 @@ EOF } EOF +# check for fault arguments + add_test 'have FAULT_VMA_ARG' < + + int + dummy(struct vm_operations_struct *ops, + struct vm_area_struct *vma, struct vm_fault *vmf) { + return ops->fault(vma, vmf); + } +EOF + ##################################################### # checks related to drivers # ##################################################### diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 513b9c9ec..3ecd4c448 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -920,8 +920,14 @@ linux_netmap_poll(struct file * file, struct poll_table_struct *pwait) } static int +#ifdef NETMAP_LINUX_HAVE_FAULT_VMA_ARG linux_netmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { +#else +linux_netmap_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; +#endif /* NETMAP_LINUX_HAVE_FAULT_VMA_ARG */ struct netmap_priv_d *priv = vma->vm_private_data; struct netmap_adapter *na = priv->np_na; struct page *page; From 6a02279fa1eb72ca63982149c85c1dff1719bec4 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 2 May 2017 11:28:37 +0200 Subject: [PATCH 0091/2207] linux: also include sched/mm.h --- LINUX/configure | 7 +++++++ LINUX/netmap_linux.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/LINUX/configure b/LINUX/configure index bf65b7992..f8f38c0e5 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1371,6 +1371,13 @@ EOF } EOF +# check for sched/mm.h + add_test 'have SCHED_MM' < + + void dummy(void) {} +EOF + ##################################################### # checks related to drivers # ##################################################### diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 3ecd4c448..05d086bf1 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -34,6 +34,9 @@ #include #include #include +#ifdef NETMAP_LINUX_HAVE_SCHED_MM +#include +#endif /* NETMAP_LINUX_HAVE_SCHED_MM */ #include "netmap_linux_config.h" From 22706bd646646c7bfdee3ca414ffb903ec579993 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 2 May 2017 12:09:28 +0200 Subject: [PATCH 0092/2207] linux/config: check for void get_stats64 --- LINUX/configure | 12 ++++++++++++ LINUX/netmap_linux.c | 14 ++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/LINUX/configure b/LINUX/configure index f8f38c0e5..451ae4374 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1378,6 +1378,18 @@ EOF void dummy(void) {} EOF +# check for void get_stats64 + add_test 'have NONVOID_GET_STATS64' < + + struct rtnl_link_stats64 * + dummy(struct net_device_ops *ops, struct net_device *dev, + struct rtnl_link_stats64 *storage) + { + return ops->ndo_get_stats64(dev, storage); + } +EOF + ##################################################### # checks related to drivers # ##################################################### diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 05d086bf1..8166729b0 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -2091,13 +2091,19 @@ static int linux_nm_vi_xmit(struct sk_buff *skb, struct net_device *netdev) } #ifdef NETMAP_LINUX_HAVE_GET_STATS64 -static struct rtnl_link_stats64 *linux_nm_vi_get_stats( - struct net_device *netdev, - struct rtnl_link_stats64 *stats) +static +#ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64 +struct rtnl_link_stats64 * +#else /* !VOID */ +void +#endif /* NETMAP_LINUX_HAVE_NONVOID_GET_STATS64 */ +linux_nm_vi_get_stats(struct net_device *netdev, struct rtnl_link_stats64 *stats) { +#ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64 return stats; +#endif /* !NETMAP_LINUX_HAVE_VOID_GET_STATS64 */ } -#endif +#endif /* NETMAP_LINUX_HAVE_GET_STATS64 */ static int linux_nm_vi_change_mtu(struct net_device *netdev, int new_mtu) { From c540f0a256202b7dd6b9f2fbc52be3fda19d994d Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Tue, 2 May 2017 13:21:39 +0200 Subject: [PATCH 0093/2207] linux/config: avoid build-prep when not necessary --- LINUX/scripts/np | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/LINUX/scripts/np b/LINUX/scripts/np index 22127ed03..eb1a4cc57 100755 --- a/LINUX/scripts/np +++ b/LINUX/scripts/np @@ -360,7 +360,7 @@ function get-kernel() ## as a default; if also the latter does not exist, the kernel is ## configure using 'allmodconfig'. ## Errors are logged to $LINUX_CONFIGS/linux-.log. -## If $LINUX_SOURCES/linux- already exists, +## If $LINUX_SOURCES/linux-/.build-prep already exists, ## nothing is done. ## In all cases, the absolute path of linux- is ## output. @@ -370,7 +370,7 @@ function build-prep() local dst=$(get-kernel $version) - [ -z "$dst" ] && return + [ -f $dst/.build-prep ] && { echo $dst; return; } ( cd $dst @@ -392,6 +392,7 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile make allmodconfig fi make modules_prepare + touch .build-prep ) >$dst.log 2>&1 || error "build-prep failed for linux $version. Please check $dst.log" echo $dst } From 82e894471d22196b4747b55ea8fc72444078c7f3 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 09:36:09 +0200 Subject: [PATCH 0094/2207] ptnetmap: ptnetmap_tx_nothread_notify unconditionally injects the interrupt We do this way because the CSB cannot be read without switching process address space. --- sys/dev/netmap/netmap_pt.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 3dbbe0592..6390fd2bf 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -400,7 +400,6 @@ ptnetmap_tx_nothread_notify(void *data) struct netmap_pt_host_adapter *pth_na = (struct netmap_pt_host_adapter *)kring->na->na_private; struct ptnetmap_state *ptns = pth_na->ptns; - struct ptnet_ring __user *ptring; if (unlikely(!ptns)) { D("ERROR ptnetmap state is NULL"); @@ -412,14 +411,12 @@ ptnetmap_tx_nothread_notify(void *data) return; } - /* Get TX ptring pointer from the CSB. */ - ptring = ptns->ptrings + kring->ring_id; - if (ptring_intr_enabled(ptring)) { - ptring_intr_enable(ptring, 0); - nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]); - IFRATE(ptns->rate_ctx.new.htxk++); - RD(1, "%s interrupt", kring->name); - } + /* We cannot access the CSB here (to check ptring->guest_need_kick), + * unless we switch address space to the one of the guest. For now + * we unconditionally inject an interrupt. */ + nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]); + IFRATE(ptns->rate_ctx.new.htxk++); + RD(1, "%s interrupt", kring->name); } /* From a4a40d311b3ad56719daabff0a122e116eca27b4 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 10:30:02 +0200 Subject: [PATCH 0095/2207] ptnetmap: don't filter out TX kicks if kring is empty --- sys/dev/netmap/netmap_pt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index e4d8e7f95..00b829d70 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -1290,8 +1290,8 @@ netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring, ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead); /* Ask for a kick from a guest to the host if needed. */ - if ((kring->rhead != kring->nr_hwcur && - NM_ACCESS_ONCE(ptring->host_need_kick)) || + if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring)) + && NM_ACCESS_ONCE(ptring->host_need_kick)) || (flags & NAF_FORCE_RECLAIM)) { ptring->sync_flags = flags; notify = true; From 813411cf358d3ae31da08f412efb86432ca894f3 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 10:46:35 +0200 Subject: [PATCH 0096/2207] ptnetmap: uniform debug print in guest *xtync routines --- sys/dev/netmap/netmap_pt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 0fb841b08..6ded68670 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -416,7 +416,7 @@ ptnetmap_tx_nothread_notify(void *data) * we unconditionally inject an interrupt. */ nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]); IFRATE(ptns->rate_ctx.new.htxk++); - RD(1, "%s interrupt", kring->name); + ND(1, "%s interrupt", kring->name); } /* @@ -1353,9 +1353,9 @@ netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring, } } - ND(1, "TX - CSB: head:%u cur:%u hwtail:%u - KRING: head:%u cur:%u tail: %u", - ptring->head, ptring->cur, ptring->hwtail, - kring->rhead, kring->rcur, kring->nr_hwtail); + ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)", + kring->name, ptring->head, ptring->cur, ptring->hwtail, + kring->rhead, kring->rcur, kring->nr_hwtail); return notify; } @@ -1418,9 +1418,9 @@ netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring, } } - ND(1, "RX - CSB: head:%u cur:%u hwtail:%u - KRING: head:%u cur:%u", - ptring->head, ptring->cur, ptring->hwtail, - kring->rhead, kring->rcur); + ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)", + kring->name, ptring->head, ptring->cur, ptring->hwtail, + kring->rhead, kring->rcur, kring->nr_hwtail); return notify; } From 022b680e9be5ad9d5acf330da9d785e69e05dd6c Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 11:11:36 +0200 Subject: [PATCH 0097/2207] ptnetmap: comment about ptnetmap_tx_workers variable --- sys/dev/netmap/netmap.c | 5 +++-- sys/dev/netmap/netmap_kern.h | 2 +- sys/dev/netmap/netmap_pt.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 9edd4cbd7..77aea3acf 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -522,7 +522,8 @@ int netmap_generic_rings = 1; /* Non-zero if ptnet devices are allowed to use virtio-net headers. */ int ptnet_vnet_hdr = 1; -int ptnetmap_worker = 1; +/* 0 if ptnetmap should not use worker threads for TX processing */ +int ptnetmap_tx_workers = 1; /* * SYSCTL calls are grouped between SYSBEGIN and SYSEND to be emulated @@ -550,7 +551,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW, &netmap_generic_ SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW, &netmap_generic_rings, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW, &netmap_generic_txqdisc, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr, 0 , ""); -SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_worker, CTLFLAG_RW, &ptnetmap_worker, 0 , ""); +SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW, &ptnetmap_tx_workers, 0 , ""); SYSEND; diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index b09bc5445..f18c58abb 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -1561,7 +1561,7 @@ extern int netmap_generic_mit; extern int netmap_generic_ringsize; extern int netmap_generic_rings; extern int netmap_generic_txqdisc; -extern int ptnetmap_worker; +extern int ptnetmap_tx_workers; /* * NA returns a pointer to the struct netmap adapter from the ifp, diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 6ded68670..e238f7744 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -679,7 +679,7 @@ static int ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na, struct ptnetmap_cfg *cfg) { - int use_tx_kthreads = ptnetmap_worker; /* snapshot */ + int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */ struct ptnetmap_state *ptns = pth_na->ptns; struct nm_kctx_cfg nmk_cfg; unsigned int num_rings; From f776fbb9fb50f82fd755b9d1f7d19361d632210d Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 16:28:14 +0200 Subject: [PATCH 0098/2207] ptnetmap: clear NAF_BDG_MAYSLEEP on VALE ports to avoid sleeping while atomic This is done only with ptnetmap_tx_workers == 0, since txsync on the passed-through port is called under spinlock (on Linux). --- sys/dev/netmap/netmap_kern.h | 5 +++++ sys/dev/netmap/netmap_pt.c | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index f18c58abb..97a6c0f02 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -2071,7 +2071,12 @@ u_int nm_os_ncpus(void); struct netmap_pt_host_adapter { struct netmap_adapter up; + /* the passed-through adapter */ struct netmap_adapter *parent; + /* parent->na_flags, saved at NETMAP_PT_HOST_CREATE time, + * and restored at NETMAP_PT_HOST_DELETE time */ + uint32_t parent_na_flags; + int (*parent_nm_notify)(struct netmap_kring *kring, int flags); void *ptns; }; diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index e238f7744..e41c1411d 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -677,9 +677,8 @@ ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na) static int ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na, - struct ptnetmap_cfg *cfg) + struct ptnetmap_cfg *cfg, int use_tx_kthreads) { - int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */ struct ptnetmap_state *ptns = pth_na->ptns; struct nm_kctx_cfg nmk_cfg; unsigned int num_rings; @@ -805,6 +804,7 @@ static int ptnetmap_create(struct netmap_pt_host_adapter *pth_na, struct ptnetmap_cfg *cfg) { + int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */ struct ptnetmap_state *ptns; unsigned int num_rings; int ret, i; @@ -841,7 +841,7 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na, DBG(ptnetmap_print_configuration(cfg)); /* Create kernel contexts. */ - if ((ret = ptnetmap_create_kctxs(pth_na, cfg))) { + if ((ret = ptnetmap_create_kctxs(pth_na, cfg, use_tx_kthreads))) { D("ERROR ptnetmap_create_kctxs()"); goto err; } @@ -851,10 +851,17 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na, goto err; } - /* Overwrite parent nm_notify krings callback. */ + /* Overwrite parent nm_notify krings callback, and + * clear NAF_BDG_MAYSLEEP if needed. */ pth_na->parent->na_private = pth_na; pth_na->parent_nm_notify = pth_na->parent->nm_notify; pth_na->parent->nm_notify = nm_unused_notify; + pth_na->parent_na_flags = pth_na->parent->na_flags; + if (!use_tx_kthreads) { + /* VALE port txsync is executed under spinlock on Linux, so + * we need to make sure the bridge cannot sleep. */ + pth_na->parent->na_flags &= ~NAF_BDG_MAYSLEEP; + } for (i = 0; i < pth_na->parent->num_rx_rings; i++) { pth_na->up.rx_rings[i].save_notify = @@ -902,6 +909,7 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na) /* Restore parent adapter callbacks. */ pth_na->parent->nm_notify = pth_na->parent_nm_notify; pth_na->parent->na_private = NULL; + pth_na->parent->na_flags = pth_na->parent_na_flags; for (i = 0; i < pth_na->parent->num_rx_rings; i++) { pth_na->up.rx_rings[i].nm_notify = From 67ab54cc4f3bf53e9bbebf9f992b67b4ef4f8870 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 16:39:56 +0200 Subject: [PATCH 0099/2207] vale: let nm_bdg_preflush return hwcur when it cannot acquire the bridge lock --- sys/dev/netmap/netmap_vale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index 1596552ed..a018f60ec 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -1462,7 +1462,7 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end) if (na->up.na_flags & NAF_BDG_MAYSLEEP) BDG_RLOCK(b); else if (!BDG_RTRYLOCK(b)) - return 0; + return j; ND(5, "rlock acquired for %d packets", ((j > end ? lim+1 : 0) + end) - j); ft = kring->nkr_ft; From c28ac0aa40a321cdce50f8e92a56180f860cac51 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 16:56:30 +0200 Subject: [PATCH 0100/2207] generic: add is_generic() function to check for emulated netmap adapters --- sys/dev/netmap/netmap_generic.c | 6 ++++++ sys/dev/netmap/netmap_kern.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c index d9d97559e..f148b2281 100644 --- a/sys/dev/netmap/netmap_generic.c +++ b/sys/dev/netmap/netmap_generic.c @@ -1172,6 +1172,12 @@ generic_netmap_dtor(struct netmap_adapter *na) D("Emulated netmap adapter for %s destroyed", na->name); } +int +na_is_generic(struct netmap_adapter *na) +{ + return na->nm_register == generic_netmap_register; +} + /* * generic_netmap_attach() makes it possible to use netmap on * a device without native netmap support. diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 97a6c0f02..8fafdd077 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -1871,6 +1871,8 @@ int generic_rx_handler(struct ifnet *ifp, struct mbuf *m);; int nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept); int nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept); +int na_is_generic(struct netmap_adapter *na); + /* * the generic transmit routine is passed a structure to optionally * build a queue of descriptors, in an OS-specific way. @@ -1927,6 +1929,7 @@ int nm_os_mitigation_active(struct nm_generic_mit *mit); void nm_os_mitigation_cleanup(struct nm_generic_mit *mit); #else /* !WITH_GENERIC */ #define generic_netmap_attach(ifp) (EOPNOTSUPP) +#define na_is_generic(na) (0) #endif /* WITH_GENERIC */ /* Shared declarations for the VALE switch. */ From 60cd9469a68695d77dc51e30b052c64b19fa652e Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 3 May 2017 16:57:09 +0200 Subject: [PATCH 0101/2207] ptnetmap: deny passthrough of emulated adapter with ptnetmap_tx_workers == 0 This is necessary because dev_queue_xmit() cannot be called under spinlock. --- sys/dev/netmap/netmap_pt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index e41c1411d..27eaa0232 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -823,6 +823,12 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na, return EINVAL; } + if (!use_tx_kthreads && na_is_generic(pth_na->parent)) { + D("ERROR ptnetmap direct transmission not supported with " + "passed-through emulated adapters"); + return EOPNOTSUPP; + } + ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kctxs)); if (!ptns) { return ENOMEM; From ca9b6de4573516ebd51e74f3179132b754047154 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Fri, 5 May 2017 16:13:00 +0200 Subject: [PATCH 0102/2207] pkt-gen: fix checksum computation for -z and -Z options --- apps/pkt-gen/pkt-gen.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index c4ca9c252..08b5b8f1b 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -764,8 +764,10 @@ update_ip(struct pkt *pkt, struct glob_arg *g) naddr = oaddr = ntohl(ip->ip_src.s_addr); nport = oport = ntohs(udp->uh_sport); if (g->options & OPT_RANDOM_SRC) { - naddr = ip->ip_src.s_addr = random(); - nport = udp->uh_sport = random(); + ip->ip_src.s_addr = random(); + udp->uh_sport = random(); + naddr = ntohl(ip->ip_src.s_addr); + nport = ntohs(udp->uh_sport); break; } if (oport < g->src_ip.port1) { @@ -798,8 +800,10 @@ update_ip(struct pkt *pkt, struct glob_arg *g) naddr = oaddr = ntohl(ip->ip_dst.s_addr); nport = oport = ntohs(udp->uh_dport); if (g->options & OPT_RANDOM_DST) { - naddr = ip->ip_dst.s_addr = random(); - nport = udp->uh_dport = random(); + ip->ip_dst.s_addr = random(); + udp->uh_dport = random(); + naddr = ntohl(ip->ip_dst.s_addr); + nport = ntohs(udp->uh_dport); break; } if (oport < g->dst_ip.port1) { @@ -857,8 +861,10 @@ update_ip6(struct pkt *pkt, struct glob_arg *g) naddr = oaddr = ntohs(ip6->ip6_src.s6_addr16[group]); nport = oport = ntohs(udp->uh_sport); if (g->options & OPT_RANDOM_SRC) { - naddr = ip6->ip6_src.s6_addr16[group] = random(); - nport = udp->uh_sport = random(); + ip6->ip6_src.s6_addr16[group] = random(); + udp->uh_sport = random(); + naddr = ntohs(ip6->ip6_src.s6_addr16[group]); + nport = ntohs(udp->uh_sport); break; } if (oport < g->src_ip.port1) { @@ -887,8 +893,10 @@ update_ip6(struct pkt *pkt, struct glob_arg *g) naddr = oaddr = ntohs(ip6->ip6_dst.s6_addr16[group]); nport = oport = ntohs(udp->uh_dport); if (g->options & OPT_RANDOM_DST) { - naddr = ip6->ip6_dst.s6_addr16[group] = random(); - nport = udp->uh_dport = random(); + ip6->ip6_dst.s6_addr16[group] = random(); + udp->uh_dport = random(); + naddr = ntohs(ip6->ip6_dst.s6_addr16[group]); + nport = ntohs(udp->uh_dport); break; } if (oport < g->dst_ip.port1) { From 334e94600b3f43e08ed828c24ffe06016c26f584 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Fri, 5 May 2017 16:15:14 +0200 Subject: [PATCH 0103/2207] pkt-gen: allow -Z and -z to be used together --- apps/pkt-gen/pkt-gen.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 08b5b8f1b..8277135f0 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -784,19 +784,19 @@ update_ip(struct pkt *pkt, struct glob_arg *g) } naddr = g->src_ip.ipv4.start; ip->ip_src.s_addr = htonl(naddr); - - /* update checksums if needed */ - if (oaddr != naddr) { - ip_sum = cksum_add(ip_sum, ~oaddr >> 16); - ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); - ip_sum = cksum_add(ip_sum, naddr >> 16); - ip_sum = cksum_add(ip_sum, naddr & 0xffff); - } - if (oport != nport) { - udp_sum = cksum_add(udp_sum, ~oport); - udp_sum = cksum_add(udp_sum, nport); - } - + } while (0); + /* update checksums if needed */ + if (oaddr != naddr) { + ip_sum = cksum_add(ip_sum, ~oaddr >> 16); + ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff); + ip_sum = cksum_add(ip_sum, naddr >> 16); + ip_sum = cksum_add(ip_sum, naddr & 0xffff); + } + if (oport != nport) { + udp_sum = cksum_add(udp_sum, ~oport); + udp_sum = cksum_add(udp_sum, nport); + } + do { naddr = oaddr = ntohl(ip->ip_dst.s_addr); nport = oport = ntohs(udp->uh_dport); if (g->options & OPT_RANDOM_DST) { @@ -881,14 +881,14 @@ update_ip6(struct pkt *pkt, struct glob_arg *g) } naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]); ip6->ip6_src.s6_addr16[group] = htons(naddr); - - /* update checksums if needed */ - if (oaddr != naddr) - udp_sum = cksum_add(~oaddr, naddr); - if (oport != nport) - udp_sum = cksum_add(udp_sum, - cksum_add(~oport, nport)); - + } while (0); + /* update checksums if needed */ + if (oaddr != naddr) + udp_sum = cksum_add(~oaddr, naddr); + if (oport != nport) + udp_sum = cksum_add(udp_sum, + cksum_add(~oport, nport)); + do { group = g->dst_ip.ipv6.egroup; naddr = oaddr = ntohs(ip6->ip6_dst.s6_addr16[group]); nport = oport = ntohs(udp->uh_dport); From ea61cb83902fe6176dde467c2d7b07a457d21762 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Fri, 5 May 2017 21:51:15 +0200 Subject: [PATCH 0104/2207] pkt-gen: comply with RFC 1624 --- apps/pkt-gen/pkt-gen.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 8277135f0..9714849a9 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -833,10 +833,10 @@ update_ip(struct pkt *pkt, struct glob_arg *g) udp_sum = cksum_add(udp_sum, nport); } if (udp_sum != 0) - udp->uh_sum = cksum_add(udp->uh_sum, ~htons(udp_sum)); + udp->uh_sum = ~cksum_add(~udp->uh_sum, htons(udp_sum)); if (ip_sum != 0) { - ip->ip_sum = cksum_add(ip->ip_sum, ~htons(ip_sum)); - udp->uh_sum = cksum_add(udp->uh_sum, ~htons(ip_sum)); + ip->ip_sum = ~cksum_add(~ip->ip_sum, htons(ip_sum)); + udp->uh_sum = ~cksum_add(~udp->uh_sum, htons(ip_sum)); } } @@ -922,7 +922,7 @@ update_ip6(struct pkt *pkt, struct glob_arg *g) udp_sum = cksum_add(udp_sum, cksum_add(~oport, nport)); if (udp_sum != 0) - udp->uh_sum = cksum_add(udp->uh_sum, ~htons(udp_sum)); + udp->uh_sum = ~cksum_add(~udp->uh_sum, udp_sum); } static void From 3947b2174f13fd54ae6db5e4831846a1811cd8c3 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Fri, 5 May 2017 22:40:11 +0200 Subject: [PATCH 0105/2207] pkt-gen: fix UDP checksum in txseq --- apps/pkt-gen/pkt-gen.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 9714849a9..3086849fb 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1902,12 +1902,19 @@ txseq_body(void *data) sent < limit; sent++, sequence++) { struct netmap_slot *slot = &ring->slot[head]; char *p = NETMAP_BUF(ring, slot->buf_idx); + uint16_t *w = (uint16_t *)PKT(pkt, body, targ->g->af), t, + *sum = (uint16_t *)(targ->g->af == AF_INET ? + &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum); slot->flags = 0; + t = *w; PKT(pkt, body, targ->g->af)[0] = sequence >> 24; PKT(pkt, body, targ->g->af)[1] = (sequence >> 16) & 0xff; + *sum = ~cksum_add(~*sum, cksum_add(~t, *w)); + t = *++w; PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff; PKT(pkt, body, targ->g->af)[3] = sequence & 0xff; + *sum = ~cksum_add(~*sum, cksum_add(~t, *w)); nm_pkt_copy(frame, p, size); if (fcnt == frags) { update_addresses(pkt, targ->g); From 7121ab32de1c78ca0106dbbe252dbc5077097555 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Thu, 11 May 2017 08:19:48 +0200 Subject: [PATCH 0106/2207] LINUX: remove NAF_BDG_MAYSLEEP flag from i40e --- LINUX/i40e_netmap_linux.h | 1 - 1 file changed, 1 deletion(-) diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h index d275de920..4a56ee6b5 100644 --- a/LINUX/i40e_netmap_linux.h +++ b/LINUX/i40e_netmap_linux.h @@ -221,7 +221,6 @@ i40e_netmap_attach(struct i40e_vsi *vsi) bzero(&na, sizeof(na)); na.ifp = vsi->netdev; - na.na_flags = NAF_BDG_MAYSLEEP; // XXX check that queues is set. na.num_tx_desc = NM_I40E_TX_RING(vsi, 0)->count; na.num_rx_desc = NM_I40E_RX_RING(vsi, 0)->count; From 78c231a198d82ece7f040bbc65cdfb450c70c40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD=20=D0=A1=D0=BF=D0=B8=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Mon, 15 May 2017 13:16:23 +0500 Subject: [PATCH 0107/2207] Added log levels for printf function as in linux. --- LINUX/bsd_glue.h | 1 - sys/dev/netmap/if_ixl_netmap.h | 2 +- sys/dev/netmap/netmap.c | 6 +++--- sys/dev/netmap/netmap_kern.h | 13 ++++++++++++- sys/dev/netmap/netmap_mem2.c | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h index 2816cb09e..39f4c9d94 100644 --- a/LINUX/bsd_glue.h +++ b/LINUX/bsd_glue.h @@ -58,7 +58,6 @@ #include // virt_to_phys #include -#define printf(fmt, arg...) printk(KERN_ERR fmt, ##arg) #define KASSERT(a, b) BUG_ON(!(a)) /*----- support for compiling on older versions of linux -----*/ diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h index f6aebbb1a..14f21e938 100644 --- a/sys/dev/netmap/if_ixl_netmap.h +++ b/sys/dev/netmap/if_ixl_netmap.h @@ -129,7 +129,7 @@ ixl_netmap_attach(struct ixl_vsi *vsi) na.ifp = vsi->ifp; na.na_flags = NAF_BDG_MAYSLEEP; // XXX check that queues is set. - printf("queues is %p\n", vsi->queues); + nm_prinf("queues is %p\n", vsi->queues); if (vsi->queues) { na.num_tx_desc = vsi->queues[0].num_desc; na.num_rx_desc = vsi->queues[0].num_desc; diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 77aea3acf..3a3ae0ee0 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -673,7 +673,7 @@ nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg) op = "Clamp"; } if (op && msg) - printf("%s %s to %d (was %d)\n", op, msg, *v, oldv); + nm_prinf("%s %s to %d (was %d)\n", op, msg, *v, oldv); return *v; } @@ -3342,7 +3342,7 @@ netmap_fini(void) netmap_uninit_bridges(); netmap_mem_fini(); NMG_LOCK_DESTROY(); - printf("netmap: unloaded module.\n"); + nm_prinf("netmap: unloaded module.\n"); } @@ -3379,7 +3379,7 @@ netmap_init(void) if (error) goto fail; - printf("netmap: loaded module\n"); + nm_prinf("netmap: loaded module\n"); return (0); fail: netmap_fini(); diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 8fafdd077..3972f82d6 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -243,12 +243,23 @@ typedef struct hrtimer{ #define NMG_UNLOCK() NM_MTX_UNLOCK(netmap_global_lock) #define NMG_LOCK_ASSERT() NM_MTX_ASSERT(netmap_global_lock) +#if defined(__FreeBSD__) +#define nm_prerr printf +#define nm_prinf printf +#elif defined (_WIN32) +#define nm_prerr DbgPrint +#define nm_prinf DbgPrint +#elif defined(linux) +#define nm_prerr(fmt, arg...) printk(KERN_ERR fmt, ##arg) +#define nm_prinf(fmt, arg...) printk(KERN_INFO fmt, ##arg) +#endif + #define ND(format, ...) #define D(format, ...) \ do { \ struct timeval __xxts; \ microtime(&__xxts); \ - printf("%03d.%06d [%4d] %-25s " format "\n", \ + nm_prerr("%03d.%06d [%4d] %-25s " format "\n", \ (int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \ __LINE__, __FUNCTION__, ##__VA_ARGS__); \ } while (0) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index 23325846b..ad990f061 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -245,7 +245,7 @@ netmap_mem_get_id(struct netmap_mem_d *nmd) #ifdef NM_DEBUG_MEM_PUTGET #define NM_DBG_REFC(nmd, func, line) \ - printf("%s:%d mem[%d] -> %d\n", func, line, (nmd)->nm_id, (nmd)->refcount); + nm_prinf("%s:%d mem[%d] -> %d\n", func, line, (nmd)->nm_id, (nmd)->refcount); #else #define NM_DBG_REFC(nmd, func, line) #endif From ea589e891075b71bda0f8449d573be0ba4cb30d1 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Wed, 17 May 2017 12:12:50 +0200 Subject: [PATCH 0108/2207] pkt-gen: fix compilation issue on FreeBSD --- apps/pkt-gen/pkt-gen.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 3086849fb..252b79a16 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1376,8 +1376,11 @@ ping_body(void *data) #endif /* BUSYWAIT */ } - if (sent > 0) - D("RTT over %"PRIu64" packets: min %d av %d ns", sent, (int)g_min, (int)((double)g_av/sent)); + if (sent > 0) { + D("RTT over %llu packets: min %d av %d ns", + (long long unsigned)sent, (int)g_min, + (int)((double)g_av/sent)); + } targ->completed = 1; /* reset the ``used`` flag. */ From 82129a8effa3825f1a44aecfc0f6f16283699f0b Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 22 May 2017 12:58:30 +0200 Subject: [PATCH 0109/2207] pkt-gen: fix compilation warning --- apps/pkt-gen/pkt-gen.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c index 252b79a16..f2ca1496a 100644 --- a/apps/pkt-gen/pkt-gen.c +++ b/apps/pkt-gen/pkt-gen.c @@ -1697,8 +1697,7 @@ receiver_body(void *data) int i; struct my_ctrs cur; - cur.pkts = cur.bytes = cur.events = cur.drop = cur.min_space = 0; - cur.t.tv_usec = cur.t.tv_sec = 0; // unused, just silence the compiler + memset(&cur, 0, sizeof(cur)); if (setaffinity(targ->thread, targ->affinity)) goto quit; @@ -2021,8 +2020,7 @@ rxseq_body(void *data) int first_slot = 1; int i, af; - cur.pkts = cur.bytes = cur.events = cur.drop = cur.min_space = 0; - cur.t.tv_usec = cur.t.tv_sec = 0; // unused, just silence the compiler + memset(&cur, 0, sizeof(cur)); if (setaffinity(targ->thread, targ->affinity)) goto quit; From 350a8836603ffc28f2bc35163eebcd8295470954 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 29 May 2017 12:58:58 +0200 Subject: [PATCH 0110/2207] linux/ixgbe: intel 5.1.3 driver --- LINUX/default-config.mak.in_ | 2 +- LINUX/final-patches/intel--ixgbe--5.1.3 | 170 ++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 LINUX/final-patches/intel--ixgbe--5.1.3 diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index c610c9dc1..214b2a0f3 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -11,7 +11,7 @@ endef enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2)))) -$(call enabled_intel_driver,ixgbe,5.0.4) +$(call enabled_intel_driver,ixgbe,5.1.3) $(call enabled_intel_driver,ixgbevf,4.0.3) e1000e@cflags := -fno-pie $(call enabled_intel_driver,e1000e,3.3.5.3) diff --git a/LINUX/final-patches/intel--ixgbe--5.1.3 b/LINUX/final-patches/intel--ixgbe--5.1.3 new file mode 100644 index 000000000..f9c7ece60 --- /dev/null +++ b/LINUX/final-patches/intel--ixgbe--5.1.3 @@ -0,0 +1,170 @@ +diff --git a/ixgbe/Makefile b/ixgbe/Makefile +index a3cc895..a038975 100644 +--- a/ixgbe/Makefile ++++ b/ixgbe/Makefile +@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver + # + +-obj-$(CONFIG_IXGBE) += ixgbe.o ++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o + +-define ixgbe-y ++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y + ixgbe_main.o + ixgbe_api.o + ixgbe_common.o +@@ -49,24 +49,24 @@ define ixgbe-y + ixgbe_x540.o + ixgbe_x550.o + endef +-ixgbe-y := $(strip ${ixgbe-y}) ++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y}) + +-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o + +-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o + +-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o + +-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o + +-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o + +-ixgbe-y += kcompat.o ++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := ixgbe ++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -127,9 +127,12 @@ ccc: clean + @+$(call devkernelbuild,modules,coccicheck MODE=report)) + + # Build manfiles +-manfile: ++manfile: ../$(DRIVER).$(MANSECTION) + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../$(DRIVER).$(MANSECTION): ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call devkernelbuild,clean) +diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c +index fe4291e..379d4f4 100644 +--- a/ixgbe/ixgbe_main.c ++++ b/ixgbe/ixgbe_main.c +@@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev); + } + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#include ++#endif ++ + /** + * ixgbe_clean_tx_irq - Reclaim resources after transmit completes + * @q_vector: structure containing interrupt and ring information +@@ -771,6 +788,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBE_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -1946,6 +1974,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, + #endif /* CONFIG_FCOE */ + u16 cleaned_count = ixgbe_desc_unused(rx_ring); + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ + do { + union ixgbe_adv_rx_desc *rx_desc; + struct sk_buff *skb; +@@ -3222,6 +3260,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } + + static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter) +@@ -3798,6 +3839,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl); + + ixgbe_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring)); + } + +@@ -11114,6 +11159,10 @@ no_info_string: + hw->mac.ops.setup_eee(hw, eee_enable); + } + ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ ++ + return 0; + + err_register: +@@ -11159,6 +11208,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) + return; + + netdev = adapter->netdev; ++ ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + #ifdef HAVE_IXGBE_DEBUG_FS + ixgbe_dbg_adapter_exit(adapter); + From 074334a131907232a46f086d8ee0944d17771522 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 29 May 2017 14:09:50 +0200 Subject: [PATCH 0111/2207] linux/ixgbevf: intel 4.1.2 driver --- LINUX/final-patches/intel--ixgbevf--4.1.2 | 171 ++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 LINUX/final-patches/intel--ixgbevf--4.1.2 diff --git a/LINUX/final-patches/intel--ixgbevf--4.1.2 b/LINUX/final-patches/intel--ixgbevf--4.1.2 new file mode 100644 index 000000000..41a92b10c --- /dev/null +++ b/LINUX/final-patches/intel--ixgbevf--4.1.2 @@ -0,0 +1,171 @@ +diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile +index ca79ef6..939f185 100644 +--- a/ixgbevf/Makefile ++++ b/ixgbevf/Makefile +@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver + # + +-obj-$(CONFIG_IXGBE) += ixgbevf.o ++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o + +-define ixgbevf-y ++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y + ixgbevf_main.o + ixgbevf_ethtool.o + ixgbe_vf.o + ixgbe_mbx.o + endef +-ixgbevf-y := $(strip ${ixgbevf-y}) +-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o +-ixgbevf-y += kcompat.o ++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y}) ++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o ++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := ixgbevf ++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -90,9 +90,12 @@ ccc: clean + @+$(call kernelbuild,modules,coccicheck MODE=report)) + + # Build manfiles +-manfile: ++manfile: ../$(DRIVER).$(MANSECTION) + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../$(DRIVER).$(MANSECTION): ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call kernelbuild,clean) +diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c +index 789187b..d51c9cd 100644 +--- a/ixgbevf/ixgbevf_main.c ++++ b/ixgbevf/ixgbevf_main.c +@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev) + ixgbevf_tx_timeout_reset(adapter); + } + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++/* ++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to ++ * be a reference on how to implement netmap support in a driver. ++ * Additional comments are in ixgbe_netmap_linux.h . ++ * ++ * The code is originally developed on FreeBSD and in the interest ++ * of maintainability we try to limit differences between the two systems. ++ * ++ * contains functions for netmap support ++ * that extend the standard driver. ++ * It also defines DEV_NETMAP so further conditional sections use ++ * that instead of CONFIG_NETMAP ++ */ ++#define NM_IXGBEVF ++#include ++#endif + + /** + * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes +@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, + if (test_bit(__IXGBEVF_DOWN, &adapter->state)) + return true; + ++#ifdef DEV_NETMAP ++ /* ++ * In netmap mode, all the work is done in the context ++ * of the client thread. Interrupt handlers only wake up ++ * clients, which may be sleeping on individual rings ++ * or on a global resource for all rings. ++ */ ++ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buffer = &tx_ring->tx_buffer_info[i]; + tx_desc = IXGBEVF_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -1192,6 +1220,17 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, + u16 cleaned_count = ixgbevf_desc_unused(rx_ring); + struct sk_buff *skb = rx_ring->skb; + ++#ifdef DEV_NETMAP ++ /* ++ * Same as the txeof routine: only wakeup clients on intr. ++ */ ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) ++ return (nm_irq == NM_IRQ_RESCHED) ? budget : 1; ++#endif /* DEV_NETMAP */ ++ ++ + do { + union ixgbe_adv_rx_desc *rx_desc; + +@@ -1819,8 +1858,11 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, + } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); + if (!wait_loop) + DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_configure_tx_ring(adapter, reg_idx); ++#endif /* DEV_NETMAP */ + } +- ++ + /** + * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset + * @adapter: board private structure +@@ -1991,6 +2033,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, + IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl); + + ixgbevf_rx_desc_queue_enable(adapter, ring); ++#ifdef DEV_NETMAP ++ if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx)) ++ return; ++#endif /* DEV_NETMAP */ + ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring)); + } + +@@ -4923,8 +4969,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, + if (netdev->features & NETIF_F_GRO) + DPRINTK(PROBE, INFO, "GRO is enabled\n"); + #endif +- + DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string); ++#ifdef DEV_NETMAP ++ ixgbe_netmap_attach(adapter); ++#endif /* DEV_NETMAP */ + cards_found++; + return 0; + +@@ -4963,6 +5011,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev) + if (!netdev) + return; + ++#ifdef DEV_NETMAP ++ netmap_detach(netdev); ++#endif /* DEV_NETMAP */ ++ + adapter = netdev_priv(netdev); + + set_bit(__IXGBEVF_REMOVE, &adapter->state); +diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h +index c08d849..d7a58a5 100644 +--- a/ixgbevf/kcompat.h ++++ b/ixgbevf/kcompat.h +@@ -25,6 +25,8 @@ + #ifndef _KCOMPAT_H_ + #define _KCOMPAT_H_ + ++#include ++ + #ifndef LINUX_VERSION_CODE + #include + #else From aa378fa4845b8f044ce200f4498cbf28d94a5d09 Mon Sep 17 00:00:00 2001 From: Giuseppe Lettieri Date: Mon, 29 May 2017 18:26:39 +0200 Subject: [PATCH 0112/2207] linux/i40e: intel 2.0.26 driver --- LINUX/default-config.mak.in_ | 5 +- LINUX/final-patches/intel--i40e--2.0.26 | 156 ++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 LINUX/final-patches/intel--i40e--2.0.26 diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_ index 214b2a0f3..47720e0ff 100644 --- a/LINUX/default-config.mak.in_ +++ b/LINUX/default-config.mak.in_ @@ -12,10 +12,9 @@ endef enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2)))) $(call enabled_intel_driver,ixgbe,5.1.3) -$(call enabled_intel_driver,ixgbevf,4.0.3) +$(call enabled_intel_driver,ixgbevf,4.1.2) e1000e@cflags := -fno-pie $(call enabled_intel_driver,e1000e,3.3.5.3) igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(call enabled_intel_driver,igb,5.3.5.4) -$(call enabled_intel_driver,i40e,2.0.23) -$(if $(filter i40e,$(E_DRIVERS)),$(eval i40e@patch := patches/intel--i40e--2.0.19)) +$(call enabled_intel_driver,i40e,2.0.26) diff --git a/LINUX/final-patches/intel--i40e--2.0.26 b/LINUX/final-patches/intel--i40e--2.0.26 new file mode 100644 index 000000000..fc577e8ee --- /dev/null +++ b/LINUX/final-patches/intel--i40e--2.0.26 @@ -0,0 +1,156 @@ +diff --git a/i40e/Makefile b/i40e/Makefile +index 1af83c9..e896ffe 100644 +--- a/i40e/Makefile ++++ b/i40e/Makefile +@@ -27,9 +27,9 @@ ifneq ($(KERNELRELEASE),) + # Makefile for the Intel(R) 40-10 Gigabit Ethernet Connection Network Driver + # + +-obj-$(CONFIG_I40E) += i40e.o ++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o + +-i40e-y := i40e_main.o \ ++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \ + i40e_ethtool.o \ + i40e_adminq.o \ + i40e_common.o \ +@@ -43,14 +43,14 @@ i40e-y := i40e_main.o \ + i40e_client.o \ + i40e_virtchnl_pf.o + +-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o +-i40e-$(CONFIG_FCOE:m=y) += i40e_fcoe.o +-i40e-y += kcompat.o ++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o ++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_FCOE:m=y) += i40e_fcoe.o ++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o + + else # ifneq($(KERNELRELEASE),) + # normal makefile + +-DRIVER := i40e ++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX) + + ifeq (,$(wildcard common.mk)) + $(error Cannot find common.mk build rules) +@@ -90,9 +90,12 @@ ccc: clean + @+$(call kernelbuild,modules,coccicheck MODE=report) + + # Build manfiles +-manfile: ++manfile: ../${DRIVER}.${MANSECTION} + @gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz + ++../${DRIVER}.${MANSECTION}: ++ touch $@ ++ + # Clean the module subdirectories + clean: + @+$(call kernelbuild,clean) +diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c +index 15e43a1..1eddcb3 100644 +--- a/i40e/i40e_main.c ++++ b/i40e/i40e_main.c +@@ -133,6 +133,11 @@ MODULE_VERSION(DRV_VERSION); + + static struct workqueue_struct *i40e_wq; + ++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) ++#define NETMAP_I40E_MAIN ++#include ++#endif ++ + /** + * i40e_get_lump - find a lump of free generic resource + * @pf: board private structure +@@ -3281,6 +3286,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) + /* cache tail off for easier writes later */ + ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q); + ++#ifdef DEV_NETMAP ++ i40e_netmap_configure_tx_ring(ring); ++#endif /* DEV_NETMAP */ ++ + return 0; + } + +@@ -3353,6 +3362,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) + ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q); + writel(0, ring->tail); + ++#ifdef DEV_NETMAP ++ if (i40e_netmap_configure_rx_ring(ring)) ++ return 0; ++#endif /* DEV_NETMAP */ ++ + i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring)); + + return 0; +@@ -10645,6 +10659,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi) + return -ENODEV; + } + ++#ifdef DEV_NETMAP ++ if (vsi->netdev_registered) ++ netmap_detach(vsi->netdev); ++#endif ++ + uplink_seid = vsi->uplink_seid; + if (vsi->type != I40E_VSI_SRIOV) { + if (vsi->netdev_registered) { +@@ -11016,6 +11035,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, + (vsi->type == I40E_VSI_VMDQ2)) { + ret = i40e_vsi_config_rss(vsi); + } ++ ++#ifdef DEV_NETMAP ++ if (vsi->netdev_registered) ++ i40e_netmap_attach(vsi); ++#endif ++ + return vsi; + + err_rings: +diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c +index 6c8aa0c..bd90202 100644 +--- a/i40e/i40e_txrx.c ++++ b/i40e/i40e_txrx.c +@@ -25,6 +25,10 @@ + #include "i40e.h" + #include "i40e_prototype.h" + ++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE) ++#include ++#endif /* DEV_NETMAP */ ++ + static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, + u32 td_tag) + { +@@ -695,6 +699,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, + unsigned int total_bytes = 0, total_packets = 0; + unsigned int budget = vsi->work_limit; + ++#ifdef DEV_NETMAP ++ if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS) ++ return true; ++#endif /* DEV_NETMAP */ ++ + tx_buf = &tx_ring->tx_bi[i]; + tx_desc = I40E_TX_DESC(tx_ring, i); + i -= tx_ring->count; +@@ -1894,6 +1903,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) + u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); + bool failure = false; + ++#ifdef DEV_NETMAP ++ int dummy, nm_irq; ++ nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy); ++ if (nm_irq != NM_IRQ_PASS) { ++ return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget; ++ } ++#endif /* DEV_NETMAP */ ++ ++ + while (likely(total_rx_packets < (unsigned int)budget)) { + union i40e_rx_desc *rx_desc; + u16 vlan_tag; From 2535f093bcc7734e6854a68bbc33f863af7357bd Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 30 May 2017 16:23:33 +0200 Subject: [PATCH 0113/2207] lb: fix warning/error raised by gcc7 --- apps/lb/lb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/lb/lb.c b/apps/lb/lb.c index debe196f5..071e689dd 100644 --- a/apps/lb/lb.c +++ b/apps/lb/lb.c @@ -107,7 +107,7 @@ struct { * the overflow queue is a circular queue of buffers */ struct overflow_queue { - char name[MAX_IFNAMELEN]; + char name[MAX_IFNAMELEN + 16]; struct netmap_slot *slots; uint32_t head; uint32_t tail; @@ -805,7 +805,7 @@ int main(int argc, char **argv) extra_bufs = 0; } q->size = extra_bufs; - snprintf(q->name, MAX_IFNAMELEN, "oq %s{%d", g->pipename, k); + snprintf(q->name, sizeof(q->name), "oq %s{%4d", g->pipename, k); p->oq = q; } } From d93db47dcf12902fdf837cdf5fa9fadf722b55a5 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Fri, 2 Jun 2017 07:01:39 +0000 Subject: [PATCH 0114/2207] freebsd: check that NA(ifp) is valid in generic_rx_handler routine --- sys/dev/netmap/netmap_freebsd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c index 66d0637fd..6d0453d3b 100644 --- a/sys/dev/netmap/netmap_freebsd.c +++ b/sys/dev/netmap/netmap_freebsd.c @@ -268,11 +268,17 @@ nm_os_mbuf_has_offld(struct mbuf *m) static void freebsd_generic_rx_handler(struct ifnet *ifp, struct mbuf *m) { - struct netmap_generic_adapter *gna = - (struct netmap_generic_adapter *)NA(ifp); - int stolen = generic_rx_handler(ifp, m); + int stolen; + if (!NM_NA_VALID(ifp)) { + RD(1, "Warning: got RX packet for invalid emulated adapter"); + return; + } + + stolen = generic_rx_handler(ifp, m); if (!stolen) { + struct netmap_generic_adapter *gna = + (struct netmap_generic_adapter *)NA(ifp); gna->save_if_input(ifp, m); } } From 57708cc0a57e1e062f9f2b85a7670a80fe302298 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 3 Jun 2017 08:11:26 -0700 Subject: [PATCH 0115/2207] LINUX: ixgbe: update next_to_use for RX rings --- LINUX/ixgbe_netmap_linux.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h index a206f8a84..24243fea9 100644 --- a/LINUX/ixgbe_netmap_linux.h +++ b/LINUX/ixgbe_netmap_linux.h @@ -499,13 +499,13 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags) nic_i = nm_next(nic_i, lim); } kring->nr_hwcur = head; - rxr->next_to_use = nic_i; // XXX not really used wmb(); /* * IMPORTANT: we must leave one free slot in the ring, * so move nic_i back by one unit */ nic_i = nm_prev(nic_i, lim); + rxr->next_to_use = nic_i; /* used for debug only */ IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(rxr->reg_idx), nic_i); } @@ -593,6 +593,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr) /* Update descriptor */ NM_IXGBE_RX_DESC(ring, i)->read.pkt_addr = htole64(paddr); } + ring->next_to_use = lim; /* used for debug only */ IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(ring_nr), lim); return 1; } From 1003227d7be98f5cc451d0408a326f82e2190271 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 3 Jun 2017 09:23:43 -0700 Subject: [PATCH 0116/2207] LINUX: ixgbe_configure_rx_ring: use ring->reg_idx --- LINUX/ixgbe_netmap_linux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h index 24243fea9..5d8322268 100644 --- a/LINUX/ixgbe_netmap_linux.h +++ b/LINUX/ixgbe_netmap_linux.h @@ -594,7 +594,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr) NM_IXGBE_RX_DESC(ring, i)->read.pkt_addr = htole64(paddr); } ring->next_to_use = lim; /* used for debug only */ - IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(ring_nr), lim); + IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(ring->reg_idx), lim); return 1; } From c6860603d6ccc3efed692368e11c91843747d1df Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sun, 4 Jun 2017 07:34:31 -0700 Subject: [PATCH 0117/2207] LINUX: fix find_queue() method for 2.6 kernels Number of RX queues can be set the same as the number of TX queues, rather than setting it to 1. --- LINUX/netmap_linux.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c index 862a7e7ea..4b0275a98 100644 --- a/LINUX/netmap_linux.c +++ b/LINUX/netmap_linux.c @@ -830,11 +830,9 @@ nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq) } else #endif /* HAVE_SET_CHANNELS */ { - *txq = ifp->real_num_tx_queues; + *txq = *rxq = ifp->real_num_tx_queues; #if defined(NETMAP_LINUX_HAVE_REAL_NUM_RX_QUEUES) *rxq = ifp->real_num_rx_queues; -#else - *rxq = 1; #endif /* HAVE_REAL_NUM_RX_QUEUES */ } } From 071435ca4b9439cfa744db37251630c5ebad803f Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 10 Apr 2017 11:48:51 +0200 Subject: [PATCH 0118/2207] add NKR_NOINTR flag and nma_intr_enable() function --- sys/dev/netmap/netmap.c | 38 ++++++++++++++++++++++++++++++++++++ sys/dev/netmap/netmap_kern.h | 3 +++ sys/dev/netmap/netmap_vale.c | 13 +++++------- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 3a3ae0ee0..c3bb02282 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2764,6 +2764,44 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr) #undef want_rx } +int +nma_intr_enable(struct netmap_adapter *na, int onoff) +{ + bool changed = false; + enum txrx t; + int i; + + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t); i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + int on = !(kring->nr_kflags & NKR_NOINTR); + + if (!!onoff != !!on) { + changed = true; + } + if (onoff) { + kring->nr_kflags &= ~NKR_NOINTR; + } else { + kring->nr_kflags |= NKR_NOINTR; + } + } + } + + if (!changed) { + return 0; /* nothing to do */ + } + + if (!na->nm_intr) { + D("Cannot %s interrupts for %s", onoff ? "enable" : "disable", + na->name); + return -1; + } + + na->nm_intr(na, onoff); + + return 0; +} + /*-------------------- driver support routines -------------------*/ diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 3972f82d6..c8bd4a68a 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -425,6 +425,7 @@ struct netmap_kring { * (used internally by pipes and * by ptnetmap host ports) */ +#define NKR_NOINTR 0x10 /* don't use interrupts on this ring */ uint32_t nr_mode; uint32_t nr_pending_mode; @@ -859,6 +860,8 @@ NMR(struct netmap_adapter *na, enum txrx t) return (t == NR_TX ? na->tx_rings : na->rx_rings); } +int nma_intr_enable(struct netmap_adapter *na, int onoff); + /* * If the NIC is owned by the kernel * (i.e., bridge), neither another bridge nor user can use it; diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index a018f60ec..e3cea78bb 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -1147,9 +1147,8 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na) bna->na_polling_state = bps; bps->bna = bna; - /* disable interrupt if possible */ - if (bna->hwna->nm_intr) - bna->hwna->nm_intr(bna->hwna, 0); + /* disable interrupts if possible */ + nma_intr_enable(bna->hwna, 0); /* start kthread now */ error = nm_bdg_polling_start_kthreads(bps); if (error) { @@ -1157,8 +1156,7 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na) nm_os_free(bps->kthreads); nm_os_free(bps); bna->na_polling_state = NULL; - if (bna->hwna->nm_intr) - bna->hwna->nm_intr(bna->hwna, 1); + nma_intr_enable(bna->hwna, 1); } return error; } @@ -1178,9 +1176,8 @@ nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na) bps->configured = false; nm_os_free(bps); bna->na_polling_state = NULL; - /* reenable interrupt */ - if (bna->hwna->nm_intr) - bna->hwna->nm_intr(bna->hwna, 1); + /* reenable interrupts */ + nma_intr_enable(bna->hwna, 1); return 0; } From d14433438befb728b5a4bf8a4228a6ded1a0ed69 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 10 Apr 2017 12:05:48 +0200 Subject: [PATCH 0119/2207] linux: virtio: implement nm_intr callback --- LINUX/virtio_netmap.h | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h index a8c78b121..1d0faa6a2 100644 --- a/LINUX/virtio_netmap.h +++ b/LINUX/virtio_netmap.h @@ -411,6 +411,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) sizeof(vna->shared_txvhdr) : sizeof(vna->shared_txvhdr.hdr); struct netmap_adapter *token; + int interrupts = !(kring->nr_kflags & NKR_NOINTR); int nospace = 0; virtqueue_disable_cb(vq); @@ -477,7 +478,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags) * hypervisor for notifications, possibly only when it has * freed a considerable amount of pending descriptors. */ - if (nm_kr_txempty(kring) || nospace) { + if (interrupts && (nm_kr_txempty(kring) || nospace)) { virtqueue_enable_cb_delayed(vq); } @@ -509,6 +510,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags) size_t vnet_hdr_len = vi->mergeable_rx_bufs ? sizeof(vna->shared_rxvhdr) : sizeof(vna->shared_rxvhdr.hdr); + int interrupts = !(kring->nr_kflags & NKR_NOINTR); /* XXX netif_carrier_ok ? */ @@ -602,7 +604,9 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags) * the hypervisor to make a call when more used RX buffers will be * ready. */ - virtqueue_enable_cb(vq); + if (interrupts) { + virtqueue_enable_cb(vq); + } ND("[C] h %d c %d t %d hwcur %d hwtail %d", @@ -671,6 +675,29 @@ virtio_netmap_init_buffers(struct virtnet_info *vi) return 1; } +/* Enable/disable interrupts on all virtqueues. */ +static void +virtio_netmap_intr(struct netmap_adapter *na, int onoff) +{ + struct virtnet_info *vi = netdev_priv(na->ifp); + enum txrx t; + int i; + + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t); i++) { + struct virtqueue *vq; + + vq = t == NR_RX ? GET_RX_VQ(vi, i) : GET_TX_VQ(vi, i); + + if (onoff) { + virtqueue_enable_cb(vq); + } else { + virtqueue_disable_cb(vq); + } + } + } +} + /* Update the virtio-net device configurations. Number of queues can * change dinamically, by 'ethtool --set-channels $IFNAME combined $N'. * This is actually the only way virtio-net can currently enable @@ -709,6 +736,7 @@ virtio_netmap_attach(struct virtnet_info *vi) na.nm_txsync = virtio_netmap_txsync; na.nm_rxsync = virtio_netmap_rxsync; na.nm_config = virtio_netmap_config; + na.nm_intr = virtio_netmap_intr; ret = netmap_attach_ext(&na, sizeof(struct netmap_virtio_adapter)); if (ret) { From c3e7955519c8db24da3fe6ca7701c62aa3e4bb50 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 10 Apr 2017 17:03:02 +0200 Subject: [PATCH 0120/2207] netmap_pt: check NKR_NOINTR flag in txsync and rxsync --- sys/dev/netmap/netmap_pt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c index 27eaa0232..b9b668a31 100644 --- a/sys/dev/netmap/netmap_pt.c +++ b/sys/dev/netmap/netmap_pt.c @@ -1356,7 +1356,7 @@ netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring, * go to sleep and we need to be notified by the host when more free * space is available. */ - if (nm_kr_txempty(kring)) { + if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) { /* Reenable notifications. */ ptring->guest_need_kick = 1; /* Double check */ @@ -1421,7 +1421,7 @@ netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring, * we need to be notified by the host when more RX slots have been * completed. */ - if (nm_kr_rxempty(kring)) { + if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) { /* Reenable notifications. */ ptring->guest_need_kick = 1; /* Double check */ From 0d1a41ae3f421ad4b7f075a15641c35ecf0c8cd9 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 10 Apr 2017 17:13:45 +0200 Subject: [PATCH 0121/2207] linux: ptnet: implement nm_intr callback --- LINUX/netmap_ptnet.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c index 9d32d3273..6fbaddf0b 100644 --- a/LINUX/netmap_ptnet.c +++ b/LINUX/netmap_ptnet.c @@ -1210,6 +1210,18 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags) return 0; } +static void +ptnet_nm_intr(struct netmap_adapter *na, int onoff) +{ + struct ptnet_info *pi = netdev_priv(na->ifp); + int i; + + for (i = 0; i < pi->num_rings; i++) { + struct ptnet_queue *pq = pi->queues[i]; + pq->ptring->guest_need_kick = onoff; + } +} + static struct netmap_adapter ptnet_nm_ops = { .nm_register = ptnet_nm_register, .nm_config = ptnet_nm_config, @@ -1218,6 +1230,7 @@ static struct netmap_adapter ptnet_nm_ops = { .nm_krings_create = ptnet_nm_krings_create, .nm_krings_delete = ptnet_nm_krings_delete, .nm_dtor = ptnet_nm_dtor, + .nm_intr = ptnet_nm_intr, }; /* From b9c30b4538ff09e5a95a034e420abd7d8364bd09 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Mon, 10 Apr 2017 15:30:00 +0000 Subject: [PATCH 0122/2207] freebsd: ptnet: implement nm_intr callback --- sys/dev/netmap/if_ptnet.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c index 4c7072774..7c3665e9c 100644 --- a/sys/dev/netmap/if_ptnet.c +++ b/sys/dev/netmap/if_ptnet.c @@ -218,6 +218,7 @@ static void ptnet_update_vnet_hdr(struct ptnet_softc *sc); static int ptnet_nm_register(struct netmap_adapter *na, int onoff); static int ptnet_nm_txsync(struct netmap_kring *kring, int flags); static int ptnet_nm_rxsync(struct netmap_kring *kring, int flags); +static void ptnet_nm_intr(struct netmap_adapter *na, int onoff); static void ptnet_tx_intr(void *opaque); static void ptnet_rx_intr(void *opaque); @@ -463,6 +464,7 @@ ptnet_attach(device_t dev) na_arg.nm_krings_create = ptnet_nm_krings_create; na_arg.nm_krings_delete = ptnet_nm_krings_delete; na_arg.nm_dtor = ptnet_nm_dtor; + na_arg.nm_intr = ptnet_nm_intr; na_arg.nm_register = ptnet_nm_register; na_arg.nm_txsync = ptnet_nm_txsync; na_arg.nm_rxsync = ptnet_nm_rxsync; @@ -1280,6 +1282,18 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags) return 0; } +static void +ptnet_nm_intr(struct netmap_adapter *na, int onoff) +{ + struct ptnet_softc *sc = if_getsoftc(na->ifp); + int i; + + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + pq->ptring->guest_need_kick = onoff; + } +} + static void ptnet_tx_intr(void *opaque) { From 7f699d489f9e465886e7f039805d7d948d102328 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 11 Apr 2017 12:23:33 +0000 Subject: [PATCH 0123/2207] freebsd: vtnet: keep interrupts disabled with NKR_NOINTR --- sys/dev/netmap/if_vtnet_netmap.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h index 4d8d9e367..5950f5812 100644 --- a/sys/dev/netmap/if_vtnet_netmap.h +++ b/sys/dev/netmap/if_vtnet_netmap.h @@ -122,6 +122,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags) struct SOFTC_T *sc = ifp->if_softc; struct vtnet_txq *txq = &sc->vtnet_txqs[ring_nr]; struct virtqueue *vq = txq->vtntx_vq; + int interrupts = !(kring->nr_kflags & NKR_NOINTR); /* * First part: process new packets to send. @@ -179,7 +180,9 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags) ring->head, ring->tail, virtqueue_nused(vq), (virtqueue_dump(vq), 1)); virtqueue_notify(vq); - virtqueue_enable_intr(vq); // like postpone with 0 + if (interrupts) { + virtqueue_enable_intr(vq); // like postpone with 0 + } } @@ -209,7 +212,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags) if (nm_i != kring->nr_hwtail /* && vtnet_txq_below_threshold(txq) == 0*/) { ND(3, "disable intr, hwcur %d", nm_i); virtqueue_disable_intr(vq); - } else { + } else if (interrupts) { ND(3, "enable intr, hwcur %d", nm_i); virtqueue_postpone_intr(vq, VQ_POSTPONE_SHORT); } @@ -277,6 +280,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags) u_int const lim = kring->nkr_num_slots - 1; u_int const head = kring->rhead; int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; + int interrupts = !(kring->nr_kflags & NKR_NOINTR); /* device-specific */ struct SOFTC_T *sc = ifp->if_softc; @@ -334,7 +338,9 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags) kring->nr_hwcur = err; virtqueue_notify(vq); /* After draining the queue may need an intr from the hypervisor */ - vtnet_rxq_enable_intr(rxq); + if (interrupts) { + vtnet_rxq_enable_intr(rxq); + } } ND("[C] h %d c %d t %d hwcur %d hwtail %d", From aea91f165b827d62187ccaf3457aefca78bd83e1 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Tue, 11 Apr 2017 13:55:50 +0000 Subject: [PATCH 0124/2207] freebsd: vtnet: implement nm_intr callback --- sys/dev/netmap/if_vtnet_netmap.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h index 5950f5812..02eeb8d9d 100644 --- a/sys/dev/netmap/if_vtnet_netmap.h +++ b/sys/dev/netmap/if_vtnet_netmap.h @@ -351,6 +351,28 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags) } +/* Enable/disable interrupts on all virtqueues. */ +static void +vtnet_netmap_intr(struct netmap_adapter *na, int onoff) +{ + struct SOFTC_T *sc = na->ifp->if_softc; + int i; + + for (i = 0; i < sc->vtnet_max_vq_pairs; i++) { + struct vtnet_rxq *rxq = &sc->vtnet_rxqs[i]; + struct vtnet_txq *txq = &sc->vtnet_txqs[i]; + struct virtqueue *txvq = txq->vtntx_vq; + + if (onoff) { + vtnet_rxq_enable_intr(rxq); + virtqueue_enable_intr(txvq); + } else { + vtnet_rxq_disable_intr(rxq); + virtqueue_disable_intr(txvq); + } + } +} + /* Make RX virtqueues buffers pointing to netmap buffers. */ static int vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc) @@ -423,6 +445,7 @@ vtnet_netmap_attach(struct SOFTC_T *sc) na.nm_txsync = vtnet_netmap_txsync; na.nm_rxsync = vtnet_netmap_rxsync; na.nm_config = vtnet_netmap_config; + na.nm_intr = vtnet_netmap_intr; na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs; D("max rings %d", sc->vtnet_max_vq_pairs); netmap_attach(&na); From 864c1b15793360f0c87c76b84c3632c0537f3b5c Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 12:51:20 +0200 Subject: [PATCH 0125/2207] linux: ptnet: update irq setup code for Linux 4.12 --- LINUX/netmap_ptnet.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c index 6fbaddf0b..5a9394525 100644 --- a/LINUX/netmap_ptnet.c +++ b/LINUX/netmap_ptnet.c @@ -94,7 +94,9 @@ struct ptnet_info { #endif /* !PTNET_CSB_ALLOC */ /* MSI-X interrupt data structures. */ +#ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX struct msix_entry *msix_entries; +#endif int num_rings; int num_tx_rings; @@ -751,6 +753,17 @@ ptnet_netpoll(struct net_device *netdev) } #endif + +unsigned int +ptnet_get_irq_vector(struct ptnet_info *pi, unsigned int i) +{ +#ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX + return pi->msix_entries[i].vector; +#else + return pci_irq_vector(pi->pdev, i); +#endif +} + static int ptnet_irqs_init(struct ptnet_info *pi) { @@ -758,6 +771,7 @@ ptnet_irqs_init(struct ptnet_info *pi) int i; /* Allocate the MSI-X interrupt vectors we need. */ +#ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX pi->msix_entries = kzalloc(sizeof(*pi->msix_entries) * pi->num_rings, GFP_KERNEL); if (!pi->msix_entries) { @@ -777,6 +791,10 @@ ptnet_irqs_init(struct ptnet_info *pi) } ret = pci_enable_msix(pi->pdev, pi->msix_entries, pi->num_rings); +#else + ret = pci_alloc_irq_vectors(pi->pdev, pi->num_rings, pi->num_rings, + PCI_IRQ_MSIX); +#endif if (ret) { pr_err("Failed to enable msix vectors (%d)\n", ret); goto err_masks; @@ -786,24 +804,24 @@ ptnet_irqs_init(struct ptnet_info *pi) struct ptnet_queue *pq = pi->queues[i]; irq_handler_t handler = (i < pi->num_tx_rings) ? ptnet_tx_intr : ptnet_rx_intr; + unsigned int vector = ptnet_get_irq_vector(pi, i); snprintf(pq->msix_name, sizeof(pq->msix_name), "%s-%d", pi->netdev->name, i); - ret = request_irq(pi->msix_entries[i].vector, handler, - 0, pq->msix_name, pq); + ret = request_irq(vector, handler, 0, pq->msix_name, pq); if (ret) { pr_err("Unable to allocate interrupt (%d)\n", ret); goto err_irqs; } pr_info("IRQ for ring #%d --> %u, handler %p\n", i, - pi->msix_entries[i].vector, handler); + vector, handler); } return 0; err_irqs: for (; i>=0; i--) { - free_irq(pi->msix_entries[i].vector, pi->queues[i]); + free_irq(ptnet_get_irq_vector(pi, i), pi->queues[i]); } i = pi->num_rings-1; err_masks: @@ -822,13 +840,17 @@ ptnet_irqs_fini(struct ptnet_info *pi) for (i=0; inum_rings; i++) { struct ptnet_queue *pq = pi->queues[i]; - free_irq(pi->msix_entries[i].vector, pq); + free_irq(ptnet_get_irq_vector(pi, i), pq); if (pq->msix_affinity_mask) { free_cpumask_var(pq->msix_affinity_mask); } } +#ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX pci_disable_msix(pi->pdev); kfree(pi->msix_entries); +#else + pci_free_irq_vectors(pi->pdev); +#endif } static int ptnet_nm_register(struct netmap_adapter *na, int onoff); From 010e27f9d7e0eebc1dee334e7fe02d5da1bb4d3f Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 12:57:12 +0200 Subject: [PATCH 0126/2207] configure: add support for HAVE_PCI_ENABLE_MSIX --- LINUX/configure | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/LINUX/configure b/LINUX/configure index 5bc1314bb..5d1a53068 100755 --- a/LINUX/configure +++ b/LINUX/configure @@ -1411,6 +1411,17 @@ EOF } EOF +# pci_enable_msix or pci_alloc_irq_vectors ? + add_test 'have PCI_ENABLE_MSIX' < + + int + dummy(struct pci_dev *dev, struct msix_entry *entries, int nvec) { + return pci_enable_msix(dev, entries, nvec); + } +EOF + + ##################################################### # checks related to drivers # ##################################################### From 3538df9489bd9d237b480a6d3e7a74158d528c85 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 13:10:41 +0200 Subject: [PATCH 0127/2207] linux: ptnet: reuse cpumask code --- LINUX/netmap_ptnet.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c index 5a9394525..7964d7a35 100644 --- a/LINUX/netmap_ptnet.c +++ b/LINUX/netmap_ptnet.c @@ -780,13 +780,6 @@ ptnet_irqs_init(struct ptnet_info *pi) } for (i=0; inum_rings; i++) { - struct ptnet_queue *pq = pi->queues[i]; - - memset(&pq->msix_affinity_mask, 0, sizeof(pq->msix_affinity_mask)); - if (!alloc_cpumask_var(&pq->msix_affinity_mask, GFP_KERNEL)) { - pr_err("Failed to alloc cpumask var\n"); - goto err_masks; - } pi->msix_entries[i].entry = i; } @@ -797,7 +790,17 @@ ptnet_irqs_init(struct ptnet_info *pi) #endif if (ret) { pr_err("Failed to enable msix vectors (%d)\n", ret); - goto err_masks; + goto err_alloc; + } + + for (i=0; inum_rings; i++) { + struct ptnet_queue *pq = pi->queues[i]; + + memset(&pq->msix_affinity_mask, 0, sizeof(pq->msix_affinity_mask)); + if (!alloc_cpumask_var(&pq->msix_affinity_mask, GFP_KERNEL)) { + pr_err("Failed to alloc cpumask var\n"); + goto err_masks; + } } for (i=0; inum_rings; i++) { @@ -828,7 +831,10 @@ ptnet_irqs_init(struct ptnet_info *pi) for (; i>=0; i--) { free_cpumask_var(pi->queues[i]->msix_affinity_mask); } - +err_alloc: +#ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX + kfree(pi->msix_entries); +#endif return ret; } From 0446b522f99cdc550d997d192bd63cb067339b90 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 13:28:01 +0200 Subject: [PATCH 0128/2207] linux: ptnet: uniform return code for IRQ allocation routines --- LINUX/netmap_ptnet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c index 7964d7a35..e57526440 100644 --- a/LINUX/netmap_ptnet.c +++ b/LINUX/netmap_ptnet.c @@ -784,11 +784,14 @@ ptnet_irqs_init(struct ptnet_info *pi) } ret = pci_enable_msix(pi->pdev, pi->msix_entries, pi->num_rings); + if (ret == 0) { /* ok */ + ret = pi->num_rings; + } #else ret = pci_alloc_irq_vectors(pi->pdev, pi->num_rings, pi->num_rings, PCI_IRQ_MSIX); #endif - if (ret) { + if (ret != pi->num_rings) { pr_err("Failed to enable msix vectors (%d)\n", ret); goto err_alloc; } From 8b3fbed7145b56d23fe6246d8108589b0f47b1cd Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 15:51:31 +0200 Subject: [PATCH 0129/2207] freebsd: spin on trylock in netmap_mem2_ofstophys() This is necessary to avoid lock order reversal panic. Fixes #314. --- sys/dev/netmap/netmap_kern.h | 1 + sys/dev/netmap/netmap_mem2.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index c8bd4a68a..4ada1c980 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -88,6 +88,7 @@ #define NM_MTX_INIT(m) sx_init(&(m), #m) #define NM_MTX_DESTROY(m) sx_destroy(&(m)) #define NM_MTX_LOCK(m) sx_xlock(&(m)) +#define NM_MTX_SPINLOCK(m) while (!sx_try_xlock(&(m))) ; #define NM_MTX_UNLOCK(m) sx_xunlock(&(m)) #define NM_MTX_ASSERT(m) sx_assert(&(m), SA_XLOCKED) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index ad990f061..b4152abf4 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -241,6 +241,7 @@ netmap_mem_get_id(struct netmap_mem_d *nmd) #define NMA_LOCK_INIT(n) NM_MTX_INIT((n)->nm_mtx) #define NMA_LOCK_DESTROY(n) NM_MTX_DESTROY((n)->nm_mtx) #define NMA_LOCK(n) NM_MTX_LOCK((n)->nm_mtx) +#define NMA_SPINLOCK(n) NM_MTX_SPINLOCK((n)->nm_mtx) #define NMA_UNLOCK(n) NM_MTX_UNLOCK((n)->nm_mtx) #ifdef NM_DEBUG_MEM_PUTGET @@ -611,7 +612,14 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) vm_paddr_t pa; struct netmap_obj_pool *p; +#if defined(__FreeBSD__) + /* This function is called by netmap_dev_pager_fault(), which holds a + * non-sleepable lock since FreeBSD 12. Since we cannot sleep, we + * spin on the trylock. */ + NMA_SPINLOCK(nmd); +#else NMA_LOCK(nmd); +#endif p = nmd->pools; for (i = 0; i < NETMAP_POOLS_NR; offset -= p[i].memtotal, i++) { From a90872096ebed6c8d711fb15aee52cf313603b23 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 20:59:06 +0200 Subject: [PATCH 0130/2207] linux: igb: fix updating next_to_use --- LINUX/if_igb_netmap.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h index f5cf65f25..817c63d11 100644 --- a/LINUX/if_igb_netmap.h +++ b/LINUX/if_igb_netmap.h @@ -176,10 +176,10 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags) wmb(); /* synchronize writes to the NIC ring */ - txr->next_to_use = nic_i; /* XXX what for ? */ /* (re)start the tx unit up to slot nic_i (excluded) */ + txr->next_to_use = nic_i; writel(nic_i, txr->tail); - mmiowb(); // XXX where do we need this ? + mmiowb(); // XXX why do we need this ? } /* @@ -192,7 +192,6 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags) D("TDH wrap %d", nic_i); nic_i -= kring->nkr_num_slots; } - txr->next_to_use = nic_i; kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); } out: @@ -284,12 +283,12 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags) } kring->nr_hwcur = head; wmb(); - rxr->next_to_use = nic_i; // XXX not really used /* * IMPORTANT: we must leave one free slot in the ring, * so move nic_i back by one unit */ nic_i = nm_prev(nic_i, lim); + rxr->next_to_use = nic_i; writel(nic_i, rxr->tail); } @@ -368,12 +367,12 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr) rx_desc->read.hdr_addr = 0; rx_desc->read.pkt_addr = htole64(paddr); } - rxr->next_to_use = 0; /* preserve buffers already made available to clients */ i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[reg_idx]); wmb(); /* Force memory writes to complete */ ND("%s rxr%d.tail %d", na->name, reg_idx, i); + rxr->next_to_use = i; writel(i, rxr->tail); return 1; // success } From 0cbf4e860f590b52c15bbf86af0a0d634d1c80f3 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 21:09:43 +0200 Subject: [PATCH 0131/2207] some cleanup in netmap_kern.h --- sys/dev/netmap/netmap_kern.h | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index c8bd4a68a..08f563dbd 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -130,7 +130,7 @@ struct nm_selinfo { }; -// XXX linux struct, not used in FreeBSD +/* Linux structs, not used in FreeBSD. */ struct net_device_ops { }; struct ethtool_ops { @@ -200,8 +200,8 @@ struct hrtimer { #define NETMAP_KERNEL_XCHANGE_POINTERS _IO('i', 180) #define NETMAP_KERNEL_SEND_SHUTDOWN_SIGNAL _IO_direct('i', 195) -//Empty data structures are not permitted by MSVC compiler -//XXX_ale, try to solve this problem +/* Empty data structures are not allowed by MSVC compiler, so + * we workaround. */ struct net_device_ops{ char data[1]; }; @@ -579,7 +579,7 @@ nm_prev(uint32_t i, uint32_t lim) +-----------------+ +-----------------+ | | | | - |XXX free slot XXX| |XXX free slot XXX| + | free | | free | +-----------------+ +-----------------+ head->| owned by user |<-hwcur | not sent to nic |<-hwcur | | | yet | @@ -899,8 +899,8 @@ struct netmap_vp_adapter { /* VALE software port */ struct netmap_hw_adapter { /* physical device */ struct netmap_adapter up; - struct net_device_ops nm_ndo; // XXX linux only - struct ethtool_ops nm_eto; // XXX linux only + struct net_device_ops nm_ndo; /* Linux only */ + struct ethtool_ops nm_eto; /* Linux only */ const struct ethtool_ops* save_ethtool; int (*nm_hw_register)(struct netmap_adapter *, int onoff); @@ -1280,9 +1280,6 @@ nm_set_native_flags(struct netmap_adapter *na) ifp->if_transmit = netmap_transmit; #elif defined (_WIN32) (void)ifp; /* prevent a warning */ - //XXX_ale can we just comment those? - //na->if_transmit = ifp->if_transmit; - //ifp->if_transmit = netmap_transmit; #else na->if_transmit = (void *)ifp->netdev_ops; ifp->netdev_ops = &((struct netmap_hw_adapter *)na)->nm_ndo; @@ -1309,8 +1306,6 @@ nm_clear_native_flags(struct netmap_adapter *na) ifp->if_transmit = na->if_transmit; #elif defined(_WIN32) (void)ifp; /* prevent a warning */ - //XXX_ale can we just comment those? - //ifp->if_transmit = na->if_transmit; #else ifp->netdev_ops = (void *)na->if_transmit; ifp->ethtool_ops = ((struct netmap_hw_adapter*)na)->save_ethtool; @@ -1432,8 +1427,8 @@ int netmap_get_hw_na(struct ifnet *ifp, * * VALE only supports unicast or broadcast. The lookup * function can return 0 .. NM_BDG_MAXPORTS-1 for regular ports, - * NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 for unknown. - * XXX in practice "unknown" might be handled same as broadcast. + * NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 to indicate + * drop. */ typedef u_int (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr, struct netmap_vp_adapter *); @@ -1472,7 +1467,7 @@ int netmap_bdg_config(struct nmreq *nmr); #ifdef WITH_PIPES /* max number of pipes per device */ -#define NM_MAXPIPES 64 /* XXX how many? */ +#define NM_MAXPIPES 64 /* XXX this should probably be a sysctl */ void netmap_pipe_dealloc(struct netmap_adapter *); int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, struct netmap_mem_d *nmd, int create); @@ -1824,7 +1819,7 @@ struct netmap_priv_d { uint32_t np_flags; /* from the ioctl */ u_int np_qfirst[NR_TXRX], np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */ - uint16_t np_txpoll; /* XXX and also np_rxpoll ? */ + uint16_t np_txpoll; int np_sync_flags; /* to be passed to nm_sync */ int np_refs; /* use with NMG_LOCK held */ From 384cbe3d4ad803c4589e3ae71cf750f9559317f4 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 21:14:34 +0200 Subject: [PATCH 0132/2207] vale: remove an if branch from the datapath --- sys/dev/netmap/netmap_vale.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index e3cea78bb..734ba55c2 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -1652,7 +1652,7 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring, */ if (((buf[6] & 1) == 0) && (na->last_smac != smac)) { /* valid src */ uint8_t *s = buf+6; - sh = nm_bridge_rthash(s); // XXX hash of source + sh = nm_bridge_rthash(s); /* hash of source */ /* update source port forwarding entry */ na->last_smac = ht[sh].mac = smac; /* XXX expire ? */ ht[sh].ports = mysrc; @@ -1662,11 +1662,10 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring, } dst = NM_BDG_BROADCAST; if ((buf[0] & 1) == 0) { /* unicast */ - dh = nm_bridge_rthash(buf); // XXX hash of dst + dh = nm_bridge_rthash(buf); /* hash of dst */ if (ht[dh].mac == dmac) { /* found dst */ dst = ht[dh].ports; } - /* XXX otherwise return NM_BDG_UNKNOWN ? */ } return dst; } @@ -1780,10 +1779,8 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na); if (netmap_verbose > 255) RD(5, "slot %d port %d -> %d", i, me, dst_port); - if (dst_port == NM_BDG_NOPORT) + if (dst_port >= NM_BDG_NOPORT) continue; /* this packet is identified to be dropped */ - else if (unlikely(dst_port > NM_BDG_MAXPORTS)) - continue; else if (dst_port == NM_BDG_BROADCAST) dst_ring = 0; /* broadcasts always go to ring 0 */ else if (unlikely(dst_port == me || From 3b0058d1b22eead597c3caee8987e7c74940c38d Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 21:53:37 +0200 Subject: [PATCH 0133/2207] LINUX: some cleanups in bsd_glue.h --- LINUX/bsd_glue.h | 17 +++++++---------- sys/dev/netmap/netmap_kern.h | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h index 39f4c9d94..4eab00158 100644 --- a/LINUX/bsd_glue.h +++ b/LINUX/bsd_glue.h @@ -182,7 +182,7 @@ typedef int bus_size_t; typedef int bus_dma_segment_t; typedef void * bus_addr_t; #define vm_paddr_t phys_addr_t -/* XXX the 'off_t' on Linux corresponds to a 'long' */ +/* the 'off_t' on Linux corresponds to a 'long' */ #define vm_offset_t uint32_t #define vm_ooffset_t unsigned long struct thread; @@ -269,7 +269,6 @@ struct thread; * * if_xname name device name * we would use "features" but it is all taken. - * XXX check for conflict in flags use. * * In netmap we use if_pspare[0] to point to the netmap_adapter, * in linux we have no spares so we overload ax25_ptr, and the detection @@ -319,7 +318,7 @@ static inline void mtx_unlock(safe_spinlock_t *m) } #define mtx_init(a, b, c, d) spin_lock_init(&((a)->sl)) -#define mtx_destroy(a) // XXX spin_lock_destroy(a) +#define mtx_destroy(a) #define mtx_lock_spin(a) mtx_lock(a) #define mtx_unlock_spin(a) mtx_unlock(a) @@ -340,10 +339,6 @@ static inline void mtx_unlock(safe_spinlock_t *m) #define BDG_SET_VAR(lval, p) ((lval) = (p)) #define BDG_GET_VAR(lval) (lval) -// XXX do we need GPF_ZERO ? -// XXX do we need GFP_DMA for slots ? -// http://www.mjmwired.net/kernel/Documentation/DMA-API.txt - #ifndef ilog2 /* not in 2.6.18 */ static inline int ilog2(uint64_t n) { @@ -355,6 +350,9 @@ static inline int ilog2(uint64_t n) } #endif /* ilog2 */ +/* XXX do we need GFP_DMA for slots ? + * Documentation/DMA-API.txt */ + #define contigmalloc(sz, ty, flags, a, b, pgsz, c) ({ \ unsigned int order_ = \ ilog2(roundup_pow_of_two(sz)/PAGE_SIZE); \ @@ -378,12 +376,11 @@ static inline int ilog2(uint64_t n) struct nm_linux_selrecord_t; #define NM_SELRECORD_T struct nm_linux_selrecord_t -#define netmap_knlist_destroy(x) // XXX todo +#define netmap_knlist_destroy(x) // TODO #define tsleep(a, b, c, t) msleep(10) -// #define wakeup(sw) // XXX double check -#define microtime do_gettimeofday // debugging +#define microtime do_gettimeofday /* debugging */ /* diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 08f563dbd..56b0f151c 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -98,7 +98,7 @@ #define MBUF_TRANSMIT(na, ifp, m) ((na)->if_transmit(ifp, m)) #define GEN_TX_MBUF_IFP(m) ((m)->m_pkthdr.rcvif) -#define NM_ATOMIC_T volatile int // XXX ? +#define NM_ATOMIC_T volatile int /* required by atomic/bitops.h */ /* atomic operations */ #include #define NM_ATOMIC_TEST_AND_SET(p) (!atomic_cmpset_acq_int((p), 0, 1)) From 1d0aeeac6848584e31d03b9c5bf28341010a2c01 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 21:59:32 +0200 Subject: [PATCH 0134/2207] netmap_mem2: some cleanup --- sys/dev/netmap/netmap_mem2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index ad990f061..5de523383 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -638,7 +638,7 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) + p[NETMAP_BUF_POOL].memtotal); NMA_UNLOCK(nmd); #ifndef _WIN32 - return 0; // XXX bad address + return 0; /* bad address */ #else vm_paddr_t res; res.QuadPart = 0; @@ -833,7 +833,6 @@ netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_ if (len > p->_objsize) { D("%s request size %d too large", p->name, len); - // XXX cannot reduce the size return NULL; } @@ -932,7 +931,7 @@ netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr) netmap_obj_malloc(&(n)->pools[NETMAP_BUF_POOL], netmap_mem_bufsize(n), _pos, _index) -#if 0 // XXX unused +#if 0 /* currently unused */ /* Return the index associated to the given packet buffer */ #define netmap_buf_index(n, v) \ (netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v)) / NETMAP_BDG_BUF_SIZE(n)) @@ -1358,7 +1357,7 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) #elif defined(_WIN32) (void)i; (void)lim; - D("unsupported on Windows"); //XXX_ale, really? + D("unsupported on Windows"); #else /* linux */ for (i = 2; i < lim; i++) { netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &p->lut[i].paddr); @@ -1374,7 +1373,7 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na) #if defined(__FreeBSD__) D("unsupported on FreeBSD"); #elif defined(_WIN32) - D("unsupported on Windows"); //XXX_ale, really? + D("unsupported on Windows"); #else /* linux */ int i, lim = p->_objtotal; From 997062695ee3ca87e87809044b9471f28d625f94 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sat, 10 Jun 2017 22:16:45 +0200 Subject: [PATCH 0135/2207] pkt-gen: some cleanups --- PORTING | 2 +- apps/pkt-gen/pkt-gen.c | 16 ++++++++-------- sys/net/netmap.h | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/PORTING b/PORTING index 4cafd4e77..807b74537 100644 --- a/PORTING +++ b/PORTING @@ -43,7 +43,7 @@ Device driver patches The argument is either the ifnet or the private device descriptor. This is in foo_attach() on FreeBSD, and somewhere in the path of - XXX foo_open() in Linux + foo_probe() in Linux + near the code called on device removal, add
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f2ca1496a..a34cdc065 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -203,12 +203,12 @@ struct pkt {
 		struct {
 			struct ip ip;
 			struct udphdr udp;
-			uint8_t body[MAX_BODYSIZE];	// XXX hardwired
+			uint8_t body[MAX_BODYSIZE];	/* hardwired */
 		} ipv4;
 		struct {
 			struct ip6_hdr ip;
 			struct udphdr udp;
-			uint8_t body[MAX_BODYSIZE];	// XXX hardwired
+			uint8_t body[MAX_BODYSIZE];	/* hardwired */
 		} ipv6;
 	};
 } __attribute__((__packed__));
@@ -1214,7 +1214,7 @@ ping_body(void *data)
 	void *frame;
 	int size;
 	struct timespec ts, now, last_print;
-	struct timespec nexttime = { 0, 0}; // XXX silence compiler
+	struct timespec nexttime = {0, 0}; /* silence compiler */
 	uint64_t sent = 0, n = targ->g->npackets;
 	uint64_t count = 0, t_cur, t_min = ~0, av = 0;
 	uint64_t g_min = ~0, g_av = 0;
@@ -1445,6 +1445,7 @@ pong_body(void *data)
 				dpkt = (uint16_t *)dst;
 				spkt = (uint16_t *)src;
 				nm_pkt_copy(src, dst, slot->len);
+				/* swap source and destination MAC */
 				dpkt[0] = spkt[3];
 				dpkt[1] = spkt[4];
 				dpkt[2] = spkt[5];
@@ -1452,7 +1453,6 @@ pong_body(void *data)
 				dpkt[4] = spkt[1];
 				dpkt[5] = spkt[2];
 				txring->slot[txcur].len = slot->len;
-				/* XXX swap src dst mac */
 				txcur = nm_ring_next(txring, txcur);
 				txavail--;
 				sent++;
@@ -2569,7 +2569,7 @@ main(int arc, char **argv)
 	g.src_mac.name = NULL;
 	g.pkt_size = 60;
 	g.nthreads = 1;
-	g.cpus = 1;		// default
+	g.cpus = 1;		/* default */
 	g.forever = 1;
 	g.tx_rate = 0;
 	g.frags = 1;
@@ -2659,7 +2659,7 @@ main(int arc, char **argv)
 			break;
 
 		case 'I':
-			g.options |= OPT_INDIRECT;	/* XXX use indirect buffer */
+			g.options |= OPT_INDIRECT;	/* use indirect buffers */
 			break;
 
 		case 'l':	/* pkt_size */
@@ -2682,8 +2682,8 @@ main(int arc, char **argv)
 			g.wait_link = atoi(optarg);
 			break;
 
-		case 'W': /* XXX changed default */
-			g.forever = 0; /* do not exit rx even with no traffic */
+		case 'W':
+			g.forever = 0; /* exit RX with no traffic */
 			break;
 
 		case 'b':	/* burst */
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3543426b6..4ac4f92e3 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -565,13 +565,13 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
+#ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
  * in ws2def.h but not sure if they are in the form we need.
- * XXX so we redefine them
- * in a convenient way to use for DeviceIoControl signatures
+ * We therefore redefine them in a convenient way to use for DeviceIoControl
+ * signatures.
  */
-#ifdef _WIN32
 #undef _IO	// ws2def.h
 #define _WIN_NM_IOCTL_TYPE 40000
 #define _IO(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \

From 2ae1063cb20301e2fbb5409fdd72fa83d7ff5db0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 10 Jun 2017 22:22:41 +0200
Subject: [PATCH 0136/2207] netmap_mem2: implement delete_rings callback for
 ptnetmap

---
 sys/dev/netmap/netmap_mem2.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 5de523383..3b20fcc8b 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2253,11 +2253,17 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 static void
 netmap_mem_pt_guest_rings_delete(struct netmap_adapter *na)
 {
-	/* TODO: remove?? */
 #if 0
-	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)na->nm_mem;
-	struct mem_pt_if *ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem,
-								na->ifp);
+	enum txrx t;
+
+	for_rx_tx(t) {
+		u_int i;
+		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			struct netmap_kring *kring = &NMR(na, t)[i];
+
+			kring->ring = NULL;
+		}
+	}
 #endif
 }
 

From d26a0895f0016f9f2354f56420a1f25bd3d2a44d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 12 Jun 2017 14:31:51 +0200
Subject: [PATCH 0137/2207] linux: virtio_net: fix logic in netmap_register
 callback

The fix is needed to allow hw rings and host rings to be open
separately and independently, in arbitrary order.
---
 LINUX/virtio_netmap.h | 127 ++++++++++++++++++++----------------------
 1 file changed, 59 insertions(+), 68 deletions(-)

diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index bca22b283..41e3c7a4d 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -261,93 +261,82 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct netmap_virtio_adapter *vna = (struct netmap_virtio_adapter *)na;
 	struct ifnet *ifp = na->ifp;
 	struct virtnet_info *vi = netdev_priv(ifp);
+	int hwrings_pending = 0, hwrings;
 	bool was_up = false;
 	int error = 0;
 	enum txrx t;
 	int i;
 
-	if (na == NULL)
-		return EINVAL;
-
-	if (na->active_fds > 0) {
-		/* virtio-net adapter currently does not support single-queue
-		 * mode. As a consequence, register (unregister) operations
-		 * only have effect with first (last) user.*/
-		return 0;
-	}
-
 	/* These virtio-net driver patches do not support single-queue mode
 	 * (modifications would be needed to free_unused_bufs()
 	 * free_receive_bufs()). As a result, we fail here if we detect
-	 * the user is trying to open only a subset of the rings. */
-	if (onoff) {
-		int hwrings_pending = 0;
-		int hwrings = nma_get_nrings(na, NR_TX) +
-				nma_get_nrings(na, NR_RX);
-
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+	 * the user is trying to open or close only a subset of the rings. */
+	hwrings = nma_get_nrings(na, NR_TX) + nma_get_nrings(na, NR_RX);
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(na, t); i++) {
+			struct netmap_kring *kring = &NMR(na, t)[i];
 
-				if (nm_kring_pending_on(kring)) {
-					hwrings_pending ++;
-				}
+			if ((onoff && nm_kring_pending_on(kring)) ||
+				(!onoff && nm_kring_pending_off(kring))) {
+				hwrings_pending ++;
 			}
 		}
+	}
 
-		if (!(hwrings_pending == 0 || hwrings_pending == hwrings)) {
-			D("virtio-net native adapter can only open "
-			  "all RX and TX hw rings");
-			return EINVAL;
-		}
+	if (!(hwrings_pending == 0 || hwrings_pending == hwrings)) {
+		D("virtio-net native adapter can only open "
+		  "all RX and TX hw rings");
+		return EINVAL;
 	}
 
 	/* It's important to make sure each virtnet_close() matches
 	 * a virtnet_open(), otherwise a napi_disable() is not matched by
 	 * a napi_enable(), which results in a deadlock. */
-	if (netif_running(ifp)) {
+	if (hwrings_pending && netif_running(ifp)) {
 		was_up = true;
 		/* Down the interface. This also disables napi. */
 		virtnet_close(ifp);
 	}
 
 	if (onoff) {
-		/* TX shared virtio-net header must be zeroed because its
-		 * content is exposed to the host. RX shared virtio-net
-		 * header is zeroed only for security reasons. */
-		memset(&vna->shared_txvhdr, 0, sizeof(vna->shared_txvhdr));
-		memset(&vna->shared_rxvhdr, 0, sizeof(vna->shared_rxvhdr));
-
-		/* Get and free any used buffers. This is necessary
-		 * before calling free_unused_bufs(), that uses
-		 * virtqueue_detach_unused_buf(). */
-		virtio_netmap_clean_used_rings(vi, na);
-
-		/* Initialize scatter-gather lists used to publish netmap
-		 * buffers through virtio descriptors, in such a way that each
-		 * each scatter-gather list contains exactly one descriptor
-		 * (which can point to a netmap buffer). This initialization is
-		 * necessary to prevent the virtio frontend (host) to think
-		 * we are using multi-descriptors scatter-gather lists. */
-		virtio_netmap_init_sgs(vi);
-
-		/* We have to drain the RX virtqueues, otherwise the
-		 * virtio_netmap_init_buffer() called by the subsequent
-		 * virtnet_open() cannot link the netmap buffers to the
-		 * virtio RX ring.
-		 * The unused buffers point to memory allocated by
-		 * the virtio-driver (e.g. sk_buffs). We need to free that
-		 * memory, otherwise we have leakage.
-		 */
-		free_unused_bufs(vi);
-
-		/* Also free the pages allocated by the driver. Since
-		 * Linux 4.10, free_receive_bufs() takes the rtnl lock
-		 * to support XDP. To avoid deadlock, we temporarily
-		 * release the lock during this call. */
-		rtnl_unlock();
-		free_receive_bufs(vi);
-		rtnl_lock();
+		if (hwrings_pending) {
+			/* TX shared virtio-net header must be zeroed because its
+			 * content is exposed to the host. RX shared virtio-net
+			 * header is zeroed only for security reasons. */
+			memset(&vna->shared_txvhdr, 0, sizeof(vna->shared_txvhdr));
+			memset(&vna->shared_rxvhdr, 0, sizeof(vna->shared_rxvhdr));
+
+			/* Get and free any used buffers. This is necessary
+			 * before calling free_unused_bufs(), that uses
+			 * virtqueue_detach_unused_buf(). */
+			virtio_netmap_clean_used_rings(vi, na);
+
+			/* Initialize scatter-gather lists used to publish netmap
+			 * buffers through virtio descriptors, in such a way that each
+			 * each scatter-gather list contains exactly one descriptor
+			 * (which can point to a netmap buffer). This initialization is
+			 * necessary to prevent the virtio frontend (host) to think
+			 * we are using multi-descriptors scatter-gather lists. */
+			virtio_netmap_init_sgs(vi);
+
+			/* We have to drain the RX virtqueues, otherwise the
+			 * virtio_netmap_init_buffer() called by the subsequent
+			 * virtnet_open() cannot link the netmap buffers to the
+			 * virtio RX ring.
+			 * The unused buffers point to memory allocated by
+			 * the virtio-driver (e.g. sk_buffs). We need to free that
+			 * memory, otherwise we have leakage.
+			 */
+			free_unused_bufs(vi);
+
+			/* Also free the pages allocated by the driver. Since
+			 * Linux 4.10, free_receive_bufs() takes the rtnl lock
+			 * to support XDP. To avoid deadlock, we temporarily
+			 * release the lock during this call. */
+			rtnl_unlock();
+			free_receive_bufs(vi);
+			rtnl_lock();
+		}
 
 		/* enable netmap mode */
 		for_rx_tx(t) {
@@ -372,11 +361,13 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		/* Get and free any used buffer. This is necessary
-		 * before calling virtqueue_detach_unused_buf(). */
-		virtio_netmap_clean_used_rings(vi, na);
+		if (hwrings_pending) {
+			/* Get and free any used buffer. This is necessary
+			 * before calling virtqueue_detach_unused_buf(). */
+			virtio_netmap_clean_used_rings(vi, na);
 
-		virtio_netmap_reclaim_unused(vi);
+			virtio_netmap_reclaim_unused(vi);
+		}
 	}
 
 	if (was_up) {

From c4d9a8a23f81bf2ce2f161ab1a604153f7a166ac Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 13 Jun 2017 10:41:17 +0200
Subject: [PATCH 0138/2207] man: import fixes from FreeBSD head

---
 share/man/man4/netmap.4 | 72 +++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 35 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 3b586c953..e86d3d17a 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -27,16 +27,15 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 14, 2015
+.Dd March 2, 2017
 .Dt NETMAP 4
 .Os
 .Sh NAME
 .Nm netmap
 .Nd a framework for fast packet I/O
-.br
 .Nm VALE
 .Nd a fast VirtuAl Local Ethernet using the netmap API
-.br
+.Pp
 .Nm netmap pipes
 .Nd a shared memory packet transport channel
 .Sh SYNOPSIS
@@ -61,7 +60,7 @@ implementing a very fast and modular in-kernel software switch/dataplane;
 a shared memory packet transport channel;
 .It Nm netmap monitors
 a mechanism similar to
-.Xr bpf
+.Xr bpf 4
 to capture traffic
 .El
 .Pp
@@ -85,7 +84,7 @@ NICs without native
 .Nm
 support can still use the API in emulated mode,
 which uses unmodified device drivers and is 3-5 times faster than
-.Xr bpf
+.Xr bpf 4
 or raw sockets.
 .Pp
 Userspace clients can dynamically switch NICs into
@@ -175,8 +174,9 @@ ports (including
 and
 .Nm netmap pipe
 ports).
-Simpler, higher level functions are described in section
-.Xr LIBRARIES .
+Simpler, higher level functions are described in the
+.Sx LIBRARIES
+section.
 .Pp
 Ports and rings are created and controlled through a file descriptor,
 created by opening a special device
@@ -191,14 +191,14 @@ argument.
 .Va arg.nr_name
 specifies the netmap port name, as follows:
 .Bl -tag -width XXXX
-.It Dv OS network interface name (e.g. 'em0', 'eth1', ... )
+.It Dv OS network interface name (e.g., 'em0', 'eth1', ... )
 the data path of the NIC is disconnected from the host stack,
 and the file descriptor is bound to the NIC (one or all queues),
 or to the host stack;
 .It Dv valeSSS:PPP
 the file descriptor is bound to port PPP of VALE switch SSS.
 Switch instances and ports are dynamically created if necessary.
-.br
+.Pp
 Both SSS and PPP have the form [0-9a-zA-Z_]+ , the string
 cannot exceed IFNAMSIZ characters, and PPP cannot
 be the name of any existing OS network interface.
@@ -340,14 +340,14 @@ should not be assumed to be a power of two.
 .Pp
 .Va head
 is the first slot available to userspace;
-.br
+.Pp
 .Va cur
 is the wakeup point:
 select/poll will unblock when
 .Va tail
 passes
 .Va cur ;
-.br
+.Pp
 .Va tail
 is the first slot reserved to the kernel.
 .Pp
@@ -419,7 +419,7 @@ Below is an example of the evolution of a TX ring:
 .Fn select
 and
 .Fn poll
-will block if there is no space in the ring, i.e.
+will block if there is no space in the ring, i.e.,
 .Dl ring->cur == ring->tail
 and return when new slots have become available.
 .Pp
@@ -453,7 +453,7 @@ slots up to
 are returned to the kernel for further receives, and
 .Va tail
 may advance to report new incoming packets.
-.br
+.Pp
 Below is an example of the evolution of an RX ring:
 .Bd -literal
     after the syscall, there are some (h)eld and some (R)eceived slots
@@ -498,7 +498,8 @@ can be delayed indefinitely.
 This flag helps detect
 when packets have been sent and a file descriptor can be closed.
 .It NS_FORWARD
-When a ring is in 'transparent' mode,
+When a ring is in 'transparent' mode (see
+.Sx TRANSPARENT MODE ) ,
 packets marked with this flag are forwarded to the other endpoint
 at the next system call, thus restoring (in a selective way)
 the connection between a NIC and the host stack.
@@ -509,7 +510,7 @@ packet must not be used in the learning bridge code.
 indicates that the packet's payload is in a user-supplied buffer
 whose user virtual address is in the 'ptr' field of the slot.
 The size can reach 65535 bytes.
-.br
+.Pp
 This is only supported on the transmit ring of
 .Nm VALE
 ports, and it helps reducing data copies in the interconnection
@@ -591,8 +592,8 @@ indicate the size of transmit and receive rings.
 indicate the number of transmit
 and receive rings.
 Both ring number and sizes may be configured at runtime
-using interface-specific functions (e.g.
-.Xr ethtool
+using interface-specific functions (e.g.,
+.Xr ethtool 8
 ).
 .El
 .It Dv NIOCREGIF
@@ -610,7 +611,7 @@ The recommended way to bind a file descriptor to a port is
 to use function
 .Va nm_open(..)
 (see
-.Xr LIBRARIES )
+.Sx LIBRARIES )
 which parses names to access specific port types and
 enable features.
 In the following we document the main features.
@@ -760,7 +761,7 @@ The following functions are available:
 .Bl -tag -width XXXXX
 .It Va  struct nm_desc * nm_open(const char *ifname, const struct nmreq *req, uint64_t flags, const struct nm_desc *arg)
 similar to
-.Xr pcap_open ,
+.Xr pcap_open 3pcap ,
 binds a file descriptor to a port.
 .Bl -tag -width XX
 .It Va ifname
@@ -773,7 +774,7 @@ The nm_flags and nm_ringid values are overwritten by parsing
 ifname and flags, and other fields can be overridden through
 the other two arguments.
 .It Va arg
-points to a struct nm_desc containing arguments (e.g. from a previously
+points to a struct nm_desc containing arguments (e.g., from a previously
 open file descriptor) that should override the defaults.
 The fields are used as described below
 .It Va flags
@@ -829,10 +830,11 @@ mode but still significantly higher than various raw socket types
 Note that for slow devices (such as 1 Gbit/s and slower NICs,
 or several 10 Gbit/s NICs whose hardware is unable to sustain line rate),
 emulated and native mode will likely have similar or same throughput.
-.br
+.Pp
 When emulation is in use, packet sniffer programs such as tcpdump
-could see received packets before they are diverted by netmap. This behaviour
-is not intentional, being just an artifact of the implementation of emulation.
+could see received packets before they are diverted by netmap.
+This behaviour is not intentional, being just an artifact of the implementation
+of emulation.
 Note that in case the netmap application subsequently moves packets received
 from the emulated adapter onto the host RX ring, the sniffer will intercept
 those packets again, since the packets are injected to the host stack as they
@@ -853,11 +855,11 @@ and module parameters on Linux
 .Bl -tag -width indent
 .It Va dev.netmap.admode: 0
 Controls the use of native or emulated adapter mode.
-.br
+.Pp
 0 uses the best available option;
-.br
+.Pp
 1 forces native mode and fails if not available;
-.br
+.Pp
 2 forces emulated hence never fails.
 .It Va dev.netmap.generic_ringsize: 1024
 Ring size used for emulated netmap mode
@@ -938,7 +940,7 @@ directory in
 .Fx
 distributions.
 .Pp
-.Xr pkt-gen
+.Xr pkt-gen 8
 is a general purpose traffic source/sink.
 .Pp
 As an example
@@ -949,15 +951,15 @@ is a traffic sink.
 Both print traffic statistics, to help monitor
 how the system performs.
 .Pp
-.Xr pkt-gen
+.Xr pkt-gen 8
 has many options can be uses to set packet sizes, addresses,
 rates, and use multiple send/receive threads and cores.
 .Pp
-.Xr bridge
+.Xr bridge 4
 is another test program which interconnects two
 .Nm
 ports.
-It can be used for zero-copy forwarding between
+It can be used for transparent forwarding between
 interfaces, as in
 .Dl bridge -i ix0 -i ix1
 or even connect the NIC to the host stack using netmap
@@ -1016,7 +1018,7 @@ void receiver(void)
     for (;;) {
 	poll(&fds, 1, -1);
         while ( (buf = nm_nextpkt(d, &h)) )
-	    consume_pkt(buf, h.len);
+	    consume_pkt(buf, h->len);
     }
     nm_close(d);
 }
@@ -1045,7 +1047,7 @@ to replenish the receive ring:
 .Ed
 .Ss ACCESSING THE HOST STACK
 The host stack is for all practical purposes just a regular ring pair,
-which you can access with the netmap API (e.g. with
+which you can access with the netmap API (e.g., with
 .Dl nm_open("netmap:eth0^", ... ) ;
 All packets that the host would send to an interface in
 .Nm
@@ -1055,11 +1057,11 @@ TX ring are send up to the host stack.
 A simple way to test the performance of a
 .Nm VALE
 switch is to attach a sender and a receiver to it,
-e.g. running the following in two different terminals:
+e.g., running the following in two different terminals:
 .Dl pkt-gen -i vale1:a -f rx # receiver
 .Dl pkt-gen -i vale1:b -f tx # sender
 The same example can be used to test netmap pipes, by simply
-changing port names, e.g.
+changing port names, e.g.,
 .Dl pkt-gen -i vale2:x{3 -f rx # receiver on the master side
 .Dl pkt-gen -i vale2:x}3 -f tx # sender on the slave side
 .Pp
@@ -1127,7 +1129,7 @@ multiqueue, schedulers, packet filters.
 Multiple transmit and receive rings are supported natively
 and can be configured with ordinary OS tools,
 such as
-.Xr ethtool
+.Xr ethtool 8
 or
 device-specific sysctl variables.
 The same goes for Receive Packet Steering (RPS)

From eb958bcadec4a2cbdcc344417f6bf256dd68070f Mon Sep 17 00:00:00 2001
From: Luiz Otavio O souza 
Date: Tue, 13 Jun 2017 09:46:23 -0300
Subject: [PATCH 0139/2207] Silence a (fatal) warning in FreeBSD when building
 one of the platforms that still requires GCC (powerpc, powerpc64 and
 sparc64).

---
 sys/dev/netmap/netmap_generic.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index f148b2281..2e92f9b69 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -168,7 +168,8 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 static void void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { }
 
 #define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
-	(m)->m_ext.ext_free = fn ? (void *)fn : (void *)void_mbuf_dtor;	\
+	(m)->m_ext.ext_free = (fn != NULL) ?		\
+	    (void *)fn : (void *)void_mbuf_dtor;	\
 } while (0)
 
 static inline struct mbuf *

From ca73ab568d7465c024feb0a4375076d620b7c7ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Tue, 13 Jun 2017 17:14:45 +0200
Subject: [PATCH 0140/2207] dkms: fix modules path

Since eb2e5621c065d6b they are not built from LINUX/ anymore
---
 LINUX/dkms/dkms.conf | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/LINUX/dkms/dkms.conf b/LINUX/dkms/dkms.conf
index 4d0017bd5..16458d86d 100644
--- a/LINUX/dkms/dkms.conf
+++ b/LINUX/dkms/dkms.conf
@@ -7,45 +7,41 @@ AUTOINSTALL=yes
 # netmap driver
 MAKE[0]=\'make\'
 BUILT_MODULE_NAME[0]=netmap
-BUILT_MODULE_LOCATION[0]=LINUX/
 DEST_MODULE_LOCATION[0]=/kernel/net/netmap/
 
 # forcedeth driver
 BUILT_MODULE_NAME[1]=forcedeth
-BUILT_MODULE_LOCATION[1]=LINUX/
 DEST_MODULE_LOCATION[1]=/kernel/drivers/net/ethernet/nvidia/
 
 # veth driver
 BUILT_MODULE_NAME[2]=veth
-BUILT_MODULE_LOCATION[2]=LINUX/
 DEST_MODULE_LOCATION[2]=/kernel/drivers/net/
 
 # virtio_net driver
 BUILT_MODULE_NAME[3]=virtio_net
-BUILT_MODULE_LOCATION[3]=LINUX/
 DEST_MODULE_LOCATION[3]=/kernel/drivers/net/
 
 # e1000 driver
 BUILT_MODULE_NAME[4]=e1000
-BUILT_MODULE_LOCATION[4]=LINUX/e1000/
+BUILT_MODULE_LOCATION[4]=e1000/
 DEST_MODULE_LOCATION[4]=/kernel/drivers/net/ethernet/intel/e1000/
 
 # e1000e driver
 BUILT_MODULE_NAME[5]=e1000e
-BUILT_MODULE_LOCATION[5]=LINUX/e1000e/
+BUILT_MODULE_LOCATION[5]=e1000e/
 DEST_MODULE_LOCATION[5]=/kernel/drivers/net/ethernet/intel/e1000e/
 
 # igb driver
 BUILT_MODULE_NAME[6]=igb
-BUILT_MODULE_LOCATION[6]=LINUX/igb/
+BUILT_MODULE_LOCATION[6]=igb/
 DEST_MODULE_LOCATION[6]=/kernel/drivers/net/ethernet/intel/igb/
 
 # ixgbe driver
 BUILT_MODULE_NAME[7]=ixgbe
-BUILT_MODULE_LOCATION[7]=LINUX/ixgbe/
+BUILT_MODULE_LOCATION[7]=ixgbe/
 DEST_MODULE_LOCATION[7]=/kernel/drivers/net/ethernet/intel/ixgbe/
 
 # i40e driver
 BUILT_MODULE_NAME[8]=i40e
-BUILT_MODULE_LOCATION[8]=LINUX/i40e/
+BUILT_MODULE_LOCATION[8]=i40e/
 DEST_MODULE_LOCATION[8]=/kernel/drivers/net/ethernet/intel/i40e/

From 0049194d9bbc675886ce9acd2236bc2a2e61e2b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Wed, 14 Jun 2017 07:02:11 +0200
Subject: [PATCH 0141/2207] Fix build when running make at toplevel

Since the make would be running as a submake, a message about cwd would be printed
and corrupt the eval.

https://www.gnu.org/software/make/manual/html_node/_002dw-Option.html

This fixes ixgbevf and i40e builds.
---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 451ae4374..626029744 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -710,7 +710,7 @@ for d in $(drv print); do
 	drv_distclean=
 	drv_conf="CONFIG_$(basename $d .c | tr a-z- A-Z_)"
 	# possibly override from config.mak
-	eval $(make -nrf read-vars.mak $d@vars E_DRIVERS="$e_drivers")
+	eval $(make -snrf read-vars.mak $d@vars E_DRIVERS="$e_drivers")
 
 	# check that the original driver had been compiled as a module, otherwise
 	# skip this driver

From 9c12cb537fe2dcbaace8914ccc13378ee7bfb936 Mon Sep 17 00:00:00 2001
From: desbma 
Date: Mon, 26 Jun 2017 23:08:19 +0200
Subject: [PATCH 0142/2207] i40e: Set NS_MOREFRAG slot flag if frame is
 incomplete

---
 LINUX/i40e_netmap_linux.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 4a56ee6b5..df2ac9e50 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -455,6 +455,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 	if (netmap_no_pendintr || force_update) {
 		int crclen = ix_crcstrip ? 0 : 4;
 		uint16_t slot_flags = kring->nkr_slot_flags;
+		uint16_t curr_slot_flag;
 
 		nic_i = rxr->next_to_clean; // or also k2n(kring->nr_hwtail)
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -470,7 +471,13 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			}
 			ring->slot[nm_i].len = ((qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
 			    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - crclen;
-			ring->slot[nm_i].flags = slot_flags;
+
+			curr_slot_flag = slot_flags;
+			if (unlikely((staterr & (1<slot[nm_i].flags = curr_slot_flag;
+
 			//bus_dmamap_sync(rxr->ptag,
 			//    rxr->buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
 			nm_i = nm_next(nm_i, lim);

From 50430247c8f20da203c431d19282f3e8625c494f Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Tue, 27 Jun 2017 14:31:10 +0200
Subject: [PATCH 0143/2207] mem: bug fix on private_new failure handling

Note: _netmap_mem_private_new() already performs
clean up
---
 sys/dev/netmap/netmap_mem2.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c3155a602..251b0c15d 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1533,15 +1533,8 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 			p[NETMAP_BUF_POOL].size);
 
 	d = _netmap_mem_private_new(p, perr);
-	if (d == NULL)
-		goto error;
 
 	return d;
-error:
-	netmap_mem_delete(d);
-	if (perr)
-		*perr = err;
-	return NULL;
 }
 
 

From 0ea03b8445712ae71a975c069bba52a42a949138 Mon Sep 17 00:00:00 2001
From: Borislav Matvey 
Date: Thu, 29 Jun 2017 07:48:12 -0700
Subject: [PATCH 0144/2207] Use htons to initialize packet's ip_len

In the expected context the use of htons is more appropriate. htons and
ntohs are actually implemented using the same function on x86, so there
is no actual functional problem.
---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index a34cdc065..3919cb881 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1000,7 +1000,7 @@ initialize_packet(struct targ *targ)
 		ip->ip_hl = sizeof(*ip) >> 2;
 		ip->ip_id = 0;
 		ip->ip_tos = IPTOS_LOWDELAY;
-		ip->ip_len = ntohs(targ->g->pkt_size - sizeof(*eh));
+		ip->ip_len = htons(targ->g->pkt_size - sizeof(*eh));
 		ip->ip_id = 0;
 		ip->ip_off = htons(IP_DF); /* Don't fragment */
 		ip->ip_ttl = IPDEFTTL;

From d4ef816a2f343aa38cc5881af1be45f023657763 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 30 Jun 2017 11:34:10 +0200
Subject: [PATCH 0145/2207] mem: remove unused variable

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 251b0c15d..f9b4497c0 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1485,7 +1485,7 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 {
 	struct netmap_mem_d *d = NULL;
 	struct netmap_obj_params p[NETMAP_POOLS_NR];
-	int i, err = 0;
+	int i;
 	u_int v, maxd;
 	/* account for the fake host rings */
 	txr++;

From e0217c3b2609c2e9484d66014d0075801669fc33 Mon Sep 17 00:00:00 2001
From: Borislav Matvey 
Date: Mon, 3 Jul 2017 04:17:08 -0700
Subject: [PATCH 0146/2207] netmap_do_regif: Reverse error path vs normal path

The error exit path should reverse all operations in backward order of
the normal path. Till this commit if netmap_mem_if_new fails then
netmap_krings_put won't be called and the usage count will leak.
---
 sys/dev/netmap/netmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c3bb02282..8ee9d2b02 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2126,10 +2126,10 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		memset(&na->na_lut, 0, sizeof(na->na_lut));
 err_del_if:
 	netmap_mem_if_delete(na, nifp);
-err_rel_excl:
-	netmap_krings_put(priv);
 err_del_rings:
 	netmap_mem_rings_delete(na);
+err_rel_excl:
+	netmap_krings_put(priv);
 err_del_krings:
 	if (na->active_fds == 0)
 		na->nm_krings_delete(na);

From e7df975863ba5539bf33d84dd2985b58f9409c8e Mon Sep 17 00:00:00 2001
From: Borislav Matvey 
Date: Mon, 3 Jul 2017 09:13:35 -0700
Subject: [PATCH 0147/2207] netmap_ioctl: Fix ifnet reference leak on failure.

The redefinition of ifp variable in the registration path was shadowing
a definition of the same variable at the start of netmap_ioctl function
and in case of netmap_do_regif failure the error path was trying to
unref the outer variable which contains NULL, while the ifnet object was
pointed by the inner ifp variable and as it went out of scope the ifnet
object will have one extra reference.
---
 sys/dev/netmap/netmap.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8ee9d2b02..17d93029b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2312,7 +2312,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		NMG_LOCK();
 		do {
 			u_int memflags;
-			struct ifnet *ifp;
 
 			if (priv->np_nifp != NULL) {	/* thread already registered */
 				error = EBUSY;

From bc0395f7b54b9a29457d4669b3df19e291a9e2f0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Jul 2017 10:33:06 +0200
Subject: [PATCH 0148/2207] vale: accept nic-attach syntax only for proper
 commands

---
 sys/dev/netmap/netmap_vale.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 734ba55c2..3fc905c99 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -786,6 +786,18 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 	} else {
 		struct netmap_adapter *hw;
 
+		/* the vale:nic syntax is only valid for some commands */
+		switch (nmr->nr_cmd) {
+		case NETMAP_BDG_ATTACH:
+		case NETMAP_BDG_DETACH:
+		case NETMAP_BDG_POLLING_ON:
+		case NETMAP_BDG_POLLING_OFF:
+			break; /* ok */
+		default:
+			error = EINVAL;
+			goto out;
+		}
+
 		error = netmap_get_hw_na(ifp, nmd, &hw);
 		if (error || hw == NULL)
 			goto out;

From ef3938b18132cc5118158831732d316ee77abf6c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Jul 2017 15:16:06 +0200
Subject: [PATCH 0149/2207] linux: check kmalloc return with IS_ERR

---
 LINUX/netmap_linux.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4b0275a98..ba0b84e8b 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -43,15 +43,21 @@
 void *
 nm_os_malloc(size_t size)
 {
-	return kmalloc(size, GFP_ATOMIC | __GFP_ZERO);
+	void *rv = kmalloc(size, GFP_ATOMIC | __GFP_ZERO);
+	if (IS_ERR(rv))
+		return NULL;
+	return rv;
 }
 
 void *
 nm_os_realloc(void *addr, size_t new_size, size_t old_size)
 {
+	void *rv;
 	(void)old_size;
-
-	return krealloc(addr, new_size, GFP_ATOMIC | __GFP_ZERO);
+	rv = krealloc(addr, new_size, GFP_ATOMIC | __GFP_ZERO);
+	if (IS_ERR(rv))
+		return NULL;
+	return rv;
 }
 
 void

From 2d3a752c53b910ee2cd57d8e95fd0a7223eb513a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 8 Jul 2017 16:03:30 +0200
Subject: [PATCH 0150/2207] linux: adapt to missing dev->destructor

---
 LINUX/configure      | 11 +++++++++++
 LINUX/netmap_linux.c |  6 ++++++
 2 files changed, 17 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 626029744..008b4d134 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1390,6 +1390,17 @@ EOF
 	}
 EOF
 
+# check for net_dev destructor
+  add_test 'have NETDEV_DTOR' <
+
+	void
+	dummy(struct net_device *dev)
+	{
+		return dev->destructor(dev);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4b0275a98..dd1641054 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2125,11 +2125,13 @@ static int linux_nm_vi_change_mtu(struct net_device *netdev, int new_mtu)
 {
 	return 0;
 }
+#ifdef NETMAP_LINUX_HAVE_NETDEV_DTOR
 static void linux_nm_vi_destructor(struct net_device *netdev)
 {
 //	netmap_detach(netdev);
 	free_netdev(netdev);
 }
+#endif
 static const struct net_device_ops nm_vi_ops = {
 	.ndo_open = linux_nm_vi_open,
 	.ndo_stop = linux_nm_vi_stop,
@@ -2148,7 +2150,11 @@ linux_nm_vi_setup(struct ifnet *dev)
 	dev->netdev_ops = &nm_vi_ops;
 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+#ifdef NETMAP_LINUX_HAVE_NETDEV_DTOR
 	dev->destructor = linux_nm_vi_destructor;
+#else 
+	dev->needs_free_netdev = 1;
+#endif
 	dev->tx_queue_len = 0;
 	/* XXX */
 	dev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST |

From 1379578534e60a64af94b2156feb74cc1bee19b7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 8 Jul 2017 16:31:34 +0200
Subject: [PATCH 0151/2207] linux/i40e: adapt to different pf->state type

---
 LINUX/configure           | 10 ++++++++++
 LINUX/i40e_netmap_linux.h |  9 +++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 008b4d134..8a50f8ba1 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1635,6 +1635,16 @@ EOF
   		return vsi->tx_rings[0];
   	}
 EOF
+   
+   add_test 'define I40E_PTR_STATE' <
+
+	int
+	dummy(struct i40e_pf *pf) {
+		return test_and_set_bit(1, &pf->state);
+	}
+EOF
   fi # i40e
 
   if drv enabled igb; then
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 4a56ee6b5..2c22e6cef 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -55,6 +55,11 @@ extern int ix_rx_miss, ix_rx_miss_bufs, ix_crcstrip;
 #define NM_I40E_TX_RING(a, r)		(&(a)->tx_rings[(r)])
 #define NM_I40E_RX_RING(a, r)		(&(a)->rx_rings[(r)])
 #endif
+#ifdef NETMAP_LINUX_I40E_PTR_STATE
+#define NM_I40E_STATE(pf)		(&(pf)->state)
+#else
+#define NM_I40E_STATE(pf)		((pf)->state)
+#endif
 
 #ifdef NETMAP_I40E_MAIN
 /*
@@ -182,7 +187,7 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
         struct i40e_pf   *pf = (struct i40e_pf *)vsi->back;
 	bool was_running;
 
-	while (test_and_set_bit(__I40E_CONFIG_BUSY, &pf->state))
+	while (test_and_set_bit(__I40E_CONFIG_BUSY, NM_I40E_STATE(pf)))
 			usleep_range(1000, 2000);
 
 	if ( (was_running = netif_running(vsi->netdev)) )
@@ -200,7 +205,7 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
 
-	clear_bit(__I40E_CONFIG_BUSY, &pf->state);
+	clear_bit(__I40E_CONFIG_BUSY, NM_I40E_STATE(pf));
 
 	return 0;
 }

From a56bdfff8418bf6dd7b448456459268cea075141 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 9 Jul 2017 16:54:41 +0200
Subject: [PATCH 0152/2207] lb: fail if pipes cannot be used in zero-copy

---
 apps/lb/lb.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 071e689dd..f56e89198 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -788,6 +788,12 @@ int main(int argc, char **argv)
 			if (p->nmd == NULL) {
 				D("cannot open %s", p->interface);
 				return (1);
+			} else if (p->nmd->req.nr_arg2 != rxport->nmd->req.nr_arg2) {
+				D("failed to open pipe #%d in zero-copy mode, "
+					"please close any application that uses either pipe %s}%d, "
+				        "or %s{%d, and retry",
+					k + 1, g->pipename, g->first_id + k, g->pipename, g->first_id + k);
+				return (1);
 			} else {
 				D("successfully opened pipe #%d %s (tx slots: %d)",
 				  k + 1, p->interface, p->nmd->req.nr_tx_slots);

From cc8eeda7101bc521746e153785cb33c1fe599384 Mon Sep 17 00:00:00 2001
From: desbma 
Date: Fri, 14 Jul 2017 23:44:52 +0200
Subject: [PATCH 0153/2207] Initial Travis CI setup

---
 .travis.yml    | 29 +++++++++++++++++++++++++++
 ci/build-linux | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 .travis.yml
 create mode 100755 ci/build-linux

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..7fe8b444a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,29 @@
+dist: trusty
+sudo: false
+language: c
+cache:
+  directories:
+    - $HOME/Linux
+env:
+  - KERNEL_VERSION=3.2   ARCH=i386
+  - KERNEL_VERSION=3.4   ARCH=i386
+  - KERNEL_VERSION=3.10  ARCH=i386
+  - KERNEL_VERSION=3.16  ARCH=i386
+  - KERNEL_VERSION=4.1   ARCH=i386
+  - KERNEL_VERSION=4.4   ARCH=i386
+  - KERNEL_VERSION=4.9   ARCH=i386
+  - KERNEL_VERSION=linus ARCH=i386
+  - KERNEL_VERSION=3.2   ARCH=x86_64
+  - KERNEL_VERSION=3.4   ARCH=x86_64
+  - KERNEL_VERSION=3.10  ARCH=x86_64
+  - KERNEL_VERSION=3.16  ARCH=x86_64
+  - KERNEL_VERSION=4.1   ARCH=x86_64
+  - KERNEL_VERSION=4.4   ARCH=x86_64
+  - KERNEL_VERSION=4.9   ARCH=x86_64
+  - KERNEL_VERSION=linus ARCH=x86_64
+matrix:
+  allow_failures:
+    - env: KERNEL_VERSION=linus ARCH=i386
+    - env: KERNEL_VERSION=linus ARCH=x86_64
+script:
+  - "./ci/build-linux $KERNEL_VERSION $ARCH"
diff --git a/ci/build-linux b/ci/build-linux
new file mode 100755
index 000000000..1923c9f52
--- /dev/null
+++ b/ci/build-linux
@@ -0,0 +1,53 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+readonly KERNEL_VERSION=${1:?}
+readonly ARCH=${2:?}
+readonly GCC_MAJOR_VERSION=$(echo '#include 
+void main() { printf("%u\n", __GNUC__); }' | gcc -x c - -o /tmp/getgccversion  && /tmp/getgccversion)
+readonly PROC_COUNT=$(grep -c '^processor' /proc/cpuinfo)
+
+
+if [ ! -d ~/Linux/$KERNEL_VERSION ]
+then
+  # clone
+  if [ "$KERNEL_VERSION" = "linus" ]
+  then
+    git clone 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git' ~/Linux/$KERNEL_VERSION
+  else
+    git clone 'https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git' ~/Linux/$KERNEL_VERSION
+    pushd ~/Linux/$KERNEL_VERSION
+    git checkout linux-${KERNEL_VERSION}.y
+    popd
+  fi
+else
+  # update
+  pushd ~/Linux/$KERNEL_VERSION
+  git pull
+  popd
+fi
+
+# configure kernel
+pushd ~/Linux/$KERNEL_VERSION
+compiler_file=compiler-gcc${GCC_MAJOR_VERSION}.h
+if [ ! -f include/linux/${compiler_file} -a ! -h include/linux/${compiler_file} ]
+then
+  # fix compilation of old kernels with recent GCC
+  pushd include/linux
+  if [ -f compiler-gcc5.h -a $GCC_MAJOR_VERSION -gt 5 ]
+  then
+    ln -sv compiler-gcc5.h ${compiler_file}
+  else
+    ln -sv compiler-gcc4.h ${compiler_file}
+  fi
+  popd
+fi
+make mrproper
+make -j $PROC_COUNT ARCH=${ARCH} defconfig
+make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
+popd
+
+# build
+./configure --kernel-dir=$HOME/Linux/$KERNEL_VERSION
+make -j $PROC_COUNT

From 0b5227de9324c88a0541ac168c6a16b14cb0742e Mon Sep 17 00:00:00 2001
From: desbma 
Date: Sat, 15 Jul 2017 00:11:50 +0200
Subject: [PATCH 0154/2207] Travis CI: Cache downloaded drivers

---
 .travis.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 7fe8b444a..21dbd0a76 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,7 @@ language: c
 cache:
   directories:
     - $HOME/Linux
+    - $HOME/Drivers
 env:
   - KERNEL_VERSION=3.2   ARCH=i386
   - KERNEL_VERSION=3.4   ARCH=i386
@@ -25,5 +26,7 @@ matrix:
   allow_failures:
     - env: KERNEL_VERSION=linus ARCH=i386
     - env: KERNEL_VERSION=linus ARCH=x86_64
+install:
+  - "rm -Rf LINUX/ext-drivers && mkdir -p $HOME/Drivers && ln -sv $HOME/Drivers LINUX/ext-drivers"
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"

From b58dae43dfa001c09242539cb34a48b804f26745 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 15 Jul 2017 14:49:11 +0200
Subject: [PATCH 0155/2207] linux/ixgbe: intel 5.2.1 version

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/intel--ixgbe--5.2.1 | 170 ++++++++++++++++++++++++
 2 files changed, 171 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.2.1

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 47720e0ff..3c17ce608 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -11,7 +11,7 @@ endef
 
 enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2))))
 
-$(call enabled_intel_driver,ixgbe,5.1.3)
+$(call enabled_intel_driver,ixgbe,5.2.1)
 $(call enabled_intel_driver,ixgbevf,4.1.2)
 e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.5.3)
diff --git a/LINUX/final-patches/intel--ixgbe--5.2.1 b/LINUX/final-patches/intel--ixgbe--5.2.1
new file mode 100644
index 000000000..267b18559
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.2.1
@@ -0,0 +1,170 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index a3cc895..a038975 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 0f65c2e..e00734b 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -771,6 +788,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2053,6 +2081,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3351,6 +3389,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+ 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
+@@ -3979,6 +4020,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11400,6 +11445,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11445,6 +11494,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 8ac2f825a4007f7d5e71a122fc8e8a3000c37817 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 15 Jul 2017 14:49:46 +0200
Subject: [PATCH 0156/2207] linux/ixgbevf: intel 4.2.1 version

---
 LINUX/default-config.mak.in_              |   2 +-
 LINUX/final-patches/intel--ixgbevf--4.2.1 | 171 ++++++++++++++++++++++
 2 files changed, 172 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.2.1

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 3c17ce608..35beffd56 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -12,7 +12,7 @@ endef
 enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2))))
 
 $(call enabled_intel_driver,ixgbe,5.2.1)
-$(call enabled_intel_driver,ixgbevf,4.1.2)
+$(call enabled_intel_driver,ixgbevf,4.2.1)
 e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.5.3)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
diff --git a/LINUX/final-patches/intel--ixgbevf--4.2.1 b/LINUX/final-patches/intel--ixgbevf--4.2.1
new file mode 100644
index 000000000..960b63d08
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.2.1
@@ -0,0 +1,171 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index ca79ef6..939f185 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 7bb8159..76e74e2 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1192,6 +1220,17 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
++
+ 	do {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1825,8 +1864,11 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+- 
++
+ /**
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+@@ -1997,6 +2039,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4919,8 +4965,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	cards_found++;
+ 	return 0;
+ 
+@@ -4959,6 +5007,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 	if (!netdev)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	adapter = netdev_priv(netdev);
+ 
+ 	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index b53b133..30f592b 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 267fbed12525747a923578cfa50603c857041254 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 15 Jul 2017 15:46:29 +0200
Subject: [PATCH 0157/2207] linux: port to 4.12

---
 ...99 => vanilla--virtio_net.c--40900--40c00} |   0
 .../vanilla--virtio_net.c--40c00--99999       | 102 ++++++++++++++++++
 2 files changed, 102 insertions(+)
 rename LINUX/final-patches/{vanilla--virtio_net.c--40900--99999 => vanilla--virtio_net.c--40900--40c00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--40c00--99999

diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40900--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--40900--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999
new file mode 100644
index 000000000..8ebf13e41
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999
@@ -0,0 +1,102 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 143d8a9..27de2c2 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -170,6 +170,10 @@ struct virtnet_info {
+ 	u32 speed;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_mrg_rxbuf hdr;
+ 	/*
+@@ -263,6 +267,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -1099,8 +1108,22 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 		container_of(napi, struct receive_queue, napi);
+ 	unsigned int received;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	struct virtnet_info *vi = rq->vq->vdev->priv;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
++
+ 	received = virtnet_receive(rq, budget);
+ 
+ 	/* Out of packets? */
+@@ -1114,6 +1137,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
+ 		if (i < vi->curr_queue_pairs)
+@@ -2559,6 +2591,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	virtnet_set_queues(vi, vi->curr_queue_pairs);
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+@@ -2615,7 +2651,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -2684,6 +2727,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From 6d50371ab648fe6fa48a49b838e8e9aa8acabedb Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 19 Jul 2017 11:36:47 +0200
Subject: [PATCH 0158/2207] adaption to upcoming Linux 4.13

---
 LINUX/bsd_glue.h |  4 ++++
 LINUX/configure  | 10 ++++++++++
 2 files changed, 14 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 4eab00158..e171e6e32 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -86,6 +86,10 @@
 #define uintptr_t	unsigned long
 #endif
 
+#ifdef NETMAP_LINUX_HAVE_WAIT_QUEUE_ENTRY_T
+#define wait_queue_t	wait_queue_entry_t
+#endif
+
 #ifndef NETMAP_LINUX_HAVE_QUEUE_MAPPING
 #define skb_get_queue_mapping(m)	(0)
 #define skb_set_queue_mapping(a, b)	do { (void)(a); (void)(b); } while (0)
diff --git a/LINUX/configure b/LINUX/configure
index 8a50f8ba1..5bc1314bb 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1401,6 +1401,16 @@ EOF
 	}
 EOF
 
+# wait_queue_t or wait_queue_entry_t ?
+  add_test 'have WAIT_QUEUE_ENTRY_T' <
+
+	void *
+	dummy(wait_queue_entry_t *wq) {
+		return wq->private;
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################

From 9ef159d94a6c0eb084b6e35fade1060897a4920b Mon Sep 17 00:00:00 2001
From: Luiz Otavio O souza 
Date: Fri, 21 Jul 2017 01:52:31 -0300
Subject: [PATCH 0159/2207] Replace zero with NULL for pointers.

Obtained from:	FreeBSD (r313982)
---
 sys/dev/netmap/netmap_freebsd.c | 2 +-
 sys/dev/netmap/netmap_mem2.c    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 6d0453d3b..4cf7f3e14 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -671,7 +671,7 @@ nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr,
 			&rid, 0, ~0, *mem_size, RF_ACTIVE);
 	if (ptn_dev->pci_mem == NULL) {
 		*nm_paddr = 0;
-		*nm_addr = 0;
+		*nm_addr = NULL;
 		return ENOMEM;
 	}
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f9b4497c0..4a8ebb212 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2146,7 +2146,7 @@ netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd)
 	    if (ptnmd->ptn_dev) {
 		nm_os_pt_memdev_iounmap(ptnmd->ptn_dev);
 	    }
-	    ptnmd->nm_addr = 0;
+	    ptnmd->nm_addr = NULL;
 	    ptnmd->nm_paddr = 0;
 	}
 }

From c51997d2e964c6f48731ccb5989f5cf71fc27a8b Mon Sep 17 00:00:00 2001
From: desbma 
Date: Mon, 24 Jul 2017 20:27:36 +0200
Subject: [PATCH 0160/2207] Comment fixes

Fixes issue #339
---
 sys/dev/netmap/netmap_monitor.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 174f35e5c..e1c63b21c 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -66,9 +66,7 @@
  *    has released them. In most cases, the consumer is a userspace
  *    application which may have modified the frame contents.
  *
- * Several copy monitors may be active on any ring.  Zero-copy monitors,
- * instead, need exclusive access to each of the monitored rings.  This may
- * change in the future, if we implement zero-copy monitor chaining.
+ * Several copy or zero-copy monitors may be active on any ring.
  *
  */
 
@@ -263,7 +261,7 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 	if (zmon && z->prev != NULL)
 		kring = z->prev;
 
-	/* sinchronize with concurrently running nm_sync()s */
+	/* synchronize with concurrently running nm_sync()s */
 	nm_kr_stop(kring, NM_KR_LOCKED);
 
 	if (nm_monitor_none(kring)) {
@@ -329,7 +327,7 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring)
 	if (zmon && mz->prev != NULL)
 		kring = mz->prev;
 
-	/* sinchronize with concurrently running nm_sync()s */
+	/* synchronize with concurrently running nm_sync()s */
 	nm_kr_stop(kring, NM_KR_LOCKED);
 
 	if (zmon) {

From 89aa78433b1070e83ab57d2bdb15f5a09c724232 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 24 Jul 2017 22:19:29 +0200
Subject: [PATCH 0161/2207] linux/i40e: 2.0.30 Intel version

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/intel--i40e--2.0.30 | 156 ++++++++++++++++++++++++
 2 files changed, 157 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.0.30

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 35beffd56..cdde8e010 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -17,4 +17,4 @@ e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.5.3)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 $(call enabled_intel_driver,igb,5.3.5.4)
-$(call enabled_intel_driver,i40e,2.0.26)
+$(call enabled_intel_driver,i40e,2.0.30)
diff --git a/LINUX/final-patches/intel--i40e--2.0.30 b/LINUX/final-patches/intel--i40e--2.0.30
new file mode 100644
index 000000000..f1099fc55
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.0.30
@@ -0,0 +1,156 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 1af83c9..e896ffe 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -27,9 +27,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
+ #
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -43,14 +43,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-$(CONFIG_FCOE:m=y) += i40e_fcoe.o
+-i40e-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_FCOE:m=y) += i40e_fcoe.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 142be1c..b0d4aa3 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -133,6 +133,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3281,6 +3286,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3353,6 +3362,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -10655,6 +10669,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -11026,6 +11045,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 15b2ecf..8611654 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -25,6 +25,10 @@
+ #include "i40e.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -695,6 +699,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1877,6 +1886,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ 	bool failure = false;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		union i40e_rx_desc *rx_desc;
+ 		u16 vlan_tag;

From d602323d6e06a45195b8bbcc7d3bfc33a388a272 Mon Sep 17 00:00:00 2001
From: Luiz Otavio O souza 
Date: Fri, 21 Jul 2017 02:00:48 -0300
Subject: [PATCH 0162/2207] Do not allow the use of the loopback interface in
 netmap.

The generic support in netmap send the packets using if_transmit() and the
loopback do not support packets coming from if_transmit()/if_start().

This avoids the use of the loopback interface and the subsequent crash that
happens when the application send packets to the loopback interface.

Details in:	https://github.com/luigirizzo/netmap/issues/322
Obtained from:	FreeBSD
---
 sys/dev/netmap/netmap_generic.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 2e92f9b69..778e09697 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap_generic.c 274353 2014-11-10 20:19
 #include  /* sockaddrs */
 #include 
 #include 
+#include 
 #include 
 #include         /* bus_dmamap_* in netmap_kern.h */
 
@@ -1198,6 +1199,13 @@ generic_netmap_attach(struct ifnet *ifp)
 	int retval;
 	u_int num_tx_desc, num_rx_desc;
 
+#ifdef __FreeBSD__
+	if (ifp->if_type == IFT_LOOP) {
+		D("if_loop is not supported by %s", __func__);
+		return EINVAL;
+	}
+#endif
+
 	num_tx_desc = num_rx_desc = netmap_generic_ringsize; /* starting point */
 
 	nm_os_generic_find_num_desc(ifp, &num_tx_desc, &num_rx_desc); /* ignore errors */

From 6f7f24068c15b1642837efa2f04b6ecdbd58f37a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 31 Jul 2017 16:04:03 +0200
Subject: [PATCH 0163/2207] linux: do not call pernet_unregister if
 registration failed

---
 LINUX/netmap_linux.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 8d022d842..1ab3a8a4e 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1245,20 +1245,26 @@ static struct pernet_operations netmap_pernet_ops = {
 #endif
 };
 
+static int netmap_bns_registered = 0;
 int
 netmap_bns_register(void)
 {
+	int rv;
 #ifdef NETMAP_LINUX_HAVE_PERNET_OPS_ID
-	return -register_pernet_subsys(&netmap_pernet_ops);
+	rv = register_pernet_subsys(&netmap_pernet_ops);
 #else
-	return -register_pernet_gen_subsys(&netmap_bns_id,
+	rv = register_pernet_gen_subsys(&netmap_bns_id,
 			&netmap_pernet_ops);
 #endif
+	netmap_bns_registered = !rv;
+	return -rv;
 }
 
 void
 netmap_bns_unregister(void)
 {
+	if (!netmap_bns_registered)
+		return;
 #ifdef NETMAP_LINUX_HAVE_PERNET_OPS_ID
 	unregister_pernet_subsys(&netmap_pernet_ops);
 #else

From c56acf2c86b0fb228b8523382a94793009a5e3a6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 31 Jul 2017 16:16:59 +0200
Subject: [PATCH 0164/2207] VALE: allocate hash tables only when needed

---
 sys/dev/netmap/netmap_vale.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3fc905c99..b9cdd1d16 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -224,9 +224,9 @@ struct nm_bridge {
 
 	/* the forwarding table, MAC+ports.
 	 * XXX should be changed to an argument to be passed to
-	 * the lookup function, and allocated on attach
+	 * the lookup function
 	 */
-	struct nm_hash_ent ht[NM_BDG_HASH];
+	struct nm_hash_ent *ht; // allocated on attach
 
 #ifdef CONFIG_NET_NS
 	struct net *ns;
@@ -363,17 +363,20 @@ nm_find_bridge(const char *name, int create)
 	}
 	if (i == num_bridges && b) { /* name not found, can create entry */
 		/* initialize the bridge */
-		strncpy(b->bdg_basename, name, namelen);
 		ND("create new bridge %s with ports %d", b->bdg_basename,
 			b->bdg_active_ports);
+		b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+		if (b->ht == NULL) {
+			D("failed to allocate hash table");
+			return NULL;
+		}
+		strncpy(b->bdg_basename, name, namelen);
 		b->bdg_namelen = namelen;
 		b->bdg_active_ports = 0;
 		for (i = 0; i < NM_BDG_MAXPORTS; i++)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
 		b->bdg_ops.lookup = netmap_bdg_learning;
-		/* reset the MAC address table */
-		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -501,6 +504,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	ND("now %d active ports", lim);
 	if (lim == 0) {
 		ND("marking bridge %s as free", b->bdg_basename);
+		nm_os_free(b->ht);
 		bzero(&b->bdg_ops, sizeof(b->bdg_ops));
 		NM_BNS_PUT(b);
 	}

From 8fc8db7c3561a0ae7d2c9190f72d7d2ea96f974b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 Aug 2017 10:28:04 +0200
Subject: [PATCH 0165/2207] moved the code from netmap_detach_common to the
 only call site

---
 sys/dev/netmap/netmap.c      | 26 +++++++++-----------------
 sys/dev/netmap/netmap_kern.h |  2 --
 2 files changed, 9 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 17d93029b..771f5b411 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2867,22 +2867,6 @@ netmap_attach_common(struct netmap_adapter *na)
 	return 0;
 }
 
-
-/* standard cleanup, called by all destructors */
-void
-netmap_detach_common(struct netmap_adapter *na)
-{
-	if (na->tx_rings) { /* XXX should not happen */
-		D("freeing leftover tx_rings");
-		na->nm_krings_delete(na);
-	}
-	netmap_pipe_dealloc(na);
-	if (na->nm_mem)
-		netmap_mem_put(na->nm_mem);
-	bzero(na, sizeof(*na));
-	nm_os_free(na);
-}
-
 /* Wrapper for the register callback provided netmap-enabled
  * hardware drivers.
  * nm_iszombie(na) means that the driver module has been
@@ -3031,7 +3015,15 @@ NM_DBG(netmap_adapter_put)(struct netmap_adapter *na)
 	if (na->nm_dtor)
 		na->nm_dtor(na);
 
-	netmap_detach_common(na);
+	if (na->tx_rings) { /* XXX should not happen */
+		D("freeing leftover tx_rings");
+		na->nm_krings_delete(na);
+	}
+	netmap_pipe_dealloc(na);
+	if (na->nm_mem)
+		netmap_mem_put(na->nm_mem);
+	bzero(na, sizeof(*na));
+	nm_os_free(na);
 
 	return 1;
 }
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 5af73db04..4213df709 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1371,8 +1371,6 @@ uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *);
  * - provide defaults for the setup callbacks and the memory allocator
  */
 int netmap_attach_common(struct netmap_adapter *);
-/* common actions to be performed on netmap adapter destruction */
-void netmap_detach_common(struct netmap_adapter *);
 /* fill priv->np_[tr]xq{first,last} using the ringid and flags information
  * coming from a struct nmreq
  */

From af213b07aaffecfb8c62addf9fec83deb6bd0dc9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 Aug 2017 16:27:42 +0200
Subject: [PATCH 0166/2207] linux/veth: import more reg/unreg code from pipes

The old code for veth register/unregister could not handle veth
interfaces appearing and disappearing while in use, possibily
causing several problems including leackage of netdev references
and netmap buffers.

The main problem was that veths were treated like normal hw interfaces,
and therefore their special clean-up functions where not being called
after a NETDEV_UNREGISTER.

Another problem was that the link between the two veths is severed during
unregister; as a consequence, the old code was not able to clean up the
remote side while shutting down the local side of the pipe.
---
 LINUX/netmap_linux.c         |  2 ++
 LINUX/veth_netmap.h          | 56 ++++++++++++++++++++++++++++++++----
 LINUX/virtio_netmap.h        |  2 +-
 sys/dev/netmap/netmap.c      |  8 ++++--
 sys/dev/netmap/netmap_kern.h |  2 +-
 sys/dev/netmap/netmap_pt.c   |  2 +-
 6 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1ab3a8a4e..4db034ab3 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2244,6 +2244,8 @@ module_exit(linux_netmap_fini);
 /* export certain symbols to other modules */
 EXPORT_SYMBOL(netmap_attach);		/* driver attach routines */
 EXPORT_SYMBOL(netmap_attach_ext);
+EXPORT_SYMBOL(netmap_adapter_get);
+EXPORT_SYMBOL(netmap_adapter_put);
 #ifdef WITH_PTNETMAP_GUEST
 EXPORT_SYMBOL(netmap_pt_guest_attach);	/* ptnetmap driver attach routine */
 EXPORT_SYMBOL(netmap_pt_guest_rxsync);	/* ptnetmap generic rxsync */
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 304090aff..5185c06a8 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -36,6 +36,12 @@
 static int veth_open(struct ifnet *ifp);
 static int veth_close(struct ifnet *ifp);
 
+struct netmap_veth_adapter {
+	struct netmap_hw_adapter up;
+	struct netmap_veth_adapter *peer;
+	int peer_ref;
+};
+
 /* To be called under RCU read lock */
 static struct netmap_adapter *
 veth_get_peer_na(struct netmap_adapter *na)
@@ -43,13 +49,26 @@ veth_get_peer_na(struct netmap_adapter *na)
 	struct ifnet *ifp = na->ifp;
 	struct veth_priv *priv = netdev_priv(ifp);
 	struct ifnet *peer_ifp;
+	struct netmap_veth_adapter *vna =
+		(struct netmap_veth_adapter *)na;
 
-	peer_ifp = rcu_dereference(priv->peer);
-	if (!peer_ifp) {
-		return NULL;
+	if (vna->peer == NULL) {
+		peer_ifp = rcu_dereference(priv->peer);
+		if (!peer_ifp) {
+			return NULL;
+		}
+		/* cache the na pointer so that we can retrieve it
+		 * and do our clean-up even when the peer_ifp is
+		 * detached from us
+		 */
+		vna->peer = (struct netmap_veth_adapter *)NA(peer_ifp);
+		netmap_adapter_get(&vna->peer->up.up);
+		vna->peer_ref = 1;
+		/* also set the cross reference from the peer_na to us */
+		vna->peer->peer = vna;
 	}
 
-	return NA(peer_ifp);
+	return &vna->peer->up.up;
 }
 
 /*
@@ -79,6 +98,17 @@ krings_needed(struct netmap_adapter *na)
 	return false;
 }
 
+static void
+veth_netmap_dtor(struct netmap_adapter *na)
+{
+	struct netmap_veth_adapter *vna =
+		(struct netmap_veth_adapter *)na;
+	if (vna->peer_ref) {
+		vna->peer_ref = 0;
+		netmap_adapter_put(&vna->peer->up.up);
+	}
+}
+
 /*
  * Register/unregister. We are already under netmap lock.
  * This register function is similar to the one used by
@@ -90,6 +120,8 @@ krings_needed(struct netmap_adapter *na)
 static int
 veth_netmap_reg(struct netmap_adapter *na, int onoff)
 {
+	struct netmap_veth_adapter *vna =
+		(struct netmap_veth_adapter *)na;
 	struct netmap_adapter *peer_na;
 	struct ifnet *ifp = na->ifp;
 	bool was_up;
@@ -179,7 +211,17 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		veth_open(ifp);
 	}
 
-	return error;
+	if (vna->peer_ref)
+		return 0;
+	if (onoff) {
+		vna->peer->peer_ref = 0;
+		netmap_adapter_put(na);
+	} else {
+		netmap_adapter_get(na);
+		vna->peer->peer_ref = 1;
+	}
+
+	return 0;
 }
 
 static int
@@ -295,8 +337,10 @@ veth_netmap_attach(struct ifnet *ifp)
 	na.nm_rxsync = netmap_pipe_rxsync;
 	na.nm_krings_create = veth_netmap_krings_create;
 	na.nm_krings_delete = veth_netmap_krings_delete;
+	na.nm_dtor = veth_netmap_dtor;
 	na.num_tx_rings = na.num_rx_rings = 1;
-	netmap_attach(&na);
+	netmap_attach_ext(&na, sizeof(struct netmap_veth_adapter),
+			0 /* do not ovveride reg */);
 }
 
 /* end of file */
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 1d0faa6a2..bca22b283 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -738,7 +738,7 @@ virtio_netmap_attach(struct virtnet_info *vi)
 	na.nm_config = virtio_netmap_config;
 	na.nm_intr = virtio_netmap_intr;
 
-	ret = netmap_attach_ext(&na, sizeof(struct netmap_virtio_adapter));
+	ret = netmap_attach_ext(&na, sizeof(struct netmap_virtio_adapter), 1);
 	if (ret) {
 		D("Failed to attach virtio-net interface");
 		return;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 771f5b411..d6bc6958b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2919,7 +2919,7 @@ netmap_hw_dtor(struct netmap_adapter *na)
  * Return 0 on success, ENOMEM otherwise.
  */
 int
-netmap_attach_ext(struct netmap_adapter *arg, size_t size)
+netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 {
 	struct netmap_hw_adapter *hwna = NULL;
 	struct ifnet *ifp = NULL;
@@ -2938,8 +2938,10 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size)
 	hwna->up = *arg;
 	hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE;
 	strncpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name));
-	hwna->nm_hw_register = hwna->up.nm_register;
-	hwna->up.nm_register = netmap_hw_reg;
+	if (override_reg) {
+		hwna->nm_hw_register = hwna->up.nm_register;
+		hwna->up.nm_register = netmap_hw_reg;
+	}
 	if (netmap_attach_common(&hwna->up)) {
 		nm_os_free(hwna);
 		goto fail;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4213df709..19a0bdd36 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1188,7 +1188,7 @@ static __inline void nm_kr_start(struct netmap_kring *kr)
  *	virtual ports (vale, pipes, monitor)
  */
 int netmap_attach(struct netmap_adapter *);
-int netmap_attach_ext(struct netmap_adapter *, size_t size);
+int netmap_attach_ext(struct netmap_adapter *, size_t size, int override_reg);
 void netmap_detach(struct ifnet *);
 int netmap_transmit(struct ifnet *, struct mbuf *);
 struct netmap_slot *netmap_reset(struct netmap_adapter *na,
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index b9b668a31..dafdb4043 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1510,7 +1510,7 @@ netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb,
 	if (arg->nm_mem == NULL)
 		return ENOMEM;
 	arg->na_flags |= NAF_MEM_OWNER;
-	error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter));
+	error = netmap_attach_ext(arg, sizeof(struct netmap_pt_guest_adapter), 1);
 	if (error)
 		return error;
 

From e7d670a9c727bec5802fbec3ac09a9e7bd727af8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 3 Aug 2017 07:31:30 +0200
Subject: [PATCH 0167/2207] fix compilation error introduced by af213b07

---
 sys/dev/netmap/netmap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d6bc6958b..6c1e4d2a1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2989,7 +2989,8 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 int
 netmap_attach(struct netmap_adapter *arg)
 {
-	return netmap_attach_ext(arg, sizeof(struct netmap_hw_adapter));
+	return netmap_attach_ext(arg, sizeof(struct netmap_hw_adapter),
+			1 /* override nm_reg */);
 }
 
 

From 1d971a670b7874704b5f6a5e5709153613551505 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 4 Aug 2017 18:08:19 +0200
Subject: [PATCH 0168/2207] pkt-gen: option for randomly sized packets

---
 apps/pkt-gen/pkt-gen.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 3919cb881..a1d063a63 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -257,6 +257,7 @@ struct glob_arg {
 	struct mac_range dst_mac;
 	struct mac_range src_mac;
 	int pkt_size;
+	int pkt_min_size;
 	int burst;
 	int forever;
 	uint64_t npackets;	/* total packets to send */
@@ -1598,6 +1599,11 @@ sender_body(void *data)
 			if (frags > 1)
 				limit = ((limit + frags - 1) / frags) * frags;
 
+			if (targ->g->pkt_min_size > 0) {
+				size = random() %
+					(targ->g->pkt_size - targ->g->pkt_min_size) +
+					targ->g->pkt_min_size;
+			}
 			m = send_packets(txring, pkt, frame, size, targ->g,
 					 limit, options, frags);
 			ND("limit %d tail %d frags %d m %d",
@@ -2219,6 +2225,9 @@ usage(void)
 		"\t-t pkts_to_send	also forces tx mode\n"
 		"\t-r pkts_to_receive	also forces rx mode\n"
 		"\t-l pkt_size		in bytes excluding CRC\n"
+		"\t                     (if passed a second time, use random sizes\n"
+		"\t                      bigger than the second one and lower than\n"
+		"\t                      the first one)\n"
 		"\t-d dst_ip[:port[-dst_ip:port]]   single or range\n"
 		"\t-s src_ip[:port[-src_ip:port]]   single or range\n"
 		"\t-D dst-mac\n"
@@ -2552,6 +2561,8 @@ main(int arc, char **argv)
 	int ch;
 	int devqueues = 1;	/* how many device queues */
 
+	int pkt_size_done = 0;
+
 	struct td_desc *fn = func;
 
 	bzero(&g, sizeof(g));
@@ -2568,6 +2579,7 @@ main(int arc, char **argv)
 	g.dst_mac.name = "ff:ff:ff:ff:ff:ff";
 	g.src_mac.name = NULL;
 	g.pkt_size = 60;
+	g.pkt_min_size = 0;
 	g.nthreads = 1;
 	g.cpus = 1;		/* default */
 	g.forever = 1;
@@ -2663,7 +2675,12 @@ main(int arc, char **argv)
 			break;
 
 		case 'l':	/* pkt_size */
-			g.pkt_size = atoi(optarg);
+			if (pkt_size_done) {
+				g.pkt_min_size = atoi(optarg);
+			} else {
+				g.pkt_size = atoi(optarg);
+				pkt_size_done = 1;
+			}
 			break;
 
 		case 'd':
@@ -2769,6 +2786,11 @@ main(int arc, char **argv)
 		usage();
 	}
 
+	if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) {
+		D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size);
+		usage();
+	}
+
 	if (g.src_mac.name == NULL) {
 		static char mybuf[20] = "00:00:00:00:00:00";
 		/* retrieve source mac address. */

From dda974f882b439eee732672db747bfd677a12ac9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 4 Aug 2017 18:19:11 +0200
Subject: [PATCH 0169/2207] linux/ixgbe: use Tx head write back

Reading the TDH was causing Tx hangs when driving a ring
at high speed. With this patch we enable Tx head write back,
which seems to solve the issue.

As a bonus, the CPU utilization is nicely improved.

An implementation very similar to this one was suggested by
Tom Barbette a couple of years ago.
---
 LINUX/final-patches/intel--ixgbe--4.4.6       | 202 ++++++++++++++++++
 LINUX/final-patches/intel--ixgbe--4.5.4       |  23 +-
 LINUX/final-patches/intel--ixgbe--5.0.4       |  23 +-
 LINUX/final-patches/intel--ixgbe--5.1.3       |  23 +-
 LINUX/final-patches/intel--ixgbe--5.2.1       |  23 +-
 .../vanilla--ixgbe--20620--20622              |  12 +-
 .../vanilla--ixgbe--20622--20623              |  17 +-
 .../vanilla--ixgbe--20623--20625              |  17 +-
 .../vanilla--ixgbe--20625--20626              |  27 +--
 .../vanilla--ixgbe--20626--30100              |  27 +--
 .../vanilla--ixgbe--30100--30200              |  27 +--
 .../vanilla--ixgbe--30200--30400              |  23 +-
 .../vanilla--ixgbe--30400--30500              |  25 +--
 .../vanilla--ixgbe--30500--30700              |  25 +--
 .../vanilla--ixgbe--30700--30a00              |  25 +--
 .../vanilla--ixgbe--30a00--30d00              |  25 +--
 .../vanilla--ixgbe--30d00--30f00              |  27 +--
 .../vanilla--ixgbe--30f00--31300              |  27 +--
 .../vanilla--ixgbe--31300--40900              |  27 +--
 .../vanilla--ixgbe--40900--99999              |  30 ++-
 LINUX/ixgbe_netmap_linux.h                    |  80 ++-----
 21 files changed, 472 insertions(+), 263 deletions(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--4.4.6

diff --git a/LINUX/final-patches/intel--ixgbe--4.4.6 b/LINUX/final-patches/intel--ixgbe--4.4.6
new file mode 100644
index 000000000..80558942f
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--4.4.6
@@ -0,0 +1,202 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index c49cba8..546435f 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 202f595..66242ee 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -709,6 +709,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -727,6 +744,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1656,7 +1684,7 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
+ 	/* Even if we own the page, we are not allowed to use atomic_set()
+ 	 * This would break get_page_unless_zero() users.
+ 	 */
+-	atomic_inc(&page->_count);
++	atomic_inc(&page->NETMAP_LINUX_PAGE_COUNT);
+ 
+ 	return true;
+ }
+@@ -1767,6 +1795,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct sk_buff *skb;
+@@ -2845,6 +2883,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3408,6 +3450,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -10104,6 +10150,10 @@ no_info_string:
+ 			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
+ 			true);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -10149,6 +10199,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
+diff --git a/ixgbe/kcompat.h b/ixgbe/kcompat.h
+index 048157a..2349540 100644
+--- a/ixgbe/kcompat.h
++++ b/ixgbe/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else
+@@ -4880,7 +4882,7 @@ static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+ 
+ static inline void page_ref_inc(struct page *page)
+ {
+-	atomic_inc(&page->_count);
++	atomic_inc(&page->NETMAP_LINUX_PAGE_COUNT);
+ }
+ 
+ #endif /* 4.6.0 */
diff --git a/LINUX/final-patches/intel--ixgbe--4.5.4 b/LINUX/final-patches/intel--ixgbe--4.5.4
index 0c09cc074..22d02824e 100644
--- a/LINUX/final-patches/intel--ixgbe--4.5.4
+++ b/LINUX/final-patches/intel--ixgbe--4.5.4
@@ -62,7 +62,7 @@ index c49cba8..546435f 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 06017ea..5b220d4 100644
+index 06017ea..0c84b61 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -747,6 +747,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -124,17 +124,18 @@ index 06017ea..5b220d4 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -2927,6 +2965,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2912,6 +2950,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3476,6 +3517,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3476,6 +3518,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -145,7 +146,7 @@ index 06017ea..5b220d4 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -10436,6 +10481,10 @@ no_info_string:
+@@ -10436,6 +10482,10 @@ no_info_string:
  		hw->mac.ops.setup_eee(hw, eee_enable);
  	}
  
@@ -156,7 +157,7 @@ index 06017ea..5b220d4 100644
  	return 0;
  
  err_register:
-@@ -10481,6 +10530,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -10481,6 +10531,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev = adapter->netdev;
diff --git a/LINUX/final-patches/intel--ixgbe--5.0.4 b/LINUX/final-patches/intel--ixgbe--5.0.4
index dc38053a1..9ada8f051 100644
--- a/LINUX/final-patches/intel--ixgbe--5.0.4
+++ b/LINUX/final-patches/intel--ixgbe--5.0.4
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 83c6250..eb9a1a1 100644
+index 83c6250..c87f03d 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -752,6 +752,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -124,17 +124,18 @@ index 83c6250..eb9a1a1 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -2932,6 +2970,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2917,6 +2955,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3481,6 +3522,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3481,6 +3523,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -145,7 +146,7 @@ index 83c6250..eb9a1a1 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -10444,6 +10489,10 @@ no_info_string:
+@@ -10444,6 +10490,10 @@ no_info_string:
  		hw->mac.ops.setup_eee(hw, eee_enable);
  	}
  
@@ -156,7 +157,7 @@ index 83c6250..eb9a1a1 100644
  	return 0;
  
  err_register:
-@@ -10489,6 +10538,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -10489,6 +10539,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev = adapter->netdev;
diff --git a/LINUX/final-patches/intel--ixgbe--5.1.3 b/LINUX/final-patches/intel--ixgbe--5.1.3
index f9c7ece60..960818f79 100644
--- a/LINUX/final-patches/intel--ixgbe--5.1.3
+++ b/LINUX/final-patches/intel--ixgbe--5.1.3
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fe4291e..379d4f4 100644
+index fe4291e..fb53dfc 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -124,17 +124,18 @@ index fe4291e..379d4f4 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3222,6 +3260,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -3207,6 +3245,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3798,6 +3839,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3798,6 +3840,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -145,7 +146,7 @@ index fe4291e..379d4f4 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -11114,6 +11159,10 @@ no_info_string:
+@@ -11114,6 +11160,10 @@ no_info_string:
  		hw->mac.ops.setup_eee(hw, eee_enable);
  	}
  
@@ -156,7 +157,7 @@ index fe4291e..379d4f4 100644
  	return 0;
  
  err_register:
-@@ -11159,6 +11208,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -11159,6 +11209,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev = adapter->netdev;
diff --git a/LINUX/final-patches/intel--ixgbe--5.2.1 b/LINUX/final-patches/intel--ixgbe--5.2.1
index 267b18559..7d0e814d3 100644
--- a/LINUX/final-patches/intel--ixgbe--5.2.1
+++ b/LINUX/final-patches/intel--ixgbe--5.2.1
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 0f65c2e..e00734b 100644
+index 0f65c2e..b5d52bb 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -124,17 +124,18 @@ index 0f65c2e..e00734b 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct ixgbe_rx_buffer *rx_buffer;
-@@ -3351,6 +3389,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -3336,6 +3374,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3979,6 +4020,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3979,6 +4021,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -145,7 +146,7 @@ index 0f65c2e..e00734b 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -11400,6 +11445,10 @@ no_info_string:
+@@ -11400,6 +11446,10 @@ no_info_string:
  		hw->mac.ops.setup_eee(hw, eee_enable);
  	}
  
@@ -156,7 +157,7 @@ index 0f65c2e..e00734b 100644
  	return 0;
  
  err_register:
-@@ -11445,6 +11494,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -11445,6 +11495,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev = adapter->netdev;
diff --git a/LINUX/final-patches/vanilla--ixgbe--20620--20622 b/LINUX/final-patches/vanilla--ixgbe--20620--20622
index ceb0341fe..6245f0b5f 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20620--20622
+++ b/LINUX/final-patches/vanilla--ixgbe--20620--20622
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index a456578..eec58c8 100644
+index a456578..a14c3e0 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -337,6 +337,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
@@ -84,14 +84,16 @@ index a456578..eec58c8 100644
  	for (i = 0; i < adapter->num_rx_queues; i++)
  		ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
  		                       (adapter->rx_ring[i].count - 1));
-@@ -2753,6 +2798,11 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -2751,8 +2796,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 	for (i = 0; i < adapter->num_tx_queues; i++) {
+ 		j = adapter->tx_ring[i].reg_idx;
  		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
++#ifdef DEV_NETMAP // XXX i and j are the same ?
++		txdctl = ixgbe_netmap_configure_tx_ring(adapter, j, txdctl);
++#endif /* DEV_NETMAP */
  		txdctl |= IXGBE_TXDCTL_ENABLE;
  		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
 +
-+#ifdef DEV_NETMAP // XXX i and j are the same ?
-+		ixgbe_netmap_configure_tx_ring(adapter, j);
-+#endif /* DEV_NETMAP */
 +
  	}
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--20622--20623 b/LINUX/final-patches/vanilla--ixgbe--20622--20623
index 12ec0b3c4..b8da63001 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20622--20623
+++ b/LINUX/final-patches/vanilla--ixgbe--20622--20623
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 6c00ee4..50d9f5e 100644
+index 6c00ee4..f14b8b8 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -400,6 +400,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
@@ -84,13 +84,20 @@ index 6c00ee4..50d9f5e 100644
  	for (i = 0; i < adapter->num_rx_queues; i++)
  		ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
  		                       (adapter->rx_ring[i]->count - 1));
-@@ -2955,6 +3000,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -2941,6 +2986,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 	for (i = 0; i < adapter->num_tx_queues; i++) {
+ 		j = adapter->tx_ring[i]->reg_idx;
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
++#ifdef DEV_NETMAP // XXX i and j are the same ?
++		txdctl = ixgbe_netmap_configure_tx_ring(adapter, j, txdctl);
++#endif /* DEV_NETMAP */
+ 		txdctl |= IXGBE_TXDCTL_ENABLE;
+ 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
+ 		if (hw->mac.type == ixgbe_mac_82599EB) {
+@@ -2955,6 +3003,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
  				DPRINTK(DRV, ERR, "Could not enable "
  				        "Tx Queue %d\n", j);
  		}
-+#ifdef DEV_NETMAP // XXX i and j are the same ?
-+		ixgbe_netmap_configure_tx_ring(adapter, j);
-+#endif /* DEV_NETMAP */
 +
  	}
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--20623--20625 b/LINUX/final-patches/vanilla--ixgbe--20623--20625
index cb610477b..82b14fa39 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20623--20625
+++ b/LINUX/final-patches/vanilla--ixgbe--20623--20625
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 74d9b6d..d2a6b08 100644
+index 74d9b6d..db08827 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -73,13 +73,20 @@ index 74d9b6d..d2a6b08 100644
  	for (i = 0; i < adapter->num_rx_queues; i++)
  		ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
  		                       (adapter->rx_ring[i]->count - 1));
-@@ -3390,6 +3433,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -3376,6 +3419,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 	for (i = 0; i < adapter->num_tx_queues; i++) {
+ 		j = adapter->tx_ring[i]->reg_idx;
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
++#ifdef DEV_NETMAP // XXX i and j are the same ?
++		txdctl = ixgbe_netmap_configure_tx_ring(adapter, j, txdctl);
++#endif /* DEV_NETMAP */
+ 		txdctl |= IXGBE_TXDCTL_ENABLE;
+ 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
+ 		if (hw->mac.type == ixgbe_mac_82599EB) {
+@@ -3390,6 +3436,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
  				DPRINTK(DRV, ERR, "Could not enable "
  				        "Tx Queue %d\n", j);
  		}
-+#ifdef DEV_NETMAP // XXX i and j are the same ?
-+		ixgbe_netmap_configure_tx_ring(adapter, j);
-+#endif /* DEV_NETMAP */
 +
  	}
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--20625--20626 b/LINUX/final-patches/vanilla--ixgbe--20625--20626
index 4842ca9e1..662c8615a 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20625--20626
+++ b/LINUX/final-patches/vanilla--ixgbe--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index eee0b29..a94380e 100644
+index eee0b29..cbaf599 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index eee0b29..a94380e 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2519,6 +2556,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
+@@ -2503,6 +2540,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	/* reinitialize flowdirector state */
+ 	set_bit(__IXGBE_FDIR_INIT_DONE, &ring->reinit_state);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -2833,6 +2873,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
++#ifdef DEV_NETMAP 
++		txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	txdctl |= IXGBE_TXDCTL_ENABLE;
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+@@ -2833,6 +2874,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index eee0b29..a94380e 100644
  	ixgbe_alloc_rx_buffers(adapter, ring, IXGBE_DESC_UNUSED(ring));
  }
  
-@@ -7048,6 +7092,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7048,6 +7093,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  
  	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
  	cards_found++;
@@ -93,7 +94,7 @@ index eee0b29..a94380e 100644
  	return 0;
  
  err_register:
-@@ -7088,6 +7137,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7088,6 +7138,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct net_device *netdev = pci_get_drvdata(pdev);
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--20626--30100 b/LINUX/final-patches/vanilla--ixgbe--20626--30100
index cb603e0a6..a9262c9ed 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20626--30100
+++ b/LINUX/final-patches/vanilla--ixgbe--20626--30100
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 30f9ccf..e570fce 100644
+index 30f9ccf..12a830c 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -221,6 +221,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index 30f9ccf..e570fce 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2730,6 +2767,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
+@@ -2714,6 +2751,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3094,6 +3134,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP 
++		txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	txdctl |= IXGBE_TXDCTL_ENABLE;
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+@@ -3094,6 +3135,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index 30f9ccf..e570fce 100644
  	ixgbe_alloc_rx_buffers(ring, IXGBE_DESC_UNUSED(ring));
  }
  
-@@ -7450,6 +7494,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7450,6 +7495,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  
  	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
  	cards_found++;
@@ -93,7 +94,7 @@ index 30f9ccf..e570fce 100644
  	return 0;
  
  err_register:
-@@ -7490,6 +7539,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7490,6 +7540,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30100--30200 b/LINUX/final-patches/vanilla--ixgbe--30100--30200
index bcefb65ac..8c5ce9f46 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30100--30200
+++ b/LINUX/final-patches/vanilla--ixgbe--30100--30200
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e1fcc95..262e92d 100644
+index e1fcc95..2d2dfb9 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -249,6 +249,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -61,17 +61,18 @@ index e1fcc95..262e92d 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2676,6 +2714,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
+@@ -2660,6 +2698,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3039,6 +3080,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP 
++		txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	txdctl |= IXGBE_TXDCTL_ENABLE;
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+@@ -3039,6 +3081,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -82,7 +83,7 @@ index e1fcc95..262e92d 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -7696,6 +7741,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7696,6 +7742,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  
  	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
  	cards_found++;
@@ -94,7 +95,7 @@ index e1fcc95..262e92d 100644
  	return 0;
  
  err_register:
-@@ -7732,6 +7782,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7732,6 +7783,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30200--30400 b/LINUX/final-patches/vanilla--ixgbe--30200--30400
index ed39437cb..71a34caef 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30200--30400
+++ b/LINUX/final-patches/vanilla--ixgbe--30200--30400
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 8ef92d1..ce93cea 100644
+index 8ef92d1..342f0d3 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -188,6 +188,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -59,17 +59,18 @@ index 8ef92d1..ce93cea 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2420,6 +2456,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2405,6 +2441,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -2783,6 +2822,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -2783,6 +2823,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -80,7 +81,7 @@ index 8ef92d1..ce93cea 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -7710,6 +7753,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7710,6 +7754,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  
  	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
  	cards_found++;
@@ -92,7 +93,7 @@ index 8ef92d1..ce93cea 100644
  	return 0;
  
  err_register:
-@@ -7746,6 +7794,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7746,6 +7795,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30400--30500 b/LINUX/final-patches/vanilla--ixgbe--30400--30500
index 16903edfe..c2cfb9b2b 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30400--30500
+++ b/LINUX/final-patches/vanilla--ixgbe--30400--30500
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 467948e9..ff180b6 100644
+index 467948e9..6ab3fb5 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index 467948e9..ff180b6 100644
  	do {
  		struct ixgbe_rx_buffer *rx_buffer;
  		union ixgbe_adv_rx_desc *rx_desc;
-@@ -2683,6 +2720,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2668,6 +2705,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3032,6 +3072,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3032,6 +3073,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index 467948e9..ff180b6 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4764,6 +4808,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -4764,6 +4809,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -89,7 +90,7 @@ index 467948e9..ff180b6 100644
  	return 0;
  
  err_req_irq:
-@@ -7152,6 +7197,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7152,6 +7198,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  
  	e_dev_info("%s\n", ixgbe_default_device_descr);
  	cards_found++;
@@ -101,7 +102,7 @@ index 467948e9..ff180b6 100644
  	return 0;
  
  err_register:
-@@ -7187,6 +7237,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7187,6 +7238,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30500--30700 b/LINUX/final-patches/vanilla--ixgbe--30500--30700
index b2070707c..78c8bf0c9 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30500--30700
+++ b/LINUX/final-patches/vanilla--ixgbe--30500--30700
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e242104..5a995de 100644
+index e242104..eab0e89 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index e242104..5a995de 100644
  	do {
  		struct ixgbe_rx_buffer *rx_buffer;
  		union ixgbe_adv_rx_desc *rx_desc;
-@@ -2725,6 +2762,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2710,6 +2747,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3102,6 +3142,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3102,6 +3143,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index e242104..5a995de 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4827,6 +4871,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -4827,6 +4872,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -89,7 +90,7 @@ index e242104..5a995de 100644
  	return 0;
  
  err_req_irq:
-@@ -7358,6 +7403,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7358,6 +7404,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  		e_err(probe, "failed to allocate sysfs resources\n");
  #endif /* CONFIG_IXGBE_HWMON */
  
@@ -100,7 +101,7 @@ index e242104..5a995de 100644
  	return 0;
  
  err_register:
-@@ -7393,6 +7442,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7393,6 +7443,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30700--30a00 b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
index 1f2104684..8fb08b834 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30700--30a00
+++ b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fa3d552..12785e3 100644
+index fa3d552..8de2ce7 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -205,6 +205,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index fa3d552..12785e3 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -2788,6 +2825,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2773,6 +2810,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3157,6 +3197,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3157,6 +3198,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index fa3d552..12785e3 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4903,6 +4947,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -4903,6 +4948,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -89,7 +90,7 @@ index fa3d552..12785e3 100644
  	return 0;
  
  err_set_queues:
-@@ -7464,6 +7509,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
+@@ -7464,6 +7510,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
  	ixgbe_dbg_adapter_init(adapter);
  #endif /* CONFIG_DEBUG_FS */
  
@@ -100,7 +101,7 @@ index fa3d552..12785e3 100644
  	return 0;
  
  err_register:
-@@ -7498,6 +7547,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+@@ -7498,6 +7548,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
index d5186f1e7..c7a5bedf6 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
+++ b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d30fbdd..0326ffd 100644
+index d30fbdd..0b4f668 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -248,6 +248,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index d30fbdd..0326ffd 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -2905,6 +2942,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -2890,6 +2927,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3266,6 +3306,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3266,6 +3307,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index d30fbdd..0326ffd 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -5037,6 +5081,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5037,6 +5082,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -89,7 +90,7 @@ index d30fbdd..0326ffd 100644
  	return 0;
  
  err_set_queues:
-@@ -7658,6 +7703,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -7658,6 +7704,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -100,7 +101,7 @@ index d30fbdd..0326ffd 100644
  	return 0;
  
  err_register:
-@@ -7692,6 +7741,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -7692,6 +7742,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
index 7083572e5..02824dea4 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 5bcc870..c4e71a9 100644
+index 5bcc870..1d71e2a 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index 5bcc870..c4e71a9 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3033,6 +3070,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -3018,6 +3055,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3394,6 +3434,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3394,6 +3435,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index 5bcc870..c4e71a9 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4600,16 +4644,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4600,16 +4645,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  	/* enable transmits */
  	netif_tx_start_all_queues(adapter->netdev);
  
@@ -98,7 +99,7 @@ index 5bcc870..c4e71a9 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5412,6 +5446,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5412,6 +5447,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -106,7 +107,7 @@ index 5bcc870..c4e71a9 100644
  	return 0;
  
  err_set_queues:
-@@ -8174,6 +8209,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8174,6 +8210,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -117,7 +118,7 @@ index 5bcc870..c4e71a9 100644
  	return 0;
  
  err_register:
-@@ -8208,6 +8247,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -8208,6 +8248,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--30f00--31300 b/LINUX/final-patches/vanilla--ixgbe--30f00--31300
index 72ffaa672..16484392e 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30f00--31300
+++ b/LINUX/final-patches/vanilla--ixgbe--30f00--31300
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d62e7a2..dfd338d 100644
+index d62e7a2..b413a71 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -417,6 +417,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index d62e7a2..dfd338d 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3131,6 +3168,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -3116,6 +3153,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3496,6 +3536,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3496,6 +3537,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index d62e7a2..dfd338d 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4698,6 +4742,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4698,6 +4743,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
@@ -91,7 +92,7 @@ index d62e7a2..dfd338d 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5503,6 +5550,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5503,6 +5551,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -99,7 +100,7 @@ index d62e7a2..dfd338d 100644
  	return 0;
  
  err_set_queues:
-@@ -8310,6 +8358,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8310,6 +8359,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -110,7 +111,7 @@ index d62e7a2..dfd338d 100644
  	return 0;
  
  err_register:
-@@ -8345,6 +8397,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -8345,6 +8398,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--31300--40900 b/LINUX/final-patches/vanilla--ixgbe--31300--40900
index 004f1a9ce..45fdf7aae 100644
--- a/LINUX/final-patches/vanilla--ixgbe--31300--40900
+++ b/LINUX/final-patches/vanilla--ixgbe--31300--40900
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 67b02bd..2160fcb 100644
+index 67b02bd..ddc67ff 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,18 @@ index 67b02bd..2160fcb 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3049,6 +3086,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -3034,6 +3071,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3483,6 +3523,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3483,6 +3524,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +82,7 @@ index 67b02bd..2160fcb 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4805,6 +4849,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4805,6 +4850,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
@@ -91,7 +92,7 @@ index 67b02bd..2160fcb 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5627,6 +5674,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5627,6 +5675,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -99,7 +100,7 @@ index 67b02bd..2160fcb 100644
  	return 0;
  
  err_set_queues:
-@@ -8521,6 +8569,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8521,6 +8570,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -110,7 +111,7 @@ index 67b02bd..2160fcb 100644
  	return 0;
  
  err_register:
-@@ -8564,6 +8616,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -8564,6 +8617,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev  = adapter->netdev;
diff --git a/LINUX/final-patches/vanilla--ixgbe--40900--99999 b/LINUX/final-patches/vanilla--ixgbe--40900--99999
index 11cf6853b..6704bf5d5 100644
--- a/LINUX/final-patches/vanilla--ixgbe--40900--99999
+++ b/LINUX/final-patches/vanilla--ixgbe--40900--99999
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fee1f2918..2a71eac 100644
+index fee1f2918..dcf36a3 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -497,6 +497,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -60,17 +60,27 @@ index fee1f2918..2a71eac 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3225,6 +3262,9 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -3210,6 +3247,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 
+ 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3224,7 +3265,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+ 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
  }
  
  static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
-@@ -3720,6 +3760,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3720,6 +3761,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -81,7 +91,7 @@ index fee1f2918..2a71eac 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -5271,6 +5315,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -5271,6 +5316,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
@@ -91,7 +101,7 @@ index fee1f2918..2a71eac 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -9799,6 +9846,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9799,6 +9847,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -102,7 +112,7 @@ index fee1f2918..2a71eac 100644
  	return 0;
  
  err_register:
-@@ -9843,6 +9894,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -9843,6 +9895,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev  = adapter->netdev;
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 5d8322268..efc1c1b5f 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -245,16 +245,10 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
-	/*
-	 * interrupts on every tx packet are expensive so request
-	 * them every half ring, or where NS_REPORT is set
-	 */
-	u_int report_frequency = kring->nkr_num_slots >> 1;
 
 	/* device-specific */
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
 	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
-	int reclaim_tx;
 
 	/*
 	 * First part: process new packets to send.
@@ -306,9 +300,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			union ixgbe_adv_tx_desc *curr = NM_IXGBE_TX_DESC(txr, nic_i);
-			int flags = (slot->flags & NS_REPORT ||
-				nic_i == 0 || nic_i == report_frequency) ?
-				IXGBE_TXD_CMD_RS : 0;
+			int flags = (nic_i % 32) ? 0 : IXGBE_TXD_CMD_RS;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
@@ -338,51 +330,10 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
-	 * Because this is expensive (we read a NIC register etc.)
-	 * we only do it in specific cases (see below).
 	 */
-	if (flags & NAF_FORCE_RECLAIM) {
-		reclaim_tx = 1; /* forced reclaim */
-	} else if (!nm_kr_txempty(kring)) {
-		reclaim_tx = 0; /* have buffers, no reclaim */
-	} else {
-		/*
-		 * No buffers available. Locate previous slot with
-		 * REPORT_STATUS set.
-		 * If the slot has DD set, we can reclaim space,
-		 * otherwise wait for the next interrupt.
-		 * This enables interrupt moderation on the tx
-		 * side though it might reduce throughput.
-		 */
-		union ixgbe_adv_tx_desc *txd = NM_IXGBE_TX_DESC(txr, 0);
-
-		nic_i = txr->next_to_clean + report_frequency;
-		if (nic_i > lim)
-			nic_i -= lim + 1;
-		// round to the closest with dd set
-		nic_i = (nic_i < kring->nkr_num_slots / 4 ||
-			 nic_i >= kring->nkr_num_slots*3/4) ?
-			0 : report_frequency;
-		reclaim_tx = txd[nic_i].wb.status & IXGBE_TXD_STAT_DD;	// XXX cpu_to_le32 ?
-	}
-	if (reclaim_tx) {
-		/*
-		 * Record completed transmissions.
-		 * We (re)use the driver's txr->next_to_clean to keep
-		 * track of the most recently completed transmission.
-		 *
-		 * The datasheet discourages the use of TDH to find
-		 * out the number of sent packets, but we only set
-		 * REPORT STATUS in a few slots so TDH is the only
-		 * good way.
-		 */
-		nic_i = IXGBE_READ_REG(&adapter->hw, NM_IXGBE_TDH(ring_nr));
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
-			nic_i -= kring->nkr_num_slots;
-		}
-		txr->next_to_clean = nic_i;
-		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
+		u32 h = *(volatile u32*)&txr->next_to_use;
+		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
 out:
 
@@ -521,16 +472,29 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
  * if in netmap mode, attach the netmap buffers to the ring and return true.
  * Otherwise return false.
  */
-static int
-ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
+static u32
+ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u32 txdctl)
 {
 	struct netmap_adapter *na = NA(adapter->netdev);
 	struct netmap_slot *slot;
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
+	u64 wba;
 	//int j;
 
         slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
-		return 0;	// not in native netmap mode
+		return txdctl;	// not in native netmap mode
+
+	/* we reset WTRESH (it must be 0 according to specs) */
+	txdctl &= ~(0x7f << 16);
+
+	/* we reuse the next_to_use+next_to_clean fields to receive the hw head */
+	wba = (u64)virt_to_phys(&txr->next_to_use);
+	IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(ring_nr),
+		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);
+	IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(ring_nr), wba >> 32);
+
 #if 0
 	/*
 	 * on a generic card we should set the address in the slot.
@@ -544,7 +508,9 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 		void *addr = PNMB(na, slot + sj, &paddr);
 	}
 #endif
-	return 1;
+
+	/* the queue will be re-enabled by the caller */
+	return txdctl;
 }
 
 static int

From 47997bae9609ea9a8c47a3f1e5a69a86c516225e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 6 Aug 2017 17:27:33 +0200
Subject: [PATCH 0170/2207] linux/ixgbevf: fix compilation after commit dda974f

---
 LINUX/ixgbe_netmap_linux.h | 80 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index efc1c1b5f..63935ceef 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -245,10 +245,16 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
+	/*
+	 * interrupts on every tx packet are expensive so request
+	 * them every half ring, or where NS_REPORT is set
+	 */
+	u_int report_frequency = kring->nkr_num_slots >> 1;
 
 	/* device-specific */
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
 	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
+	int reclaim_tx;
 
 	/*
 	 * First part: process new packets to send.
@@ -300,7 +306,13 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			union ixgbe_adv_tx_desc *curr = NM_IXGBE_TX_DESC(txr, nic_i);
-			int flags = (nic_i % 32) ? 0 : IXGBE_TXD_CMD_RS;
+			int flags = (slot->flags & NS_REPORT ||
+#ifndef NM_IXGBEVF
+				!(nic_i % 32)
+#else /* NM_IXGBEVF */
+				nic_i == 0 || nic_i == report_frequency
+#endif /* NM_IXGBEVF */
+				) ? IXGBE_TXD_CMD_RS : 0;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
@@ -331,10 +343,62 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
+#ifndef NM_IXGBEVF
+	(void)reclaim_tx;
+	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
 		u32 h = *(volatile u32*)&txr->next_to_use;
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
+#else /* NM_IXGBEVF */
+	/*
+	 * Because this is expensive (we read a NIC register etc.)
+	 * we only do it in specific cases (see below).
+	 */
+	if (flags & NAF_FORCE_RECLAIM) {
+		reclaim_tx = 1; /* forced reclaim */
+	} else if (!nm_kr_txempty(kring)) {
+		reclaim_tx = 0; /* have buffers, no reclaim */
+	} else {
+		/*
+		 * No buffers available. Locate previous slot with
+		 * REPORT_STATUS set.
+		 * If the slot has DD set, we can reclaim space,
+		 * otherwise wait for the next interrupt.
+		 * This enables interrupt moderation on the tx
+		 * side though it might reduce throughput.
+		 */
+		union ixgbe_adv_tx_desc *txd = NM_IXGBE_TX_DESC(txr, 0);
+
+		nic_i = txr->next_to_clean + report_frequency;
+		if (nic_i > lim)
+			nic_i -= lim + 1;
+		// round to the closest with dd set
+		nic_i = (nic_i < kring->nkr_num_slots / 4 ||
+			 nic_i >= kring->nkr_num_slots*3/4) ?
+			0 : report_frequency;
+		reclaim_tx = txd[nic_i].wb.status & IXGBE_TXD_STAT_DD;	// XXX cpu_to_le32 ?
+	}
+	if (reclaim_tx) {
+		/*
+		 * Record completed transmissions.
+		 * We (re)use the driver's txr->next_to_clean to keep
+		 * track of the most recently completed transmission.
+		 *
+		 * The datasheet discourages the use of TDH to find
+		 * out the number of sent packets, but we only set
+		 * REPORT STATUS in a few slots so TDH is the only
+		 * good way.
+		 */
+		nic_i = IXGBE_READ_REG(&adapter->hw, NM_IXGBE_TDH(ring_nr));
+		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
+			D("TDH wrap %d", nic_i);
+			nic_i -= kring->nkr_num_slots;
+		}
+		txr->next_to_clean = nic_i;
+		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+	}
+#endif /* NM_IXGBEVF */
 out:
 
 	return 0;
@@ -473,19 +537,28 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
  * Otherwise return false.
  */
 static u32
-ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u32 txdctl)
+ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr
+#ifndef NM_IXGBEVF
+		, u32 txdctl
+#endif /* !NM_IXGBEVF */
+		)
 {
 	struct netmap_adapter *na = NA(adapter->netdev);
 	struct netmap_slot *slot;
+#ifndef NM_IXGBEVF
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
 	u64 wba;
+#else /* NM_IXGBEVF */
+	u32 txdctl = 0;
+#endif /* NM_IXGBEVF */
 	//int j;
 
         slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
 		return txdctl;	// not in native netmap mode
 
+#ifndef NM_IXGBEVF
 	/* we reset WTRESH (it must be 0 according to specs) */
 	txdctl &= ~(0x7f << 16);
 
@@ -494,6 +567,9 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(ring_nr),
 		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);
 	IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(ring_nr), wba >> 32);
+#else /* NM_IXGBEVF */
+	txdctl = 1;
+#endif /* NM_IXGBEVF */
 
 #if 0
 	/*

From 3c3ab5faa2ab9c89db09cd8339d0e96a1a78c41a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 6 Aug 2017 20:26:36 +0200
Subject: [PATCH 0171/2207] linux/scripts: fix build check of external drivers

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index eb1a4cc57..eb7cd654a 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -416,7 +416,7 @@ function check-patch()
 	# extract the driver name
 	local driver=$(scripts/vers $_patch -s -p -p)
 	# extract the driver type (vanilla or external)
-	local dtype=$(scripts/vers $_patch -s -p)
+	local dtype=$(scripts/vers $_patch -s -p -p -p)
 	local p=$(realpath $patch)
 	mkdir -p log
 	local log="$(realpath log)/$(basename $patch)"

From 308aa206e2f996c30ff01c5a28cb89151da3edb0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Aug 2017 11:31:57 +0200
Subject: [PATCH 0172/2207] linux: reduce differences between ixgbe and ixgbevf

---
 LINUX/final-patches/intel--ixgbevf--3.2.2     | 178 ++++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--3.3.2     |  27 ++-
 LINUX/final-patches/intel--ixgbevf--4.0.3     |  25 ++-
 LINUX/final-patches/intel--ixgbevf--4.1.2     |  25 ++-
 LINUX/final-patches/intel--ixgbevf--4.2.1     |  25 ++-
 .../vanilla--ixgbevf--20622--30500            |  10 +-
 .../vanilla--ixgbevf--30500--30600            |  10 +-
 .../vanilla--ixgbevf--30600--30700            |  10 +-
 .../vanilla--ixgbevf--30700--30d00            |  10 +-
 .../vanilla--ixgbevf--30d00--30e00            |  10 +-
 .../vanilla--ixgbevf--30e00--30f00            |  23 +--
 .../vanilla--ixgbevf--30f00--31200            |  23 +--
 .../vanilla--ixgbevf--31200--31300            |  23 +--
 .../vanilla--ixgbevf--31300--40000            |  23 +--
 .../vanilla--ixgbevf--40000--40900            |  23 +--
 .../vanilla--ixgbevf--40900--40b00            | 118 ++++++++++++
 ...--99999 => vanilla--ixgbevf--40b00--40c00} |  25 +--
 .../vanilla--ixgbevf--40c00--99999            | 118 ++++++++++++
 LINUX/ixgbe_netmap_linux.h                    |  36 ++--
 19 files changed, 592 insertions(+), 150 deletions(-)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--3.2.2
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--40900--40b00
 rename LINUX/final-patches/{vanilla--ixgbevf--40900--99999 => vanilla--ixgbevf--40b00--40c00} (82%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--40c00--99999

diff --git a/LINUX/final-patches/intel--ixgbevf--3.2.2 b/LINUX/final-patches/intel--ixgbevf--3.2.2
new file mode 100644
index 000000000..e293506d2
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--3.2.2
@@ -0,0 +1,178 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index b50a61d..e8aa31c 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,23 +28,23 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_param.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -91,9 +91,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index bf6cc35..dee644c 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -303,6 +303,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -322,6 +339,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1140,6 +1168,17 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
++
+ 	do {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1762,6 +1801,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1943,6 +1986,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4767,8 +4814,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	cards_found++;
+ 	return 0;
+ 
+@@ -4807,6 +4856,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 	if (!netdev)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	adapter = netdev_priv(netdev);
+ 
+ 	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 683975b..2647519 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else
+@@ -4793,7 +4795,7 @@ static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+ 
+ static inline void page_ref_inc(struct page *page)
+ {
+-	atomic_inc(&page->_count);
++	atomic_inc(&page->NETMAP_LINUX_PAGE_COUNT);
+ }
+ 
+ #endif /* 4.6.0 */
diff --git a/LINUX/final-patches/intel--ixgbevf--3.3.2 b/LINUX/final-patches/intel--ixgbevf--3.3.2
index f50556456..68fbd4524 100644
--- a/LINUX/final-patches/intel--ixgbevf--3.3.2
+++ b/LINUX/final-patches/intel--ixgbevf--3.3.2
@@ -1,4 +1,4 @@
-diff --git a/ixgbevf/Makefile b/ixgbevf-3.3.2/src/Makefile
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
 index d85c225..da05d8b 100644
 --- a/ixgbevf/Makefile
 +++ b/ixgbevf/Makefile
@@ -46,7 +46,7 @@ index d85c225..da05d8b 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 2435281..a64d083 100644
+index 2435281..c2cbc6f 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -109,20 +109,27 @@ index 2435281..a64d083 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1823,8 +1862,11 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -1814,6 +1853,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1824,7 +1867,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
  }
 - 
 +
  /**
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
-@@ -1995,6 +2037,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+@@ -1995,6 +2038,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -133,7 +140,7 @@ index 2435281..a64d083 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -4883,8 +4929,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+@@ -4883,8 +4930,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
          if (netdev->features & NETIF_F_GRO)
                  DPRINTK(PROBE, INFO, "GRO is enabled\n");
  #endif
@@ -145,7 +152,7 @@ index 2435281..a64d083 100644
  	cards_found++;
  	return 0;
  
-@@ -4923,6 +4971,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+@@ -4923,6 +4972,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/intel--ixgbevf--4.0.3 b/LINUX/final-patches/intel--ixgbevf--4.0.3
index 2b5e68ddb..401d3b1a5 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.0.3
+++ b/LINUX/final-patches/intel--ixgbevf--4.0.3
@@ -46,7 +46,7 @@ index d85c225..da05d8b 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 88f87cc..b285f33 100644
+index 88f87cc..166ae8f 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -109,20 +109,27 @@ index 88f87cc..b285f33 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1823,8 +1862,11 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -1814,6 +1853,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1824,7 +1867,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
  }
 - 
 +
  /**
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
-@@ -1995,6 +2037,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+@@ -1995,6 +2038,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -133,7 +140,7 @@ index 88f87cc..b285f33 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -4888,8 +4934,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+@@ -4888,8 +4935,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
          if (netdev->features & NETIF_F_GRO)
                  DPRINTK(PROBE, INFO, "GRO is enabled\n");
  #endif
@@ -145,7 +152,7 @@ index 88f87cc..b285f33 100644
  	cards_found++;
  	return 0;
  
-@@ -4928,6 +4976,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+@@ -4928,6 +4977,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/intel--ixgbevf--4.1.2 b/LINUX/final-patches/intel--ixgbevf--4.1.2
index 41a92b10c..018719dde 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.1.2
+++ b/LINUX/final-patches/intel--ixgbevf--4.1.2
@@ -46,7 +46,7 @@ index ca79ef6..939f185 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 789187b..d51c9cd 100644
+index 789187b..19207f8 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -109,20 +109,27 @@ index 789187b..d51c9cd 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1819,8 +1858,11 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -1810,6 +1849,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1820,7 +1863,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
  }
 - 
 +
  /**
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
-@@ -1991,6 +2033,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+@@ -1991,6 +2034,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -133,7 +140,7 @@ index 789187b..d51c9cd 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -4923,8 +4969,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+@@ -4923,8 +4970,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
          if (netdev->features & NETIF_F_GRO)
                  DPRINTK(PROBE, INFO, "GRO is enabled\n");
  #endif
@@ -145,7 +152,7 @@ index 789187b..d51c9cd 100644
  	cards_found++;
  	return 0;
  
-@@ -4963,6 +5011,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+@@ -4963,6 +5012,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/intel--ixgbevf--4.2.1 b/LINUX/final-patches/intel--ixgbevf--4.2.1
index 960b63d08..914a1068d 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.2.1
+++ b/LINUX/final-patches/intel--ixgbevf--4.2.1
@@ -46,7 +46,7 @@ index ca79ef6..939f185 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 7bb8159..76e74e2 100644
+index 7bb8159..3bba8b6 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -109,20 +109,27 @@ index 7bb8159..76e74e2 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1825,8 +1864,11 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -1816,6 +1855,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1826,7 +1869,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
  }
 - 
 +
  /**
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
-@@ -1997,6 +2039,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+@@ -1997,6 +2040,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -133,7 +140,7 @@ index 7bb8159..76e74e2 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -4919,8 +4965,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+@@ -4919,8 +4966,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
          if (netdev->features & NETIF_F_GRO)
                  DPRINTK(PROBE, INFO, "GRO is enabled\n");
  #endif
@@ -145,7 +152,7 @@ index 7bb8159..76e74e2 100644
  	cards_found++;
  	return 0;
  
-@@ -4959,6 +5007,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+@@ -4959,6 +5008,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--20622--30500 b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
index 2db37ac3e..8ecad6fdd 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--20622--30500
+++ b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 0cd6202..acc1f94 100644
+index 0cd6202..8e59446 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -209,6 +209,24 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter,
@@ -74,16 +74,16 @@ index 0cd6202..acc1f94 100644
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
   *
-@@ -1320,6 +1364,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+@@ -1319,6 +1363,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+ 		 */
  		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
  		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
 +#ifdef DEV_NETMAP
-+		ixgbe_netmap_configure_tx_ring(adapter, i);
++		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
 +#endif /* DEV_NETMAP */
+ 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
  	}
  }
- 
 @@ -1582,6 +1629,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
  	ixgbevf_configure_rx(adapter);
  	for (i = 0; i < adapter->num_rx_queues; i++) {
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
index 24ad625de..057e9b5f7 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30500--30600
+++ b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 41e3225..16a7107 100644
+index 41e3225..487ea85 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -186,6 +186,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
@@ -71,16 +71,16 @@ index 41e3225..16a7107 100644
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
   *
-@@ -1296,6 +1337,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+@@ -1295,6 +1336,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+ 		 */
  		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
  		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
 +#ifdef DEV_NETMAP
-+		ixgbe_netmap_configure_tx_ring(adapter, i);
++		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
 +#endif /* DEV_NETMAP */
+ 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
  	}
  }
- 
 @@ -1532,6 +1576,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
  	ixgbevf_configure_rx(adapter);
  	for (i = 0; i < adapter->num_rx_queues; i++) {
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
index 265748988..7cadf029f 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30600--30700
+++ b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 60ef645..7f6efe8 100644
+index 60ef645..6594f9e 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -71,16 +71,16 @@ index 60ef645..7f6efe8 100644
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
   *
-@@ -1040,6 +1081,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+@@ -1039,6 +1080,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+ 		 */
  		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
  		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
 +#ifdef DEV_NETMAP
-+		ixgbe_netmap_configure_tx_ring(adapter, i);
++		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
 +#endif /* DEV_NETMAP */
+ 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
  	}
  }
- 
 @@ -1242,6 +1286,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
  	ixgbevf_configure_rx(adapter);
  	for (i = 0; i < adapter->num_rx_queues; i++) {
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
index 95bbaf738..acf84d794 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index de1ad50..31ac551 100644
+index de1ad50..b0079d7 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -71,16 +71,16 @@ index de1ad50..31ac551 100644
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
   *
-@@ -1027,6 +1068,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+@@ -1026,6 +1067,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+ 		 */
  		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
  		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
 +#ifdef DEV_NETMAP
-+		ixgbe_netmap_configure_tx_ring(adapter, i);
++		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
 +#endif /* DEV_NETMAP */
+ 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
  	}
  }
- 
 @@ -1266,6 +1310,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
  	ixgbevf_configure_rx(adapter);
  	for (i = 0; i < adapter->num_rx_queues; i++) {
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
index ef22eda7f..da625d5b0 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 92ef4cb..1141b53 100644
+index 92ef4cb..f9818b2 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -71,16 +71,16 @@ index 92ef4cb..1141b53 100644
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
   *
-@@ -1118,6 +1159,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+@@ -1117,6 +1158,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+ 		 */
  		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
  		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
 +#ifdef DEV_NETMAP
-+		ixgbe_netmap_configure_tx_ring(adapter, i);
++		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
 +#endif /* DEV_NETMAP */
+ 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
  	}
  }
- 
 @@ -1379,6 +1423,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
  	ixgbevf_configure_rx(adapter);
  	for (i = 0; i < adapter->num_rx_queues; i++) {
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
index 6273ad298..2c5f90a29 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 9df2898..f49ce78 100644
+index 9df2898..f29d0f6 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -175,6 +175,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -63,17 +63,18 @@ index 9df2898..f49ce78 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1161,6 +1201,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+@@ -1152,6 +1192,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
+ 		  32;          /* PTHRESH = 32 */
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
  
- /**
-@@ -1330,6 +1373,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	/* poll to verify queue is enabled */
+@@ -1330,6 +1374,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -84,7 +85,7 @@ index 9df2898..f49ce78 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -3538,6 +3585,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -3538,6 +3586,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
  
  	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
@@ -96,7 +97,7 @@ index 9df2898..f49ce78 100644
  	cards_found++;
  	return 0;
  
-@@ -3570,6 +3622,11 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+@@ -3570,6 +3623,11 @@ static void ixgbevf_remove(struct pci_dev *pdev)
  	struct net_device *netdev = pci_get_drvdata(pdev);
  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
index 3dd0fe086..cd3dc1446 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
+++ b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index d0799e8..002646d 100644
+index d0799e8..e8037a4 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -63,17 +63,18 @@ index d0799e8..002646d 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1208,6 +1248,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+@@ -1199,6 +1239,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
+ 		  32;          /* PTHRESH = 32 */
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
  
- /**
-@@ -1381,6 +1424,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	/* poll to verify queue is enabled */
+@@ -1381,6 +1425,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -84,7 +85,7 @@ index d0799e8..002646d 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -3601,6 +3648,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -3601,6 +3649,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
  
  	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
@@ -96,7 +97,7 @@ index d0799e8..002646d 100644
  	cards_found++;
  	return 0;
  
-@@ -3634,6 +3686,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+@@ -3634,6 +3687,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
  	struct net_device *netdev = pci_get_drvdata(pdev);
  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
index 963df03f7..68d8394f4 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--31200--31300
+++ b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 030a219..75ac799 100644
+index 030a219..b1cefd7 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -63,17 +63,18 @@ index 030a219..75ac799 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1208,6 +1248,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+@@ -1199,6 +1239,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
+ 		  32;          /* PTHRESH = 32 */
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
  
- /**
-@@ -1381,6 +1424,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	/* poll to verify queue is enabled */
+@@ -1381,6 +1425,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -84,7 +85,7 @@ index 030a219..75ac799 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -3598,6 +3645,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -3598,6 +3646,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
  
  	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
@@ -96,7 +97,7 @@ index 030a219..75ac799 100644
  	return 0;
  
  err_register:
-@@ -3630,6 +3682,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+@@ -3630,6 +3683,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
  	struct net_device *netdev = pci_get_drvdata(pdev);
  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
index cd92598af..81cf84e97 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--31300--40000
+++ b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 38c7a0b..ffeb57e 100644
+index 38c7a0b..a533005 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -208,6 +208,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -63,17 +63,18 @@ index 38c7a0b..ffeb57e 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1488,6 +1528,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+@@ -1479,6 +1519,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
+ 		  32;          /* PTHRESH = 32 */
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
  
- /**
-@@ -1624,6 +1667,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	/* poll to verify queue is enabled */
+@@ -1624,6 +1668,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -84,7 +85,7 @@ index 38c7a0b..ffeb57e 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -3877,6 +3924,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -3877,6 +3925,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  		break;
  	}
  
@@ -95,7 +96,7 @@ index 38c7a0b..ffeb57e 100644
  	return 0;
  
  err_register:
-@@ -3914,6 +3965,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+@@ -3914,6 +3966,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40000--40900 b/LINUX/final-patches/vanilla--ixgbevf--40000--40900
index 0b418b278..659b3dea5 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40000--40900
+++ b/LINUX/final-patches/vanilla--ixgbevf--40000--40900
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 4186981..54e0ac2 100644
+index 4186981..5bdcba7 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -283,6 +283,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -63,17 +63,18 @@ index 4186981..54e0ac2 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1594,6 +1634,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+@@ -1585,6 +1625,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
  
- /**
-@@ -1763,6 +1806,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	/* poll to verify queue is enabled */
+@@ -1763,6 +1807,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -84,7 +85,7 @@ index 4186981..54e0ac2 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -4064,6 +4111,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -4064,6 +4112,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  		break;
  	}
  
@@ -95,7 +96,7 @@ index 4186981..54e0ac2 100644
  	return 0;
  
  err_register:
-@@ -4101,6 +4152,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+@@ -4101,6 +4153,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--40b00 b/LINUX/final-patches/vanilla--ixgbevf--40900--40b00
new file mode 100644
index 000000000..4dcb4d137
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--40900--40b00
@@ -0,0 +1,118 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index cbf70fe..1a006e1 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -313,6 +331,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -929,6 +959,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1604,6 +1644,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1612,7 +1656,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(reg_idx));
+ 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ /**
+@@ -1791,6 +1835,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4152,6 +4200,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4189,6 +4241,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 	if (!netdev)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	adapter = netdev_priv(netdev);
+ 
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--99999 b/LINUX/final-patches/vanilla--ixgbevf--40b00--40c00
similarity index 82%
rename from LINUX/final-patches/vanilla--ixgbevf--40900--99999
rename to LINUX/final-patches/vanilla--ixgbevf--40b00--40c00
index 509202c7b..82557a9bc 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40900--99999
+++ b/LINUX/final-patches/vanilla--ixgbevf--40b00--40c00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index cbf70fe..1212ce6 100644
+index 80bab26..0aed560 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -46,7 +46,7 @@ index cbf70fe..1212ce6 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -929,6 +959,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+@@ -919,6 +949,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
  	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
  	struct sk_buff *skb = rx_ring->skb;
  
@@ -63,17 +63,18 @@ index cbf70fe..1212ce6 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  
-@@ -1613,6 +1653,9 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
- 		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
+@@ -1555,6 +1595,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
 +#ifdef DEV_NETMAP
-+	ixgbe_netmap_configure_tx_ring(adapter, reg_idx);
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
 +#endif /* DEV_NETMAP */
- }
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
  
- /**
-@@ -1791,6 +1834,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	/* poll to verify queue is enabled */
+@@ -1742,6 +1786,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
  
  	ixgbevf_rx_desc_queue_enable(adapter, ring);
@@ -84,7 +85,7 @@ index cbf70fe..1212ce6 100644
  	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
  }
  
-@@ -4152,6 +4199,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -4120,6 +4168,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  		break;
  	}
  
@@ -95,7 +96,7 @@ index cbf70fe..1212ce6 100644
  	return 0;
  
  err_register:
-@@ -4189,6 +4240,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+@@ -4157,6 +4209,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
  	if (!netdev)
  		return;
  
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40c00--99999 b/LINUX/final-patches/vanilla--ixgbevf--40c00--99999
new file mode 100644
index 000000000..8c0c4eac9
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--40c00--99999
@@ -0,0 +1,118 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index eee29bd..54102fd 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -313,6 +331,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -919,6 +949,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1555,6 +1595,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1563,7 +1607,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(reg_idx));
+ 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ /**
+@@ -1763,6 +1807,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4147,6 +4195,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4185,6 +4237,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 	if (!netdev)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	adapter = netdev_priv(netdev);
+ 
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 63935ceef..9726b6e3b 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -47,6 +47,8 @@
 #define NM_IXGBE_TDT(ring_nr)		IXGBE_TDT(ring_nr)
 #define NM_IXGBE_TDH(ring_nr)		IXGBE_TDH(ring_nr)
 #define NM_IXGBE_RDT(ring_nr)		IXGBE_RDT(ring_nr)
+#define NM_IXGBE_TDWBAH(ring_nr)	IXGBE_TDWBAH(ring_nr)
+#define NM_IXGBE_TDWBAL(ring_nr)	IXGBE_TDWBAL(ring_nr)
 #define NM_IXGBE_ADAPTER 		ixgbe_adapter
 #define NM_IXGBE_RESETTING 		__IXGBE_RESETTING
 #define NM_IXGBE_DOWN(adapter)		ixgbe_down(adapter)
@@ -144,9 +146,12 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 /***********************************************************************
  *                        ixgbevf                                      *
  ***********************************************************************/
+#define NM_IXGBE_USE_TDH		// TODO switch to head wb
 #define NM_IXGBE_TDT(ring_nr)		IXGBE_VFTDT(ring_nr)
 #define NM_IXGBE_TDH(ring_nr)		IXGBE_VFTDH(ring_nr)
 #define NM_IXGBE_RDT(ring_nr)		IXGBE_VFRDT(ring_nr)
+#define NM_IXGBE_TDWBAH(ring_nr)	IXGBE_VFTDWBAH(ring_nr)
+#define NM_IXGBE_TDWBAL(ring_nr)	IXGBE_VFTDWBAL(ring_nr)
 #ifdef NETMAP_LINUX_IXGBEVF_IXGBE_MACROS
 #define NM_IXGBE_TX_DESC(_1, _2)	IXGBE_TX_DESC_ADV(*(_1), _2)
 #define NM_IXGBE_RX_DESC(_1, _2)	IXGBE_RX_DESC_ADV(*(_1), _2)
@@ -307,11 +312,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			/* device-specific */
 			union ixgbe_adv_tx_desc *curr = NM_IXGBE_TX_DESC(txr, nic_i);
 			int flags = (slot->flags & NS_REPORT ||
-#ifndef NM_IXGBEVF
-				!(nic_i % 32)
-#else /* NM_IXGBEVF */
 				nic_i == 0 || nic_i == report_frequency
-#endif /* NM_IXGBEVF */
 				) ? IXGBE_TXD_CMD_RS : 0;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
@@ -343,14 +344,14 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
-#ifndef NM_IXGBEVF
+#ifndef NM_IXGBE_USE_TDH
 	(void)reclaim_tx;
 	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
 		u32 h = *(volatile u32*)&txr->next_to_use;
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
-#else /* NM_IXGBEVF */
+#else /* NM_IXGBE_USE_TDH */
 	/*
 	 * Because this is expensive (we read a NIC register etc.)
 	 * we only do it in specific cases (see below).
@@ -398,7 +399,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 		txr->next_to_clean = nic_i;
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
 	}
-#endif /* NM_IXGBEVF */
+#endif /* NM_IXGBE_USE_TDH */
 out:
 
 	return 0;
@@ -537,39 +538,32 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
  * Otherwise return false.
  */
 static u32
-ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr
-#ifndef NM_IXGBEVF
-		, u32 txdctl
-#endif /* !NM_IXGBEVF */
+ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u32 txdctl
 		)
 {
 	struct netmap_adapter *na = NA(adapter->netdev);
 	struct netmap_slot *slot;
-#ifndef NM_IXGBEVF
+#ifndef NM_IXGBE_USE_TDH
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
 	u64 wba;
-#else /* NM_IXGBEVF */
-	u32 txdctl = 0;
-#endif /* NM_IXGBEVF */
+#endif /* !NM_IXGBE_USE_TDH */
 	//int j;
 
         slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
 		return txdctl;	// not in native netmap mode
 
-#ifndef NM_IXGBEVF
+#ifndef NM_IXGBE_USE_TDH
 	/* we reset WTRESH (it must be 0 according to specs) */
 	txdctl &= ~(0x7f << 16);
 
 	/* we reuse the next_to_use+next_to_clean fields to receive the hw head */
 	wba = (u64)virt_to_phys(&txr->next_to_use);
-	IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(ring_nr),
+	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAL(ring_nr),
 		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);
-	IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(ring_nr), wba >> 32);
-#else /* NM_IXGBEVF */
-	txdctl = 1;
-#endif /* NM_IXGBEVF */
+	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAH(ring_nr), wba >> 32);
+#endif /* !NM_IXGBE_USE_TDH */
 
 #if 0
 	/*

From 7c3175170513006f4fea4361269782cc3e050ded Mon Sep 17 00:00:00 2001
From: Radha krishna Saragadam 
Date: Sat, 19 Aug 2017 15:53:13 -0400
Subject: [PATCH 0173/2207] Updated the README about e1000 patch issue seen in
 3.10 kernel version

---
 LINUX/README | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/LINUX/README b/LINUX/README
index 0a929f621..f151c5631 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -267,6 +267,17 @@ COMMON PROBLEMS
   In emulated netmap mode (i.e. with unpatched drivers) VLAN tags are never
   visible by the netmap application.
 
+* if you are using e1000 with netmap, you verify the result of the patch from
+  final-patches/vanilla--e1000--20620--31200 that was applied on
+  e1000/e1000_main.c. It was observed that when using older kernel version
+  netmap hook that needs to be applied on e1000_clean_rx_irq is actually 
+  applied on e1000_clean_jumbo_rx_irq. As a result it will end up in packets
+  going directly from NIC Rx Rings to Host stack.
+
+     # Do manual changes in e1000/e1000_main.c
+
+  If patch is wrongly applied on e1000_clean_jumbo_rx_irq, then apply the
+  required netmap hook in e1000_clean_rx_irq from e1000_clean_jumbo_rx_irq.
 
 REVISION HISTORY
 -----------------

From 8ded2fce7b4001cd882b0a5d53a610f3c03c860b Mon Sep 17 00:00:00 2001
From: Radha krishna Saragadam 
Date: Sun, 20 Aug 2017 02:26:40 -0400
Subject: [PATCH 0174/2207] Updated common problems section for e1000 patch
 based on comments

---
 LINUX/README | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/LINUX/README b/LINUX/README
index f151c5631..5cdbfb3e1 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -267,17 +267,15 @@ COMMON PROBLEMS
   In emulated netmap mode (i.e. with unpatched drivers) VLAN tags are never
   visible by the netmap application.
 
-* if you are using e1000 with netmap, you verify the result of the patch from
-  final-patches/vanilla--e1000--20620--31200 that was applied on
-  e1000/e1000_main.c. It was observed that when using older kernel version
+* if you are using e1000 with netmap, you should verify the result of the patch
+  from final-patches/vanilla--e1000--20620--31200 that was applied on
+  e1000/e1000_main.c. It was observed that when using non-vanilla kernel version
   netmap hook that needs to be applied on e1000_clean_rx_irq is actually 
   applied on e1000_clean_jumbo_rx_irq. As a result it will end up in packets
   going directly from NIC Rx Rings to Host stack.
 
-     # Do manual changes in e1000/e1000_main.c
-
-  If patch is wrongly applied on e1000_clean_jumbo_rx_irq, then apply the
-  required netmap hook in e1000_clean_rx_irq from e1000_clean_jumbo_rx_irq.
+     # You should fix this issue by manually patching e1000/e1000_main.c to add
+  the correct netmap hook in e1000_clean_rx_irq
 
 REVISION HISTORY
 -----------------

From c86ed9faafd4139280a756695da9a0f15ec81aed Mon Sep 17 00:00:00 2001
From: Radha krishna Saragadam 
Date: Sun, 20 Aug 2017 14:57:11 -0400
Subject: [PATCH 0175/2207] Updated common problems section for e1000 patch
 based on comments

---
 LINUX/README | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/README b/LINUX/README
index 5cdbfb3e1..e48512ae3 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -273,8 +273,8 @@ COMMON PROBLEMS
   netmap hook that needs to be applied on e1000_clean_rx_irq is actually 
   applied on e1000_clean_jumbo_rx_irq. As a result it will end up in packets
   going directly from NIC Rx Rings to Host stack.
-
-     # You should fix this issue by manually patching e1000/e1000_main.c to add
+      
+      You should fix this issue by manually patching e1000/e1000_main.c to add
   the correct netmap hook in e1000_clean_rx_irq
 
 REVISION HISTORY

From e944f3c997d2d3a00d49b347e14ae6a264885fce Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 24 Aug 2017 13:49:27 +0200
Subject: [PATCH 0176/2207] lb: readability improvement

---
 apps/lb/lb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index f56e89198..57a2d1c24 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -856,7 +856,7 @@ int main(int argc, char **argv)
 
 		for (i = 0; i < npipes; ++i) {
 			struct netmap_ring *ring = ports[i].ring;
-			if (!glob_arg.busy_wait && nm_ring_next(ring, ring->tail) == ring->cur) {
+			if (!glob_arg.busy_wait && !nm_tx_pending(ring)) {
 				/* no need to poll, there are no packets pending */
 				continue;
 			}

From 2d58149d8c519c34762c5b84d960790fa6351a43 Mon Sep 17 00:00:00 2001
From: Borislav Matvey 
Date: Mon, 28 Aug 2017 01:32:09 -0700
Subject: [PATCH 0177/2207] Check if carrier present instead of running.

Replace the check whether interface is running with a check whether
there is actual carrier, otherwise packets will be reported as sent
although there is no actual link on the interface.

Tested by sending packets with:
pkt-gen -i ethX -f tx -n 0 -l 1500

Pkt-gen shows that it is sending packets even after the cable was
physically unplugged from the interface.

The check in ixgbe is the same in txsync handler.
---
 LINUX/i40e_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index f9949cd7d..a52602d3b 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -283,7 +283,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 	struct i40e_vsi *vsi = np->vsi;
 	struct i40e_ring *txr;
 
-	if (!netif_running(ifp))
+	if (!netif_carrier_ok(ifp))
 		return 0;
 
 	txr = NM_I40E_TX_RING(vsi, kring->ring_id);

From 5c9957fa7608d9707aa290b25fc2e0a099d6735a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 17 Sep 2017 01:53:17 -0400
Subject: [PATCH 0178/2207] linux: virtio-net: fix receive buffer
 initialization bug

The init_buffer function needs to expose all the netmap receive
buffers to the hypervisor. Before this patch, rxsync used to
return uninitialized (or old) receive buffers.
---
 LINUX/virtio_netmap.h | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 41e3c7a4d..f0e4f23e1 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -513,18 +513,20 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 	rmb();
 	/*
 	 * First part: import newly received packets.
-	 * Only accept our
-	 * own buffers (matching the token). We should only get
-	 * matching buffers, because of free_unused_bufs()
-	 * and virtio_netmap_init_buffers().
+	 * Only accept our own buffers (matching the token). We should only get
+	 * matching buffers, because of free_unused_bufs() and
+	 * virtio_netmap_init_buffers(). We may need to stop early to avoid
+	 * hwtail to overrun hwcur;
 	 */
 	if (netmap_no_pendintr || force_update) {
+		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
 		uint16_t slot_flags = kring->nkr_slot_flags;
 		struct netmap_adapter *token;
 
+
 		nm_i = kring->nr_hwtail;
 		n = 0;
-		for (;;) {
+		while (nm_i != hwtail_lim) {
 			int len;
 			token = virtqueue_get_buf(vq, &len);
 			if (token == NULL)
@@ -637,11 +639,16 @@ virtio_netmap_init_buffers(struct virtnet_info *vi)
 			continue;
 		}
 
-		/* Add up to na>-num_rx_desc-1 buffers to this RX virtqueue.
-		 * It's important to leave one virtqueue slot free, otherwise
-		 * we can run into ring->cur/ring->tail wraparounds.
+		/*
+		 * Add exactly na->num_rx_desc descriptor chains to this RX
+		 * virtqueue, as virtio_netmap_rxsync() assumes the chains
+		 * are returned in the same order by virtqueue_get_buf().
+		 * It is technically possible that the hypervisor returns
+		 * na->num_rx_desc chains before the user can consume them,
+		 * so virtio_netmap_rxsync() must prevent ring->tail to
+		 * wrap around ring->head.
 		 */
-		for (i = 0; i < na->num_rx_desc-1; i++) {
+		for (i = 0; i < na->num_rx_desc; i++) {
 			void *addr;
 
 			slot = &ring->slot[i];

From a60d4e54937c081ee0bbe30f6b4ec873baebe09b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Sep 2017 14:57:18 +0200
Subject: [PATCH 0179/2207] linux/igb: Intel 5.4.5.13 version

---
 LINUX/default-config.mak.in_             |   2 +-
 LINUX/final-patches/intel--igb--5.3.5.12 | 138 +++++++++++++++++++++++
 2 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.12

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 75037da5f..4d6021ed8 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -16,5 +16,5 @@ $(call enabled_intel_driver,ixgbevf,4.2.1)
 e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.5.10)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
-$(call enabled_intel_driver,igb,5.3.5.10)
+$(call enabled_intel_driver,igb,5.3.5.12)
 $(call enabled_intel_driver,i40e,2.1.26)
diff --git a/LINUX/final-patches/intel--igb--5.3.5.12 b/LINUX/final-patches/intel--igb--5.3.5.12
new file mode 100644
index 000000000..9e4f55e73
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.12
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index e3bd4f3..2f6895a 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -46,19 +46,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -115,9 +115,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 6c9b112..65a4e93 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * igb_init_module - Driver Registration Routine
+  *
+@@ -3061,6 +3065,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3264,6 +3272,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3672,6 +3684,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7226,6 +7241,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8240,6 +8260,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8558,6 +8583,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 39ad7dab8c8b32e9bdc6d7482e7da60094d5f700 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 19 Sep 2017 10:44:04 +0200
Subject: [PATCH 0180/2207] linux/e1000e: Intel 3.3.6 version

---
 LINUX/default-config.mak.in_             |   2 +-
 LINUX/final-patches/intel--e1000e--3.3.6 | 110 +++++++++++++++++++++++
 2 files changed, 111 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.3.6

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 4d6021ed8..2e9dad3e7 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -14,7 +14,7 @@ enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driv
 $(call enabled_intel_driver,ixgbe,5.2.3)
 $(call enabled_intel_driver,ixgbevf,4.2.1)
 e1000e@cflags := -fno-pie
-$(call enabled_intel_driver,e1000e,3.3.5.10)
+$(call enabled_intel_driver,e1000e,3.3.6)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 $(call enabled_intel_driver,igb,5.3.5.12)
 $(call enabled_intel_driver,i40e,2.1.26)
diff --git a/LINUX/final-patches/intel--e1000e--3.3.6 b/LINUX/final-patches/intel--e1000e--3.3.6
new file mode 100644
index 000000000..beced2309
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.3.6
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index c4558ce..b951433 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -36,7 +36,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -139,7 +139,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -345,6 +345,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index 815b777..bb06ea4 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -499,6 +499,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1022,6 +1026,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1339,6 +1354,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4237,6 +4257,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8433,6 +8457,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8534,6 +8562,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 2b954ad7ad41afaef8ca6f46d70c8f4dde2c5d58 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Sep 2017 14:14:35 +0200
Subject: [PATCH 0181/2207] linux/ixgbe: fix paths in 5.2.4 patch

---
 LINUX/final-patches/intel--ixgbe--5.2.4 | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/LINUX/final-patches/intel--ixgbe--5.2.4 b/LINUX/final-patches/intel--ixgbe--5.2.4
index 5c62eecce..6195267a1 100644
--- a/LINUX/final-patches/intel--ixgbe--5.2.4
+++ b/LINUX/final-patches/intel--ixgbe--5.2.4
@@ -1,7 +1,7 @@
-diff --git a/src/Makefile b/src/Makefile
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
 index a3cc895..a038975 100644
---- a/src/Makefile
-+++ b/src/Makefile
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
 @@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
  # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
  #
@@ -61,10 +61,10 @@ index a3cc895..a038975 100644
  # Clean the module subdirectories
  clean:
  	@+$(call devkernelbuild,clean)
-diff --git a/src/ixgbe_main.c b/src/ixgbe_main.c
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
 index c7a1499..f2a3c3e 100644
---- a/src/ixgbe_main.c
-+++ b/src/ixgbe_main.c
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
  	}
  }

From ecd86e52c49cb77021d13dc7528e78ca0102f4ba Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 21 Sep 2017 22:00:10 +0200
Subject: [PATCH 0182/2207] nm_open: split parse functionality in new nm_parse

---
 sys/net/netmap_user.h | 93 ++++++++++++++++++++++++++++---------------
 1 file changed, 60 insertions(+), 33 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 758084c1d..f7070f52f 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -611,39 +611,21 @@ nm_is_identifier(const char *s, const char *e)
 	return 1;
 }
 
-/*
- * Try to open, return descriptor if successful, NULL otherwise.
- * An invalid netmap name will return errno = 0;
- * You can pass a pointer to a pre-filled nm_desc to add special
- * parameters. Flags is used as follows
- * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
- *			if the nr_arg2 (memory block) matches.
- * NM_OPEN_ARG1		use req.nr_arg1 from arg
- * NM_OPEN_ARG2		use req.nr_arg2 from arg
- * NM_OPEN_RING_CFG	user ring config from arg
- */
-static struct nm_desc *
-nm_open(const char *ifname, const struct nmreq *req,
-	uint64_t new_flags, const struct nm_desc *arg)
+#define MAXERRMSG 80
+static int
+nm_parse(const char *ifname, struct nm_desc *d, char *err)
 {
-	struct nm_desc *d = NULL;
-	const struct nm_desc *parent = arg;
-	u_int namelen;
-	uint32_t nr_ringid = 0, nr_flags, nr_reg;
+	int is_vale;
 	const char *port = NULL;
 	const char *vpname = NULL;
-#define MAXERRMSG 80
+	u_int namelen;
+	uint32_t nr_ringid = 0, nr_flags;
 	char errmsg[MAXERRMSG] = "";
-	enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK, P_MEMID } p_state;
-	int is_vale;
 	long num;
 	uint16_t nr_arg2 = 0;
+	enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK, P_MEMID } p_state;
 
-	if (strncmp(ifname, "netmap:", 7) &&
-			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
-		errno = 0; /* name not recognised, not an error */
-		return NULL;
-	}
+	errno = 0;
 
 	is_vale = (ifname[0] == 'v');
 	if (is_vale) {
@@ -679,6 +661,9 @@ nm_open(const char *ifname, const struct nmreq *req,
 		snprintf(errmsg, MAXERRMSG, "name too long");
 		goto fail;
 	}
+	memcpy(d->req.nr_name, ifname, namelen);
+	d->req.nr_name[namelen] = '\0';
+
 	p_state = P_START;
 	nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
 	while (*port) {
@@ -798,6 +783,49 @@ nm_open(const char *ifname, const struct nmreq *req,
 			(nr_flags & NR_ZCOPY_MON) ? "ZCOPY_MON" : "",
 			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
 			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
+
+	d->req.nr_flags |= nr_flags;
+	d->req.nr_ringid |= nr_ringid;
+	if (nr_arg2)
+		d->req.nr_arg2 = nr_arg2;
+
+	d->self = d;
+
+	return 0;
+fail:
+	if (!errno)
+		errno = EINVAL;
+	if (err)
+		strncpy(err, errmsg, MAXERRMSG);
+	return -1;
+}
+
+/*
+ * Try to open, return descriptor if successful, NULL otherwise.
+ * An invalid netmap name will return errno = 0;
+ * You can pass a pointer to a pre-filled nm_desc to add special
+ * parameters. Flags is used as follows
+ * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
+ *			if the nr_arg2 (memory block) matches.
+ * NM_OPEN_ARG1		use req.nr_arg1 from arg
+ * NM_OPEN_ARG2		use req.nr_arg2 from arg
+ * NM_OPEN_RING_CFG	user ring config from arg
+ */
+static struct nm_desc *
+nm_open(const char *ifname, const struct nmreq *req,
+	uint64_t new_flags, const struct nm_desc *arg)
+{
+	struct nm_desc *d = NULL;
+	const struct nm_desc *parent = arg;
+	char errmsg[MAXERRMSG] = "";
+	uint32_t nr_reg;
+
+	if (strncmp(ifname, "netmap:", 7) &&
+			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
+		errno = 0; /* name not recognised, not an error */
+		return NULL;
+	}
+
 	d = (struct nm_desc *)calloc(1, sizeof(*d));
 	if (d == NULL) {
 		snprintf(errmsg, MAXERRMSG, "nm_desc alloc failure");
@@ -813,16 +841,15 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (req)
 		d->req = *req;
+
+	if (!(new_flags & NM_OPEN_IFNAME)) {
+		if (nm_parse(ifname, d, errmsg) < 0)
+			goto fail;
+	}
+
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= ~NETMAP_RING_MASK;
 
-	/* these fields are overridden by ifname and flags processing */
-	d->req.nr_ringid |= nr_ringid;
-	d->req.nr_flags |= nr_flags;
-	if (nr_arg2)
-		d->req.nr_arg2 = nr_arg2;
-	memcpy(d->req.nr_name, ifname, namelen);
-	d->req.nr_name[namelen] = '\0';
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
 		if (new_flags & NM_OPEN_ARG1)

From 90effa7b946beb5c3888b0fc5c3d37f2d1475aaf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 21 Sep 2017 22:01:50 +0200
Subject: [PATCH 0183/2207] pkt-gen: use nm_parse to avoid nm_close

---
 apps/pkt-gen/pkt-gen.c | 41 ++++++++++++++++++++---------------------
 1 file changed, 20 insertions(+), 21 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d3cdbd287..2883121f3 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2888,19 +2888,26 @@ main(int arc, char **argv)
     } else if (g.dummy_send) { /* but DEV_NETMAP */
 	D("using a dummy send routine");
     } else {
-	struct nmreq base_nmd;
+	struct nm_desc base_nmd;
+	char errmsg[MAXERRMSG];
+	u_int flags;
 
 	bzero(&base_nmd, sizeof(base_nmd));
 
-	parse_nmr_config(g.nmr_config, &base_nmd);
+	parse_nmr_config(g.nmr_config, &base_nmd.req);
 	if (g.extra_bufs) {
-		base_nmd.nr_arg3 = g.extra_bufs;
+		base_nmd.req.nr_arg3 = g.extra_bufs;
 	}
 	if (g.extra_pipes) {
-	    base_nmd.nr_arg1 = g.extra_pipes;
+	    base_nmd.req.nr_arg1 = g.extra_pipes;
 	}
 
-	base_nmd.nr_flags |= NR_ACCEPT_VNET_HDR;
+	base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR;
+
+	if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) {
+		D("Invalid name '%s': %s", g.ifname, errmsg);
+		goto out;
+	}
 
 	/*
 	 * Open the netmap device using nm_open().
@@ -2909,26 +2916,18 @@ main(int arc, char **argv)
 	 * which in turn may take some time for the PHY to
 	 * reconfigure. We do the open here to have time to reset.
 	 */
-	g.nmd = nm_open(g.ifname, &base_nmd, 0, NULL);
+	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
+		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
+	if (g.nthreads > 1) {
+		base_nmd.req.nr_flags &= ~NR_REG_MASK;
+		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
+		base_nmd.req.nr_ringid = 0;
+	}
+	g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd);
 	if (g.nmd == NULL) {
 		D("Unable to open %s: %s", g.ifname, strerror(errno));
 		goto out;
 	}
-
-	if (g.nthreads > 1) {
-		struct nm_desc saved_desc = *g.nmd;
-		saved_desc.self = &saved_desc;
-		saved_desc.mem = NULL;
-		nm_close(g.nmd);
-		saved_desc.req.nr_flags &= ~NR_REG_MASK;
-		saved_desc.req.nr_flags |= NR_REG_ONE_NIC;
-		saved_desc.req.nr_ringid = 0;
-		g.nmd = nm_open(g.ifname, &base_nmd, NM_OPEN_IFNAME, &saved_desc);
-		if (g.nmd == NULL) {
-			D("Unable to open %s: %s", g.ifname, strerror(errno));
-			goto out;
-		}
-	}
 	g.main_fd = g.nmd->fd;
 	D("mapped %dKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
 

From 9d9e5db3675acf60fa8ac01217f8f47389b1640c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 24 Sep 2017 19:16:19 +0200
Subject: [PATCH 0184/2207] vale: fix crash due to NULL rx rings

Ports attached to a VALE switch may have not have allocated all the
RX rings, therefore the sender must check for the ring
existance before trying to write into it.

Partial allocation may happen if the port has many rings and
only one is opened (-x syntax in nm_open), or if the port
is opened only for TX (/T flag in nm_open).
---
 sys/dev/netmap/netmap_vale.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index b9cdd1d16..ce7f4c9d4 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1924,6 +1924,9 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 			dst_nr = dst_nr % nrings;
 		kring = &dst_na->up.rx_rings[dst_nr];
 		ring = kring->ring;
+		/* the destination ring may have not been opened for RX */
+		if (unlikely(ring == NULL))
+			goto cleanup;
 		lim = kring->nkr_num_slots - 1;
 
 retry:

From 7bbd0b0004cb257d9113e24dd4e72eecce9cf5fa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 24 Sep 2017 19:51:00 +0200
Subject: [PATCH 0185/2207] vale: fix race in port attach/detach

When a port, opened on a subset of the rings, is detached
from a VALE switch, its rings are marked OFF in mutual exclusion
with the switch tx routine, but are deleted only later, when
the mutual exclusion has been left. With this patch the switch
tx routine skips rings marked OFF.
---
 sys/dev/netmap/netmap_vale.c |  2 +-
 sys/net/netmap_user.h        | 19 ++++++++++++-------
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index ce7f4c9d4..ac58a7711 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1925,7 +1925,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		kring = &dst_na->up.rx_rings[dst_nr];
 		ring = kring->ring;
 		/* the destination ring may have not been opened for RX */
-		if (unlikely(ring == NULL))
+		if (unlikely(ring == NULL || kring->nr_mode != NKR_NETMAP_ON))
 			goto cleanup;
 		lim = kring->nkr_num_slots - 1;
 
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index f7070f52f..825363475 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -889,12 +889,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
-        /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
-	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
-	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
-		goto fail;
-	}
-
 	nr_reg = d->req.nr_flags & NR_REG_MASK;
 
 	if (nr_reg == NR_REG_SW) { /* host stack */
@@ -919,6 +913,13 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->first_rx_ring = d->last_rx_ring = 0;
 	}
 
+        /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
+	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
+	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
+		goto fail;
+	}
+
+
 #ifdef DEBUG_NETMAP_USER
     { /* debugging code */
 	int i;
@@ -998,7 +999,11 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 	}
 	{
 		struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
-		struct netmap_ring *r = NETMAP_RXRING(nifp, );
+		struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
+		if ((void *)r == (void *)nifp) {
+			/* the descriptor is open for TX only */
+			r = NETMAP_TXRING(nifp, d->first_tx_ring);
+		}
 
 		*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
 		*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;

From 6a7ff5a9f795d8914213369851bc07e66452c149 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 4 Oct 2017 14:37:49 +0200
Subject: [PATCH 0186/2207] linux: configure: add probe test to check if
 skb->users has type refcount_t

---
 LINUX/configure | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 9c4b17eea..5659d6f5f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1421,6 +1421,17 @@ EOF
 	}
 EOF
 
+  # are skb->users and qdisc->refcnt atomic_t or refcount_t ?
+  add_test 'have REFCOUNT_T' <
+
+	unsigned int
+	dummy(void) {
+                struct sk_buff *skb = NULL;
+                return refcount_read(&skb->users);
+	}
+EOF
+
 
   #####################################################
   # checks related to drivers                         #

From 3a100e22ac0a1a4289c137a07ad31a437783f017 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 4 Oct 2017 14:47:50 +0200
Subject: [PATCH 0187/2207] linux: fix compilation failures due to introduction
 of refcount_t

---
 LINUX/bsd_glue.h     |  4 ++++
 LINUX/netmap_linux.c | 10 +++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index e171e6e32..0663b3da3 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -233,7 +233,11 @@ struct thread;
 #define	m_nextpkt		next			// chain of mbufs
 #define m_freem(m)		dev_kfree_skb_any(m)	// free a sk_buff
 
+#ifdef NETMAP_LINUX_HAVE_REFCOUNT_T
+#define MBUF_REFCNT(m)			refcount_read(&((m)->users))
+#else  /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
 #define MBUF_REFCNT(m)			NM_ATOMIC_READ(&((m)->users))
+#endif /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
 /*
  * on tx we force skb->queue_mapping = ring_nr,
  * but on rx it is the driver that sets the value,
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 07c6de913..aebc3a86b 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -642,7 +642,11 @@ nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 		qdisc_destroy(ifp->qdisc);
 	}
 	if (intercept) {
+#ifdef NETMAP_LINUX_HAVE_REFCOUNT_T
+		refcount_inc(&fqdisc->refcnt);
+#else  /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
 		atomic_inc(&fqdisc->refcnt);
+#endif /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
 		ifp->qdisc = fqdisc;
 	} else {
 		ifp->qdisc = &noop_qdisc;
@@ -747,7 +751,11 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 
 	/* Hold a reference on this, we are going to recycle mbufs as
 	 * much as possible. */
-	NM_ATOMIC_INC(&m->users);
+#ifdef NETMAP_LINUX_HAVE_REFCOUNT_T
+	refcount_inc(&m->users);
+#else  /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
+	atomic_inc(&m->users);
+#endif /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
 
 	/* On linux m->dev is not reliable, since it can be changed by the
 	 * ndo_start_xmit() callback. This happens, for instance, with veth

From 9ce367ae3b2049f4addcc18ad402491015f39148 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 Sep 2017 17:52:08 +0200
Subject: [PATCH 0188/2207] linux/i40e: store pci dev reference for iommu
 mapping

---
 LINUX/i40e_netmap_linux.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index a52602d3b..f20799a48 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -226,6 +226,7 @@ i40e_netmap_attach(struct i40e_vsi *vsi)
 	bzero(&na, sizeof(na));
 
 	na.ifp = vsi->netdev;
+	na.pdev = &vsi->back->pdev->dev;
 	// XXX check that queues is set.
 	na.num_tx_desc = NM_I40E_TX_RING(vsi, 0)->count;
 	na.num_rx_desc = NM_I40E_RX_RING(vsi, 0)->count;

From 191aab0174c2d636ceb7d3793d366274336e30a1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 5 Oct 2017 17:01:27 +0200
Subject: [PATCH 0189/2207] linux/mem: release iommu group reference

---
 LINUX/netmap_linux.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index aebc3a86b..45738e170 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -172,6 +172,9 @@ int nm_iommu_group_id(struct device *dev)
 		return 0;
 
 	id = iommu_group_id(grp);
+
+	iommu_group_put(grp);
+
 	return id;
 }
 #else /* ! HAVE_IOMMU */

From b2e99d984f890f74fa1a9cbf57ff43121f575a19 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Mar 2017 18:45:15 +0100
Subject: [PATCH 0190/2207] mem: refactor bitmap initialization

---
 sys/dev/netmap/netmap_mem2.c | 139 +++++++++++++++++++----------------
 1 file changed, 77 insertions(+), 62 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c7b42de90..cdf33f612 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -296,58 +296,88 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	return nmd->lasterr;
 }
 
+
+static int
+netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
+{
+	u_int n, j;
+
+	if (p->bitmap == NULL) {
+		/* Allocate the bitmap */
+		n = (p->objtotal + 31) / 32;
+		p->bitmap = nm_os_malloc(sizeof(uint32_t) * n);
+		if (p->bitmap == NULL) {
+			D("Unable to create bitmap (%d entries) for allocator '%s'", (int)n,
+			    p->name);
+			return ENOMEM;
+		}
+		p->bitmap_slots = n;
+	} else {
+		memset(p->bitmap, 0, p->bitmap_slots);
+	}
+
+	p->objfree = 0;
+	/*
+	 * Set all the bits in the bitmap that have
+	 * corresponding buffers to 1 to indicate they are
+	 * free.
+	 */
+	for (j = 0; j < p->objtotal; j++) {
+		if (p->lut[j].vaddr != NULL) {
+			p->bitmap[ (j>>5) ] |=  ( 1U << (j & 31U) );
+			p->objfree++;
+		}
+	}
+
+	if (p->objfree == 0)
+		return ENOMEM;
+
+	return 0;
+}
+
+static int
+netmap_mem_init_bitmaps(struct netmap_mem_d *nmd)
+{
+	int i, error = 0;
+
+	for (i = 0; i < NETMAP_POOLS_NR; i++) {
+		struct netmap_obj_pool *p = &nmd->pools[i];
+
+		error = netmap_init_obj_allocator_bitmap(p);
+		if (error)
+			return error;
+	}
+
+	/*
+	 * buffers 0 and 1 are reserved
+	 */
+	if (nmd->pools[NETMAP_BUF_POOL].objfree < 2) {
+		return ENOMEM;
+	}
+
+	nmd->pools[NETMAP_BUF_POOL].objfree -= 2;
+	if (nmd->pools[NETMAP_BUF_POOL].bitmap) {
+		/* XXX This check is a workaround that prevents a
+		 * NULL pointer crash which currently happens only
+		 * with ptnetmap guests.
+		 * Removed shared-info --> is the bug still there? */
+		nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3U;
+	}
+	return 0;
+}
+
 void
 netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	NMA_LOCK(nmd);
 	netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na);
 	if (nmd->active == 1) {
-		u_int i;
-
 		/*
 		 * Reset the allocator when it falls out of use so that any
 		 * pool resources leaked by unclean application exits are
 		 * reclaimed.
 		 */
-		for (i = 0; i < NETMAP_POOLS_NR; i++) {
-			struct netmap_obj_pool *p;
-			u_int j;
-
-			p = &nmd->pools[i];
-			p->objfree = p->objtotal;
-			/*
-			 * Reproduce the net effect of the M_ZERO malloc()
-			 * and marking of free entries in the bitmap that
-			 * occur in finalize_obj_allocator()
-			 */
-			memset(p->bitmap,
-			    '\0',
-			    sizeof(uint32_t) * ((p->objtotal + 31) / 32));
-
-			/*
-			 * Set all the bits in the bitmap that have
-			 * corresponding buffers to 1 to indicate they are
-			 * free.
-			 */
-			for (j = 0; j < p->objtotal; j++) {
-				if (p->lut[j].vaddr != NULL) {
-					p->bitmap[ (j>>5) ] |=  ( 1 << (j & 31) );
-				}
-			}
-		}
-
-		/*
-		 * Per netmap_mem_finalize_all(),
-		 * buffers 0 and 1 are reserved
-		 */
-		nmd->pools[NETMAP_BUF_POOL].objfree -= 2;
-		if (nmd->pools[NETMAP_BUF_POOL].bitmap) {
-			/* XXX This check is a workaround that prevents a
-			 * NULL pointer crash which currently happens only
-			 * with ptnetmap guests.
-			 * Removed shared-info --> is the bug still there? */
-			nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3;
-		}
+		netmap_mem_init_bitmaps(nmd);
 	}
 	nmd->ops->nmd_deref(nmd);
 
@@ -1235,18 +1265,8 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 		goto clean;
 	}
 
-	/* Allocate the bitmap */
-	n = (p->objtotal + 31) / 32;
-	p->bitmap = nm_os_malloc(sizeof(uint32_t) * n);
-	if (p->bitmap == NULL) {
-		D("Unable to create bitmap (%d entries) for allocator '%s'", (int)n,
-		    p->name);
-		goto clean;
-	}
-	p->bitmap_slots = n;
-
 	/*
-	 * Allocate clusters, init pointers and bitmap
+	 * Allocate clusters, init pointers
 	 */
 
 	n = p->_clustsize;
@@ -1274,7 +1294,6 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 				goto out;
 			lim = i / 2;
 			for (i--; i >= lim; i--) {
-				p->bitmap[ (i>>5) ] &=  ~( 1 << (i & 31) );
 				if (i % p->_clustentries == 0 && p->lut[i].vaddr)
 					contigfree(p->lut[i].vaddr,
 						n, M_NETMAP);
@@ -1287,8 +1306,7 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 			break;
 		}
 		/*
-		 * Set bitmap and lut state for all buffers in the current
-		 * cluster.
+		 * Set lut state for all buffers in the current cluster.
 		 *
 		 * [i, lim) is the set of buffer indexes that cover the
 		 * current cluster.
@@ -1298,15 +1316,11 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 		 * of p->_objsize.
 		 */
 		for (; i < lim; i++, clust += p->_objsize) {
-			p->bitmap[ (i>>5) ] |=  ( 1 << (i & 31) );
 			p->lut[i].vaddr = clust;
 			p->lut[i].paddr = vtophys(clust);
 		}
 	}
-	p->objfree = p->objtotal;
 	p->memtotal = p->numclusters * p->_clustsize;
-	if (p->objfree == 0)
-		goto clean;
 	if (netmap_verbose)
 		D("Pre-allocated %d clusters (%d/%dKB) for '%s'",
 		    p->numclusters, p->_clustsize >> 10,
@@ -1410,9 +1424,10 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
 			goto error;
 		nmd->nm_totalsize += nmd->pools[i].memtotal;
 	}
-	/* buffers 0 and 1 are reserved */
-	nmd->pools[NETMAP_BUF_POOL].objfree -= 2;
-	nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3;
+	nmd->lasterr = netmap_mem_init_bitmaps(nmd);
+	if (nmd->lasterr)
+		goto error;
+
 	nmd->flags |= NETMAP_MEM_FINALIZED;
 
 	if (netmap_verbose)

From 546c4e63c9a8c32fd64f6799ebeff5e993d8c6db Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 6 Oct 2017 13:50:16 +0200
Subject: [PATCH 0191/2207] linux: fix broken dma-mapping

---
 sys/dev/netmap/netmap_kern.h | 36 +++++++++++++---
 sys/dev/netmap/netmap_mem2.c | 83 +++++++++++++++++++++++++++++++-----
 2 files changed, 102 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8877284de..55b5b0fff 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -624,6 +624,7 @@ tail->|                 |<-hwtail    |                 |<-hwlease
 
 struct netmap_lut {
 	struct lut_entry *lut;
+	struct plut_entry *plut;
 	uint32_t objtotal;	/* max buffer index */
 	uint32_t objsize;	/* buffer size */
 };
@@ -1611,13 +1612,14 @@ static void netmap_dmamap_cb(__unused void *arg,
 /* bus_dmamap_load wrapper: call aforementioned function if map != NULL.
  * XXX can we do it without a callback ?
  */
-static inline void
+static inline int
 netmap_load_map(struct netmap_adapter *na,
 	bus_dma_tag_t tag, bus_dmamap_t map, void *buf)
 {
 	if (map)
 		bus_dmamap_load(tag, map, buf, NETMAP_BUF_SIZE(na),
 		    netmap_dmamap_cb, NULL, BUS_DMA_NOWAIT);
+	return 0;
 }
 
 static inline void
@@ -1647,14 +1649,17 @@ netmap_reload_map(struct netmap_adapter *na,
 int nm_iommu_group_id(bus_dma_tag_t dev);
 #include 
 
-static inline void
+static inline int
 netmap_load_map(struct netmap_adapter *na,
-	bus_dma_tag_t tag, bus_dmamap_t map, void *buf)
+	bus_dma_tag_t tag, bus_dmamap_t map, void *buf, u_int size)
 {
-	if (0 && map) {
-		*map = dma_map_single(na->pdev, buf, NETMAP_BUF_SIZE(na),
+	if (map) {
+		*map = dma_map_single(na->pdev, buf, size,
 				      DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(na->pdev, *map))
+			return ENOMEM;
 	}
+	return 0;
 }
 
 static inline void
@@ -1757,10 +1762,26 @@ netmap_idx_k2n(struct netmap_kring *kr, int idx)
 
 
 /* Entries of the look-up table. */
+#ifndef linux
 struct lut_entry {
 	void *vaddr;		/* virtual address. */
 	vm_paddr_t paddr;	/* physical address. */
 };
+#else /* linux */
+/* dma-mapping in linux can assign a buffer a different address
+ * depending on the device, so we need to have a separate 
+ * physical-adress look-up table for each na.
+ * We can still share the vaddrs, though, therefore we split
+ * the lut_entry structure.
+ */
+struct lut_entry {
+	void *vaddr;		/* virtual address. */
+};
+
+struct plut_entry {
+	vm_paddr_t paddr;	/* physical address. */
+};
+#endif /* !linux */
 
 struct netmap_obj_pool;
 
@@ -1782,12 +1803,13 @@ PNMB(struct netmap_adapter *na, struct netmap_slot *slot, uint64_t *pp)
 {
 	uint32_t i = slot->buf_idx;
 	struct lut_entry *lut = na->na_lut.lut;
+	struct plut_entry *plut = na->na_lut.plut;
 	void *ret = (i >= na->na_lut.objtotal) ? lut[0].vaddr : lut[i].vaddr;
 
 #ifndef _WIN32
-	*pp = (i >= na->na_lut.objtotal) ? lut[0].paddr : lut[i].paddr;
+	*pp = (i >= na->na_lut.objtotal) ? plut[0].paddr : plut[i].paddr;
 #else
-	*pp = (i >= na->na_lut.objtotal) ? (uint64_t)lut[0].paddr.QuadPart : (uint64_t)lut[i].paddr.QuadPart;
+	*pp = (i >= na->na_lut.objtotal) ? (uint64_t)plut[0].paddr.QuadPart : (uint64_t)plut[i].paddr.QuadPart;
 #endif
 	return ret;
 }
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index cdf33f612..e163a23e6 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -370,7 +370,8 @@ void
 netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	NMA_LOCK(nmd);
-	netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na);
+	if (na->active_fds <= 0)
+		netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na);
 	if (nmd->active == 1) {
 		/*
 		 * Reset the allocator when it falls out of use so that any
@@ -1248,6 +1249,29 @@ nm_alloc_lut(u_int nobj)
 	return lut;
 }
 
+static struct plut_entry *
+nm_alloc_plut(u_int nobj)
+{
+	size_t n = sizeof(struct plut_entry) * nobj;
+	struct plut_entry *lut;
+#ifdef linux
+	lut = vmalloc(n);
+#else
+	lut = nm_os_malloc(n);
+#endif
+	return lut;
+}
+
+static void
+nm_free_plut(struct plut_entry * lut)
+{
+#ifdef linux
+	vfree(lut);
+#else
+	nm_os_free(lut);
+#endif
+}
+
 /* call with NMA_LOCK held */
 static int
 netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
@@ -1317,7 +1341,9 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 		 */
 		for (; i < lim; i++, clust += p->_objsize) {
 			p->lut[i].vaddr = clust;
+#ifndef linux
 			p->lut[i].paddr = vtophys(clust);
+#endif
 		}
 	}
 	p->memtotal = p->numclusters * p->_clustsize;
@@ -1366,6 +1392,7 @@ static int
 netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 {
 	int i, lim = p->_objtotal;
+	struct netmap_lut *lut = &na->na_lut;
 
 	if (na == NULL || na->pdev == NULL)
 		return 0;
@@ -1373,16 +1400,21 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 #if defined(__FreeBSD__)
 	(void)i;
 	(void)lim;
+	(void)lut;
 	D("unsupported on FreeBSD");
-
 #elif defined(_WIN32)
 	(void)i;
 	(void)lim;
+	(void)lut;
 	D("unsupported on Windows");
 #else /* linux */
-	for (i = 2; i < lim; i++) {
-		netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &p->lut[i].paddr);
+	ND("unmapping and freeing plut for %s", na->name);
+	for (i = 2; i < lim; i += p->_clustentries) {
+		if (lut->plut[i].paddr)
+			netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr);
 	}
+	nm_free_plut(lut->plut);
+	lut->plut = NULL;
 #endif /* linux */
 
 	return 0;
@@ -1391,23 +1423,54 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 static int
 netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 {
+	int error = 0;
+	int i, lim = p->_objtotal;
+	struct netmap_lut *lut = &na->na_lut;
+
+	if (na->pdev == NULL)
+		return 0;
+
 #if defined(__FreeBSD__)
+	(void)i;
+	(void)lim;
+	(void)lut;
 	D("unsupported on FreeBSD");
 #elif defined(_WIN32)
+	(void)i;
+	(void)lim;
+	(void)lut;
 	D("unsupported on Windows");
 #else /* linux */
-	int i, lim = p->_objtotal;
 
-	if (na->pdev == NULL)
+	if (lut->plut != NULL) {
+		ND("plut already allocated for %s", na->name);
 		return 0;
+	}
+
+	ND("allocating physical lut for %s", na->name);
+	lut->plut = nm_alloc_plut(lim);
+	if (lut->plut == NULL)
+		return ENOMEM;
 
-	for (i = 2; i < lim; i++) {
-		netmap_load_map(na, (bus_dma_tag_t) na->pdev, &p->lut[i].paddr,
-				p->lut[i].vaddr);
+	for (i = 0; i < lim; i += p->_clustentries) {
+		int j;
+
+		error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr,
+				p->lut[i].vaddr, p->_clustsize);
+		if (error)
+			break;
+
+		for (j = 1; j < p->_clustentries; j++) {
+			lut->plut[i + j].paddr = lut->plut[i + j - 1].paddr + p->_objsize;
+		}
 	}
+
+	if (error)
+		netmap_mem_unmap(p, na);
+
 #endif /* linux */
 
-	return 0;
+	return error;
 }
 
 static int

From 1a99c669dd1b15e2018f93b1d25d87e2c81a93f8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 9 Oct 2017 11:56:36 +0200
Subject: [PATCH 0192/2207] man: import vale(4)

---
 LINUX/netmap.mak.in   |   1 +
 share/man/man4/vale.4 | 131 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+)
 create mode 100644 share/man/man4/vale.4

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index d8f31013a..d853880a4 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -135,6 +135,7 @@ MAN_PREFIX := $(INCLUDE_PREFIX)
 
 install-docs:
 	install -D -m 644 $(SRCDIR)/../share/man/man4/netmap.4 $(DESTDIR)/$(MAN_PREFIX)/share/man/man4/netmap.4
+	install -D -m 644 $(SRCDIR)/../share/man/man4/vale.4 $(DESTDIR)/$(MAN_PREFIX)/share/man/man4/vale.4
 
 distclean: clean $(S_DRIVERS:%=distclean-%)
 	rm -f config.status config.log netmap_linux_config.h \
diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
new file mode 100644
index 000000000..722d8f0aa
--- /dev/null
+++ b/share/man/man4/vale.4
@@ -0,0 +1,131 @@
+.\" Copyright (c) 2012 Luigi Rizzo, Universita` di Pisa
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" This document is derived in part from the enet man page (enet.4)
+.\" distributed with 4.3BSD Unix.
+.\"
+.\" $FreeBSD$
+.\" $Id: $
+.\"
+.Dd July 27, 2012
+.Dt VALE 4
+.Os
+.Sh NAME
+.Nm vale
+.Nd a very fast Virtual Local Ethernet using the netmap API
+.Sh SYNOPSIS
+.Cd device netmap
+.Sh DESCRIPTION
+.Nm
+is a feature of the
+.Xr netmap 4
+module that implements multiple Virtual switches that can
+be used to interconnect netmap clients, including traffic
+sources and sinks, packet forwarders, userspace firewalls,
+and so on.
+.Pp
+.Nm
+is implemented completely in software, and is extremely fast.
+On a modern machine it can move almost 20 Million packets per
+second (Mpps) per core with small frames, and about 70 Gbit/s
+with 1500 byte frames.
+.Sh OPERATION
+.Nm
+dynamically creates switches and ports as clients connect
+to it using the
+.Xr netmap 4
+API.
+.Pp
+.Nm
+ports are named
+.Pa vale[bdg:][port]
+where
+.Pa vale
+is the prefix indicating a VALE switch rather than a standard interface,
+.Pa bdg
+indicates a specific switch (the colon is a separator),
+and
+.Pa port
+indicates a port within the switch.
+Bridge and port names are arbitrary strings, the only
+constraint being that the full name must fit within 16
+characters.
+.Pp
+See
+.Xr netmap 4
+for details on the API.
+.Ss LIMITS
+.Nm
+currently supports up to 4 switches, 16 ports per switch, with
+1024 buffers per port.
+These hard limits will be
+changed to sysctl variables in future releases.
+.Sh SYSCTL VARIABLES
+.Nm
+uses the following sysctl variables to control operation:
+.Bl -tag -width dev.netmap.verbose
+.It dev.netmap.bridge
+The maximum number of packets processed internally
+in each iteration.
+Defaults to 1024, use lower values to trade latency
+with throughput.
+.It dev.netmap.verbose
+Set to non-zero values to enable in-kernel diagnostics.
+.El
+.Sh EXAMPLES
+Create one switch, with a traffic generator connected to one
+port, and a netmap-enabled tcpdump instance on another port:
+.Bd -literal -offset indent
+tcpdump -ni vale-a:1 &
+pkt-gen  -i vale-a:0 -f tx &
+.Ed
+.Pp
+Create two switches,
+each connected to two qemu machines on different ports.
+.Bd -literal -offset indent
+qemu -net nic -net netmap,ifname=vale-1:a ... &
+qemu -net nic -net netmap,ifname=vale-1:b ... &
+qemu -net nic -net netmap,ifname=vale-2:c ... &
+qemu -net nic -net netmap,ifname=vale-2:d ... &
+.Ed
+.Sh SEE ALSO
+.Xr netmap 4
+.Pp
+.Xr http://info.iet.unipi.it/~luigi/vale/
+.Pp
+Luigi Rizzo, Giuseppe Lettieri: VALE, a switched ethernet for virtual machines,
+June 2012, http://info.iet.unipi.it/~luigi/vale/
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+switch was designed and implemented in 2012 by
+.An Luigi Rizzo
+and
+.An Giuseppe Lettieri
+at the Universita` di Pisa.
+.Pp
+.Nm
+was funded by the European Commission within FP7 Projects
+CHANGE (257422) and OPENLAB (287581).

From 2809efd8c3acbc66d6f35b94837d9f3dfdde8244 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 9 Oct 2017 11:57:40 +0200
Subject: [PATCH 0193/2207] man: vale: fix naming of VALE ports ('-' cannot be
 used)

---
 share/man/man4/vale.4 | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
index 722d8f0aa..53deef2bb 100644
--- a/share/man/man4/vale.4
+++ b/share/man/man4/vale.4
@@ -97,17 +97,17 @@ Set to non-zero values to enable in-kernel diagnostics.
 Create one switch, with a traffic generator connected to one
 port, and a netmap-enabled tcpdump instance on another port:
 .Bd -literal -offset indent
-tcpdump -ni vale-a:1 &
-pkt-gen  -i vale-a:0 -f tx &
+tcpdump -ni valea:1 &
+pkt-gen  -i valea:0 -f tx &
 .Ed
 .Pp
 Create two switches,
 each connected to two qemu machines on different ports.
 .Bd -literal -offset indent
-qemu -net nic -net netmap,ifname=vale-1:a ... &
-qemu -net nic -net netmap,ifname=vale-1:b ... &
-qemu -net nic -net netmap,ifname=vale-2:c ... &
-qemu -net nic -net netmap,ifname=vale-2:d ... &
+qemu -net nic -net netmap,ifname=vale1:a ... &
+qemu -net nic -net netmap,ifname=vale1:b ... &
+qemu -net nic -net netmap,ifname=vale2:c ... &
+qemu -net nic -net netmap,ifname=vale2:d ... &
 .Ed
 .Sh SEE ALSO
 .Xr netmap 4

From d9a02966112d2f17c07828d03074d8bfec6cb828 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 10 Oct 2017 12:46:15 +0200
Subject: [PATCH 0194/2207] lib: fix typo causing ringid to always be zero

---
 sys/net/netmap_user.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 825363475..d8cf04d16 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -848,7 +848,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	}
 
 	d->req.nr_version = NETMAP_API;
-	d->req.nr_ringid &= ~NETMAP_RING_MASK;
+	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {

From e56b5cbb5e15af6359c5eeb3be72b368ab18eca1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 10 Oct 2017 13:44:18 +0200
Subject: [PATCH 0195/2207] pkt-gen: fix use of uninitialzed ptr on early
 Ctrl+C

---
 apps/pkt-gen/pkt-gen.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 2883121f3..6418d68c1 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1635,10 +1635,12 @@ sender_body(void *data)
 		}
 	}
 	/* flush any remaining packets */
-	D("flush tail %d head %d on thread %p",
-		txring->tail, txring->head,
-		(void *)pthread_self());
-	ioctl(pfd.fd, NIOCTXSYNC, NULL);
+	if (txring != NULL) {
+		D("flush tail %d head %d on thread %p",
+			txring->tail, txring->head,
+			(void *)pthread_self());
+		ioctl(pfd.fd, NIOCTXSYNC, NULL);
+	}
 
 	/* final part: wait all the TX queues to be empty. */
 	for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {

From 4fc03d309977b6d7350434767c136d1cc6a98667 Mon Sep 17 00:00:00 2001
From: JUNJIE NAN 
Date: Tue, 10 Oct 2017 21:51:02 -0500
Subject: [PATCH 0196/2207] Fixed lut_entry has no paddr member issue

The error: 'struct lut_entry' has no member named 'paddr'
---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index e163a23e6..272aeb714 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2197,7 +2197,7 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 
 	for (i = 0; i < nbuffers; i++) {
 		ptnmd->buf_lut.lut[i].vaddr = vaddr;
-		ptnmd->buf_lut.lut[i].paddr = paddr;
+		ptnmd->buf_lut.plut[i].paddr = paddr;
 		vaddr += bufsize;
 		paddr += bufsize;
 	}

From 377566ba446bf0ac2062dd54588a1b8343e5bd24 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Oct 2017 14:55:03 +0200
Subject: [PATCH 0197/2207] ptnetmap: allocator: don't init plut as it is not
 present

---
 sys/dev/netmap/netmap_mem2.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 272aeb714..c6030c6d6 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2197,7 +2197,6 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 
 	for (i = 0; i < nbuffers; i++) {
 		ptnmd->buf_lut.lut[i].vaddr = vaddr;
-		ptnmd->buf_lut.plut[i].paddr = paddr;
 		vaddr += bufsize;
 		paddr += bufsize;
 	}

From fed4d7c9fac66b7c0c1c4d6a5c79f46a9ff79751 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 21 Sep 2017 15:20:07 +0200
Subject: [PATCH 0198/2207] linux/ixgbe: look at size instead of DD in RX

---
 LINUX/ixgbe_netmap_linux.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 9726b6e3b..bb9e23fd2 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -468,10 +468,12 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 		for (n = 0; ; n++) {
 			union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(rxr, nic_i);
 			uint32_t staterr = le32toh(curr->wb.upper.status_error);
+			u_int size = le16toh(curr->wb.upper.length);
 
-			if ((staterr & IXGBE_RXD_STAT_DD) == 0)
+			if (!size)
 				break;
-			ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
+
+			ring->slot[nm_i].len = size;
 			ring->slot[nm_i].flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG |
 										slot_flags:slot_flags);
 			nm_i = nm_next(nm_i, lim);
@@ -509,6 +511,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
+			curr->wb.upper.length = 0;
 			curr->wb.upper.status_error = 0;
 			curr->read.pkt_addr = htole64(paddr);
 			nm_i = nm_next(nm_i, lim);

From 1597e0cb9e7b541f11d9c9aad2afe620ea339596 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Oct 2017 16:48:04 +0200
Subject: [PATCH 0199/2207] linux/ixgbe: properly initialize RX slots

---
 LINUX/ixgbe_netmap_linux.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index bb9e23fd2..c917b0d44 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -626,11 +626,14 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 		 * (see comment in ixgbe_setup_transmit_ring() ).
 		 */
 		int si = netmap_idx_n2k(&na->rx_rings[ring_nr], i);
+		union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(ring, i);
 		uint64_t paddr;
 		PNMB(na, slot + si, &paddr);
 		// netmap_load_map(rxr->ptag, rxbuf->pmap, addr);
 		/* Update descriptor */
-		NM_IXGBE_RX_DESC(ring, i)->read.pkt_addr = htole64(paddr);
+		curr->read.pkt_addr = htole64(paddr);
+		curr->wb.upper.length = 0;
+		curr->wb.upper.status_error = 0;
 	}
 	ring->next_to_use = lim; /* used for debug only */
 	IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(ring->reg_idx), lim);

From e17c52fed37c6c2380046de1ccf0d562a752576a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 16 Oct 2017 08:43:03 +0200
Subject: [PATCH 0200/2207] LINUX: improve mkdev debug string

---
 LINUX/bsd_glue.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 0663b3da3..bcbb0e4b6 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -418,7 +418,7 @@ typedef unsigned int (d_poll_t)(struct file * file, struct poll_table_struct *pw
  */
 #define make_dev_credf(_flags, _cdev, _zero, _cred, _uid, _gid, _perm, _name)	\
 	({error = misc_register(_cdev);				\
-	D("run mknod /dev/%s c %d %d # error %d",		\
+	D("run mknod /dev/%s c %d %d # returned %d",		\
 	    (_cdev)->name, MISC_MAJOR, (_cdev)->minor, error);	\
 	 _cdev; } )
 #define destroy_dev(_cdev)	misc_deregister(_cdev)

From 2d07ae648a09fe23566581e61b9006265113f02f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 22 Oct 2017 17:20:48 +0200
Subject: [PATCH 0201/2207] bwrap: fix ownership management of netmap rings

On attachment to VALE, the usage counter is incremented for the wrapper
rings. Now the increment is propagated also to wrapped port rings.

On detachment from VALE, the wrapper netmap-rings were always
released. Now the ownership is passed to the wrapped adapter, instead.

The previous behaviour did not cause any problem in the normal cases
(attanching/detaching hardware or persistent-VALE ports), but it is
incorrect for netmap-enabled veths, which must manage the netmap-rings
lifetime by themselves.
---
 sys/dev/netmap/netmap.c      |  3 ++-
 sys/dev/netmap/netmap_mem2.c | 13 ++++++++++---
 sys/dev/netmap/netmap_vale.c | 21 ++++++++++++++++++---
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6c1e4d2a1..09164822c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1894,7 +1894,8 @@ netmap_krings_get(struct netmap_priv_d *priv)
 	int excl = (priv->np_flags & NR_EXCLUSIVE);
 	enum txrx t;
 
-	ND("%s: grabbing tx [%d, %d) rx [%d, %d)",
+	if (netmap_verbose)
+		D("%s: grabbing tx [%d, %d) rx [%d, %d)",
 			na->name,
 			priv->np_qfirst[NR_TX],
 			priv->np_qlast[NR_TX],
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c6030c6d6..787999cdb 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1727,10 +1727,13 @@ netmap_free_rings(struct netmap_adapter *na)
 			struct netmap_ring *ring = kring->ring;
 
 			if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) {
-				ND("skipping ring %s (ring %p, users %d)",
-						kring->name, ring, kring->users);
+				if (netmap_verbose)
+					D("NOT deleting ring %s (ring %p, users %d neekring %d)",
+						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
 				continue;
 			}
+			if (netmap_verbose)
+				D("deleting ring %s", kring->name);
 			if (i != nma_get_nrings(na, t) || na->na_flags & NAF_HOST_RINGS)
 				netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots);
 			netmap_ring_free(na->nm_mem, ring);
@@ -1763,9 +1766,13 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 
 			if (ring || (!kring->users && !(kring->nr_kflags & NKR_NEEDRING))) {
 				/* uneeded, or already created by somebody else */
-				ND("skipping ring %s", kring->name);
+				if (netmap_verbose)
+					D("NOT creating ring %s (ring %p, users %d neekring %d)",
+						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
 				continue;
 			}
+			if (netmap_verbose)
+				D("creating %s", kring->name);
 			ndesc = kring->nkr_num_slots;
 			len = sizeof(struct netmap_ring) +
 				  ndesc * sizeof(struct netmap_slot);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index ac58a7711..31102dd6e 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2508,9 +2508,14 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 
 	/* copy up the current ring state information */
 	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(na, t) + 1; i++)
-			NMR(na, t)[i].nr_mode =
-				NMR(hwna, t)[i].nr_mode;
+		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			struct netmap_kring *kring = &NMR(hwna, t)[i];
+			NMR(na, t)[i].nr_mode = kring->nr_mode;
+			/* also record the fact that we are
+			 * using/no longer using the hwna ring
+			 */
+			kring->users = onoff;
+		}
 	}
 
 	/* impersonate a netmap_vp_adapter */
@@ -2548,6 +2553,14 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		hwna->na_lut.lut = NULL;
 		hwna->na_lut.objtotal = 0;
 		hwna->na_lut.objsize = 0;
+
+		/* pass ownership of the netmap rings to the hwna */
+		for_rx_tx(t) {
+			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+				NMR(na, t)[i].ring = NULL;
+			}
+		}
+
 	}
 
 	return 0;
@@ -2623,6 +2636,8 @@ netmap_bwrap_krings_delete(struct netmap_adapter *na)
 
 	ND("%s", na->name);
 
+	/* delete any netmap rings that are no longer needed */
+	netmap_mem_rings_delete(hwna);
 	hwna->nm_krings_delete(hwna);
 	netmap_vp_krings_delete(na);
 }

From fa328c6f1b588a9913a6adf9e3a59b14e4ff500c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 22 Oct 2017 22:28:15 +0200
Subject: [PATCH 0202/2207] Revert "bwrap: update to new rings-on-demand
 scheme"

This reverts commit 6aaad2635df5dfb17ddcb8681ca96d65482fe8c8.

This commit was causing netmap-rings leakages in the
following scenario:

ip link add veth0 type veth peer name veth1
pkt-gen -i veth1 # rings of veth0 created
vale-ctl -a vale0:veth0 # rings of veth0 overriden by bwrap
---
 sys/dev/netmap/netmap_vale.c | 79 ++++++++++++++++++++++--------------
 1 file changed, 48 insertions(+), 31 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 31102dd6e..786d599fe 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2470,28 +2470,6 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 			hostna->up.na_lut = na->na_lut;
 		}
 
-		/* cross-link the netmap rings
-		 * The original number of rings comes from hwna,
-		 * rx rings on one side equals tx rings on the other.
-		 */
-		for_rx_tx(t) {
-			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-			for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
-				NMR(hwna, r)[i].ring = NMR(na, t)[i].ring;
-			}
-		}
-
-		if (na->na_flags & NAF_HOST_RINGS) {
-			struct netmap_adapter *hna = &hostna->up;
-			/* the hostna rings are the host rings of the bwrap.
-			 * The corresponding krings must point back to the
-			 * hostna
-			 */
-			hna->tx_rings = &na->tx_rings[na->num_tx_rings];
-			hna->tx_rings[0].na = hna;
-			hna->rx_rings = &na->rx_rings[na->num_rx_rings];
-			hna->rx_rings[0].na = hna;
-		}
 	}
 
 	/* pass down the pending ring state information */
@@ -2511,10 +2489,6 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
 			struct netmap_kring *kring = &NMR(hwna, t)[i];
 			NMR(na, t)[i].nr_mode = kring->nr_mode;
-			/* also record the fact that we are
-			 * using/no longer using the hwna ring
-			 */
-			kring->users = onoff;
 		}
 	}
 
@@ -2594,6 +2568,7 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	struct netmap_bwrap_adapter *bna =
 		(struct netmap_bwrap_adapter *)na;
 	struct netmap_adapter *hwna = bna->hwna;
+	struct netmap_adapter *hostna = &bna->host.up;
 	int i, error = 0;
 	enum txrx t;
 
@@ -2610,16 +2585,49 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 		goto err_del_vp_rings;
 	}
 
-	/* get each ring slot number from the corresponding hwna ring */
-	for_rx_tx(t) {
-		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-		for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
-			NMR(na, t)[i].nkr_num_slots = NMR(hwna, r)[i].nkr_num_slots;
+	/* increment the usage counter for all the hwna krings */
+        for_rx_tx(t) {
+                for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
+			NMR(hwna, t)[i].users++;
 		}
+        }
+
+	/* now create the actual rings */
+	error = netmap_mem_rings_create(hwna);
+	if (error) {
+		goto err_dec_users;
+	}
+
+	/* cross-link the netmap rings
+	 * The original number of rings comes from hwna,
+	 * rx rings on one side equals tx rings on the other.
+	 */
+        for_rx_tx(t) {
+                enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
+                for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
+                        NMR(na, t)[i].nkr_num_slots = NMR(hwna, r)[i].nkr_num_slots;
+                        NMR(na, t)[i].ring = NMR(hwna, r)[i].ring;
+                }
+        }
+
+	if (na->na_flags & NAF_HOST_RINGS) {
+		/* the hostna rings are the host rings of the bwrap.
+		 * The corresponding krings must point back to the
+		 * hostna
+		 */
+		hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
+		hostna->tx_rings[0].na = hostna;
+		hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
+		hostna->rx_rings[0].na = hostna;
 	}
 
 	return 0;
 
+err_dec_users:
+        for_rx_tx(t) {
+		NMR(hwna, t)[i].users--;
+        }
+	hwna->nm_krings_delete(hwna);
 err_del_vp_rings:
 	netmap_vp_krings_delete(na);
 
@@ -2633,9 +2641,18 @@ netmap_bwrap_krings_delete(struct netmap_adapter *na)
 	struct netmap_bwrap_adapter *bna =
 		(struct netmap_bwrap_adapter *)na;
 	struct netmap_adapter *hwna = bna->hwna;
+	enum txrx t;
+	int i;
 
 	ND("%s", na->name);
 
+	/* decrement the usage counter for all the hwna krings */
+        for_rx_tx(t) {
+                for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
+			NMR(hwna, t)[i].users--;
+		}
+        }
+
 	/* delete any netmap rings that are no longer needed */
 	netmap_mem_rings_delete(hwna);
 	hwna->nm_krings_delete(hwna);

From 479eb82282c296ee41a0f9f9924090176d9cdf11 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 25 Oct 2017 18:57:48 +0200
Subject: [PATCH 0203/2207] linux: veth_netmap_reg: hold rcu read lock only
 when necessary

In particular this avoids that we hold the lock while calling
netmap_mem_rings_create() and netmap_mem_rings_delete().
This was a problem as those functions need to take the sleeping
lock of the allocator (and we cannot sleep inside the RCU).
---
 LINUX/veth_netmap.h | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 5185c06a8..10e10bbf0 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -53,8 +53,10 @@ veth_get_peer_na(struct netmap_adapter *na)
 		(struct netmap_veth_adapter *)na;
 
 	if (vna->peer == NULL) {
+		rcu_read_lock();
 		peer_ifp = rcu_dereference(priv->peer);
 		if (!peer_ifp) {
+			rcu_read_unlock();
 			return NULL;
 		}
 		/* cache the na pointer so that we can retrieve it
@@ -66,6 +68,7 @@ veth_get_peer_na(struct netmap_adapter *na)
 		vna->peer_ref = 1;
 		/* also set the cross reference from the peer_na to us */
 		vna->peer->peer = vna;
+		rcu_read_unlock();
 	}
 
 	return &vna->peer->up.up;
@@ -129,11 +132,8 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 	int error;
 	int i;
 
-	rcu_read_lock();
-
 	peer_na = veth_get_peer_na(na);
 	if (!peer_na) {
-		rcu_read_unlock();
 		return EINVAL;
 	}
 
@@ -159,7 +159,6 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		/* create all missing needed rings on the other end */
 		error = netmap_mem_rings_create(peer_na);
 		if (error) {
-			rcu_read_unlock();
 			return error;
 		}
 
@@ -205,8 +204,6 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		}
 	}
 
-	rcu_read_unlock();
-
 	if (na->active_fds == 0 && was_up) {
 		veth_open(ifp);
 	}

From fb3e735cac687eb411ead31c964a93c94a0ce5e0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 30 Oct 2017 12:44:03 +0100
Subject: [PATCH 0204/2207] linux/ixgbe: Intel 5.3.3 driver

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/intel--ixgbe--5.3.3 | 171 ++++++++++++++++++++++++
 2 files changed, 172 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.3.3

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 2e9dad3e7..ccbabd798 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -11,7 +11,7 @@ endef
 
 enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2))))
 
-$(call enabled_intel_driver,ixgbe,5.2.3)
+$(call enabled_intel_driver,ixgbe,5.3.3)
 $(call enabled_intel_driver,ixgbevf,4.2.1)
 e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.6)
diff --git a/LINUX/final-patches/intel--ixgbe--5.3.3 b/LINUX/final-patches/intel--ixgbe--5.3.3
new file mode 100644
index 000000000..91029e0ee
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.3.3
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index a3cc895..a038975 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 70ba606..b738703 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -733,6 +733,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -751,6 +768,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2032,6 +2060,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3319,6 +3357,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3966,6 +4008,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11481,6 +11527,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11526,6 +11576,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 09b6b97bfab14ecb10d1b2d4d98d5eb68a9a5160 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 30 Oct 2017 12:52:18 +0100
Subject: [PATCH 0205/2207] linux/ixgbevf: Intel 4.3.2 version

---
 LINUX/default-config.mak.in_              |   2 +-
 LINUX/final-patches/intel--ixgbevf--4.3.2 | 177 ++++++++++++++++++++++
 2 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.3.2

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index ccbabd798..e9e249503 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -12,7 +12,7 @@ endef
 enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2))))
 
 $(call enabled_intel_driver,ixgbe,5.3.3)
-$(call enabled_intel_driver,ixgbevf,4.2.1)
+$(call enabled_intel_driver,ixgbevf,4.3.2)
 e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.6)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
diff --git a/LINUX/final-patches/intel--ixgbevf--4.3.2 b/LINUX/final-patches/intel--ixgbevf--4.3.2
new file mode 100644
index 000000000..3cacb03e4
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.3.2
@@ -0,0 +1,177 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index ca79ef6..939f185 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 7c5bf52..c153522 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1192,6 +1220,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1825,6 +1863,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1835,7 +1877,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+- 
++
+ /**
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+@@ -2012,6 +2054,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4969,8 +5015,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5008,6 +5056,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 	if (!netdev)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	adapter = netdev_priv(netdev);
+ 
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index a36ee42..7f09616 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From a205ab1191b7664849e965817dc311d7282fb785 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Fri, 18 Aug 2017 14:38:44 +0200
Subject: [PATCH 0206/2207] Respect dkms $kernelver

Fix kernel upgrades when the module is built for kernel different from the one running
---
 LINUX/configure | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 5659d6f5f..0565d73cc 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -620,10 +620,14 @@ exec 2>> config.log
 # check for sane configuration
 ################################
 
+[ -n "$kernelver" ] || {
+	kernelver="$(uname -r)"
+}
+
 [ -n "$ksrc" ] || {
 	# user did not provide a kernel dir,
 	# we try to find one by ourselves
-	ksrc="/lib/modules/$(uname -r)/build"
+	ksrc="/lib/modules/${kernelver}/build"
 }
 
 [ -n "$src" ] || {

From 4b19b6646f9ba287df1163564a015a3f6d369ef2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 31 Oct 2017 19:26:25 +0100
Subject: [PATCH 0207/2207] LINUX: generic_xmit_frame: reset m->next if not
 NULL

We do not allow that mbufs in the pool are chained, as we use
them independently.
---
 LINUX/netmap_linux.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 45738e170..5d5efbd66 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -772,6 +772,11 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	skb_set_queue_mapping(m, a->ring_nr);
 	m->priority = a->qevent ? NM_MAGIC_PRIORITY_TXQE : NM_MAGIC_PRIORITY_TX;
 
+	if (unlikely(m->next)) {
+		RD(1, "Warning: resetting skb->next as it is not NULL\n");
+		m->next = NULL;
+	}
+
 	ret = dev_queue_xmit(m);
 
 	if (unlikely(ret != NET_XMIT_SUCCESS)) {

From d8e66289352712accb3c3a213bd232b9748e84be Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 1 Nov 2017 10:30:25 +0100
Subject: [PATCH 0208/2207] LINUX: ptnet: improve logs by printing function
 prefix

---
 LINUX/netmap_ptnet.c | 69 ++++++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 35 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index e57526440..fe7a74259 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -127,7 +127,8 @@ hang_tmr_callback(unsigned long arg)
 	struct netmap_kring *kring = na->rx_rings + prq->q.kring_id;
 	struct netmap_ring *ring = kring->ring;
 
-	pr_info("HANG RX#%d: hwc %u h %u c %u hwt %u t %u rx.guest_need_kick %u\n",
+	pr_info("PTNET HANG RX#%d: hwc %u h %u c %u hwt %u t %u"
+		" rx.guest_need_kick %u\n",
 		kring->ring_id, kring->nr_hwcur, ring->head, ring->cur,
 		kring->nr_hwtail, ring->tail, prq->q.ptring->guest_need_kick);
 
@@ -370,8 +371,8 @@ ptnet_get_stats(struct net_device *netdev)
 static int
 ptnet_change_mtu(struct net_device *netdev, int new_mtu)
 {
-	pr_info("%s changing MTU from %d to %d\n",
-		netdev->name, netdev->mtu, new_mtu);
+	pr_info("%s: %s changing MTU from %d to %d\n",
+		__func__, netdev->name, netdev->mtu, new_mtu);
 	netdev->mtu = new_mtu;
 
 	return 0;
@@ -539,7 +540,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 #endif
 		if (unlikely(!skb)) {
 			pr_err("%s: skb allocation failed\n",
-			       __func__);
+				__func__);
 			break;
 		}
 
@@ -578,7 +579,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 					skbpage = ptnet_alloc_page(prq);
 					if (unlikely(!skbpage)) {
 						pr_err("%s: pntet_alloc_page() failed\n",
-						       __func__);
+							__func__);
 						break;
 					}
 					skbdata = page_address(skbpage);
@@ -775,7 +776,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 	pi->msix_entries = kzalloc(sizeof(*pi->msix_entries) * pi->num_rings,
 				   GFP_KERNEL);
 	if (!pi->msix_entries) {
-		pr_err("Failed to allocate msix entires\n");
+		pr_err("%s: Failed to allocate msix entires\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -792,7 +793,8 @@ ptnet_irqs_init(struct ptnet_info *pi)
 				    PCI_IRQ_MSIX);
 #endif
 	if (ret != pi->num_rings) {
-		pr_err("Failed to enable msix vectors (%d)\n", ret);
+		pr_err("%s: Failed to enable msix vectors (%d)\n",
+			__func__, ret);
 		goto err_alloc;
 	}
 
@@ -801,7 +803,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 
 		memset(&pq->msix_affinity_mask, 0, sizeof(pq->msix_affinity_mask));
 		if (!alloc_cpumask_var(&pq->msix_affinity_mask, GFP_KERNEL)) {
-			pr_err("Failed to alloc cpumask var\n");
+			pr_err("%s: Failed to alloc cpumask var\n", __func__);
 			goto err_masks;
 		}
 	}
@@ -816,11 +818,12 @@ ptnet_irqs_init(struct ptnet_info *pi)
 			 "%s-%d", pi->netdev->name, i);
 		ret = request_irq(vector, handler, 0, pq->msix_name, pq);
 		if (ret) {
-			pr_err("Unable to allocate interrupt (%d)\n", ret);
+			pr_err("%s: Unable to allocate interrupt (%d)\n",
+				__func__, ret);
 			goto err_irqs;
 		}
-		pr_info("IRQ for ring #%d --> %u, handler %p\n", i,
-                        vector, handler);
+		pr_info("%s: IRQ for ring #%d --> %u, handler %p\n",
+                        __func__, i, vector, handler);
 	}
 
 	return 0;
@@ -878,32 +881,32 @@ ptnet_open(struct net_device *netdev)
 	int ret;
 	int i;
 
-	D("%s: netif_running %u", __func__, netif_running(netdev));
-
 	netmap_update_config(na_dr);
 
 	ret = netmap_mem_finalize(na_dr->nm_mem, na_dr);
 	if (ret) {
-		pr_err("netmap_mem_finalize() failed\n");
+		pr_err("%s: netmap_mem_finalize() failed\n", __func__);
 		goto err_mem_finalize;
 	}
 
 	if (pi->ptna->backend_regifs == 0) {
 		ret = ptnet_nm_krings_create(na_nm);
 		if (ret) {
-			pr_err("ptnet_nm_krings_create() failed\n");
+			pr_err("%s: ptnet_nm_krings_create() failed\n",
+				__func__);
 			goto err_mem_finalize;
 		}
 
 		ret = netmap_mem_rings_create(na_dr);
 		if (ret) {
-			pr_err("netmap_mem_rings_create() failed\n");
+			pr_err("%s: netmap_mem_rings_create() failed\n",
+				__func__);
 			goto err_rings_create;
 		}
 
 		ret = netmap_mem_get_lut(na_dr->nm_mem, &na_dr->na_lut);
 		if (ret) {
-			pr_err("netmap_mem_get_lut() failed\n");
+			pr_err("%s: netmap_mem_get_lut() failed\n", __func__);
 			goto err_get_lut;
 		}
 	}
@@ -923,8 +926,6 @@ ptnet_open(struct net_device *netdev)
 
 	netif_tx_start_all_queues(netdev);
 
-	pr_info("%s: %p\n", __func__, pi);
-
 	for (i = 0; i < na_dr->num_rx_rings; i++){
 		struct ptnet_rx_queue *prq = (struct ptnet_rx_queue *)
 					pi->rxqueues[i];
@@ -944,7 +945,8 @@ ptnet_open(struct net_device *netdev)
 		 * the interface was down. Schedule NAPI to flush packets that
 		 * are pending in the RX ring. We won't receive further
 		 * interrupts until the pending ones will be processed. */
-		D("Schedule NAPI to flush RX ring #%d", i);
+		pr_info("%s: Schedule NAPI to flush RX ring #%d\n",
+			__func__, i);
 		ptnet_napi_schedule(&prq->q);
 	}
 
@@ -975,8 +977,6 @@ ptnet_close(struct net_device *netdev)
 	struct netmap_adapter *na_nm = &pi->ptna->hwup.up;
 	int i;
 
-	D("%s: netif_running %u", __func__, netif_running(netdev));
-
 	netif_tx_stop_all_queues(netdev);
 
 	for (i = 0; i < na_dr->num_rx_rings; i++){
@@ -1009,8 +1009,6 @@ ptnet_close(struct net_device *netdev)
 	}
 	netmap_mem_deref(na_dr->nm_mem, na_dr);
 
-	pr_info("%s: %p\n", __func__, pi);
-
 	return 0;
 }
 
@@ -1105,13 +1103,15 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	 * in the RX rings, since we will not receive further interrupts
 	 * until these will be processed. */
 	if (native && !onoff && na->active_fds == 0) {
-		D("Exit netmap mode, re-enable interrupts");
+		pr_info("%s: Exit netmap mode, re-enable interrupts\n",
+			__func__);
 		for (i = 0; i < pi->num_rings; i++) {
 			ptring = pi->queues[i]->ptring;
 			ptring->guest_need_kick = 1;
 		}
 		if (netif_running(netdev)) {
-			D("Exit netmap mode, schedule NAPI to flush RX ring");
+			pr_info("%s: Exit netmap mode, schedule NAPI to flush RX ring\n",
+				__func__);
 			for (i = 0; i < na->num_rx_rings; i++){
 				ptnet_napi_schedule(pi->rxqueues[i]);
 			}
@@ -1205,7 +1205,7 @@ ptnet_nm_config(struct netmap_adapter *na, unsigned *txr, unsigned *txd,
 	*txd = ioread32(pi->ioaddr + PTNET_IO_NUM_TX_SLOTS);
 	*rxd = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_SLOTS);
 
-	pr_info("txr %u, rxr %u, txd %u, rxd %u\n",
+	pr_info("%s: txr %u, rxr %u, txd %u, rxd %u\n", __func__,
 		*txr, *rxr, *txd, *rxd);
 
 	return 0;
@@ -1310,8 +1310,8 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	}
 
 	err = -EIO;
-	pr_info("IO BAR (registers): start 0x%llx, len %llu, flags 0x%lx\n",
-		pci_resource_start(pdev, PTNETMAP_IO_PCI_BAR),
+	pr_info("%s: IO BAR (registers): start 0x%llx, len %llu, flags 0x%lx\n",
+		__func__, pci_resource_start(pdev, PTNETMAP_IO_PCI_BAR),
 		pci_resource_len(pdev, PTNETMAP_IO_PCI_BAR),
 		pci_resource_flags(pdev, PTNETMAP_IO_PCI_BAR));
 
@@ -1378,8 +1378,8 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* Map the CSB memory exposed by the device. We don't use
 	 * pci_ioremap_bar(), since we want the ioremap_cache() function
 	 * to be called internally, rather than ioremap_nocache(). */
-	pr_info("MEMORY BAR (CSB): start 0x%llx, len %llu, flags 0x%lx\n",
-		pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
+	pr_info("%s: MEMORY BAR (CSB): start 0x%llx, len %llu, flags 0x%lx\n",
+		__func__, pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
 		pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR),
 		pci_resource_flags(pdev, PTNETMAP_MEM_PCI_BAR));
 	pi->csbaddr = ioremap_cache(pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
@@ -1507,11 +1507,11 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	netif_carrier_on(netdev);
 
-	pr_info("%s: %p\n", __func__, pi);
+	pr_info("%s: device %s registered \n", __func__, netdev->name);
 
 	return 0;
 
-	pr_info("%s: failed\n", __func__);
+	pr_info("%s: failed to probe device\n", __func__);
 err_netreg:
 	ptnet_irqs_fini(pi);
 err_irqs:
@@ -1554,6 +1554,7 @@ ptnet_remove(struct pci_dev *pdev)
 	 * two netmap adapters (ptna, ptna->dr) must happen
          * afterwards. */
 	unregister_netdev(netdev);
+	pr_info("%s: device %s unregistered\n", __func__, netdev->name);
 
 	/* Uninitialize netmap adapters for this device. */
 	netmap_detach(netdev);
@@ -1577,8 +1578,6 @@ ptnet_remove(struct pci_dev *pdev)
 	pci_release_selected_regions(pdev, pi->bars);
 	free_netdev(netdev);
 	pci_disable_device(pdev);
-
-	pr_info("%s: %p\n", __func__, pi);
 }
 
 #if 0

From c9cf92ddf3c701c845b7a2a8ff8a88ae42aeed0a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 1 Nov 2017 23:10:25 +0100
Subject: [PATCH 0209/2207] linux: check for NULL ifp in emulated netmap setup

---
 LINUX/netmap_linux.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 5d5efbd66..e3c392360 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -415,6 +415,11 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
     struct netmap_adapter *na = &gna->up.up;
     struct ifnet *ifp = netmap_generic_getifp(gna);
 
+    if (!ifp) {
+        D("Failed to get ifp");
+        return -EBUSY;
+    }
+
     if (intercept) {
         return -netdev_rx_handler_register(ifp,
                 &linux_generic_rx_handler, na);
@@ -584,7 +589,7 @@ nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 				GFP_KERNEL);
 		if (!nla) {
 			D("Failed to allocate netlink attribute");
-			return ENOMEM;
+			return -1;
 		}
 		nla->nla_type = RTM_NEWQDISC;
 		nla->nla_len = nla_attr_size(sizeof(*qdiscopt));
@@ -679,6 +684,11 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 	struct ifnet *ifp = netmap_generic_getifp(gna);
 	int err;
 
+	if (!ifp) {
+		D("Failed to get ifp");
+		return -1;
+	}
+
 	err = nm_os_catch_qdisc(gna, intercept);
 	if (err) {
 		return err;

From e4bb02b68c4d0cbd716e17075558e3cfe292ff44 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 2 Nov 2017 12:35:45 +0100
Subject: [PATCH 0210/2207] linux: kthread: don't bind to CPU if affinity is
 not set

This bug was causing all ptnetmap threads to run on the same
CPU (CPU 0).
---
 LINUX/netmap_linux.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e3c392360..c0b064268 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1590,6 +1590,7 @@ nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
 	nmk->use_kthread = cfg->use_kthread;
 	atomic_set(&nmk->scheduled, 0);
 	nmk->attach_user = cfg->attach_user;
+	nmk->affinity = -1;  /* unspecified */
 
 	/* open event fds */
 	error = nm_kctx_open_files(nmk, opaque);
@@ -1630,7 +1631,9 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 			goto err;
 		}
 
-		kthread_bind(nmk->worker, nmk->affinity);
+		if (nmk->affinity >= 0) {
+			kthread_bind(nmk->worker, nmk->affinity);
+		}
 		wake_up_process(nmk->worker);
 	}
 

From 6f46cffdead332d7747752286cd0ebbae308a4e6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 2 Nov 2017 15:17:51 +0100
Subject: [PATCH 0211/2207] attach: check that NA(ifp) is not busy before
 calling NM_ATTACH_NA(ifp)

This fixes a bug that shows up when PF_RING is used together with
netmap.
---
 sys/dev/netmap/netmap.c         | 10 ++++++++++
 sys/dev/netmap/netmap_generic.c |  9 +++++++++
 2 files changed, 19 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 09164822c..10f3fdf2e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2932,7 +2932,17 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 
 	if (arg == NULL || arg->ifp == NULL)
 		goto fail;
+
 	ifp = arg->ifp;
+	if (NA(ifp) && !NM_NA_VALID(ifp)) {
+		/* If NA(ifp) is not null but there is no valid netmap
+		 * adapter it means that someone else is using the same
+		 * pointer (e.g. ax25_ptr on linux). This happens for
+		 * instance when also PF_RING is in use. */
+		D("Error: netmap adapter hook is busy");
+		return EBUSY;
+	}
+
 	hwna = nm_os_malloc(size);
 	if (hwna == NULL)
 		goto fail;
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 778e09697..bc1b84a8b 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1206,6 +1206,15 @@ generic_netmap_attach(struct ifnet *ifp)
 	}
 #endif
 
+	if (NA(ifp) && !NM_NA_VALID(ifp)) {
+		/* If NA(ifp) is not null but there is no valid netmap
+		 * adapter it means that someone else is using the same
+		 * pointer (e.g. ax25_ptr on linux). This happens for
+		 * instance when also PF_RING is in use. */
+		D("Error: netmap adapter hook is busy");
+		return EBUSY;
+	}
+
 	num_tx_desc = num_rx_desc = netmap_generic_ringsize; /* starting point */
 
 	nm_os_generic_find_num_desc(ifp, &num_tx_desc, &num_rx_desc); /* ignore errors */

From 6caa5593cf89373a2f264de18164de361410156b Mon Sep 17 00:00:00 2001
From: Carl Smith 
Date: Fri, 3 Nov 2017 09:54:25 +1300
Subject: [PATCH 0212/2207] mem: fix non-const casting of nr_buf_size

One some platforms this previously resulted in
nr_buf_size being initialised to random values
as only 16-bits of the 32 bit value was set.
The symtoms were that buffer offsets were
incorrectly calculated and invalid memory
accesses occurred.
---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 787999cdb..f8de03ac2 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1793,7 +1793,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 			ring->head = kring->rhead;
 			ring->cur = kring->rcur;
 			ring->tail = kring->rtail;
-			*(uint16_t *)(uintptr_t)&ring->nr_buf_size =
+			*(uint32_t *)(uintptr_t)&ring->nr_buf_size =
 				netmap_mem_bufsize(na->nm_mem);
 			ND("%s h %d c %d t %d", kring->name,
 				ring->head, ring->cur, ring->tail);

From d3ed0e338b56009c226c0113c4e6827409c61829 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 2 Nov 2017 16:50:36 +0100
Subject: [PATCH 0213/2207] linux/i40e: Intel 2.3.6 version

---
 LINUX/default-config.mak.in_           |   2 +-
 LINUX/final-patches/intel--i40e--2.3.6 | 154 +++++++++++++++++++++++++
 LINUX/i40e_netmap_linux.h              |   2 +-
 3 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.3.6

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index e9e249503..df26b6521 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -17,4 +17,4 @@ e1000e@cflags := -fno-pie
 $(call enabled_intel_driver,e1000e,3.3.6)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 $(call enabled_intel_driver,igb,5.3.5.12)
-$(call enabled_intel_driver,i40e,2.1.26)
+$(call enabled_intel_driver,i40e,2.3.6)
diff --git a/LINUX/final-patches/intel--i40e--2.3.6 b/LINUX/final-patches/intel--i40e--2.3.6
new file mode 100644
index 000000000..b7eea198d
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.3.6
@@ -0,0 +1,154 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index ff50970..8d7f7fb 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -30,9 +30,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -46,13 +46,13 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 7fea797..f8122fb 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3239,6 +3244,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3320,6 +3329,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -10843,6 +10857,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -11211,6 +11230,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 6ec8bf6..01938de 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -26,6 +26,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -788,6 +792,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2254,6 +2263,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ 	bool failure = false;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index f20799a48..73969df69 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -517,7 +517,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
 
-			union i40e_32byte_rx_desc *curr = I40E_RX_DESC(rxr, nic_i);
+			union i40e_rx_desc *curr = I40E_RX_DESC(rxr, nic_i);
 
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
 				goto ring_reset;

From acbb0a7fc77146abde34d69679e7e2d9e2213261 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 2 Nov 2017 17:48:34 +0100
Subject: [PATCH 0214/2207] ixgbe/ixgbevf: call a driver-specific netmap detach
 function

The netmap detach function is a stub for now. It will
be used later to tear-down the ixgbe dma-mapped area
for head write-back.
---
 LINUX/final-patches/intel--ixgbe--4.4.6       |   4 +-
 LINUX/final-patches/intel--ixgbe--4.5.4       |   4 +-
 LINUX/final-patches/intel--ixgbe--5.0.4       |   4 +-
 LINUX/final-patches/intel--ixgbe--5.1.3       |   4 +-
 LINUX/final-patches/intel--ixgbe--5.2.1       |   4 +-
 LINUX/final-patches/intel--ixgbe--5.2.3       |   8 +-
 LINUX/final-patches/intel--ixgbe--5.2.4       |   4 +-
 LINUX/final-patches/intel--ixgbe--5.3.3       |   4 +-
 LINUX/final-patches/intel--ixgbevf--3.2.2     |  14 +--
 LINUX/final-patches/intel--ixgbevf--3.3.2     |  14 +--
 LINUX/final-patches/intel--ixgbevf--4.0.3     |  14 +--
 LINUX/final-patches/intel--ixgbevf--4.1.2     |  14 +--
 LINUX/final-patches/intel--ixgbevf--4.2.1     |  14 +--
 LINUX/final-patches/intel--ixgbevf--4.2.2     |  32 ++---
 LINUX/final-patches/intel--ixgbevf--4.3.2     |  14 +--
 .../vanilla--ixgbe--20620--20622              |   4 +-
 .../vanilla--ixgbe--20622--20623              |   4 +-
 .../vanilla--ixgbe--20623--20625              |   4 +-
 .../vanilla--ixgbe--20625--20626              |   4 +-
 .../vanilla--ixgbe--20626--30100              |   4 +-
 .../vanilla--ixgbe--30100--30200              |   4 +-
 .../vanilla--ixgbe--30200--30400              |   4 +-
 .../vanilla--ixgbe--30400--30500              |   4 +-
 .../vanilla--ixgbe--30500--30700              |   4 +-
 .../vanilla--ixgbe--30700--30a00              |   4 +-
 .../vanilla--ixgbe--30a00--30d00              |   6 +-
 .../vanilla--ixgbe--30d00--30f00              |   6 +-
 .../vanilla--ixgbe--30f00--31300              |   6 +-
 .../vanilla--ixgbe--31300--40900              |   6 +-
 .../vanilla--ixgbe--40900--99999              |   6 +-
 ...--30500 => vanilla--ixgbevf--20622--30500} |  22 ++--
 .../vanilla--ixgbevf--30500--30600            |   4 +-
 .../vanilla--ixgbevf--30600--30700            |   4 +-
 .../vanilla--ixgbevf--30700--30d00            |   4 +-
 .../vanilla--ixgbevf--30d00--30e00            |   4 +-
 .../vanilla--ixgbevf--30e00--30f00            |   4 +-
 .../vanilla--ixgbevf--30f00--31200            |   4 +-
 .../vanilla--ixgbevf--31200--31300            |   4 +-
 .../vanilla--ixgbevf--31300--40000            |   4 +-
 ...--40900 => vanilla--ixgbevf--40000--40700} |   4 +-
 .../vanilla--ixgbevf--40700--40800            | 109 ++++++++++++++++++
 .../vanilla--ixgbevf--40800--40900            | 109 ++++++++++++++++++
 .../vanilla--ixgbevf--40900--99999            |  14 +--
 LINUX/ixgbe_netmap_linux.h                    |   6 +
 44 files changed, 371 insertions(+), 147 deletions(-)
 rename LINUX/final-patches/{vanilla--ixgbevf--30200--30500 => vanilla--ixgbevf--20622--30500} (84%)
 rename LINUX/final-patches/{vanilla--ixgbevf--40000--40900 => vanilla--ixgbevf--40000--40700} (98%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--40700--40800
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--40800--40900

diff --git a/LINUX/final-patches/intel--ixgbe--4.4.6 b/LINUX/final-patches/intel--ixgbe--4.4.6
index 80558942f..477113f29 100644
--- a/LINUX/final-patches/intel--ixgbe--4.4.6
+++ b/LINUX/final-patches/intel--ixgbe--4.4.6
@@ -62,7 +62,7 @@ index c49cba8..546435f 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 202f595..66242ee 100644
+index 202f595..ec4f8d8 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -709,6 +709,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -172,7 +172,7 @@ index 202f595..66242ee 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--4.5.4 b/LINUX/final-patches/intel--ixgbe--4.5.4
index 22d02824e..135a3d8d1 100644
--- a/LINUX/final-patches/intel--ixgbe--4.5.4
+++ b/LINUX/final-patches/intel--ixgbe--4.5.4
@@ -62,7 +62,7 @@ index c49cba8..546435f 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 06017ea..0c84b61 100644
+index 06017ea..4974b37 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -747,6 +747,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index 06017ea..0c84b61 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.0.4 b/LINUX/final-patches/intel--ixgbe--5.0.4
index 9ada8f051..84495c50e 100644
--- a/LINUX/final-patches/intel--ixgbe--5.0.4
+++ b/LINUX/final-patches/intel--ixgbe--5.0.4
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 83c6250..c87f03d 100644
+index 83c6250..5da5967 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -752,6 +752,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index 83c6250..c87f03d 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.1.3 b/LINUX/final-patches/intel--ixgbe--5.1.3
index 960818f79..f35ff7c76 100644
--- a/LINUX/final-patches/intel--ixgbe--5.1.3
+++ b/LINUX/final-patches/intel--ixgbe--5.1.3
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fe4291e..fb53dfc 100644
+index fe4291e..0b8f0e4 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index fe4291e..fb53dfc 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.2.1 b/LINUX/final-patches/intel--ixgbe--5.2.1
index 7d0e814d3..8bcdd059e 100644
--- a/LINUX/final-patches/intel--ixgbe--5.2.1
+++ b/LINUX/final-patches/intel--ixgbe--5.2.1
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 0f65c2e..b5d52bb 100644
+index 0f65c2e..26a5de6 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index 0f65c2e..b5d52bb 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.2.3 b/LINUX/final-patches/intel--ixgbe--5.2.3
index 5540a0320..b78cedd0d 100644
--- a/LINUX/final-patches/intel--ixgbe--5.2.3
+++ b/LINUX/final-patches/intel--ixgbe--5.2.3
@@ -1,4 +1,4 @@
-diff --git a/ixgbe/Makefile b/src/Makefile
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
 index a3cc895..a038975 100644
 --- a/ixgbe/Makefile
 +++ b/ixgbe/Makefile
@@ -61,8 +61,8 @@ index a3cc895..a038975 100644
  # Clean the module subdirectories
  clean:
  	@+$(call devkernelbuild,clean)
-diff --git a/ixgbe/ixgbe_main.c b/src/ixgbe_main.c
-index 68bead6..ef93357 100644
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 68bead6..dc29ca1 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index 68bead6..ef93357 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.2.4 b/LINUX/final-patches/intel--ixgbe--5.2.4
index 6195267a1..cab246e69 100644
--- a/LINUX/final-patches/intel--ixgbe--5.2.4
+++ b/LINUX/final-patches/intel--ixgbe--5.2.4
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index c7a1499..f2a3c3e 100644
+index c7a1499..eaf8c4a 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -753,6 +753,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index c7a1499..f2a3c3e 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.3.3 b/LINUX/final-patches/intel--ixgbe--5.3.3
index 91029e0ee..01d214f5a 100644
--- a/LINUX/final-patches/intel--ixgbe--5.3.3
+++ b/LINUX/final-patches/intel--ixgbe--5.3.3
@@ -62,7 +62,7 @@ index a3cc895..a038975 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 70ba606..b738703 100644
+index 70ba606..a33879e 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -733,6 +733,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -163,7 +163,7 @@ index 70ba606..b738703 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbevf--3.2.2 b/LINUX/final-patches/intel--ixgbevf--3.2.2
index e293506d2..70dfd2540 100644
--- a/LINUX/final-patches/intel--ixgbevf--3.2.2
+++ b/LINUX/final-patches/intel--ixgbevf--3.2.2
@@ -46,7 +46,7 @@ index b50a61d..e8aa31c 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index bf6cc35..dee644c 100644
+index bf6cc35..934c2ae 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -303,6 +303,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -143,17 +143,17 @@ index bf6cc35..dee644c 100644
  	cards_found++;
  	return 0;
  
-@@ -4807,6 +4856,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4809,6 +4858,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
 diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index 683975b..2647519 100644
 --- a/ixgbevf/kcompat.h
diff --git a/LINUX/final-patches/intel--ixgbevf--3.3.2 b/LINUX/final-patches/intel--ixgbevf--3.3.2
index 68fbd4524..388e13822 100644
--- a/LINUX/final-patches/intel--ixgbevf--3.3.2
+++ b/LINUX/final-patches/intel--ixgbevf--3.3.2
@@ -46,7 +46,7 @@ index d85c225..da05d8b 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 2435281..c2cbc6f 100644
+index 2435281..f50475d 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -152,17 +152,17 @@ index 2435281..c2cbc6f 100644
  	cards_found++;
  	return 0;
  
-@@ -4923,6 +4972,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4925,6 +4974,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
 diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index 976dc04..30b8868 100644
 --- a/ixgbevf/kcompat.h
diff --git a/LINUX/final-patches/intel--ixgbevf--4.0.3 b/LINUX/final-patches/intel--ixgbevf--4.0.3
index 401d3b1a5..bbad1a6bd 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.0.3
+++ b/LINUX/final-patches/intel--ixgbevf--4.0.3
@@ -46,7 +46,7 @@ index d85c225..da05d8b 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 88f87cc..166ae8f 100644
+index 88f87cc..945d7bd 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -152,17 +152,17 @@ index 88f87cc..166ae8f 100644
  	cards_found++;
  	return 0;
  
-@@ -4928,6 +4977,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4930,6 +4979,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
 diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index a39ec3c..b9437ca 100644
 --- a/ixgbevf/kcompat.h
diff --git a/LINUX/final-patches/intel--ixgbevf--4.1.2 b/LINUX/final-patches/intel--ixgbevf--4.1.2
index 018719dde..23972e405 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.1.2
+++ b/LINUX/final-patches/intel--ixgbevf--4.1.2
@@ -46,7 +46,7 @@ index ca79ef6..939f185 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 789187b..19207f8 100644
+index 789187b..8169ad7 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -152,17 +152,17 @@ index 789187b..19207f8 100644
  	cards_found++;
  	return 0;
  
-@@ -4963,6 +5012,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4965,6 +5014,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
 diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index c08d849..d7a58a5 100644
 --- a/ixgbevf/kcompat.h
diff --git a/LINUX/final-patches/intel--ixgbevf--4.2.1 b/LINUX/final-patches/intel--ixgbevf--4.2.1
index 914a1068d..d56b2ac8c 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.2.1
+++ b/LINUX/final-patches/intel--ixgbevf--4.2.1
@@ -46,7 +46,7 @@ index ca79ef6..939f185 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 7bb8159..3bba8b6 100644
+index 7bb8159..220faa6 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -152,17 +152,17 @@ index 7bb8159..3bba8b6 100644
  	cards_found++;
  	return 0;
  
-@@ -4959,6 +5008,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4961,6 +5010,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVE, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
 diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index b53b133..30f592b 100644
 --- a/ixgbevf/kcompat.h
diff --git a/LINUX/final-patches/intel--ixgbevf--4.2.2 b/LINUX/final-patches/intel--ixgbevf--4.2.2
index c59915e20..c5e2fceef 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.2.2
+++ b/LINUX/final-patches/intel--ixgbevf--4.2.2
@@ -1,7 +1,7 @@
-diff --git a/src/Makefile b/src/Makefile
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
 index ca79ef6..939f185 100644
---- a/src/Makefile
-+++ b/src/Makefile
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
 @@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
  # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
  #
@@ -45,10 +45,10 @@ index ca79ef6..939f185 100644
  # Clean the module subdirectories
  clean:
  	@+$(call kernelbuild,clean)
-diff --git a/src/ixgbevf_main.c b/src/ixgbevf_main.c
-index c1f7021..d4dd337 100644
---- a/src/ixgbevf_main.c
-+++ b/src/ixgbevf_main.c
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index c1f7021..f2ecac4 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
  	ixgbevf_tx_timeout_reset(adapter);
  }
@@ -152,21 +152,21 @@ index c1f7021..d4dd337 100644
  	cards_found++;
  	return 0;
  
-@@ -4959,6 +5008,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4961,6 +5010,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVE, &adapter->state);
-diff --git a/src/kcompat.h b/src/kcompat.h
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index 6b93e54..34d4440 100644
---- a/src/kcompat.h
-+++ b/src/kcompat.h
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
 @@ -25,6 +25,8 @@
  #ifndef _KCOMPAT_H_
  #define _KCOMPAT_H_
diff --git a/LINUX/final-patches/intel--ixgbevf--4.3.2 b/LINUX/final-patches/intel--ixgbevf--4.3.2
index 3cacb03e4..1eb36cea6 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.3.2
+++ b/LINUX/final-patches/intel--ixgbevf--4.3.2
@@ -46,7 +46,7 @@ index ca79ef6..939f185 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 7c5bf52..c153522 100644
+index 7c5bf52..045005e 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -151,17 +151,17 @@ index 7c5bf52..c153522 100644
  	return 0;
  
  err_register:
-@@ -5008,6 +5056,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -5010,6 +5058,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
 diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
 index a36ee42..7f09616 100644
 --- a/ixgbevf/kcompat.h
diff --git a/LINUX/final-patches/vanilla--ixgbe--20620--20622 b/LINUX/final-patches/vanilla--ixgbe--20620--20622
index 2dde2dca8..ee0c0bd8a 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20620--20622
+++ b/LINUX/final-patches/vanilla--ixgbe--20620--20622
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index a456578b8578..a14c3e048f07 100644
+index a456578..12c3857 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -337,6 +337,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
@@ -113,7 +113,7 @@ index a456578b8578..a14c3e048f07 100644
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--20622--20623 b/LINUX/final-patches/vanilla--ixgbe--20622--20623
index 4c4bed7b9..91a2af59b 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20622--20623
+++ b/LINUX/final-patches/vanilla--ixgbe--20622--20623
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 6c00ee493a3b..f14b8b8259a4 100644
+index 6c00ee4..36f9ef2 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -400,6 +400,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
@@ -117,7 +117,7 @@ index 6c00ee493a3b..f14b8b8259a4 100644
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--20623--20625 b/LINUX/final-patches/vanilla--ixgbe--20623--20625
index 5cfb5869d..a9aed3202 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20623--20625
+++ b/LINUX/final-patches/vanilla--ixgbe--20623--20625
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 74d9b6df3029..db08827fb443 100644
+index 74d9b6d..803bc4b 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -108,7 +108,7 @@ index 74d9b6df3029..db08827fb443 100644
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--20625--20626 b/LINUX/final-patches/vanilla--ixgbe--20625--20626
index 3aaf231af..32abae28e 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20625--20626
+++ b/LINUX/final-patches/vanilla--ixgbe--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index eee0b298bd36..cbaf5999579d 100644
+index eee0b29..b7722c9 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -99,7 +99,7 @@ index eee0b298bd36..cbaf5999579d 100644
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--20626--30100 b/LINUX/final-patches/vanilla--ixgbe--20626--30100
index 4713f5aed..c95807eec 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20626--30100
+++ b/LINUX/final-patches/vanilla--ixgbe--20626--30100
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 30f9ccfb4f87..12a830cb307f 100644
+index 30f9ccf..4f5a19e 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -221,6 +221,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -99,7 +99,7 @@ index 30f9ccfb4f87..12a830cb307f 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30100--30200 b/LINUX/final-patches/vanilla--ixgbe--30100--30200
index 70bab4192..e53050a31 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30100--30200
+++ b/LINUX/final-patches/vanilla--ixgbe--30100--30200
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e1fcc9589278..2d2dfb932f9d 100644
+index e1fcc95..8753411 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -249,6 +249,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -100,7 +100,7 @@ index e1fcc9589278..2d2dfb932f9d 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30200--30400 b/LINUX/final-patches/vanilla--ixgbe--30200--30400
index 8475092dc..e76337ec8 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30200--30400
+++ b/LINUX/final-patches/vanilla--ixgbe--30200--30400
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 8ef92d1a6aa1..342f0d33d259 100644
+index 8ef92d1..6574699 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -188,6 +188,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -98,7 +98,7 @@ index 8ef92d1a6aa1..342f0d33d259 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30400--30500 b/LINUX/final-patches/vanilla--ixgbe--30400--30500
index 389f5b069..383d8cf47 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30400--30500
+++ b/LINUX/final-patches/vanilla--ixgbe--30400--30500
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 467948e9ecd9..6ab3fb525641 100644
+index 467948e9..568104f 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -107,7 +107,7 @@ index 467948e9ecd9..6ab3fb525641 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30500--30700 b/LINUX/final-patches/vanilla--ixgbe--30500--30700
index bd3168fd3..60497e568 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30500--30700
+++ b/LINUX/final-patches/vanilla--ixgbe--30500--30700
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e242104ab471..eab0e8928662 100644
+index e242104..6320fd1 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -106,7 +106,7 @@ index e242104ab471..eab0e8928662 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30700--30a00 b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
index 9365f5a72..752c6d4b9 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30700--30a00
+++ b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fa3d552e1f4a..8de2ce7e652d 100644
+index fa3d552..f0f4735 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -205,6 +205,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -106,7 +106,7 @@ index fa3d552e1f4a..8de2ce7e652d 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef CONFIG_DEBUG_FS
diff --git a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
index 858adec65..092be9a70 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
+++ b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d30fbdd81fca..0b4f66839b1e 100644
+index d30fbdd..a6bcb88 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -248,6 +248,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -90,7 +90,7 @@ index d30fbdd81fca..0b4f66839b1e 100644
  	return 0;
  
  err_set_queues:
-@@ -7658,6 +7704,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -7658,6 +7704,10 @@ skip_sriov:
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -106,7 +106,7 @@ index d30fbdd81fca..0b4f66839b1e 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	ixgbe_dbg_adapter_exit(adapter);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
index 5f9bd64b2..3f462f13e 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 5bcc870f8367..1d71e2a9d4d5 100644
+index 5bcc870..eef4667 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -107,7 +107,7 @@ index 5bcc870f8367..1d71e2a9d4d5 100644
  	return 0;
  
  err_set_queues:
-@@ -8174,6 +8210,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8174,6 +8210,10 @@ skip_sriov:
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -123,7 +123,7 @@ index 5bcc870f8367..1d71e2a9d4d5 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	ixgbe_dbg_adapter_exit(adapter);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30f00--31300 b/LINUX/final-patches/vanilla--ixgbe--30f00--31300
index 1487e7fb8..e2e3e7f6e 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30f00--31300
+++ b/LINUX/final-patches/vanilla--ixgbe--30f00--31300
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d62e7a25cf97..b413a71d799c 100644
+index d62e7a2..1c0b31a 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -417,6 +417,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -100,7 +100,7 @@ index d62e7a25cf97..b413a71d799c 100644
  	return 0;
  
  err_set_queues:
-@@ -8310,6 +8359,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8310,6 +8359,10 @@ skip_sriov:
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -116,7 +116,7 @@ index d62e7a25cf97..b413a71d799c 100644
  	struct net_device *netdev = adapter->netdev;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	ixgbe_dbg_adapter_exit(adapter);
diff --git a/LINUX/final-patches/vanilla--ixgbe--31300--40900 b/LINUX/final-patches/vanilla--ixgbe--31300--40900
index fb675aec2..e6a8e222e 100644
--- a/LINUX/final-patches/vanilla--ixgbe--31300--40900
+++ b/LINUX/final-patches/vanilla--ixgbe--31300--40900
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 67b02bde179e..ddc67ff5a63e 100644
+index 67b02bd..ba3e46d 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -100,7 +100,7 @@ index 67b02bde179e..ddc67ff5a63e 100644
  	return 0;
  
  err_set_queues:
-@@ -8521,6 +8570,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8521,6 +8570,10 @@ skip_sriov:
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -117,7 +117,7 @@ index 67b02bde179e..ddc67ff5a63e 100644
  	netdev  = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	ixgbe_dbg_adapter_exit(adapter);
diff --git a/LINUX/final-patches/vanilla--ixgbe--40900--99999 b/LINUX/final-patches/vanilla--ixgbe--40900--99999
index f7c9cd011..6067c43e1 100644
--- a/LINUX/final-patches/vanilla--ixgbe--40900--99999
+++ b/LINUX/final-patches/vanilla--ixgbe--40900--99999
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fee1f2918ead..dcf36a33f3c7 100644
+index fee1f2918..7b86ce4 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -497,6 +497,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -101,7 +101,7 @@ index fee1f2918ead..dcf36a33f3c7 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -9799,6 +9847,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9799,6 +9847,10 @@ skip_sriov:
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -118,7 +118,7 @@ index fee1f2918ead..dcf36a33f3c7 100644
  	netdev  = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	ixgbe_dbg_adapter_exit(adapter);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30200--30500 b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
similarity index 84%
rename from LINUX/final-patches/vanilla--ixgbevf--30200--30500
rename to LINUX/final-patches/vanilla--ixgbevf--20622--30500
index 15822950e..705ca371e 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30200--30500
+++ b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
@@ -1,8 +1,8 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 4c8e19951d57..7a6d084c0aff 100644
+index 0cd6202..57e93f4 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
-@@ -180,6 +180,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
+@@ -209,6 +209,24 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter,
  
  static void ixgbevf_tx_timeout(struct net_device *netdev);
  
@@ -27,7 +27,7 @@ index 4c8e19951d57..7a6d084c0aff 100644
  /**
   * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
   * @adapter: board private structure
-@@ -195,6 +213,20 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
+@@ -224,6 +242,20 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
  	unsigned int i, eop, count = 0;
  	unsigned int total_bytes = 0, total_packets = 0;
  
@@ -48,7 +48,7 @@ index 4c8e19951d57..7a6d084c0aff 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->tx_buffer_info[i].next_to_watch;
  	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-@@ -465,6 +497,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+@@ -507,6 +539,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
  	int cleaned_count = 0;
  	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
  
@@ -65,7 +65,7 @@ index 4c8e19951d57..7a6d084c0aff 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1261,6 +1303,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter,
+@@ -1289,6 +1331,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter,
  }
  
  /**
@@ -74,7 +74,7 @@ index 4c8e19951d57..7a6d084c0aff 100644
   * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
   * @adapter: board private structure
   *
-@@ -1291,6 +1335,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+@@ -1319,6 +1363,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
  		 */
  		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
  		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
@@ -84,7 +84,7 @@ index 4c8e19951d57..7a6d084c0aff 100644
  		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
  	}
  }
-@@ -1524,6 +1571,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
+@@ -1582,6 +1629,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
  	ixgbevf_configure_rx(adapter);
  	for (i = 0; i < adapter->num_rx_queues; i++) {
  		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
@@ -94,8 +94,8 @@ index 4c8e19951d57..7a6d084c0aff 100644
  		ixgbevf_alloc_rx_buffers(adapter, ring, ring->count);
  		ring->next_to_use = ring->count - 1;
  		writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail);
-@@ -3460,6 +3510,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
- 	hw_dbg(hw, "LRO is disabled\n");
+@@ -3485,6 +3535,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+ 	hw_dbg(hw, "LRO is disabled \n");
  
  	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
 +
@@ -106,13 +106,13 @@ index 4c8e19951d57..7a6d084c0aff 100644
  	cards_found++;
  	return 0;
  
-@@ -3491,6 +3546,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+@@ -3516,6 +3571,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
  	struct net_device *netdev = pci_get_drvdata(pdev);
  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
  
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
index 4773cfd6d..e8b4ea1f9 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30500--30600
+++ b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 41e32257a4e8..487ea8562d7e 100644
+index 41e3225..5a9610e 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -186,6 +186,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
@@ -109,7 +109,7 @@ index 41e32257a4e8..487ea8562d7e 100644
  
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
index b44318194..5458d64d8 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30600--30700
+++ b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 60ef64587412..6594f9ec0a4a 100644
+index 60ef645..b0c3eb1 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -110,7 +110,7 @@ index 60ef64587412..6594f9ec0a4a 100644
  
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
index f44136526..da9db16b3 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index de1ad506665d..b0079d74c050 100644
+index de1ad50..154571d 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -110,7 +110,7 @@ index de1ad506665d..b0079d74c050 100644
  
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
index aea9f7489..341ae4859 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 92ef4cb5a8e8..f9818b2403c4 100644
+index 92ef4cb..3c5d85c 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -110,7 +110,7 @@ index 92ef4cb5a8e8..f9818b2403c4 100644
  
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
index 772eaf8c9..1c5314c2a 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 9df28985eba7..f29d0f651271 100644
+index 9df2898..05d9620 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -175,6 +175,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -103,7 +103,7 @@ index 9df28985eba7..f29d0f651271 100644
  
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
index da01a1f14..cda03e2be 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
+++ b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index d0799e8e31e4..e8037a4c0441 100644
+index d0799e8..3105f9c 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -102,7 +102,7 @@ index d0799e8e31e4..e8037a4c0441 100644
  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
index 8c0fc3a2e..76369471f 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--31200--31300
+++ b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 030a219c85e3..b1cefd751648 100644
+index 030a219..07adcf8 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -102,7 +102,7 @@ index 030a219c85e3..b1cefd751648 100644
  	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	set_bit(__IXGBEVF_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
index 7d96790a2..abd865e5b 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--31300--40000
+++ b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 38c7a0be8197..a53300522c16 100644
+index 38c7a0b..ce0c373 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -208,6 +208,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
@@ -101,7 +101,7 @@ index 38c7a0be8197..a53300522c16 100644
  		return;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	adapter = netdev_priv(netdev);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40000--40900 b/LINUX/final-patches/vanilla--ixgbevf--40000--40700
similarity index 98%
rename from LINUX/final-patches/vanilla--ixgbevf--40000--40900
rename to LINUX/final-patches/vanilla--ixgbevf--40000--40700
index b3e4ae7e2..93b9a8ab3 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40000--40900
+++ b/LINUX/final-patches/vanilla--ixgbevf--40000--40700
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 4186981e562d..5bdcba71c944 100644
+index 4186981..f37d7cc 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -283,6 +283,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -101,7 +101,7 @@ index 4186981e562d..5bdcba71c944 100644
  		return;
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	adapter = netdev_priv(netdev);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40700--40800 b/LINUX/final-patches/vanilla--ixgbevf--40700--40800
new file mode 100644
index 000000000..7a5378a78
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--40700--40800
@@ -0,0 +1,109 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index acc2401..3d0b47e 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -292,6 +292,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -311,6 +329,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -927,6 +957,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1602,6 +1642,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1789,6 +1833,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4131,6 +4179,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4170,6 +4222,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40800--40900 b/LINUX/final-patches/vanilla--ixgbevf--40800--40900
new file mode 100644
index 000000000..39cd13e9e
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--40800--40900
@@ -0,0 +1,109 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index d9d6616..501804f 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -313,6 +331,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -929,6 +959,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1604,6 +1644,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1791,6 +1835,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4143,6 +4191,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4180,6 +4232,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 	if (!netdev)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	adapter = netdev_priv(netdev);
+ 
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--99999 b/LINUX/final-patches/vanilla--ixgbevf--40900--99999
index 384a5f546..0c9776c1f 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40900--99999
+++ b/LINUX/final-patches/vanilla--ixgbevf--40900--99999
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index cbf70fe4028a..1a006e1c8a5d 100644
+index cbf70fe..724ea09 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -105,14 +105,14 @@ index cbf70fe4028a..1a006e1c8a5d 100644
  	return 0;
  
  err_register:
-@@ -4189,6 +4241,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
+@@ -4191,6 +4243,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
  
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
- 	adapter = netdev_priv(netdev);
- 
  	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index c917b0d44..fe4fec074 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -668,4 +668,10 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	netmap_attach(&na);
 }
 
+static void
+ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter)
+{
+	netmap_detach(adapter->netdev);
+}
+
 /* end of file */

From 5dd12aa3fcf8b0ea18b1702bf80a0ab46fe3038c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 3 Nov 2017 23:12:31 +0100
Subject: [PATCH 0215/2207] ixgbe: prevent free of non-allocated memory

---
 LINUX/ixgbe_netmap_linux.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index fe4fec074..050bc72df 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -528,6 +528,13 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 		IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(rxr->reg_idx), nic_i);
 	}
 
+	/* some versions of the ixgbe driver will blindly try to deallocate
+	 * stuff from next_to_clean to next_to_alloc on ifdown, but we skipped
+	 * the corresponding allocations when we put the card in netmap mode.
+	 * We prevent this by always having next_to_alloc==next_to_clean
+	 */
+	rxr->next_to_alloc = rxr->next_to_clean;
+
 
 	return 0;
 

From ecd42de824a2f908d285bee6219be50604871e5f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 3 Nov 2017 23:18:50 +0100
Subject: [PATCH 0216/2207] ixgbe: support IOMMU

---
 LINUX/ixgbe_netmap_linux.h | 76 +++++++++++++++++++++++++++++++++++---
 1 file changed, 70 insertions(+), 6 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 050bc72df..eb143ab5f 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -111,6 +111,17 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 }
 #endif /* NETMAP_LINUX_IXGBE_HAVE_DISABLE */
 
+struct netmap_ixgbe_head {
+	dma_addr_t map;
+	u32* phead;
+};
+
+struct netmap_ixgbe_adapter {
+	struct netmap_hw_adapter up;
+	struct dma_pool *pool;
+	struct netmap_ixgbe_head heads[];
+};
+
 /*
  * In netmap mode, overwrite the srrctl register with netmap_buf_size
  * to properly configure the Receive Buffer Size
@@ -244,6 +255,9 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	struct netmap_adapter *na = kring->na;
 	struct ifnet *ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
+#ifndef NM_IXGBE_USE_TDH
+	struct netmap_ixgbe_adapter *ina = (struct netmap_ixgbe_adapter *)na;
+#endif /* !NM_IXGBE_USE_TDH */
 	u_int ring_nr = kring->ring_id;
 	u_int nm_i;	/* index into the netmap ring */
 	u_int nic_i;	/* index into the NIC ring */
@@ -348,7 +362,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	(void)reclaim_tx;
 	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
-		u32 h = *(volatile u32*)&txr->next_to_use;
+		u32 h = *ina->heads[ring_nr].phead;
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
 #else /* NM_IXGBE_USE_TDH */
@@ -555,10 +569,9 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	struct netmap_slot *slot;
 #ifndef NM_IXGBE_USE_TDH
 	struct ixgbe_hw *hw = &adapter->hw;
-	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
+	struct netmap_ixgbe_adapter *ina = (struct netmap_ixgbe_adapter *)na;
 	u64 wba;
 #endif /* !NM_IXGBE_USE_TDH */
-	//int j;
 
         slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
@@ -568,8 +581,7 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	/* we reset WTRESH (it must be 0 according to specs) */
 	txdctl &= ~(0x7f << 16);
 
-	/* we reuse the next_to_use+next_to_clean fields to receive the hw head */
-	wba = (u64)virt_to_phys(&txr->next_to_use);
+	wba = (u64)ina->heads[ring_nr].map;
 	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAL(ring_nr),
 		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);
 	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAH(ring_nr), wba >> 32);
@@ -648,6 +660,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 }
 
 
+static void ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter);
 /*
  * The attach routine, called near the end of ixgbe_attach(),
  * fills the parameters for netmap_attach() and calls it.
@@ -659,6 +672,18 @@ static void
 ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 {
 	struct netmap_adapter na;
+	struct netmap_ixgbe_adapter *ina;
+	struct dma_pool *pool;
+	int i;
+
+	// allocate head-writeback region
+	pool = dma_pool_create("head-wb",
+			&adapter->pdev->dev, sizeof(u32),
+			L1_CACHE_BYTES, 0);
+	if (pool == NULL) {
+		pr_err("netmap: failed to allocated head-wb pool");
+		return;
+	}
 
 	bzero(&na, sizeof(na));
 
@@ -672,12 +697,51 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
 	na.nm_intr = ixgbe_netmap_intr;
-	netmap_attach(&na);
+	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter) +
+				sizeof(struct netmap_ixgbe_head) * adapter->num_tx_queues, 1)) {
+		pr_err("netmap: failed to attach netmap adapter");
+		dma_pool_destroy(pool);
+		return;
+	}
+	ina = (struct netmap_ixgbe_adapter *)NA(adapter->netdev);
+	ina->pool = pool;
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct netmap_ixgbe_head *h = &ina->heads[i];
+		h->phead = dma_pool_alloc(pool, GFP_KERNEL, &h->map);
+		if (h->phead == NULL) {
+			pr_err("netmap: failed to allocated head %d", i);
+			ixgbe_netmap_detach(adapter);
+			return;
+		}
+	}
+
+	return;
 }
 
 static void
 ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter)
 {
+	struct netmap_adapter *na;
+	struct netmap_ixgbe_adapter *ina;
+	int i;
+
+	if (!NM_NA_VALID(adapter->netdev))
+		return;
+
+	na = NA(adapter->netdev);
+
+	ina = (struct netmap_ixgbe_adapter *)na;
+	if (ina->pool != NULL) {
+		for (i = 0; i < na->num_tx_rings; i++) {
+			struct netmap_ixgbe_head *h = &ina->heads[i];
+			if (h->phead == NULL)
+				break;
+			dma_pool_free(ina->pool, h->phead, h->map);
+			h->phead = NULL;
+		}
+		dma_pool_destroy(ina->pool);
+		ina->pool = NULL;
+	}
 	netmap_detach(adapter->netdev);
 }
 

From 726230c8ed3d258fd8d24a99610d2dde7a8375ac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 3 Nov 2017 23:44:17 +0100
Subject: [PATCH 0217/2207] ixgbe: compile-out head-wb when using TDH

---
 LINUX/ixgbe_netmap_linux.h | 41 +++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index eb143ab5f..7d30a55f8 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -111,17 +111,6 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 }
 #endif /* NETMAP_LINUX_IXGBE_HAVE_DISABLE */
 
-struct netmap_ixgbe_head {
-	dma_addr_t map;
-	u32* phead;
-};
-
-struct netmap_ixgbe_adapter {
-	struct netmap_hw_adapter up;
-	struct dma_pool *pool;
-	struct netmap_ixgbe_head heads[];
-};
-
 /*
  * In netmap mode, overwrite the srrctl register with netmap_buf_size
  * to properly configure the Receive Buffer Size
@@ -202,6 +191,22 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 #endif /* NM_IXGBE */
 /**********************************************************************/
 
+struct netmap_ixgbe_head {
+#ifndef NM_IXGBE_USE_TDH
+	dma_addr_t map;
+	u32* phead;
+#endif /*! NM_IXGBE_USE_TDH */
+};
+
+struct netmap_ixgbe_adapter {
+	struct netmap_hw_adapter up;
+#ifndef NM_IXGBE_USE_TDH
+	struct dma_pool *pool;
+	struct netmap_ixgbe_head heads[];
+#endif /*! NM_IXGBE_USE_TDH */
+};
+
+
 /*
  * Register/unregister. We are already under netmap lock.
  * Only called on the first register or the last unregister.
@@ -362,7 +367,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	(void)reclaim_tx;
 	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
-		u32 h = *ina->heads[ring_nr].phead;
+		u32 h = ACCESS_ONCE(*ina->heads[ring_nr].phead);
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
 #else /* NM_IXGBE_USE_TDH */
@@ -672,6 +677,7 @@ static void
 ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 {
 	struct netmap_adapter na;
+#ifndef NM_IXGBE_USE_TDH
 	struct netmap_ixgbe_adapter *ina;
 	struct dma_pool *pool;
 	int i;
@@ -684,6 +690,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 		pr_err("netmap: failed to allocated head-wb pool");
 		return;
 	}
+#endif /*! NM_IXGBE_USE_TDH */
 
 	bzero(&na, sizeof(na));
 
@@ -700,9 +707,12 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter) +
 				sizeof(struct netmap_ixgbe_head) * adapter->num_tx_queues, 1)) {
 		pr_err("netmap: failed to attach netmap adapter");
+#ifndef NM_IXGBE_USE_TDH
 		dma_pool_destroy(pool);
+#endif /*! NM_IXGBE_USE_TDH */
 		return;
 	}
+#ifndef NM_IXGBE_USE_TDH
 	ina = (struct netmap_ixgbe_adapter *)NA(adapter->netdev);
 	ina->pool = pool;
 	for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -714,22 +724,24 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 			return;
 		}
 	}
-
-	return;
+#endif /*! NM_IXGBE_USE_TDH */
 }
 
 static void
 ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter)
 {
 	struct netmap_adapter *na;
+#ifndef NM_IXGBE_USE_TDH
 	struct netmap_ixgbe_adapter *ina;
 	int i;
+#endif /*! NM_IXGBE_USE_TDH */
 
 	if (!NM_NA_VALID(adapter->netdev))
 		return;
 
 	na = NA(adapter->netdev);
 
+#ifndef NM_IXGBE_USE_TDH
 	ina = (struct netmap_ixgbe_adapter *)na;
 	if (ina->pool != NULL) {
 		for (i = 0; i < na->num_tx_rings; i++) {
@@ -742,6 +754,7 @@ ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter)
 		dma_pool_destroy(ina->pool);
 		ina->pool = NULL;
 	}
+#endif /*! NM_IXGBE_USE_TDH */
 	netmap_detach(adapter->netdev);
 }
 

From dde791036f7b98771ea8a114822592ce9243f906 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 4 Nov 2017 10:59:49 +0100
Subject: [PATCH 0218/2207] pkt-gen: let rxseq look at all opened rings

The purpose of this patch is to simplify testing using txseq/rxseq.

Before this patch, rxseq only looked at the first RX ring.  The packets
from txseq, however, may be received on another ring and be completely
missed by rxseq.

Moreover, if the other rings were also opened in netmap mode (as it is
the case with a command like 'pkt-gen -i netmap:eth0 -frxseq'), the
actual destination ring was never emptied. If Flow Control was enabled,
this in turn caused TX-hangs in the sender.
---
 apps/pkt-gen/pkt-gen.c | 188 ++++++++++++++++++++++-------------------
 1 file changed, 99 insertions(+), 89 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 6418d68c1..28e0ef07d 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2036,18 +2036,25 @@ rxseq_body(void *data)
 	int dump = targ->g->options & OPT_DUMP;
 	struct netmap_ring *ring;
 	unsigned int frags_exp = 1;
-	uint32_t seq_exp = 0;
 	struct my_ctrs cur;
 	unsigned int frags = 0;
 	int first_packet = 1;
 	int first_slot = 1;
-	int i, af;
+	int i, j, af, nrings;
+	uint32_t seq, *seq_exp = NULL;
 
 	memset(&cur, 0, sizeof(cur));
 
 	if (setaffinity(targ->thread, targ->affinity))
 		goto quit;
 
+	nrings = targ->nmd->last_rx_ring - targ->nmd->first_rx_ring + 1;
+	seq_exp = calloc(nrings, sizeof(uint32_t));
+	if (seq_exp == NULL) {
+		D("failed to allocate seq array");
+		goto quit;
+	}
+
 	D("reading from %s fd %d main_fd %d",
 		targ->g->ifname, targ->fd, targ->g->main_fd);
 	/* unbounded wait for the first packet. */
@@ -2061,11 +2068,9 @@ rxseq_body(void *data)
 
 	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
 
-	ring = NETMAP_RXRING(targ->nmd->nifp, targ->nmd->first_rx_ring);
 
 	while (!targ->cancel) {
 		unsigned int head;
-		uint32_t seq;
 		int limit;
 
 		/* Once we started to receive packets, wait at most 1 seconds
@@ -2081,107 +2086,110 @@ rxseq_body(void *data)
 			goto quit;
 		}
 
-		if (nm_ring_empty(ring))
-			continue;
+		for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) {
+			ring = NETMAP_RXRING(targ->nmd->nifp, j);
+			if (nm_ring_empty(ring))
+				continue;
 
-		limit = nm_ring_space(ring);
-		if (limit > targ->g->burst)
-			limit = targ->g->burst;
+			limit = nm_ring_space(ring);
+			if (limit > targ->g->burst)
+				limit = targ->g->burst;
 
 #if 0
-		/* Enable this if
-		 *     1) we remove the early-return optimization from
-		 *        the netmap poll implementation, or
-		 *     2) pipes get NS_MOREFRAG support.
-		 * With the current netmap implementation, an experiment like
-		 *    pkt-gen -i vale:1{1 -f txseq -F 9
-		 *    pkt-gen -i vale:1}1 -f rxseq
-		 * would get stuck as soon as we find nm_ring_space(ring) < 9,
-		 * since here limit is rounded to 0 and
-		 * pipe rxsync is not called anymore by the poll() of this loop.
-		 */
-		if (frags_exp > 1) {
-			int o = limit;
-			/* Cut off to the closest smaller multiple. */
-			limit = (limit / frags_exp) * frags_exp;
-			RD(2, "LIMIT %d --> %d", o, limit);
-		}
+			/* Enable this if
+			 *     1) we remove the early-return optimization from
+			 *        the netmap poll implementation, or
+			 *     2) pipes get NS_MOREFRAG support.
+			 * With the current netmap implementation, an experiment like
+			 *    pkt-gen -i vale:1{1 -f txseq -F 9
+			 *    pkt-gen -i vale:1}1 -f rxseq
+			 * would get stuck as soon as we find nm_ring_space(ring) < 9,
+			 * since here limit is rounded to 0 and
+			 * pipe rxsync is not called anymore by the poll() of this loop.
+			 */
+			if (frags_exp > 1) {
+				int o = limit;
+				/* Cut off to the closest smaller multiple. */
+				limit = (limit / frags_exp) * frags_exp;
+				RD(2, "LIMIT %d --> %d", o, limit);
+			}
 #endif
 
-		for (head = ring->head, i = 0; i < limit; i++) {
-			struct netmap_slot *slot = &ring->slot[head];
-			char *p = NETMAP_BUF(ring, slot->buf_idx);
-			int len = slot->len;
-			struct pkt *pkt;
+			for (head = ring->head, i = 0; i < limit; i++) {
+				struct netmap_slot *slot = &ring->slot[head];
+				char *p = NETMAP_BUF(ring, slot->buf_idx);
+				int len = slot->len;
+				struct pkt *pkt;
 
-			if (dump) {
-				dump_payload(p, slot->len, ring, head);
-			}
+				if (dump) {
+					dump_payload(p, slot->len, ring, head);
+				}
 
-			frags++;
-			if (!(slot->flags & NS_MOREFRAG)) {
-				if (first_packet) {
+				frags++;
+				if (!(slot->flags & NS_MOREFRAG)) {
+					if (first_packet) {
+						first_packet = 0;
+					} else if (frags != frags_exp) {
+						char prbuf[512];
+						RD(1, "Received packets with %u frags, "
+								"expected %u, '%s'", frags, frags_exp,
+								multi_slot_to_string(ring, head-frags+1,
+							       	frags,
+									prbuf, sizeof(prbuf)));
+					}
 					first_packet = 0;
-				} else if (frags != frags_exp) {
-					char prbuf[512];
-					RD(1, "Received packets with %u frags, "
-					      "expected %u, '%s'", frags, frags_exp,
-					      multi_slot_to_string(ring, head-frags+1, frags,
-								   prbuf, sizeof(prbuf)));
+					frags_exp = frags;
+					frags = 0;
 				}
-				first_packet = 0;
-				frags_exp = frags;
-				frags = 0;
-			}
 
-			p -= sizeof(pkt->vh) - targ->g->virt_header;
-			len += sizeof(pkt->vh) - targ->g->virt_header;
-			pkt = (struct pkt *)p;
-			if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP)
-				af = AF_INET;
-			else
-				af = AF_INET6;
-
-			if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) +
-			    sizeof(seq)) {
-				RD(1, "%s: packet too small (len=%u)", __func__,
-				      slot->len);
-			} else {
-				seq = (PKT(pkt, body, af)[0] << 24) |
-				    (PKT(pkt, body, af)[1] << 16) |
-				    (PKT(pkt, body, af)[2] << 8) |
-				    PKT(pkt, body, af)[3];
-				if (first_slot) {
-					/* Grab the first one, whatever it
-					   is. */
-					seq_exp = seq;
-					first_slot = 0;
-				} else if (seq != seq_exp) {
-					uint32_t delta = seq - seq_exp;
-
-					if (delta < (0xFFFFFFFF >> 1)) {
-						RD(2, "Sequence GAP: exp %u found %u",
-						      seq_exp, seq);
-					} else {
-						RD(2, "Sequence OUT OF ORDER: "
-						      "exp %u found %u", seq_exp, seq);
+				p -= sizeof(pkt->vh) - targ->g->virt_header;
+				len += sizeof(pkt->vh) - targ->g->virt_header;
+				pkt = (struct pkt *)p;
+				if (ntohs(pkt->eh.ether_type) == ETHERTYPE_IP)
+					af = AF_INET;
+				else
+					af = AF_INET6;
+
+				if ((char *)pkt + len < ((char *)PKT(pkt, body, af)) +
+						sizeof(seq)) {
+					RD(1, "%s: packet too small (len=%u)", __func__,
+							slot->len);
+				} else {
+					seq = (PKT(pkt, body, af)[0] << 24) |
+						(PKT(pkt, body, af)[1] << 16) |
+						(PKT(pkt, body, af)[2] << 8) |
+						PKT(pkt, body, af)[3];
+					if (first_slot) {
+						/* Grab the first one, whatever it
+						   is. */
+						seq_exp[j] = seq;
+						first_slot = 0;
+					} else if (seq != seq_exp[j]) {
+						uint32_t delta = seq - seq_exp[j];
+
+						if (delta < (0xFFFFFFFF >> 1)) {
+							RD(2, "Sequence GAP: exp %u found %u",
+									seq_exp[j], seq);
+						} else {
+							RD(2, "Sequence OUT OF ORDER: "
+									"exp %u found %u", seq_exp[j], seq);
+						}
+						seq_exp[j] = seq;
 					}
-					seq_exp = seq;
+					seq_exp[j]++;
 				}
-				seq_exp++;
-			}
 
-			cur.bytes += slot->len;
-			head = nm_ring_next(ring, head);
-			cur.pkts++;
-		}
+				cur.bytes += slot->len;
+				head = nm_ring_next(ring, head);
+				cur.pkts++;
+			}
 
-		ring->cur = ring->head = head;
+			ring->cur = ring->head = head;
 
-		cur.events++;
-		targ->ctr = cur;
+			cur.events++;
+			targ->ctr = cur;
+		}
 	}
-
 	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
 
 out:
@@ -2189,6 +2197,8 @@ rxseq_body(void *data)
 	targ->ctr = cur;
 
 quit:
+	if (seq_exp != NULL)
+		free(seq_exp);
 	/* reset the ``used`` flag. */
 	targ->used = 0;
 

From 866df6bc4251aca71ee6990ca8e587bb33d42e86 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 4 Nov 2017 12:02:14 +0100
Subject: [PATCH 0219/2207] pkt-gen: support busywait in txseq/rxseq

---
 apps/pkt-gen/pkt-gen.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 28e0ef07d..c1bfce298 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1891,17 +1891,26 @@ txseq_body(void *data)
 		}
 
 		/* wait for available room in the send queue */
+#ifdef BUSYWAIT
+		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
+			D("ioctl error on queue %d: %s", targ->me,
+					strerror(errno));
+			goto quit;
+		}
+#else /* !BUSYWAIT */
 		if (poll(&pfd, 1, 2000) <= 0) {
 			if (targ->cancel)
 				break;
 			D("poll error/timeout on queue %d: %s", targ->me,
 				strerror(errno));
+			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {
 			D("poll error on %d ring %d-%d", pfd.fd,
 				targ->nmd->first_tx_ring, targ->nmd->last_tx_ring);
 			goto quit;
 		}
+#endif /* !BUSYWAIT */
 
 		/* If no room poll() again. */
 		space = nm_ring_space(ring);
@@ -2073,8 +2082,13 @@ rxseq_body(void *data)
 		unsigned int head;
 		int limit;
 
-		/* Once we started to receive packets, wait at most 1 seconds
-		   before quitting. */
+#ifdef BUSYWAIT
+		if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) {
+			D("ioctl error on queue %d: %s", targ->me,
+					strerror(errno));
+			goto quit;
+		}
+#else /* !BUSYWAIT */
 		if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) {
 			clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
 			targ->toc.tv_sec -= 1; /* Subtract timeout time. */
@@ -2085,6 +2099,7 @@ rxseq_body(void *data)
 			D("poll err");
 			goto quit;
 		}
+#endif /* !BUSYWAIT */
 
 		for (j = targ->nmd->first_rx_ring; j <= targ->nmd->last_rx_ring; j++) {
 			ring = NETMAP_RXRING(targ->nmd->nifp, j);
@@ -2192,7 +2207,9 @@ rxseq_body(void *data)
 	}
 	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc);
 
+#ifndef BUSYWAIT
 out:
+#endif /* !BUSYWAIT */
 	targ->completed = 1;
 	targ->ctr = cur;
 

From 4668619a3f336c7c4ed9bcd9e883f12195c211e9 Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Tue, 7 Nov 2017 00:17:00 +0300
Subject: [PATCH 0220/2207] Removed unavailable project file

---
 WINDOWS/netmap.sln | 23 ++---------------------
 1 file changed, 2 insertions(+), 21 deletions(-)

diff --git a/WINDOWS/netmap.sln b/WINDOWS/netmap.sln
index 386351496..44729029c 100644
--- a/WINDOWS/netmap.sln
+++ b/WINDOWS/netmap.sln
@@ -1,7 +1,7 @@
 īģŋ
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.30501.0
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netmap", "netmap.vcxproj", "{789055E4-2677-413D-A638-3E2AED7C7427}"
 EndProject
@@ -20,8 +20,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nm-ndis", "nm-ndis\nm-ndis.
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nm-ndis-pkg", "nm-ndis\nm-ndis-pkg.vcxproj", "{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sysctl", "Sysctl\Sysctl.vcxproj", "{C315D4A0-BBDC-46C4-973A-DE631517FA48}"
-EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -265,22 +263,6 @@ Global
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win8.1 Release|x64.ActiveCfg = Win8.1 Release|x64
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win8.1 Release|x64.Build.0 = Win8.1 Release|x64
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win8.1 Release|x64.Deploy.0 = Win8.1 Release|x64
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Debug|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Debug|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Release|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Release|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win7 Debug|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win7 Debug|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win7 Release|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win7 Release|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8 Debug|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8 Debug|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8 Release|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8 Release|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8.1 Debug|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8.1 Debug|x64.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8.1 Release|Win32.ActiveCfg = Release|Win32
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48}.Win8.1 Release|x64.ActiveCfg = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -291,6 +273,5 @@ Global
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED} = {84E0C4A9-E647-4ECB-B7B6-76D908925A15}
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10} = {D93B3836-DCAF-4E38-9E2F-9D22C64DA946}
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E} = {D93B3836-DCAF-4E38-9E2F-9D22C64DA946}
-		{C315D4A0-BBDC-46C4-973A-DE631517FA48} = {84E0C4A9-E647-4ECB-B7B6-76D908925A15}
 	EndGlobalSection
 EndGlobal

From 9ed27f6bfd6192ca7812d5bec874bb380b8c66d8 Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Wed, 8 Nov 2017 20:12:26 +0300
Subject: [PATCH 0221/2207] added if_ref() stub function

---
 WINDOWS/netmap_windows.c | 10 ++++++++++
 WINDOWS/win_glue.h       |  7 ++++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 8289d421a..ee757272b 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -885,6 +885,16 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
     DbgPrint("bdg_mismatch_datapath unimplemented!!!\n");
 }
 
+void if_ref(struct net_device *ifp)
+{
+	/*
+	* XXX This is just to shut up the compiler.
+	* I wouldn't know what to out in here yet...
+	*/
+	DbgPrint("unimplemented if_ref!!!\n");
+/* 	dev_hold(ifp); */
+}
+
 void
 if_rele(struct net_device *ifp)
 {
diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index f615a4fa6..dfcce1eae 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -46,7 +46,7 @@
 #pragma warning(disable:4118)	//error in between signed and unsigned
 //#pragma warning(disable:4115)	//definition of type between parenthesis
 #pragma warning(disable:4127)	//constant conditional expression
-#pragma warning(disable:4133)	//warning: uncompatible types: From <1> to <2>
+#pragma warning(disable:4133)	//warning: incompatible types: From <1> to <2>
 #pragma warning(disable:4142)	//benign type redefinition
 // #pragma warning(disable:4189)	//local variable initialized but without references
 #pragma warning(disable:4200)	//non-standard extension: matrix of zero dimension in struct/union
@@ -54,8 +54,8 @@
 #pragma warning(disable:4229)	// zero-size arrays // XXX
 #pragma warning(disable:4242)	//possible loss of data in conversion
 #pragma warning(disable:4244)	//possible loss of data in conversion
-#pragma warning(disable:4245)	//conversion from int to uint_32t: corrispondence error between signed and unsigned
-#pragma warning(disable:4389)	//wrong corrispondence between signed and unsigned
+#pragma warning(disable:4245)	//conversion from int to uint_32t: correspondence error between signed and unsigned
+#pragma warning(disable:4389)	//wrong correspondence between signed and unsigned
 
 #pragma warning(disable:4267)	//conversion from 'size_t' to . possible loss of data
 
@@ -360,6 +360,7 @@ win32_ndis_packet_freem(struct mbuf* m)
 
 struct net_device* ifunit_ref(const char *name);
 void if_rele(struct net_device *ifp);
+void if_ref(struct net_device *ifp);
 
 PVOID send_up_to_stack(struct ifnet *ifp, struct mbuf *m, PVOID head);
 

From dfa7daa4f61175bba7d389ad21fb280a776dd90e Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Wed, 8 Nov 2017 20:15:03 +0300
Subject: [PATCH 0222/2207] Added win10 (SDK and WDK) support for netmap core
 driver

---
 WINDOWS/netmap-pkg.vcxproj      | 101 ++++++++++++++++++----
 WINDOWS/netmap-pkg.vcxproj.user |  12 +++
 WINDOWS/netmap.inf              |   4 +-
 WINDOWS/netmap.sln              |  63 ++++++++++++++
 WINDOWS/netmap.vcxproj          | 143 ++++++++++++++++++++++++++++----
 WINDOWS/netmap.vcxproj.user     |   5 +-
 6 files changed, 291 insertions(+), 37 deletions(-)

diff --git a/WINDOWS/netmap-pkg.vcxproj b/WINDOWS/netmap-pkg.vcxproj
index a80e60f42..b232745c2 100644
--- a/WINDOWS/netmap-pkg.vcxproj
+++ b/WINDOWS/netmap-pkg.vcxproj
@@ -1,32 +1,93 @@
 īģŋ
 
-
   
     Utility
     Package
     true
-    WindowsKernelModeDriver8.1
+    WindowsKernelModeDriver10.0
   
-
-
+  
+    
+      Win10 Debug
+      Win32
+    
+    
+      Win10 Debug
+      x64
+    
+    
+      Win10 Release
+      Win32
+    
+    
+      Win10 Release
+      x64
+    
+    
+      Win8.1 Debug
+      Win32
+    
+    
+      Win8.1 Release
+      Win32
+    
+    
+      Win8 Debug
+      Win32
+    
+    
+      Win8 Release
+      Win32
+    
+    
+      Win7 Debug
+      Win32
+    
+    
+      Win7 Release
+      Win32
+    
+    
+      Win8.1 Debug
+      x64
+    
+    
+      Win8.1 Release
+      x64
+    
+    
+      Win8 Debug
+      x64
+    
+    
+      Win8 Release
+      x64
+    
+    
+      Win7 Debug
+      x64
+    
+    
+      Win7 Release
+      x64
+    
+  
   
     {72648F4C-6AAA-4E69-99C9-66D9D6400EE9}
     {4605da2c-74a5-4865-98e1-152ef136825f}
     netmap-pkg
+    10.0.14393.0
   
-
   
-
   
   
-
   
     
   
-
   
-  
-
+  
+    true
+  
   
     DbgengKernelDebugger
     False
@@ -39,29 +100,33 @@
     True
     
     133563
-    $(SolutionDir)\Output-$(ConfigurationName)\
-    $(SolutionDir)\Output-$(ConfigurationName)\tmp\netmap-pkg\
+    $(SolutionDir)Output-$(ConfigurationName)\
+    $(SolutionDir)Output-$(ConfigurationName)\tmp\$(ProjectName)\
+  
+  
+    true
+  
+  
+    true
+  
+  
+    true
   
-
   
     
       4
       true
     
   
-
   
     
   
-
   
     
       {789055e4-2677-413d-a638-3e2aed7c7427}
     
   
-
   
-
   
   
-
+
\ No newline at end of file
diff --git a/WINDOWS/netmap-pkg.vcxproj.user b/WINDOWS/netmap-pkg.vcxproj.user
index 469728d61..50f0ac150 100644
--- a/WINDOWS/netmap-pkg.vcxproj.user
+++ b/WINDOWS/netmap-pkg.vcxproj.user
@@ -21,4 +21,16 @@
   
     TestSign
   
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
 
\ No newline at end of file
diff --git a/WINDOWS/netmap.inf b/WINDOWS/netmap.inf
index dd9509a6e..32e221e6a 100644
--- a/WINDOWS/netmap.inf
+++ b/WINDOWS/netmap.inf
@@ -5,7 +5,7 @@
 [Version]
 Signature="$WINDOWS NT$"
 Class=System
-ClassGuid={9BF68A6C-4C18-4FB4-A2FD-0E54B36F9252}
+ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}
 Provider=%ManufacturerName%
 DriverVer=05/18/2015,0.0.1.1
 CatalogFile=Netmap.cat
@@ -46,7 +46,7 @@ DelService=netmap,0x200 ; SPSVCINST_STOPSERVICE
 [Netmap_Service_Inst]
 DisplayName    = %ClassName%
 ServiceType    = 1               ; SERVICE_KERNEL_DRIVER
-StartType      = 2               ; SERVICE_AUTO_START 
+StartType      = 2               ; SERVICE_AUTO_START
 ErrorControl   = 1               ; SERVICE_ERROR_NORMAL
 ServiceBinary  = %12%\netmap.sys
 ;LoadOrderGroup = Extended Base
diff --git a/WINDOWS/netmap.sln b/WINDOWS/netmap.sln
index 44729029c..865400a05 100644
--- a/WINDOWS/netmap.sln
+++ b/WINDOWS/netmap.sln
@@ -19,6 +19,9 @@ EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nm-ndis", "nm-ndis\nm-ndis.vcxproj", "{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nm-ndis-pkg", "nm-ndis\nm-ndis-pkg.vcxproj", "{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}"
+	ProjectSection(ProjectDependencies) = postProject
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10} = {86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}
+	EndProjectSection
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -26,6 +29,10 @@ Global
 		Debug|x64 = Debug|x64
 		Release|Win32 = Release|Win32
 		Release|x64 = Release|x64
+		Win10 Debug|Win32 = Win10 Debug|Win32
+		Win10 Debug|x64 = Win10 Debug|x64
+		Win10 Release|Win32 = Win10 Release|Win32
+		Win10 Release|x64 = Win10 Release|x64
 		Win7 Debug|Win32 = Win7 Debug|Win32
 		Win7 Debug|x64 = Win7 Debug|x64
 		Win7 Release|Win32 = Win7 Release|Win32
@@ -50,6 +57,18 @@ Global
 		{789055E4-2677-413D-A638-3E2AED7C7427}.Release|x64.ActiveCfg = Win8.1 Release|x64
 		{789055E4-2677-413D-A638-3E2AED7C7427}.Release|x64.Build.0 = Win8.1 Release|x64
 		{789055E4-2677-413D-A638-3E2AED7C7427}.Release|x64.Deploy.0 = Win8.1 Release|x64
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Debug|Win32.ActiveCfg = Win10 Debug|Win32
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Debug|Win32.Build.0 = Win10 Debug|Win32
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Debug|Win32.Deploy.0 = Win10 Debug|Win32
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Debug|x64.ActiveCfg = Win10 Debug|x64
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Debug|x64.Build.0 = Win10 Debug|x64
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Debug|x64.Deploy.0 = Win10 Debug|x64
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Release|Win32.ActiveCfg = Win10 Release|Win32
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Release|Win32.Build.0 = Win10 Release|Win32
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Release|Win32.Deploy.0 = Win10 Release|Win32
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Release|x64.ActiveCfg = Win10 Release|x64
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Release|x64.Build.0 = Win10 Release|x64
+		{789055E4-2677-413D-A638-3E2AED7C7427}.Win10 Release|x64.Deploy.0 = Win10 Release|x64
 		{789055E4-2677-413D-A638-3E2AED7C7427}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
 		{789055E4-2677-413D-A638-3E2AED7C7427}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
 		{789055E4-2677-413D-A638-3E2AED7C7427}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64
@@ -90,6 +109,18 @@ Global
 		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Release|x64.ActiveCfg = Win8.1 Release|x64
 		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Release|x64.Build.0 = Win8.1 Release|x64
 		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Release|x64.Deploy.0 = Win8.1 Release|x64
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Debug|Win32.ActiveCfg = Win10 Debug|Win32
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Debug|Win32.Build.0 = Win10 Debug|Win32
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Debug|Win32.Deploy.0 = Win10 Debug|Win32
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Debug|x64.ActiveCfg = Win10 Debug|x64
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Debug|x64.Build.0 = Win10 Debug|x64
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Debug|x64.Deploy.0 = Win10 Debug|x64
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Release|Win32.ActiveCfg = Win10 Release|Win32
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Release|Win32.Build.0 = Win10 Release|Win32
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Release|Win32.Deploy.0 = Win10 Release|Win32
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Release|x64.ActiveCfg = Win10 Release|x64
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Release|x64.Build.0 = Win10 Release|x64
+		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win10 Release|x64.Deploy.0 = Win10 Release|x64
 		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
 		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
 		{72648F4C-6AAA-4E69-99C9-66D9D6400EE9}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64
@@ -132,6 +163,14 @@ Global
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Release|x64.ActiveCfg = Win8.1 Release|x64
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Release|x64.Build.0 = Win8.1 Release|x64
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Release|x64.Deploy.0 = Win8.1 Release|x64
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Debug|Win32.ActiveCfg = Win10 Debug|Win32
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Debug|Win32.Build.0 = Win10 Debug|Win32
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Debug|x64.ActiveCfg = Win10 Debug|x64
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Debug|x64.Build.0 = Win10 Debug|x64
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Release|Win32.ActiveCfg = Win10 Release|Win32
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Release|Win32.Build.0 = Win10 Release|Win32
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Release|x64.ActiveCfg = Win10 Release|x64
+		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win10 Release|x64.Build.0 = Win10 Release|x64
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
 		{A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32
@@ -179,6 +218,18 @@ Global
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Release|x64.ActiveCfg = Win8.1 Release|x64
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Release|x64.Build.0 = Win8.1 Release|x64
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Release|x64.Deploy.0 = Win8.1 Release|x64
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Debug|Win32.ActiveCfg = Win10 Debug|Win32
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Debug|Win32.Build.0 = Win10 Debug|Win32
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Debug|Win32.Deploy.0 = Win10 Debug|Win32
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Debug|x64.ActiveCfg = Win10 Debug|x64
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Debug|x64.Build.0 = Win10 Debug|x64
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Debug|x64.Deploy.0 = Win10 Debug|x64
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Release|Win32.ActiveCfg = Win10 Release|Win32
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Release|Win32.Build.0 = Win10 Release|Win32
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Release|Win32.Deploy.0 = Win10 Release|Win32
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Release|x64.ActiveCfg = Win10 Release|x64
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Release|x64.Build.0 = Win10 Release|x64
+		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win10 Release|x64.Deploy.0 = Win10 Release|x64
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
 		{86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32
@@ -227,6 +278,18 @@ Global
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Release|x64.ActiveCfg = Win8.1 Release|x64
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Release|x64.Build.0 = Win8.1 Release|x64
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Release|x64.Deploy.0 = Win8.1 Release|x64
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Debug|Win32.ActiveCfg = Win10 Debug|Win32
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Debug|Win32.Build.0 = Win10 Debug|Win32
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Debug|Win32.Deploy.0 = Win10 Debug|Win32
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Debug|x64.ActiveCfg = Win10 Debug|x64
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Debug|x64.Build.0 = Win10 Debug|x64
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Debug|x64.Deploy.0 = Win10 Debug|x64
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Release|Win32.ActiveCfg = Win10 Release|Win32
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Release|Win32.Build.0 = Win10 Release|Win32
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Release|Win32.Deploy.0 = Win10 Release|Win32
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Release|x64.ActiveCfg = Win10 Release|x64
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Release|x64.Build.0 = Win10 Release|x64
+		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win10 Release|x64.Deploy.0 = Win10 Release|x64
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
 		{F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32
diff --git a/WINDOWS/netmap.vcxproj b/WINDOWS/netmap.vcxproj
index ab41bea7a..df5a4f626 100644
--- a/WINDOWS/netmap.vcxproj
+++ b/WINDOWS/netmap.vcxproj
@@ -1,21 +1,98 @@
 īģŋ
 
-
+  
+    
+      Win10 Debug
+      Win32
+    
+    
+      Win10 Debug
+      x64
+    
+    
+      Win10 Release
+      Win32
+    
+    
+      Win10 Release
+      x64
+    
+    
+      Win8.1 Debug
+      Win32
+    
+    
+      Win8.1 Release
+      Win32
+    
+    
+      Win8 Debug
+      Win32
+    
+    
+      Win8 Release
+      Win32
+    
+    
+      Win7 Debug
+      Win32
+    
+    
+      Win7 Release
+      Win32
+    
+    
+      Win8.1 Debug
+      x64
+    
+    
+      Win8.1 Release
+      x64
+    
+    
+      Win8 Debug
+      x64
+    
+    
+      Win8 Release
+      x64
+    
+    
+      Win7 Debug
+      x64
+    
+    
+      Win7 Release
+      x64
+    
+  
   
     {789055E4-2677-413D-A638-3E2AED7C7427}
     {dd38f7fc-d7bd-488b-9242-7d8754cde80d}
     netmap
+    10.0.14393.0
   
-
   
-    Driver 
-    WDM 
-    WindowsKernelModeDriver8.1
+    Driver
+    
+    WDM
+    
+    WindowsKernelModeDriver10.0
   
-
   
   
-
+  
+    true
+  
+  
+    true
+  
+  
+    true
+  
+  
+    true
+  
   
     
       Speed
@@ -28,7 +105,6 @@
       %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib;$(DDK_LIB_PATH)\wmilib.lib;$(DDK_LIB_PATH)\netio.lib;
     
   
-
   
     
       Neither
@@ -41,7 +117,6 @@
       %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib;$(DDK_LIB_PATH)\wmilib.lib;
     
   
-
   
     
       Speed
@@ -51,7 +126,6 @@
       _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions);NDIS60=1;
     
   
-
   
     
       Speed
@@ -60,7 +134,6 @@
       true
     
   
-
   
     
       Speed
@@ -69,7 +142,6 @@
       true
     
   
-
   
     
       Speed
@@ -78,7 +150,50 @@
       true
     
   
-
+  
+    
+      Speed
+      AnySuitable
+      MaxSpeed
+      true
+      Level3
+      false
+      Level3
+      false
+    
+    
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+    
+    
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+    
+  
+  
+    
+      Level3
+    
+  
+  
+    
+      false
+    
+    
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+    
+  
+  
+    
+      Level3
+    
+  
+  
+    
+      false
+    
+    
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+    
+  
   
     
     
@@ -103,4 +218,4 @@
   
   
   
-
+
\ No newline at end of file
diff --git a/WINDOWS/netmap.vcxproj.user b/WINDOWS/netmap.vcxproj.user
index e3dd0cf45..195c0b81a 100644
--- a/WINDOWS/netmap.vcxproj.user
+++ b/WINDOWS/netmap.vcxproj.user
@@ -1,10 +1,9 @@
 īģŋ
 
   
-    
-    
+    CN="WDKTestCert Ali,131544860236513530" | ECEA8629ADED6CB0522E374EB5072BC9D2D865C9
   
   
     TestSign
   
-
+
\ No newline at end of file

From 639db19fca41f0f3c0ed1ea32e781e4bbee39656 Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Wed, 8 Nov 2017 20:18:18 +0300
Subject: [PATCH 0223/2207] Added win10 (SDK and WDK) support for nm-ndis
 driver

And fixed a few problems in the some of its project files
---
 WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj         | 129 +++++++++++++-----
 WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.filters |  14 +-
 WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.user    |  34 ++++-
 WINDOWS/nm-ndis/nm-ndis.vcxproj             | 143 +++++++++++++++-----
 WINDOWS/nm-ndis/nm-ndis.vcxproj.filters     |  40 +++++-
 WINDOWS/nm-ndis/nm-ndis.vcxproj.user        |   6 +
 6 files changed, 282 insertions(+), 84 deletions(-)

diff --git a/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj b/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj
index befd62240..0df8e7cdb 100644
--- a/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj
+++ b/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj
@@ -1,75 +1,132 @@
 īģŋ
 
-
-   
-    WindowsKernelModeDriver8.1
+  
     Utility
     Package
     true
+    WindowsKernelModeDriver10.0
   
-
-  
-
-  
-    WindowsKernelModeDriver8.1
-    Utility
-    Package
-    true
-    Win8.1 Debug
-  
-
+  
+    
+      Win10 Debug
+      Win32
+    
+    
+      Win10 Debug
+      x64
+    
+    
+      Win10 Release
+      Win32
+    
+    
+      Win10 Release
+      x64
+    
+    
+      Win8.1 Debug
+      Win32
+    
+    
+      Win8.1 Release
+      Win32
+    
+    
+      Win8 Debug
+      Win32
+    
+    
+      Win8 Release
+      Win32
+    
+    
+      Win7 Debug
+      Win32
+    
+    
+      Win7 Release
+      Win32
+    
+    
+      Win8.1 Debug
+      x64
+    
+    
+      Win8.1 Release
+      x64
+    
+    
+      Win8 Debug
+      x64
+    
+    
+      Win8 Release
+      x64
+    
+    
+      Win7 Debug
+      x64
+    
+    
+      Win7 Release
+      x64
+    
+  
   
     {F54EA0D4-064F-4AD9-AA21-8F9F3B90AC8E}
-    {EA453FB1-F3EF-493B-B384-DD83BAB817D3}
-    $(MSBuildProjectName)
+    {4605da2c-74a5-4865-98e1-152ef136825f}
     nm-ndis-pkg
+    10.0.14393.0
   
-
-
+  
   
   
-
   
     
   
-
-
-  
-    $(SolutionDir)\Output-$(ConfigurationName)\
-    $(SolutionDir)\Output-$(ConfigurationName)\tmp\$(ProjectName)\
+  
+  
+    true
   
-
   
     DbgengKernelDebugger
     False
-    False
-    None
+    True
     
     
-    
     
-    
-    %PathToInf%
     False
     False
     True
     
     133563
+    $(SolutionDir)Output-$(ConfigurationName)\
+    $(SolutionDir)Output-$(ConfigurationName)\tmp\$(ProjectName)\
+  
+  
+    true
+  
+  
+    true
+  
+  
+    true
   
-
-  
+  
+    
+      4
+      true
+    
   
-
   
-    
     
   
   
     
-      {86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}
+      {789055e4-2677-413d-a638-3e2aed7c7427}
     
   
   
   
   
-
+
\ No newline at end of file
diff --git a/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.filters b/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.filters
index 8f9d2ceff..e1b34f2aa 100644
--- a/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.filters
+++ b/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.filters
@@ -1,21 +1,9 @@
 īģŋ
 
   
-    
-      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*
-      {446F6A95-37A1-4B03-8A92-410687C4D886}
-    
-    
-      h;hpp;hxx;hm;inl;inc;xsd
-      {EA0E0C58-3231-40D0-8E7C-2C45BAC612B4}
-    
-    
-      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml
-      {9ACC37D4-AA63-4917-A0A9-CE371E1BBD46}
-    
     
+      {8E41214B-6785-4CFE-B992-037D68949A14}
       inf;inv;inx;mof;mc;
-      {02639A71-564D-46D6-89B9-7E42931F9188}
     
   
 
\ No newline at end of file
diff --git a/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.user b/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.user
index 7431a9009..50f0ac150 100644
--- a/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.user
+++ b/WINDOWS/nm-ndis/nm-ndis-pkg.vcxproj.user
@@ -1,6 +1,36 @@
 īģŋ
 
-  
+  
+    False
+    True
+    DriverTest
+    
+    
+    C:\Program Files (x86)\Windows Kits\8.1\Testing\Tests\Utilities\DefaultDriverPackageInstallationTask.dll
+    10.216.1.205
+    10.216.1.205
+    
+    Microsoft.DriverKit.DefaultDriverPackageInstallationClass.PerformDefaultDriverPackageInstallation
+    
+    True
+  
+  
+    
+    
+  
+  
     TestSign
   
-
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+  
+    CN="WDKTestCert Ali,131544860649071360" | 10000FDB00D12EF1C204354F46F27C83B8A54118
+  
+
\ No newline at end of file
diff --git a/WINDOWS/nm-ndis/nm-ndis.vcxproj b/WINDOWS/nm-ndis/nm-ndis.vcxproj
index f3c131557..d032b3b63 100644
--- a/WINDOWS/nm-ndis/nm-ndis.vcxproj
+++ b/WINDOWS/nm-ndis/nm-ndis.vcxproj
@@ -1,28 +1,111 @@
 īģŋ
 
-
-
+  
+    
+      Win10 Debug
+      Win32
+    
+    
+      Win10 Debug
+      x64
+    
+    
+      Win10 Release
+      Win32
+    
+    
+      Win10 Release
+      x64
+    
+    
+      Win8.1 Debug
+      Win32
+    
+    
+      Win8.1 Release
+      Win32
+    
+    
+      Win8 Debug
+      Win32
+    
+    
+      Win8 Release
+      Win32
+    
+    
+      Win7 Debug
+      Win32
+    
+    
+      Win7 Release
+      Win32
+    
+    
+      Win8.1 Debug
+      x64
+    
+    
+      Win8.1 Release
+      x64
+    
+    
+      Win8 Debug
+      x64
+    
+    
+      Win8 Release
+      x64
+    
+    
+      Win7 Debug
+      x64
+    
+    
+      Win7 Release
+      x64
+    
+  
   
     {86BB0F88-ECD9-4E2C-AD47-AE4071D1DE10}
     {47A52D61-9E9E-4FEA-9033-C1434C5F8870}
     nm-ndis
+    10.0.14393.0
   
-
   
-    Driver 
-    WDM 
-    WindowsKernelModeDriver8.1
+    Driver
+    
+    WDM
+    
+    WindowsKernelModeDriver10.0
   
-
   
   
-
-
-
   
     
       %(AdditionalIncludeDirectories);..;.
@@ -32,8 +115,8 @@
       %(PreprocessorDefinitions);NDIS630=1
       %(PreprocessorDefinitions);NDISLWF=1
       %(PreprocessorDefinitions);NDIS_WDM=1
-      true
-      Level4
+      false
+      Level3
     
     
       %(AdditionalIncludeDirectories);..;.
@@ -43,7 +126,6 @@
       %(PreprocessorDefinitions);NDISLWF=1
       %(PreprocessorDefinitions);NDIS_WDM=1
     
-
     
       %(AdditionalIncludeDirectories);..;.
       %(PreprocessorDefinitions);NDIS60=1
@@ -52,28 +134,25 @@
       %(PreprocessorDefinitions);NDISLWF=1
       %(PreprocessorDefinitions);NDIS_WDM=1
     
-
   
-
   
     
       %(PreprocessorDefinitions);_KERNEL=1;
     
   
-
   
-
   
     
     
       %(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
     
     
       
       
     
   
-
   
     
       Speed
@@ -82,8 +161,6 @@
       true
     
   
-
-
   
     
       Speed
@@ -92,7 +169,20 @@
       true
     
   
-
+  
+    
+      Speed
+      AnySuitable
+      MaxSpeed
+      true
+    
+    
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+    
+    
+      $(SolutionDir)Output-$(ConfigurationName)\$(TargetName)-pkg\$(TargetName).pdb
+    
+  
   
     
       Speed
@@ -101,7 +191,6 @@
       true
     
   
-
   
     
       Speed
@@ -110,7 +199,6 @@
       true
     
   
-
   
     
       Neither
@@ -120,9 +208,6 @@
       false
     
   
-
-
-
   
     
       ;%(AdditionalIncludeDirectories)
@@ -150,19 +235,15 @@
     
     
   
-
   
     
   
-
   
     
     
   
-
   
     
   
-
   
-
+
\ No newline at end of file
diff --git a/WINDOWS/nm-ndis/nm-ndis.vcxproj.filters b/WINDOWS/nm-ndis/nm-ndis.vcxproj.filters
index 0d3463669..2a74aaa1e 100644
--- a/WINDOWS/nm-ndis/nm-ndis.vcxproj.filters
+++ b/WINDOWS/nm-ndis/nm-ndis.vcxproj.filters
@@ -269,6 +269,42 @@
     
     
     
+    
+      Header Files
+    
+    
+    
+    
+    
+      Header Files
+    
+    
+    
+    
+    
+      Header Files
+    
+    
+    
+    
+    
+      Header Files
+    
+    
+    
+    
+    
+      Header Files
+    
+    
+    
+    
+    
+      Header Files
+    
+    
+    
+    
   
   
     
@@ -276,6 +312,6 @@
     
   
   
-    
+    
   
-
+
\ No newline at end of file
diff --git a/WINDOWS/nm-ndis/nm-ndis.vcxproj.user b/WINDOWS/nm-ndis/nm-ndis.vcxproj.user
index dedc94cc2..30fece355 100644
--- a/WINDOWS/nm-ndis/nm-ndis.vcxproj.user
+++ b/WINDOWS/nm-ndis/nm-ndis.vcxproj.user
@@ -12,9 +12,15 @@
   
     TestSign
   
+  
+    TestSign
+  
   
     TestSign
   
+  
+    TestSign
+  
   
     TestSign
   

From 70bb5ce297827619a721f00efa1b89f3936bb1ec Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Wed, 8 Nov 2017 20:19:25 +0300
Subject: [PATCH 0224/2207] Added win10 (SDK) support for loader

---
 WINDOWS/Loader/loader.vcxproj | 44 +++++++++++++++++++++++++----------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/WINDOWS/Loader/loader.vcxproj b/WINDOWS/Loader/loader.vcxproj
index be67f679c..e63660d39 100644
--- a/WINDOWS/Loader/loader.vcxproj
+++ b/WINDOWS/Loader/loader.vcxproj
@@ -1,7 +1,22 @@
 īģŋ
 
   
-
+    
+      Win10 Debug
+      Win32
+    
+    
+      Win10 Debug
+      x64
+    
+    
+      Win10 Release
+      Win32
+    
+    
+      Win10 Release
+      x64
+    
     
       Win8.1 Debug
       Win32
@@ -38,12 +53,10 @@
       Win7 Debug
       x64
     
-
     
       Win8.1 Release
       x64
     
-
     
       Win8 Release
       x64
@@ -53,24 +66,22 @@
       x64
     
   
-
   
     {A0394AC2-3D0E-4B5E-9F5F-FA4CEE1ABBED}
     $(MSBuildProjectName)
-   
+    
     Win8.1 Debug
     Win32
     {BA5AA988-42F7-47EE-8963-173B9E7F94C5}
     loader
+    10.0.14393.0
   
   
-
   
     
-    WindowsApplicationForDrivers8.1
+    WindowsApplicationForDrivers10.0
     Application
   
-
   
     Win7
     False
@@ -83,6 +94,11 @@
     WindowsV6.3
     False
   
+  
+    
+    
+    False
+  
   
     Win7
     True
@@ -95,7 +111,11 @@
     WindowsV6.3
     True
   
-
+  
+    
+    
+    True
+  
   
   
     $(SolutionDir)\Output-$(ConfigurationName)\
@@ -112,8 +132,8 @@
   
   
     
-      true
-      Level4
+      false
+      Level3
       %(AdditionalIncludeDirectories);..\sys
     
     
@@ -145,4 +165,4 @@
     
   
   
-
+
\ No newline at end of file

From b7947b1a2bddb369fa1c57dddcb0a589cda067a0 Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Wed, 8 Nov 2017 20:36:38 +0300
Subject: [PATCH 0225/2207] Made struct plut_entry and struct lut_entry
 reachable for windows as well

---
 sys/dev/netmap/netmap_kern.h | 8 ++++----
 sys/dev/netmap/netmap_mem2.c | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 55b5b0fff..d60e9794f 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1762,15 +1762,15 @@ netmap_idx_k2n(struct netmap_kring *kr, int idx)
 
 
 /* Entries of the look-up table. */
-#ifndef linux
+#if !defined(linux) && !defined(_WIN32)
 struct lut_entry {
 	void *vaddr;		/* virtual address. */
 	vm_paddr_t paddr;	/* physical address. */
 };
-#else /* linux */
+#else /* linux & _WIN32 */
 /* dma-mapping in linux can assign a buffer a different address
  * depending on the device, so we need to have a separate 
- * physical-adress look-up table for each na.
+ * physical-address look-up table for each na.
  * We can still share the vaddrs, though, therefore we split
  * the lut_entry structure.
  */
@@ -1781,7 +1781,7 @@ struct lut_entry {
 struct plut_entry {
 	vm_paddr_t paddr;	/* physical address. */
 };
-#endif /* !linux */
+#endif /* !linux & !_WIN32 */
 
 struct netmap_obj_pool;
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f8de03ac2..6623bad62 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1341,7 +1341,7 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 		 */
 		for (; i < lim; i++, clust += p->_objsize) {
 			p->lut[i].vaddr = clust;
-#ifndef linux
+#if !defined(linux) && !defined(_WIN32)
 			p->lut[i].paddr = vtophys(clust);
 #endif
 		}

From 79a0a2ff9b3314119ab79c9300c4b09c155770c6 Mon Sep 17 00:00:00 2001
From: Ali Abdulkadir 
Date: Thu, 9 Nov 2017 00:42:55 +0300
Subject: [PATCH 0226/2207] Removed some trailing white space

---
 WINDOWS/win_glue.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index dfcce1eae..14078e5e1 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -22,7 +22,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
- 
+
 #ifndef NETMAP_WIN_GLUE_H
 #define NETMAP_WIN_GLUE_H
 
@@ -117,7 +117,7 @@ typedef char *			caddr_t;
 
 typedef PHYSICAL_ADDRESS 	vm_paddr_t;
 typedef uint32_t		vm_offset_t;
-typedef ULONG 			vm_ooffset_t; 
+typedef ULONG 			vm_ooffset_t;
 
 #define thread PIO_STACK_LOCATION
 
@@ -127,7 +127,7 @@ typedef ULONG 			vm_ooffset_t;
 /*
  *	ERRNO -> NTSTATUS TRANSLATION
  */
-#define ENOBUFS		STATUS_DEVICE_INSUFFICIENT_RESOURCES	
+#define ENOBUFS		STATUS_DEVICE_INSUFFICIENT_RESOURCES
 #define EOPNOTSUPP	STATUS_INVALID_DEVICE_REQUEST
 
 /*
@@ -215,7 +215,7 @@ typedef struct _win_SELINFO
 	KGUARDED_MUTEX mutex;
 } win_SELINFO;
 
-static void 
+static void
 nm_os_selinfo_init(win_SELINFO* queue)
 {
 	KeInitializeEvent(&queue->queue, NotificationEvent, TRUE);
@@ -266,7 +266,7 @@ static int time_uptime_w32()
 struct netmap_adapter;
 
 struct net_device {
-	char	if_xname[IFNAMSIZ];			// external name (name + unit) 
+	char	if_xname[IFNAMSIZ];			// external name (name + unit)
 	//        struct ifaltq if_snd;         /* output queue (includes altq) */
 	struct netmap_adapter	*na;
 	void	*pfilter;
@@ -333,7 +333,7 @@ struct mbuf *win_make_mbuf(struct net_device *, uint32_t, const char *);
 	// XXX do we also need the netmap_default_mbuf_destructor ?
 
 
-static inline void 
+static inline void
 win32_ndis_packet_freem(struct mbuf* m)
 {
 	if (m != NULL) {
@@ -345,7 +345,7 @@ win32_ndis_packet_freem(struct mbuf* m)
 		ExFreeToNPagedLookasideList(&m->dev->mbuf_pool, m);
 		//free(m, M_DEVBUF);
 
-	}	
+	}
 }
 
 /*

From 1e5db46247cb054b47d994ff8a924ff6ccb42b09 Mon Sep 17 00:00:00 2001
From: aayla-secura 
Date: Thu, 9 Nov 2017 08:59:17 +1000
Subject: [PATCH 0227/2207] Fixes issue #392.

Changed:
sys/net/netmap_user.h:
	nm_inject and nm_dispatch did not inject into/read from
	rings in the range first_*x_ring+1 .. cur_*x_ring-1.
---
 sys/net/netmap_user.h | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index d8cf04d16..03622e345 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1024,13 +1024,13 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 static int
 nm_inject(struct nm_desc *d, const void *buf, size_t size)
 {
-	u_int c, n = d->last_tx_ring - d->first_tx_ring + 1;
+	u_int c, n = d->last_tx_ring - d->first_tx_ring + 1,
+		ri = d->cur_tx_ring;
 
-	for (c = 0; c < n ; c++) {
+	for (c = 0; c < n ; c++, ri++) {
 		/* compute current ring to use */
 		struct netmap_ring *ring;
 		uint32_t i, idx;
-		uint32_t ri = d->cur_tx_ring + c;
 
 		if (ri > d->last_tx_ring)
 			ri = d->first_tx_ring;
@@ -1068,13 +1068,13 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
 	 * of buffers and the int is large enough that we never wrap,
 	 * so we can omit checking for -1
 	 */
-	for (c=0; c < n && cnt != got; c++) {
+	for (c=0; c < n && cnt != got; c++, ri++) {
 		/* compute current ring to use */
 		struct netmap_ring *ring;
 
-		ri = d->cur_rx_ring + c;
 		if (ri > d->last_rx_ring)
 			ri = d->first_rx_ring;
+		d->cur_rx_ring = ri;
 		ring = NETMAP_RXRING(d->nifp, ri);
 		for ( ; !nm_ring_empty(ring) && cnt != got; got++) {
 			u_int idx, i;
@@ -1095,7 +1095,6 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
 		d->hdr.flags = 0;
 		cb(arg, &d->hdr, d->hdr.buf);
 	}
-	d->cur_rx_ring = ri;
 	return got;
 }
 

From bb6f4c69907a7ce241bd03bb0faaef52a3ce93a9 Mon Sep 17 00:00:00 2001
From: aayla-secura 
Date: Thu, 9 Nov 2017 13:36:08 +1000
Subject: [PATCH 0228/2207] Fixed wrong cur_rx_ring when dispatching 1st packet
 in ring

Changed:
sys/net/netmap_user.h:
	To be able to set NM_MORE_PKTS nm_dispatch calls the handler on
	the next execution of the loop over each ring. After changing
	rings, the handler was seeing the new cur_rx_ring and not the
	one where the buffer was coming from.
---
 sys/net/netmap_user.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 03622e345..d08a220bd 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1074,7 +1074,6 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
 
 		if (ri > d->last_rx_ring)
 			ri = d->first_rx_ring;
-		d->cur_rx_ring = ri;
 		ring = NETMAP_RXRING(d->nifp, ri);
 		for ( ; !nm_ring_empty(ring) && cnt != got; got++) {
 			u_int idx, i;
@@ -1083,6 +1082,9 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
 			}
 			i = ring->cur;
 			idx = ring->slot[i].buf_idx;
+			/* d->cur_rx_ring doesn't change inside this loop, but
+			 * set it here, so it reflects d->hdr.buf's ring */
+			d->cur_rx_ring = ri;
 			d->hdr.slot = &ring->slot[i];
 			d->hdr.buf = (u_char *)NETMAP_BUF(ring, idx);
 			// __builtin_prefetch(buf);

From 95252919cb217fc1d9b1ac7f6c322233f363e247 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Nov 2017 13:38:53 +0100
Subject: [PATCH 0229/2207] ixgbe: reset ring pointers before leaving netmap
 mode

---
 LINUX/ixgbe_netmap_linux.h | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 7d30a55f8..d4235cfbd 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -216,12 +216,37 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 {
 	struct ifnet *ifp = na->ifp;
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
+	int i;
 
 	// adapter->netdev->trans_start = jiffies; // disable watchdog ?
 	/* protect against other reinit */
 	while (test_and_set_bit(NM_IXGBE_RESETTING, &adapter->state))
 		usleep_range(1000, 2000);
 
+	/* reset all next_to_* pointers before leaving netmap mode */
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct netmap_kring *kring = &na->rx_rings[i];
+
+		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
+			struct NM_IXGBE_RING *rxr = NM_IXGBE_RX_RING(adapter, i);
+
+			rxr->next_to_clean = 0;
+			rxr->next_to_use = 0;
+			rxr->next_to_alloc = 0;
+		}
+	}
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct netmap_kring *kring = &na->tx_rings[i];
+
+		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
+			struct NM_IXGBE_RING *rxr = NM_IXGBE_TX_RING(adapter, i);
+
+			rxr->next_to_clean = 0;
+			rxr->next_to_use = 0;
+		}
+	}
+
 	if (netif_running(adapter->netdev))
 		NM_IXGBE_DOWN(adapter);
 
@@ -547,14 +572,6 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 		IXGBE_WRITE_REG(&adapter->hw, NM_IXGBE_RDT(rxr->reg_idx), nic_i);
 	}
 
-	/* some versions of the ixgbe driver will blindly try to deallocate
-	 * stuff from next_to_clean to next_to_alloc on ifdown, but we skipped
-	 * the corresponding allocations when we put the card in netmap mode.
-	 * We prevent this by always having next_to_alloc==next_to_clean
-	 */
-	rxr->next_to_alloc = rxr->next_to_clean;
-
-
 	return 0;
 
 ring_reset:

From da116fd90faf5f6ca579d516f299f4ff36b0b8c1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Nov 2017 14:10:59 +0100
Subject: [PATCH 0230/2207] ixgbe/ixgbevf: check for definition of
 next_to_alloc

---
 LINUX/configure            | 19 +++++++++++++++++++
 LINUX/ixgbe_netmap_linux.h | 11 +++++++++++
 2 files changed, 30 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 0565d73cc..6b40c967a 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1541,6 +1541,16 @@ EOF
  	 	ixgbe_irq_disable_queues(adapter, qmask);
  	 }
 EOF
+
+  # is next_to_alloc defined?
+  add_test "define IXGBE_HAVE_NTA" <next_to_alloc;
+	}
+EOF
   fi # ixgbe
 
   if drv enabled ixgbevf; then
@@ -1566,6 +1576,15 @@ EOF
   	dummy(struct ixgbevf_adapter *adapter) {
   		return adapter->tx_ring[0];
   	}
+EOF
+  # is next_to_alloc defined?
+  add_test "define IXGBEVF_HAVE_NTA" <next_to_alloc;
+	}
 EOF
   fi
 
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index d4235cfbd..89449a917 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -142,6 +142,10 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
 }
 
+#ifdef NETMAP_LINUX_HAVE_IXGBE_NTA
+#define NETMAP_LINUX_HAVE_NTA
+#endif /* NETMAP_LINUX_HAVE_IXGBE_NTA */
+
 #else
 /***********************************************************************
  *                        ixgbevf                                      *
@@ -188,6 +192,11 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	// TODO
 	D("not supported");
 }
+
+#ifdef NETMAP_LINUX_HAVE_IXGBEVF_NTA
+#define NETMAP_LINUX_HAVE_NTA
+#endif /* NETMAP_LINUX_HAVE_IXGBEVF_NTA */
+
 #endif /* NM_IXGBE */
 /**********************************************************************/
 
@@ -232,7 +241,9 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 
 			rxr->next_to_clean = 0;
 			rxr->next_to_use = 0;
+#ifdef NETMAP_LINUX_HAVE_NTA
 			rxr->next_to_alloc = 0;
+#endif /* NETMAP_LINUX_HAVE_NTA */
 		}
 	}
 

From 5715d81b6dc01783296036858c2302ee1b6b1a18 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Nov 2017 14:11:24 +0100
Subject: [PATCH 0231/2207] ixgbe: small fix in some vanilla patches

---
 LINUX/configure                                  | 2 +-
 LINUX/final-patches/vanilla--ixgbe--30a00--30d00 | 2 +-
 LINUX/final-patches/vanilla--ixgbe--30d00--30f00 | 2 +-
 LINUX/final-patches/vanilla--ixgbe--30f00--31300 | 2 +-
 LINUX/final-patches/vanilla--ixgbe--31300--40900 | 2 +-
 LINUX/final-patches/vanilla--ixgbe--40900--99999 | 2 +-
 LINUX/ixgbe_netmap_linux.h                       | 8 ++++----
 7 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 6b40c967a..7d40f8a21 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1579,7 +1579,7 @@ EOF
 EOF
   # is next_to_alloc defined?
   add_test "define IXGBEVF_HAVE_NTA" <flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -9799,6 +9847,10 @@ skip_sriov:
+@@ -9799,6 +9847,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 89449a917..cf809a017 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -142,9 +142,9 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
 }
 
-#ifdef NETMAP_LINUX_HAVE_IXGBE_NTA
+#ifdef NETMAP_LINUX_IXGBE_HAVE_NTA
 #define NETMAP_LINUX_HAVE_NTA
-#endif /* NETMAP_LINUX_HAVE_IXGBE_NTA */
+#endif /* NETMAP_LINUX_IXGBE_HAVE_NTA */
 
 #else
 /***********************************************************************
@@ -193,9 +193,9 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	D("not supported");
 }
 
-#ifdef NETMAP_LINUX_HAVE_IXGBEVF_NTA
+#ifdef NETMAP_LINUX_IXGBEVF_HAVE_NTA
 #define NETMAP_LINUX_HAVE_NTA
-#endif /* NETMAP_LINUX_HAVE_IXGBEVF_NTA */
+#endif /* NETMAP_LINUX_IXGBEVF_HAVE_NTA */
 
 #endif /* NM_IXGBE */
 /**********************************************************************/

From 233c3b43c394afb19d39d09d36ed7d887fa9fb78 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 13 Nov 2017 18:42:05 +0100
Subject: [PATCH 0232/2207] linux: ported drivers to 4.14

---
 .../vanilla--e1000--20620--31200              |   2 +-
 .../vanilla--e1000--31200--99999              |   2 +-
 .../vanilla--e1000e--20620--30100             |   2 +-
 .../vanilla--e1000e--30100--30400             |   2 +-
 .../vanilla--e1000e--30400--30900             |   2 +-
 .../vanilla--e1000e--30900--99999             |   2 +-
 .../vanilla--forcedeth.c--20626--99999        |   2 +-
 .../final-patches/vanilla--i40e--30c00--40100 |   4 +-
 .../final-patches/vanilla--i40e--40100--40300 |   4 +-
 .../final-patches/vanilla--i40e--40300--40400 |   4 +-
 .../final-patches/vanilla--i40e--40400--40700 |   4 +-
 ...700--99999 => vanilla--i40e--40700--40e00} |   4 +-
 .../final-patches/vanilla--i40e--40e00--99999 | 104 ++++++++++++++++++
 .../final-patches/vanilla--igb--20621--20623  |   2 +-
 .../final-patches/vanilla--igb--20623--30200  |   2 +-
 .../final-patches/vanilla--igb--30200--30800  |   2 +-
 .../final-patches/vanilla--igb--30800--30f00  |   2 +-
 .../final-patches/vanilla--igb--30f00--40100  |   2 +-
 .../final-patches/vanilla--igb--40100--40400  |   2 +-
 .../final-patches/vanilla--igb--40400--99999  |   2 +-
 .../vanilla--r8169.c--20620--20625            |   2 +-
 .../vanilla--r8169.c--20625--20626            |   2 +-
 .../vanilla--r8169.c--20626--30400            |   2 +-
 .../vanilla--veth.c--20620--30900             |   2 +-
 .../vanilla--veth.c--30900--30f00             |   2 +-
 .../vanilla--veth.c--30f00--99999             |   2 +-
 .../vanilla--virtio_net.c--20622--20625       |   2 +-
 .../vanilla--virtio_net.c--20625--20626       |   2 +-
 .../vanilla--virtio_net.c--20626--30300       |   2 +-
 .../vanilla--virtio_net.c--30300--30500       |   2 +-
 .../vanilla--virtio_net.c--30500--30800       |   2 +-
 .../vanilla--virtio_net.c--30800--30b00       |   2 +-
 .../vanilla--virtio_net.c--30b00--31100       |   2 +-
 .../vanilla--virtio_net.c--31100--31300       |   2 +-
 .../vanilla--virtio_net.c--31300--40100       |   2 +-
 .../vanilla--virtio_net.c--40100--40900       |   2 +-
 .../vanilla--virtio_net.c--40900--40c00       |   2 +-
 .../vanilla--virtio_net.c--40c00--99999       |   2 +-
 38 files changed, 146 insertions(+), 42 deletions(-)
 rename LINUX/final-patches/{vanilla--i40e--40700--99999 => vanilla--i40e--40700--40e00} (97%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--40e00--99999

diff --git a/LINUX/final-patches/vanilla--e1000--20620--31200 b/LINUX/final-patches/vanilla--e1000--20620--31200
index c36154ed8..0d8bb0577 100644
--- a/LINUX/final-patches/vanilla--e1000--20620--31200
+++ b/LINUX/final-patches/vanilla--e1000--20620--31200
@@ -1,5 +1,5 @@
 diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index bcd192ca47b0..013f52897fd8 100644
+index bcd192c..013f528 100644
 --- a/e1000/e1000_main.c
 +++ b/e1000/e1000_main.c
 @@ -190,6 +190,10 @@ static struct pci_error_handlers e1000_err_handler = {
diff --git a/LINUX/final-patches/vanilla--e1000--31200--99999 b/LINUX/final-patches/vanilla--e1000--31200--99999
index e3cd77bd4..eeca93fd1 100644
--- a/LINUX/final-patches/vanilla--e1000--31200--99999
+++ b/LINUX/final-patches/vanilla--e1000--31200--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index 24f3986cfae2..c28425f57a81 100644
+index 24f3986..c28425f 100644
 --- a/e1000/e1000_main.c
 +++ b/e1000/e1000_main.c
 @@ -200,6 +200,10 @@ static const struct pci_error_handlers e1000_err_handler = {
diff --git a/LINUX/final-patches/vanilla--e1000e--20620--30100 b/LINUX/final-patches/vanilla--e1000e--20620--30100
index 947e1a4ed..85fb9c8e4 100644
--- a/LINUX/final-patches/vanilla--e1000e--20620--30100
+++ b/LINUX/final-patches/vanilla--e1000e--20620--30100
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index fad8f9ea0043..cd4abfdb51c4 100644
+index fad8f9e..cd4abfd 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -87,6 +87,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
diff --git a/LINUX/final-patches/vanilla--e1000e--30100--30400 b/LINUX/final-patches/vanilla--e1000e--30100--30400
index dbf41231c..7163c8fbf 100644
--- a/LINUX/final-patches/vanilla--e1000e--30100--30400
+++ b/LINUX/final-patches/vanilla--e1000e--30100--30400
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 2198e615f241..588f1ecdcb1d 100644
+index 2198e61..588f1ec 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -452,6 +452,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
diff --git a/LINUX/final-patches/vanilla--e1000e--30400--30900 b/LINUX/final-patches/vanilla--e1000e--30400--30900
index 9936324a8..8c8534cf5 100644
--- a/LINUX/final-patches/vanilla--e1000e--30400--30900
+++ b/LINUX/final-patches/vanilla--e1000e--30400--30900
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 9520a6ac1f30..bf94805911f9 100644
+index 9520a6a..bf94805 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -467,6 +467,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
diff --git a/LINUX/final-patches/vanilla--e1000e--30900--99999 b/LINUX/final-patches/vanilla--e1000e--30900--99999
index c20b7abe9..742729b4f 100644
--- a/LINUX/final-patches/vanilla--e1000e--30900--99999
+++ b/LINUX/final-patches/vanilla--e1000e--30900--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 7e615e2bf7e6..32ce408f6b77 100644
+index 7e615e2..32ce408 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -473,6 +473,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
diff --git a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 b/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
index 4eb888276..e9723a2aa 100644
--- a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
+++ b/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
@@ -1,5 +1,5 @@
 diff --git a/forcedeth.c b/forcedeth.c
-index 9c0b1bac6af6..b081d6ba11a2 100644
+index 9c0b1ba..b081d6b 100644
 --- a/forcedeth.c
 +++ b/forcedeth.c
 @@ -1865,12 +1865,25 @@ static void nv_init_tx(struct net_device *dev)
diff --git a/LINUX/final-patches/vanilla--i40e--30c00--40100 b/LINUX/final-patches/vanilla--i40e--30c00--40100
index 2d28f6fe9..9e3b301de 100644
--- a/LINUX/final-patches/vanilla--i40e--30c00--40100
+++ b/LINUX/final-patches/vanilla--i40e--30c00--40100
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 221aa4795017..4e61898c06ab 100644
+index 221aa47..4e61898 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -86,6 +86,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -62,7 +62,7 @@ index 221aa4795017..4e61898c06ab 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 49d2cfa9b0cc..83f3c560887a 100644
+index 49d2cfa..83f3c56 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -27,6 +27,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40100--40300 b/LINUX/final-patches/vanilla--i40e--40100--40300
index f01b14737..048bcfc69 100644
--- a/LINUX/final-patches/vanilla--i40e--40100--40300
+++ b/LINUX/final-patches/vanilla--i40e--40100--40300
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 5b5bea159bd5..c8a329231fcf 100644
+index 5b5bea1..c8a32923 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -91,6 +91,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -62,7 +62,7 @@ index 5b5bea159bd5..c8a329231fcf 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 9d95042d5a0f..80f8a88a3ae8 100644
+index 9d95042d..80f8a88 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40300--40400 b/LINUX/final-patches/vanilla--i40e--40300--40400
index 27fc6ca1b..153fcc710 100644
--- a/LINUX/final-patches/vanilla--i40e--40300--40400
+++ b/LINUX/final-patches/vanilla--i40e--40300--40400
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 3dd26cdd0bf2..05b896037ee4 100644
+index 3dd26cd..05b8960 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -94,6 +94,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -63,7 +63,7 @@ index 3dd26cdd0bf2..05b896037ee4 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 738aca68f665..77e14b3828d7 100644
+index 738aca6..77e14b3 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40400--40700 b/LINUX/final-patches/vanilla--i40e--40400--40700
index 62ecf0dd3..e8669c0f4 100644
--- a/LINUX/final-patches/vanilla--i40e--40400--40700
+++ b/LINUX/final-patches/vanilla--i40e--40400--40700
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 4a9873ec28c7..2803d1142f17 100644
+index 4a9873ec..2803d11 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -97,6 +97,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -63,7 +63,7 @@ index 4a9873ec28c7..2803d1142f17 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 635b3ac17877..baed465e8b35 100644
+index 635b3ac..baed465 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40700--99999 b/LINUX/final-patches/vanilla--i40e--40700--40e00
similarity index 97%
rename from LINUX/final-patches/vanilla--i40e--40700--99999
rename to LINUX/final-patches/vanilla--i40e--40700--40e00
index a3b01f104..912df8274 100644
--- a/LINUX/final-patches/vanilla--i40e--40700--99999
+++ b/LINUX/final-patches/vanilla--i40e--40700--40e00
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 501f15d9f4d6..df240129be69 100644
+index 501f15d..df24012 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -110,6 +110,10 @@ MODULE_LICENSE("GPL");
@@ -62,7 +62,7 @@ index 501f15d9f4d6..df240129be69 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index a8868e1bf832..9186a17975b8 100644
+index a8868e1..9186a17 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40e00--99999 b/LINUX/final-patches/vanilla--i40e--40e00--99999
new file mode 100644
index 000000000..db8d94525
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--40e00--99999
@@ -0,0 +1,104 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 6498da8..d45069e 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -113,6 +113,10 @@ MODULE_LICENSE("GPL");
+ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+@@ -2980,6 +2984,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3059,6 +3067,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -10051,6 +10064,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -10418,6 +10436,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 120c68f..70d59e2 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -31,6 +31,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -745,6 +749,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2069,6 +2078,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ 	bool failure = false, xdp_xmit = false;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;
diff --git a/LINUX/final-patches/vanilla--igb--20621--20623 b/LINUX/final-patches/vanilla--igb--20621--20623
index 22476d6f2..470149b91 100644
--- a/LINUX/final-patches/vanilla--igb--20621--20623
+++ b/LINUX/final-patches/vanilla--igb--20621--20623
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index c881347cb26d..a2af3799f5a8 100644
+index c881347..a2af379 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -226,6 +226,10 @@ char *igb_get_hw_dev_name(struct e1000_hw *hw)
diff --git a/LINUX/final-patches/vanilla--igb--20623--30200 b/LINUX/final-patches/vanilla--igb--20623--30200
index a258b2391..7708b0fff 100644
--- a/LINUX/final-patches/vanilla--igb--20623--30200
+++ b/LINUX/final-patches/vanilla--igb--20623--30200
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index cea37e0837ff..81fd28b8cb4e 100644
+index cea37e0..81fd28b 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -201,6 +201,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
diff --git a/LINUX/final-patches/vanilla--igb--30200--30800 b/LINUX/final-patches/vanilla--igb--30200--30800
index 9ae06fa01..4043728f5 100644
--- a/LINUX/final-patches/vanilla--igb--30200--30800
+++ b/LINUX/final-patches/vanilla--igb--30200--30800
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index ced544499f1b..43c2419cd340 100644
+index ced5444..43c2419 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -225,6 +225,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
diff --git a/LINUX/final-patches/vanilla--igb--30800--30f00 b/LINUX/final-patches/vanilla--igb--30800--30f00
index 1eaa64b3c..1e3643441 100644
--- a/LINUX/final-patches/vanilla--igb--30800--30f00
+++ b/LINUX/final-patches/vanilla--igb--30800--30f00
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 31cfe2ec75df..2776ed444bf4 100644
+index 31cfe2e..2776ed4 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -247,6 +247,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--igb--30f00--40100 b/LINUX/final-patches/vanilla--igb--30f00--40100
index 81138684a..8f7a2004a 100644
--- a/LINUX/final-patches/vanilla--igb--30f00--40100
+++ b/LINUX/final-patches/vanilla--igb--30f00--40100
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 16430a8440fa..c2c462218ec3 100644
+index 16430a8..c2c4622 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -257,6 +257,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--igb--40100--40400 b/LINUX/final-patches/vanilla--igb--40100--40400
index 00a867770..dfee4bdf4 100644
--- a/LINUX/final-patches/vanilla--igb--40100--40400
+++ b/LINUX/final-patches/vanilla--igb--40100--40400
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index a0a9b1fcb5e8..85be1ebd02ab 100644
+index a0a9b1f..85be1eb 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -251,6 +251,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--igb--40400--99999 b/LINUX/final-patches/vanilla--igb--40400--99999
index 5d5ea3430..f73685ad5 100644
--- a/LINUX/final-patches/vanilla--igb--40400--99999
+++ b/LINUX/final-patches/vanilla--igb--40400--99999
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index ea7b09887245..ddb376efc198 100644
+index ea7b098..ddb376e 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -253,6 +253,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--r8169.c--20620--20625 b/LINUX/final-patches/vanilla--r8169.c--20620--20625
index 20b7a6018..d4a8f3781 100644
--- a/LINUX/final-patches/vanilla--r8169.c--20620--20625
+++ b/LINUX/final-patches/vanilla--r8169.c--20620--20625
@@ -1,5 +1,5 @@
 diff --git a/r8169.c b/r8169.c
-index 0fe2fc90f207..5d363e589803 100644
+index 0fe2fc9..5d363e5 100644
 --- a/r8169.c
 +++ b/r8169.c
 @@ -537,6 +537,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
diff --git a/LINUX/final-patches/vanilla--r8169.c--20625--20626 b/LINUX/final-patches/vanilla--r8169.c--20625--20626
index e5cf077e7..fe419354f 100644
--- a/LINUX/final-patches/vanilla--r8169.c--20625--20626
+++ b/LINUX/final-patches/vanilla--r8169.c--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/r8169.c b/r8169.c
-index 53b13deade95..ced4849577f0 100644
+index 53b13de..ced4849 100644
 --- a/r8169.c
 +++ b/r8169.c
 @@ -535,6 +535,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
diff --git a/LINUX/final-patches/vanilla--r8169.c--20626--30400 b/LINUX/final-patches/vanilla--r8169.c--20626--30400
index a1b9eb6f6..5e6d6473a 100644
--- a/LINUX/final-patches/vanilla--r8169.c--20626--30400
+++ b/LINUX/final-patches/vanilla--r8169.c--20626--30400
@@ -1,5 +1,5 @@
 diff --git a/r8169.c b/r8169.c
-index 7ffdb80adf40..fc9272305d02 100644
+index 7ffdb80..fc92723 100644
 --- a/r8169.c
 +++ b/r8169.c
 @@ -590,6 +590,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
diff --git a/LINUX/final-patches/vanilla--veth.c--20620--30900 b/LINUX/final-patches/vanilla--veth.c--20620--30900
index c63d70bf1..fffae7d65 100644
--- a/LINUX/final-patches/vanilla--veth.c--20620--30900
+++ b/LINUX/final-patches/vanilla--veth.c--20620--30900
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index 52af5017c46b..a416e437bebf 100644
+index 52af501..a416e43 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -38,6 +38,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--veth.c--30900--30f00 b/LINUX/final-patches/vanilla--veth.c--30900--30f00
index 04f5b4e43..e2ca5b885 100644
--- a/LINUX/final-patches/vanilla--veth.c--30900--30f00
+++ b/LINUX/final-patches/vanilla--veth.c--30900--30f00
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index 07a4af0aa3dc..672375e5c5c8 100644
+index 07a4af0..672375e 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -36,6 +36,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--veth.c--30f00--99999 b/LINUX/final-patches/vanilla--veth.c--30f00--99999
index 9d0b49ad7..0e17d9ca0 100644
--- a/LINUX/final-patches/vanilla--veth.c--30f00--99999
+++ b/LINUX/final-patches/vanilla--veth.c--30f00--99999
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index b4a10bcb66a0..52b7c371f06b 100644
+index b4a10bc..52b7c37 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -37,6 +37,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
index 342b63b0b..775493f38 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
+++ b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index b0577dd1a42d..0c873c4ae173 100644
+index b0577dd..0c873c4 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -64,6 +64,10 @@ struct virtnet_info
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
index 8edbcc909..2e013c912 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
+++ b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index b6d402806ae6..60bb2b2cc257 100644
+index b6d4028..60bb2b2 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -67,6 +67,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
index d6a60b6db..03ad70378 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
+++ b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 82dba5aaf423..06324f8b2593 100644
+index 82dba5a..06324f8 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -67,6 +67,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
index 7f5e9463b..deba61c7e 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 4880aa8b4c28..64e3625b1750 100644
+index 4880aa8..64e3625 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -80,6 +80,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
index 51dbf469e..91c23fba3 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index f18149ae2588..cc935cfce8b2 100644
+index f18149a..cc935cf 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -90,6 +90,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 b/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
index b75bfeb91..4bec12874 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 35c00c5ea02a..bfbb1787ec55 100644
+index 35c00c5..bfbb178 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -132,6 +132,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
index 29a0d5966..06d6ee96a 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 3d2a90a62649..23654348b613 100644
+index 3d2a90a..2365434 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -131,6 +131,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
index 09db3f340..9f1b59fc6 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 59caa06f34a6..b64cb151db9f 100644
+index 59caa06..b64cb15 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -145,6 +145,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
index bc49240cf..a703e7170 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 059fdf1bf5ee..d79cd6a386e0 100644
+index 059fdf1..d79cd6a 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
index 3e453fd44..e83d330fa 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 63c7810e1545..f5fc43c34afa 100644
+index 63c7810..f5fc43c 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
index e852dffa3..437566ac0 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index cbf1c613c67a..be4daabbc51b 100644
+index cbf1c61..be4daab 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -155,6 +155,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999
index b254abd9b..8ebf13e41 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 143d8a95a60d..27de2c282e08 100644
+index 143d8a9..27de2c2 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -170,6 +170,10 @@ struct virtnet_info {

From b2f8a33b822ba9ff7e89f9df046003dac45f7d5e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 17:01:07 +0100
Subject: [PATCH 0233/2207] mem: don't access the plut after it is gone

---
 sys/dev/netmap/netmap_mem2.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f8de03ac2..e75368c88 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1409,6 +1409,8 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	D("unsupported on Windows");
 #else /* linux */
 	ND("unmapping and freeing plut for %s", na->name);
+	if (lut->plut == NULL)
+		return 0;
 	for (i = 2; i < lim; i += p->_clustentries) {
 		if (lut->plut[i].paddr)
 			netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr);

From 541977a187be2a0baf59d373994b85e71bb2e220 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 20 Nov 2017 10:39:52 +0100
Subject: [PATCH 0234/2207] documentation: add README.ptnetmap

---
 README.images   | 428 ------------------------------------------------
 README.ptnetmap | 111 +++++++++++++
 2 files changed, 111 insertions(+), 428 deletions(-)
 delete mode 100644 README.images
 create mode 100644 README.ptnetmap

diff --git a/README.images b/README.images
deleted file mode 100644
index 1023c506f..000000000
--- a/README.images
+++ /dev/null
@@ -1,428 +0,0 @@
-	EXPERIMENTING WITH NETMAP, VALE AND FAST QEMU
-	---------------------------------------------
-
-***** DISCLAIMER *****
-2016-12-20
-The bootable images referenced here are still available, but they contain
-a very old version of the netmap software. As a result, also the
-instructions here are outdated, as they refer to the old images.
-In particular, the e1000-paravirt solution has been deprecated and
-replaced by a solution based on the netmap passthrough.
-New images with updated software are being produced and will be published
-soon.
-
-***** END OF DIS *****
-
-To ease experiments with Netmap, the VALE switch and our Qemu enhancements
-we have prepared a couple of bootable images (linux and FreeBSD).
-You can find them on the netmap page
-
-	http://info.iet.unipi.it/~luigi/netmap/
-
-where you can also look at more recent versions of this file.
-
-Below are step-by-step instructions on experiments you can run
-with these images. The two main versions are
-
-	picobsd.hdd	-> FreeBSD HEAD (netmap + VALE)
-	tinycore.hdd	-> Linux (qemu + netmap + VALE)
-
-Booting the image
------------------
-For all experiments you need to copy the image on a USB stick
-and boot a PC with it. Alternatively, you can use the image
-with VirtualBox, Qemu or other emulators, as an example
-
-    qemu-system-x86_64 -hda IMAGE_FILE -m 1G -machine accel=kvm ...
-
-(remove 'accel=kvm' if your host does not support kvm).
-The images do not install anything on the hard disk.
-
-Both systems have preloaded drivers for a number of network cards
-(including the intel 10 Gbit ones) with netmap extensions.
-The VALE switch is also available (it is part of the netmap module).
-ssh, scp and a few other utilities are also included.
-
-FreeBSD image:
-
-  + the OS boots directly in console mode, you can switch
-    between terminals with ALT-Fn.
-    The password for the 'root' account is 'setup'
-
-  + if you are connected to a network, you can use
-    	dhclient em0 # or other interface name
-    to obtain an IP address and external connectivity.
-
-Linux image:
-
-  + in addition to the netmap/VALE modules, the KVM kernel module
-    is also preloaded.
-
-  + the boot-loader gives you two main options (each with
-    a variant to delay boot in case you have slow devices):
-
-    + "Boot TinyCore"
-      boots in an X11 environment as user 'tc'.
-      You can create a few terminals using the icon at the
-      bottom. You can use "sudo -s" to get root access.
-      In case no suitable video card is available/detected,
-      it falls back to command line mode.
-
-    + "Boot Core (command line only)"
-      boots in console mode with virtual terminals.
-      You're automatically logged in as user 'tc'.
-      To log in the other terminals use the same username
-      (no password required).
-
-  + The system should automatically recognize the existing ethernet
-    devices, and load the appropriate netmap-capable device drivers
-    when available.  Interfaces are configured through DHCP when possible.
-
-
-General test recommendations
-----------------------------
-NOTE: The tests outlined in the following sections can generate very high
-packet rates, and some hardware misconfiguration problems may prevent
-you from achieving maximum speed.
-Common problems are:
-
-+ slow link autonegotiation.
-  Our programs typically wait 2-4 seconds for
-  link negotiation to complete, but some NIC/switch combinations
-  are much slower. In this case you should increase the delay
-  (pkt-gen has the -w XX option for that) or possibly force
-  the link speed and duplex mode on both sides.
-
-  Check the link speed to make sure there are no nogotiation
-  problems, and that you see the expected speed.
-
-    ethtool IFNAME	# on linux
-    ifconfig IFNAME	# on FreeBSD
-
-+ ethernet flow control.
-  If the receiving port is slow (often the case in presence
-  of multicast/broadcast traffic, or also unicast if you are
-  sending to non-netmap receivers), it will generate ethernet
-  flow control frames that throttle down the sender.
-
-  We recommend to disable BOTH RX and TX ethernet flow control
-  on BOTH sender and receiver.
-  On Linux this can be done with ethtool:
-
-    ethtool -A IFNAME tx off rx off
-
-  whereas on FreeBSD there are device-specific sysctl
-
-	sysctl dev.ix.0.queue0.flow_control = 0
-
-+ CPU power saving.
-  The CPU governor on linux, or equivalent in FreeBSD, tend to
-  throttle down the clock rate reducing performance.
-  Unlike other similar systems, netmap does not have busy-wait
-  loops, so the CPU load is generally low and this can trigger
-  the clock slowdown.
-
-  Make sure that ALL CPUs run at maximum speed, possibly
-  disabling the dynamic frequency-scaling mechanisms.
-
-    cpufreq-set -gperformance	# on linux
-
-    sysctl dev.cpu.0.freq=3401	# on FreeBSD.
-
-+ wrong MAC address
-  netmap does not put the NIC in promiscuous mode, so unless the
-  application does it, the NIC will only receive broadcast traffic or
-  unicast directed to its own MAC address.
-
-
-STANDARD SOCKET TESTS
----------------------
-For most socket-based experiments you can use the "netperf" tool installed
-on the system (version 2.6.0). Be careful to use a matching version for
-the other netperf endpoint (e.g. netserver) when running tests between
-different machines.
-
-Interesting experiments are:
-
-    netperf -H x.y.z.w -tTCP_STREAM  # test TCP throughput
-    netperf -H x.y.z.w -tTCP_RR      # test latency
-    netperf -H x.y.z.w -tUDP_STREAM -- -m8  # test UDP throughput with short packets
-
-where x.y.z.w is the host running "netserver".
-
-
-RAW SOCKET AND TAP TESTS
-------------------------
-For experiments with raw sockets and tap devices you can use the l2
-utilities (l2open, l2send, l2recv) installed on the system.
-With these utilities you can send/receive custom network packets
-to/from raw sockets or tap file descriptors.
-
-The receiver can be run with one of the following commands
-
-    l2open -r IFNAME l2recv     # receive from a raw socket attached to IFNAME
-    l2open -t IFNAME l2recv     # receive from a file descriptor opened on the tap IFNAME
-
-The receiver process will wait indefinitely for the first packet
-and then keep receiving as long as packets keep coming. When the
-flow stops (after a 2 seconds timeout) the process terminates and
-prints the received packet rate and packet count.
-
-To run the sender in an easy way, you can use the script l2-send.sh
-in the home directory. This script defines several shell variables
-that can be manually changed to customize the test (see
-the comments in the script itself).
-
-As an example, you can test configurations with Virtual
-Machines attached to host tap devices bridged together.
-
-
-Tests using the Linux in-kernel pktgen
---------------------------------------
-To use the Linux in-kernel packet generator, you can use the
-script "linux-pktgen.sh" in the home directory.
-The pktgen creates a kernel thread for each hardware TX queue
-of a given NIC.
-
-By manually changing the script shell variable definitions you
-can change the test configuration (e.g. addresses in the generated
-packet). Please change the "NCPU" variable to match the number
-of CPUs on your machine. The script has an argument which
-specifies the number of NIC queues (i.e. kernel threads)
-to use minus one.
-
-For example:
-
-    ./linux-pktgen.sh 2  # Uses 3 NIC queues
-
-When the script terminates, it prints the per-queue rates and
-the total rate achieved.
-
-
-NETMAP AND VALE EXPERIMENTS
----------------------------
-
-For most experiments with netmap you can use the "pkt-gen" command
-(do not confuse it with the Linux in-kernel pktgen), which has a large
-number of options to send and receive traffic (also on TAP devices).
-
-pkt-gen normally generates UDP traffic for a specific IP address
-and using the brodadcast MAC address
-
-Netmap testing with network interfaces
---------------------------------------
-
-Remember that you need a netmap-capable driver in order to use
-netmap on a specific NIC. Currently supported drivers are e1000,
-e1000e, ixgbe, igb. For updated information please visit
-http://info.iet.unipi.it/~luigi/netmap/
-
-Before running pkt-gen, make sure that the link is up.
-
-Run pkt-gen on an interface called "IFNAME":
-
-    pkt-gen -i IFNAME -f tx  # run a pkt-gen sender
-    pkt-gen -i IFNAME -f rx  # run a pkt-gen receiver
-
-pkt-gen without arguments will show other options, e.g.
-  + -w sec	modifies the wait time for link negotioation
-  + -l len	modifies the packet size
-  + -d, -s	set the IP destination/source addresses and ports
-  + -D, -S	set the MAC destination/source addresses
-
-and more.
-
-Testing the VALE switch
-------------------------
-
-To use the VALE switch instead of physical ports you only need
-to change the interface name in the pkt-gen command.
-As an example, on a single machine, you can run senders and receivers
-on multiple ports of a VALE switch as follows (run the commands into
-separate terminals to see the output)
-
-    pkt-gen -ivale0:01 -ftx  # run a sender on the port 01 of the switch vale0
-    pkt-gen -ivale0:02 -frx  # receiver on the port 02 of same switch
-    pkt-gen -ivale0:03 -ftx  # another sender on the port 03
-
-The VALE switches and ports are created (and destroyed) on the fly.
-
-
-Transparent connection of physical ports to the VALE switch
------------------------------------------------------------
-
-It is also possible to use a network device as a port of a VALE
-switch. You can do this with the following command:
-
-    vale-ctl -h vale0:eth0  # attach interface "eth0" to the "vale0" switch
-
-To detach an interface from a bridge:
-
-    vale-ctl -d vale0:eth0  # detach interface "eth0" from the "vale0" switch
-
-These operations can be issued at any moment.
-
-
-Tests with our modified QEMU
-----------------------------
-
-The Linux image also contains our modified QEMU, with the VALE backend and
-the "e1000-paravirt" frontend (a paravirtualized e1000 emulation).
-
-After you have booted the image on a physical machine (so you can exploit
-KVM), you can boot the same image a second time (recursively) with QEMU.
-Therefore, you can run all the tests above also from within the virtual
-machine environment.
-
-To make VM testing easier, the home directory contains some
-some useful scripts to set up and launch VMs on the physical machine.
-
-+ "prep-taps.sh"
-  creates and sets up two permanent tap interfaces ("tap01" and "tap02")
-  and a Linux in-kernel bridge. The tap interfaces are then bridged
-  together on the same bridge. The bridge interface ("br0"), is given
-  the address 10.0.0.200/24.
-
-  This setup can be used to make two VMs communicate through the
-  host bridge, or to test the speed of a linux switch using
-  l2open
-
-+ "unprep-taps.sh"
-  undoes the above setup.
-
-+ "launch-qemu.sh"
-  can be used to run QEMU virtual machines. It takes four arguments:
-
-    + The first argument can be "qemu" or "kvm", depending on
-      whether we want to use the standard QEMU binary translation
-      or the hardware virtualization acceleration.
-
-    + The third argument can be "--tap", "--netuser" or "--vale",
-      and tells QEMU what network backend to use: a tap device,
-      the QEMU user networking (slirp), or a VALE switch port.
-
-    + When the third argument is "--tap" or "--vale", the fourth
-      argument specifies an index (e.g. "01", "02", etc..) which
-      tells QEMU what tap device or VALE port to use as backend.
-
-  You can manually modify the script to set the shell variables that
-  select the type of emulated device (e.g.  e1000, virtio-net-pci, ...)
-  and related options (ioeventfd, virtio vhost, e1000 mitigation, ....).
-
-  The default setup has an "e1000" device with interrupt mitigation
-  disabled.
-
-You can try the paravirtualized e1000 device ("e1000-paravirt")
-or the "virtio-net" device to get better performance. However, bear
-in mind that these paravirtualized devices don't have netmap support
-(whereas the standard e1000 does have netmap support).
-
-Examples:
-
-    # Run a kvm VM attached to the port 01 of a VALE switch
-    ./launch-qemu.sh kvm --vale 01
-
-    # Run a kvm VM attached to the port 02 of the same VALE switch
-    ./launch-qemu.sh kvm --vale 02
-
-    # Run a kvm VM attached to the tap called "tap01"
-    ./launch-qemu.sh kvm --tap 01
-
-    # Run a kvm VM attached to the tap called "tap02"
-    ./launch-qemu.sh kvm --tap 02
-
-
-Guest-to-guest tests
---------------------
-
-If you run two VMs attached to the same switch (which can be a Linux
-bridge or a VALE switch), you can run guest-to-guest experiments.
-
-All the tests reported in the previous sections are possible (normal
-sockets, raw sockets, pkt-gen, ...), indipendently of the backend used.
-
-In the following examples we assume that:
-
-    + Each VM has an ethernet interface called "eth0".
-
-    + The interface of the first VM is given the IP 10.0.0.1/24.
-
-    + The interface of the second VM is given the IP 10.0.0.2/24.
-
-    + The Linux bridge interface "br0" on the host is given the
-      IP 10.0.0.200/24.
-
-Examples:
-
-    [1] ### Test UDP short packets over traditional sockets ###
-        # On the guest 10.0.0.2 run
-            netserver
-        # on the guest 10.0.0.1 run
-            netperf -H10.0.0.2 -tUDP_STREAM -- -m8
-
-    [2] ### Test UDP short packets with pkt-gen ###
-        # On the guest 10.0.0.2 run
-            pkt-gen -ieth0 -frx
-        # On the guest 10.0.0.1 run
-            pkt-gen -ieth0 -ftx
-
-    [3] ### Test guest-to-guest latency ###
-        # On the guest 10.0.0.2 run
-            netserver
-        # On the guest 10.0.0.1 run
-            netperf -H10.0.0.2 -tTCP_RR
-
-Note that you can use pkt-gen into a VM only if the emulated ethernet
-device is supported by netmap. The default emulated device is
-"e1000", which has netmap support.  If you try to run pkt-gen on
-an unsupported device, pkt-gen will not work, reporting that it is
-unable to register the interface.
-
-
-Guest-to-host tests (follows from the previous section)
--------------------------------------------------------
-
-If you run only a VM on your host machine, you can measure the
-network performance between the VM and the host machine.  In this
-case the experiment setup depends on the backend you are using.
-
-With the tap backend, you can use the bridge interface "br0" as a
-communication endpoint. You can run normal/raw sockets experiments,
-but you cannot use pkt-gen on the "br0" interface, since the Linux
-bridge interface is not supported by netmap.
-
-Examples with the tap backend:
-
-    [1] ### Test TCP throughput over traditional sockets ###
-        # On the host run
-            netserver
-        # on the guest 10.0.0.1 run
-            netperf -H10.0.0.200 -tTCP_STREAM
-
-    [2] ### Test UDP short packets with pkt-gen and l2 ###
-        # On the host run
-            l2open -r br0 l2recv
-        # On the guest 10.0.0.1 run (xx:yy:zz:ww:uu:vv is the
-        # "br0" hardware address)
-            pkt-gen -ieth0 -ftx -d10.0.0.200:7777 -Dxx:yy:zz:ww:uu:vv
-
-
-With the VALE backend you can perform only UDP tests, since we don't have
-a netmap application which implements a TCP endpoint: pkt-gen generates
-UDP packets.
-As a communication endpoint on the host, you can use a virtual VALE port
-opened on the fly by a pkt-gen instance.
-
-Examples with the VALE backend:
-
-    [1] ### Test UDP short packets ###
-        # On the host run
-            pkt-gen -ivale0:99 -frx
-        # On the guest 10.0.0.1 run
-            pkt-gen -ieth0 -ftx
-
-    [2] ### Test UDP big packets (receiver on the guest) ###
-        # On the guest 10.0.0.1 run
-            pkt-gen -ieth0 -frx
-        # On the host run pkt-gen -ivale0:99 -ftx -l1460
-
diff --git a/README.ptnetmap b/README.ptnetmap
new file mode 100644
index 000000000..53e0b6ca9
--- /dev/null
+++ b/README.ptnetmap
@@ -0,0 +1,111 @@
+===========================================================================
+                        NETMAP PASSTHROUGH HOWTO
+===========================================================================
+
+This document describes how to configure netmap passthrough, a technology
+that enables very fast network I/O (up to 30 Mpps and more) for QEMU Virtual
+Machines.
+With netmap passthrough you can make an arbitrary netmap port (physical NIC,
+VALE port, pipe endpoint, monitor, ...) available inside a VM. In this way
+your (unmodified) netmap application can run isolated inside a VM, without
+losing the performance advantages of netmap. In particular you will still
+able to zerocopy across the passed-through netmap ports (a.k.a. ptnetmap
+ports).
+Netmap passthrough requires support in both host (hypervisor) and guest OS.
+Host needs a ptnetmap-capable hypervisor like QEMU (Linux host with KVM
+enabled) or bhyve (FreeBSD host). Guest OS requires some ptnetmap drivers that
+are already included with netmap, although not enabled by default.
+Guest OS ptnetmap drivers are available for both Linux and FreeBSD guests.
+
+Netmap passthrough is an enabler technology for Network Function
+Virtualization, as it can be used to build chains of VMs for high-rate
+middlebox packet processing. Given the variety
+of netmap ports you can decide to connect the VMs together through
+zerocopy ports (i.e. netmap pipes), or with copy for untrusted VMs
+(i.e. VALE ports). You can get NIC-independent NIC passthrough by
+directly passing a dedicated physical netmap port to a VM.
+
+More informations about ptnetmap are available in these slides:
+    * https://github.com/vmaffione/netmap-tutorial/blob/master/virtualization.pdf
+and these papers
+    * http://info.iet.unipi.it/~luigi/papers/20160613-ptnet.pdf
+    * http://info.iet.unipi.it/~luigi/papers/20150315-netmap-passthrough.pdf (older)
+
+---------------------------------------------------------------------------
+                Configure Linux host and QEMU for ptnetmap
+---------------------------------------------------------------------------
+
+On the Linux host, configure, build and install netmap with ptnetmap support:
+
+    $ git clone https://github.com/luigirizzo/netmap.git
+    $ cd netmap
+    $ ./configure --enable-ptnetmap [other options]
+    $ make
+    $ sudo make install
+
+Download, build and install the ptnetmap-enabled QEMU:
+
+    $ git clone https://github.com/vmaffione/qemu
+    $ ./configure --target-list=x86_64-softmmu --enable-kvm --enable-vhost-net --disable-werror --enable-netmap --enable-ptnetmap
+    $ make
+    $ sudo make install
+
+Load the ptnetmap-enabled netmap
+
+    $ sudo rmmod netmap  # Possibly remove a previous netmap module:
+    $ sudo modprobe netmap
+
+Example to run a VM passing through a VALE port (vale1:10):
+
+    $ sudo qemu-system-x86_64 img.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device ptnet-pci,netdev=data10,mac=00:AA:BB:CC:0a:0a -netdev netmap,ifname=vale1:10,id=data10,passthrough=on
+
+Example to run a VM passing though the "left" endpoints of two pipes endpoints
+(the "right" endpoints can be connected to other VMs or netmap programs running
+directly on the host.
+
+    $ sudo qemu-system-x86_64 img.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device ptnet-pci,netdev=data1,mac=00:AA:BB:CC:0b:01 -netdev netmap,ifname=netmap:pipe0{1,id=data1,passthrough=on -device ptnet-pci,netdev=data1,mac=00:AA:BB:CC:0b:02 -netdev netmap,ifname=netmap:pipe1{1,id=data1,passthrough=on
+
+
+---------------------------------------------------------------------------
+                Configure Linux guest for ptnetmap
+---------------------------------------------------------------------------
+
+In the Linux guest, compile, build and install netmap with ptnetmap support:
+
+    $ git clone https://github.com/luigirizzo/netmap.git
+    $ cd netmap
+    $ ./configure --enable-ptnetmap
+    $ make
+    $ sudo make install
+
+Load netmap module
+
+    $ sudo rmmod netmap  # Possibly remove a previous netmap module:
+    $ sudo modprobe netmap
+
+As the netmap module is loaded, a new network interface will show up for each
+passed-through netmap port, (e.g. 'ens4'). You can check that an interface is
+a netmap passthrough one checking the driver:
+
+    $ ethtool -i ens4
+    driver: ptnetmap-guest-drivers
+    version:
+    [...]
+
+A guest ptnetmap port behaves like any other netmap ports. You can use pkt-gen
+to test transmission;
+
+    $ sudo pkt-gen -i ens4 -f tx
+
+
+---------------------------------------------------------------------------
+                Use ptnetmap with FreeBSD guests
+---------------------------------------------------------------------------
+
+Netmap passthrough guest drivers are already included with netmap from FreeBSD
+12 versions. When running FreeBSD guest with ptnetmap ports (e.g. using QEMU as
+described above), an interface called "ptnet$N" will show up for each passed
+through port.
+If you want to use ptnetmap with older FreeBSD guests you can just update your
+FreeBSD source tree with the updated netmap code from github and rebuild your
+kernel.

From 06b978912b03b15ee6a3a97468d2f7b97b5d69d3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 20 Nov 2017 11:51:16 +0100
Subject: [PATCH 0235/2207] README.ptnetmap: add more information

---
 README.ptnetmap | 159 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 154 insertions(+), 5 deletions(-)

diff --git a/README.ptnetmap b/README.ptnetmap
index 53e0b6ca9..45678cbca 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap
@@ -2,6 +2,10 @@
                         NETMAP PASSTHROUGH HOWTO
 ===========================================================================
 
+---------------------------------------------------------------------------
+1. Introduction
+---------------------------------------------------------------------------
+
 This document describes how to configure netmap passthrough, a technology
 that enables very fast network I/O (up to 30 Mpps and more) for QEMU Virtual
 Machines.
@@ -25,14 +29,19 @@ zerocopy ports (i.e. netmap pipes), or with copy for untrusted VMs
 (i.e. VALE ports). You can get NIC-independent NIC passthrough by
 directly passing a dedicated physical netmap port to a VM.
 
-More informations about ptnetmap are available in these slides:
+More information about ptnetmap are available in these slides:
+
     * https://github.com/vmaffione/netmap-tutorial/blob/master/virtualization.pdf
-and these papers
+
+and in these papers
+
     * http://info.iet.unipi.it/~luigi/papers/20160613-ptnet.pdf
     * http://info.iet.unipi.it/~luigi/papers/20150315-netmap-passthrough.pdf (older)
 
+and in section 7 of this document.
+
 ---------------------------------------------------------------------------
-                Configure Linux host and QEMU for ptnetmap
+2. Configure Linux host and QEMU for ptnetmap
 ---------------------------------------------------------------------------
 
 On the Linux host, configure, build and install netmap with ptnetmap support:
@@ -67,7 +76,13 @@ directly on the host.
 
 
 ---------------------------------------------------------------------------
-                Configure Linux guest for ptnetmap
+3. Configure FreeBSD host and bhyve for ptnetmap
+---------------------------------------------------------------------------a
+TODO
+
+
+---------------------------------------------------------------------------
+4. Configure Linux guest for ptnetmap
 ---------------------------------------------------------------------------
 
 In the Linux guest, compile, build and install netmap with ptnetmap support:
@@ -99,7 +114,7 @@ to test transmission;
 
 
 ---------------------------------------------------------------------------
-                Use ptnetmap with FreeBSD guests
+5. Use ptnetmap with FreeBSD guests
 ---------------------------------------------------------------------------
 
 Netmap passthrough guest drivers are already included with netmap from FreeBSD
@@ -109,3 +124,137 @@ through port.
 If you want to use ptnetmap with older FreeBSD guests you can just update your
 FreeBSD source tree with the updated netmap code from github and rebuild your
 kernel.
+
+
+----------------------------------------------------------------------
+6. ptnetmap tunables
+----------------------------------------------------------------------
+
+By default ptnetmap uses dedicated host kernel threads to transmit and
+receive packets for the VM (i.e. to run NIOCTXSYNC and NIOCRXSYNC on
+the passed-through netmap ports). It is possible to disable TX kernel
+threads by setting the ptnetmap_tx_workers sysctl to zero on the host
+machine, e.g.
+
+    # echo 0 > /sys/module/netmap/parameters/ptnetmap_tx_workers
+
+so that transmissions are perfomed directly by the VM vCPU threads.
+Depending on your workload, disabling TX kernel threads can result to
+improved performance (throughput/latency) and/or improved CPU utilization.
+
+While ptnetmap is mainly designed for the VMs to run middleboxes applications
+(e.g. firewall, DDoS prevention, load balancing, IDS, typically carried out
+by network operators), it also offers good performance when VMs run TCP/UDP
+user applications. To make this possible, virtualized offloadings are
+supported using the virtio-net header defined by the VirtIO standard
+(http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-1680006).
+When the header is enabled in the guest OS and supported by the VM network
+backend (e.g. VALE port and TAP devices both support it), two VMs on the
+same host (e.g. connected through a VALE switch) can exchange TSO packets
+(up to 64KB each) without the need to perform any TCP segmentation or
+computing TCP checksums.
+This header is the key for very high TCP VM-to-VM throughput (20+ Gbps),
+and it is stored before the ethernet header of each packet sent or received
+by your VMs.
+If you want to use ptnetmap mainly to run middleboxes application (which
+is the common case), you should disable the virtio-net header in the guest
+OS:
+
+    # echo 0 > /sys/module/netmap/parameters/ptnet_vnet_hdr
+
+This step is needed to avoid performance issues in case your datapath exits the
+hypervisor host through a physical NIC or goes through netmap ports that don't
+support the virtio-net header.
+
+
+---------------------------------------------------------------------------
+7. Some background about ptnetmap
+---------------------------------------------------------------------------
+
+Netmap is a framework for high performance network I/O. It exposes an
+hardware-independent API which allows userspace application to directly interact
+with NIC hardware rings, in order to receive and transmit Ethernet frames.
+Rings are always accessed in the context of system calls and NIC interrups
+are used to notify applications about NIC processing completion.
+The performance boost of netmap w.r.t. traditional socket API primarily comes
+from: (i) batching, since it is possible to send/receive hundreds of packets
+with a single system call, (ii) preallocation of packet buffers and memory
+mapping of those in the application address space.
+
+Several netmap extension have been developed to support virtualization.
+Netmap support for various paravirtualized drivers - e.g. virtio-net, Xen
+netfront/netback - allows netmap applications to run in the guest over fast
+paravirtualized I/O devices.
+
+The Virtual Ethernet (VALE) software switch, which supports scalable high
+performance local communication (over 20 Mpps between two switch ports), can
+then be used to connect together multiple VMs.
+
+However, in a typical scenario with two communicating netmap applications
+running in different VMs (on the same host) connected through a VALE switch,
+the journey of a packet is still quite convoluted. As a matter of facts,
+while netmap is fast on both the host (the VALE switch) and the guest
+(interaction between application and the emulated device), each packet still
+needs to be processed from the hypervisor, which needs to emulate the
+device model used in the guest (e.g. e1000, virtio-net). The emulation
+involves device-specific overhead - queue processing, format conversions,
+packet copies, address translations, etc. As a consequence, the maximum
+packet rate between the two VMs is often limited by 2-5 Mpps.
+
+To overcome these limitations, ptnetmap has been introduced as a passthrough
+technique to completely avoid hypervisor processing in the packet
+datapath, unblocking the full potential of netmap also for virtual machine
+environments.
+With ptnetmap, a netmap port on the host can be exposed to the guest in a
+protected way, so that netmap applications in the guest can directly access
+the rings and packet buffers of the host port, avoiding all the extra overhead
+involved in the emulation of network devices. System calls issued by guest
+applications on ptnetmap ports are served by kernel threads (one
+per ring) running in the netmap host.
+
+Similarly to VirtIO paravirtualization, synchronization between
+guest netmap (driver) and host netmap (kernel threads) happens through a
+shared memory area called Communication Status Block (CSB), which is used
+to store producer-consumer state and notification suppression flags.
+
+Two notification mechanisms needs to be supported by the hypervisor to allow
+guest and host netmap to wake up each other.
+On QEMU/bhyve, notifications from guest to host are implemented with accesses
+to I/O registers which cause a trap in the hypervisor. Notifications in the
+other direction are implemented using KVM/bhyve interrupt injection mechanisms.
+MSI-X interrupts are used since they have less overhead than traditional
+PCI interrupts.
+
+Since I/O register accesses and interrupts are very expensive in the common
+case of hardware assisted virtualization, they are suppressed when not needed,
+i.e. each time the host (or the guest) is actively polling the CSB to
+check for more work. From an high-level perspective, the system tries to
+dynamically switch between polling operation under high load, and
+interrupt-based operation under lower loads.
+
+The original ptnetmap implementation required ptnetmap-enabled virtio-net/e1000
+drivers. Only the notification functionalities of those devices were reused,
+while the datapath (e.g. e1000 rings or virtio-net Virtual Queues) was
+completely bypassed.
+
+The ptnet device has been introduced as a cleaner approach to ptnetmap that
+also adds the ability to interact with the standard TCP/IP network stack
+and supports multi-ring netmap ports. The introduction of a new device model
+does not limit the adoption of this solution, since ptnet drivers are
+distributed together with netmap, and hypervisor modifications are needed in
+any case.
+
+The ptnet device belongs to the classes of paravirtualized devices, like
+virtio-net. Unlike virtio-net, however, ptnet does not define an interface
+to exchange packets (datapath), but the existing netmap API is used instead.
+However, a CSB - cleaned up and extended to support an arbitrary number of
+rings - is still used for producer-consumer synchronization and notification
+suppression.
+
+A number of device registers are used for configuration (number of rings and
+slots, device MAC address, supported features, ...) while "kick" registers
+are used for guest-to-host notifications.
+The ptnetmap kthread infrastructure, moreover, has been already extended to
+suppor an arbitrary number of rings, where currently each ring is served
+by a different kernel thread.
+

From 79d8182505c064b1634977efbc67f7d944578db1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 20 Nov 2017 11:53:26 +0100
Subject: [PATCH 0236/2207] README: add pointer to netmap tutorial

---
 README | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README b/README
index 26ea36a90..58260b75b 100644
--- a/README
+++ b/README
@@ -16,6 +16,8 @@ This repository, hosted at https://github.com/luigirizzo/netmap , contains
 source code (BSD-Copyright) for FreeBSD, Linux and Windows.
 Note that recent FreeBSD distributions already include both NETMAP and VALE.
 
+A netmap tutorial is avaliable at https://github.com/vmaffione/netmap-tutorial.
+
 
 What is this good for
 ---------------------

From 50cbee911ef9071084c08ee6133ad9a77588d088 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 20 Nov 2017 11:56:31 +0100
Subject: [PATCH 0237/2207] README.ptnetmap: fix typo

---
 README.ptnetmap | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.ptnetmap b/README.ptnetmap
index 45678cbca..c082c4440 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap
@@ -77,7 +77,7 @@ directly on the host.
 
 ---------------------------------------------------------------------------
 3. Configure FreeBSD host and bhyve for ptnetmap
----------------------------------------------------------------------------a
+---------------------------------------------------------------------------
 TODO
 
 

From 788f25dcc48dfec2e481573277b662968f690042 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 23 Nov 2017 15:14:20 +0100
Subject: [PATCH 0238/2207] vale: fix performance issue on the mismatch
 datapath

This was due to uninitialized vpna->mfs (left to 0).
---
 sys/dev/netmap/netmap_vale.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 786d599fe..5fb4dcbe6 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -148,6 +148,8 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #define NM_BDG_BATCH_MAX	(NM_BDG_BATCH + NM_MULTISEG)
 /* NM_FT_NULL terminates a list of slots in the ft */
 #define NM_FT_NULL		NM_BDG_BATCH_MAX
+/* Default size for the Maximum Frame Size. */
+#define NM_BDG_MFS_DEFAULT	1514
 
 
 /*
@@ -738,7 +740,6 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 	for (j = 0; j < b->bdg_active_ports; j++) {
 		i = b->bdg_port_index[j];
 		vpna = b->bdg_ports[i];
-		// KASSERT(na != NULL);
 		ND("checking %s", vpna->up.name);
 		if (!strcmp(vpna->up.name, nr_name)) {
 			netmap_adapter_get(&vpna->up);
@@ -1910,6 +1911,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 				 * TCPv4 we must account for ethernet header, IP header
 				 * and TCPv4 header).
 				 */
+				KASSERT(dst_na->mfs > 0, ("vpna->mfs is 0"));
 				needed = (needed * na->mfs) /
 						(dst_na->mfs - WORST_CASE_GSO_HEADER) + 1;
 				ND(3, "srcmtu=%u, dstmtu=%u, x=%u", na->mfs, dst_na->mfs, needed);
@@ -2259,7 +2261,10 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
 	nm_bound_var(&nmr->nr_arg3, 0, 0,
 			128*NM_BDG_MAXSLOTS, NULL);
 	na->num_rx_desc = nmr->nr_rx_slots;
-	vpna->mfs = 1514;
+	/* Set the mfs to a default value, as it is needed on the VALE
+	 * mismatch datapath. XXX We should set it according to the MTU
+	 * known to the kernel. */
+	vpna->mfs = NM_BDG_MFS_DEFAULT;
 	vpna->last_smac = ~0llu;
 	/*if (vpna->mfs > netmap_buf_size)  TODO netmap_buf_size is zero??
 		vpna->mfs = netmap_buf_size; */
@@ -2809,6 +2814,8 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	na->nm_mem = netmap_mem_get(hwna->nm_mem);
 	na->virt_hdr_len = hwna->virt_hdr_len;
 	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
+	/* Set the mfs, needed on the VALE mismatch datapath. */
+	bna->up.mfs = NM_BDG_MFS_DEFAULT;
 
 	bna->hwna = hwna;
 	netmap_adapter_get(hwna);
@@ -2836,6 +2843,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		na->na_hostvp = hwna->na_hostvp =
 			hostna->na_hostvp = &bna->host;
 		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
+		bna->host.mfs = NM_BDG_MFS_DEFAULT;
 	}
 
 	ND("%s<->%s txr %d txd %d rxr %d rxd %d",

From d00cf60bdc0982e895a0a8c715adf2dd403f34a0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 24 Nov 2017 11:58:15 +0100
Subject: [PATCH 0239/2207] vale: offloadings: reduce rate-limited logging

---
 sys/dev/netmap/netmap_offloadings.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index 8e5de7f7a..3ebd975bf 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -168,7 +168,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 	u_int dst_slots = 0;
 
 	if (unlikely(ft_p == ft_end)) {
-		RD(3, "No source slots to process");
+		RD(1, "No source slots to process");
 		return;
 	}
 
@@ -187,11 +187,11 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 		/* Initial sanity check on the source virtio-net header. If
 		 * something seems wrong, just drop the packet. */
 		if (src_len < na->up.virt_hdr_len) {
-			RD(3, "Short src vnet header, dropping");
+			RD(1, "Short src vnet header, dropping");
 			return;
 		}
 		if (vnet_hdr_is_bad(vh)) {
-			RD(3, "Bad src vnet header, dropping");
+			RD(1, "Bad src vnet header, dropping");
 			return;
 		}
 	}
@@ -264,7 +264,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 			if (dst_slots >= *howmany) {
 				/* We still have work to do, but we've run out of
 				 * dst slots, so we have to drop the packet. */
-				RD(3, "Not enough slots, dropping GSO packet");
+				ND(1, "Not enough slots, dropping GSO packet");
 				return;
 			}
 
@@ -279,7 +279,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 				 * encapsulation. */
 				for (;;) {
 					if (src_len < ethhlen) {
-						RD(3, "Short GSO fragment [eth], dropping");
+						RD(1, "Short GSO fragment [eth], dropping");
 						return;
 					}
 					ethertype = be16toh(*((uint16_t *)
@@ -295,7 +295,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 									(gso_hdr + ethhlen);
 
 						if (src_len < ethhlen + 20) {
-							RD(3, "Short GSO fragment "
+							RD(1, "Short GSO fragment "
 							      "[IPv4], dropping");
 							return;
 						}
@@ -308,14 +308,14 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 						iphlen = 40;
 						break;
 					default:
-						RD(3, "Unsupported ethertype, "
+						RD(1, "Unsupported ethertype, "
 						      "dropping GSO packet");
 						return;
 				}
 				ND(3, "type=%04x", ethertype);
 
 				if (src_len < ethhlen + iphlen) {
-					RD(3, "Short GSO fragment [IP], dropping");
+					RD(1, "Short GSO fragment [IP], dropping");
 					return;
 				}
 
@@ -327,7 +327,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 								(gso_hdr + ethhlen + iphlen);
 
 					if (src_len < ethhlen + iphlen + 20) {
-						RD(3, "Short GSO fragment "
+						RD(1, "Short GSO fragment "
 								"[TCP], dropping");
 						return;
 					}
@@ -338,7 +338,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 				}
 
 				if (src_len < gso_hdr_len) {
-					RD(3, "Short GSO fragment [TCP/UDP], dropping");
+					RD(1, "Short GSO fragment [TCP/UDP], dropping");
 					return;
 				}
 

From a6e8e7b94f44f1dc0339adb2ffb0360470b97bc5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 24 Nov 2017 12:00:30 +0100
Subject: [PATCH 0240/2207] vale: offloadings: make vnet_hdr_is_bad() inline

---
 sys/dev/netmap/netmap_offloadings.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index 3ebd975bf..d16ca1e85 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -130,7 +130,7 @@ gso_fix_segment(uint8_t *pkt, size_t len, u_int ipv4, u_int iphlen, u_int tcp,
 	ND("TCP/UDP csum %x", be16toh(*check));
 }
 
-static int
+static inline int
 vnet_hdr_is_bad(struct nm_vnet_hdr *vh)
 {
 	uint8_t gso_type = vh->gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
@@ -190,7 +190,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 			RD(1, "Short src vnet header, dropping");
 			return;
 		}
-		if (vnet_hdr_is_bad(vh)) {
+		if (unlikely(vnet_hdr_is_bad(vh))) {
 			RD(1, "Bad src vnet header, dropping");
 			return;
 		}

From b439c7da3d887940d8b3a0d90b0147d2bca1ec9c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 Nov 2017 10:58:55 +0100
Subject: [PATCH 0241/2207] pipe: improved fasth path

---
 sys/dev/netmap/netmap_pipe.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 36f5a3c9d..0230e3261 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -180,6 +180,7 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
         u_int j, k, lim_tx = txkring->nkr_num_slots - 1,
                 lim_rx = rxkring->nkr_num_slots - 1;
         int m, busy;
+	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
         ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
         ND(2, "before: hwcur %d hwtail %d cur %d head %d tail %d", txkring->nr_hwcur, txkring->nr_hwtail,
@@ -206,18 +207,18 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 	}
 
         while (limit-- > 0) {
-                struct netmap_slot *rs = &rxkring->ring->slot[j];
-                struct netmap_slot *ts = &txkring->ring->slot[k];
+                struct netmap_slot *rs = &rxring->slot[j];
+                struct netmap_slot *ts = &txring->slot[k];
                 struct netmap_slot tmp;
 
-                /* swap the slots */
+		prefetch(ts + 1);
+
+                /* swap the slots and report the buffer change */
                 tmp = *rs;
                 *rs = *ts;
+		rs->flags |= NS_BUF_CHANGED;
                 *ts = tmp;
-
-                /* report the buffer change */
 		ts->flags |= NS_BUF_CHANGED;
-		rs->flags |= NS_BUF_CHANGED;
 
                 j = nm_next(j, lim_rx);
                 k = nm_next(k, lim_tx);

From 2213d899978fc62612c480d52a9559d4f1a359b4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 16:12:04 +0100
Subject: [PATCH 0242/2207] travis: take linux code from release tarballs

---
 .travis.yml    | 20 --------------------
 ci/build-linux | 26 +++++---------------------
 2 files changed, 5 insertions(+), 41 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 21dbd0a76..3c56bd0f3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,32 +1,12 @@
 dist: trusty
 sudo: false
 language: c
-cache:
-  directories:
-    - $HOME/Linux
-    - $HOME/Drivers
 env:
-  - KERNEL_VERSION=3.2   ARCH=i386
-  - KERNEL_VERSION=3.4   ARCH=i386
-  - KERNEL_VERSION=3.10  ARCH=i386
-  - KERNEL_VERSION=3.16  ARCH=i386
   - KERNEL_VERSION=4.1   ARCH=i386
   - KERNEL_VERSION=4.4   ARCH=i386
   - KERNEL_VERSION=4.9   ARCH=i386
-  - KERNEL_VERSION=linus ARCH=i386
-  - KERNEL_VERSION=3.2   ARCH=x86_64
-  - KERNEL_VERSION=3.4   ARCH=x86_64
-  - KERNEL_VERSION=3.10  ARCH=x86_64
-  - KERNEL_VERSION=3.16  ARCH=x86_64
   - KERNEL_VERSION=4.1   ARCH=x86_64
   - KERNEL_VERSION=4.4   ARCH=x86_64
   - KERNEL_VERSION=4.9   ARCH=x86_64
-  - KERNEL_VERSION=linus ARCH=x86_64
-matrix:
-  allow_failures:
-    - env: KERNEL_VERSION=linus ARCH=i386
-    - env: KERNEL_VERSION=linus ARCH=x86_64
-install:
-  - "rm -Rf LINUX/ext-drivers && mkdir -p $HOME/Drivers && ln -sv $HOME/Drivers LINUX/ext-drivers"
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"
diff --git a/ci/build-linux b/ci/build-linux
index 1923c9f52..ecbc6096f 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -8,28 +8,12 @@ readonly GCC_MAJOR_VERSION=$(echo '#include 
 void main() { printf("%u\n", __GNUC__); }' | gcc -x c - -o /tmp/getgccversion  && /tmp/getgccversion)
 readonly PROC_COUNT=$(grep -c '^processor' /proc/cpuinfo)
 
-
-if [ ! -d ~/Linux/$KERNEL_VERSION ]
-then
-  # clone
-  if [ "$KERNEL_VERSION" = "linus" ]
-  then
-    git clone 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git' ~/Linux/$KERNEL_VERSION
-  else
-    git clone 'https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git' ~/Linux/$KERNEL_VERSION
-    pushd ~/Linux/$KERNEL_VERSION
-    git checkout linux-${KERNEL_VERSION}.y
-    popd
-  fi
-else
-  # update
-  pushd ~/Linux/$KERNEL_VERSION
-  git pull
-  popd
-fi
+# fetch the code
+wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-${KERNEL_VERSION}.tar.gz
+tar xzf linux-${KERNEL_VERSION}.tar.gz
 
 # configure kernel
-pushd ~/Linux/$KERNEL_VERSION
+pushd linux-${KERNEL_VERSION}
 compiler_file=compiler-gcc${GCC_MAJOR_VERSION}.h
 if [ ! -f include/linux/${compiler_file} -a ! -h include/linux/${compiler_file} ]
 then
@@ -49,5 +33,5 @@ make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
 # build
-./configure --kernel-dir=$HOME/Linux/$KERNEL_VERSION
+./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION}
 make -j $PROC_COUNT

From ac2e646fa68e5530488130d818bdb48479d483e3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 16:21:14 +0100
Subject: [PATCH 0243/2207] travis: add support for 3.x kernels

---
 .travis.yml    | 10 +++++++---
 ci/build-linux |  2 +-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 3c56bd0f3..f8469ecc0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,11 +2,15 @@ dist: trusty
 sudo: false
 language: c
 env:
-  - KERNEL_VERSION=4.1   ARCH=i386
-  - KERNEL_VERSION=4.4   ARCH=i386
-  - KERNEL_VERSION=4.9   ARCH=i386
+  - KERNEL_VERSION=3.10  ARCH=x86_64
+  - KERNEL_VERSION=3.16  ARCH=x86_64
   - KERNEL_VERSION=4.1   ARCH=x86_64
   - KERNEL_VERSION=4.4   ARCH=x86_64
   - KERNEL_VERSION=4.9   ARCH=x86_64
+  - KERNEL_VERSION=4.1   ARCH=i386
+  - KERNEL_VERSION=4.4   ARCH=i386
+  - KERNEL_VERSION=4.9   ARCH=i386
+  - KERNEL_VERSION=3.10  ARCH=i386
+  - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"
diff --git a/ci/build-linux b/ci/build-linux
index ecbc6096f..c8089b7aa 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -9,7 +9,7 @@ void main() { printf("%u\n", __GNUC__); }' | gcc -x c - -o /tmp/getgccversion  &
 readonly PROC_COUNT=$(grep -c '^processor' /proc/cpuinfo)
 
 # fetch the code
-wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-${KERNEL_VERSION}.tar.gz
+wget https://www.kernel.org/pub/linux/kernel/v${KERNEL_VERSION:0:1}.x/linux-${KERNEL_VERSION}.tar.gz
 tar xzf linux-${KERNEL_VERSION}.tar.gz
 
 # configure kernel

From 9f20d7e16e91f1f3b7fdc7ef7038198c7494177c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 16:26:53 +0100
Subject: [PATCH 0244/2207] travis: enable ptnetmap in the test builds

---
 ci/build-linux | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index c8089b7aa..0fb3ee970 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -33,5 +33,5 @@ make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
 # build
-./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION}
+./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --enable-ptnetmap
 make -j $PROC_COUNT

From 1381353cfd8156de8e958ce1871137c3f0938eab Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 16:36:28 +0100
Subject: [PATCH 0245/2207] travis: add all 3.x and 4.x versions

---
 .travis.yml | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index f8469ecc0..c81acd4bd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,15 +2,40 @@ dist: trusty
 sudo: false
 language: c
 env:
+  - KERNEL_VERSION=3.0   ARCH=x86_64
+  - KERNEL_VERSION=3.1   ARCH=x86_64
+  - KERNEL_VERSION=3.2   ARCH=x86_64
+  - KERNEL_VERSION=3.3   ARCH=x86_64
+  - KERNEL_VERSION=3.4   ARCH=x86_64
+  - KERNEL_VERSION=3.5   ARCH=x86_64
+  - KERNEL_VERSION=3.6   ARCH=x86_64
+  - KERNEL_VERSION=3.7   ARCH=x86_64
+  - KERNEL_VERSION=3.8   ARCH=x86_64
+  - KERNEL_VERSION=3.9   ARCH=x86_64
   - KERNEL_VERSION=3.10  ARCH=x86_64
+  - KERNEL_VERSION=3.11  ARCH=x86_64
+  - KERNEL_VERSION=3.12  ARCH=x86_64
+  - KERNEL_VERSION=3.13  ARCH=x86_64
+  - KERNEL_VERSION=3.14  ARCH=x86_64
+  - KERNEL_VERSION=3.15  ARCH=x86_64
   - KERNEL_VERSION=3.16  ARCH=x86_64
+  - KERNEL_VERSION=3.17  ARCH=x86_64
+  - KERNEL_VERSION=3.18  ARCH=x86_64
+  - KERNEL_VERSION=3.19  ARCH=x86_64
+  - KERNEL_VERSION=4.0   ARCH=x86_64
   - KERNEL_VERSION=4.1   ARCH=x86_64
+  - KERNEL_VERSION=4.2   ARCH=x86_64
+  - KERNEL_VERSION=4.3   ARCH=x86_64
   - KERNEL_VERSION=4.4   ARCH=x86_64
+  - KERNEL_VERSION=4.5   ARCH=x86_64
+  - KERNEL_VERSION=4.6   ARCH=x86_64
+  - KERNEL_VERSION=4.7   ARCH=x86_64
+  - KERNEL_VERSION=4.8   ARCH=x86_64
   - KERNEL_VERSION=4.9   ARCH=x86_64
-  - KERNEL_VERSION=4.1   ARCH=i386
-  - KERNEL_VERSION=4.4   ARCH=i386
-  - KERNEL_VERSION=4.9   ARCH=i386
-  - KERNEL_VERSION=3.10  ARCH=i386
+  - KERNEL_VERSION=4.10  ARCH=x86_64
+  - KERNEL_VERSION=4.11  ARCH=x86_64
+  - KERNEL_VERSION=4.12  ARCH=x86_64
+  - KERNEL_VERSION=4.13  ARCH=x86_64
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"

From 74a3ef40fcd5fb5351fbd77a55bb1162154e2ebf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 16:54:13 +0100
Subject: [PATCH 0246/2207] travis: switch to a VM environment, add placeholder
 for integration tests

---
 .travis.yml              |  3 ++-
 ci/build-linux           | 10 ++++++----
 ci/run-integration-tests |  6 ++++++
 3 files changed, 14 insertions(+), 5 deletions(-)
 create mode 100755 ci/run-integration-tests

diff --git a/.travis.yml b/.travis.yml
index c81acd4bd..cad15e620 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
 dist: trusty
-sudo: false
+sudo: required
 language: c
 env:
   - KERNEL_VERSION=3.0   ARCH=x86_64
@@ -39,3 +39,4 @@ env:
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"
+  - "./ci/run-integration-tests"
diff --git a/ci/build-linux b/ci/build-linux
index 0fb3ee970..901c152fe 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -8,16 +8,16 @@ readonly GCC_MAJOR_VERSION=$(echo '#include 
 void main() { printf("%u\n", __GNUC__); }' | gcc -x c - -o /tmp/getgccversion  && /tmp/getgccversion)
 readonly PROC_COUNT=$(grep -c '^processor' /proc/cpuinfo)
 
-# fetch the code
+# Fetch the kernel code
 wget https://www.kernel.org/pub/linux/kernel/v${KERNEL_VERSION:0:1}.x/linux-${KERNEL_VERSION}.tar.gz
 tar xzf linux-${KERNEL_VERSION}.tar.gz
 
-# configure kernel
+# Configure kernel
 pushd linux-${KERNEL_VERSION}
 compiler_file=compiler-gcc${GCC_MAJOR_VERSION}.h
 if [ ! -f include/linux/${compiler_file} -a ! -h include/linux/${compiler_file} ]
 then
-  # fix compilation of old kernels with recent GCC
+  # Fix compilation of old kernels with recent GCC
   pushd include/linux
   if [ -f compiler-gcc5.h -a $GCC_MAJOR_VERSION -gt 5 ]
   then
@@ -32,6 +32,8 @@ make -j $PROC_COUNT ARCH=${ARCH} defconfig
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
-# build
+# Build and install
 ./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --enable-ptnetmap
 make -j $PROC_COUNT
+sudo make install
+depmod -a
diff --git a/ci/run-integration-tests b/ci/run-integration-tests
new file mode 100755
index 000000000..3d51146fb
--- /dev/null
+++ b/ci/run-integration-tests
@@ -0,0 +1,6 @@
+#!/bin/bash -eu
+
+sudo modprobe netmap
+sudo pkt-gen -i vale:x -f tx -n 100 -w0
+sudo pkt-gen -i netmap:pipe{3 -f tx -n 65 -w0
+sudo rmmod netmap

From 1d58210ee18a9d49d54cd29bbac66fc1a98f9d95 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 17:01:31 +0100
Subject: [PATCH 0247/2207] pkt-gen: return error code on failure

---
 apps/pkt-gen/pkt-gen.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index c1bfce298..4b9f143f1 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -71,7 +71,7 @@
 
 #include "ctrs.h"
 
-static void usage(void);
+static void usage(int);
 
 #ifdef _WIN32
 #define cpuset_t        DWORD_PTR   //uint64_t
@@ -410,7 +410,7 @@ extract_ip_range(struct ip_range *r, int af)
 	name = strdup(r->name);
 	if (name == NULL) {
 		D("strdup failed");
-		usage();
+		usage(-1);
 	}
 	/* the first - splits start/end of range */
 	ap = strchr(name, '-');
@@ -2257,7 +2257,7 @@ tx_output(struct my_ctrs *cur, double delta, const char *msg)
 }
 
 static void
-usage(void)
+usage(int errcode)
 {
 	const char *cmd = "pkt-gen";
 	fprintf(stderr,
@@ -2329,7 +2329,7 @@ usage(void)
 		     "\t-m			ignored\n"
 		     "",
 		cmd);
-	exit(0);
+	exit(errcode);
 }
 
 enum {
@@ -2668,14 +2668,17 @@ main(int arc, char **argv)
 	g.wait_link = 2;
 
 	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
-	    "T:w:WvR:XC:H:e:E:m:rP:zZA")) != -1) {
+	    "T:w:WvR:XC:H:e:E:m:rP:zZAh")) != -1) {
 
 		switch(ch) {
 		default:
 			D("bad option %c %s", ch, optarg);
-			usage();
+			usage(-1);
 			break;
 
+                case 'h':
+                        usage(0);
+                        break;
 		case '4':
 			g.af = AF_INET;
 			break;
@@ -2846,7 +2849,7 @@ main(int arc, char **argv)
 
 	if (strlen(g.ifname) <=0 ) {
 		D("missing ifname");
-		usage();
+		usage(-1);
 	}
 
 	if (g.burst == 0) {
@@ -2857,7 +2860,7 @@ main(int arc, char **argv)
 	g.system_cpus = i = system_ncpus();
 	if (g.cpus < 0 || g.cpus > i) {
 		D("%d cpus is too high, have only %d cpus", g.cpus, i);
-		usage();
+		usage(-1);
 	}
 	D("running on %d cpus (have %d)", g.cpus, i);
 	if (g.cpus == 0)
@@ -2865,12 +2868,12 @@ main(int arc, char **argv)
 
 	if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) {
 		D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE);
-		usage();
+		usage(-1);
 	}
 
 	if (g.pkt_min_size > 0 && (g.pkt_min_size < 16 || g.pkt_min_size > g.pkt_size)) {
 		D("bad pktminsize %d [16..%d]\n", g.pkt_min_size, g.pkt_size);
-		usage();
+		usage(-1);
 	}
 
 	if (g.src_mac.name == NULL) {
@@ -2884,14 +2887,14 @@ main(int arc, char **argv)
 	}
 	/* extract address ranges */
 	if (extract_mac_range(&g.src_mac) || extract_mac_range(&g.dst_mac))
-		usage();
+		usage(-1);
 	g.options |= extract_ip_range(&g.src_ip, g.af);
 	g.options |= extract_ip_range(&g.dst_ip, g.af);
 
 	if (g.virt_header != 0 && g.virt_header != VIRT_HDR_1
 			&& g.virt_header != VIRT_HDR_2) {
 		D("bad virtio-net-header length");
-		usage();
+		usage(-1);
 	}
 
     if (g.dev_type == DEV_TAP) {
@@ -2899,7 +2902,7 @@ main(int arc, char **argv)
 	g.main_fd = tap_alloc(g.ifname);
 	if (g.main_fd < 0) {
 		D("cannot open tap %s", g.ifname);
-		usage();
+		usage(-1);
 	}
 #ifndef NO_PCAP
     } else if (g.dev_type == DEV_PCAP) {
@@ -2909,7 +2912,7 @@ main(int arc, char **argv)
 	g.p = pcap_open_live(g.ifname, 256 /* XXX */, 1, 100, pcap_errbuf);
 	if (g.p == NULL) {
 		D("cannot open pcap on %s", g.ifname);
-		usage();
+		usage(-1);
 	}
 	g.main_fd = pcap_fileno(g.p);
 	D("using pcap on %s fileno %d", g.ifname, g.main_fd);
@@ -3021,7 +3024,7 @@ main(int arc, char **argv)
 	/* Exit if something went wrong. */
 	if (g.main_fd < 0) {
 		D("aborting");
-		usage();
+		usage(-1);
 	}
     }
 

From bd020e1652ceed04cf7aa63f46e43119c05a94f1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 17:03:09 +0100
Subject: [PATCH 0248/2207] travis: build: add missing sudo on depmod command

---
 ci/build-linux | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 901c152fe..1add1c6e8 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -36,4 +36,4 @@ popd
 ./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --enable-ptnetmap
 make -j $PROC_COUNT
 sudo make install
-depmod -a
+sudo depmod -a

From 3c67cf20635b616ee30bf9b394244994afd6363f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 17:14:43 +0100
Subject: [PATCH 0249/2207] apps: vale-ctl: add usage() function

---
 apps/pkt-gen/pkt-gen.c   |  2 +-
 apps/vale-ctl/vale-ctl.c | 52 ++++++++++++++++++++--------------------
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 4b9f143f1..d821b3921 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1803,7 +1803,7 @@ receiver_body(void *data)
 
 			m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes);
 			cur.pkts += m;
-			if (m > 0) //XXX-ste: can m be 0?
+			if (m > 0)
 				cur.events++;
 		}
 		cur.min_space = targ->ctr.min_space;
diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index 500429a21..0b12abfae 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -196,44 +196,44 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2)
 	return error;
 }
 
+static void
+usage(int errcode)
+{
+    fprintf(stderr,
+            "Usage:\n"
+            "vale-ctl arguments\n"
+            "\t-g interface	interface name to get info\n"
+            "\t-d interface	interface name to be detached\n"
+            "\t-a interface	interface name to be attached\n"
+            "\t-h interface	interface name to be attached with the host stack\n"
+            "\t-n interface	interface name to be created\n"
+            "\t-r interface	interface name to be deleted\n"
+            "\t-l list all or specified bridge's interfaces (default)\n"
+            "\t-C string ring/slot setting of an interface creating by -n\n"
+            "\t-p interface start polling. Additional -C x,y,z configures\n"
+            "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n"
+            "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n"
+            "\t\t z: (ONE_NIC only) num of total cores/rings\n"
+            "\t-P interface stop polling\n"
+            "\t-m memid to use when creating a new interface\n");
+    exit(errcode);
+}
+
 int
 main(int argc, char *argv[])
 {
 	int ch, nr_cmd = 0, nr_arg = 0;
-	const char *command = basename(argv[0]);
 	char *name = NULL, *nmr_config = NULL;
 	int nr_arg2 = 0;
 
-	if (argc > 5) {
-usage:
-		fprintf(stderr,
-			"Usage:\n"
-			"%s arguments\n"
-			"\t-g interface	interface name to get info\n"
-			"\t-d interface	interface name to be detached\n"
-			"\t-a interface	interface name to be attached\n"
-			"\t-h interface	interface name to be attached with the host stack\n"
-			"\t-n interface	interface name to be created\n"
-			"\t-r interface	interface name to be deleted\n"
-			"\t-l list all or specified bridge's interfaces (default)\n"
-			"\t-C string ring/slot setting of an interface creating by -n\n"
-			"\t-p interface start polling. Additional -C x,y,z configures\n"
-			"\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n"
-			"\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n"
-			"\t\t z: (ONE_NIC only) num of total cores/rings\n"
-			"\t-P interface stop polling\n"
-			"\t-m memid to use when creating a new interface\n"
-			"", command);
-		return 0;
-	}
-
 	while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:")) != -1) {
 		if (ch != 'C' && ch != 'm')
 			name = optarg; /* default */
 		switch (ch) {
 		default:
 			fprintf(stderr, "bad option %c %s", ch, optarg);
-			goto usage;
+			usage(-1);
+			break;
 		case 'd':
 			nr_cmd = NETMAP_BDG_DETACH;
 			break;
@@ -272,7 +272,7 @@ main(int argc, char *argv[])
 	}
 	if (optind != argc) {
 		// fprintf(stderr, "optind %d argc %d\n", optind, argc);
-		goto usage;
+		usage(-1);
 	}
 	if (argc == 1) {
 		nr_cmd = NETMAP_BDG_LIST;

From 0456f3417258b63ffd651d98463434ad0f2b7f0a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 17:23:57 +0100
Subject: [PATCH 0250/2207] travis: enable integration tests for local kernel
 only

---
 .travis.yml    |  3 ++-
 ci/build-linux | 12 ++++++++++--
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index cad15e620..c2fc69a9d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@ dist: trusty
 sudo: required
 language: c
 env:
+  - KERNEL_VERSION=local ARCH=x86_64
   - KERNEL_VERSION=3.0   ARCH=x86_64
   - KERNEL_VERSION=3.1   ARCH=x86_64
   - KERNEL_VERSION=3.2   ARCH=x86_64
@@ -39,4 +40,4 @@ env:
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"
-  - "./ci/run-integration-tests"
+  - "[ ${KERNEL_VERSION} != local ] || ./ci/run-integration-tests"
diff --git a/ci/build-linux b/ci/build-linux
index 1add1c6e8..c1f505d1c 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -8,6 +8,16 @@ readonly GCC_MAJOR_VERSION=$(echo '#include 
 void main() { printf("%u\n", __GNUC__); }' | gcc -x c - -o /tmp/getgccversion  && /tmp/getgccversion)
 readonly PROC_COUNT=$(grep -c '^processor' /proc/cpuinfo)
 
+if [ ${KERNEL_VERSION} == "local" ]; then
+    sudo apt-get -qq update
+    sudo apt-get install -y linux-headers-$(uname -r)
+    ./configure --no-drivers
+    make -j $PROC_COUNT
+    sudo make install
+    sudo depmod -a
+    exit 0
+fi
+
 # Fetch the kernel code
 wget https://www.kernel.org/pub/linux/kernel/v${KERNEL_VERSION:0:1}.x/linux-${KERNEL_VERSION}.tar.gz
 tar xzf linux-${KERNEL_VERSION}.tar.gz
@@ -35,5 +45,3 @@ popd
 # Build and install
 ./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --enable-ptnetmap
 make -j $PROC_COUNT
-sudo make install
-sudo depmod -a

From 3774938debb48b6bc98d5124f719903de443e3ce Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 18:11:57 +0100
Subject: [PATCH 0251/2207] utils: testmmap: fix compilation issue

---
 utils/testmmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d08e734cf..7ec1ee6aa 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -80,7 +80,7 @@ void resetvar(int v, char *b)
 
 #define output_err(ret, format, args...)\
 	do {\
-		if (ret < 0) {\
+		if ((ret) < 0) {\
 			resetvar(curr_var, VAR_FAILED);\
 			outecho(format, ##args);\
 			outecho("error: %s", strerror(errno));\

From d69e3050aa46335f6b5bc40b114f26e14a9efbdf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Nov 2017 18:36:15 +0100
Subject: [PATCH 0252/2207] add clang-format support for files not in the
 FreeBSD repo

---
 .clang-format       | 11 +++++++++++
 LINUX/netmap.mak.in |  3 +++
 2 files changed, 14 insertions(+)
 create mode 100644 .clang-format

diff --git a/.clang-format b/.clang-format
new file mode 100644
index 000000000..75ada3d24
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: LLVM
+AllowShortIfStatementsOnASingleLine: false
+AlignConsecutiveAssignments: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: TopLevelDefinitions
+BreakBeforeBraces: Linux
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+IndentCaseLabels: false
+IndentWidth: 8
+UseTab: Always
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index d853880a4..0adaf63bf 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -146,3 +146,6 @@ distclean: clean $(S_DRIVERS:%=distclean-%)
 	if [ -L drv-subdir.mak ]; then rm drv-subdir.mak; fi
 	if [ -L read-vars.mak ]; then rm read-vars.mak; fi
 	rm -rf build-apps
+
+format:
+	clang-format -i -style=file $(shell git ls-files "utils/*.[ch]" "apps/*.[ch]" "extra/*.[ch]" "LINUX/*.[ch]" "WINDOWS/*.[ch]")

From 3ca3449edcf21b7ca5a06512d0f6e591f3a93e5e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 1 Dec 2017 08:47:14 +0100
Subject: [PATCH 0253/2207] windows: add disclaimer in README

---
 WINDOWS/README.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/WINDOWS/README.txt b/WINDOWS/README.txt
index e6651a5ef..1636f89b4 100644
--- a/WINDOWS/README.txt
+++ b/WINDOWS/README.txt
@@ -1,3 +1,8 @@
+**************************************************************
+DISCLAIMER: This documentation is currently outdated.
+            It is going to be updated soon.
+**************************************************************
+
 This directory contains the Windows version of netmap, developed by
 Alessio Faina as part of his MS thesis at the Universita` di Pisa.
 

From 333140c937c04fc767d353b0b29e593e65be8c99 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Mar 2017 18:41:06 +0100
Subject: [PATCH 0254/2207] linux/glue: fix return value of copyin/copyout

---
 LINUX/bsd_glue.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index bcbb0e4b6..82ccbf01b 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -264,8 +264,8 @@ struct thread;
 
 #define m_copydata(m, o, l, b)          skb_copy_bits(m, o, b, l)
 
-#define copyin(_from, _to, _len)	copy_from_user(_to, _from, _len)
-#define copyout(_from, _to, _len)	copy_to_user(_to, _from, _len)
+#define copyin(_from, _to, _len)	(copy_from_user(_to, _from, _len) ? EFAULT : 0)
+#define copyout(_from, _to, _len)	(copy_to_user(_to, _from, _len) ? EFAULT : 0)
 
 /*
  * struct ifnet is remapped into struct net_device on linux.

From 9a5be3acc90a9456837a539e1638c798c132787c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Mar 2017 18:42:26 +0100
Subject: [PATCH 0255/2207] mem: move free lut to its own function

---
 sys/dev/netmap/netmap_mem2.c | 91 +++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 42 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 434bcd2cb..51b2523ba 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -630,6 +630,54 @@ nm_mem_assign_group(struct netmap_mem_d *nmd, struct device *dev)
 	return err;
 }
 
+static struct lut_entry *
+nm_alloc_lut(u_int nobj)
+{
+	size_t n = sizeof(struct lut_entry) * nobj;
+	struct lut_entry *lut;
+#ifdef linux
+	lut = vmalloc(n);
+#else
+	lut = nm_os_malloc(n);
+#endif
+	return lut;
+}
+
+static void
+nm_free_lut(struct lut_entry *lut, u_int objtotal)
+{
+	bzero(lut, sizeof(struct lut_entry) * objtotal);
+#ifdef linux
+	vfree(lut);
+#else
+	nm_os_free(lut);
+#endif
+}
+
+static struct plut_entry *
+nm_alloc_plut(u_int nobj)
+{
+	size_t n = sizeof(struct plut_entry) * nobj;
+	struct plut_entry *lut;
+#ifdef linux
+	lut = vmalloc(n);
+#else
+	lut = nm_os_malloc(n);
+#endif
+	return lut;
+}
+
+static void
+nm_free_plut(struct plut_entry * lut)
+{
+#ifdef linux
+	vfree(lut);
+#else
+	nm_os_free(lut);
+#endif
+}
+
+
 /*
  * First, find the allocator that contains the requested offset,
  * then locate the cluster through a lookup table.
@@ -1121,12 +1169,7 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 			if (p->lut[i].vaddr)
 				contigfree(p->lut[i].vaddr, p->_clustsize, M_NETMAP);
 		}
-		bzero(p->lut, sizeof(struct lut_entry) * p->objtotal);
-#ifdef linux
-		vfree(p->lut);
-#else
-		nm_os_free(p->lut);
-#endif
+		nm_free_lut(p->lut, p->objtotal);
 	}
 	p->lut = NULL;
 	p->objtotal = 0;
@@ -1236,42 +1279,6 @@ netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int obj
 	return 0;
 }
 
-static struct lut_entry *
-nm_alloc_lut(u_int nobj)
-{
-	size_t n = sizeof(struct lut_entry) * nobj;
-	struct lut_entry *lut;
-#ifdef linux
-	lut = vmalloc(n);
-#else
-	lut = nm_os_malloc(n);
-#endif
-	return lut;
-}
-
-static struct plut_entry *
-nm_alloc_plut(u_int nobj)
-{
-	size_t n = sizeof(struct plut_entry) * nobj;
-	struct plut_entry *lut;
-#ifdef linux
-	lut = vmalloc(n);
-#else
-	lut = nm_os_malloc(n);
-#endif
-	return lut;
-}
-
-static void
-nm_free_plut(struct plut_entry * lut)
-{
-#ifdef linux
-	vfree(lut);
-#else
-	nm_os_free(lut);
-#endif
-}
-
 /* call with NMA_LOCK held */
 static int
 netmap_finalize_obj_allocator(struct netmap_obj_pool *p)

From 3371407686c4f5525b2b8f3b03f534e05b45ce6f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Mar 2017 18:52:58 +0100
Subject: [PATCH 0256/2207] testmmap: fix print of embedded pointer

---
 utils/testmmap.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 7ec1ee6aa..44e1b5c6b 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -801,10 +801,10 @@ nmr_arg_error()
 void
 nmr_pools_info_get()
 {
-	uintptr_t *pp = (uintptr_t *)&curr_nmr.nr_arg1;
-	struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
+	void **pp = (void **)&curr_nmr.nr_arg1;
+	struct netmap_pools_info *upi = *pp;
 
-	printf("arg1+2+3:  %p\n", pp);
+	printf("arg1+2+3:  %p\n", *pp);
 	printf("    memsize:    %"PRIu64"\n", upi->memsize);
 	printf("    memid:      %"PRIu32"\n", upi->memid);
 	printf("    if off:     %"PRIu32"\n", upi->if_pool_offset);

From a44e158d5178c6893e4933a9d5ff5ad796323dd3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 31 Mar 2017 14:45:20 +0200
Subject: [PATCH 0257/2207] testmmap: parse files from comand line

---
 utils/testmmap.c | 35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 44e1b5c6b..0b700e8c5 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1206,9 +1206,9 @@ int find_command(const char* cmd)
 
 #define MAX_CHAN 10
 
-void prompt()
+void prompt(FILE *f)
 {
-	if (isatty(STDIN_FILENO)) {
+	if (isatty(fileno(f))) {
 		printf("> ");
 	}
 }
@@ -1243,7 +1243,7 @@ void do_exit()
 }
 
 void
-cmd_loop()
+cmd_loop(FILE *input)
 {
 	char buf[1024];
 	int i;
@@ -1253,7 +1253,7 @@ cmd_loop()
 
 	atexit(do_exit);
 
-	for (prompt(); fgets(buf, 1024, stdin); prompt()) {
+	for (prompt(input); fgets(buf, 1024, input); prompt(input)) {
 		char *cmd;
 		int slot;
 
@@ -1420,6 +1420,9 @@ cmd_loop()
 			}
 			continue;
 		}
+		if (strcmp(cmd, "next") == 0) {
+			return;
+		}
 		i = find_command(cmd);
 		if (i < N_CMDS) {
 			commands[i].f();
@@ -1444,9 +1447,25 @@ cmd_loop()
 int
 main(int argc, char **argv)
 {
-	(void) argc;
-	(void) argv;
-	printf("testmmap\n");
-	cmd_loop();
+	int i;
+	if (argc > 1) {
+		for (i = 1; i < argc; i++) {
+			FILE *f;
+		       	if (!strcmp(argv[i], "-")) {
+				f = stdin;
+			} else {
+				f = fopen(argv[i], "r");
+				if (f == NULL) {
+					perror(argv[i]);
+					continue;
+				}
+			}
+			cmd_loop(f);
+			if (f != stdin)
+				fclose(f);
+		}
+	} else {
+		cmd_loop(stdin);
+	}
 	return 0;
 }

From d05498b7f40f761f7adb384aa48a988d9305c13a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Dec 2017 19:06:50 +0100
Subject: [PATCH 0258/2207] linux/scipts: fake compiler-ggc7.h if missing

---
 LINUX/scripts/np | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index eb7cd654a..690421e78 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -378,6 +378,8 @@ function build-prep()
 			ln -s compiler-gcc4.h include/linux/compiler-gcc5.h
 		[ -e include/linux/compiler-gcc6.h ] ||
 			ln -s compiler-gcc5.h include/linux/compiler-gcc6.h
+		[ -e include/linux/compiler-gcc7.h ] ||
+			ln -s compiler-gcc6.h include/linux/compiler-gcc7.h
 		# force disabling PIE
 		sed -i -e '/^all: vmlinux/a\
 \

From 05ad1b244a7c327aa0ebf930cb715f2d61006f89 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Dec 2017 17:59:02 +0100
Subject: [PATCH 0259/2207] allow multiple calls to netmap_reset

---
 sys/dev/netmap/netmap.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 10f3fdf2e..73bccc812 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3219,6 +3219,9 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 
 		kring = na->tx_rings + n;
 
+		if (kring->nr_mode == NKR_NETMAP_ON)
+			return kring->ring->slot;
+
 		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
 			kring->nr_mode = NKR_NETMAP_OFF;
 			return NULL;
@@ -3231,6 +3234,10 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 			return NULL;
 		kring = na->rx_rings + n;
 
+		if (kring->nr_mode == NKR_NETMAP_ON)
+			return kring->ring->slot;
+
+
 		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
 			kring->nr_mode = NKR_NETMAP_OFF;
 			return NULL;

From 68c230fdf41c56c0ad2c93617a589eaf64f41e3e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Dec 2017 18:43:09 +0100
Subject: [PATCH 0260/2207] i40e: set rx buffer size in netmap mode

---
 LINUX/bsd_glue.h                              |  4 +++
 LINUX/final-patches/intel--i40e--1.5.25       | 21 ++++++++++++----
 LINUX/final-patches/intel--i40e--1.6.42       | 19 +++++++++++---
 LINUX/final-patches/intel--i40e--2.0.19       | 19 +++++++++++---
 LINUX/final-patches/intel--i40e--2.0.26       | 19 +++++++++++---
 LINUX/final-patches/intel--i40e--2.0.30       | 19 +++++++++++---
 LINUX/final-patches/intel--i40e--2.1.26       | 25 +++++++++++++------
 LINUX/final-patches/intel--i40e--2.3.6        | 19 +++++++++++---
 .../final-patches/vanilla--i40e--30c00--40100 | 21 ++++++++++++----
 .../final-patches/vanilla--i40e--40100--40300 | 21 ++++++++++++----
 .../final-patches/vanilla--i40e--40300--40400 | 21 ++++++++++++----
 .../final-patches/vanilla--i40e--40400--40700 | 21 ++++++++++++----
 .../final-patches/vanilla--i40e--40700--40e00 | 21 ++++++++++++----
 .../final-patches/vanilla--i40e--40e00--99999 | 21 ++++++++++++----
 LINUX/i40e_netmap_linux.h                     | 20 +++++++++++++++
 15 files changed, 229 insertions(+), 62 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index bcbb0e4b6..c80b1bc88 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -496,4 +496,8 @@ void netmap_bns_unregister(void);
 
 #define if_printf(ifp, fmt, ...)  dev_info(&(ifp)->dev, fmt, ##__VA_ARGS__)
 
+#ifndef BIT_ULL
+#define BIT_ULL(nr)	(1ULL << (nr))
+#endif /* !BIT_ULL */
+
 #endif /* NETMAP_BSD_GLUE_H */
diff --git a/LINUX/final-patches/intel--i40e--1.5.25 b/LINUX/final-patches/intel--i40e--1.5.25
index 8c0ee87c3..fdb60b9fb 100644
--- a/LINUX/final-patches/intel--i40e--1.5.25
+++ b/LINUX/final-patches/intel--i40e--1.5.25
@@ -1,5 +1,5 @@
 diff --git a/i40e/Makefile b/i40e/Makefile
-index 8c1483c..104b8c9 100644
+index 8c1483c..509f19e 100644
 --- a/i40e/Makefile
 +++ b/i40e/Makefile
 @@ -27,9 +27,9 @@ ifneq ($(KERNELRELEASE),)
@@ -48,7 +48,7 @@ index 8c1483c..104b8c9 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 577cc4a..d9ee330 100644
+index e729c22..b830e4c 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -132,6 +132,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -74,7 +74,18 @@ index 577cc4a..d9ee330 100644
  	return 0;
  }
  
-@@ -3141,6 +3150,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3119,6 +3128,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3141,6 +3154,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index 577cc4a..d9ee330 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10100,6 +10114,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10101,6 +10119,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index 577cc4a..d9ee330 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -10461,6 +10480,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -10462,6 +10485,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--1.6.42 b/LINUX/final-patches/intel--i40e--1.6.42
index 095c6cc6b..a08dd95a3 100644
--- a/LINUX/final-patches/intel--i40e--1.6.42
+++ b/LINUX/final-patches/intel--i40e--1.6.42
@@ -48,7 +48,7 @@ index a190706..314e79e 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 4dd9457..f4783e5 100644
+index 4dd9457..a2949b4 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -134,6 +134,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -74,7 +74,18 @@ index 4dd9457..f4783e5 100644
  	return 0;
  }
  
-@@ -3286,6 +3295,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3264,6 +3273,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3286,6 +3299,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index 4dd9457..f4783e5 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10417,6 +10431,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10417,6 +10435,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index 4dd9457..f4783e5 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -10788,6 +10807,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -10788,6 +10811,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.0.19 b/LINUX/final-patches/intel--i40e--2.0.19
index dbd8d03b4..52547772e 100644
--- a/LINUX/final-patches/intel--i40e--2.0.19
+++ b/LINUX/final-patches/intel--i40e--2.0.19
@@ -48,7 +48,7 @@ index 1af83c9..e896ffe 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 7a2d4d7..659cf4a 100644
+index 7a2d4d7..0b79e20 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -133,6 +133,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -74,7 +74,18 @@ index 7a2d4d7..659cf4a 100644
  	return 0;
  }
  
-@@ -3353,6 +3362,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3331,6 +3340,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3353,6 +3366,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index 7a2d4d7..659cf4a 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10570,6 +10584,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10570,6 +10588,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index 7a2d4d7..659cf4a 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -10941,6 +10960,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -10941,6 +10964,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.0.26 b/LINUX/final-patches/intel--i40e--2.0.26
index fc577e8ee..e8dad5e7d 100644
--- a/LINUX/final-patches/intel--i40e--2.0.26
+++ b/LINUX/final-patches/intel--i40e--2.0.26
@@ -48,7 +48,7 @@ index 1af83c9..e896ffe 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 15e43a1..1eddcb3 100644
+index 15e43a1..d02fc33 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -133,6 +133,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -74,7 +74,18 @@ index 15e43a1..1eddcb3 100644
  	return 0;
  }
  
-@@ -3353,6 +3362,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3331,6 +3340,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3353,6 +3366,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index 15e43a1..1eddcb3 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10645,6 +10659,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10645,6 +10663,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index 15e43a1..1eddcb3 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -11016,6 +11035,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -11016,6 +11039,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.0.30 b/LINUX/final-patches/intel--i40e--2.0.30
index f1099fc55..7632ee559 100644
--- a/LINUX/final-patches/intel--i40e--2.0.30
+++ b/LINUX/final-patches/intel--i40e--2.0.30
@@ -48,7 +48,7 @@ index 1af83c9..e896ffe 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 142be1c..b0d4aa3 100644
+index 142be1c..9a00bf1 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -133,6 +133,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -74,7 +74,18 @@ index 142be1c..b0d4aa3 100644
  	return 0;
  }
  
-@@ -3353,6 +3362,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3331,6 +3340,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3353,6 +3366,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index 142be1c..b0d4aa3 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10655,6 +10669,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10655,6 +10673,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index 142be1c..b0d4aa3 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -11026,6 +11045,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -11026,6 +11049,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.1.26 b/LINUX/final-patches/intel--i40e--2.1.26
index 233f25275..273454fb0 100644
--- a/LINUX/final-patches/intel--i40e--2.1.26
+++ b/LINUX/final-patches/intel--i40e--2.1.26
@@ -1,4 +1,4 @@
-diff --git a/i40e/Makefile b/src/Makefile
+diff --git a/i40e/Makefile b/i40e/Makefile
 index f653b71..c356d02 100644
 --- a/i40e/Makefile
 +++ b/i40e/Makefile
@@ -45,8 +45,8 @@ index f653b71..c356d02 100644
  # Clean the module subdirectories
  clean:
  	@+$(call kernelbuild,clean)
-diff --git a/i40e/i40e_main.c b/src/i40e_main.c
-index 4c70594..32a22ad 100644
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 4c70594..8a7cace 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -72,7 +72,18 @@ index 4c70594..32a22ad 100644
  	return 0;
  }
  
-@@ -3291,6 +3300,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3263,6 +3272,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3291,6 +3304,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -84,7 +95,7 @@ index 4c70594..32a22ad 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10844,6 +10858,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10844,6 +10862,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -96,7 +107,7 @@ index 4c70594..32a22ad 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -11212,6 +11231,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -11212,6 +11235,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
@@ -109,7 +120,7 @@ index 4c70594..32a22ad 100644
  	return vsi;
  
  err_rings:
-diff --git a/i40e/i40e_txrx.c b/src/i40e_txrx.c
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
 index cbd49a9..7c83c01 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
diff --git a/LINUX/final-patches/intel--i40e--2.3.6 b/LINUX/final-patches/intel--i40e--2.3.6
index b7eea198d..57b0a3ef7 100644
--- a/LINUX/final-patches/intel--i40e--2.3.6
+++ b/LINUX/final-patches/intel--i40e--2.3.6
@@ -46,7 +46,7 @@ index ff50970..8d7f7fb 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 7fea797..f8122fb 100644
+index 7fea797..6eaed5b 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -72,7 +72,18 @@ index 7fea797..f8122fb 100644
  	return 0;
  }
  
-@@ -3320,6 +3329,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3292,6 +3301,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3320,6 +3333,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -84,7 +95,7 @@ index 7fea797..f8122fb 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10843,6 +10857,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10843,6 +10861,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -96,7 +107,7 @@ index 7fea797..f8122fb 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -11211,6 +11230,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -11211,6 +11234,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/vanilla--i40e--30c00--40100 b/LINUX/final-patches/vanilla--i40e--30c00--40100
index 9e3b301de..98258a9c1 100644
--- a/LINUX/final-patches/vanilla--i40e--30c00--40100
+++ b/LINUX/final-patches/vanilla--i40e--30c00--40100
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 221aa47..4e61898 100644
+index 221aa4795017..db5394879249 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -86,6 +86,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -25,7 +25,18 @@ index 221aa47..4e61898 100644
  	return 0;
  }
  
-@@ -2207,6 +2216,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2185,6 +2194,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	rx_ctx.l2tsel = 1;
+ 	rx_ctx.showiv = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -2207,6 +2220,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -37,7 +48,7 @@ index 221aa47..4e61898 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -5876,6 +5890,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -5876,6 +5894,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -49,7 +60,7 @@ index 221aa47..4e61898 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -6124,6 +6143,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -6124,6 +6147,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  		break;
  	}
  
@@ -62,7 +73,7 @@ index 221aa47..4e61898 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 49d2cfa..83f3c56 100644
+index 49d2cfa9b0cc..83f3c560887a 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -27,6 +27,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40100--40300 b/LINUX/final-patches/vanilla--i40e--40100--40300
index 048bcfc69..c38ad5115 100644
--- a/LINUX/final-patches/vanilla--i40e--40100--40300
+++ b/LINUX/final-patches/vanilla--i40e--40100--40300
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 5b5bea1..c8a32923 100644
+index 5b5bea159bd5..45bfb58a5c5f 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -91,6 +91,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -25,7 +25,18 @@ index 5b5bea1..c8a32923 100644
  	return 0;
  }
  
-@@ -2614,6 +2623,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2592,6 +2601,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -2614,6 +2627,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -37,7 +48,7 @@ index 5b5bea1..c8a32923 100644
  	if (ring_is_ps_enabled(ring)) {
  		i40e_alloc_rx_headers(ring);
  		i40e_alloc_rx_buffers_ps(ring, I40E_DESC_UNUSED(ring));
-@@ -8515,6 +8529,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -8515,6 +8533,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -49,7 +60,7 @@ index 5b5bea1..c8a32923 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -8850,6 +8869,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -8850,6 +8873,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  		break;
  	}
  
@@ -62,7 +73,7 @@ index 5b5bea1..c8a32923 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 9d95042d..80f8a88 100644
+index 9d95042d5a0f..80f8a88a3ae8 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40300--40400 b/LINUX/final-patches/vanilla--i40e--40300--40400
index 153fcc710..e2a68e88f 100644
--- a/LINUX/final-patches/vanilla--i40e--40300--40400
+++ b/LINUX/final-patches/vanilla--i40e--40300--40400
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 3dd26cd..05b8960 100644
+index 3dd26cdd0bf2..ebed661a1148 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -94,6 +94,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -25,7 +25,18 @@ index 3dd26cd..05b8960 100644
  	return 0;
  }
  
-@@ -2702,6 +2711,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2680,6 +2689,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -2702,6 +2715,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -37,7 +48,7 @@ index 3dd26cd..05b8960 100644
  	if (ring_is_ps_enabled(ring)) {
  		i40e_alloc_rx_headers(ring);
  		i40e_alloc_rx_buffers_ps(ring, I40E_DESC_UNUSED(ring));
-@@ -8757,6 +8771,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -8757,6 +8775,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -49,7 +60,7 @@ index 3dd26cd..05b8960 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -9101,6 +9120,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -9101,6 +9124,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
@@ -63,7 +74,7 @@ index 3dd26cd..05b8960 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 738aca6..77e14b3 100644
+index 738aca68f665..77e14b3828d7 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40400--40700 b/LINUX/final-patches/vanilla--i40e--40400--40700
index e8669c0f4..03a39ce85 100644
--- a/LINUX/final-patches/vanilla--i40e--40400--40700
+++ b/LINUX/final-patches/vanilla--i40e--40400--40700
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 4a9873ec..2803d11 100644
+index 4a9873ec28c7..58c0ca3401d3 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -97,6 +97,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -25,7 +25,18 @@ index 4a9873ec..2803d11 100644
  	return 0;
  }
  
-@@ -2893,6 +2902,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2871,6 +2880,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -2893,6 +2906,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -37,7 +48,7 @@ index 4a9873ec..2803d11 100644
  	if (ring_is_ps_enabled(ring)) {
  		i40e_alloc_rx_headers(ring);
  		i40e_alloc_rx_buffers_ps(ring, I40E_DESC_UNUSED(ring));
-@@ -9031,6 +9045,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -9031,6 +9049,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -49,7 +60,7 @@ index 4a9873ec..2803d11 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -9377,6 +9396,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -9377,6 +9400,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
@@ -63,7 +74,7 @@ index 4a9873ec..2803d11 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 635b3ac..baed465 100644
+index 635b3ac17877..baed465e8b35 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40700--40e00 b/LINUX/final-patches/vanilla--i40e--40700--40e00
index 912df8274..407b97f18 100644
--- a/LINUX/final-patches/vanilla--i40e--40700--40e00
+++ b/LINUX/final-patches/vanilla--i40e--40700--40e00
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 501f15d..df24012 100644
+index 501f15d9f4d6..0073159583d7 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -110,6 +110,10 @@ MODULE_LICENSE("GPL");
@@ -24,7 +24,18 @@ index 501f15d..df24012 100644
  	return 0;
  }
  
-@@ -2902,6 +2910,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2880,6 +2888,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -2902,6 +2914,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -36,7 +47,7 @@ index 501f15d..df24012 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -9511,6 +9524,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -9511,6 +9528,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -48,7 +59,7 @@ index 501f15d..df24012 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -9911,6 +9929,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -9911,6 +9933,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
@@ -62,7 +73,7 @@ index 501f15d..df24012 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index a8868e1..9186a17 100644
+index a8868e1bf832..9186a17975b8 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
diff --git a/LINUX/final-patches/vanilla--i40e--40e00--99999 b/LINUX/final-patches/vanilla--i40e--40e00--99999
index db8d94525..11324a074 100644
--- a/LINUX/final-patches/vanilla--i40e--40e00--99999
+++ b/LINUX/final-patches/vanilla--i40e--40e00--99999
@@ -1,5 +1,5 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 6498da8..d45069e 100644
+index 6498da8806cb..7fbe7d5a62f9 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -113,6 +113,10 @@ MODULE_LICENSE("GPL");
@@ -24,7 +24,18 @@ index 6498da8..d45069e 100644
  	return 0;
  }
  
-@@ -3059,6 +3067,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3031,6 +3039,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3059,6 +3071,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -36,7 +47,7 @@ index 6498da8..d45069e 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10051,6 +10064,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10051,6 +10068,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -48,7 +59,7 @@ index 6498da8..d45069e 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -10418,6 +10436,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -10418,6 +10440,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
@@ -62,7 +73,7 @@ index 6498da8..d45069e 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 120c68f..70d59e2 100644
+index 120c68f78951..70d59e253a7b 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -31,6 +31,10 @@
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 73969df69..cca07e369 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -136,6 +136,26 @@ i40e_netmap_configure_tx_ring(struct i40e_ring *ring)
 	netmap_reset(na, NR_TX, ring->queue_index, 0);
 }
 
+static void
+i40e_netmap_preconfigure_rx_ring(struct i40e_ring *ring,
+		struct i40e_hmc_obj_rxq *rx_ctx)
+{
+	struct netmap_adapter *na;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return;
+	}
+
+	na = NA(ring->netdev);
+
+	if (netmap_reset(na, NR_RX, ring->queue_index, 0) == NULL)
+		return;	// not in native netmap mode
+
+	rx_ctx->dbuff = DIV_ROUND_UP(NETMAP_BUF_SIZE(na),
+			BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
+}
+
 static int
 i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 {

From 5662d41e10464693b8156d1a955bf2854ff7c7f2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Dec 2017 09:45:27 +0100
Subject: [PATCH 0261/2207] man: document nr_arg3

---
 share/man/man4/netmap.4 | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index e86d3d17a..afbcd49b3 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -266,9 +266,15 @@ normally depends on the hardware.
 NICs also have an extra tx/rx ring pair connected to the host stack.
 .Em NIOCREGIF
 can also request additional unbound buffers in the same memory space,
-to be used as temporary storage for packets.
+to be used as temporary storage for packets. The number of extra
+buffers is specified in the
+.Va arg.nr_arg3
+field. On success, the kernel writes back to
+.Va arg.nr_arg3
+the number of extra buffers actually allocated (they may be less
+than the amount requested if the memory space ran out of buffers).
 .Pa ni_bufs_head
-contains the index of the first of these free rings,
+contains the index of the first of these extra buffers,
 which are connected in a list (the first uint32_t of each
 buffer being the index of the next buffer in the list).
 A

From 45026cb10ca38254c65623a469d699691042b369 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Dec 2017 10:10:45 +0100
Subject: [PATCH 0262/2207] man: netmap: more explanation on extra buffers

---
 share/man/man4/netmap.4 | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index afbcd49b3..d372cbeb2 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -279,7 +279,13 @@ which are connected in a list (the first uint32_t of each
 buffer being the index of the next buffer in the list).
 A
 .Dv 0
-indicates the end of the list.
+indicates the end of the list. The application is free to modify
+this list and use the buffers (i.e., binding them to the slots of a
+netmap ring). When closing the netmap file descriptor,
+the kernel frees the buffers contained in the list pointed by
+.Pa ni_bufs_head
+, irrespectively of the buffers originally provided by the kernel on
+.Em NIOCREGIF.
 .It Dv struct netmap_ring (one per ring)
 .Bd -literal
 struct netmap_ring {

From 7992ecca697e90f63f2e7fc59dde9d708a163887 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 3 Dec 2017 19:59:21 +0100
Subject: [PATCH 0263/2207] lb: optmized hash calculation

---
 apps/lb/pkt_hash.c | 93 +++++++++++++++++++++++++---------------------
 1 file changed, 50 insertions(+), 43 deletions(-)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index ebd439592..8fb893ce5 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -48,6 +48,9 @@
 /* for memset */
 #include 
 
+#include 
+#include 
+
 //#include 
 /*---------------------------------------------------------------------*/
 /**
@@ -57,36 +60,49 @@
 static void
 build_sym_key_cache(uint32_t *cache, int cache_len)
 {
-	static const uint8_t key[] = {
-		0x50, 0x6d, 0x50, 0x6d,
-                0x50, 0x6d, 0x50, 0x6d,
-                0x50, 0x6d, 0x50, 0x6d,
-                0x50, 0x6d, 0x50, 0x6d,
-                0xcb, 0x2b, 0x5a, 0x5a,
-		0xb4, 0x30, 0x7b, 0xae,
-                0xa3, 0x2d, 0xcb, 0x77,
-                0x0c, 0xf2, 0x30, 0x80,
-                0x3b, 0xb7, 0x42, 0x6a,
-                0xfa, 0x01, 0xac, 0xbe};
+	static const uint8_t key[] = { 0x50, 0x6d };
 
         uint32_t result = (((uint32_t)key[0]) << 24) |
                 (((uint32_t)key[1]) << 16) |
-                (((uint32_t)key[2]) << 8)  |
-                ((uint32_t)key[3]);
+                (((uint32_t)key[0]) << 8)  |
+                ((uint32_t)key[1]);
 
         uint32_t idx = 32;
         int i;
 
         for (i = 0; i < cache_len; i++, idx++) {
-                uint8_t shift = (idx % (sizeof(uint8_t) * 8));
+                uint8_t shift = (idx % 8);
                 uint32_t bit;
 
                 cache[i] = result;
-                bit = ((key[idx/(sizeof(uint8_t) * 8)] << shift)
-		       & 0x80) ? 1 : 0;
+                bit = ((key[(idx/8) & 1] << shift) & 0x80) ? 1 : 0;
                 result = ((result << 1) | bit);
         }
 }
+
+static void
+build_byte_cache(uint32_t byte_cache[256][4])
+{
+#define KEY_CACHE_LEN			96
+	int i, j, k;
+	uint32_t key_cache[KEY_CACHE_LEN];
+
+	build_sym_key_cache(key_cache, KEY_CACHE_LEN);
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0; j < 256; j++) {
+			uint8_t b = j;
+			byte_cache[j][i] = 0;
+			for (k = 0; k < 8; k++) {
+				if (b & 0x80)
+					byte_cache[j][i] ^= key_cache[8 * i + k];
+				b <<= 1U;
+			}
+		}
+	}
+}
+
+
 /*---------------------------------------------------------------------*/
 /**
  ** Computes symmetric hash based on the 4-tuple header data
@@ -94,40 +110,31 @@ build_sym_key_cache(uint32_t *cache, int cache_len)
 static uint32_t
 sym_hash_fn(uint32_t sip, uint32_t dip, uint16_t sp, uint32_t dp)
 {
-#define MSB32				0x80000000
-#define MSB16				0x8000
-#define KEY_CACHE_LEN			96
-
 	uint32_t rc = 0;
-	int i;
 	static int first_time = 1;
-	static uint32_t key_cache[KEY_CACHE_LEN] = {0};
+	static uint32_t byte_cache[256][4];
+	uint8_t *sip_b = (uint8_t *)&sip,
+		*dip_b = (uint8_t *)&dip,
+		*sp_b  = (uint8_t *)&sp,
+		*dp_b  = (uint8_t *)&dp;
 
 	if (first_time) {
-		build_sym_key_cache(key_cache, KEY_CACHE_LEN);
+		build_byte_cache(byte_cache);
 		first_time = 0;
 	}
 
-	for (i = 0; i < 32; i++) {
-                if (sip & MSB32)
-                        rc ^= key_cache[i];
-                sip <<= 1;
-        }
-        for (i = 0; i < 32; i++) {
-                if (dip & MSB32)
-			rc ^= key_cache[32+i];
-                dip <<= 1;
-        }
-        for (i = 0; i < 16; i++) {
-		if (sp & MSB16)
-                        rc ^= key_cache[64+i];
-                sp <<= 1;
-        }
-        for (i = 0; i < 16; i++) {
-                if (dp & MSB16)
-                        rc ^= key_cache[80+i];
-                dp <<= 1;
-        }
+	rc = byte_cache[sip_b[3]][0] ^
+	     byte_cache[sip_b[2]][1] ^
+	     byte_cache[sip_b[1]][2] ^
+	     byte_cache[sip_b[0]][3] ^
+	     byte_cache[dip_b[3]][0] ^
+	     byte_cache[dip_b[2]][1] ^
+	     byte_cache[dip_b[1]][2] ^
+	     byte_cache[dip_b[0]][3] ^
+	     byte_cache[sp_b[1]][0] ^
+	     byte_cache[sp_b[0]][1] ^
+	     byte_cache[dp_b[1]][2] ^
+	     byte_cache[dp_b[0]][3];
 
 	return rc;
 }

From bbff7825bc7f03fbccbf18f753657ac3e746b3dc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 19 Apr 2017 23:31:07 +0200
Subject: [PATCH 0264/2207] mem: restore default allocator on last unregif

---
 sys/dev/netmap/netmap.c      | 20 ++++++++++++++++----
 sys/dev/netmap/netmap_kern.h |  1 +
 sys/dev/netmap/netmap_mem2.c |  5 ++++-
 sys/dev/netmap/netmap_mem2.h |  2 +-
 4 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 73bccc812..0a0869ae4 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -910,7 +910,19 @@ netmap_hw_krings_delete(struct netmap_adapter *na)
 	netmap_krings_delete(na);
 }
 
-
+static void
+netmap_mem_drop(struct netmap_adapter *na)
+{
+	int last = netmap_mem_deref(na->nm_mem, na);
+	/* if the native allocator had been overrided on regif,
+	 * restore it now and drop the temporary one
+	 */
+	if (last && na->nm_mem_prev) {
+		netmap_mem_put(na->nm_mem);
+		na->nm_mem = na->nm_mem_prev;
+		na->nm_mem_prev = NULL;
+	}
+}
 
 /*
  * Undo everything that was done in netmap_do_regif(). In particular,
@@ -978,7 +990,7 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 	/* delete the nifp */
 	netmap_mem_if_delete(na, priv->np_nifp);
 	/* drop the allocator */
-	netmap_mem_deref(na->nm_mem, na);
+	netmap_mem_drop(na);
 	/* mark the priv as unregistered */
 	priv->np_na = NULL;
 	priv->np_nifp = NULL;
@@ -1407,7 +1419,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
 assign_mem:
 	if (nmd != NULL && !((*na)->na_flags & NAF_MEM_OWNER) &&
 	    (*na)->active_fds == 0 && ((*na)->nm_mem != nmd)) {
-		netmap_mem_put((*na)->nm_mem);
+		(*na)->nm_mem_prev = (*na)->nm_mem;
 		(*na)->nm_mem = netmap_mem_get(nmd);
 	}
 
@@ -2135,7 +2147,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	if (na->active_fds == 0)
 		na->nm_krings_delete(na);
 err_drop_mem:
-	netmap_mem_deref(na->nm_mem, na);
+	netmap_mem_drop(na);
 err:
 	priv->np_na = NULL;
 	return error;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d60e9794f..446870b7b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -807,6 +807,7 @@ struct netmap_adapter {
 	 * buffer addresses, the total number of buffers and the buffer size.
 	 */
  	struct netmap_mem_d *nm_mem;
+	struct netmap_mem_d *nm_mem_prev;
 	struct netmap_lut na_lut;
 
 	/* additional information attached to this adapter
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 51b2523ba..2eef18c2a 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -366,13 +366,15 @@ netmap_mem_init_bitmaps(struct netmap_mem_d *nmd)
 	return 0;
 }
 
-void
+int
 netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
+	int last_user = 0;
 	NMA_LOCK(nmd);
 	if (na->active_fds <= 0)
 		netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na);
 	if (nmd->active == 1) {
+		last_user = 1;
 		/*
 		 * Reset the allocator when it falls out of use so that any
 		 * pool resources leaked by unclean application exits are
@@ -383,6 +385,7 @@ netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	nmd->ops->nmd_deref(nmd);
 
 	NMA_UNLOCK(nmd);
+	return last_user;
 }
 
 
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 66e688afd..9d19ebd2a 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -134,7 +134,7 @@ struct netmap_if * netmap_mem_if_new(struct netmap_adapter *, struct netmap_priv
 void 	   netmap_mem_if_delete(struct netmap_adapter *, struct netmap_if *);
 int	   netmap_mem_rings_create(struct netmap_adapter *);
 void	   netmap_mem_rings_delete(struct netmap_adapter *);
-void 	   netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *);
+int 	   netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *);
 int	netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
 int	   netmap_mem_get_info(struct netmap_mem_d *, u_int *size, u_int *memflags, uint16_t *id);
 ssize_t    netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr);

From c3ad05b5b8cfa49a35a4e990a24d7eec3e7600fc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 8 Dec 2017 21:32:28 +0100
Subject: [PATCH 0265/2207] netmap_poll: don't skip nm_os_selrecord() on Linux

---
 LINUX/netmap_linux.c    |  4 ++--
 sys/dev/netmap/netmap.c | 23 ++++++-----------------
 2 files changed, 8 insertions(+), 19 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index c0b064268..7771c900a 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -935,13 +935,13 @@ struct nm_linux_selrecord_t {
  * - file is passed as 'td';
  */
 static u_int
-linux_netmap_poll(struct file * file, struct poll_table_struct *pwait)
+linux_netmap_poll(struct file *file, struct poll_table_struct *pwait)
 {
 #ifdef NETMAP_LINUX_PWAIT_KEY
 	int events = pwait ? pwait->NETMAP_LINUX_PWAIT_KEY : \
 		     POLLIN | POLLOUT | POLLERR;
 #else
-	int events = POLLIN | POLLOUT; /* XXX maybe... */
+	int events = POLLIN | POLLOUT | POLLERR;
 #endif /* PWAIT_KEY */
 	struct nm_linux_selrecord_t sr = {
 		.file = file,
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 73bccc812..838e85014 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2531,7 +2531,6 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 #define want_tx want[NR_TX]
 #define want_rx want[NR_RX]
 	struct mbq q;	/* packets from RX hw queues to host stack */
-	enum txrx t;
 
 	/*
 	 * In order to avoid nested locks, we need to "double check"
@@ -2583,14 +2582,15 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	check_all_tx = nm_si_user(priv, NR_TX);
 	check_all_rx = nm_si_user(priv, NR_RX);
 
+#ifdef __FreeBSD__
 	/*
 	 * We start with a lock free round which is cheap if we have
 	 * slots available. If this fails, then lock and call the sync
-	 * routines.
+	 * routines. We can't do this on Linux, as the contract says
+	 * that we must call nm_os_selrecord() unconditionally.
 	 */
-#if 1 /* new code- call rx if any of the ring needs to release or read buffers */
 	if (want_tx) {
-		t = NR_TX;
+		enum txrx t = NR_TX;
 		for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) {
 			kring = &NMR(na, t)[i];
 			/* XXX compare ring->cur and kring->tail */
@@ -2601,8 +2601,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		}
 	}
 	if (want_rx) {
+		enum txrx t = NR_RX;
 		want_rx = 0; /* look for a reason to run the handlers */
-		t = NR_RX;
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
 			kring = &NMR(na, t)[i];
 			if (kring->ring->cur == kring->ring->tail /* try fetch new buffers */
@@ -2613,18 +2613,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		if (!want_rx)
 			revents |= events & (POLLIN | POLLRDNORM); /* we have data */
 	}
-#else /* old code */
-	for_rx_tx(t) {
-		for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) {
-			kring = &NMR(na, t)[i];
-			/* XXX compare ring->cur and kring->tail */
-			if (!nm_ring_empty(kring->ring)) {
-				revents |= want[t];
-				want[t] = 0;	/* also breaks the loop */
-			}
-		}
-	}
-#endif /* old code */
+#endif
 
 	/*
 	 * If we want to push packets out (priv->np_txpoll) or

From b75c0c7d0a030dfeb04c459e37324af625010303 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 11 Dec 2017 15:30:37 +0100
Subject: [PATCH 0266/2207] freebsd: fix various compilation issues

---
 sys/dev/netmap/netmap_kern.h | 14 +++++++++-----
 sys/dev/netmap/netmap_mem2.c |  3 +++
 sys/dev/netmap/netmap_pipe.c |  2 +-
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d60e9794f..b73e36364 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -621,6 +621,10 @@ tail->|                 |<-hwtail    |                 |<-hwlease
  *    a circular array where completions should be reported.
  */
 
+struct lut_entry;
+#ifdef __FreeBSD__
+#define plut_entry lut_entry
+#endif
 
 struct netmap_lut {
 	struct lut_entry *lut;
@@ -1762,7 +1766,7 @@ netmap_idx_k2n(struct netmap_kring *kr, int idx)
 
 
 /* Entries of the look-up table. */
-#if !defined(linux) && !defined(_WIN32)
+#ifdef __FreeBSD__
 struct lut_entry {
 	void *vaddr;		/* virtual address. */
 	vm_paddr_t paddr;	/* physical address. */
@@ -1781,7 +1785,7 @@ struct lut_entry {
 struct plut_entry {
 	vm_paddr_t paddr;	/* physical address. */
 };
-#endif /* !linux & !_WIN32 */
+#endif /* linux & _WIN32 */
 
 struct netmap_obj_pool;
 
@@ -1806,10 +1810,10 @@ PNMB(struct netmap_adapter *na, struct netmap_slot *slot, uint64_t *pp)
 	struct plut_entry *plut = na->na_lut.plut;
 	void *ret = (i >= na->na_lut.objtotal) ? lut[0].vaddr : lut[i].vaddr;
 
-#ifndef _WIN32
-	*pp = (i >= na->na_lut.objtotal) ? plut[0].paddr : plut[i].paddr;
-#else
+#ifdef _WIN32
 	*pp = (i >= na->na_lut.objtotal) ? (uint64_t)plut[0].paddr.QuadPart : (uint64_t)plut[i].paddr.QuadPart;
+#else
+	*pp = (i >= na->na_lut.objtotal) ? plut[0].paddr : plut[i].paddr;
 #endif
 	return ret;
 }
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 51b2523ba..369e11999 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -391,6 +391,9 @@ static int
 netmap_mem2_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut)
 {
 	lut->lut = nmd->pools[NETMAP_BUF_POOL].lut;
+#ifdef __FreeBSD__
+	lut->plut = lut->lut;
+#endif
 	lut->objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal;
 	lut->objsize = nmd->pools[NETMAP_BUF_POOL]._objsize;
 
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 0230e3261..f8fab8729 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -211,7 +211,7 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
                 struct netmap_slot *ts = &txring->slot[k];
                 struct netmap_slot tmp;
 
-		prefetch(ts + 1);
+		__builtin_prefetch(ts + 1);
 
                 /* swap the slots and report the buffer change */
                 tmp = *rs;

From 11f0c03160cea74ba64bfa81bb9fd5dedb925c8d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 11 Dec 2017 23:41:20 +0100
Subject: [PATCH 0267/2207] linux: netmap_poll: call poll_wait()
 unconditionally

---
 sys/dev/netmap/netmap.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index fdca5f006..cfd0744cb 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2627,11 +2627,18 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	}
 #endif
 
+#ifdef linux
+	/* The selrecord must be unconditional on linux. */
+	nm_os_selrecord(sr, check_all_tx ?
+	    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]].si);
+	nm_os_selrecord(sr, check_all_rx ?
+		&na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]].si);
+#endif /* linux */
+
 	/*
 	 * If we want to push packets out (priv->np_txpoll) or
 	 * want_tx is still set, we must issue txsync calls
 	 * (on all rings, to avoid that the tx rings stall).
-	 * XXX should also check cur != hwcur on the tx rings.
 	 * Fortunately, normal tx mode has np_txpoll set.
 	 */
 	if (priv->np_txpoll || want_tx) {
@@ -2648,6 +2655,12 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 			kring = &na->tx_rings[i];
 			ring = kring->ring;
 
+			/*
+			 * Don't try to txsync this TX ring if we already found some
+			 * space in some of the TX rings (want_tx == 0) and there are no
+			 * TX slots in this ring that need to be flushed to the NIC
+			 * (cur == hwcur).
+			 */
 			if (!send_down && !want_tx && ring->cur == kring->nr_hwcur)
 				continue;
 
@@ -2681,8 +2694,10 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		/* if there were any packet to forward we must have handled them by now */
 		send_down = 0;
 		if (want_tx && retry_tx && sr) {
+#ifndef linux
 			nm_os_selrecord(sr, check_all_tx ?
 			    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]].si);
+#endif /* !linux */
 			retry_tx = 0;
 			goto flush_tx;
 		}
@@ -2737,10 +2752,12 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 			}
 		}
 
+#ifndef linux
 		if (retry_rx && sr) {
 			nm_os_selrecord(sr, check_all_rx ?
 			    &na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]].si);
 		}
+#endif /* !linux */
 		if (send_down || retry_rx) {
 			retry_rx = 0;
 			if (send_down)

From efd6aaa3c144c9272252398ac71078ef0b24978a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Dec 2017 20:10:32 +0100
Subject: [PATCH 0268/2207] testmmap: fix print of cur/tail

---
 utils/testmmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 0b700e8c5..481e41bb1 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -588,8 +588,8 @@ do_ring()
 	}
 	printf("]\n");
 	printf("head        %u\n", ring->head);
-	printf("cur         %u\n", ring->head);
-	printf("tail        %u\n", ring->head);
+	printf("cur         %u\n", ring->cur);
+	printf("tail        %u\n", ring->tail);
 	printf("flags       %x", ring->flags);
 	if (ring->flags) {
 		printf(" [");

From 96f9b2c66bb96daa342ed698134b11dbe6f41daa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 12 Dec 2017 10:44:17 +0100
Subject: [PATCH 0269/2207] linux/ixgbe: initialize tx heads

---
 LINUX/ixgbe_netmap_linux.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index cf809a017..643a0cefb 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -751,6 +751,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 			ixgbe_netmap_detach(adapter);
 			return;
 		}
+		*h->phead = 0;
 	}
 #endif /*! NM_IXGBE_USE_TDH */
 }

From ca912a1c037bb36274ef34d625b836581e53f5c5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 12 Dec 2017 10:44:54 +0100
Subject: [PATCH 0270/2207] linux/ixgbe: move head-wb allocation to kring
 creation

The number of rings may change, so kring allocation is
the proper time to allocate all per-ring resources.
---
 LINUX/ixgbe_netmap_linux.h | 100 +++++++++++++++++++++++++------------
 LINUX/netmap_linux.c       |   2 +
 2 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 643a0cefb..36904dbe4 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -211,7 +211,7 @@ struct netmap_ixgbe_adapter {
 	struct netmap_hw_adapter up;
 #ifndef NM_IXGBE_USE_TDH
 	struct dma_pool *pool;
-	struct netmap_ixgbe_head heads[];
+	struct netmap_ixgbe_head *heads;
 #endif /*! NM_IXGBE_USE_TDH */
 };
 
@@ -404,6 +404,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
 		u32 h = ACCESS_ONCE(*ina->heads[ring_nr].phead);
+		RD(5, "%s: h %d", kring->name, h);
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
 #else /* NM_IXGBE_USE_TDH */
@@ -595,8 +596,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
  * Otherwise return false.
  */
 static u32
-ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u32 txdctl
-		)
+ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u32 txdctl)
 {
 	struct netmap_adapter *na = NA(adapter->netdev);
 	struct netmap_slot *slot;
@@ -613,7 +613,7 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 #ifndef NM_IXGBE_USE_TDH
 	/* we reset WTRESH (it must be 0 according to specs) */
 	txdctl &= ~(0x7f << 16);
-
+	
 	wba = (u64)ina->heads[ring_nr].map;
 	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAL(ring_nr),
 		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);
@@ -692,6 +692,66 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	return 1;
 }
 
+static void
+ixgbe_netmap_krings_delete(struct netmap_adapter *na)
+{
+#ifndef NM_IXGBE_USE_TDH
+	struct netmap_ixgbe_adapter *ina =
+		(struct netmap_ixgbe_adapter *)na;
+
+	ina = (struct netmap_ixgbe_adapter *)na;
+	if (ina->heads != NULL) {
+		int i;
+
+		for (i = 0; i < na->num_tx_rings; i++) {
+			struct netmap_ixgbe_head *h = &ina->heads[i];
+			if (h->phead != NULL)
+				dma_pool_free(ina->pool, h->phead, h->map);
+			h->phead = NULL;
+		}
+		kfree(ina->heads);
+		ina->heads = NULL;
+	}
+#endif /*! NM_IXGBE_USE_TDH */
+	netmap_hw_krings_delete(na);
+}
+
+static int
+ixgbe_netmap_krings_create(struct netmap_adapter *na)
+{
+	struct netmap_ixgbe_adapter *ina =
+		(struct netmap_ixgbe_adapter *)na;
+	int i, ret;
+       
+	ret = netmap_hw_krings_create(na);
+	if (ret)
+		return ret;
+
+#ifndef NM_IXGBE_USE_TDH
+	ret = ENOMEM;
+	ina->heads = kmalloc(sizeof(struct netmap_ixgbe_head) * na->num_tx_rings,
+			GFP_KERNEL | __GFP_ZERO);
+	if (ina->heads == NULL)
+		goto err;
+	for (i = 0; i < na->num_tx_rings; i++) {
+		struct netmap_ixgbe_head *h = &ina->heads[i];
+
+		h->phead = dma_pool_alloc(ina->pool, GFP_KERNEL, &h->map);
+		if (h->phead == NULL) {
+			pr_err("netmap: failed to allocated head %d", i);
+			goto err;
+		}
+		*h->phead = 0;
+		D("%s: phead %p *phead %x", na->tx_rings[i].name, h->phead, *h->phead);
+	}
+	return 0;
+
+err:
+	ixgbe_netmap_krings_delete(na);
+#endif /*! NM_IXGBE_USE_TDH */
+	return ret;
+}
+
 
 static void ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter);
 /*
@@ -708,7 +768,6 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 #ifndef NM_IXGBE_USE_TDH
 	struct netmap_ixgbe_adapter *ina;
 	struct dma_pool *pool;
-	int i;
 
 	// allocate head-writeback region
 	pool = dma_pool_create("head-wb",
@@ -729,11 +788,12 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.nm_txsync = ixgbe_netmap_txsync;
 	na.nm_rxsync = ixgbe_netmap_rxsync;
 	na.nm_register = ixgbe_netmap_reg;
+	na.nm_krings_create = ixgbe_netmap_krings_create;
+	na.nm_krings_delete = ixgbe_netmap_krings_delete;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
 	na.nm_intr = ixgbe_netmap_intr;
-	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter) +
-				sizeof(struct netmap_ixgbe_head) * adapter->num_tx_queues, 1)) {
+	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter), 1)) {
 		pr_err("netmap: failed to attach netmap adapter");
 #ifndef NM_IXGBE_USE_TDH
 		dma_pool_destroy(pool);
@@ -743,47 +803,25 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 #ifndef NM_IXGBE_USE_TDH
 	ina = (struct netmap_ixgbe_adapter *)NA(adapter->netdev);
 	ina->pool = pool;
-	for (i = 0; i < adapter->num_tx_queues; i++) {
-		struct netmap_ixgbe_head *h = &ina->heads[i];
-		h->phead = dma_pool_alloc(pool, GFP_KERNEL, &h->map);
-		if (h->phead == NULL) {
-			pr_err("netmap: failed to allocated head %d", i);
-			ixgbe_netmap_detach(adapter);
-			return;
-		}
-		*h->phead = 0;
-	}
 #endif /*! NM_IXGBE_USE_TDH */
 }
 
 static void
 ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter)
 {
-	struct netmap_adapter *na;
 #ifndef NM_IXGBE_USE_TDH
 	struct netmap_ixgbe_adapter *ina;
-	int i;
-#endif /*! NM_IXGBE_USE_TDH */
 
 	if (!NM_NA_VALID(adapter->netdev))
 		return;
 
-	na = NA(adapter->netdev);
-
-#ifndef NM_IXGBE_USE_TDH
-	ina = (struct netmap_ixgbe_adapter *)na;
+	ina = (struct netmap_ixgbe_adapter *)NA(adapter->netdev);
 	if (ina->pool != NULL) {
-		for (i = 0; i < na->num_tx_rings; i++) {
-			struct netmap_ixgbe_head *h = &ina->heads[i];
-			if (h->phead == NULL)
-				break;
-			dma_pool_free(ina->pool, h->phead, h->map);
-			h->phead = NULL;
-		}
 		dma_pool_destroy(ina->pool);
 		ina->pool = NULL;
 	}
 #endif /*! NM_IXGBE_USE_TDH */
+
 	netmap_detach(adapter->netdev);
 }
 
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 7771c900a..91477e331 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2294,6 +2294,8 @@ EXPORT_SYMBOL(netmap_disable_all_rings);
 EXPORT_SYMBOL(netmap_enable_all_rings);
 EXPORT_SYMBOL(netmap_krings_create);
 EXPORT_SYMBOL(netmap_krings_delete);	/* used by veth module */
+EXPORT_SYMBOL(netmap_hw_krings_create);
+EXPORT_SYMBOL(netmap_hw_krings_delete);
 EXPORT_SYMBOL(netmap_mem_rings_create);	/* used by veth module */
 EXPORT_SYMBOL(netmap_mem_rings_delete);	/* used by veth module */
 #ifdef WITH_PIPES

From b82d3e3d132d1c1eac574aa57aa2925ff9403869 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 12 Dec 2017 10:37:10 +0100
Subject: [PATCH 0271/2207] pkt-gen: stop looking for ring space when there is
 nothing left to send

This avoids some misleading warnings when using the -n option.
---
 apps/pkt-gen/pkt-gen.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d821b3921..f51fe7288 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1604,6 +1604,10 @@ sender_body(void *data)
 		for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
 			int m;
 			uint64_t limit = rate_limit ?  tosend : targ->g->burst;
+
+			if (n > 0 && n == sent)
+				break;
+
 			if (n > 0 && n - sent < limit)
 				limit = n - sent;
 			txring = NETMAP_TXRING(nifp, i);

From 988e698bded2ddca2f2500a6ed6ddeda663d0251 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Dec 2017 10:41:06 +0100
Subject: [PATCH 0272/2207] avoid automatic configure when target is clean or
 distclean

---
 GNUmakefile | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/GNUmakefile b/GNUmakefile
index 5b71d26b0..6427df74b 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,4 +1,4 @@
-all: netmap.mak
+all:
 
 -include netmap.mak
 
@@ -6,9 +6,14 @@ COMPAT_ARGS=$(if $(KSRC),--kernel-dir=$(KSRC),)\
 	    $(if $(SRC),--kernel-sources=$(SRC),)\
 	    $(if $(NODRIVERS),--no-drivers)
 
+
 netmap.mak:
 	@echo 'The new way to build netmap is to run the provided configure script first,'
 	@echo 'followed by make.'
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),distclean)
 	@echo 'We run configure for you now, with compatible arguments, and restart make.'
 	@echo 'Please run configure again if this is not what you want.'
 	./configure $(COMPAT_ARGS)
+endif
+endif

From 239d7e19e8155e999e3eccddae2277b544c93645 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 13 Dec 2017 15:09:48 +0100
Subject: [PATCH 0273/2207] man: fix documentation about transparent mode

---
 share/man/man4/netmap.4      | 7 +++----
 sys/dev/netmap/netmap_kern.h | 3 +--
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index d372cbeb2..aa8063a4e 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -510,10 +510,9 @@ can be delayed indefinitely.
 This flag helps detect
 when packets have been sent and a file descriptor can be closed.
 .It NS_FORWARD
-When a ring is in 'transparent' mode (see
-.Sx TRANSPARENT MODE ) ,
-packets marked with this flag are forwarded to the other endpoint
-at the next system call, thus restoring (in a selective way)
+When a ring is in 'transparent' mode,
+packets marked with this flag by the user application are forwarded to the
+other endpoint at the next system call, thus restoring (in a selective way)
 the connection between a NIC and the host stack.
 .It NS_NO_LEARN
 tells the forwarding code that the source MAC address for this
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index b69daf0a9..56c0782ee 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -370,8 +370,7 @@ struct netmap_zmon_list {
  * TX rings: hwcur + hwofs coincides with next_to_send
  *
  * For received packets, slot->flags is set to nkr_slot_flags
- * so we can provide a proper initial value (e.g. set NS_FORWARD
- * when operating in 'transparent' mode).
+ * so we can provide a proper initial value.
  *
  * The following fields are used to implement lock-free copy of packets
  * from input to output ports in VALE switch:

From acd7ac033c4e2eb7c66f556ebe1800d7046e3020 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 13 Dec 2017 16:08:31 +0100
Subject: [PATCH 0274/2207] drivers: remove unused nkr_slot_flags

---
 LINUX/forcedeth_netmap.h         | 4 +---
 LINUX/i40e_netmap_linux.h        | 8 +++-----
 LINUX/if_e1000_netmap.h          | 4 +---
 LINUX/if_e1000e_netmap.h         | 3 +--
 LINUX/if_igb_netmap.h            | 4 +---
 LINUX/if_re_netmap_linux.h       | 3 +--
 LINUX/ixgbe_netmap_linux.h       | 5 +----
 LINUX/virtio_netmap.h            | 3 +--
 sys/dev/netmap/if_em_netmap.h    | 4 +---
 sys/dev/netmap/if_igb_netmap.h   | 4 +---
 sys/dev/netmap/if_ixl_netmap.h   | 3 +--
 sys/dev/netmap/if_lem_netmap.h   | 4 +---
 sys/dev/netmap/if_re_netmap.h    | 3 +--
 sys/dev/netmap/if_vtnet_netmap.h | 3 +--
 sys/dev/netmap/ixgbe_netmap.h    | 3 +--
 sys/dev/netmap/netmap.c          | 2 +-
 sys/dev/netmap/netmap_generic.c  | 3 +--
 sys/dev/netmap/netmap_kern.h     | 2 --
 18 files changed, 19 insertions(+), 46 deletions(-)

diff --git a/LINUX/forcedeth_netmap.h b/LINUX/forcedeth_netmap.h
index 0fcb3923c..8ffa1a65c 100644
--- a/LINUX/forcedeth_netmap.h
+++ b/LINUX/forcedeth_netmap.h
@@ -242,8 +242,6 @@ forcedeth_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	rmb();
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = np->get_rx.ex - rxr; /* next pkt to check */
 		/* put_rx is the refill position, one before nr_hwcur.
 		 * This slot is not available
@@ -257,7 +255,7 @@ forcedeth_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (statlen & NV_RX2_AVAIL) /* still owned by the NIC */
 				break;
 			ring->slot[nm_i].len = statlen & LEN_MASK_V2; // XXX crc?
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			// ifp->stats.rx_packets++;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index cca07e369..70697052a 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -480,8 +480,6 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	if (netmap_no_pendintr || force_update) {
 		int crclen = ix_crcstrip ? 0 : 4;
-		uint16_t slot_flags = kring->nkr_slot_flags;
-		uint16_t curr_slot_flag;
 
 		nic_i = rxr->next_to_clean; // or also k2n(kring->nr_hwtail)
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -491,6 +489,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			uint64_t qword = le64toh(curr->wb.qword1.status_error_len);
 			uint32_t staterr = (qword & I40E_RXD_QW1_STATUS_MASK)
 				 >> I40E_RXD_QW1_STATUS_SHIFT;
+		        uint16_t slot_flags = 0;
 
 			if ((staterr & (1<slot[nm_i].len = ((qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
 			    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - crclen;
 
-			curr_slot_flag = slot_flags;
 			if (unlikely((staterr & (1<slot[nm_i].flags = curr_slot_flag;
+			ring->slot[nm_i].flags = slot_flags;
 
 			//bus_dmamap_sync(rxr->ptag,
 			//    rxr->buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index b88e42246..3479682af 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -210,8 +210,6 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -222,7 +220,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			ring->slot[nm_i].len = le16toh(curr->length) - 4;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index e6dea798f..19e1fcb06 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -235,7 +235,6 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
 		int strip_crc = (adapter->flags2 & FLAG2_CRC_STRIPPING) ? 0 : 4;
 
 		nic_i = rxr->next_to_clean;
@@ -248,7 +247,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			ring->slot[nm_i].len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 817c63d11..7f4e82027 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -233,8 +233,6 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -246,7 +244,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
diff --git a/LINUX/if_re_netmap_linux.h b/LINUX/if_re_netmap_linux.h
index fdbe46e99..3420e0248 100644
--- a/LINUX/if_re_netmap_linux.h
+++ b/LINUX/if_re_netmap_linux.h
@@ -198,7 +198,6 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * is to stop right before nm_hwcur.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
 		uint32_t stop_i = nm_prev(kring->nr_hwcur, lim);
 
 		nic_i = sc->cur_rx; /* next pkt to check */
@@ -215,7 +214,7 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 			/* XXX subtract crc */
 			total_len = (total_len < 4) ? 0 : total_len - 4;
 			ring->slot[nm_i].len = total_len;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			// ifp->stats.rx_packets++;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 36904dbe4..6e62a7921 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -516,8 +516,6 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * rxr->next_to_clean is set to 0 on a ring reinit
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -530,8 +528,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 				break;
 
 			ring->slot[nm_i].len = size;
-			ring->slot[nm_i].flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG |
-										slot_flags:slot_flags);
+			ring->slot[nm_i].flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index f0e4f23e1..c68355690 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -520,7 +520,6 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	if (netmap_no_pendintr || force_update) {
 		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
-		uint16_t slot_flags = kring->nkr_slot_flags;
 		struct netmap_adapter *token;
 
 
@@ -547,7 +546,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 				}
 
 				ring->slot[nm_i].len = len;
-				ring->slot[nm_i].flags = slot_flags;
+				ring->slot[nm_i].flags = 0;
 				nm_i = nm_next(nm_i, lim);
 				n++;
 			}
diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index 5a66f0e04..bf3d432c3 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -233,8 +233,6 @@ em_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = rxr->next_to_check;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -245,7 +243,7 @@ em_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			bus_dmamap_sync(rxr->rxtag, rxr->rx_buffers[nic_i].map,
 				BUS_DMASYNC_POSTREAD);
 			nm_i = nm_next(nm_i, lim);
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index 884785f71..4d2a1f9a9 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -215,8 +215,6 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = rxr->next_to_check;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -227,7 +225,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			bus_dmamap_sync(rxr->ptag,
 			    rxr->rx_buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
 			nm_i = nm_next(nm_i, lim);
diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h
index 14f21e938..48369aa02 100644
--- a/sys/dev/netmap/if_ixl_netmap.h
+++ b/sys/dev/netmap/if_ixl_netmap.h
@@ -331,7 +331,6 @@ ixl_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	if (netmap_no_pendintr || force_update) {
 		int crclen = ixl_crcstrip ? 0 : 4;
-		uint16_t slot_flags = kring->nkr_slot_flags;
 
 		nic_i = rxr->next_check; // or also k2n(kring->nr_hwtail)
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -346,7 +345,7 @@ ixl_netmap_rxsync(struct netmap_kring *kring, int flags)
 				break;
 			ring->slot[nm_i].len = ((qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
 			    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - crclen;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			bus_dmamap_sync(rxr->ptag,
 			    rxr->buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
 			nm_i = nm_next(nm_i, lim);
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index d8c590145..cd87dd483 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -214,8 +214,6 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
-
 		nic_i = adapter->next_rx_desc_to_check;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -232,7 +230,7 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags)
 				len = 0;
 			}
 			ring->slot[nm_i].len = len;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			bus_dmamap_sync(adapter->rxtag,
 				adapter->rx_buffer_area[nic_i].map,
 				BUS_DMASYNC_POSTREAD);
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index 28971cb7d..55f614c2b 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -199,7 +199,6 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * is to stop right before nm_hwcur.
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
 		uint32_t stop_i = nm_prev(kring->nr_hwcur, lim);
 
 		nic_i = sc->rl_ldata.rl_rx_prodidx; /* next pkt to check */
@@ -216,7 +215,7 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 			/* XXX subtract crc */
 			total_len = (total_len < 4) ? 0 : total_len - 4;
 			ring->slot[nm_i].len = total_len;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			/*  sync was in re_newbuf() */
 			bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
 			    rxd[nic_i].rx_dmamap, BUS_DMASYNC_POSTREAD);
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 02eeb8d9d..292e0c94b 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -301,7 +301,6 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * and vtnet_netmap_init_buffers().
 	 */
 	if (netmap_no_pendintr || force_update) {
-		uint16_t slot_flags = kring->nkr_slot_flags;
                 struct netmap_adapter *token;
 
                 nm_i = kring->nr_hwtail;
@@ -313,7 +312,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
                                 break;
                         if (likely(token == (void *)rxq)) {
                             ring->slot[nm_i].len = len;
-                            ring->slot[nm_i].flags = slot_flags;
+                            ring->slot[nm_i].flags = 0;
                             nm_i = nm_next(nm_i, lim);
                             n++;
                         } else {
diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h
index ddfed4a44..2a581b490 100644
--- a/sys/dev/netmap/ixgbe_netmap.h
+++ b/sys/dev/netmap/ixgbe_netmap.h
@@ -395,7 +395,6 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	if (netmap_no_pendintr || force_update) {
 		int crclen = (ix_crcstrip || IXGBE_IS_VF(adapter) ) ? 0 : 4;
-		uint16_t slot_flags = kring->nkr_slot_flags;
 
 		nic_i = rxr->next_to_check; // or also k2n(kring->nr_hwtail)
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -407,7 +406,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & IXGBE_RXD_STAT_DD) == 0)
 				break;
 			ring->slot[nm_i].len = le16toh(curr->wb.upper.length) - crclen;
-			ring->slot[nm_i].flags = slot_flags;
+			ring->slot[nm_i].flags = 0;
 			bus_dmamap_sync(rxr->ptag,
 			    rxr->rx_buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
 			nm_i = nm_next(nm_i, lim);
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index cfd0744cb..7a6a6d0e7 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1299,7 +1299,7 @@ netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
                                 D("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
 
 			slot->len = len;
-			slot->flags = kring->nkr_slot_flags;
+			slot->flags = 0;
 			nm_i = nm_next(nm_i, lim);
 			mbq_enqueue(&fq, m);
 		}
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index bc1b84a8b..b2f0227a7 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1015,7 +1015,6 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags)
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
 
 	/* Adapter-specific variables. */
-	uint16_t slot_flags = kring->nkr_slot_flags;
 	u_int nm_buf_len = NETMAP_BUF_SIZE(na);
 	struct mbq tmpq;
 	struct mbuf *m;
@@ -1094,7 +1093,7 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags)
 			avail -= nm_buf_len;
 
 			ring->slot[nm_i].len = copy;
-			ring->slot[nm_i].flags = slot_flags | (mlen ? NS_MOREFRAG : 0);
+			ring->slot[nm_i].flags = (mlen ? NS_MOREFRAG : 0);
 			nm_i = nm_next(nm_i, lim);
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 56c0782ee..6ac84fd96 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -441,8 +441,6 @@ struct netmap_kring {
 	 */
 	int32_t		nkr_hwofs;
 
-	uint16_t	nkr_slot_flags;	/* initial value for flags */
-
 	/* last_reclaim is opaque marker to help reduce the frequency
 	 * of operations such as reclaiming tx buffers. A possible use
 	 * is set it to ticks and do the reclaim only once per tick.

From a107f48383c35535aadb318beb0342c387cc4af4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 14 Dec 2017 10:10:06 +0100
Subject: [PATCH 0275/2207] mem finalize: propagate errors of netmap_mem_map()

This fixes some of the bugs in #345.
---
 sys/dev/netmap/netmap_mem2.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 64296fa0a..544c1cdf0 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -291,7 +291,7 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	}
 
 	if (!nmd->lasterr && na->pdev)
-		netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
+		nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
 
 	return nmd->lasterr;
 }
@@ -1464,8 +1464,10 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 
 	ND("allocating physical lut for %s", na->name);
 	lut->plut = nm_alloc_plut(lim);
-	if (lut->plut == NULL)
+	if (lut->plut == NULL) {
+		D("Failed to allocate physical lut for %s", na->name);
 		return ENOMEM;
+        }
 
 	for (i = 0; i < lim; i += p->_clustentries) {
 		int j;

From edd4b3668847b4dc8aaaba14a93af539dac4b00a Mon Sep 17 00:00:00 2001
From: Dusan Cerhaty 
Date: Thu, 14 Dec 2017 10:01:08 +0000
Subject: [PATCH 0276/2207] mem: fix unloading of dma mappings

This resolves issue #407.
---
 LINUX/netmap_linux.c         | 1 +
 sys/dev/netmap/netmap_kern.h | 4 +---
 sys/dev/netmap/netmap_mem2.c | 4 ++--
 3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 91477e331..ed8a71de9 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6ac84fd96..48864de9c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1666,10 +1666,8 @@ netmap_load_map(struct netmap_adapter *na,
 
 static inline void
 netmap_unload_map(struct netmap_adapter *na,
-	bus_dma_tag_t tag, bus_dmamap_t map)
+	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz)
 {
-	u_int sz = NETMAP_BUF_SIZE(na);
-
 	if (*map) {
 		dma_unmap_single(na->pdev, *map, sz,
 				 DMA_BIDIRECTIONAL);
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 544c1cdf0..c7e05639a 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1424,9 +1424,9 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	ND("unmapping and freeing plut for %s", na->name);
 	if (lut->plut == NULL)
 		return 0;
-	for (i = 2; i < lim; i += p->_clustentries) {
+	for (i = 0; i < lim; i += p->_clustentries) {
 		if (lut->plut[i].paddr)
-			netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr);
+			netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr, p->_clustsize);
 	}
 	nm_free_plut(lut->plut);
 	lut->plut = NULL;

From 95a1b1e56305554a454f22ae60f339418ece8917 Mon Sep 17 00:00:00 2001
From: Dusan Cerhaty 
Date: Thu, 14 Dec 2017 10:17:48 +0000
Subject: [PATCH 0277/2207] igb: sync dma rx buffers from device

Synchronize dma mapped buffers of RX rings for IGB driver only.

This resolves issue #409.
---
 LINUX/if_igb_netmap.h        |  8 ++++++--
 sys/dev/netmap/netmap_kern.h | 10 ++++++++++
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 7f4e82027..075789d45 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -240,11 +240,15 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			union e1000_adv_rx_desc *curr =
 					E1000_RX_DESC_ADV(*rxr, nic_i);
 			uint32_t staterr = le32toh(curr->wb.upper.status_error);
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t paddr;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
-			ring->slot[nm_i].len = le16toh(curr->wb.upper.length);
-			ring->slot[nm_i].flags = 0;
+			PNMB(na, slot, &paddr);
+			slot->len = le16toh(curr->wb.upper.length);
+			slot->flags = 0;
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, NETMAP_BUF_SIZE(na));
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 48864de9c..196bc06f8 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1674,6 +1674,16 @@ netmap_unload_map(struct netmap_adapter *na,
 	}
 }
 
+static inline void
+netmap_sync_map(struct netmap_adapter *na,
+	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz)
+{
+	if (*map) {
+		dma_sync_single_for_cpu(na->pdev, *map, sz,
+				DMA_FROM_DEVICE);
+	}
+}
+
 static inline void
 netmap_reload_map(struct netmap_adapter *na,
 	bus_dma_tag_t tag, bus_dmamap_t map, void *buf)

From b6bfb2ec2352cf77391017ed927006dfc4932c84 Mon Sep 17 00:00:00 2001
From: Dusan Cerhaty 
Date: Thu, 14 Dec 2017 12:08:50 +0000
Subject: [PATCH 0278/2207] mem/netmap_sync_map(): add enum txrx parameter

---
 LINUX/if_igb_netmap.h        | 2 +-
 sys/dev/netmap/netmap_kern.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 075789d45..21632b1fa 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -248,7 +248,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->wb.upper.length);
 			slot->flags = 0;
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, NETMAP_BUF_SIZE(na));
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 196bc06f8..c1bb513fe 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1676,7 +1676,7 @@ netmap_unload_map(struct netmap_adapter *na,
 
 static inline void
 netmap_sync_map(struct netmap_adapter *na,
-	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz)
+	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz, enum txrx t)
 {
 	if (*map) {
 		dma_sync_single_for_cpu(na->pdev, *map, sz,

From c3e629274bab0116666b0471e39f7c165994d754 Mon Sep 17 00:00:00 2001
From: Dusan Cerhaty 
Date: Thu, 14 Dec 2017 12:12:03 +0000
Subject: [PATCH 0279/2207] mem/netmap_sync_map(): fix compile on FreeBSD

---
 sys/dev/netmap/netmap_kern.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c1bb513fe..f5e3bc4d5 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1632,6 +1632,8 @@ netmap_unload_map(struct netmap_adapter *na,
 		bus_dmamap_unload(tag, map);
 }
 
+#define netmap_sync_map(na, tag, map, sz, t)
+
 /* update the map when a buffer changes. */
 static inline void
 netmap_reload_map(struct netmap_adapter *na,

From 1837ec7aaa60c80692385d5bd7bc0141cb0b73cb Mon Sep 17 00:00:00 2001
From: Dusan Cerhaty 
Date: Fri, 15 Dec 2017 12:24:27 +0000
Subject: [PATCH 0280/2207] mem/netmap_sync_map(): ability to sync dma memory
 for device also

From now, syncing of DMA mapped memory is now possible also from main memory to
device what is necessary in case of transmitting packets. The support is
currently integrated into IGB driver.
---
 LINUX/if_igb_netmap.h        | 1 +
 sys/dev/netmap/netmap_kern.h | 8 ++++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 21632b1fa..acd1fe72f 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -159,6 +159,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, NETMAP_BUF_SIZE(na), NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->read.buffer_addr = htole64(paddr);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f5e3bc4d5..23354f3ce 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1681,8 +1681,12 @@ netmap_sync_map(struct netmap_adapter *na,
 	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz, enum txrx t)
 {
 	if (*map) {
-		dma_sync_single_for_cpu(na->pdev, *map, sz,
-				DMA_FROM_DEVICE);
+		if (t == NR_RX)
+			dma_sync_single_for_cpu(na->pdev, *map, sz,
+					DMA_FROM_DEVICE);
+		else
+			dma_sync_single_for_device(na->pdev, *map, sz,
+					DMA_TO_DEVICE);
 	}
 }
 

From 9b86914b4751b5400b7155999ef9e871a877a6e7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Dec 2017 15:07:04 +0100
Subject: [PATCH 0281/2207] ixgbevf: fix unused vars warnings

---
 LINUX/ixgbe_netmap_linux.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 6e62a7921..31339cf8b 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -716,9 +716,12 @@ ixgbe_netmap_krings_delete(struct netmap_adapter *na)
 static int
 ixgbe_netmap_krings_create(struct netmap_adapter *na)
 {
+#ifndef NM_IXGBE_USE_TDH
 	struct netmap_ixgbe_adapter *ina =
 		(struct netmap_ixgbe_adapter *)na;
-	int i, ret;
+	int i;
+#endif /* !NM_IXGBE_USE_TDH */
+        int ret;
        
 	ret = netmap_hw_krings_create(na);
 	if (ret)

From 382825854a21a597482b8db1479029272007b345 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Dec 2017 12:53:31 +0100
Subject: [PATCH 0282/2207] linux: configure: add probe for UDP fragmentation
 offload (UFO)

---
 LINUX/configure | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 7d40f8a21..5322f24cb 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1436,6 +1436,16 @@ EOF
 	}
 EOF
 
+  # kernels from 4.14 onwards don't have support for UDP fragmentation
+  # offload.
+  add_test 'have UFO' <
+
+	unsigned int
+	dummy(void) {
+                return NETIF_F_UFO;
+	}
+EOF
 
   #####################################################
   # checks related to drivers                         #

From f22bdac0387d3249baa83d56b7df56d3ad4a3c9d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Dec 2017 12:58:23 +0100
Subject: [PATCH 0283/2207] linux: ptnet: add conditiona code for UFO

---
 LINUX/netmap_ptnet.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index fe7a74259..3907013cc 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -260,8 +260,10 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 			vh->hdr.gso_size = skb_shinfo(skb)->gso_size;
 			if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
 				vh->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+#ifdef NETMAP_LINUX_HAVE_UFO
 			} else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) {
 				vh->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP;
+#endif /* NETMAP_LINUX_HAVE_UFO */
 			} else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
 				vh->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
 			}
@@ -636,10 +638,11 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 			case VIRTIO_NET_HDR_GSO_TCPV4:
 				skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 				break;
-
+#ifdef NETMAP_LINUX_HAVE_UFO
 			case VIRTIO_NET_HDR_GSO_UDP:
 				skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
 				break;
+#endif /* NETMAP_LINUX_HAVE_UFO */
 
 			case VIRTIO_NET_HDR_GSO_TCPV6:
 				skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
@@ -1449,7 +1452,9 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 		if (ptnet_gso) {
 			hw_features |= NETIF_F_TSO
+#ifdef NETMAP_LINUX_HAVE_UFO
 				       | NETIF_F_UFO
+#endif /* NETMAP_LINUX_HAVE_UFO */
 				       | NETIF_F_TSO_ECN
 				       | NETIF_F_TSO6;
 			netdev->features |= NETIF_F_GSO_ROBUST;

From 357d50d5c23cf88f3a7e0fc6db28faeeb1543665 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Dec 2017 12:59:00 +0100
Subject: [PATCH 0284/2207] travis: add support for 4.14 kernels

---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index c2fc69a9d..d48092739 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,6 +37,7 @@ env:
   - KERNEL_VERSION=4.11  ARCH=x86_64
   - KERNEL_VERSION=4.12  ARCH=x86_64
   - KERNEL_VERSION=4.13  ARCH=x86_64
+  - KERNEL_VERSION=4.14  ARCH=x86_64
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"

From 125dcf033a3bceef0fed70c5c2f6d8a783db390d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Dec 2017 16:35:45 +0100
Subject: [PATCH 0285/2207] linux: i40e: remove redundant check

---
 LINUX/i40e_netmap_linux.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 70697052a..25a1cb7a3 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -457,8 +457,6 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 	if (head > lim)
 		return netmap_ring_reinit(kring);
 
-	if (!rxr)
-		return ENXIO;
 	/* XXX check sync modes */
 	//bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
 	//		BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);

From 54c1b6bdbf1c902bf383f112693841012f4fe7fb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Dec 2017 21:52:19 +0100
Subject: [PATCH 0286/2207] linux: i40e: check for rxr->desc or txr->desc being
 NULL

---
 LINUX/i40e_netmap_linux.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 25a1cb7a3..b65ee4c59 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -308,8 +308,10 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 		return 0;
 
 	txr = NM_I40E_TX_RING(vsi, kring->ring_id);
-	if (!txr)
+	if (unlikely(!txr || !txr->desc)) {
+		D("ring %s is missing (txr=%p)", kring->name, txr);
 		return ENXIO;
+	}
 	//bus_dmamap_sync(txr->dma.tag, txr->dma.map,
 	//		BUS_DMASYNC_POSTREAD);
 
@@ -451,8 +453,10 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 		return 0;
        
 	rxr = NM_I40E_RX_RING(vsi, kring->ring_id);
-	if (!rxr)
+	if (unlikely(!rxr || !rxr->desc)) {
+		D("ring %s is missing (rxr=%p)", kring->name, rxr);
 		return ENXIO;
+	}
 
 	if (head > lim)
 		return netmap_ring_reinit(kring);

From 6dbd0e85efd2d48a7e46e0969af27eaf6c0d6c4d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Dec 2017 22:48:57 +0100
Subject: [PATCH 0287/2207] linux: i40e: rate limit missing ring error

---
 LINUX/i40e_netmap_linux.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index b65ee4c59..4f356e9a2 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -309,7 +309,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 
 	txr = NM_I40E_TX_RING(vsi, kring->ring_id);
 	if (unlikely(!txr || !txr->desc)) {
-		D("ring %s is missing (txr=%p)", kring->name, txr);
+		RD(1, "ring %s is missing (txr=%p)", kring->name, txr);
 		return ENXIO;
 	}
 	//bus_dmamap_sync(txr->dma.tag, txr->dma.map,
@@ -454,7 +454,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
        
 	rxr = NM_I40E_RX_RING(vsi, kring->ring_id);
 	if (unlikely(!rxr || !rxr->desc)) {
-		D("ring %s is missing (rxr=%p)", kring->name, rxr);
+		RD(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
 		return ENXIO;
 	}
 

From e008e81aa73e113d18937fe37656c37a34897f2b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 19 Dec 2017 18:35:06 +0100
Subject: [PATCH 0288/2207] mem: fix cleanup after map error

---
 sys/dev/netmap/netmap_mem2.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c7e05639a..f7683ab38 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -290,8 +290,12 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 		NMA_UNLOCK(nmd);
 	}
 
-	if (!nmd->lasterr && na->pdev)
+	if (!nmd->lasterr && na->pdev) {
 		nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
+		if (nmd->lasterr) {
+			netmap_mem_deref(nmd, na);
+		}
+	}
 
 	return nmd->lasterr;
 }

From ea433fb1414d85d7501de298938635292b65a93b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 19 Dec 2017 23:43:39 +0100
Subject: [PATCH 0289/2207] linux/ixgbe: turn off debug message

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 31339cf8b..2cda8265d 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -404,7 +404,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
 		u32 h = ACCESS_ONCE(*ina->heads[ring_nr].phead);
-		RD(5, "%s: h %d", kring->name, h);
+		ND(5, "%s: h %d", kring->name, h);
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}
 #else /* NM_IXGBE_USE_TDH */

From 7db876aeb1ba4b301e7b49d08e02c4941472e14a Mon Sep 17 00:00:00 2001
From: Dusan Cerhaty 
Date: Wed, 20 Dec 2017 07:38:43 +0000
Subject: [PATCH 0290/2207] igb: pass size of packet when synchronizing DMA
 buffers

---
 LINUX/if_igb_netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index acd1fe72f..58926a5ea 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -159,7 +159,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, NETMAP_BUF_SIZE(na), NR_TX);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->read.buffer_addr = htole64(paddr);
@@ -249,7 +249,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->wb.upper.length);
 			slot->flags = 0;
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, NETMAP_BUF_SIZE(na), NR_RX);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}

From d5e6ca01446a690dcc436d4606ef81462c05119b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Dec 2017 19:34:35 +0100
Subject: [PATCH 0291/2207] linux/e1000: sync dma in tx and rx

---
 LINUX/if_e1000_netmap.h | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 3479682af..0d6977ff7 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -139,6 +139,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 				curr->buffer_addr = htole64(paddr);
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
@@ -216,11 +217,16 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 		for (n = 0; ; n++) {
 			struct e1000_rx_desc *curr = E1000_RX_DESC(*rxr, nic_i);
 			uint32_t staterr = le32toh(curr->status);
+			struct netmap_slot *slot;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
-			ring->slot[nm_i].len = le16toh(curr->length) - 4;
-			ring->slot[nm_i].flags = 0;
+
+			slot = ring->slot + nm_i;
+			slot->len = le16toh(curr->length) - 4;
+			slot->flags = 0;
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
+					&curr->buffer_addr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}

From 55521b3d5ce2f7820a1aeed86c01805707bc5e22 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 21 Dec 2017 09:21:41 +0100
Subject: [PATCH 0292/2207] linux: set physical address to 0 on dma mapping
 failure

---
 sys/dev/netmap/netmap_kern.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 23354f3ce..bf3ad8d1d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1660,8 +1660,10 @@ netmap_load_map(struct netmap_adapter *na,
 	if (map) {
 		*map = dma_map_single(na->pdev, buf, size,
 				      DMA_BIDIRECTIONAL);
-		if (dma_mapping_error(na->pdev, *map))
+		if (dma_mapping_error(na->pdev, *map)) {
+			*map = 0;
 			return ENOMEM;
+		}
 	}
 	return 0;
 }

From 5977b74536a72f8577d060223378b279c0275da5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 21 Dec 2017 10:19:27 +0100
Subject: [PATCH 0293/2207] linux: glue: clean up unused macros

---
 LINUX/bsd_glue.h | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 1ba8f13e3..e01a8f56e 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -398,17 +398,6 @@ struct nm_linux_selrecord_t;
 #define	cdev			miscdevice
 #define	cdevsw			miscdevice
 
-
-/*
- * XXX to complete - the dmamap interface
- */
-#define	BUS_DMA_NOWAIT	0
-#define	bus_dmamap_load(_1, _2, _3, _4, _5, _6, _7)
-#define	bus_dmamap_unload(_1, _2)
-
-typedef int (d_mmap_t)(struct file *f, struct vm_area_struct *vma);
-typedef unsigned int (d_poll_t)(struct file * file, struct poll_table_struct *pwait);
-
 /*
  * make_dev_credf() will set an error and return the first argument.
  * This relies on the availability of the 'error' local variable.

From 4fef56b4804e3a6ae3857ccd62e0ad29f7328d9a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 21 Dec 2017 10:40:43 +0100
Subject: [PATCH 0294/2207] linux: more cleanup on DMA mapping code

---
 sys/dev/netmap/netmap_kern.h | 65 +++++++++++++++---------------------
 1 file changed, 27 insertions(+), 38 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index bf3ad8d1d..c9908400c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1653,6 +1653,33 @@ netmap_reload_map(struct netmap_adapter *na,
 int nm_iommu_group_id(bus_dma_tag_t dev);
 #include 
 
+/*
+ * on linux we need
+ *	dma_map_single(&pdev->dev, virt_addr, len, direction)
+ *	dma_unmap_single(&adapter->pdev->dev, phys_addr, len, direction)
+ */
+#if 0
+	struct e1000_buffer *buffer_info =  &tx_ring->buffer_info[l];
+	/* set time_stamp *before* dma to help avoid a possible race */
+	buffer_info->time_stamp = jiffies;
+	buffer_info->mapped_as_page = false;
+	buffer_info->length = len;
+	//buffer_info->next_to_watch = l;
+	/* reload dma map */
+	dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
+			NETMAP_BUF_SIZE, DMA_TO_DEVICE);
+	buffer_info->dma = dma_map_single(&adapter->pdev->dev,
+			addr, NETMAP_BUF_SIZE, DMA_TO_DEVICE);
+
+	if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
+		D("dma mapping error");
+		/* goto dma_error; See e1000_put_txbuf() */
+		/* XXX reset */
+	}
+	tx_desc->buffer_addr = htole64(buffer_info->dma); //XXX
+
+#endif
+
 static inline int
 netmap_load_map(struct netmap_adapter *na,
 	bus_dma_tag_t tag, bus_dmamap_t map, void *buf, u_int size)
@@ -1707,44 +1734,6 @@ netmap_reload_map(struct netmap_adapter *na,
 				DMA_BIDIRECTIONAL);
 }
 
-/*
- * XXX How do we redefine these functions:
- *
- * on linux we need
- *	dma_map_single(&pdev->dev, virt_addr, len, direction)
- *	dma_unmap_single(&adapter->pdev->dev, phys_addr, len, direction
- * The len can be implicit (on netmap it is NETMAP_BUF_SIZE)
- * unfortunately the direction is not, so we need to change
- * something to have a cross API
- */
-
-#if 0
-	struct e1000_buffer *buffer_info =  &tx_ring->buffer_info[l];
-	/* set time_stamp *before* dma to help avoid a possible race */
-	buffer_info->time_stamp = jiffies;
-	buffer_info->mapped_as_page = false;
-	buffer_info->length = len;
-	//buffer_info->next_to_watch = l;
-	/* reload dma map */
-	dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
-			NETMAP_BUF_SIZE, DMA_TO_DEVICE);
-	buffer_info->dma = dma_map_single(&adapter->pdev->dev,
-			addr, NETMAP_BUF_SIZE, DMA_TO_DEVICE);
-
-	if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
-		D("dma mapping error");
-		/* goto dma_error; See e1000_put_txbuf() */
-		/* XXX reset */
-	}
-	tx_desc->buffer_addr = htole64(buffer_info->dma); //XXX
-
-#endif
-
-/*
- * The bus_dmamap_sync() can be one of wmb() or rmb() depending on direction.
- */
-#define bus_dmamap_sync(_a, _b, _c)
-
 #endif /* linux */
 
 

From f89a184326ae23da4b8349c58453c4788ffd6852 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 21 Dec 2017 13:41:36 +0100
Subject: [PATCH 0295/2207] avoid use-after-free on driver-module removal

By setting the NAF_ZOMBIE flag too early, we were preventing
the netmap adapter destructor from zeroing the NA(ifp) field,
causing a use-after-free later on.
---
 sys/dev/netmap/netmap.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7a6a6d0e7..951289450 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3088,15 +3088,14 @@ netmap_detach(struct ifnet *ifp)
 
 	NMG_LOCK();
 	netmap_set_all_rings(na, NM_KR_LOCKED);
-	na->na_flags |= NAF_ZOMBIE;
 	/*
 	 * if the netmap adapter is not native, somebody
 	 * changed it, so we can not release it here.
 	 * The NAF_ZOMBIE flag will notify the new owner that
 	 * the driver is gone.
 	 */
-	if (na->na_flags & NAF_NATIVE) {
-	        netmap_adapter_put(na);
+	if (!(na->na_flags & NAF_NATIVE) || !netmap_adapter_put(na)) {
+		na->na_flags |= NAF_ZOMBIE;
 	}
 	/* give active users a chance to notice that NAF_ZOMBIE has been
 	 * turned on, so that they can stop and return an error to userspace.

From 8fb45a7d80119dedbff5aa9cf08c028e3c9f76d7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 10:21:56 +0100
Subject: [PATCH 0296/2207] netmap_reset: don't return true when the ring is
 pending-off

---
 sys/dev/netmap/netmap.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 951289450..1e11e5591 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3236,14 +3236,14 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 
 		kring = na->tx_rings + n;
 
-		if (kring->nr_mode == NKR_NETMAP_ON)
-			return kring->ring->slot;
-
 		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
 			kring->nr_mode = NKR_NETMAP_OFF;
 			return NULL;
 		}
 
+		if (kring->nr_mode == NKR_NETMAP_ON)
+			return kring->ring->slot;
+
 		// XXX check whether we should use hwcur or rcur
 		new_hwofs = kring->nr_hwcur - new_cur;
 	} else {
@@ -3251,15 +3251,14 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 			return NULL;
 		kring = na->rx_rings + n;
 
-		if (kring->nr_mode == NKR_NETMAP_ON)
-			return kring->ring->slot;
-
-
 		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
 			kring->nr_mode = NKR_NETMAP_OFF;
 			return NULL;
 		}
 
+		if (kring->nr_mode == NKR_NETMAP_ON)
+			return kring->ring->slot;
+
 		new_hwofs = kring->nr_hwtail - new_cur;
 	}
 	lim = kring->nkr_num_slots - 1;

From 8ef4dfc57fc0871a72427699a82b039585d29263 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 10:46:03 +0100
Subject: [PATCH 0297/2207] linux/ixgbe: reset ring pointers only when leaving
 netmap mode

Before this patch we were resetting ring pointers also for rings that
were being used by the stack, thus causing all sort of problems.
---
 LINUX/ixgbe_netmap_linux.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 2cda8265d..046927b26 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -236,7 +236,7 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		struct netmap_kring *kring = &na->rx_rings[i];
 
-		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
+		if (nm_kring_pending_off(kring)) {
 			struct NM_IXGBE_RING *rxr = NM_IXGBE_RX_RING(adapter, i);
 
 			rxr->next_to_clean = 0;
@@ -250,7 +250,7 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 	for (i = 0; i < adapter->num_tx_queues; i++) {
 		struct netmap_kring *kring = &na->tx_rings[i];
 
-		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
+		if (nm_kring_pending_off(kring)) {
 			struct NM_IXGBE_RING *rxr = NM_IXGBE_TX_RING(adapter, i);
 
 			rxr->next_to_clean = 0;

From 5a224e051dcf351d4dda551c53a48c0f102600fb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 11:38:08 +0100
Subject: [PATCH 0298/2207] linux/e1000e: add proper dma sync in tx and rx

---
 LINUX/if_e1000e_netmap.h | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 19e1fcb06..1117c026a 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -161,8 +161,6 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
 			if (slot->flags & NS_BUF_CHANGED) {
-				/* buffer has changed, reload map */
-				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr)
 				curr->buffer_addr = htole64(paddr);
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
@@ -171,6 +169,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			curr->upper.data = 0;
 			curr->lower.data = htole32(adapter->txd_cmd | len | flags |
 				E1000_TXD_CMD_EOP);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -243,11 +242,16 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 		for (n = 0; ; n++) {
 			NM_E1K_RX_DESC_T *curr = E1000_RX_DESC_EXT(*rxr, nic_i);
 			uint32_t staterr = le32toh(curr->NM_E1R_RX_STATUS);
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t paddr;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
-			ring->slot[nm_i].len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
-			ring->slot[nm_i].flags = 0;
+			PNMB(na, slot, &paddr);
+			slot->len = le16toh(curr->wb.upper.length) - strip_crc;
+			slot->flags = 0;
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr,
+					slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -274,8 +278,6 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 				goto ring_reset;
 			curr->NM_E1R_RX_BUFADDR = htole64(paddr); /* reload ext.desc. addr. */
 			if (slot->flags & NS_BUF_CHANGED) {
-				/* buffer has changed, reload map */
-				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr)
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
 			curr->NM_E1R_RX_STATUS = 0;

From ef7d64ca56f0bae64df8447235bc8b8908ff5d83 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 11:44:25 +0100
Subject: [PATCH 0299/2207] linux/ixgbe: add proper dma sync in tx and rx

---
 LINUX/ixgbe_netmap_linux.h | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 046927b26..46e573147 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -372,10 +372,6 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
-			if (slot->flags & NS_BUF_CHANGED) {
-				/* buffer has changed, reload map */
-				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
-			}
 			if (!(slot->flags & NS_MOREFRAG))
 				flags |= IXGBE_TXD_CMD_EOP;
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
@@ -386,6 +382,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			curr->read.cmd_type_len = htole32(len | flags |
 				IXGBE_ADVTXD_DTYP_DATA | IXGBE_ADVTXD_DCMD_DEXT |
 				IXGBE_ADVTXD_DCMD_IFCS);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -523,12 +520,17 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(rxr, nic_i);
 			uint32_t staterr = le32toh(curr->wb.upper.status_error);
 			u_int size = le16toh(curr->wb.upper.length);
+			uint64_t paddr;
+			struct netmap_slot *slot = &ring->slot[nm_i];
 
 			if (!size)
 				break;
 
-			ring->slot[nm_i].len = size;
-			ring->slot[nm_i].flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
+			slot->len = size;
+			slot->flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
+			PNMB(na, slot, &paddr);
+			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, size, NR_RX);
+
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -560,8 +562,6 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 				goto ring_reset;
 
 			if (slot->flags & NS_BUF_CHANGED) {
-				/* buffer has changed, reload map */
-				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, addr);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
 			curr->wb.upper.length = 0;

From 0992dd598237c7bce797105407e9656917c8fe26 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 11:47:18 +0100
Subject: [PATCH 0300/2207] linux/e1000: use host endianess for sync'ed buf
 address

---
 LINUX/if_e1000_netmap.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 0d6977ff7..a7aff1853 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -218,15 +218,17 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			struct e1000_rx_desc *curr = E1000_RX_DESC(*rxr, nic_i);
 			uint32_t staterr = le32toh(curr->status);
 			struct netmap_slot *slot;
+			uint64_t paddr;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 
+			PNMB(na, slot, &paddr);
 			slot = ring->slot + nm_i;
 			slot->len = le16toh(curr->length) - 4;
 			slot->flags = 0;
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
-					&curr->buffer_addr, slot->len, NR_RX);
+					&paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}

From 7b54bc7bfde5bc94766c5ab296136ad577dd9ee5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 13:39:48 +0100
Subject: [PATCH 0301/2207] linux: build the kernel modules with debug symbols
 by default

Pass --no-force-debug to configure to disable.
---
 LINUX/configure     | 11 +++++++++++
 LINUX/netmap.mak.in |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 5322f24cb..0fc270a8f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -3,6 +3,7 @@
 BUILDDIR=$PWD
 SRCDIR=$(cd $(dirname $0); pwd)
 MODNAME=netmap
+DEBUG=1
 
 # setelem2n  
 setelem2n()
@@ -259,6 +260,7 @@ replace_vars()
 		-e "s|@APPS_LD@|$ld|g" \
 		-e "s|@PREFIX@|$prefix|g" \
 		-e "s|@DESTDIR@|$DESTDIR|g" \
+		-e "s|@DEBUG@|$DEBUG|g" \
 		$1
 }
 
@@ -299,6 +301,9 @@ Available options:
   --disable-ptnetmap           disable ptnetmap (both guest and host)
   --enable-sink   	       enable the netmap sink device
   --disable-sink   	       disable the netmap sink device
+  --force-debug	       	       build the modules w/ debug symbols (default)
+  --no-force-debug	       build the modules w/ or w/o debug symbols,
+  			       according to the kernel configuration
   --cache=		       dir for reusing/caching of netmap_linux_config.h
 
   --cc=                        C compiler to be used for the apps [$cc]
@@ -592,6 +597,12 @@ for opt do
 		app print
 		exit
 	;;
+	--force-debug)
+		DEBUG=1
+	;;
+	--no-force-debug)
+		DEBUG=
+	;;
 	*)
 		echo "Unrecognized option: $opt" | warning
 	;;
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 0adaf63bf..d593ce469 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -9,6 +9,7 @@ MODNAME:=@MODNAME@
 SUBSYS:=@SUBSYS@
 SRCDIR:=@SRCDIR@
 BUILDDIR:=@BUILDDIR@
+DEBUG:=@DEBUG@
 
 # The following commands are needed to build the modules as out-of-tree,
 # in fact the kernel sources path must be specified.
@@ -17,6 +18,7 @@ BUILDDIR:=@BUILDDIR@
 EXTRA_CFLAGS := -I$(BUILDDIR) -I$(SRCDIR) -I$(SRCDIR)/../sys -I$(SRCDIR)/../sys/dev -DCONFIG_NETMAP
 EXTRA_CFLAGS += -Wno-unused-but-set-variable
 EXTRA_CFLAGS += $(foreach s,$(SUBSYS),-DCONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_))
+EXTRA_CFLAGS += $(if $(DEBUG),-g)
 
 
 # We use KSRC for the kernel configuration and sources.

From 10777706aa34128d6544dcbebdb6319bfc67343a Mon Sep 17 00:00:00 2001
From: Juha-Matti Tilli 
Date: Fri, 22 Dec 2017 14:55:24 +0200
Subject: [PATCH 0302/2207] linux: promiscuous mode improvements to
 LINUX/README

Document that promiscuous mode may need to be turned on after starting
the netmap application. This may require temporarily turning off the
mode.
---
 LINUX/README | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/LINUX/README b/LINUX/README
index e48512ae3..97df34d78 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -258,6 +258,18 @@ COMMON PROBLEMS
 
       # ip link set eth0 promisc on
 
+  Some drivers (e.g. i40e with patched driver) may require the
+  promiscuous mode flag to be set after starting the application, not
+  before it. If the promiscuous mode flag is already on, you may need
+  to turn it off temporarily first. For such drivers, start the
+  application first, and then execute these commands:
+
+      # ip link set eth0 promisc off
+      # ip link set eth0 promisc on
+
+  When writing your own application, consider embedding system()
+  calls for these commands into your application.
+
 * if you are receiving VLAN-tagged packets, netmap applications (with
   patched drivers) may not see the VLAN tag because receive VLAN offloading
   is enabled (and so VLAN tags are stripped by the NIC). To disable it use

From 52a9b4cb37d66c2ae316cdd1e3429d8ee9934e19 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 22 Dec 2017 14:35:02 +0100
Subject: [PATCH 0303/2207] linux: README: some rephrasing

---
 LINUX/README | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/LINUX/README b/LINUX/README
index 97df34d78..015e75c39 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -258,17 +258,18 @@ COMMON PROBLEMS
 
       # ip link set eth0 promisc on
 
-  Some drivers (e.g. i40e with patched driver) may require the
-  promiscuous mode flag to be set after starting the application, not
-  before it. If the promiscuous mode flag is already on, you may need
-  to turn it off temporarily first. For such drivers, start the
+  Some drivers (e.g. the netmap-patched i40e) may disable promiscuous
+  mode during the down/up cycle that happens when putting the NIC
+  in netmap mode. This means that it may be necessary to enable
+  promiscuous mode again after starting the netmap application.
+  If the promiscuous mode was already enabled, you may need to
+  disable it before enabling it again. For these drivers, start the
   application first, and then execute these commands:
 
       # ip link set eth0 promisc off
       # ip link set eth0 promisc on
 
-  When writing your own application, consider embedding system()
-  calls for these commands into your application.
+  or incorporate equivalent operations in your application.
 
 * if you are receiving VLAN-tagged packets, netmap applications (with
   patched drivers) may not see the VLAN tag because receive VLAN offloading

From 1920bc1550422527aded2ddbd0b2e00ad3eb2554 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 14 Nov 2017 17:56:57 +0100
Subject: [PATCH 0304/2207] nm_open: do not ovverride nr_arg2 if not asked for

---
 sys/net/netmap_user.h | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index d08a220bd..5074b0b60 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -786,8 +786,7 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 
 	d->req.nr_flags |= nr_flags;
 	d->req.nr_ringid |= nr_ringid;
-	if (nr_arg2)
-		d->req.nr_arg2 = nr_arg2;
+	d->req.nr_arg2 = nr_arg2;
 
 	d->self = d;
 
@@ -856,10 +855,10 @@ nm_open(const char *ifname, const struct nmreq *req,
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 		d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
 			parent->req.nr_arg1 : 4;
-		if (new_flags & NM_OPEN_ARG2)
+		if (new_flags & NM_OPEN_ARG2) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
-		d->req.nr_arg2 = new_flags & NM_OPEN_ARG2 ?
-			parent->req.nr_arg2 : 0;
+			d->req.nr_arg2 =  parent->req.nr_arg2;
+		}
 		if (new_flags & NM_OPEN_ARG3)
 			D("overriding ARG3 %d", parent->req.nr_arg3);
 		d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?

From 714e188452ab798dde1ab3b53e0b0c6187440a6d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 17:31:22 +0100
Subject: [PATCH 0305/2207] linux/config: select external drivers versions
 during configure

---
 LINUX/README                 |  8 ++++++++
 LINUX/configure              | 23 ++++++++++++++++++++++-
 LINUX/default-config.mak.in_ | 16 ++++++++++------
 LINUX/netmap.mak.in          |  1 +
 LINUX/read-vars.mak          |  1 +
 5 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/LINUX/README b/LINUX/README
index 015e75c39..8ad4ab474 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -170,6 +170,14 @@ features, namely:
   (LOW included, HIGH excluded, so vanilla--r8169.c--20638--30300 applies
   from 2.6.38 to 3.3.0 (excluded).
 
+  The patches for the external drivers are named VENDOR--DRIVER--VERSION,
+  where VENDOR is just intel as of now, and VERSION is the upstream driver
+  version number (assigned by the VENDOR). If you want to use a different
+  VERSION than the default, and the patches directory contains a patch
+  for the version you are interest in, you can use the --select-version
+  option of configure. E.g., to select the 5.2.4 version of the ixgbe
+  external driver, pass --select-version=ixgbe:5.2.4 to configure.
+
 HOW TO USE THE CODE
 -------------------
 
diff --git a/LINUX/configure b/LINUX/configure
index 0fc270a8f..be2562909 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -281,6 +281,8 @@ Available options:
   --drivers=                   only compile the given drivers (comma sep.)
   --no-ext-drivers             do not use external drivers
   --no-ext-drivers=            do not use the given external drivers (comma sep.)
+  --select-version=	       comma sep. list of driver:version expressions
+  			       (select a different versions for external drivers)
   --no-apps	               do not compile any app
   --no-apps=                   do not compile the given apps (comma sep.)
   --apps=                      only compile the given apps (comma sep.)
@@ -421,7 +423,6 @@ EOF
 # run_tests: run all accumulated tests and exec the pertinent
 #   success/failure actions for each one.
 run_tests() {
-	cp $BUILDDIR/default-config.mak $TMPDIR
 	ln -s $BUILDDIR/patches $TMPDIR
 	cat > $TMPDIR/Makefile <> extdrv-versions.mak
+done
+
 replace_vars $SRCDIR/default-config.mak.in_ > default-config.mak
 
 
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index df26b6521..cfafc2f61 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -9,12 +9,16 @@ $(1)@distclean	:= rm -rf $(1)-$(2)
 $(1)@force	:= 1
 endef
 
-enabled_intel_driver = $(if $(filter $(1),$(E_DRIVERS)),$(eval $(call intel_driver,$(1),$(2))))
+define default
+$(1)@v := $(if $($(1)@v),$($(1)@v),$(2))
+endef
 
-$(call enabled_intel_driver,ixgbe,5.3.3)
-$(call enabled_intel_driver,ixgbevf,4.3.2)
 e1000e@cflags := -fno-pie
-$(call enabled_intel_driver,e1000e,3.3.6)
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
-$(call enabled_intel_driver,igb,5.3.5.12)
-$(call enabled_intel_driver,i40e,2.3.6)
+$(eval $(call default,ixgbe,5.3.3))
+$(eval $(call default,ixgbevf,4.3.2))
+$(eval $(call default,e1000e,3.3.6))
+$(eval $(call default,igb,5.3.5.12))
+$(eval $(call default,i40e,2.3.6))
+
+$(foreach d,$(E_DRIVERS),$(eval $(call intel_driver,$d,$($(d)@v))))
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index d593ce469..ce71bc972 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -76,6 +76,7 @@ all: $(S_DRIVERS:%=get-%) netmap.ko $(E_DRIVERS:%=build-%) apps
 netmap.ko:
 	$(MAKE) $(COMMON_OPTS) CONFIG_NETMAP=m $(MOD_LIST) O_DRIVERS="$(patsubst %.c,%.o,$(filter-out $(DRIVERS_EXT),$(DRIVERS)))" NETMAP_DRIVER_SUFFIX=$(DRVSUFFIX)
 
+-include extdrv-versions.mak
 -include default-config.mak
 -include config.mak
 -include drivers.mak
diff --git a/LINUX/read-vars.mak b/LINUX/read-vars.mak
index 4ef892d85..87088f312 100644
--- a/LINUX/read-vars.mak
+++ b/LINUX/read-vars.mak
@@ -1,3 +1,4 @@
+-include extdrv-versions.mak
 -include default-config.mak
 -include config.mak
 -include drivers.mak

From c25ac1a152c363cfac510b91c42ba85b52b606fe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 18:39:25 +0100
Subject: [PATCH 0306/2207] linux/scripts: uniform cache name for driver path

---
 LINUX/scripts/np | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 690421e78..68c44bc21 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -127,14 +127,14 @@ function driver-path()
 {
 	get-params "driver version" "$@"
 	
-	cat cache/$version/$driver/path 2>/dev/null && return
+	cat cache/$version/vanilla-$driver/path 2>/dev/null && return
 	local kern=$(get-kernel $version)
 	[ -z "$kern" ] && error "no such kernel version: $version"
-	mkdir -p cache/$version/$driver
+	mkdir -p cache/$version/vanilla-$driver
 	(
 		cd $kern
 		find drivers/net -name $driver
-	) | tee cache/$version/$driver/path
+	) | tee cache/$version/vanilla-$driver/path
 }
 
 

From b560afc428647f94c3c807a703b546b186c20449 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 18:49:31 +0100
Subject: [PATCH 0307/2207] linux/scripts: accept optional version for external
 drivers

---
 LINUX/final-patches/intel--ixgbe--5.3.4 | 171 ++++++++++++++++++++++++
 LINUX/scripts/np                        |   8 +-
 2 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.3.4

diff --git a/LINUX/final-patches/intel--ixgbe--5.3.4 b/LINUX/final-patches/intel--ixgbe--5.3.4
new file mode 100644
index 000000000..b9f3d73f6
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.3.4
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index a3cc895..a038975 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 7b18584..6bee72d 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -734,6 +734,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -752,6 +769,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2033,6 +2061,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3320,6 +3358,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3967,6 +4009,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11232,6 +11278,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11277,6 +11327,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 68c44bc21..175f6feb3 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -417,6 +417,9 @@ function check-patch()
 	local end=$(scripts/vers $_patch -s)
 	# extract the driver name
 	local driver=$(scripts/vers $_patch -s -p -p)
+	# possibly extract the selected driver version
+	driver_version=${driver#*:}
+	driver=${driver%%:*}
 	# extract the driver type (vanilla or external)
 	local dtype=$(scripts/vers $_patch -s -p -p -p)
 	local p=$(realpath $patch)
@@ -431,7 +434,7 @@ function check-patch()
 
 	while scripts/vers -b $v1 $v2 -L; do
 		# cache lookup
-		local cache=$PWD/cache/$v1/$dtype-$driver
+		local cache=$PWD/cache/$v1/$dtype-$driver${driver_version+:$driver_version}
 		mkdir -p $cache
 		local cpatch=$cache/patch
 		local cnmcommit=$cache/nmcommit
@@ -477,6 +480,9 @@ function check-patch()
 				rm -rf ext-drivers
 				ln -s $EXT_DRIVERS ext-drivers
 				ln -s final-patches patches
+				if [ -n "$driver_version" ]; then
+					config_opts="$config_opts --select-version=$driver:$driver_version"
+				fi
 			fi
 			if [ "$driver" != "veth.c" ]; then
 				config_opts="$config_opts --disable-pipe"

From ffcb1223e1a133779a665ef029bf7c1e194c7f14 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 20:24:33 +0100
Subject: [PATCH 0308/2207] linux/i40e: patch for Intel 2.4.3 version

---
 LINUX/final-patches/intel--i40e--2.4.3 | 154 +++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.4.3

diff --git a/LINUX/final-patches/intel--i40e--2.4.3 b/LINUX/final-patches/intel--i40e--2.4.3
new file mode 100644
index 000000000..19c245cd8
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.4.3
@@ -0,0 +1,154 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index ff50970..8d7f7fb 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -30,9 +30,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -46,13 +46,13 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 52a661a..0289012 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3280,6 +3285,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3361,6 +3370,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -10901,6 +10915,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -11269,6 +11288,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 0c949dd..c68df7d 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -26,6 +26,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -788,6 +792,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2386,6 +2395,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ 	bool failure = false;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 37d1c7cba2ea7d4e11af37d7dfb269a082d79ad1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Dec 2017 20:26:59 +0100
Subject: [PATCH 0309/2207] linux/e1000e: patch for Intel version 3.4.0.2

---
 LINUX/final-patches/intel--e1000e--3.4.0.2 | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.4.0.2

diff --git a/LINUX/final-patches/intel--e1000e--3.4.0.2 b/LINUX/final-patches/intel--e1000e--3.4.0.2
new file mode 100644
index 000000000..3650d58a8
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.4.0.2
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index c4558ce..b951433 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -36,7 +36,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -139,7 +139,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -345,6 +345,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index bfc6624..56a7d56 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -500,6 +500,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1023,6 +1027,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1340,6 +1355,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4253,6 +4273,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8449,6 +8473,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8550,6 +8578,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From c4ccececb47e51b994c3b6ec6f6e6cdefb41cb47 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Dec 2017 16:13:19 +0100
Subject: [PATCH 0310/2207] linux/igb: patch for Intel 5.3.5.15 version

---
 LINUX/final-patches/intel--igb--5.3.5.15 | 138 +++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.15

diff --git a/LINUX/final-patches/intel--igb--5.3.5.15 b/LINUX/final-patches/intel--igb--5.3.5.15
new file mode 100644
index 000000000..c01a0326f
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.15
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index e3bd4f3..eb59e33 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -46,19 +46,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -115,9 +115,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index f6faafc..11d8097 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * igb_init_module - Driver Registration Routine
+  *
+@@ -3061,6 +3065,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3264,6 +3272,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3672,6 +3684,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7226,6 +7241,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8240,6 +8260,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8558,6 +8583,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From ea973467a7624702b6acbba9b1e46e04fd3470a4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Dec 2017 12:23:44 +0100
Subject: [PATCH 0311/2207] linux/ixgbe: add missing barrier in rx path

---
 LINUX/bsd_glue.h           | 4 ++++
 LINUX/ixgbe_netmap_linux.h | 6 +++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index e01a8f56e..98aed6e96 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -63,6 +63,10 @@
 /*----- support for compiling on older versions of linux -----*/
 #include "netmap_linux_config.h"
 
+#ifndef dma_rmb
+#define dma_rmb() rmb()
+#endif /* dma_rmb */
+
 #ifdef NETMAP_LINUX_HAVE_PAGE_REF
 #include 
 #endif /* NETMAP_LINUX_HAVE_PAGE_REF */
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 46e573147..83932863c 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -518,7 +518,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 		for (n = 0; ; n++) {
 			union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(rxr, nic_i);
-			uint32_t staterr = le32toh(curr->wb.upper.status_error);
+			uint32_t staterr;
 			u_int size = le16toh(curr->wb.upper.length);
 			uint64_t paddr;
 			struct netmap_slot *slot = &ring->slot[nm_i];
@@ -526,6 +526,10 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (!size)
 				break;
 
+			dma_rmb();
+
+			staterr = le32toh(curr->wb.upper.status_error);
+
 			slot->len = size;
 			slot->flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			PNMB(na, slot, &paddr);

From 9be7ae00a0a991a911e17856d5a23b122fcffc92 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Dec 2017 13:06:47 +0100
Subject: [PATCH 0312/2207] linux/ixgbe: play nice with the ixgbe pointers

The netmap ixgbe driver reuses the next_to_clean pointers
also used by the original driver. With current versions of
the driver, this confuses ixgbe_down().

The previous code reset the pointers to sane values before
leaving netmap mode. This, however, missed the case when ixgbe_down()
is called while some rings are in still in netmap mode.

The current patch always keeps all the pointers updated. This removes
the need for the reset.
---
 LINUX/ixgbe_netmap_linux.h | 32 +++++---------------------------
 sys/dev/netmap/netmap.c    |  6 ------
 2 files changed, 5 insertions(+), 33 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 83932863c..c372475b1 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -225,39 +225,12 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 {
 	struct ifnet *ifp = na->ifp;
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
-	int i;
 
 	// adapter->netdev->trans_start = jiffies; // disable watchdog ?
 	/* protect against other reinit */
 	while (test_and_set_bit(NM_IXGBE_RESETTING, &adapter->state))
 		usleep_range(1000, 2000);
 
-	/* reset all next_to_* pointers before leaving netmap mode */
-	for (i = 0; i < adapter->num_rx_queues; i++) {
-		struct netmap_kring *kring = &na->rx_rings[i];
-
-		if (nm_kring_pending_off(kring)) {
-			struct NM_IXGBE_RING *rxr = NM_IXGBE_RX_RING(adapter, i);
-
-			rxr->next_to_clean = 0;
-			rxr->next_to_use = 0;
-#ifdef NETMAP_LINUX_HAVE_NTA
-			rxr->next_to_alloc = 0;
-#endif /* NETMAP_LINUX_HAVE_NTA */
-		}
-	}
-
-	for (i = 0; i < adapter->num_tx_queues; i++) {
-		struct netmap_kring *kring = &na->tx_rings[i];
-
-		if (nm_kring_pending_off(kring)) {
-			struct NM_IXGBE_RING *rxr = NM_IXGBE_TX_RING(adapter, i);
-
-			rxr->next_to_clean = 0;
-			rxr->next_to_use = 0;
-		}
-	}
-
 	if (netif_running(adapter->netdev))
 		NM_IXGBE_DOWN(adapter);
 
@@ -450,6 +423,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			nic_i -= kring->nkr_num_slots;
 		}
 		txr->next_to_clean = nic_i;
+		txr->next_to_use = txr->next_to_clean;
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
 	}
 #endif /* NM_IXGBE_USE_TDH */
@@ -540,6 +514,10 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
+			rxr->next_to_use = rxr->next_to_clean;
+#ifdef NETMAP_LINUX_IXGBE_HAVE_NTA
+			rxr->next_to_alloc = rxr->next_to_clean;
+#endif /* NETMAP_LINUX_HAVE_NTA */
 			kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1e11e5591..3ecf9f1c8 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3241,9 +3241,6 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 			return NULL;
 		}
 
-		if (kring->nr_mode == NKR_NETMAP_ON)
-			return kring->ring->slot;
-
 		// XXX check whether we should use hwcur or rcur
 		new_hwofs = kring->nr_hwcur - new_cur;
 	} else {
@@ -3256,9 +3253,6 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 			return NULL;
 		}
 
-		if (kring->nr_mode == NKR_NETMAP_ON)
-			return kring->ring->slot;
-
 		new_hwofs = kring->nr_hwtail - new_cur;
 	}
 	lim = kring->nkr_num_slots - 1;

From c0f2bfc415ee475ce55d8b9dca07a078fcebcef0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 30 Dec 2017 11:13:45 +0100
Subject: [PATCH 0313/2207] linux: skip kring notifications within netmap_poll

These notifications where added to support several threads listening on
the same netmap rings. Since commit 11f0c031, however, the notifications
may target the current thread. This confuses linux do_poll(), which may
enter an infinite loop as a result. The actual occurrence of the loop
depends on several things, including the kernel version and the way the
netmap port was opened.

It is not clear whether the use case that motivated these notifications
has actually ever worked on linux. Either way, I am killing them for now.
---
 sys/dev/netmap/netmap.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3ecf9f1c8..93bb29130 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2688,7 +2688,9 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 			if (found) { /* notify other listeners */
 				revents |= want_tx;
 				want_tx = 0;
+#ifndef linux
 				kring->nm_notify(kring, 0);
+#endif /* linux */
 			}
 		}
 		/* if there were any packet to forward we must have handled them by now */
@@ -2748,7 +2750,9 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 			if (found) {
 				revents |= want_rx;
 				retry_rx = 0;
+#ifndef linux
 				kring->nm_notify(kring, 0);
+#endif /* linux */
 			}
 		}
 

From 3415ba93f7d194e719d08c3253f35bb3327fe29b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 30 Dec 2017 12:10:26 +0100
Subject: [PATCH 0314/2207] linux/e1000: fix use of uninitialized slot

---
 LINUX/if_e1000_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index a7aff1853..45c8284ed 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -223,8 +223,8 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 
-			PNMB(na, slot, &paddr);
 			slot = ring->slot + nm_i;
+			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->length) - 4;
 			slot->flags = 0;
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev,

From 681f97f2a71aba285b88c488b5776f27304861fd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jan 2018 14:47:31 +0100
Subject: [PATCH 0315/2207] linux/ixgbe: patch for Intel 5.3.5 version

---
 LINUX/final-patches/intel--ixgbe--5.3.5 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.3.5

diff --git a/LINUX/final-patches/intel--ixgbe--5.3.5 b/LINUX/final-patches/intel--ixgbe--5.3.5
new file mode 100644
index 000000000..812b8b8b0
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.3.5
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index a3cc895..a038975 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 6c7e4cd..6e34fb1 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -734,6 +734,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -752,6 +769,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2033,6 +2061,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3320,6 +3358,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3967,6 +4009,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11232,6 +11278,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11277,6 +11327,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 235ef92952ed61e1ddecdecf52ee4d84ed3e7810 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jan 2018 14:50:35 +0100
Subject: [PATCH 0316/2207] linux/ixgbevf: patch for Intel version 4.3.3

---
 LINUX/final-patches/intel--ixgbevf--4.3.3 | 177 ++++++++++++++++++++++
 1 file changed, 177 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.3.3

diff --git a/LINUX/final-patches/intel--ixgbevf--4.3.3 b/LINUX/final-patches/intel--ixgbevf--4.3.3
new file mode 100644
index 000000000..4933a3ab2
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.3.3
@@ -0,0 +1,177 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index ca79ef6..939f185 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index e50d8ae..2eb1e3e 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1192,6 +1220,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1825,6 +1863,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1835,7 +1877,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+- 
++
+ /**
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+@@ -2012,6 +2054,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4969,8 +5015,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5010,6 +5058,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 71c5d93..97d2b32 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From e77b8923bd53c5eb3146393bf636113e0b83a306 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 12 Jan 2018 15:34:09 +0100
Subject: [PATCH 0317/2207] NS_MOREFRAG: fix documentation

---
 sys/net/netmap.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 4ac4f92e3..a85bb3004 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -215,7 +215,8 @@ struct netmap_slot {
 
 #define	NS_MOREFRAG	0x0020	/* packet has more fragments */
  	/*
-	 * (VALE ports only)
+	 * (VALE ports, ptnetmap ports and some NIC ports, e.g.
+         * ixgbe and i40e on Linux)
 	 * Set on all but the last slot of a multi-segment packet.
 	 * The 'len' field refers to the individual fragment.
 	 */

From 9075f4ac1ae48b57e4314d68e1a78954532001cd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Jan 2018 20:30:49 +0100
Subject: [PATCH 0318/2207] netmap_mem_map: zero out physical plut to deal with
 DMA mapping errors

Fixes #70.
---
 sys/dev/netmap/netmap_mem2.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f7683ab38..d1629db4d 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1473,6 +1473,10 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 		return ENOMEM;
         }
 
+	for (i = 0; i < lim; i += p->_clustentries) {
+		lut->plut[i].paddr = 0;
+	}
+
 	for (i = 0; i < lim; i += p->_clustentries) {
 		int j;
 

From f0729ac3b3d1dc0d7a8c53267c6534a17579abdd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Jan 2018 19:41:35 +0100
Subject: [PATCH 0319/2207] ptnetmap: split CSB to let host and guest write on
 different cachelines

---
 LINUX/netmap_ptnet.c         | 150 +++++++++++++++---------------
 sys/dev/netmap/if_ptnet.c    |   3 +-
 sys/dev/netmap/netmap_kern.h |  21 +++--
 sys/dev/netmap/netmap_pt.c   | 172 ++++++++++++++++++-----------------
 sys/net/netmap_virt.h        |  39 ++++----
 5 files changed, 193 insertions(+), 192 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 3907013cc..f3143419b 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -57,7 +57,8 @@ struct ptnet_info;
 /* Per-ring data structure. */
 struct ptnet_queue {
 	struct ptnet_info *pi;
-	struct ptnet_ring *ptring;
+	struct ptnet_gh_ring *ptgh;
+	struct ptnet_hg_ring *pthg;
 	int kring_id;
 	u8* __iomem kick;
 
@@ -105,7 +106,9 @@ struct ptnet_info {
 
 	/* CSB memory to be used for producer/consumer state
 	 * synchronization. */
-	struct ptnet_csb *csb;
+	struct page *csb_pages;
+	struct ptnet_gh_ring *csb_gh;
+	struct ptnet_hg_ring *csb_hg;
 
 	int min_tx_slots;
 
@@ -130,7 +133,7 @@ hang_tmr_callback(unsigned long arg)
 	pr_info("PTNET HANG RX#%d: hwc %u h %u c %u hwt %u t %u"
 		" rx.guest_need_kick %u\n",
 		kring->ring_id, kring->nr_hwcur, ring->head, ring->cur,
-		kring->nr_hwtail, ring->tail, prq->q.ptring->guest_need_kick);
+		kring->nr_hwtail, ring->tail, prq->q.ptgh->guest_need_kick);
 
 	if (mod_timer(&prq->hang_timer,
 		      jiffies + msecs_to_jiffies(HANG_INTVAL_MS))) {
@@ -140,12 +143,12 @@ hang_tmr_callback(unsigned long arg)
 #endif
 
 static inline void
-ptnet_sync_tail(struct ptnet_ring *ptring, struct netmap_kring *kring)
+ptnet_sync_tail(struct ptnet_hg_ring *pthg, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(ptring, kring);
+        ptnetmap_guest_read_kring_csb(pthg, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -213,7 +216,8 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	int queue_idx = skb_get_queue_mapping(skb);
 	struct ptnet_queue *pq = pi->queues[queue_idx];
-	struct ptnet_ring *ptring = pq->ptring;
+	struct ptnet_gh_ring *ptgh = pq->ptgh;
+	struct ptnet_hg_ring *pthg = pq->pthg;
 	struct netmap_kring *kring;
 	struct xmit_copy_args a;
 	int f;
@@ -227,7 +231,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 	/* Update hwcur and hwtail (completed TX slots) as known by the host,
 	 * by reading from CSB. */
-	ptnet_sync_tail(ptring, kring);
+	ptnet_sync_tail(pthg, kring);
 
 	if (unlikely(ptnet_tx_slots(a.ring) < pi->min_tx_slots)) {
 		ND(1, "TX ring unexpected overflow, requeuing");
@@ -320,13 +324,13 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	if (!XMIT_MORE(skb)) {
 		/* Tell the host to process the new packets, updating cur and
 		 * head in the CSB. */
-		ptnetmap_guest_write_kring_csb(ptring, kring->rcur,
+		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
 					       kring->rhead);
 	}
 
         /* Ask for a kick from a guest to the host if needed. */
-	if (NM_ACCESS_ONCE(ptring->host_need_kick)) {
-		ptring->sync_flags = NAF_FORCE_RECLAIM;
+	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
+		ptgh->sync_flags = NAF_FORCE_RECLAIM;
 		iowrite32(0, pq->kick);
 	}
 
@@ -334,14 +338,14 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	 * qdisc layer and enable notifications. */
 	if (ptnet_tx_slots(a.ring) < pi->min_tx_slots) {
 		netif_stop_subqueue(netdev, pq->kring_id);
-		ptring->guest_need_kick = 1;
+		ptgh->guest_need_kick = 1;
 
                 /* Double check. */
-		ptnet_sync_tail(ptring, kring);
+		ptnet_sync_tail(pthg, kring);
 		if (unlikely(ptnet_tx_slots(a.ring) >= pi->min_tx_slots)) {
 			/* More TX space came in the meanwhile. */
 			netif_start_subqueue(netdev, pq->kring_id);
-			ptring->guest_need_kick = 0;
+			ptgh->guest_need_kick = 0;
 		}
 	}
 
@@ -411,11 +415,11 @@ ptnet_napi_schedule(struct ptnet_queue *pq)
 	if (likely(napi_schedule_prep(&prq->napi))) {
 		/* It's good thing to reset rx.guest_need_kick as soon as
 		 * possible. */
-		pq->ptring->guest_need_kick = 0;
+		pq->ptgh->guest_need_kick = 0;
 		__napi_schedule(&prq->napi);
 	} else {
 		/* NAPI is already scheduled and we are ok with it. */
-		pq->ptring->guest_need_kick = 1;
+		pq->ptgh->guest_need_kick = 1;
 	}
 }
 
@@ -472,7 +476,8 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 	struct ptnet_rx_queue *prq = container_of(napi, struct ptnet_rx_queue,
 					          napi);
 	struct ptnet_queue *pq = (struct ptnet_queue *)prq;
-	struct ptnet_ring *ptring = pq->ptring;
+	struct ptnet_gh_ring *ptgh = pq->ptgh;
+	struct ptnet_hg_ring *pthg = pq->pthg;
 	struct ptnet_info *pi = pq->pi;
 	struct netmap_adapter *na = &pi->ptna->dr.up;
 	struct netmap_kring *kring = &na->rx_rings[pq->kring_id];
@@ -499,7 +504,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 
 	/* Update hwtail, rtail, tail and hwcur to what is known from the host,
 	 * reading from CSB. */
-	ptnet_sync_tail(ptring, kring);
+	ptnet_sync_tail(pthg, kring);
 
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
@@ -696,7 +701,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		/* Budget was not fully consumed, since we have no more
 		 * completed RX slots. We can enable notifications and
 		 * exit polling mode. */
-                ptring->guest_need_kick = 1;
+                ptgh->guest_need_kick = 1;
 #ifdef NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE
 		napi_complete_done(napi, work_done);
 #else
@@ -704,7 +709,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 #endif
 
                 /* Double check for more completed RX slots. */
-		ptnet_sync_tail(ptring, kring);
+		ptnet_sync_tail(pthg, kring);
 		if (head != ring->tail) {
 			/* If there is more work to do, disable notifications
 			 * and reschedule. */
@@ -725,11 +730,11 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		ring->head = ring->cur = head;
 		kring->rcur = ring->cur;
 		kring->rhead = ring->head;
-		ptnetmap_guest_write_kring_csb(ptring, kring->rcur,
+		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
 					       kring->rhead);
 		/* Kick the host if needed. */
-		if (NM_ACCESS_ONCE(ptring->host_need_kick)) {
-			ptring->sync_flags = NAF_FORCE_READ;
+		if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
+			ptgh->sync_flags = NAF_FORCE_READ;
 			iowrite32(0, pq->kick);
 		}
 	}
@@ -1046,7 +1051,8 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < pi->num_rings; i++) {
-		struct ptnet_ring *ptring = pi->queues[i]->ptring;
+		struct ptnet_gh_ring *ptgh = pi->queues[i]->ptgh;
+		struct ptnet_hg_ring *pthg = pi->queues[i]->pthg;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1054,15 +1060,15 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings + i - na->num_tx_rings;
 		}
-		kring->rhead = kring->ring->head = ptring->head;
-		kring->rcur = kring->ring->cur = ptring->cur;
-		kring->nr_hwcur = ptring->hwcur;
+		kring->rhead = kring->ring->head = ptgh->head;
+		kring->rcur = kring->ring->cur = ptgh->cur;
+		kring->nr_hwcur = pthg->hwcur;
 		kring->nr_hwtail = kring->rtail =
-			kring->ring->tail = ptring->hwtail;
+			kring->ring->tail = pthg->hwtail;
 
 		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
-		   ptring->hwcur, ptring->head, ptring->cur,
-		   ptring->hwtail);
+		   pthg->hwcur, ptgh->head, ptgh->cur,
+		   pthg->hwtail);
 		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
@@ -1088,7 +1094,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	struct net_device *netdev = na->ifp;
 	struct ptnet_info *pi = netdev_priv(netdev);
 	int native = (na == &pi->ptna->hwup.up);
-	struct ptnet_ring *ptring;
+	struct ptnet_gh_ring *ptgh;
+	struct ptnet_hg_ring *pthg;
 	enum txrx t;
 	int ret = 0;
 	int i;
@@ -1109,8 +1116,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		pr_info("%s: Exit netmap mode, re-enable interrupts\n",
 			__func__);
 		for (i = 0; i < pi->num_rings; i++) {
-			ptring = pi->queues[i]->ptring;
-			ptring->guest_need_kick = 1;
+			ptgh = pi->queues[i]->ptgh;
+			ptgh->guest_need_kick = 1;
 		}
 		if (netif_running(netdev)) {
 			pr_info("%s: Exit netmap mode, schedule NAPI to flush RX ring\n",
@@ -1126,9 +1133,10 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		if (pi->ptna->backend_regifs == 0) {
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < pi->num_rings; i++) {
-				ptring = pi->queues[i]->ptring;
-				ptring->host_need_kick = 1;
-				ptring->guest_need_kick = (i >= pi->num_tx_rings);
+				ptgh = pi->queues[i]->ptgh;
+				pthg = pi->queues[i]->pthg;
+				ptgh->guest_need_kick = (i >= pi->num_tx_rings);
+				pthg->host_need_kick = 1;
 			}
 
 			/* Set the virtio-net header length. */
@@ -1221,7 +1229,7 @@ ptnet_nm_txsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = pi->queues[kring->ring_id];
 	bool notify;
 
-	notify = netmap_pt_guest_txsync(pq->ptring, kring, flags);
+	notify = netmap_pt_guest_txsync(pq->ptgh, pq->pthg, kring, flags);
 	if (notify) {
 		iowrite32(0, pq->kick);
 	}
@@ -1236,7 +1244,7 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = pi->rxqueues[kring->ring_id];
 	bool notify;
 
-	notify = netmap_pt_guest_rxsync(pq->ptring, kring, flags);
+	notify = netmap_pt_guest_rxsync(pq->ptgh, pq->pthg, kring, flags);
 	if (notify) {
 		iowrite32(0, pq->kick);
 	}
@@ -1252,7 +1260,7 @@ ptnet_nm_intr(struct netmap_adapter *na, int onoff)
 
 	for (i = 0; i < pi->num_rings; i++) {
 		struct ptnet_queue *pq = pi->queues[i];
-		pq->ptring->guest_need_kick = onoff;
+		pq->ptgh->guest_need_kick = onoff;
 	}
 }
 
@@ -1377,39 +1385,29 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		}
 	}
 
-#ifndef PTNET_CSB_ALLOC
-	/* Map the CSB memory exposed by the device. We don't use
-	 * pci_ioremap_bar(), since we want the ioremap_cache() function
-	 * to be called internally, rather than ioremap_nocache(). */
-	pr_info("%s: MEMORY BAR (CSB): start 0x%llx, len %llu, flags 0x%lx\n",
-		__func__, pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
-		pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR),
-		pci_resource_flags(pdev, PTNETMAP_MEM_PCI_BAR));
-	pi->csbaddr = ioremap_cache(pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
-				    pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR));
-	if (!pi->csbaddr)
-		goto err_csb;
-	pi->csb = (struct ptnet_csb *)pi->csbaddr;
-
-#else  /* PTNET_CSB_ALLOC */
-
 	/* Alloc the CSB here and tell the hypervisor its physical address. */
-	pi->csb = kzalloc(sizeof(struct ptnet_csb), GFP_KERNEL);
-	if (!pi->csb) {
+	pi->csb_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, 1);
+	if (pi->csb_pages == NULL) {
 		goto err_csb;
 	}
+	pi->csb_gh = page_address(pi->csb_pages);
+	pi->csb_hg = page_address(pi->csb_pages) + PAGE_SIZE;
 
 	{
-		phys_addr_t paddr = virt_to_phys(pi->csb);
+		/* CSB allocation protocol. Write to GH_BAH first, then
+		 * to GH_BAL. Same for HG_BAH and HG_BAL. */
+		phys_addr_t paddr = virt_to_phys(pi->csb_gh);
+		iowrite32((paddr >> 32) & 0xffffffff,
+				ioaddr + PTNET_IO_CSB_GH_BAH);
+		iowrite32(paddr & 0xffffffff,
+				ioaddr + PTNET_IO_CSB_GH_BAL);
 
-		/* CSB allocation protocol. Write CSBBAH first, then
-		 * CSBBAL. */
+		paddr = virt_to_phys(pi->csb_hg);
 		iowrite32((paddr >> 32) & 0xffffffff,
-			  ioaddr + PTNET_IO_CSBBAH);
+				ioaddr + PTNET_IO_CSB_HG_BAH);
 		iowrite32(paddr & 0xffffffff,
-			  ioaddr + PTNET_IO_CSBBAL);
+				ioaddr + PTNET_IO_CSB_HG_BAL);
 	}
-#endif /* PTNET_CSB_ALLOC */
 
 	/* Initialize common parts of all the queues (interrupt
 	 * setup excluded). */
@@ -1417,11 +1415,12 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		struct ptnet_queue *pq = pi->queues[i];
 		pq->pi = pi;
 		pq->kring_id = i;
-		pq->kick = ioaddr + PTNET_IO_KICK_BASE + 4 * i;
-		pq->ptring = pi->csb->rings + i;
 		if (i >= num_tx_rings) {
 			pq->kring_id -= num_tx_rings;
 		}
+		pq->kick = ioaddr + PTNET_IO_KICK_BASE + 4 * i;
+		pq->ptgh = pi->csb_gh + i;
+		pq->pthg = pi->csb_hg + i;
 	}
 
 	netdev->netdev_ops = &ptnet_netdev_ops;
@@ -1498,8 +1497,8 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	ptnet_nm_ops.num_rx_rings = num_rx_rings;
 	na_arg = ptnet_nm_ops;
 	na_arg.ifp = pi->netdev;
-	netmap_pt_guest_attach(&na_arg, pi->csb, nifp_offset,
-			        ioread32(ioaddr + PTNET_IO_HOSTMEMID));
+	netmap_pt_guest_attach(&na_arg, nifp_offset,
+				ioread32(ioaddr + PTNET_IO_HOSTMEMID));
 	/* Now a netmap adapter for this device has been allocated, and it
 	 * can be accessed through NA(ifp). We have to initialize the CSB
 	 * pointer. */
@@ -1520,13 +1519,8 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 err_netreg:
 	ptnet_irqs_fini(pi);
 err_irqs:
-#ifdef PTNET_CSB_ALLOC
-	kfree(pi->csb);
-#endif /* PTNET_CSB_ALLOC */
+	put_page(pi->csb_pages);
 err_csb:
-#ifndef PTNET_CSB_ALLOC
-	iounmap(pi->csbaddr);
-#endif  /* !PTNET_CSB_ALLOC */
 	free_netdev(netdev);
 err_ptfeat:
 	iounmap(ioaddr);
@@ -1573,13 +1567,11 @@ ptnet_remove(struct pci_dev *pdev)
 	ptnet_irqs_fini(pi);
 
 	iounmap(pi->ioaddr);
-#ifndef  PTNET_CSB_ALLOC
-	iounmap(pi->csbaddr);
-#else  /* !PTNET_CSB_ALLOC */
-	iowrite32(0, pi->ioaddr + PTNET_IO_CSBBAH);
-	iowrite32(0, pi->ioaddr + PTNET_IO_CSBBAL);
-	kfree(pi->csb);
-#endif /* !PTNET_CSB_ALLOC */
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAH);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAL);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAH);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAL);
+	put_page(pi->csb_pages);
 	pci_release_selected_regions(pdev, pi->bars);
 	free_netdev(netdev);
 	pci_disable_device(pdev);
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 7c3665e9c..42afea012 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -169,7 +169,8 @@ struct ptnet_softc {
 	unsigned int		num_tx_rings;
 	struct ptnet_queue	*queues;
 	struct ptnet_queue	*rxqueues;
-	struct ptnet_csb	*csb;
+	struct ptnet_gh_ring    *csb_gh;
+	struct ptnet_hg_ring    *csb_hg;
 
 	unsigned int		min_tx_space;
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c9908400c..0351bf492 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2148,8 +2148,6 @@ struct netmap_pt_guest_adapter {
         /* The netmap adapter to be used by the driver. */
         struct netmap_hw_adapter dr;
 
-	void *csb;
-
 	/* Reference counter to track users of backend netmap port: the
 	 * network stack and netmap clients.
 	 * Used to decide when we need (de)allocate krings/rings and
@@ -2158,13 +2156,18 @@ struct netmap_pt_guest_adapter {
 
 };
 
-int netmap_pt_guest_attach(struct netmap_adapter *na, void *csb,
-			   unsigned int nifp_offset, unsigned int memid);
-struct ptnet_ring;
-bool netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
-			    int flags);
-bool netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
-			    int flags);
+int netmap_pt_guest_attach(struct netmap_adapter *na,
+			unsigned int nifp_offset,
+			unsigned int memid);
+struct ptnet_gh_ring;
+struct ptnet_hg_ring;
+bool netmap_pt_guest_txsync(struct ptnet_gh_ring *ptgh,
+			struct ptnet_hg_ring *pthg,
+			struct netmap_kring *kring,
+			int flags);
+bool netmap_pt_guest_rxsync(struct ptnet_gh_ring *ptgh,
+			struct ptnet_hg_ring *pthg,
+			struct netmap_kring *kring, int flags);
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index dafdb4043..186a8d83c 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -169,18 +169,19 @@ rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail,
 #endif /* RATE */
 
 struct ptnetmap_state {
-    /* Kthreads. */
-    struct nm_kctx **kctxs;
+	/* Kthreads. */
+	struct nm_kctx **kctxs;
 
-    /* Shared memory with the guest (TX/RX) */
-    struct ptnet_ring __user *ptrings;
+	/* Shared memory with the guest (TX/RX) */
+	struct ptnet_gh_ring __user *csb_gh;
+	struct ptnet_hg_ring __user *csb_hg;
 
-    bool stopped;
+	bool stopped;
 
-    /* Netmap adapter wrapping the backend. */
-    struct netmap_pt_host_adapter *pth_na;
+	/* Netmap adapter wrapping the backend. */
+	struct netmap_pt_host_adapter *pth_na;
 
-    IFRATE(struct rate_context rate_ctx;)
+	IFRATE(struct rate_context rate_ctx;)
 };
 
 static inline void
@@ -200,27 +201,27 @@ ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring)
 
 /* Enable or disable guest --> host kicks. */
 static inline void
-ptring_kick_enable(struct ptnet_ring __user *ptring, uint32_t val)
+pthg_kick_enable(struct ptnet_hg_ring __user *pthg, uint32_t val)
 {
-    CSB_WRITE(ptring, host_need_kick, val);
+    CSB_WRITE(pthg, host_need_kick, val);
 }
 
 /* Are guest interrupt enabled or disabled? */
 static inline uint32_t
-ptring_intr_enabled(struct ptnet_ring __user *ptring)
+ptgh_intr_enabled(struct ptnet_gh_ring __user *ptgh)
 {
     uint32_t v;
 
-    CSB_READ(ptring, guest_need_kick, v);
+    CSB_READ(ptgh, guest_need_kick, v);
 
     return v;
 }
 
 /* Enable or disable guest interrupts. */
 static inline void
-ptring_intr_enable(struct ptnet_ring __user *ptring, uint32_t val)
+ptgh_intr_enable(struct ptnet_gh_ring __user *ptgh, uint32_t val)
 {
-    CSB_WRITE(ptring, guest_need_kick, val);
+    CSB_WRITE(ptgh, guest_need_kick, val);
 }
 
 /* Handle TX events: from the guest or from the backend */
@@ -231,7 +232,8 @@ ptnetmap_tx_handler(void *data, int is_kthread)
     struct netmap_pt_host_adapter *pth_na =
 		(struct netmap_pt_host_adapter *)kring->na->na_private;
     struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_ring __user *ptring;
+    struct ptnet_gh_ring __user *ptgh;
+    struct ptnet_hg_ring __user *pthg;
     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
     bool more_txspace = false;
     struct nm_kctx *kth;
@@ -257,8 +259,9 @@ ptnetmap_tx_handler(void *data, int is_kthread)
     /* This is a guess, to be fixed in the rate callback. */
     IFRATE(ptns->rate_ctx.new.gtxk++);
 
-    /* Get TX ptring pointer from the CSB. */
-    ptring = ptns->ptrings + kring->ring_id;
+    /* Get TX ptgh/pthg pointer from the CSB. */
+    ptgh = ptns->csb_gh + kring->ring_id;
+    pthg = ptns->csb_hg + kring->ring_id;
     kth = ptns->kctxs[kring->ring_id];
 
     num_slots = kring->nkr_num_slots;
@@ -266,9 +269,9 @@ ptnetmap_tx_handler(void *data, int is_kthread)
     shadow_ring.cur = kring->rcur;
 
     /* Disable guest --> host notifications. */
-    ptring_kick_enable(ptring, 0);
+    pthg_kick_enable(pthg, 0);
     /* Copy the guest kring pointers from the CSB */
-    ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
+    ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
 
     for (;;) {
 	/* If guest moves ahead too fast, let's cut the move so
@@ -299,7 +302,7 @@ ptnetmap_tx_handler(void *data, int is_kthread)
         if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
             /* Reinit ring and enable notifications. */
             netmap_ring_reinit(kring);
-            ptring_kick_enable(ptring, 1);
+            pthg_kick_enable(pthg, 1);
             break;
         }
 
@@ -310,7 +313,7 @@ ptnetmap_tx_handler(void *data, int is_kthread)
         IFRATE(pre_tail = kring->rtail);
         if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
             /* Reenable notifications. */
-            ptring_kick_enable(ptring, 1);
+            pthg_kick_enable(pthg, 1);
             D("ERROR txsync()");
 	    break;
         }
@@ -320,7 +323,7 @@ ptnetmap_tx_handler(void *data, int is_kthread)
          * Copy host hwcur and hwtail into the CSB for the guest sync(), and
 	 * do the nm_sync_finalize.
          */
-        ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur,
+        ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur,
 				      kring->nr_hwtail);
         if (kring->rtail != kring->nr_hwtail) {
 	    /* Some more room available in the parent adapter. */
@@ -337,16 +340,16 @@ ptnetmap_tx_handler(void *data, int is_kthread)
 
 #ifndef BUSY_WAIT
         /* Interrupt the guest if needed. */
-        if (more_txspace && ptring_intr_enabled(ptring) && is_kthread) {
+        if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
             /* Disable guest kick to avoid sending unnecessary kicks */
-            ptring_intr_enable(ptring, 0);
+            ptgh_intr_enable(ptgh, 0);
             nm_os_kctx_send_irq(kth);
             IFRATE(ptns->rate_ctx.new.htxk++);
             more_txspace = false;
         }
 #endif
         /* Read CSB to see if there is more work to do. */
-        ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
+        ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
 #ifndef BUSY_WAIT
         if (shadow_ring.head == kring->rhead) {
             /*
@@ -358,13 +361,13 @@ ptnetmap_tx_handler(void *data, int is_kthread)
                 usleep_range(1,1);
             }
             /* Reenable notifications. */
-            ptring_kick_enable(ptring, 1);
+            pthg_kick_enable(pthg, 1);
             /* Doublecheck. */
-            ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
+            ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
             if (shadow_ring.head != kring->rhead) {
 		/* We won the race condition, there are more packets to
 		 * transmit. Disable notifications and do another cycle */
-		ptring_kick_enable(ptring, 0);
+		pthg_kick_enable(pthg, 0);
 		continue;
 	    }
 	    break;
@@ -385,8 +388,8 @@ ptnetmap_tx_handler(void *data, int is_kthread)
 
     nm_kr_put(kring);
 
-    if (more_txspace && ptring_intr_enabled(ptring) && is_kthread) {
-        ptring_intr_enable(ptring, 0);
+    if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
+        ptgh_intr_enable(ptgh, 0);
         nm_os_kctx_send_irq(kth);
         IFRATE(ptns->rate_ctx.new.htxk++);
     }
@@ -411,7 +414,7 @@ ptnetmap_tx_nothread_notify(void *data)
 		return;
 	}
 
-	/* We cannot access the CSB here (to check ptring->guest_need_kick),
+	/* We cannot access the CSB here (to check ptgh->guest_need_kick),
 	 * unless we switch address space to the one of the guest. For now
 	 * we unconditionally inject an interrupt. */
         nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]);
@@ -440,7 +443,8 @@ ptnetmap_rx_handler(void *data, int is_kthread)
     struct netmap_pt_host_adapter *pth_na =
 		(struct netmap_pt_host_adapter *)kring->na->na_private;
     struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_ring __user *ptring;
+    struct ptnet_gh_ring __user *ptgh;
+    struct ptnet_hg_ring __user *pthg;
     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
     struct nm_kctx *kth;
     uint32_t num_slots;
@@ -467,8 +471,9 @@ ptnetmap_rx_handler(void *data, int is_kthread)
     /* This is a guess, to be fixed in the rate callback. */
     IFRATE(ptns->rate_ctx.new.grxk++);
 
-    /* Get RX ptring pointer from the CSB. */
-    ptring = ptns->ptrings + (pth_na->up.num_tx_rings + kring->ring_id);
+    /* Get RX ptgh and pthg pointers from the CSB. */
+    ptgh = ptns->csb_gh + (pth_na->up.num_tx_rings + kring->ring_id);
+    pthg = ptns->csb_hg + (pth_na->up.num_tx_rings + kring->ring_id);
     kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id];
 
     num_slots = kring->nkr_num_slots;
@@ -476,9 +481,9 @@ ptnetmap_rx_handler(void *data, int is_kthread)
     shadow_ring.cur = kring->rcur;
 
     /* Disable notifications. */
-    ptring_kick_enable(ptring, 0);
+    pthg_kick_enable(pthg, 0);
     /* Copy the guest kring pointers from the CSB */
-    ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
+    ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
 
     for (;;) {
 	uint32_t hwtail;
@@ -488,7 +493,7 @@ ptnetmap_rx_handler(void *data, int is_kthread)
         if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
             /* Reinit ring and enable notifications. */
             netmap_ring_reinit(kring);
-            ptring_kick_enable(ptring, 1);
+            pthg_kick_enable(pthg, 1);
             break;
         }
 
@@ -499,7 +504,7 @@ ptnetmap_rx_handler(void *data, int is_kthread)
         IFRATE(pre_tail = kring->rtail);
         if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
             /* Reenable notifications. */
-            ptring_kick_enable(ptring, 1);
+            pthg_kick_enable(pthg, 1);
             D("ERROR rxsync()");
 	    break;
         }
@@ -508,7 +513,7 @@ ptnetmap_rx_handler(void *data, int is_kthread)
          * Copy host hwcur and hwtail into the CSB for the guest sync()
          */
 	hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-        ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur, hwtail);
+        ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur, hwtail);
         if (kring->rtail != hwtail) {
 	    kring->rtail = hwtail;
             some_recvd = true;
@@ -526,16 +531,16 @@ ptnetmap_rx_handler(void *data, int is_kthread)
 
 #ifndef BUSY_WAIT
 	/* Interrupt the guest if needed. */
-        if (some_recvd && ptring_intr_enabled(ptring)) {
+        if (some_recvd && ptgh_intr_enabled(ptgh)) {
             /* Disable guest kick to avoid sending unnecessary kicks */
-            ptring_intr_enable(ptring, 0);
+            ptgh_intr_enable(ptgh, 0);
             nm_os_kctx_send_irq(kth);
             IFRATE(ptns->rate_ctx.new.hrxk++);
             some_recvd = false;
         }
 #endif
         /* Read CSB to see if there is more work to do. */
-        ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
+        ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
 #ifndef BUSY_WAIT
         if (ptnetmap_norxslots(kring, shadow_ring.head)) {
             /*
@@ -545,13 +550,13 @@ ptnetmap_rx_handler(void *data, int is_kthread)
              */
             usleep_range(1,1);
             /* Reenable notifications. */
-            ptring_kick_enable(ptring, 1);
+            pthg_kick_enable(pthg, 1);
             /* Doublecheck. */
-            ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots);
+            ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
             if (!ptnetmap_norxslots(kring, shadow_ring.head)) {
 		/* We won the race condition, more slots are available. Disable
 		 * notifications and do another cycle. */
-                ptring_kick_enable(ptring, 0);
+                pthg_kick_enable(pthg, 0);
                 continue;
 	    }
             break;
@@ -576,8 +581,8 @@ ptnetmap_rx_handler(void *data, int is_kthread)
     nm_kr_put(kring);
 
     /* Interrupt the guest if needed. */
-    if (some_recvd && ptring_intr_enabled(ptring)) {
-        ptring_intr_enable(ptring, 0);
+    if (some_recvd && ptgh_intr_enabled(ptgh)) {
+        ptgh_intr_enable(ptgh, 0);
         nm_os_kctx_send_irq(kth);
         IFRATE(ptns->rate_ctx.new.hrxk++);
     }
@@ -590,8 +595,8 @@ ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
 	int k;
 
 	D("ptnetmap configuration:");
-	D("  CSB ptrings @%p, num_rings=%u, cfgtype %08x", cfg->ptrings,
-	  cfg->num_rings, cfg->cfgtype);
+	D("  CSB @%p@:%p, num_rings=%u, cfgtype %08x", cfg->csb_gh,
+	  cfg->csb_hg, cfg->num_rings, cfg->cfgtype);
 	for (k = 0; k < cfg->num_rings; k++) {
 		switch (cfg->cfgtype) {
 		case PTNETMAP_CFGTYPE_QEMU: {
@@ -624,16 +629,18 @@ ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
 
 /* Copy actual state of the host ring into the CSB for the guest init */
 static int
-ptnetmap_kring_snapshot(struct netmap_kring *kring, struct ptnet_ring __user *ptring)
+ptnetmap_kring_snapshot(struct netmap_kring *kring,
+			struct ptnet_gh_ring __user *ptgh,
+			struct ptnet_hg_ring __user *pthg)
 {
-    if (CSB_WRITE(ptring, head, kring->rhead))
+    if (CSB_WRITE(ptgh, head, kring->rhead))
         goto err;
-    if (CSB_WRITE(ptring, cur, kring->rcur))
+    if (CSB_WRITE(ptgh, cur, kring->rcur))
         goto err;
 
-    if (CSB_WRITE(ptring, hwcur, kring->nr_hwcur))
+    if (CSB_WRITE(pthg, hwcur, kring->nr_hwcur))
         goto err;
-    if (CSB_WRITE(ptring, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
+    if (CSB_WRITE(pthg, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
         goto err;
 
     DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);)
@@ -665,7 +672,8 @@ ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na)
 
 	for (k = 0; k < num_rings; k++) {
 		kring = ptnetmap_kring(pth_na, k);
-		err |= ptnetmap_kring_snapshot(kring, ptns->ptrings + k);
+		err |= ptnetmap_kring_snapshot(kring, ptns->csb_gh + k,
+						ptns->csb_hg + k);
 	}
 
 	return err;
@@ -842,7 +850,8 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
     ptns->pth_na = pth_na;
 
     /* Store the CSB address provided by the hypervisor. */
-    ptns->ptrings = cfg->ptrings;
+    ptns->csb_gh = cfg->csb_gh;
+    ptns->csb_hg = cfg->csb_hg;
 
     DBG(ptnetmap_print_configuration(cfg));
 
@@ -1321,26 +1330,26 @@ netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
  * block (no space in the ring).
  */
 bool
-netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
-		       int flags)
+netmap_pt_guest_txsync(struct ptnet_gh_ring *ptgh, struct ptnet_hg_ring *pthg,
+			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
 
 	/* Disable notifications */
-	ptring->guest_need_kick = 0;
+	ptgh->guest_need_kick = 0;
 
 	/*
 	 * First part: tell the host (updating the CSB) to process the new
 	 * packets.
 	 */
-	kring->nr_hwcur = ptring->hwcur;
-	ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead);
+	kring->nr_hwcur = pthg->hwcur;
+	ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
 
         /* Ask for a kick from a guest to the host if needed. */
 	if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
-		&& NM_ACCESS_ONCE(ptring->host_need_kick)) ||
+		&& NM_ACCESS_ONCE(pthg->host_need_kick)) ||
 			(flags & NAF_FORCE_RECLAIM)) {
-		ptring->sync_flags = flags;
+		ptgh->sync_flags = flags;
 		notify = true;
 	}
 
@@ -1348,7 +1357,7 @@ netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
-                ptnetmap_guest_read_kring_csb(ptring, kring);
+                ptnetmap_guest_read_kring_csb(pthg, kring);
 	}
 
         /*
@@ -1358,17 +1367,17 @@ netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
          */
 	if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
-		ptring->guest_need_kick = 1;
+		ptgh->guest_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(ptring, kring);
+                ptnetmap_guest_read_kring_csb(pthg, kring);
                 /* If there is new free space, disable notifications */
 		if (unlikely(!nm_kr_txempty(kring))) {
-			ptring->guest_need_kick = 0;
+			ptgh->guest_need_kick = 0;
 		}
 	}
 
 	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
-		kring->name, ptring->head, ptring->cur, ptring->hwtail,
+		kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
 	return notify;
@@ -1386,20 +1395,20 @@ netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
  * block (no more completed slots in the ring).
  */
 bool
-netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
-		       int flags)
+netmap_pt_guest_rxsync(struct ptnet_gh_ring *ptgh, struct ptnet_hg_ring *pthg,
+			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
 
         /* Disable notifications */
-	ptring->guest_need_kick = 0;
+	ptgh->guest_need_kick = 0;
 
 	/*
 	 * First part: import newly received packets, by updating the kring
 	 * hwtail to the hwtail known from the host (read from the CSB).
 	 * This also updates the kring hwcur.
 	 */
-        ptnetmap_guest_read_kring_csb(ptring, kring);
+        ptnetmap_guest_read_kring_csb(pthg, kring);
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
 	/*
@@ -1407,11 +1416,11 @@ netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
 	 * released, by updating cur and head in the CSB.
 	 */
 	if (kring->rhead != kring->nr_hwcur) {
-		ptnetmap_guest_write_kring_csb(ptring, kring->rcur,
+		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
 					       kring->rhead);
                 /* Ask for a kick from the guest to the host if needed. */
-		if (NM_ACCESS_ONCE(ptring->host_need_kick)) {
-			ptring->sync_flags = flags;
+		if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
+			ptgh->sync_flags = flags;
 			notify = true;
 		}
 	}
@@ -1423,17 +1432,17 @@ netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring,
          */
 	if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
-                ptring->guest_need_kick = 1;
+                ptgh->guest_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(ptring, kring);
+                ptnetmap_guest_read_kring_csb(pthg, kring);
                 /* If there are new slots, disable notifications. */
 		if (!nm_kr_rxempty(kring)) {
-                        ptring->guest_need_kick = 0;
+                        ptgh->guest_need_kick = 0;
                 }
         }
 
 	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
-		kring->name, ptring->head, ptring->cur, ptring->hwtail,
+		kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
 	return notify;
@@ -1492,13 +1501,13 @@ ptnet_nm_dtor(struct netmap_adapter *na)
 	struct netmap_pt_guest_adapter *ptna =
 			(struct netmap_pt_guest_adapter *)na;
 
-	netmap_mem_put(ptna->dr.up.nm_mem); // XXX is this needed?
+	netmap_mem_put(ptna->dr.up.nm_mem);
 	memset(&ptna->dr, 0, sizeof(ptna->dr));
 	netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp);
 }
 
 int
-netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb,
+netmap_pt_guest_attach(struct netmap_adapter *arg,
 		       unsigned int nifp_offset, unsigned int memid)
 {
 	struct netmap_pt_guest_adapter *ptna;
@@ -1516,7 +1525,6 @@ netmap_pt_guest_attach(struct netmap_adapter *arg, void *csb,
 
 	/* get the netmap_pt_guest_adapter */
 	ptna = (struct netmap_pt_guest_adapter *) NA(ifp);
-	ptna->csb = csb;
 
 	/* Initialize a separate pass-through netmap adapter that is going to
 	 * be used by the ptnet driver only, and so never exposed to netmap
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index e5c823ea2..882febb70 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -85,7 +85,8 @@ struct ptnetmap_cfg {
 	uint16_t cfgtype;	/* how to interpret the cfg entries */
 	uint16_t entry_size;	/* size of a config entry */
 	uint32_t num_rings;	/* number of config entries */
-	void *ptrings;		/* ptrings inside CSB */
+	void *csb_gh;		/* CSB for guest --> host communication */
+	void *csb_hg;		/* CSB for host --> guest communication */
 	/* Configuration entries are allocated right after the struct. */
 };
 
@@ -146,8 +147,8 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 #define PTNET_IO_PTCTL		4
 #define PTNET_IO_MAC_LO		8
 #define PTNET_IO_MAC_HI		12
-#define PTNET_IO_CSBBAH		16
-#define PTNET_IO_CSBBAL		20
+#define PTNET_IO_CSBBAH		16 /* deprecated */
+#define PTNET_IO_CSBBAL		20 /* deprecated */
 #define PTNET_IO_NIFP_OFS	24
 #define PTNET_IO_NUM_TX_RINGS	28
 #define PTNET_IO_NUM_RX_RINGS	32
@@ -155,7 +156,11 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 #define PTNET_IO_NUM_RX_SLOTS	40
 #define PTNET_IO_VNET_HDR_LEN	44
 #define PTNET_IO_HOSTMEMID	48
-#define PTNET_IO_END		52
+#define PTNET_IO_CSB_GH_BAH     52
+#define PTNET_IO_CSB_GH_BAL     56
+#define PTNET_IO_CSB_HG_BAH     60
+#define PTNET_IO_CSB_HG_BAL     64
+#define PTNET_IO_END		68
 #define PTNET_IO_KICK_BASE	128
 #define PTNET_IO_MASK		0xff
 
@@ -163,28 +168,20 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 #define PTNETMAP_PTCTL_CREATE		1
 #define PTNETMAP_PTCTL_DELETE		2
 
-/* If defined, CSB is allocated by the guest, not by the host. */
-#define PTNET_CSB_ALLOC
-
 /* ptnetmap ring fields shared between guest and host */
-struct ptnet_ring {
-	/* XXX revise the layout to minimize cache bounces. */
+struct ptnet_gh_ring {
 	uint32_t head;		  /* GW+ HR+ the head of the guest netmap_ring */
 	uint32_t cur;		  /* GW+ HR+ the cur of the guest netmap_ring */
 	uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */
 	uint32_t sync_flags;	  /* GW+ HR+ the flags of the guest [tx|rx]sync() */
+};
+struct ptnet_hg_ring {
 	uint32_t hwcur;		  /* GR+ HW+ the hwcur of the host netmap_kring */
 	uint32_t hwtail;	  /* GR+ HW+ the hwtail of the host netmap_kring */
 	uint32_t host_need_kick;  /* GR+ HW+ guest-->host notification enable */
 	char pad[4];
 };
 
-/* CSB for the ptnet device. */
-struct ptnet_csb {
-#define NETMAP_VIRT_CSB_SIZE   4096
-	struct ptnet_ring rings[NETMAP_VIRT_CSB_SIZE/sizeof(struct ptnet_ring)];
-};
-
 #ifdef WITH_PTNETMAP_GUEST
 
 /* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */
@@ -197,7 +194,7 @@ uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
 /* Guest driver: Write kring pointers (cur, head) to the CSB.
  * This routine is coupled with ptnetmap_host_read_kring_csb(). */
 static inline void
-ptnetmap_guest_write_kring_csb(struct ptnet_ring *ptr, uint32_t cur,
+ptnetmap_guest_write_kring_csb(struct ptnet_gh_ring *ptr, uint32_t cur,
 			       uint32_t head)
 {
     /*
@@ -228,16 +225,16 @@ ptnetmap_guest_write_kring_csb(struct ptnet_ring *ptr, uint32_t cur,
 /* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
  * This routine is coupled with ptnetmap_host_write_kring_csb(). */
 static inline void
-ptnetmap_guest_read_kring_csb(struct ptnet_ring *ptr, struct netmap_kring *kring)
+ptnetmap_guest_read_kring_csb(struct ptnet_hg_ring *pthg, struct netmap_kring *kring)
 {
     /*
      * We place a memory barrier to make sure that the update of hwtail never
      * overtakes the update of hwcur.
      * (see explanation in ptnetmap_host_write_kring_csb).
      */
-    kring->nr_hwtail = ptr->hwtail;
+    kring->nr_hwtail = pthg->hwtail;
     mb();
-    kring->nr_hwcur = ptr->hwcur;
+    kring->nr_hwcur = pthg->hwcur;
 }
 
 #endif /* WITH_PTNETMAP_GUEST */
@@ -259,7 +256,7 @@ ptnetmap_guest_read_kring_csb(struct ptnet_ring *ptr, struct netmap_kring *kring
 /* Host netmap: Write kring pointers (hwcur, hwtail) to the CSB.
  * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
 static inline void
-ptnetmap_host_write_kring_csb(struct ptnet_ring __user *ptr, uint32_t hwcur,
+ptnetmap_host_write_kring_csb(struct ptnet_hg_ring __user *ptr, uint32_t hwcur,
         uint32_t hwtail)
 {
     /*
@@ -285,7 +282,7 @@ ptnetmap_host_write_kring_csb(struct ptnet_ring __user *ptr, uint32_t hwcur,
 /* Host netmap: Read kring pointers (head, cur, sync_flags) from the CSB.
  * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
 static inline void
-ptnetmap_host_read_kring_csb(struct ptnet_ring __user *ptr,
+ptnetmap_host_read_kring_csb(struct ptnet_gh_ring __user *ptr,
 			     struct netmap_ring *shadow_ring,
 			     uint32_t num_slots)
 {

From d3566ef48799c5a0566ab126e47b227587fabb3c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 15:04:29 +0100
Subject: [PATCH 0320/2207] ptnetmap: prevent host from accessing the GH CSB

---
 sys/dev/netmap/netmap_pt.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 186a8d83c..c9c661cb0 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -217,13 +217,6 @@ ptgh_intr_enabled(struct ptnet_gh_ring __user *ptgh)
     return v;
 }
 
-/* Enable or disable guest interrupts. */
-static inline void
-ptgh_intr_enable(struct ptnet_gh_ring __user *ptgh, uint32_t val)
-{
-    CSB_WRITE(ptgh, guest_need_kick, val);
-}
-
 /* Handle TX events: from the guest or from the backend */
 static void
 ptnetmap_tx_handler(void *data, int is_kthread)
@@ -342,7 +335,6 @@ ptnetmap_tx_handler(void *data, int is_kthread)
         /* Interrupt the guest if needed. */
         if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
             /* Disable guest kick to avoid sending unnecessary kicks */
-            ptgh_intr_enable(ptgh, 0);
             nm_os_kctx_send_irq(kth);
             IFRATE(ptns->rate_ctx.new.htxk++);
             more_txspace = false;
@@ -389,7 +381,6 @@ ptnetmap_tx_handler(void *data, int is_kthread)
     nm_kr_put(kring);
 
     if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
-        ptgh_intr_enable(ptgh, 0);
         nm_os_kctx_send_irq(kth);
         IFRATE(ptns->rate_ctx.new.htxk++);
     }
@@ -533,7 +524,6 @@ ptnetmap_rx_handler(void *data, int is_kthread)
 	/* Interrupt the guest if needed. */
         if (some_recvd && ptgh_intr_enabled(ptgh)) {
             /* Disable guest kick to avoid sending unnecessary kicks */
-            ptgh_intr_enable(ptgh, 0);
             nm_os_kctx_send_irq(kth);
             IFRATE(ptns->rate_ctx.new.hrxk++);
             some_recvd = false;
@@ -582,7 +572,6 @@ ptnetmap_rx_handler(void *data, int is_kthread)
 
     /* Interrupt the guest if needed. */
     if (some_recvd && ptgh_intr_enabled(ptgh)) {
-        ptgh_intr_enable(ptgh, 0);
         nm_os_kctx_send_irq(kth);
         IFRATE(ptns->rate_ctx.new.hrxk++);
     }

From fde7fe6f994003f5a44789b2efca295a1c588470 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 17:54:26 +0100
Subject: [PATCH 0321/2207] ptnetmap: upgrade FreeBSD driver to use the
 splitted CSB

---
 sys/dev/netmap/if_ptnet.c | 120 +++++++++++++++++++++-----------------
 1 file changed, 67 insertions(+), 53 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 42afea012..0030cc158 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -88,10 +88,6 @@
 #include 
 #include 
 
-#ifndef PTNET_CSB_ALLOC
-#error "No support for on-device CSB"
-#endif
-
 #ifndef INET
 #error "INET not defined, cannot support offloadings"
 #endif
@@ -132,7 +128,8 @@ struct ptnet_queue {
 	struct				resource *irq;
 	void				*cookie;
 	int				kring_id;
-	struct ptnet_ring		*ptring;
+	struct ptnet_gh_ring		*ptgh;
+	struct ptnet_hg_ring		*pthg;
 	unsigned int			kick;
 	struct mtx			lock;
 	struct buf_ring			*bufring; /* for TX queues */
@@ -325,26 +322,34 @@ ptnet_attach(device_t dev)
 	ptfeatures = bus_read_4(sc->iomem, PTNET_IO_PTFEAT); /* acked */
 	sc->ptfeatures = ptfeatures;
 
-	/* Allocate CSB and carry out CSB allocation protocol (CSBBAH first,
-	 * then CSBBAL). */
-	sc->csb = malloc(sizeof(struct ptnet_csb), M_DEVBUF,
-			 M_NOWAIT | M_ZERO);
-	if (sc->csb == NULL) {
+	/* Allocate CSB and carry out CSB allocation protocol. */
+	sc->csb_gh = contigmalloc(2*PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO,
+				  (size_t)0, -1UL, PAGE_SIZE, 0);
+	if (sc->csb_gh == NULL) {
 		device_printf(dev, "Failed to allocate CSB\n");
 		err = ENOMEM;
 		goto err_path;
 	}
+	sc->csb_hg = (struct ptnet_hg_ring *)(((char *)sc->csb_gh) + PAGE_SIZE);
 
 	{
 		/*
 		 * We use uint64_t rather than vm_paddr_t since we
 		 * need 64 bit addresses even on 32 bit platforms.
 		 */
-		uint64_t paddr = vtophys(sc->csb);
+		uint64_t paddr = vtophys(sc->csb_gh);
 
-		bus_write_4(sc->iomem, PTNET_IO_CSBBAH,
-			    (paddr >> 32) & 0xffffffff);
-		bus_write_4(sc->iomem, PTNET_IO_CSBBAL, paddr & 0xffffffff);
+		/* CSB allocation protocol: write to BAH first, then
+		 * to BAL (for both GH and HG sections). */
+		bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAH,
+				(paddr >> 32) & 0xffffffff);
+		bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAL,
+				paddr & 0xffffffff);
+		paddr = vtophys(sc->csb_hg);
+		bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAH,
+				(paddr >> 32) & 0xffffffff);
+		bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAL,
+				paddr & 0xffffffff);
 	}
 
 	num_tx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
@@ -367,7 +372,8 @@ ptnet_attach(device_t dev)
 		pq->sc = sc;
 		pq->kring_id = i;
 		pq->kick = PTNET_IO_KICK_BASE + 4 * i;
-		pq->ptring = sc->csb->rings + i;
+		pq->ptgh = sc->csb_gh + i;
+		pq->pthg = sc->csb_hg + i;
 		snprintf(pq->lock_name, sizeof(pq->lock_name), "%s-%d",
 			 device_get_nameunit(dev), i);
 		mtx_init(&pq->lock, pq->lock_name, NULL, MTX_DEF);
@@ -470,7 +476,7 @@ ptnet_attach(device_t dev)
 	na_arg.nm_txsync = ptnet_nm_txsync;
 	na_arg.nm_rxsync = ptnet_nm_rxsync;
 
-	netmap_pt_guest_attach(&na_arg, sc->csb, nifp_offset,
+	netmap_pt_guest_attach(&na_arg, nifp_offset,
                                 bus_read_4(sc->iomem, PTNET_IO_HOSTMEMID));
 
 	/* Now a netmap adapter for this ifp has been allocated, and it
@@ -529,11 +535,14 @@ ptnet_detach(device_t dev)
 
 	ptnet_irqs_fini(sc);
 
-	if (sc->csb) {
-		bus_write_4(sc->iomem, PTNET_IO_CSBBAH, 0);
-		bus_write_4(sc->iomem, PTNET_IO_CSBBAL, 0);
-		free(sc->csb, M_DEVBUF);
-		sc->csb = NULL;
+	if (sc->csb_gh) {
+		bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAH, 0);
+		bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAL, 0);
+		bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAH, 0);
+		bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAL, 0);
+		contigfree(sc->csb_gh, 2*PAGE_SIZE, M_DEVBUF);
+		sc->csb_gh = NULL;
+		sc->csb_hg = NULL;
 	}
 
 	if (sc->queues) {
@@ -780,7 +789,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 					/* Make sure the worker sees the
 					 * IFF_DRV_RUNNING down. */
 					PTNET_Q_LOCK(pq);
-					pq->ptring->guest_need_kick = 0;
+					pq->ptgh->guest_need_kick = 0;
 					PTNET_Q_UNLOCK(pq);
 					/* Wait for rescheduling to finish. */
 					if (pq->taskq) {
@@ -794,7 +803,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 				for (i = 0; i < sc->num_rings; i++) {
 					pq = sc-> queues + i;
 					PTNET_Q_LOCK(pq);
-					pq->ptring->guest_need_kick = 1;
+					pq->ptgh->guest_need_kick = 1;
 					PTNET_Q_UNLOCK(pq);
 				}
 			}
@@ -1112,7 +1121,8 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < sc->num_rings; i++) {
-		struct ptnet_ring *ptring = sc->queues[i].ptring;
+		struct ptnet_gh_ring *ptgh = sc->queues[i].ptgh;
+		struct ptnet_hg_ring *pthg = sc->queues[i].pthg;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1120,15 +1130,15 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings + i - na->num_tx_rings;
 		}
-		kring->rhead = kring->ring->head = ptring->head;
-		kring->rcur = kring->ring->cur = ptring->cur;
-		kring->nr_hwcur = ptring->hwcur;
+		kring->rhead = kring->ring->head = ptgh->head;
+		kring->rcur = kring->ring->cur = ptgh->cur;
+		kring->nr_hwcur = pthg->hwcur;
 		kring->nr_hwtail = kring->rtail =
-			kring->ring->tail = ptring->hwtail;
+			kring->ring->tail = pthg->hwtail;
 
 		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
-		   ptring->hwcur, ptring->head, ptring->cur,
-		   ptring->hwtail);
+		   pthg->hwcur, ptgh->head, ptgh->cur,
+		   pthg->hwtail);
 		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
@@ -1172,7 +1182,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		D("Exit netmap mode, re-enable interrupts");
 		for (i = 0; i < sc->num_rings; i++) {
 			pq = sc->queues + i;
-			pq->ptring->guest_need_kick = 1;
+			pq->ptgh->guest_need_kick = 1;
 		}
 	}
 
@@ -1181,8 +1191,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < sc->num_rings; i++) {
 				pq = sc->queues + i;
-				pq->ptring->host_need_kick = 1;
-				pq->ptring->guest_need_kick =
+				pq->pthg->host_need_kick = 1;
+				pq->ptgh->guest_need_kick =
 					(!(ifp->if_capenable & IFCAP_POLLING)
 						&& i >= sc->num_tx_rings);
 			}
@@ -1260,7 +1270,7 @@ ptnet_nm_txsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = sc->queues + kring->ring_id;
 	bool notify;
 
-	notify = netmap_pt_guest_txsync(pq->ptring, kring, flags);
+	notify = netmap_pt_guest_txsync(pq->ptgh, pq->pthg, kring, flags);
 	if (notify) {
 		ptnet_kick(pq);
 	}
@@ -1275,7 +1285,7 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = sc->rxqueues + kring->ring_id;
 	bool notify;
 
-	notify = netmap_pt_guest_rxsync(pq->ptring, kring, flags);
+	notify = netmap_pt_guest_rxsync(pq->ptgh, pq->pthg, kring, flags);
 	if (notify) {
 		ptnet_kick(pq);
 	}
@@ -1291,7 +1301,7 @@ ptnet_nm_intr(struct netmap_adapter *na, int onoff)
 
 	for (i = 0; i < sc->num_rings; i++) {
 		struct ptnet_queue *pq = sc->queues + i;
-		pq->ptring->guest_need_kick = onoff;
+		pq->ptgh->guest_need_kick = onoff;
 	}
 }
 
@@ -1658,12 +1668,12 @@ ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr)
 /* End of offloading-related functions to be shared with vtnet. */
 
 static inline void
-ptnet_sync_tail(struct ptnet_ring *ptring, struct netmap_kring *kring)
+ptnet_sync_tail(struct ptnet_hg_ring *pthg, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(ptring, kring);
+        ptnetmap_guest_read_kring_csb(pthg, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -1674,7 +1684,8 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 		  unsigned int head, unsigned int sync_flags)
 {
 	struct netmap_ring *ring = kring->ring;
-	struct ptnet_ring *ptring = pq->ptring;
+	struct ptnet_gh_ring *ptgh = pq->ptgh;
+	struct ptnet_hg_ring *pthg = pq->pthg;
 
 	/* Some packets have been pushed to the netmap ring. We have
 	 * to tell the host to process the new packets, updating cur
@@ -1684,11 +1695,11 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 	/* Mimic nm_txsync_prologue/nm_rxsync_prologue. */
 	kring->rcur = kring->rhead = head;
 
-	ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead);
+	ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
 
 	/* Kick the host if needed. */
-	if (NM_ACCESS_ONCE(ptring->host_need_kick)) {
-		ptring->sync_flags = sync_flags;
+	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
+		ptgh->sync_flags = sync_flags;
 		ptnet_kick(pq);
 	}
 }
@@ -1708,7 +1719,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	if_t ifp = sc->ifp;
 	unsigned int batch_count = 0;
-	struct ptnet_ring *ptring;
+	struct ptnet_gh_ring *ptgh;
+	struct ptnet_hg_ring *pthg;
 	struct netmap_kring *kring;
 	struct netmap_ring *ring;
 	struct netmap_slot *slot;
@@ -1737,7 +1749,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 		return ENETDOWN;
 	}
 
-	ptring = pq->ptring;
+	ptgh = pq->ptgh;
+	pthg = pq->pthg;
 	kring = na->tx_rings + pq->kring_id;
 	ring = kring->ring;
 	lim = kring->nkr_num_slots - 1;
@@ -1749,17 +1762,17 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 			/* We ran out of slot, let's see if the host has
 			 * freed up some, by reading hwcur and hwtail from
 			 * the CSB. */
-			ptnet_sync_tail(ptring, kring);
+			ptnet_sync_tail(pthg, kring);
 
 			if (PTNET_TX_NOSPACE(head, kring, minspace)) {
 				/* Still no slots available. Reactivate the
 				 * interrupts so that we can be notified
 				 * when some free slots are made available by
 				 * the host. */
-				ptring->guest_need_kick = 1;
+				ptgh->guest_need_kick = 1;
 
 				/* Double-check. */
-				ptnet_sync_tail(ptring, kring);
+				ptnet_sync_tail(pthg, kring);
 				if (likely(PTNET_TX_NOSPACE(head, kring,
 							    minspace))) {
 					break;
@@ -1768,7 +1781,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 				RD(1, "Found more slots by doublecheck");
 				/* More slots were freed before reactivating
 				 * the interrupts. */
-				ptring->guest_need_kick = 0;
+				ptgh->guest_need_kick = 0;
 			}
 		}
 
@@ -1998,7 +2011,8 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 {
 	struct ptnet_softc *sc = pq->sc;
 	bool have_vnet_hdr = sc->vnet_hdr_len;
-	struct ptnet_ring *ptring = pq->ptring;
+	struct ptnet_gh_ring *ptgh = pq->ptgh;
+	struct ptnet_hg_ring *pthg = pq->pthg;
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	struct netmap_kring *kring = na->rx_rings + pq->kring_id;
 	struct netmap_ring *ring = kring->ring;
@@ -2028,21 +2042,21 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 			/* We ran out of slot, let's see if the host has
 			 * added some, by reading hwcur and hwtail from
 			 * the CSB. */
-			ptnet_sync_tail(ptring, kring);
+			ptnet_sync_tail(pthg, kring);
 
 			if (head == ring->tail) {
 				/* Still no slots available. Reactivate
 				 * interrupts as they were disabled by the
 				 * host thread right before issuing the
 				 * last interrupt. */
-				ptring->guest_need_kick = 1;
+				ptgh->guest_need_kick = 1;
 
 				/* Double-check. */
-				ptnet_sync_tail(ptring, kring);
+				ptnet_sync_tail(pthg, kring);
 				if (likely(head == ring->tail)) {
 					break;
 				}
-				ptring->guest_need_kick = 0;
+				ptgh->guest_need_kick = 0;
 			}
 		}
 

From ba831786eda5a74e4430ab182fdcb3750fe1e299 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 18:43:26 +0100
Subject: [PATCH 0322/2207] freebsd: ptnet: add check on the number of rings
 allowed in CSB

---
 sys/dev/netmap/if_ptnet.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 0030cc158..52af00ac9 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -322,6 +322,18 @@ ptnet_attach(device_t dev)
 	ptfeatures = bus_read_4(sc->iomem, PTNET_IO_PTFEAT); /* acked */
 	sc->ptfeatures = ptfeatures;
 
+	num_tx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
+	num_rx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
+	sc->num_rings = num_tx_rings + num_rx_rings;
+	sc->num_tx_rings = num_tx_rings;
+
+	if (sc->num_rings * sizeof(struct ptnet_gh_ring) > PAGE_SIZE) {
+		device_printf(dev, "CSB cannot handle that many rings (%u)\n",
+				sc->num_rings);
+		err = ENOMEM;
+		goto err_path;
+	}
+
 	/* Allocate CSB and carry out CSB allocation protocol. */
 	sc->csb_gh = contigmalloc(2*PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO,
 				  (size_t)0, -1UL, PAGE_SIZE, 0);
@@ -352,11 +364,6 @@ ptnet_attach(device_t dev)
 				paddr & 0xffffffff);
 	}
 
-	num_tx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
-	num_rx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
-	sc->num_rings = num_tx_rings + num_rx_rings;
-	sc->num_tx_rings = num_tx_rings;
-
 	/* Allocate and initialize per-queue data structures. */
 	sc->queues = malloc(sizeof(struct ptnet_queue) * sc->num_rings,
 			    M_DEVBUF, M_NOWAIT | M_ZERO);

From 56724653d9ae36deae8c9027a0e878bc1cc7e49d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 18:47:52 +0100
Subject: [PATCH 0323/2207] linux: ptnet: add check for max number of rings in
 CSB

---
 LINUX/netmap_ptnet.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index f3143419b..e47bd710b 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1366,6 +1366,12 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	pi->num_rings = num_tx_rings + num_rx_rings;
 	pi->num_tx_rings = num_tx_rings;
 
+	if (pi->num_rings * sizeof(struct ptnet_gh_ring) > PAGE_SIZE) {
+		pr_err("%s: CSB for device %s cannot handle too many "
+			"rings (%u)\n",__func__, netdev->name, pi->num_rings);
+		goto err_ptfeat;
+	}
+
 	/* Initialize the arrays of pointers with the per-ring structures. */
 	pi->queues = (struct ptnet_queue **)(pi + 1);
 	pi->rxqueues = pi->queues + num_tx_rings;

From dddbdd56d96c73fe3d4977c72dea5376eac1170b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 19:08:26 +0100
Subject: [PATCH 0324/2207] ptnetmap: use 64 bytes CSB entries to match
 cacheline size

---
 sys/net/netmap_virt.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 882febb70..14f4e99b9 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -168,18 +168,19 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 #define PTNETMAP_PTCTL_CREATE		1
 #define PTNETMAP_PTCTL_DELETE		2
 
-/* ptnetmap ring fields shared between guest and host */
+/* ptnetmap synchronization variables shared between guest and host */
 struct ptnet_gh_ring {
 	uint32_t head;		  /* GW+ HR+ the head of the guest netmap_ring */
 	uint32_t cur;		  /* GW+ HR+ the cur of the guest netmap_ring */
 	uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */
 	uint32_t sync_flags;	  /* GW+ HR+ the flags of the guest [tx|rx]sync() */
+	char pad[32];		  /* pad to a 64 bytes cacheline */
 };
 struct ptnet_hg_ring {
 	uint32_t hwcur;		  /* GR+ HW+ the hwcur of the host netmap_kring */
 	uint32_t hwtail;	  /* GR+ HW+ the hwtail of the host netmap_kring */
 	uint32_t host_need_kick;  /* GR+ HW+ guest-->host notification enable */
-	char pad[4];
+	char pad[4+32];
 };
 
 #ifdef WITH_PTNETMAP_GUEST

From afd5159711540d069aa74fa2ee0bc7a7f53069ac Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 19:14:36 +0100
Subject: [PATCH 0325/2207] ptnetmap: rename ptnet_*_ring to avoid mentioning
 "ring"

---
 LINUX/netmap_ptnet.c         | 28 ++++++++++++++--------------
 sys/dev/netmap/if_ptnet.c    | 30 +++++++++++++++---------------
 sys/dev/netmap/netmap_kern.h | 12 ++++++------
 sys/dev/netmap/netmap_pt.c   | 24 ++++++++++++------------
 sys/net/netmap_virt.h        | 12 ++++++------
 5 files changed, 53 insertions(+), 53 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index e47bd710b..59b8d928c 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -57,8 +57,8 @@ struct ptnet_info;
 /* Per-ring data structure. */
 struct ptnet_queue {
 	struct ptnet_info *pi;
-	struct ptnet_gh_ring *ptgh;
-	struct ptnet_hg_ring *pthg;
+	struct ptnet_csb_gh *ptgh;
+	struct ptnet_csb_hg *pthg;
 	int kring_id;
 	u8* __iomem kick;
 
@@ -107,8 +107,8 @@ struct ptnet_info {
 	/* CSB memory to be used for producer/consumer state
 	 * synchronization. */
 	struct page *csb_pages;
-	struct ptnet_gh_ring *csb_gh;
-	struct ptnet_hg_ring *csb_hg;
+	struct ptnet_csb_gh *csb_gh;
+	struct ptnet_csb_hg *csb_hg;
 
 	int min_tx_slots;
 
@@ -143,7 +143,7 @@ hang_tmr_callback(unsigned long arg)
 #endif
 
 static inline void
-ptnet_sync_tail(struct ptnet_hg_ring *pthg, struct netmap_kring *kring)
+ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
@@ -216,8 +216,8 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	int queue_idx = skb_get_queue_mapping(skb);
 	struct ptnet_queue *pq = pi->queues[queue_idx];
-	struct ptnet_gh_ring *ptgh = pq->ptgh;
-	struct ptnet_hg_ring *pthg = pq->pthg;
+	struct ptnet_csb_gh *ptgh = pq->ptgh;
+	struct ptnet_csb_hg *pthg = pq->pthg;
 	struct netmap_kring *kring;
 	struct xmit_copy_args a;
 	int f;
@@ -476,8 +476,8 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 	struct ptnet_rx_queue *prq = container_of(napi, struct ptnet_rx_queue,
 					          napi);
 	struct ptnet_queue *pq = (struct ptnet_queue *)prq;
-	struct ptnet_gh_ring *ptgh = pq->ptgh;
-	struct ptnet_hg_ring *pthg = pq->pthg;
+	struct ptnet_csb_gh *ptgh = pq->ptgh;
+	struct ptnet_csb_hg *pthg = pq->pthg;
 	struct ptnet_info *pi = pq->pi;
 	struct netmap_adapter *na = &pi->ptna->dr.up;
 	struct netmap_kring *kring = &na->rx_rings[pq->kring_id];
@@ -1051,8 +1051,8 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < pi->num_rings; i++) {
-		struct ptnet_gh_ring *ptgh = pi->queues[i]->ptgh;
-		struct ptnet_hg_ring *pthg = pi->queues[i]->pthg;
+		struct ptnet_csb_gh *ptgh = pi->queues[i]->ptgh;
+		struct ptnet_csb_hg *pthg = pi->queues[i]->pthg;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1094,8 +1094,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	struct net_device *netdev = na->ifp;
 	struct ptnet_info *pi = netdev_priv(netdev);
 	int native = (na == &pi->ptna->hwup.up);
-	struct ptnet_gh_ring *ptgh;
-	struct ptnet_hg_ring *pthg;
+	struct ptnet_csb_gh *ptgh;
+	struct ptnet_csb_hg *pthg;
 	enum txrx t;
 	int ret = 0;
 	int i;
@@ -1366,7 +1366,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	pi->num_rings = num_tx_rings + num_rx_rings;
 	pi->num_tx_rings = num_tx_rings;
 
-	if (pi->num_rings * sizeof(struct ptnet_gh_ring) > PAGE_SIZE) {
+	if (pi->num_rings * sizeof(struct ptnet_csb_gh) > PAGE_SIZE) {
 		pr_err("%s: CSB for device %s cannot handle too many "
 			"rings (%u)\n",__func__, netdev->name, pi->num_rings);
 		goto err_ptfeat;
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 52af00ac9..ec6005380 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -128,8 +128,8 @@ struct ptnet_queue {
 	struct				resource *irq;
 	void				*cookie;
 	int				kring_id;
-	struct ptnet_gh_ring		*ptgh;
-	struct ptnet_hg_ring		*pthg;
+	struct ptnet_csb_gh		*ptgh;
+	struct ptnet_csb_hg		*pthg;
 	unsigned int			kick;
 	struct mtx			lock;
 	struct buf_ring			*bufring; /* for TX queues */
@@ -166,8 +166,8 @@ struct ptnet_softc {
 	unsigned int		num_tx_rings;
 	struct ptnet_queue	*queues;
 	struct ptnet_queue	*rxqueues;
-	struct ptnet_gh_ring    *csb_gh;
-	struct ptnet_hg_ring    *csb_hg;
+	struct ptnet_csb_gh    *csb_gh;
+	struct ptnet_csb_hg    *csb_hg;
 
 	unsigned int		min_tx_space;
 
@@ -327,7 +327,7 @@ ptnet_attach(device_t dev)
 	sc->num_rings = num_tx_rings + num_rx_rings;
 	sc->num_tx_rings = num_tx_rings;
 
-	if (sc->num_rings * sizeof(struct ptnet_gh_ring) > PAGE_SIZE) {
+	if (sc->num_rings * sizeof(struct ptnet_csb_gh) > PAGE_SIZE) {
 		device_printf(dev, "CSB cannot handle that many rings (%u)\n",
 				sc->num_rings);
 		err = ENOMEM;
@@ -342,7 +342,7 @@ ptnet_attach(device_t dev)
 		err = ENOMEM;
 		goto err_path;
 	}
-	sc->csb_hg = (struct ptnet_hg_ring *)(((char *)sc->csb_gh) + PAGE_SIZE);
+	sc->csb_hg = (struct ptnet_csb_hg *)(((char *)sc->csb_gh) + PAGE_SIZE);
 
 	{
 		/*
@@ -1128,8 +1128,8 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < sc->num_rings; i++) {
-		struct ptnet_gh_ring *ptgh = sc->queues[i].ptgh;
-		struct ptnet_hg_ring *pthg = sc->queues[i].pthg;
+		struct ptnet_csb_gh *ptgh = sc->queues[i].ptgh;
+		struct ptnet_csb_hg *pthg = sc->queues[i].pthg;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1675,7 +1675,7 @@ ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr)
 /* End of offloading-related functions to be shared with vtnet. */
 
 static inline void
-ptnet_sync_tail(struct ptnet_hg_ring *pthg, struct netmap_kring *kring)
+ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
@@ -1691,8 +1691,8 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 		  unsigned int head, unsigned int sync_flags)
 {
 	struct netmap_ring *ring = kring->ring;
-	struct ptnet_gh_ring *ptgh = pq->ptgh;
-	struct ptnet_hg_ring *pthg = pq->pthg;
+	struct ptnet_csb_gh *ptgh = pq->ptgh;
+	struct ptnet_csb_hg *pthg = pq->pthg;
 
 	/* Some packets have been pushed to the netmap ring. We have
 	 * to tell the host to process the new packets, updating cur
@@ -1726,8 +1726,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	if_t ifp = sc->ifp;
 	unsigned int batch_count = 0;
-	struct ptnet_gh_ring *ptgh;
-	struct ptnet_hg_ring *pthg;
+	struct ptnet_csb_gh *ptgh;
+	struct ptnet_csb_hg *pthg;
 	struct netmap_kring *kring;
 	struct netmap_ring *ring;
 	struct netmap_slot *slot;
@@ -2018,8 +2018,8 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 {
 	struct ptnet_softc *sc = pq->sc;
 	bool have_vnet_hdr = sc->vnet_hdr_len;
-	struct ptnet_gh_ring *ptgh = pq->ptgh;
-	struct ptnet_hg_ring *pthg = pq->pthg;
+	struct ptnet_csb_gh *ptgh = pq->ptgh;
+	struct ptnet_csb_hg *pthg = pq->pthg;
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	struct netmap_kring *kring = na->rx_rings + pq->kring_id;
 	struct netmap_ring *ring = kring->ring;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0351bf492..f7a880e19 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2159,14 +2159,14 @@ struct netmap_pt_guest_adapter {
 int netmap_pt_guest_attach(struct netmap_adapter *na,
 			unsigned int nifp_offset,
 			unsigned int memid);
-struct ptnet_gh_ring;
-struct ptnet_hg_ring;
-bool netmap_pt_guest_txsync(struct ptnet_gh_ring *ptgh,
-			struct ptnet_hg_ring *pthg,
+struct ptnet_csb_gh;
+struct ptnet_csb_hg;
+bool netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh,
+			struct ptnet_csb_hg *pthg,
 			struct netmap_kring *kring,
 			int flags);
-bool netmap_pt_guest_rxsync(struct ptnet_gh_ring *ptgh,
-			struct ptnet_hg_ring *pthg,
+bool netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh,
+			struct ptnet_csb_hg *pthg,
 			struct netmap_kring *kring, int flags);
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index c9c661cb0..e08c85e3d 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -173,8 +173,8 @@ struct ptnetmap_state {
 	struct nm_kctx **kctxs;
 
 	/* Shared memory with the guest (TX/RX) */
-	struct ptnet_gh_ring __user *csb_gh;
-	struct ptnet_hg_ring __user *csb_hg;
+	struct ptnet_csb_gh __user *csb_gh;
+	struct ptnet_csb_hg __user *csb_hg;
 
 	bool stopped;
 
@@ -201,14 +201,14 @@ ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring)
 
 /* Enable or disable guest --> host kicks. */
 static inline void
-pthg_kick_enable(struct ptnet_hg_ring __user *pthg, uint32_t val)
+pthg_kick_enable(struct ptnet_csb_hg __user *pthg, uint32_t val)
 {
     CSB_WRITE(pthg, host_need_kick, val);
 }
 
 /* Are guest interrupt enabled or disabled? */
 static inline uint32_t
-ptgh_intr_enabled(struct ptnet_gh_ring __user *ptgh)
+ptgh_intr_enabled(struct ptnet_csb_gh __user *ptgh)
 {
     uint32_t v;
 
@@ -225,8 +225,8 @@ ptnetmap_tx_handler(void *data, int is_kthread)
     struct netmap_pt_host_adapter *pth_na =
 		(struct netmap_pt_host_adapter *)kring->na->na_private;
     struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_gh_ring __user *ptgh;
-    struct ptnet_hg_ring __user *pthg;
+    struct ptnet_csb_gh __user *ptgh;
+    struct ptnet_csb_hg __user *pthg;
     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
     bool more_txspace = false;
     struct nm_kctx *kth;
@@ -434,8 +434,8 @@ ptnetmap_rx_handler(void *data, int is_kthread)
     struct netmap_pt_host_adapter *pth_na =
 		(struct netmap_pt_host_adapter *)kring->na->na_private;
     struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_gh_ring __user *ptgh;
-    struct ptnet_hg_ring __user *pthg;
+    struct ptnet_csb_gh __user *ptgh;
+    struct ptnet_csb_hg __user *pthg;
     struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
     struct nm_kctx *kth;
     uint32_t num_slots;
@@ -619,8 +619,8 @@ ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
 /* Copy actual state of the host ring into the CSB for the guest init */
 static int
 ptnetmap_kring_snapshot(struct netmap_kring *kring,
-			struct ptnet_gh_ring __user *ptgh,
-			struct ptnet_hg_ring __user *pthg)
+			struct ptnet_csb_gh __user *ptgh,
+			struct ptnet_csb_hg __user *pthg)
 {
     if (CSB_WRITE(ptgh, head, kring->rhead))
         goto err;
@@ -1319,7 +1319,7 @@ netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
  * block (no space in the ring).
  */
 bool
-netmap_pt_guest_txsync(struct ptnet_gh_ring *ptgh, struct ptnet_hg_ring *pthg,
+netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
 			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
@@ -1384,7 +1384,7 @@ netmap_pt_guest_txsync(struct ptnet_gh_ring *ptgh, struct ptnet_hg_ring *pthg,
  * block (no more completed slots in the ring).
  */
 bool
-netmap_pt_guest_rxsync(struct ptnet_gh_ring *ptgh, struct ptnet_hg_ring *pthg,
+netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
 			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 14f4e99b9..648181a9a 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -169,14 +169,14 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 #define PTNETMAP_PTCTL_DELETE		2
 
 /* ptnetmap synchronization variables shared between guest and host */
-struct ptnet_gh_ring {
+struct ptnet_csb_gh {
 	uint32_t head;		  /* GW+ HR+ the head of the guest netmap_ring */
 	uint32_t cur;		  /* GW+ HR+ the cur of the guest netmap_ring */
 	uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */
 	uint32_t sync_flags;	  /* GW+ HR+ the flags of the guest [tx|rx]sync() */
 	char pad[32];		  /* pad to a 64 bytes cacheline */
 };
-struct ptnet_hg_ring {
+struct ptnet_csb_hg {
 	uint32_t hwcur;		  /* GR+ HW+ the hwcur of the host netmap_kring */
 	uint32_t hwtail;	  /* GR+ HW+ the hwtail of the host netmap_kring */
 	uint32_t host_need_kick;  /* GR+ HW+ guest-->host notification enable */
@@ -195,7 +195,7 @@ uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
 /* Guest driver: Write kring pointers (cur, head) to the CSB.
  * This routine is coupled with ptnetmap_host_read_kring_csb(). */
 static inline void
-ptnetmap_guest_write_kring_csb(struct ptnet_gh_ring *ptr, uint32_t cur,
+ptnetmap_guest_write_kring_csb(struct ptnet_csb_gh *ptr, uint32_t cur,
 			       uint32_t head)
 {
     /*
@@ -226,7 +226,7 @@ ptnetmap_guest_write_kring_csb(struct ptnet_gh_ring *ptr, uint32_t cur,
 /* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
  * This routine is coupled with ptnetmap_host_write_kring_csb(). */
 static inline void
-ptnetmap_guest_read_kring_csb(struct ptnet_hg_ring *pthg, struct netmap_kring *kring)
+ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
 {
     /*
      * We place a memory barrier to make sure that the update of hwtail never
@@ -257,7 +257,7 @@ ptnetmap_guest_read_kring_csb(struct ptnet_hg_ring *pthg, struct netmap_kring *k
 /* Host netmap: Write kring pointers (hwcur, hwtail) to the CSB.
  * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
 static inline void
-ptnetmap_host_write_kring_csb(struct ptnet_hg_ring __user *ptr, uint32_t hwcur,
+ptnetmap_host_write_kring_csb(struct ptnet_csb_hg __user *ptr, uint32_t hwcur,
         uint32_t hwtail)
 {
     /*
@@ -283,7 +283,7 @@ ptnetmap_host_write_kring_csb(struct ptnet_hg_ring __user *ptr, uint32_t hwcur,
 /* Host netmap: Read kring pointers (head, cur, sync_flags) from the CSB.
  * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
 static inline void
-ptnetmap_host_read_kring_csb(struct ptnet_gh_ring __user *ptr,
+ptnetmap_host_read_kring_csb(struct ptnet_csb_gh __user *ptr,
 			     struct netmap_ring *shadow_ring,
 			     uint32_t num_slots)
 {

From db1c59ed6c955e0a7ec4d116d9698a2dc3398dd3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 19:32:04 +0100
Subject: [PATCH 0326/2207] ptnetmap: move netmap_adapter_get() call after
 na->name initialization

This allows for easier debugging.
---
 sys/dev/netmap/netmap_pt.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index e08c85e3d..acb4a6903 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1272,13 +1272,11 @@ netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
     }
 
     *na = &pth_na->up;
-    netmap_adapter_get(*na);
-
     /* set parent busy, because attached for ptnetmap */
     parent->na_flags |= NAF_BUSY;
-
     strncpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
     strcat(pth_na->up.name, "-PTN");
+    netmap_adapter_get(*na);
 
     DBG(D("%s ptnetmap request DONE", pth_na->up.name));
 

From 58e3b4948ec2d67dedd0408800c536a11f0ff0a4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Jan 2018 19:34:27 +0100
Subject: [PATCH 0327/2207] linux: fix compilation error in case
 NM_DEBUG_PUTGET is defined

---
 LINUX/netmap_linux.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index ed8a71de9..db376b065 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2273,8 +2273,13 @@ module_exit(linux_netmap_fini);
 /* export certain symbols to other modules */
 EXPORT_SYMBOL(netmap_attach);		/* driver attach routines */
 EXPORT_SYMBOL(netmap_attach_ext);
+#ifdef NM_DEBUG_PUTGET
+EXPORT_SYMBOL(__netmap_adapter_get);
+EXPORT_SYMBOL(__netmap_adapter_put);
+#else
 EXPORT_SYMBOL(netmap_adapter_get);
 EXPORT_SYMBOL(netmap_adapter_put);
+#endif /* NM_DEBUG_PUTGET */
 #ifdef WITH_PTNETMAP_GUEST
 EXPORT_SYMBOL(netmap_pt_guest_attach);	/* ptnetmap driver attach routine */
 EXPORT_SYMBOL(netmap_pt_guest_rxsync);	/* ptnetmap generic rxsync */

From b6a97107d3abfe4ee40c0da310ecf3af6023327e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Jan 2018 14:43:17 +0100
Subject: [PATCH 0328/2207] virt: fix size of ptnetmap csb entries to 64 bytes

---
 sys/net/netmap_virt.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 648181a9a..a520a16dc 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -174,13 +174,13 @@ struct ptnet_csb_gh {
 	uint32_t cur;		  /* GW+ HR+ the cur of the guest netmap_ring */
 	uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */
 	uint32_t sync_flags;	  /* GW+ HR+ the flags of the guest [tx|rx]sync() */
-	char pad[32];		  /* pad to a 64 bytes cacheline */
+	char pad[48];		  /* pad to a 64 bytes cacheline */
 };
 struct ptnet_csb_hg {
 	uint32_t hwcur;		  /* GR+ HW+ the hwcur of the host netmap_kring */
 	uint32_t hwtail;	  /* GR+ HW+ the hwtail of the host netmap_kring */
 	uint32_t host_need_kick;  /* GR+ HW+ guest-->host notification enable */
-	char pad[4+32];
+	char pad[4+48];
 };
 
 #ifdef WITH_PTNETMAP_GUEST

From 7efd2f0ec48c1dbc120bd041f35746d22ab900b8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Jan 2018 15:02:17 +0100
Subject: [PATCH 0329/2207] ptnetmap: remove useless instructions

---
 sys/dev/netmap/netmap_pt.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index acb4a6903..edb49dc50 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -258,8 +258,6 @@ ptnetmap_tx_handler(void *data, int is_kthread)
     kth = ptns->kctxs[kring->ring_id];
 
     num_slots = kring->nkr_num_slots;
-    shadow_ring.head = kring->rhead;
-    shadow_ring.cur = kring->rcur;
 
     /* Disable guest --> host notifications. */
     pthg_kick_enable(pthg, 0);
@@ -468,8 +466,6 @@ ptnetmap_rx_handler(void *data, int is_kthread)
     kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id];
 
     num_slots = kring->nkr_num_slots;
-    shadow_ring.head = kring->rhead;
-    shadow_ring.cur = kring->rcur;
 
     /* Disable notifications. */
     pthg_kick_enable(pthg, 0);

From 6a02a2ceab224d0c3334cd777d094101c1763977 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 20 Jan 2018 13:26:56 +0100
Subject: [PATCH 0330/2207] freebsd: ptnet: reload ring->head after unlock-lock
 sequence

---
 sys/dev/netmap/if_ptnet.c | 50 ++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index ec6005380..1805a7f31 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -2024,10 +2024,10 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 	struct netmap_kring *kring = na->rx_rings + pq->kring_id;
 	struct netmap_ring *ring = kring->ring;
 	unsigned int const lim = kring->nkr_num_slots - 1;
-	unsigned int head = ring->head;
 	unsigned int batch_count = 0;
 	if_t ifp = sc->ifp;
 	unsigned int count = 0;
+	uint32_t head;
 
 	PTNET_Q_LOCK(pq);
 
@@ -2037,13 +2037,15 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
+	head = ring->head;
 	while (count < budget) {
-		unsigned int prev_head = head;
+		uint32_t prev_head = head;
 		struct mbuf *mhead, *mtail;
 		struct virtio_net_hdr *vh;
 		struct netmap_slot *slot;
 		unsigned int nmbuf_len;
 		uint8_t *nmbuf;
+		int deliver = 1; /* the mbuf to the network stack. */
 host_sync:
 		if (head == ring->tail) {
 			/* We ran out of slot, let's see if the host has
@@ -2082,6 +2084,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 				RD(1, "Fragmented vnet-hdr: dropping");
 				head = ptnet_rx_discard(kring, head);
 				pq->stats.iqdrops ++;
+				deliver = 0;
 				goto skip;
 			}
 			ND(1, "%s: vnet hdr: flags %x csum_start %u "
@@ -2188,31 +2191,40 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 				m_freem(mhead);
 				RD(1, "Csum offload error: dropping");
 				pq->stats.iqdrops ++;
-				goto skip;
+				deliver = 0;
 			}
 		}
 
-		pq->stats.packets ++;
-		pq->stats.bytes += mhead->m_pkthdr.len;
-
-		PTNET_Q_UNLOCK(pq);
-		(*ifp->if_input)(ifp, mhead);
-		PTNET_Q_LOCK(pq);
-
-		if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
-			/* The interface has gone down while we didn't
-			 * have the lock. Stop any processing and exit. */
-			goto unlock;
-		}
 skip:
 		count ++;
-		if (++batch_count == PTNET_RX_BATCH) {
-			/* Some packets have been pushed to the network stack.
-			 * We need to update the CSB to tell the host about the new
-			 * ring->cur and ring->head (RX buffer refill). */
+		if (++batch_count >= PTNET_RX_BATCH) {
+			/* Some packets have been (or will be) pushed to the network
+			 * stack. We need to update the CSB to tell the host about
+			 * the new ring->cur and ring->head (RX buffer refill). */
 			ptnet_ring_update(pq, kring, head, NAF_FORCE_READ);
 			batch_count = 0;
 		}
+
+		if (likely(deliver))  {
+			pq->stats.packets ++;
+			pq->stats.bytes += mhead->m_pkthdr.len;
+
+			PTNET_Q_UNLOCK(pq);
+			(*ifp->if_input)(ifp, mhead);
+			PTNET_Q_LOCK(pq);
+			/* The ring->head index (and related indices) are
+			 * updated under pq lock by ptnet_ring_update().
+			 * Since we dropped the lock to call if_input(), we
+			 * must reload ring->head and restart processing the
+			 * ring from there. */
+			head = ring->head;
+
+			if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
+				/* The interface has gone down while we didn't
+				 * have the lock. Stop any processing and exit. */
+				goto unlock;
+			}
+		}
 	}
 escape:
 	if (batch_count) {

From c46e33b1e42c2954037be1d8b7a8316a67fc1bf7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Jan 2018 12:38:41 +0000
Subject: [PATCH 0331/2207] FreeBSD: fix warning on unused functions

---
 sys/dev/netmap/netmap_mem2.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index d1629db4d..1870b8fed 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -664,28 +664,22 @@ nm_free_lut(struct lut_entry *lut, u_int objtotal)
 #endif
 }
 
+#ifdef linux
 static struct plut_entry *
 nm_alloc_plut(u_int nobj)
 {
 	size_t n = sizeof(struct plut_entry) * nobj;
 	struct plut_entry *lut;
-#ifdef linux
 	lut = vmalloc(n);
-#else
-	lut = nm_os_malloc(n);
-#endif
 	return lut;
 }
 
 static void
 nm_free_plut(struct plut_entry * lut)
 {
-#ifdef linux
 	vfree(lut);
-#else
-	nm_os_free(lut);
-#endif
 }
+#endif
 
 
 /*

From c076f8a6def868a01ad35d5f096de1b6664d5d79 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Jan 2018 15:22:30 +0100
Subject: [PATCH 0332/2207] bwrap: do not assume that the hw port has the host
 rings

---
 sys/dev/netmap/netmap_vale.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 5fb4dcbe6..2ada26c12 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2346,7 +2346,8 @@ netmap_bwrap_dtor(struct netmap_adapter *na)
 	struct nm_bridge *b = bna->up.na_bdg,
 		*bh = bna->host.na_bdg;
 
-	netmap_mem_put(bna->host.up.nm_mem);
+	if (bna->host.up.nm_mem)
+		netmap_mem_put(bna->host.up.nm_mem);
 
 	if (b) {
 		netmap_bdg_detach_common(b, bna->up.bdg_port,
@@ -2747,7 +2748,7 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, 0, NR_REG_NIC_SW);
+		error = netmap_do_regif(npriv, na, nmr->nr_ringid, nmr->nr_flags);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;

From 951954764b2941c305489730929df97e380dbdc7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Jan 2018 15:23:01 +0100
Subject: [PATCH 0333/2207] VALE: allow chaining of VALE switches

One can now use persistent VALE ports to chain two VALE switches:

vale-ctl -n vi0  	# create a persistent VALE port
vale-ctl -a vale0:vi0	# attach to the first switch
vale-ctl -a vale1:vi0	# attach to the second switch

Now vale0:x will be able to talk to vale1:y.

This can be useful to compose customized forwarding functions.
---
 sys/dev/netmap/netmap_vale.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 2ada26c12..bba274350 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2209,7 +2209,7 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 
 	if (vpna->na_bdg)
-		return EBUSY;
+		return netmap_bwrap_attach(name, na);
 	na->na_vp = vpna;
 	strncpy(na->name, name, sizeof(na->name));
 	na->na_hostvp = NULL;

From e8d35d01c1f2fd22147674ecc7d739c8636748fd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 26 Jan 2018 18:20:37 +0100
Subject: [PATCH 0334/2207] linux/config: add --kernel-versin= option

---
 LINUX/configure | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index be2562909..4b627bd6e 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -272,6 +272,8 @@ Available options:
   --help                       print this message
   --kernel-dir=                path to configured kernel directory
   --kernel-sources=            path to full kernel sources
+  --kernel-version=	       specifiy the kernel version
+  				(assuming everything is in the default place)
   --kernel-opts=	       additional options to pass to kernel make
                                (you can call this several times)
   --install-mod-path=          where the modules will be installed
@@ -517,6 +519,8 @@ for opt do
 	;;
 	--kernel-sources=*) src="$optarg"
 	;;
+	--kernel-version=*) ksrc="/lib/modules/$optarg/build"
+	;;
 	--kernel-opts=*) kopts="$kopts $optarg"
 	;;
 	--install-mod-path=*) modpath="$optarg"

From d19d4c8bc323f54d44a9cfc5bfe7d6d5af9fea48 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 29 Jan 2018 14:08:33 +0100
Subject: [PATCH 0335/2207] linux: don't assume that ACCESS_ONCE is available

---
 LINUX/bsd_glue.h           | 2 +-
 LINUX/ixgbe_netmap_linux.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 98aed6e96..fafde1f4d 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -325,7 +325,7 @@ static inline void mtx_lock(safe_spinlock_t *m)
 
 static inline void mtx_unlock(safe_spinlock_t *m)
 {
-	ulong flags = ACCESS_ONCE(m->flags);
+	ulong flags = *(volatile ulong *)&m->flags;
         spin_unlock_irqrestore(&(m->sl), flags);
 }
 
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index c372475b1..9c5a03b16 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -373,7 +373,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	(void)reclaim_tx;
 	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
-		u32 h = ACCESS_ONCE(*ina->heads[ring_nr].phead);
+		u32 h = NM_ACCESS_ONCE(*ina->heads[ring_nr].phead);
 		ND(5, "%s: h %d", kring->name, h);
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
 	}

From 4855d04931799e0693813461b41c4bd4ae4e6e39 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 29 Jan 2018 14:41:48 +0100
Subject: [PATCH 0336/2207] linux/e1000e: fix compilation on older very old
 kernels

---
 LINUX/if_e1000e_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 1117c026a..e9f66b17b 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -248,7 +248,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			PNMB(na, slot, &paddr);
-			slot->len = le16toh(curr->wb.upper.length) - strip_crc;
+			slot->len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
 			slot->flags = 0;
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr,
 					slot->len, NR_RX);

From 7244e442befccd9c61a692c41935312e856029f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 29 Jan 2018 14:48:39 +0100
Subject: [PATCH 0337/2207] linux: patches for v4.15

---
 ...99 => vanilla--virtio_net.c--40c00--40f00} |  0
 .../vanilla--virtio_net.c--40f00--99999       | 99 +++++++++++++++++++
 2 files changed, 99 insertions(+)
 rename LINUX/final-patches/{vanilla--virtio_net.c--40c00--99999 => vanilla--virtio_net.c--40c00--40f00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--40f00--99999

diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40c00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--40c00--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40f00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40f00--99999
new file mode 100644
index 000000000..63ce0bbf1
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40f00--99999
@@ -0,0 +1,99 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 559b215..00aad16 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -181,6 +181,10 @@ struct virtnet_info {
+ 	unsigned long guest_offloads;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_mrg_rxbuf hdr;
+ 	/*
+@@ -274,6 +278,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -1205,6 +1214,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int received;
+ 	bool xdp_xmit = false;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	struct virtnet_info *vi = rq->vq->vdev->priv;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -1223,6 +1245,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
+ 		if (i < vi->curr_queue_pairs)
+@@ -2685,6 +2716,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	virtnet_set_queues(vi, vi->curr_queue_pairs);
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+@@ -2736,7 +2771,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -2803,6 +2845,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From 20dd29fc379313c7ffcfb32740762efb87934149 Mon Sep 17 00:00:00 2001
From: Mitchell Horne 
Date: Wed, 31 Jan 2018 11:13:50 -0500
Subject: [PATCH 0338/2207] Clean up sysctls

Add descriptions to all sysctls that are missing them.
Remove unused sysctls and their variables:
 - netmap_mitigate
 - netmap_flags
Wrap netmap_generic_txqdisc in #ifdef linux
---
 sys/dev/netmap/netmap.c      | 43 ++++++++++++++++++++++--------------
 sys/dev/netmap/netmap_kern.h |  2 ++
 sys/dev/netmap/netmap_pipe.c |  3 ++-
 sys/dev/netmap/netmap_vale.c |  3 ++-
 utils/testmod/kern_test.c    |  2 +-
 5 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 93bb29130..2d4a6b88e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -480,10 +480,8 @@ ports attached to the switch)
 int netmap_verbose;
 
 static int netmap_no_timestamp; /* don't timestamp on rxsync */
-int netmap_mitigate = 1;
 int netmap_no_pendintr = 1;
 int netmap_txsync_retry = 2;
-int netmap_flags = 0;	/* debug flags */
 static int netmap_fwd = 0;	/* force transparent forwarding */
 
 /*
@@ -513,7 +511,9 @@ int netmap_generic_mit = 100*1000;
  * Anyway users looking for the best performance should
  * use native adapters.
  */
+#ifdef linux
 int netmap_generic_txqdisc = 1;
+#endif
 
 /* Default number of slots and queues for generic adapters. */
 int netmap_generic_ringsize = 1024;
@@ -537,21 +537,32 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
     CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
     CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
-SYSCTL_INT(_dev_netmap, OID_AUTO, mitigate, CTLFLAG_RW, &netmap_mitigate, 0, "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr,
-    CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets.");
+SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, CTLFLAG_RW, &netmap_no_pendintr,
+    0, "Always look for new received packets.");
 SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW,
-    &netmap_txsync_retry, 0 , "Number of txsync loops in bridge's flush.");
-
-SYSCTL_INT(_dev_netmap, OID_AUTO, flags, CTLFLAG_RW, &netmap_flags, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW, &netmap_generic_ringsize, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW, &netmap_generic_rings, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW, &netmap_generic_txqdisc, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW, &ptnetmap_tx_workers, 0 , "");
+    &netmap_txsync_retry, 0, "Number of txsync loops in bridge's flush.");
+
+SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0,
+    "Force NR_FORWARD mode");
+SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0,
+    "Adapter mode. 0 selects the best option available,"
+    "1 forces native adapter, 2 forces emulated adapter");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit,
+    0, "RX notification interval in nanoseconds");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW,
+    &netmap_generic_ringsize, 0,
+    "Number of per-ring slots for emulated netmap mode");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW,
+    &netmap_generic_rings, 0,
+    "Number of TX/RX queues for emulated netmap adapters");
+#ifdef linux
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW,
+    &netmap_generic_txqdisc, 0, "Use qdisc for generic adapters");
+#endif
+SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr,
+    0, "Allow ptnet devices to use virtio-net headers");
+SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW,
+    &ptnetmap_tx_workers, 0, "Use worker threads for pnetmap TX processing");
 
 SYSEND;
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f7a880e19..ea8e8ffc1 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1569,7 +1569,9 @@ extern int netmap_flags;
 extern int netmap_generic_mit;
 extern int netmap_generic_ringsize;
 extern int netmap_generic_rings;
+#ifdef linux
 extern int netmap_generic_txqdisc;
+#endif
 extern int ptnetmap_tx_workers;
 
 /*
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index f8fab8729..3b936d96f 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -79,7 +79,8 @@
 static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
 SYSBEGIN(vars_pipes);
 SYSCTL_DECL(_dev_netmap);
-SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW, &netmap_default_pipes, 0 , "");
+SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW,
+    &netmap_default_pipes, 0, "For compatibility only");
 SYSEND;
 
 /* allocate the pipe array in the parent adapter */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index bba274350..0704e4daa 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -160,7 +160,8 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 static int bridge_batch = NM_BDG_BATCH; /* bridge batch size */
 SYSBEGIN(vars_vale);
 SYSCTL_DECL(_dev_netmap);
-SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0 , "");
+SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
+    "Max batch size to be used in the bridge");
 SYSEND;
 
 static int netmap_vp_create(struct nmreq *, struct ifnet *,
diff --git a/utils/testmod/kern_test.c b/utils/testmod/kern_test.c
index 8773a6c2f..408c4092e 100644
--- a/utils/testmod/kern_test.c
+++ b/utils/testmod/kern_test.c
@@ -90,7 +90,7 @@ SYSCTL_ULONG(_kern_test, OID_AUTO, count,
 SYSCTL_ULONG(_kern_test, OID_AUTO, cycles,
     CTLFLAG_RW, &t_delta, 0, "runtime");
 SYSCTL_STRING(_kern_test, OID_AUTO, name,
-	CTLFLAG_RW, &test_name, sizeof(test_name), "");
+	CTLFLAG_RW, &test_name, sizeof(test_name), "name of the test");
 SYSCTL_PROC(_kern_test, OID_AUTO, run,
     CTLTYPE_U64 | CTLFLAG_RW, 0, 0, test_run,
     "U64", "run the test");

From 4ed7e52039b32a2fe5d4fed646f928a9a0a1fb2c Mon Sep 17 00:00:00 2001
From: Mitchell Horne 
Date: Wed, 31 Jan 2018 11:18:51 -0500
Subject: [PATCH 0339/2207] Add missing sysctls entries to man page

Entries added:
- dev.netmap.generic_rings
- dev.netmap.ptnet_vnet_hdr
- dev.netmap.ptnetmap_tx_workers
---
 share/man/man4/netmap.4 | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index aa8063a4e..bb09a6626 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 2, 2017
+.Dd January 31, 2018
 .Dt NETMAP 4
 .Os
 .Sh NAME
@@ -872,6 +872,8 @@ Controls the use of native or emulated adapter mode.
 1 forces native mode and fails if not available;
 .Pp
 2 forces emulated hence never fails.
+.It Va dev.netmap.generic_rings: 1
+Number of rings used for emulated netmap mode
 .It Va dev.netmap.generic_ringsize: 1024
 Ring size used for emulated netmap mode
 .It Va dev.netmap.generic_mit: 100000
@@ -913,6 +915,10 @@ Batch size used when moving packets across a
 switch.
 Values above 64 generally guarantee good
 performance.
+.It Va dev.netmap.ptnet_vnet_hdr: 1
+Allow ptnet devices to use virtio-net headers
+.It Va dev.netmap.ptnetmap_tx_workers: 1
+Use worker threads for ptnetmap TX processing
 .El
 .Sh SYSTEM CALLS
 .Nm

From cd5a07c4cd1a20738dec2d0b115ee767a9b3d3b0 Mon Sep 17 00:00:00 2001
From: Mitchell Horne 
Date: Wed, 31 Jan 2018 11:13:50 -0500
Subject: [PATCH 0340/2207] Clean up sysctls

Add descriptions to all sysctls that are missing them.
Remove unused sysctls and their variables:
 - netmap_mitigate
 - netmap_flags
Wrap netmap_generic_txqdisc in #ifdef linux
---
 sys/dev/netmap/netmap.c      | 43 ++++++++++++++++++++++--------------
 sys/dev/netmap/netmap_kern.h |  2 ++
 sys/dev/netmap/netmap_pipe.c |  3 ++-
 sys/dev/netmap/netmap_vale.c |  3 ++-
 utils/testmod/kern_test.c    |  2 +-
 5 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 93bb29130..2d4a6b88e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -480,10 +480,8 @@ ports attached to the switch)
 int netmap_verbose;
 
 static int netmap_no_timestamp; /* don't timestamp on rxsync */
-int netmap_mitigate = 1;
 int netmap_no_pendintr = 1;
 int netmap_txsync_retry = 2;
-int netmap_flags = 0;	/* debug flags */
 static int netmap_fwd = 0;	/* force transparent forwarding */
 
 /*
@@ -513,7 +511,9 @@ int netmap_generic_mit = 100*1000;
  * Anyway users looking for the best performance should
  * use native adapters.
  */
+#ifdef linux
 int netmap_generic_txqdisc = 1;
+#endif
 
 /* Default number of slots and queues for generic adapters. */
 int netmap_generic_ringsize = 1024;
@@ -537,21 +537,32 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
     CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
     CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
-SYSCTL_INT(_dev_netmap, OID_AUTO, mitigate, CTLFLAG_RW, &netmap_mitigate, 0, "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr,
-    CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets.");
+SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, CTLFLAG_RW, &netmap_no_pendintr,
+    0, "Always look for new received packets.");
 SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW,
-    &netmap_txsync_retry, 0 , "Number of txsync loops in bridge's flush.");
-
-SYSCTL_INT(_dev_netmap, OID_AUTO, flags, CTLFLAG_RW, &netmap_flags, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW, &netmap_generic_ringsize, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW, &netmap_generic_rings, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW, &netmap_generic_txqdisc, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr, 0 , "");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW, &ptnetmap_tx_workers, 0 , "");
+    &netmap_txsync_retry, 0, "Number of txsync loops in bridge's flush.");
+
+SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0,
+    "Force NR_FORWARD mode");
+SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0,
+    "Adapter mode. 0 selects the best option available,"
+    "1 forces native adapter, 2 forces emulated adapter");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit,
+    0, "RX notification interval in nanoseconds");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW,
+    &netmap_generic_ringsize, 0,
+    "Number of per-ring slots for emulated netmap mode");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW,
+    &netmap_generic_rings, 0,
+    "Number of TX/RX queues for emulated netmap adapters");
+#ifdef linux
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW,
+    &netmap_generic_txqdisc, 0, "Use qdisc for generic adapters");
+#endif
+SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr,
+    0, "Allow ptnet devices to use virtio-net headers");
+SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW,
+    &ptnetmap_tx_workers, 0, "Use worker threads for pnetmap TX processing");
 
 SYSEND;
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f7a880e19..ea8e8ffc1 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1569,7 +1569,9 @@ extern int netmap_flags;
 extern int netmap_generic_mit;
 extern int netmap_generic_ringsize;
 extern int netmap_generic_rings;
+#ifdef linux
 extern int netmap_generic_txqdisc;
+#endif
 extern int ptnetmap_tx_workers;
 
 /*
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index f8fab8729..3b936d96f 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -79,7 +79,8 @@
 static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
 SYSBEGIN(vars_pipes);
 SYSCTL_DECL(_dev_netmap);
-SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW, &netmap_default_pipes, 0 , "");
+SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW,
+    &netmap_default_pipes, 0, "For compatibility only");
 SYSEND;
 
 /* allocate the pipe array in the parent adapter */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index bba274350..0704e4daa 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -160,7 +160,8 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 static int bridge_batch = NM_BDG_BATCH; /* bridge batch size */
 SYSBEGIN(vars_vale);
 SYSCTL_DECL(_dev_netmap);
-SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0 , "");
+SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
+    "Max batch size to be used in the bridge");
 SYSEND;
 
 static int netmap_vp_create(struct nmreq *, struct ifnet *,
diff --git a/utils/testmod/kern_test.c b/utils/testmod/kern_test.c
index 8773a6c2f..408c4092e 100644
--- a/utils/testmod/kern_test.c
+++ b/utils/testmod/kern_test.c
@@ -90,7 +90,7 @@ SYSCTL_ULONG(_kern_test, OID_AUTO, count,
 SYSCTL_ULONG(_kern_test, OID_AUTO, cycles,
     CTLFLAG_RW, &t_delta, 0, "runtime");
 SYSCTL_STRING(_kern_test, OID_AUTO, name,
-	CTLFLAG_RW, &test_name, sizeof(test_name), "");
+	CTLFLAG_RW, &test_name, sizeof(test_name), "name of the test");
 SYSCTL_PROC(_kern_test, OID_AUTO, run,
     CTLTYPE_U64 | CTLFLAG_RW, 0, 0, test_run,
     "U64", "run the test");

From 22a3ce9ccb2e0d31a756d21e06e190616a392db7 Mon Sep 17 00:00:00 2001
From: Mitchell Horne 
Date: Wed, 31 Jan 2018 11:18:51 -0500
Subject: [PATCH 0341/2207] Add missing sysctls entries to man page

Entries added:
- dev.netmap.generic_rings
- dev.netmap.ptnet_vnet_hdr
- dev.netmap.ptnetmap_tx_workers
---
 share/man/man4/netmap.4 | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index aa8063a4e..bb09a6626 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 2, 2017
+.Dd January 31, 2018
 .Dt NETMAP 4
 .Os
 .Sh NAME
@@ -872,6 +872,8 @@ Controls the use of native or emulated adapter mode.
 1 forces native mode and fails if not available;
 .Pp
 2 forces emulated hence never fails.
+.It Va dev.netmap.generic_rings: 1
+Number of rings used for emulated netmap mode
 .It Va dev.netmap.generic_ringsize: 1024
 Ring size used for emulated netmap mode
 .It Va dev.netmap.generic_mit: 100000
@@ -913,6 +915,10 @@ Batch size used when moving packets across a
 switch.
 Values above 64 generally guarantee good
 performance.
+.It Va dev.netmap.ptnet_vnet_hdr: 1
+Allow ptnet devices to use virtio-net headers
+.It Va dev.netmap.ptnetmap_tx_workers: 1
+Use worker threads for ptnetmap TX processing
 .El
 .Sh SYSTEM CALLS
 .Nm

From fa168a2e2225dfc34dd7bf10010a8f56c49beb45 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 11:32:13 +0100
Subject: [PATCH 0342/2207] vale: reset na pointer on port destruction

---
 sys/dev/netmap/netmap_vale.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 0704e4daa..28d9dda2e 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -547,11 +547,14 @@ netmap_vp_dtor(struct netmap_adapter *na)
 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
 	}
 
-	if (vpna->autodelete && na->ifp != NULL) {
-		ND("releasing %s", na->ifp->if_xname);
-		NMG_UNLOCK();
-		nm_os_vi_detach(na->ifp);
-		NMG_LOCK();
+	if (na->ifp != NULL && !nm_iszombie(na)) {
+		WNA(na->ifp) = NULL;
+		if (vpna->autodelete) {
+			ND("releasing %s", na->ifp->if_xname);
+			NMG_UNLOCK();
+			nm_os_vi_detach(na->ifp);
+			NMG_LOCK();
+		}
 	}
 }
 

From 1050af454ff613713edcc93958918b92747790c0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 16:20:20 +0100
Subject: [PATCH 0343/2207] netmap.h: introduce new control API: struct
 nmreq_register

---
 sys/dev/netmap/netmap.c |   2 +-
 sys/net/netmap.h        | 116 ++++++++++++++++++++++++++++------------
 2 files changed, 83 insertions(+), 35 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2d4a6b88e..3ed315b5c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -260,7 +260,7 @@ ports attached to the switch)
  *
  *  Any network interface known to the system (including a persistent VALE
  *  port) can be attached to a VALE switch by issuing the
- *  NETMAP_BDG_ATTACH subcommand. After the attachment, persistent VALE ports
+ *  NETMAP_REQ_VALE_ATTACH command. After the attachment, persistent VALE ports
  *  look exactly like ephemeral VALE ports (as created in step 2 above).  The
  *  attachment of other interfaces, instead, requires the creation of a
  *  netmap_bwrap_adapter.  Moreover, the attached interface must be put in
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a85bb3004..71c7ed6c3 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -367,7 +367,6 @@ struct netmap_if {
 };
 
 
-#ifndef NIOCREGIF
 /*
  * ioctl names and related fields
  *
@@ -532,40 +531,12 @@ struct nmreq {
 
 	uint16_t	nr_arg2;
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
-	uint32_t	nr_flags;
+	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
+#define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */
 	/* various modes, extends nr_ringid */
 	uint32_t	spare2[1];
 };
 
-#define NR_REG_MASK		0xf /* values for nr_flags */
-enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
-	NR_REG_ALL_NIC	= 1,
-	NR_REG_SW	= 2,
-	NR_REG_NIC_SW	= 3,
-	NR_REG_ONE_NIC	= 4,
-	NR_REG_PIPE_MASTER = 5,
-	NR_REG_PIPE_SLAVE = 6,
-};
-/* monitor uses the NR_REG to select the rings to monitor */
-#define NR_MONITOR_TX	0x100
-#define NR_MONITOR_RX	0x200
-#define NR_ZCOPY_MON	0x400
-/* request exclusive access to the selected rings */
-#define NR_EXCLUSIVE	0x800
-/* request ptnetmap host support */
-#define NR_PASSTHROUGH_HOST	NR_PTNETMAP_HOST /* deprecated */
-#define NR_PTNETMAP_HOST	0x1000
-#define NR_RX_RINGS_ONLY	0x2000
-#define NR_TX_RINGS_ONLY	0x4000
-/* Applications set this flag if they are able to deal with virtio-net headers,
- * that is send/receive frames that start with a virtio-net header.
- * If not set, NIOCREGIF will fail with netmap ports that require applications
- * to use those headers. If the flag is set, the application can use the
- * NETMAP_VNET_HDR_GET command to figure out the header length. */
-#define NR_ACCEPT_VNET_HDR	0x8000
-
-#define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
-
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
@@ -591,11 +562,11 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 #define NETMAP_GETSOCKOPT _IO('i', 141)
 
 
-//These linknames are for the Netmap Core Driver
+/* These linknames are for the Netmap Core Driver */
 #define NETMAP_NT_DEVICE_NAME			L"\\Device\\NETMAP"
 #define NETMAP_DOS_DEVICE_NAME			L"\\DosDevices\\netmap"
 
-//Definition of a structure used to pass a virtual address within an IOCTL
+/* Definition of a structure used to pass a virtual address within an IOCTL */
 typedef struct _MEMORY_ENTRY {
 	PVOID       pUsermodeVirtualAddress;
 } MEMORY_ENTRY, *PMEMORY_ENTRY;
@@ -619,9 +590,86 @@ typedef struct _POLL_REQUEST_DATA {
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
 #define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
 #define NIOCCONFIG	_IOWR('i',150, struct nm_ifreq) /* for ext. modules */
-#endif /* !NIOCREGIF */
 
 
+/*
+ * New API to control netmap control devices, deprecating 'struct nmreq',
+ * NIOCREGIF, NIOCGINFO and NIOCCONFIG. New applications should only use
+ * nmreq_xyz structs.
+ */
+
+/* Header common to all requests. */
+struct nmreq_header {
+	uint16_t	nr_version;	/* API version */
+	uint16_t	nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+};
+
+enum {
+	/* Register a netmap port with the device. */
+	NETMAP_REQ_REGISTER = 1,
+	NETMAP_REQ_VALE_ATTACH,
+};
+
+/* Bind (register) a netmap port to this control device. */
+struct nmreq_register {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
+	uint64_t	nr_offset;	/* nifp offset in the shared region */
+	uint64_t	nr_memsize;	/* size of the shared region */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	uint16_t	nr_ringid;	/* ring(s) we care about */
+	uint32_t	nr_mode;	/* specify NR_REG_* modes */
+
+	uint64_t	nr_flags;	/* additional flags (see below) */
+/* monitors use nr_ringid and nr_mode to select the rings to monitor */
+#define NR_MONITOR_TX	0x100
+#define NR_MONITOR_RX	0x200
+#define NR_ZCOPY_MON	0x400
+/* request exclusive access to the selected rings */
+#define NR_EXCLUSIVE	0x800
+/* request ptnetmap host support */
+#define NR_PASSTHROUGH_HOST	NR_PTNETMAP_HOST /* deprecated */
+#define NR_PTNETMAP_HOST	0x1000
+#define NR_RX_RINGS_ONLY	0x2000
+#define NR_TX_RINGS_ONLY	0x4000
+/* Applications set this flag if they are able to deal with virtio-net headers,
+ * that is send/receive frames that start with a virtio-net header.
+ * If not set, NIOCREGIF will fail with netmap ports that require applications
+ * to use those headers. If the flag is set, the application can use the
+ * NETMAP_VNET_HDR_GET command to figure out the header length. */
+#define NR_ACCEPT_VNET_HDR	0x8000
+/* The following two have the same meaning of NETMAP_NO_TX_POLL and
+ * NETMAP_DO_RX_POLL. */
+#define NR_DO_RX_POLL		0x10000
+#define NR_NO_TX_POLL		0x20000
+
+	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
+	uint8_t         nr_spare[64];
+};
+
+/* Valid values for nmreq_register.nr_mode (see above). */
+enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
+	NR_REG_ALL_NIC	= 1,
+	NR_REG_SW	= 2,
+	NR_REG_NIC_SW	= 3,
+	NR_REG_ONE_NIC	= 4,
+	NR_REG_PIPE_MASTER = 5,
+	NR_REG_PIPE_SLAVE = 6,
+};
+
+#define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
+
+struct nmreq_vale_attach {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+};
+
 /*
  * Helper functions for kernel and userspace
  */

From d60cbf1ff989144057d4889691b3782dfab34b91 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 16:28:25 +0100
Subject: [PATCH 0344/2207] na_bdg_ctl: remove unused (and obsoleted) struct
 nmreq argument

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 sys/dev/netmap/netmap_vale.c | 9 ++++-----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index ea8e8ffc1..cec5fda3c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -789,7 +789,7 @@ struct netmap_adapter {
 	 *      Called with NMG_LOCK held.
 	 */
 	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *);
-	int (*nm_bdg_ctl)(struct netmap_adapter *, struct nmreq *, int);
+	int (*nm_bdg_ctl)(struct netmap_adapter *, int);
 
 	/* adapter used to attach this adapter to a VALE switch (if any) */
 	struct netmap_vp_adapter *na_vp;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 28d9dda2e..d9faca7ec 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -515,12 +515,11 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 
 /* nm_bdg_ctl callback for VALE ports */
 static int
-netmap_vp_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach)
+netmap_vp_bdg_ctl(struct netmap_adapter *na, int attach)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 	struct nm_bridge *b = vpna->na_bdg;
 
-	(void)nmr;	// XXX merge ?
 	if (attach)
 		return 0; /* nothing to do */
 	if (b) {
@@ -885,7 +884,7 @@ nm_bdg_ctl_attach(struct nmreq *nmr)
 		/* nop for VALE ports. The bwrap needs to put the hwna
 		 * in netmap mode (see netmap_bwrap_bdg_ctl)
 		 */
-		error = na->nm_bdg_ctl(na, nmr, 1);
+		error = na->nm_bdg_ctl(na, 1);
 		if (error)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
@@ -933,7 +932,7 @@ nm_bdg_ctl_detach(struct nmreq *nmr)
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
 		 */
-		error = na->nm_bdg_ctl(na, nmr, 0);
+		error = na->nm_bdg_ctl(na, 0);
 	}
 
 	netmap_adapter_put(na);
@@ -2734,7 +2733,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
  * directed to hwna.
  */
 static int
-netmap_bwrap_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach)
+netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 {
 	struct netmap_priv_d *npriv;
 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;

From c8644453c53d52ae7f3f96859914ed30993f40bb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 17:06:29 +0100
Subject: [PATCH 0345/2207] netmap.h: introduce nmreq_* commands for bridge
 operations

---
 sys/net/netmap.h | 76 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 55 insertions(+), 21 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 71c7ed6c3..2dceb570a 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -324,6 +324,18 @@ struct netmap_ring {
 	 * Enables the NS_FORWARD slot flag for the ring.
 	 */
 
+/*
+ * Helper functions for kernel and userspace
+ */
+
+/*
+ * check if space is available in the ring.
+ */
+static inline int
+nm_ring_empty(struct netmap_ring *ring)
+{
+	return (ring->cur == ring->tail);
+}
 
 /*
  * Netmap representation of an interface and its queue(s).
@@ -527,7 +539,6 @@ struct nmreq {
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
 #define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
-#define NETMAP_BDG_HOST		1	/* attach the host stack on ATTACH */
 
 	uint16_t	nr_arg2;
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
@@ -537,6 +548,17 @@ struct nmreq {
 	uint32_t	spare2[1];
 };
 
+/*
+ * Opaque structure that is passed to an external kernel
+ * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
+ * bridge port (at this point ephemeral VALE interface).
+ */
+#define NM_IFRDATA_LEN 256
+struct nm_ifreq {
+	char nifr_name[IFNAMSIZ];
+	char data[NM_IFRDATA_LEN];
+};
+
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
@@ -607,10 +629,18 @@ struct nmreq_header {
 enum {
 	/* Register a netmap port with the device. */
 	NETMAP_REQ_REGISTER = 1,
+	/* Attach a netmap port to a VALE switch. */
 	NETMAP_REQ_VALE_ATTACH,
+	/* Detach a netmap port from a VALE switch. */
+	NETMAP_REQ_VALE_DETACH,
+	/* List the ports attached to a VALE switch. */
+	NETMAP_REQ_VALE_LIST,
 };
 
-/* Bind (register) a netmap port to this control device. */
+/*
+ * nr_reqtype: NETMAP_REQ_REGISTER
+ * Bind (register) a netmap port to this control device.
+ */
 struct nmreq_register {
 	struct nmreq_header nr_hdr;
 	char		nr_name[64];	/* name of the netmap port */
@@ -664,34 +694,38 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_ATTACH
+ * Attach a netmap port to a VALE switch. Both the name of the netmap
+ * port and the VALE switch are specified through the nr_name argument.
+ */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
-	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	char		nr_name[128];	/* name in the form valeXXX:YYY */
+	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
+	uint16_t	nr_flags;	/* flags (see below) */
+#define NETMAP_BDG_HOST		0x1	/* attach the host stack */
 };
 
 /*
- * Helper functions for kernel and userspace
- */
-
-/*
- * check if space is available in the ring.
+ * nr_reqtype: NETMAP_REQ_VALE_DETACH
+ * Detach a netmap port from a VALE switch. Both the name of the netmap
+ * port and the VALE switch are specified through the nr_name argument.
  */
-static inline int
-nm_ring_empty(struct netmap_ring *ring)
-{
-	return (ring->cur == ring->tail);
-}
+struct nmreq_vale_detach {
+	struct nmreq_header nr_hdr;
+	char		nr_name[128];	/* name in the form valeXXX:YYY */
+};
 
 /*
- * Opaque structure that is passed to an external kernel
- * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
- * bridge port (at this point ephemeral VALE interface).
+ * nr_reqtype: NETMAP_REQ_VALE_LIST
+ * List the ports of a VALE switch.
  */
-#define NM_IFRDATA_LEN 256
-struct nm_ifreq {
-	char nifr_name[IFNAMSIZ];
-	char data[NM_IFRDATA_LEN];
+struct nmreq_vale_list {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the VALE switch or empty */
+	uint16_t	nr_bridge_idx;
+	uint16_t	nr_port_idx;
 };
 
 #endif /* _NET_NETMAP_H_ */

From 2a3677f81327ee026605cd2de441debc63cd1387 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 17:31:56 +0100
Subject: [PATCH 0346/2207] netmap.h: introduce nmreq_* structs to handle
 persistent VALE ports

---
 sys/net/netmap.h | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 2dceb570a..44ccbe5b6 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -635,6 +635,12 @@ enum {
 	NETMAP_REQ_VALE_DETACH,
 	/* List the ports attached to a VALE switch. */
 	NETMAP_REQ_VALE_LIST,
+	/* Set the port header length (was virtio-net header length). */
+	NETMAP_REQ_SET_PORT_HDR,
+	/* Create a new persistent VALE port. */
+	NETMAP_REQ_VALE_NEWIF,
+	/* Delete a persistent VALE port. */
+	NETMAP_REQ_VALE_DELIF,
 };
 
 /*
@@ -701,7 +707,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[128];	/* name in the form valeXXX:YYY */
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* attach the host stack */
@@ -714,7 +720,7 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[128];	/* name in the form valeXXX:YYY */
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
 };
 
 /*
@@ -728,4 +734,36 @@ struct nmreq_vale_list {
 	uint16_t	nr_port_idx;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_SET_PORT_HDR
+ * Set the port header length.
+ */
+struct nmreq_set_port_hdr {
+	struct nmreq_header nr_hdr;
+	uint32_t	nr_hdr_len;
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_NEWIF
+ * Create a new persistent VALE port.
+ */
+struct nmreq_vale_newif {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_DELIF
+ * Delete a persistent VALE port.
+ */
+struct nmreq_vale_delif {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
+};
+
 #endif /* _NET_NETMAP_H_ */

From de99d0fef6bc5730f80fa85e6086af87a2de73f4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 17:36:36 +0100
Subject: [PATCH 0347/2207] netmap.h: introduce nmreq_* structs for vnet header
 set/get

---
 sys/net/netmap.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 44ccbe5b6..4b7acf1d2 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -636,7 +636,9 @@ enum {
 	/* List the ports attached to a VALE switch. */
 	NETMAP_REQ_VALE_LIST,
 	/* Set the port header length (was virtio-net header length). */
-	NETMAP_REQ_SET_PORT_HDR,
+	NETMAP_REQ_PORT_HDR_SET,
+	/* Get the port header length (was virtio-net header length). */
+	NETMAP_REQ_PORT_HDR_GET,
 	/* Create a new persistent VALE port. */
 	NETMAP_REQ_VALE_NEWIF,
 	/* Delete a persistent VALE port. */
@@ -735,11 +737,22 @@ struct nmreq_vale_list {
 };
 
 /*
- * nr_reqtype: NETMAP_REQ_SET_PORT_HDR
+ * nr_reqtype: NETMAP_REQ_PORT_HDR_SET
  * Set the port header length.
  */
 struct nmreq_set_port_hdr {
 	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
+	uint32_t	nr_hdr_len;
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_PORT_HDR_GET
+ * Get the port header length.
+ */
+struct nmreq_get_port_hdr {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
 	uint32_t	nr_hdr_len;
 };
 

From 7fac54cc0a78513f56b77577c3fdc85c1f507658 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 18:28:54 +0100
Subject: [PATCH 0348/2207] netmap.h, netmap_virt.h: introduce nmreq_* structs
 for netmap passthrough

---
 sys/net/netmap.h      | 74 +++++++++++++++++++++++++++++++------------
 sys/net/netmap_virt.h | 24 +++++++++++++-
 2 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 4b7acf1d2..06d9dcc18 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -529,7 +529,6 @@ struct nmreq {
 #define NETMAP_BDG_REGOPS	3	/* register bridge callbacks */
 #define NETMAP_BDG_LIST		4	/* get bridge's info */
 #define NETMAP_BDG_VNET_HDR     5       /* set the port virtio-net-hdr length */
-#define NETMAP_BDG_OFFSET	NETMAP_BDG_VNET_HDR	/* deprecated alias */
 #define NETMAP_BDG_NEWIF	6	/* create a virtual port */
 #define NETMAP_BDG_DELIF	7	/* destroy a virtual port */
 #define NETMAP_PT_HOST_CREATE	8	/* create ptnetmap kthreads */
@@ -643,15 +642,29 @@ enum {
 	NETMAP_REQ_VALE_NEWIF,
 	/* Delete a persistent VALE port. */
 	NETMAP_REQ_VALE_DELIF,
+	/* Enable polling kthread on a VALE port. */
+	NETMAP_REQ_VALE_POLLING_ENABLE,
+	/* Disable polling kthread on a VALE port. */
+	NETMAP_REQ_VALE_POLLING_DISABLE,
+	/* Get info about the pools of a memory allocator. */
+	NETMAP_REQ_POOLS_INFO_GET,
+	/* Enable host-side ptnetmap processing (e.g. start ptnetmap
+	 * kthreads). */
+	NETMAP_REQ_PASSTHROUGH_ENABLE,
+	/* Disable host-side ptnetmap processing (e.g. stop ptnetmap
+	 * kthreads). */
+	NETMAP_REQ_PASSTHROUGH_DISABLE,
 };
 
+#define NETMAP_REQ_IFNAMSIZ	64
+
 /*
  * nr_reqtype: NETMAP_REQ_REGISTER
  * Bind (register) a netmap port to this control device.
  */
 struct nmreq_register {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -709,7 +722,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* attach the host stack */
@@ -722,7 +735,7 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 /*
@@ -731,28 +744,19 @@ struct nmreq_vale_detach {
  */
 struct nmreq_vale_list {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the VALE switch or empty */
+	/* Name of the VALE port (valeXXX:YYY) or empty. */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint16_t	nr_bridge_idx;
 	uint16_t	nr_port_idx;
 };
 
 /*
- * nr_reqtype: NETMAP_REQ_PORT_HDR_SET
+ * nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
  * Set the port header length.
  */
-struct nmreq_set_port_hdr {
+struct nmreq_port_hdr {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
-	uint32_t	nr_hdr_len;
-};
-
-/*
- * nr_reqtype: NETMAP_REQ_PORT_HDR_GET
- * Get the port header length.
- */
-struct nmreq_get_port_hdr {
-	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint32_t	nr_hdr_len;
 };
 
@@ -762,7 +766,7 @@ struct nmreq_get_port_hdr {
  */
 struct nmreq_vale_newif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -776,7 +780,37 @@ struct nmreq_vale_newif {
  */
 struct nmreq_vale_delif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
+ * Enable or disable polling kthreads on a VALE port.
+ */
+struct nmreq_vale_polling {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
+ * Get info about the pools of a memory allocator (used i.e. by
+ * a ptnetmap-enabled hypervisor).
+ */
+struct nmreq_pools_info_get {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];
+	uint64_t	nr_memsize;
+	uint64_t	nr_mem_id;
+	uint64_t	nr_if_pool_offset;
+	uint32_t	nr_if_pool_objtotal;
+	uint32_t	nr_if_pool_objsize;
+	uint64_t	nr_ring_pool_offset;
+	uint32_t	nr_ring_pool_objtotal;
+	uint32_t	nr_ring_pool_objsize;
+	uint64_t	nr_buf_pool_offset;
+	uint32_t	nr_buf_pool_objtotal;
+	uint32_t	nr_buf_pool_objsize;
 };
 
 #endif /* _NET_NETMAP_H_ */
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index a520a16dc..7b1f769d8 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -109,10 +109,31 @@ struct ptnetmap_cfgentry_bhyve {
 	} ioctl_data;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_PASSTHROUGH_ENABLE
+ * Enable host-side ptnetmap processing (e.g. start ptnetmap kthreads).
+ */
+struct nmreq_passthrough_enable {
+	struct nmreq_header	nr_hdr;
+	/* Userspace pointer to a variable-size struct containing the
+	 * ptnetmap configuration. */
+	struct pnetmap_cfg	*nr_cfg;
+	/* Length of the configuration struct above (in bytes). */
+	uint32_t		nr_cfg_len;
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_PASSTHROUGH_DISABLE
+ * Disalbe host-side ptnetmap processing (e.g. stop ptnetmap kthreads).
+ */
+struct nmreq_passthrough_disable {
+	struct nmreq_header	nr_hdr;
+};
+
 /*
  * Structure filled-in by the kernel when asked for allocator info
  * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
- * ptnetmap.
+ * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
  */
 struct netmap_pools_info {
 	uint64_t memsize;	/* same as nmr->nr_memsize */
@@ -131,6 +152,7 @@ struct netmap_pools_info {
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
  * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.
+ * XXX deprecated
  */
 static inline void
 nmreq_pointer_put(struct nmreq *nmr, void *userptr)

From afddd8fbc17bb8a25c1ccf7c4387f9539544c163 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 18:37:25 +0100
Subject: [PATCH 0349/2207] netmap.h: add missing nmreq_vale_ops_register

---
 sys/net/netmap.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 06d9dcc18..5d2473fc7 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -654,6 +654,8 @@ enum {
 	/* Disable host-side ptnetmap processing (e.g. stop ptnetmap
 	 * kthreads). */
 	NETMAP_REQ_PASSTHROUGH_DISABLE,
+	/* Program a VALE switch by registering custom callbacks. */
+	NETMAP_REQ_VALE_OPS_REGISTER,
 };
 
 #define NETMAP_REQ_IFNAMSIZ	64
@@ -813,4 +815,16 @@ struct nmreq_pools_info_get {
 	uint32_t	nr_buf_pool_objsize;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_OPS_REGISTER
+ * Program a VALE switch by registering custom callbacks (e.g.
+ * lookup, config and dtor). This netmap request should not
+ * be called from userspace programs, but only by kernel
+ * modules.
+ */
+struct nmreq_vale_ops_register {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+};
+
 #endif /* _NET_NETMAP_H_ */

From dbd858d9be314c03f5494e92da9d794aaae93d61 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 18:57:15 +0100
Subject: [PATCH 0350/2207] netmap.h: add missing struct to replace NIOCGINFO

---
 sys/net/netmap.h | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 5d2473fc7..d8393032b 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -614,9 +614,8 @@ typedef struct _POLL_REQUEST_DATA {
 
 
 /*
- * New API to control netmap control devices, deprecating 'struct nmreq',
- * NIOCREGIF, NIOCGINFO and NIOCCONFIG. New applications should only use
- * nmreq_xyz structs.
+ * New API to control netmap control devices. New applications should only use
+ * nmreq_xyz structs with the NIOCCTRL ioctl() command.
  */
 
 /* Header common to all requests. */
@@ -628,6 +627,8 @@ struct nmreq_header {
 enum {
 	/* Register a netmap port with the device. */
 	NETMAP_REQ_REGISTER = 1,
+	/* Get information from a netmap port. */
+	NETMAP_REQ_PORT_INFO_GET,
 	/* Attach a netmap port to a VALE switch. */
 	NETMAP_REQ_VALE_ATTACH,
 	/* Detach a netmap port from a VALE switch. */
@@ -715,6 +716,30 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 	NR_REG_PIPE_SLAVE = 6,
 };
 
+/* A single ioctl number is shared by all the new API command.
+ * Demultiplexing is done using the nr_hdr.nr_reqtype field.
+ * FreeBSD uses the size value embedded in the _IOWR to determine
+ * how much to copy in/out, so we define the ioctl() command
+ * specifying the largest among the nmreq_xyz structs. */
+#define NIOCCTRL	_IOWR('i', 151, struct nmreq_register)
+
+/*
+ * nr_reqtype: NETMAP_REQ_PORT_INFO_GET
+ * Get information about a netmap port, including number of rings.
+ * slots per ring, id of the memory allocator, etc.
+ */
+struct nmreq_port_info_get {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* netmap port name */
+	uint64_t	nr_offset;	/* nifp offset in the shared region */
+	uint64_t	nr_memsize;	/* size of the shared region */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+};
+
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
 /*

From c9ac7f52f1bb982c085a26914e858b22214e818e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 19:11:21 +0100
Subject: [PATCH 0351/2207] nmreq: move legacy definitions in a separate file
 to improve readability

---
 LINUX/netmap.mak.in     |   1 +
 sys/net/netmap.h        | 242 ++-----------------------------------
 sys/net/netmap_legacy.h | 260 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 234 deletions(-)
 create mode 100644 sys/net/netmap_legacy.h

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index ce71bc972..4e2a5b30f 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -133,6 +133,7 @@ install-headers:
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap.h
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_user.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_user.h
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_virt.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_virt.h
+	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_legacy.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_legacy.h
 
 MAN_PREFIX := $(INCLUDE_PREFIX)
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d8393032b..9ceb6ee66 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -378,240 +378,10 @@ struct netmap_if {
 	const ssize_t	ring_ofs[0];
 };
 
-
-/*
- * ioctl names and related fields
- *
- * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
- *	whose identity is set in NIOCREGIF through nr_ringid.
- *	These are non blocking and take no argument.
- *
- * NIOCGINFO takes a struct ifreq, the interface name is the input,
- *	the outputs are number of queues and number of descriptor
- *	for each queue (useful to set number of threads etc.).
- *	The info returned is only advisory and may change before
- *	the interface is bound to a file descriptor.
- *
- * NIOCREGIF takes an interface name within a struct nmre,
- *	and activates netmap mode on the interface (if possible).
- *
- * The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
- * can pass it down to other NIC-related ioctls.
- *
- * The actual argument (struct nmreq) has a number of options to request
- * different functions.
- * The following are used in NIOCREGIF when nr_cmd == 0:
- *
- * nr_name	(in)
- *	The name of the port (em0, valeXXX:YYY, etc.)
- *	limited to IFNAMSIZ for backward compatibility.
- *
- * nr_version	(in/out)
- *	Must match NETMAP_API as used in the kernel, error otherwise.
- *	Always returns the desired value on output.
- *
- * nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
- *	On input, non-zero values may be used to reconfigure the port
- *	according to the requested values, but this is not guaranteed.
- *	On output the actual values in use are reported.
- *
- * nr_ringid (in)
- *	Indicates how rings should be bound to the file descriptors.
- *	If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
- *	are used to indicate the ring number, and nr_flags specifies
- *	the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
- *
- *	NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
- *	If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
- *	the binding as follows:
- *	0 (default)			binds all physical rings
- *	NETMAP_HW_RING | ring number	binds a single ring pair
- *	NETMAP_SW_RING			binds only the host tx/rx rings
- *
- *	NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
- *		packets on tx rings only if POLLOUT is set.
- *		The default is to push any pending packet.
- *
- *	NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
- *		packets on rx rings also when POLLIN is NOT set.
- *		The default is to touch the rx ring only with POLLIN.
- *		Note that this is the opposite of TX because it
- *		reflects the common usage.
- *
- *	NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
- *	NETMAP_PRIV_MEM is set on return for ports that do not use
- *		the global memory allocator.
- *		This information is not significant and applications
- *		should look at the region id in nr_arg2
- *
- * nr_flags	is the recommended mode to indicate which rings should
- *		be bound to a file descriptor. Values are NR_REG_*
- *
- * nr_arg1 (in)	The number of extra rings to be reserved.
- *		Especially when allocating a VALE port the system only
- *		allocates the amount of memory needed for the port.
- *		If more shared memory rings are desired (e.g. for pipes),
- *		the first invocation for the same basename/allocator
- *		should specify a suitable number. Memory cannot be
- *		extended after the first allocation without closing
- *		all ports on the same region.
- *
- * nr_arg2 (in/out) The identity of the memory region used.
- *		On input, 0 means the system decides autonomously,
- *		other values may try to select a specific region.
- *		On return the actual value is reported.
- *		Region '1' is the global allocator, normally shared
- *		by all interfaces. Other values are private regions.
- *		If two ports the same region zero-copy is possible.
- *
- * nr_arg3 (in/out)	number of extra buffers to be allocated.
- *
- *
- *
- * nr_cmd (in)	if non-zero indicates a special command:
- *	NETMAP_BDG_ATTACH	 and nr_name = vale*:ifname
- *		attaches the NIC to the switch; nr_ringid specifies
- *		which rings to use. Used by vale-ctl -a ...
- *	    nr_arg1 = NETMAP_BDG_HOST also attaches the host port
- *		as in vale-ctl -h ...
- *
- *	NETMAP_BDG_DETACH	and nr_name = vale*:ifname
- *		disconnects a previously attached NIC.
- *		Used by vale-ctl -d ...
- *
- *	NETMAP_BDG_LIST
- *		list the configuration of VALE switches.
- *
- *	NETMAP_BDG_VNET_HDR
- *		Set the virtio-net header length used by the client
- *		of a VALE switch port.
- *
- *	NETMAP_BDG_NEWIF
- *		create a persistent VALE port with name nr_name.
- *		Used by vale-ctl -n ...
- *
- *	NETMAP_BDG_DELIF
- *		delete a persistent VALE port. Used by vale-ctl -d ...
- *
- * nr_arg1, nr_arg2, nr_arg3  (in/out)		command specific
- *
- *
- *
- */
-
-
-/*
- * struct nmreq overlays a struct ifreq (just the name)
- */
-struct nmreq {
-	char		nr_name[IFNAMSIZ];
-	uint32_t	nr_version;	/* API version */
-	uint32_t	nr_offset;	/* nifp offset in the shared region */
-	uint32_t	nr_memsize;	/* size of the shared region */
-	uint32_t	nr_tx_slots;	/* slots in tx rings */
-	uint32_t	nr_rx_slots;	/* slots in rx rings */
-	uint16_t	nr_tx_rings;	/* number of tx rings */
-	uint16_t	nr_rx_rings;	/* number of rx rings */
-
-	uint16_t	nr_ringid;	/* ring(s) we care about */
-#define NETMAP_HW_RING		0x4000	/* single NIC ring pair */
-#define NETMAP_SW_RING		0x2000	/* only host ring pair */
-
-#define NETMAP_RING_MASK	0x0fff	/* the ring number */
-
-#define NETMAP_NO_TX_POLL	0x1000	/* no automatic txsync on poll */
-
-#define NETMAP_DO_RX_POLL	0x8000	/* DO automatic rxsync on poll */
-
-	uint16_t	nr_cmd;
-#define NETMAP_BDG_ATTACH	1	/* attach the NIC */
-#define NETMAP_BDG_DETACH	2	/* detach the NIC */
-#define NETMAP_BDG_REGOPS	3	/* register bridge callbacks */
-#define NETMAP_BDG_LIST		4	/* get bridge's info */
-#define NETMAP_BDG_VNET_HDR     5       /* set the port virtio-net-hdr length */
-#define NETMAP_BDG_NEWIF	6	/* create a virtual port */
-#define NETMAP_BDG_DELIF	7	/* destroy a virtual port */
-#define NETMAP_PT_HOST_CREATE	8	/* create ptnetmap kthreads */
-#define NETMAP_PT_HOST_DELETE	9	/* delete ptnetmap kthreads */
-#define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
-#define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
-#define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
-#define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
-	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
-
-	uint16_t	nr_arg2;
-	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
-	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
-#define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */
-	/* various modes, extends nr_ringid */
-	uint32_t	spare2[1];
-};
-
-/*
- * Opaque structure that is passed to an external kernel
- * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
- * bridge port (at this point ephemeral VALE interface).
- */
-#define NM_IFRDATA_LEN 256
-struct nm_ifreq {
-	char nifr_name[IFNAMSIZ];
-	char data[NM_IFRDATA_LEN];
-};
-
-#ifdef _WIN32
-/*
- * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
- * in ws2def.h but not sure if they are in the form we need.
- * We therefore redefine them in a convenient way to use for DeviceIoControl
- * signatures.
- */
-#undef _IO	// ws2def.h
-#define _WIN_NM_IOCTL_TYPE 40000
-#define _IO(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
-		METHOD_BUFFERED, FILE_ANY_ACCESS  )
-#define _IO_direct(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
-		METHOD_OUT_DIRECT, FILE_ANY_ACCESS  )
-
-#define _IOWR(_c, _n, _s)	_IO(_c, _n)
-
-/* We havesome internal sysctl in addition to the externally visible ones */
-#define NETMAP_MMAP _IO_direct('i', 160)	// note METHOD_OUT_DIRECT
-#define NETMAP_POLL _IO('i', 162)
-
-/* and also two setsockopt for sysctl emulation */
-#define NETMAP_SETSOCKOPT _IO('i', 140)
-#define NETMAP_GETSOCKOPT _IO('i', 141)
-
-
-/* These linknames are for the Netmap Core Driver */
-#define NETMAP_NT_DEVICE_NAME			L"\\Device\\NETMAP"
-#define NETMAP_DOS_DEVICE_NAME			L"\\DosDevices\\netmap"
-
-/* Definition of a structure used to pass a virtual address within an IOCTL */
-typedef struct _MEMORY_ENTRY {
-	PVOID       pUsermodeVirtualAddress;
-} MEMORY_ENTRY, *PMEMORY_ENTRY;
-
-typedef struct _POLL_REQUEST_DATA {
-	int events;
-	int timeout;
-	int revents;
-} POLL_REQUEST_DATA;
-
-#endif /* _WIN32 */
-
-/*
- * FreeBSD uses the size value embedded in the _IOWR to determine
- * how much to copy in/out. So we need it to match the actual
- * data structure we pass. We put some spares in the structure
- * to ease compatibility with other versions
- */
-#define NIOCGINFO	_IOWR('i', 145, struct nmreq) /* return IF info */
-#define NIOCREGIF	_IOWR('i', 146, struct nmreq) /* interface register */
-#define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
-#define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
-#define NIOCCONFIG	_IOWR('i',150, struct nm_ifreq) /* for ext. modules */
-
+/* Legacy interface to interact with a netmap control device.
+ * Included for backward compatibility. The user should not include this
+ * file directly. */
+#include "netmap_legacy.h"
 
 /*
  * New API to control netmap control devices. New applications should only use
@@ -723,6 +493,10 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * specifying the largest among the nmreq_xyz structs. */
 #define NIOCCTRL	_IOWR('i', 151, struct nmreq_register)
 
+/* The ioctl commands to sync TX/RX netmap rings. */
+#define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
+#define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
+
 /*
  * nr_reqtype: NETMAP_REQ_PORT_INFO_GET
  * Get information about a netmap port, including number of rings.
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
new file mode 100644
index 000000000..19121173b
--- /dev/null
+++ b/sys/net/netmap_legacy.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``S IS''AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _NET_NETMAP_LEGACY_H_
+#define _NET_NETMAP_LEGACY_H_
+
+/*
+ * ioctl names and related fields
+ *
+ * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
+ *	whose identity is set in NIOCREGIF through nr_ringid.
+ *	These are non blocking and take no argument.
+ *
+ * NIOCGINFO takes a struct ifreq, the interface name is the input,
+ *	the outputs are number of queues and number of descriptor
+ *	for each queue (useful to set number of threads etc.).
+ *	The info returned is only advisory and may change before
+ *	the interface is bound to a file descriptor.
+ *
+ * NIOCREGIF takes an interface name within a struct nmre,
+ *	and activates netmap mode on the interface (if possible).
+ *
+ * The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
+ * can pass it down to other NIC-related ioctls.
+ *
+ * The actual argument (struct nmreq) has a number of options to request
+ * different functions.
+ * The following are used in NIOCREGIF when nr_cmd == 0:
+ *
+ * nr_name	(in)
+ *	The name of the port (em0, valeXXX:YYY, etc.)
+ *	limited to IFNAMSIZ for backward compatibility.
+ *
+ * nr_version	(in/out)
+ *	Must match NETMAP_API as used in the kernel, error otherwise.
+ *	Always returns the desired value on output.
+ *
+ * nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
+ *	On input, non-zero values may be used to reconfigure the port
+ *	according to the requested values, but this is not guaranteed.
+ *	On output the actual values in use are reported.
+ *
+ * nr_ringid (in)
+ *	Indicates how rings should be bound to the file descriptors.
+ *	If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
+ *	are used to indicate the ring number, and nr_flags specifies
+ *	the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
+ *
+ *	NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
+ *	If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
+ *	the binding as follows:
+ *	0 (default)			binds all physical rings
+ *	NETMAP_HW_RING | ring number	binds a single ring pair
+ *	NETMAP_SW_RING			binds only the host tx/rx rings
+ *
+ *	NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
+ *		packets on tx rings only if POLLOUT is set.
+ *		The default is to push any pending packet.
+ *
+ *	NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
+ *		packets on rx rings also when POLLIN is NOT set.
+ *		The default is to touch the rx ring only with POLLIN.
+ *		Note that this is the opposite of TX because it
+ *		reflects the common usage.
+ *
+ *	NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
+ *	NETMAP_PRIV_MEM is set on return for ports that do not use
+ *		the global memory allocator.
+ *		This information is not significant and applications
+ *		should look at the region id in nr_arg2
+ *
+ * nr_flags	is the recommended mode to indicate which rings should
+ *		be bound to a file descriptor. Values are NR_REG_*
+ *
+ * nr_arg1 (in)	The number of extra rings to be reserved.
+ *		Especially when allocating a VALE port the system only
+ *		allocates the amount of memory needed for the port.
+ *		If more shared memory rings are desired (e.g. for pipes),
+ *		the first invocation for the same basename/allocator
+ *		should specify a suitable number. Memory cannot be
+ *		extended after the first allocation without closing
+ *		all ports on the same region.
+ *
+ * nr_arg2 (in/out) The identity of the memory region used.
+ *		On input, 0 means the system decides autonomously,
+ *		other values may try to select a specific region.
+ *		On return the actual value is reported.
+ *		Region '1' is the global allocator, normally shared
+ *		by all interfaces. Other values are private regions.
+ *		If two ports the same region zero-copy is possible.
+ *
+ * nr_arg3 (in/out)	number of extra buffers to be allocated.
+ *
+ *
+ *
+ * nr_cmd (in)	if non-zero indicates a special command:
+ *	NETMAP_BDG_ATTACH	 and nr_name = vale*:ifname
+ *		attaches the NIC to the switch; nr_ringid specifies
+ *		which rings to use. Used by vale-ctl -a ...
+ *	    nr_arg1 = NETMAP_BDG_HOST also attaches the host port
+ *		as in vale-ctl -h ...
+ *
+ *	NETMAP_BDG_DETACH	and nr_name = vale*:ifname
+ *		disconnects a previously attached NIC.
+ *		Used by vale-ctl -d ...
+ *
+ *	NETMAP_BDG_LIST
+ *		list the configuration of VALE switches.
+ *
+ *	NETMAP_BDG_VNET_HDR
+ *		Set the virtio-net header length used by the client
+ *		of a VALE switch port.
+ *
+ *	NETMAP_BDG_NEWIF
+ *		create a persistent VALE port with name nr_name.
+ *		Used by vale-ctl -n ...
+ *
+ *	NETMAP_BDG_DELIF
+ *		delete a persistent VALE port. Used by vale-ctl -d ...
+ *
+ * nr_arg1, nr_arg2, nr_arg3  (in/out)		command specific
+ *
+ *
+ *
+ */
+
+
+/*
+ * struct nmreq overlays a struct ifreq (just the name)
+ */
+struct nmreq {
+	char		nr_name[IFNAMSIZ];
+	uint32_t	nr_version;	/* API version */
+	uint32_t	nr_offset;	/* nifp offset in the shared region */
+	uint32_t	nr_memsize;	/* size of the shared region */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+
+	uint16_t	nr_ringid;	/* ring(s) we care about */
+#define NETMAP_HW_RING		0x4000	/* single NIC ring pair */
+#define NETMAP_SW_RING		0x2000	/* only host ring pair */
+
+#define NETMAP_RING_MASK	0x0fff	/* the ring number */
+
+#define NETMAP_NO_TX_POLL	0x1000	/* no automatic txsync on poll */
+
+#define NETMAP_DO_RX_POLL	0x8000	/* DO automatic rxsync on poll */
+
+	uint16_t	nr_cmd;
+#define NETMAP_BDG_ATTACH	1	/* attach the NIC */
+#define NETMAP_BDG_DETACH	2	/* detach the NIC */
+#define NETMAP_BDG_REGOPS	3	/* register bridge callbacks */
+#define NETMAP_BDG_LIST		4	/* get bridge's info */
+#define NETMAP_BDG_VNET_HDR     5       /* set the port virtio-net-hdr length */
+#define NETMAP_BDG_NEWIF	6	/* create a virtual port */
+#define NETMAP_BDG_DELIF	7	/* destroy a virtual port */
+#define NETMAP_PT_HOST_CREATE	8	/* create ptnetmap kthreads */
+#define NETMAP_PT_HOST_DELETE	9	/* delete ptnetmap kthreads */
+#define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
+#define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
+#define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
+#define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
+	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
+
+	uint16_t	nr_arg2;
+	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
+	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
+#define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */
+	/* various modes, extends nr_ringid */
+	uint32_t	spare2[1];
+};
+
+#ifdef _WIN32
+/*
+ * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
+ * in ws2def.h but not sure if they are in the form we need.
+ * We therefore redefine them in a convenient way to use for DeviceIoControl
+ * signatures.
+ */
+#undef _IO	// ws2def.h
+#define _WIN_NM_IOCTL_TYPE 40000
+#define _IO(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
+		METHOD_BUFFERED, FILE_ANY_ACCESS  )
+#define _IO_direct(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
+		METHOD_OUT_DIRECT, FILE_ANY_ACCESS  )
+
+#define _IOWR(_c, _n, _s)	_IO(_c, _n)
+
+/* We havesome internal sysctl in addition to the externally visible ones */
+#define NETMAP_MMAP _IO_direct('i', 160)	// note METHOD_OUT_DIRECT
+#define NETMAP_POLL _IO('i', 162)
+
+/* and also two setsockopt for sysctl emulation */
+#define NETMAP_SETSOCKOPT _IO('i', 140)
+#define NETMAP_GETSOCKOPT _IO('i', 141)
+
+
+/* These linknames are for the Netmap Core Driver */
+#define NETMAP_NT_DEVICE_NAME			L"\\Device\\NETMAP"
+#define NETMAP_DOS_DEVICE_NAME			L"\\DosDevices\\netmap"
+
+/* Definition of a structure used to pass a virtual address within an IOCTL */
+typedef struct _MEMORY_ENTRY {
+	PVOID       pUsermodeVirtualAddress;
+} MEMORY_ENTRY, *PMEMORY_ENTRY;
+
+typedef struct _POLL_REQUEST_DATA {
+	int events;
+	int timeout;
+	int revents;
+} POLL_REQUEST_DATA;
+#endif /* _WIN32 */
+
+/*
+ * Opaque structure that is passed to an external kernel
+ * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
+ * bridge port (at this point ephemeral VALE interface).
+ */
+#define NM_IFRDATA_LEN 256
+struct nm_ifreq {
+	char nifr_name[IFNAMSIZ];
+	char data[NM_IFRDATA_LEN];
+};
+
+/*
+ * FreeBSD uses the size value embedded in the _IOWR to determine
+ * how much to copy in/out. So we need it to match the actual
+ * data structure we pass. We put some spares in the structure
+ * to ease compatibility with other versions
+ */
+#define NIOCGINFO	_IOWR('i', 145, struct nmreq) /* return IF info */
+#define NIOCREGIF	_IOWR('i', 146, struct nmreq) /* interface register */
+#define NIOCCONFIG	_IOWR('i',150, struct nm_ifreq) /* for ext. modules */
+
+#endif /* _NET_NETMAP_LEGACY_H_ */

From 1ef56328964cb01fbd0ae595c029ce5b0e1c5d82 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Jan 2018 17:17:45 +0100
Subject: [PATCH 0352/2207] newnmreq: introduce nmreq_from_legacy()

---
 sys/dev/netmap/netmap.c | 77 ++++++++++++++++++++++++++++++++++++++---
 sys/net/netmap.h        |  4 +--
 sys/net/netmap_legacy.h |  2 +-
 3 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3ed315b5c..18f73496f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2192,16 +2192,75 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
+/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
+ * (new API). The new struct is dynamically allocated. */
+static struct nmreq_header *
+nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
+{
+	/* Sanitize nmr->nr_name by adding the string terminator. */
+	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
+		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
+	}
+
+	switch (ioctl_cmd) {
+	case NIOCREGIF: {
+		switch (nmr->nr_cmd) {
+		case 0: {
+			/* Regular NIOCREGIF operation. */
+			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
+			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
+				req->nr_flags |= NR_NO_TX_POLL;
+			}
+			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
+				req->nr_flags |= NR_DO_RX_POLL;
+			}
+			req->nr_pipes = nmr->nr_arg1;
+			req->nr_extra_bufs = nmr->nr_arg3;
+			return (struct nmreq_header *)req;
+			break;
+		}
+		}
+		break;
+	}
+	}
+
+	return NULL;
+oom:
+	D("Failed to allocate memory for nmreq_xyz struct");
+	return NULL;
+}
+
+/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
+ * It also frees the nmreq_xyz struct, as it was allocated by
+ * nmreq_from_legacy(). */
+static void
+nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
+{
+	nm_os_free(hdr);
+}
 
 /*
  * ioctl(2) support for the "netmap" device.
  *
  * Following a list of accepted commands:
- * - NIOCGINFO
+ * - NIOCCTRL		device control API
+ * - NIOCTXSYNC		sync TX rings
+ * - NIOCRXSYNC		sync RX rings
  * - SIOCGIFADDR	just for convenience
- * - NIOCREGIF
- * - NIOCTXSYNC
- * - NIOCRXSYNC
+ * - NIOCGINFO		deprecated (legacy API)
+ * - NIOCREGIF		deprecated (legacy API)
  *
  * Return 0 on success, errno otherwise.
  */
@@ -2236,6 +2295,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	}
 
 	switch (cmd) {
+	case NIOCCTRL: {
+		struct nmreq_header *hdr = (struct nmreq_header *)data;
+
+		switch (hdr->nr_reqtype) {
+		default: {
+			break;
+		}
+		}
+		break;
+	}
 	case NIOCGINFO:		/* return capabilities etc */
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			error = netmap_bdg_ctl(nmr, NULL);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 9ceb6ee66..16905a574 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -39,7 +39,7 @@
 #ifndef _NET_NETMAP_H_
 #define _NET_NETMAP_H_
 
-#define	NETMAP_API	11		/* current API version */
+#define	NETMAP_API	12		/* current API version */
 
 #define	NETMAP_MIN_API	11		/* min and max versions accepted */
 #define	NETMAP_MAX_API	15
@@ -472,8 +472,8 @@ struct nmreq_register {
 #define NR_DO_RX_POLL		0x10000
 #define NR_NO_TX_POLL		0x20000
 
+	uint32_t	nr_pipes;	/* number of pipes to create */
 	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
-	uint8_t         nr_spare[64];
 };
 
 /* Valid values for nmreq_register.nr_mode (see above). */
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 19121173b..c5f94980b 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -187,7 +187,7 @@ struct nmreq {
 #define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
 
-	uint16_t	nr_arg2;
+	uint16_t	nr_arg2;	/* id of the memory allocator */
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
 	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
 #define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */

From 505e78563bb06b98998187e727405c7285666308 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Jan 2018 17:32:55 +0100
Subject: [PATCH 0353/2207] netmap.h: introduce struct nmreq_option

---
 sys/net/netmap.h | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 16905a574..3a397d393 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -388,10 +388,19 @@ struct netmap_if {
  * nmreq_xyz structs with the NIOCCTRL ioctl() command.
  */
 
+/* Header common to all request options. */
+struct nmreq_option {
+	/* Pointer ot the next option. */
+	struct nmreq_option	*nro_next;
+	/* Option type. */
+	uint16_t		nro_reqtype;
+};
+
 /* Header common to all requests. */
 struct nmreq_header {
-	uint16_t	nr_version;	/* API version */
-	uint16_t	nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+	uint16_t		nr_version;	/* API version */
+	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+	struct nmreq_option	*options;	/* command-specific options */
 };
 
 enum {
@@ -429,6 +438,12 @@ enum {
 	NETMAP_REQ_VALE_OPS_REGISTER,
 };
 
+enum {
+	/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
+	 * from user-space allocated memory pools (e.g. hugepages). */
+	NETMAP_REQ_OPT_EXTMEM = 1,
+};
+
 #define NETMAP_REQ_IFNAMSIZ	64
 
 /*

From 2f8a5378caba828d884c615cdf501a2ad903d93b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Jan 2018 18:53:27 +0100
Subject: [PATCH 0354/2207] nmreq_from_legacy: support several vale commands

---
 sys/dev/netmap/netmap.c | 59 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 18f73496f..d28c32e96 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2197,6 +2197,8 @@ ring_timestamp_set(struct netmap_ring *ring)
 static struct nmreq_header *
 nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 {
+	struct nmreq_header *hdr = NULL;
+
 	/* Sanitize nmr->nr_name by adding the string terminator. */
 	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
@@ -2209,6 +2211,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
@@ -2228,7 +2231,57 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			}
 			req->nr_pipes = nmr->nr_arg1;
 			req->nr_extra_bufs = nmr->nr_arg3;
-			return (struct nmreq_header *)req;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_ATTACH: {
+			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DETACH: {
+			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_VNET_HDR:
+		case NETMAP_VNET_HDR_GET: {
+			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
+				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_hdr_len = nmr->nr_arg1;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_NEWIF : {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DELIF: {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		}
@@ -2236,7 +2289,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	}
 	}
 
-	return NULL;
+	hdr->nr_version = NETMAP_API; /* new API */
+
+	return hdr;
 oom:
 	D("Failed to allocate memory for nmreq_xyz struct");
 	return NULL;

From 5c7b5276522d40cdd69c02b74de2ce4a30588284 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 17:15:52 +0100
Subject: [PATCH 0355/2207] nmreq_from_legacy: support missing commands

ptnetmap configuration commands are not supported for now, as
they will be supported through a nmreq_register option.
---
 sys/dev/netmap/netmap.c | 53 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d28c32e96..ec265b854 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2284,6 +2284,59 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
+		case NETMAP_BDG_POLLING_ON:
+		case NETMAP_BDG_POLLING_OFF: {
+			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
+				NETMAP_REQ_VALE_POLLING_ENABLE :
+				NETMAP_REQ_VALE_POLLING_DISABLE;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_POOLS_INFO_GET: {
+			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			/* Most of the fields are for output (see
+			 * nmreq_to_legacy). */
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_PT_HOST_CREATE:
+		case NETMAP_PT_HOST_DELETE: {
+			D("Netmap passthrough not supported yet");
+			return NULL;
+			break;
+		}
+		}
+		break;
+	}
+	case NIOCGINFO: {
+		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
+			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_bridge_idx = nmr->nr_arg1;
+			req->nr_port_idx = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+		} else {
+			/* Regular NIOCGINFO. */
+			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
 		}
 		break;
 	}

From a8dba4acfafc15c8e9fb9e0404260c85668bc9ad Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 17:58:18 +0100
Subject: [PATCH 0356/2207] implement nmreq_to_legacy() to convert nmreq_xyx to
 legacy nmreq

---
 sys/dev/netmap/netmap.c | 117 +++++++++++++++++++++++++++++++++++++++-
 sys/net/netmap_legacy.h |  19 +++++++
 sys/net/netmap_virt.h   |  19 -------
 3 files changed, 134 insertions(+), 21 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ec265b854..1163d9632 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2296,6 +2296,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			break;
 		}
 		case NETMAP_POOLS_INFO_GET: {
+			/* We could deny this request similar to ptnetmap requests. */
 			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
@@ -2325,7 +2326,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			hdr = (struct nmreq_header *)req;
 		} else {
 			/* Regular NIOCGINFO. */
-			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
@@ -2353,10 +2354,122 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
  * It also frees the nmreq_xyz struct, as it was allocated by
  * nmreq_from_legacy(). */
-static void
+static int
 nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
+	int ret = 0;
+	/* Don't bzero 'nmr', we may need the pointers stored into
+	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
+
+	switch (hdr->nr_reqtype) {
+	case NETMAP_REQ_REGISTER: {
+		struct nmreq_register *req = (struct nmreq_register *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_ringid = req->nr_ringid;
+		if (req->nr_flags & NR_NO_TX_POLL) {
+			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
+		}
+		if (req->nr_flags & NR_DO_RX_POLL) {
+			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
+		}
+		nmr->nr_flags = req->nr_mode | req->nr_flags;
+		nmr->nr_arg1 = req->nr_pipes;
+		nmr->nr_arg3 = req->nr_extra_bufs;
+		break;
+	}
+	case NETMAP_REQ_PORT_INFO_GET: {
+		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_ATTACH: {
+		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_arg1 = req->nr_flags;
+		break;
+	}
+	case NETMAP_REQ_VALE_DETACH: {
+		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		break;
+	}
+	case NETMAP_REQ_VALE_LIST: {
+		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_arg1 = req->nr_bridge_idx;
+		nmr->nr_arg2 = req->nr_port_idx;
+		break;
+	}
+	case NETMAP_REQ_PORT_HDR_SET:
+	case NETMAP_REQ_PORT_HDR_GET: {
+		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_arg1 = req->nr_hdr_len;
+		break;
+	}
+	case NETMAP_REQ_VALE_NEWIF: {
+		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_DELIF: {
+		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		break;
+	}
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+	case NETMAP_REQ_VALE_POLLING_DISABLE: {
+		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		break;
+	}
+	case NETMAP_REQ_POOLS_INFO_GET: {
+		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
+		struct netmap_pools_info pi;
+		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		pi.memsize = req->nr_memsize;
+		pi.memid = req->nr_mem_id;
+		pi.if_pool_offset = req->nr_if_pool_offset;
+		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
+		pi.if_pool_objsize = req->nr_if_pool_objsize;
+		pi.ring_pool_offset = req->nr_ring_pool_offset;
+		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
+		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
+		pi.buf_pool_offset = req->nr_buf_pool_offset;
+		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
+		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
+		ret = copyout(&pi, upi, sizeof(pi));
+		if (ret) {
+			D("copyout() failed");
+		}
+		break;
+	}
+	}
+
 	nm_os_free(hdr);
+	return ret;
 }
 
 /*
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index c5f94980b..9b961a05a 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -195,6 +195,25 @@ struct nmreq {
 	uint32_t	spare2[1];
 };
 
+/*
+ * Structure filled-in by the kernel when asked for allocator info
+ * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
+ * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
+ */
+struct netmap_pools_info {
+	uint64_t memsize;	/* same as nmr->nr_memsize */
+	uint32_t memid;		/* same as nmr->nr_arg2 */
+	uint32_t if_pool_offset;
+	uint32_t if_pool_objtotal;
+	uint32_t if_pool_objsize;
+	uint32_t ring_pool_offset;
+	uint32_t ring_pool_objtotal;
+	uint32_t ring_pool_objsize;
+	uint32_t buf_pool_offset;
+	uint32_t buf_pool_objtotal;
+	uint32_t buf_pool_objsize;
+};
+
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 7b1f769d8..5fb529ee4 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -130,25 +130,6 @@ struct nmreq_passthrough_disable {
 	struct nmreq_header	nr_hdr;
 };
 
-/*
- * Structure filled-in by the kernel when asked for allocator info
- * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
- * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
- */
-struct netmap_pools_info {
-	uint64_t memsize;	/* same as nmr->nr_memsize */
-	uint32_t memid;		/* same as nmr->nr_arg2 */
-	uint32_t if_pool_offset;
-	uint32_t if_pool_objtotal;
-	uint32_t if_pool_objsize;
-	uint32_t ring_pool_offset;
-	uint32_t ring_pool_objtotal;
-	uint32_t ring_pool_objsize;
-	uint32_t buf_pool_offset;
-	uint32_t buf_pool_objtotal;
-	uint32_t buf_pool_objsize;
-};
-
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
  * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.

From 8f27b6995a5e0ccbed9e1e3c402b3768c3accf43 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 18:23:13 +0100
Subject: [PATCH 0357/2207] nmreq_from_legacy: support original netmap API
 (NR_REG_DEFAULT)

---
 sys/dev/netmap/netmap.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1163d9632..39d04ff5e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2221,6 +2221,20 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_rx_rings = nmr->nr_rx_rings;
 			req->nr_mem_id = nmr->nr_arg2;
 			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
+				/* Convert the older nmr->nr_ringid (original
+				 * netmap control API) to nmr->nr_flags. */
+				u_int regmode = NR_REG_DEFAULT;
+				if (req->nr_ringid & NETMAP_SW_RING) {
+					regmode = NR_REG_SW;
+				} else if (req->nr_ringid & NETMAP_HW_RING) {
+					regmode = NR_REG_ONE_NIC;
+				} else {
+					regmode = NR_REG_ALL_NIC;
+				}
+				nmr->nr_flags = regmode |
+					(nmr->nr_flags & (~NR_REG_MASK));
+			}
 			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
 			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
 			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {

From 2feeee442f8327202ffb07fba1867f9063703d5e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 19:49:35 +0100
Subject: [PATCH 0358/2207] large refactor to use new request structs
 internally

---
 LINUX/netmap_linux.c            |   7 +-
 sys/dev/netmap/netmap.c         | 590 +++++++++++++++++++-------------
 sys/dev/netmap/netmap_kern.h    |  46 ++-
 sys/dev/netmap/netmap_mem2.c    |  51 ++-
 sys/dev/netmap/netmap_mem2.h    |   8 +-
 sys/dev/netmap/netmap_monitor.c |  35 +-
 sys/dev/netmap/netmap_pipe.c    |  42 +--
 sys/dev/netmap/netmap_pt.c      | 135 +++-----
 sys/dev/netmap/netmap_vale.c    | 449 +++++++++++-------------
 sys/net/netmap.h                |  24 +-
 10 files changed, 719 insertions(+), 668 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index db376b065..ea302e363 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -988,8 +988,9 @@ static int
 linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
 {
 	int error = 0;
-	unsigned long off;
-	u_int memsize, memflags;
+	uint64_t off;
+	unsigned int memflags;
+	uint64_t memsize;
 	struct netmap_priv_d *priv = f->private_data;
 	struct netmap_adapter *na = priv->np_na;
 	/*
@@ -2292,7 +2293,7 @@ EXPORT_SYMBOL(netmap_reset);		/* ring init routines */
 EXPORT_SYMBOL(netmap_rx_irq);	        /* default irq handler */
 EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 #ifdef WITH_VALE
-EXPORT_SYMBOL(netmap_bdg_ctl);		/* bridge configuration routine */
+EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
 EXPORT_SYMBOL(netmap_bdg_learning);	/* the default lookup function */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
 #endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 39d04ff5e..c4f44fe61 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1441,7 +1441,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  * MUST BE CALLED UNDER NMG_LOCK()
  *
  * Get a refcounted reference to a netmap adapter attached
- * to the interface specified by nmr.
+ * to the interface specified by req.
  * This is always called in the execution of an ioctl().
  *
  * Return ENXIO if the interface specified by the request does
@@ -1451,11 +1451,11 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  * could not be allocated.
  * If successful, hold a reference to the netmap adapter.
  *
- * If the interface specified by nmr is a system one, also keep
+ * If the interface specified by req is a system one, also keep
  * a reference to it and return a valid *ifp.
  */
 int
-netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	      struct ifnet **ifp, struct netmap_mem_d *nmd, int create)
 {
 	int error = 0;
@@ -1470,8 +1470,8 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
 	/* if the request contain a memid, try to find the
 	 * corresponding memory region
 	 */
-	if (nmd == NULL && nmr->nr_arg2) {
-		nmd = netmap_mem_find(nmr->nr_arg2);
+	if (nmd == NULL && req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
 		if (nmd == NULL)
 			return EINVAL;
 		/* keep the rereference */
@@ -1490,22 +1490,23 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
 	 */
 
 	/* try to see if this is a ptnetmap port */
-	error = netmap_get_pt_host_na(nmr, na, nmd, create);
+	error = netmap_get_pt_host_na(req, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a monitor port */
-	error = netmap_get_monitor_na(nmr, na, nmd, create);
+	error = netmap_get_monitor_na(req, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a pipe port */
-	error = netmap_get_pipe_na(nmr, na, nmd, create);
+	error = netmap_get_pipe_na(req, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a bridge port */
-	error = netmap_get_bdg_na(nmr, na, nmd, create);
+	error = netmap_get_bdg_na((struct nmreq_header *)req,
+					na, nmd, create);
 	if (error)
 		goto out;
 
@@ -1518,7 +1519,7 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
 	 * This may still be a tap, a veth/epair, or even a
 	 * persistent VALE port.
 	 */
-	*ifp = ifunit_ref(nmr->nr_name);
+	*ifp = ifunit_ref(req->nr_hdr.nr_name);
 	if (*ifp == NULL) {
 		error = ENXIO;
 		goto out;
@@ -1763,39 +1764,27 @@ netmap_ring_reinit(struct netmap_kring *kring)
  *
  */
 int
-netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags)
+netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
+			uint16_t nr_ringid, uint64_t nr_flags)
 {
 	struct netmap_adapter *na = priv->np_na;
-	u_int j, i = ringid & NETMAP_RING_MASK;
-	u_int reg = flags & NR_REG_MASK;
 	int excluded_direction[] = { NR_TX_RINGS_ONLY, NR_RX_RINGS_ONLY };
 	enum txrx t;
+	u_int j;
 
-	if (reg == NR_REG_DEFAULT) {
-		/* convert from old ringid to flags */
-		if (ringid & NETMAP_SW_RING) {
-			reg = NR_REG_SW;
-		} else if (ringid & NETMAP_HW_RING) {
-			reg = NR_REG_ONE_NIC;
-		} else {
-			reg = NR_REG_ALL_NIC;
-		}
-		D("deprecated API, old ringid 0x%x -> ringid %x reg %d", ringid, i, reg);
-	}
-
-	if ((flags & NR_PTNETMAP_HOST) && ((reg != NR_REG_ALL_NIC &&
-                    reg != NR_REG_PIPE_MASTER && reg != NR_REG_PIPE_SLAVE) ||
-			flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
+	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC &&
+                    nr_mode != NR_REG_PIPE_MASTER && nr_mode != NR_REG_PIPE_SLAVE) ||
+			nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
 		D("Error: only NR_REG_ALL_NIC supported with netmap passthrough");
 		return EINVAL;
 	}
 
 	for_rx_tx(t) {
-		if (flags & excluded_direction[t]) {
+		if (nr_flags & excluded_direction[t]) {
 			priv->np_qfirst[t] = priv->np_qlast[t] = 0;
 			continue;
 		}
-		switch (reg) {
+		switch (nr_mode) {
 		case NR_REG_ALL_NIC:
 		case NR_REG_PIPE_MASTER:
 		case NR_REG_PIPE_SLAVE:
@@ -1810,20 +1799,21 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
 				D("host rings not supported");
 				return EINVAL;
 			}
-			priv->np_qfirst[t] = (reg == NR_REG_SW ?
+			priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
 				nma_get_nrings(na, t) : 0);
 			priv->np_qlast[t] = nma_get_nrings(na, t) + 1;
-			ND("%s: %s %d %d", reg == NR_REG_SW ? "SW" : "NIC+SW",
+			ND("%s: %s %d %d", nr_mode == NR_REG_SW ? "SW" : "NIC+SW",
 				nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		case NR_REG_ONE_NIC:
-			if (i >= na->num_tx_rings && i >= na->num_rx_rings) {
-				D("invalid ring id %d", i);
+			if (nr_ringid >= na->num_tx_rings &&
+					nr_ringid >= na->num_rx_rings) {
+				D("invalid ring id %d", nr_ringid);
 				return EINVAL;
 			}
 			/* if not enough rings, use the first one */
-			j = i;
+			j = nr_ringid;
 			if (j >= nma_get_nrings(na, t))
 				j = 0;
 			priv->np_qfirst[t] = j;
@@ -1832,11 +1822,11 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		default:
-			D("invalid regif type %d", reg);
+			D("invalid regif type %d", nr_mode);
 			return EINVAL;
 		}
 	}
-	priv->np_flags = (flags & ~NR_REG_MASK) | reg;
+	priv->np_flags = nr_flags | nr_mode; // TODO
 
 	/* Allow transparent forwarding mode in the host --> nic
 	 * direction only if all the TX hw rings have been opened. */
@@ -1852,7 +1842,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
 			priv->np_qlast[NR_TX],
 			priv->np_qfirst[NR_RX],
 			priv->np_qlast[NR_RX],
-			i);
+			nr_ringid);
 	}
 	return 0;
 }
@@ -1863,18 +1853,19 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
  * for all rings is the same as a single ring.
  */
 static int
-netmap_set_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags)
+netmap_set_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
+		uint16_t nr_ringid, uint64_t nr_flags)
 {
 	struct netmap_adapter *na = priv->np_na;
 	int error;
 	enum txrx t;
 
-	error = netmap_interp_ringid(priv, ringid, flags);
+	error = netmap_interp_ringid(priv, nr_mode, nr_ringid, nr_flags);
 	if (error) {
 		return error;
 	}
 
-	priv->np_txpoll = (ringid & NETMAP_NO_TX_POLL) ? 0 : 1;
+	priv->np_txpoll = (nr_flags & NR_NO_TX_POLL) ? 0 : 1;
 
 	/* optimization: count the users registered for more than
 	 * one ring, which are the ones sleeping on the global queue.
@@ -1977,7 +1968,6 @@ netmap_krings_put(struct netmap_priv_d *priv)
 			priv->np_qfirst[NR_RX],
 			priv->np_qlast[MR_RX]);
 
-
 	for_rx_tx(t) {
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
 			kring = &NMR(na, t)[i];
@@ -2062,7 +2052,7 @@ netmap_krings_put(struct netmap_priv_d *priv)
  */
 int
 netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
-	uint16_t ringid, uint32_t flags)
+	uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags)
 {
 	struct netmap_if *nifp = NULL;
 	int error;
@@ -2071,7 +2061,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	/* ring configuration may have changed, fetch from the card */
 	netmap_update_config(na);
 	priv->np_na = na;     /* store the reference */
-	error = netmap_set_ringid(priv, ringid, flags);
+	error = netmap_set_ringid(priv, nr_mode, nr_ringid, nr_flags);
 	if (error)
 		goto err;
 	error = netmap_mem_finalize(na->nm_mem, na);
@@ -2212,7 +2202,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -2252,7 +2241,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_mem_id = nmr->nr_arg2;
 			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
 			hdr = (struct nmreq_header *)req;
@@ -2262,7 +2250,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
@@ -2272,7 +2259,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_hdr_len = nmr->nr_arg1;
 			hdr = (struct nmreq_header *)req;
 			break;
@@ -2281,7 +2267,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
 			req->nr_tx_rings = nmr->nr_tx_rings;
@@ -2294,7 +2279,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
@@ -2305,7 +2289,19 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			switch (nmr->nr_flags & NR_REG_MASK) {
+			default:
+				req->nr_mode = 0; /* invalid */
+				break;
+			case NR_REG_ONE_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
+				break;
+			case NR_REG_ALL_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+				break;
+			}
+			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
+			req->nr_num_polling_cpus = nmr->nr_arg1;
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
@@ -2314,7 +2310,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			/* Most of the fields are for output (see
 			 * nmreq_to_legacy). */
 			hdr = (struct nmreq_header *)req;
@@ -2334,7 +2329,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
 			hdr = (struct nmreq_header *)req;
@@ -2343,7 +2337,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -2357,7 +2350,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	}
 	}
 
+	KASSERT(hdr != NULL, "Invalid NULL netmap request");
 	hdr->nr_version = NETMAP_API; /* new API */
+	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
 
 	return hdr;
 oom:
@@ -2375,10 +2370,11 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	/* Don't bzero 'nmr', we may need the pointers stored into
 	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
 
+	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req = (struct nmreq_register *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -2400,7 +2396,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
 		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -2412,19 +2407,17 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_VALE_ATTACH: {
 		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg2 = req->nr_mem_id;
 		nmr->nr_arg1 = req->nr_flags;
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
 		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_LIST: {
 		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
@@ -2432,13 +2425,11 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_PORT_HDR_SET:
 	case NETMAP_REQ_PORT_HDR_GET: {
 		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_hdr_len;
 		break;
 	}
 	case NETMAP_REQ_VALE_NEWIF: {
 		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_tx_slots = req->nr_tx_slots;
 		nmr->nr_rx_slots = req->nr_rx_slots;
 		nmr->nr_tx_rings = req->nr_tx_rings;
@@ -2448,13 +2439,25 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_VALE_DELIF: {
 		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
 		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		switch (req->nr_mode) {
+		default:
+			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
+			break;
+		case NETMAP_POLLING_MODE_MULTI_CPU:
+			nmr->nr_flags = NR_REG_ONE_NIC;
+			break;
+		case NETMAP_POLLING_MODE_SINGLE_CPU:
+			nmr->nr_flags = NR_REG_ALL_NIC;
+			break;
+		}
+		nmr->nr_ringid = req->nr_first_cpu_id;
+		nmr->nr_arg1 = req->nr_num_polling_cpus;
 		break;
 	}
 	case NETMAP_REQ_POOLS_INFO_GET: {
@@ -2462,7 +2465,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
 		struct netmap_pools_info pi;
 		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		pi.memsize = req->nr_memsize;
 		pi.memid = req->nr_mem_id;
 		pi.if_pool_offset = req->nr_if_pool_offset;
@@ -2482,10 +2484,19 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	}
 
-	nm_os_free(hdr);
 	return ret;
 }
 
+static void
+nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
+				 struct nmreq_register *regreq)
+{
+	bzero(regreq, sizeof(*regreq));
+	memcpy(®req->nr_hdr, hdr, sizeof(regreq->nr_hdr));
+	regreq->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	regreq->nr_hdr.nr_options = NULL;
+}
+
 /*
  * ioctl(2) support for the "netmap" device.
  *
@@ -2503,7 +2514,6 @@ int
 netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *td)
 {
 	struct mbq q;	/* packets from RX hw queues to host stack */
-	struct nmreq *nmr = (struct nmreq *) data;
 	struct netmap_adapter *na = NULL;
 	struct netmap_mem_d *nmd = NULL;
 	struct ifnet *ifp = NULL;
@@ -2514,210 +2524,319 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	int sync_flags;
 	enum txrx t;
 
-	if (cmd == NIOCGINFO || cmd == NIOCREGIF) {
-		/* truncate name */
-		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
-		if (nmr->nr_version != NETMAP_API) {
-			D("API mismatch for %s got %d need %d",
-				nmr->nr_name,
-				nmr->nr_version, NETMAP_API);
-			nmr->nr_version = NETMAP_API;
-		}
-		if (nmr->nr_version < NETMAP_MIN_API ||
-		    nmr->nr_version > NETMAP_MAX_API) {
-			return EINVAL;
-		}
-	}
-
 	switch (cmd) {
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
-
-		switch (hdr->nr_reqtype) {
-		default: {
-			break;
-		}
+		if (hdr->nr_version != NETMAP_API) {
+			D("API mismatch for reqtype %d: got %d need %d",
+				hdr->nr_version,
+				hdr->nr_version, NETMAP_API);
+			hdr->nr_version = NETMAP_API;
 		}
-		break;
-	}
-	case NIOCGINFO:		/* return capabilities etc */
-		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
-			error = netmap_bdg_ctl(nmr, NULL);
-			break;
+		if (hdr->nr_version < NETMAP_MIN_API ||
+		    hdr->nr_version > NETMAP_MAX_API) {
+			return EINVAL;
 		}
 
-		NMG_LOCK();
-		do {
-			/* memsize is always valid */
-			u_int memflags;
+		/* Sanitize hdr->nr_name. */
+		hdr->nr_name[sizeof(hdr->nr_name) - 1] = '\0';
 
-			if (nmr->nr_name[0] != '\0') {
+		switch (hdr->nr_reqtype) {
+		case NETMAP_REQ_REGISTER: {
+			struct nmreq_register *req =
+				(struct nmreq_register *)hdr;
+			/* Protect access to priv from concurrent requests. */
+			NMG_LOCK();
+			do {
+				u_int memflags;
 
-				/* get a refcount */
-				error = netmap_get_na(nmr, &na, &ifp, NULL, 1 /* create */);
-				if (error) {
-					na = NULL;
-					ifp = NULL;
+				if (priv->np_nifp != NULL) {	/* thread already registered */
+					error = EBUSY;
 					break;
 				}
-				nmd = na->nm_mem; /* get memory allocator */
-			} else {
-				nmd = netmap_mem_find(nmr->nr_arg2 ? nmr->nr_arg2 : 1);
-				if (nmd == NULL) {
-					error = EINVAL;
+
+				if (req->nr_mem_id) {
+					/* find the allocator and get a reference */
+					nmd = netmap_mem_find(req->nr_mem_id);
+					if (nmd == NULL) {
+						error = EINVAL;
+						break;
+					}
+				}
+				/* find the interface and a reference */
+				error = netmap_get_na(req, &na, &ifp, nmd,
+						      1 /* create */); /* keep reference */
+				if (error)
+					break;
+				if (NETMAP_OWNED_BY_KERN(na)) {
+					error = EBUSY;
+					break;
+				}
+
+				if (na->virt_hdr_len && !(req->nr_flags & NR_ACCEPT_VNET_HDR)) {
+					error = EIO;
+					break;
+				}
+
+				error = netmap_do_regif(priv, na, req->nr_mode,
+							req->nr_ringid, req->nr_flags);
+				if (error) {    /* reg. failed, release priv and ref */
+					break;
+				}
+				nifp = priv->np_nifp;
+				priv->np_td = td; /* for debugging purposes */
+
+				/* return the offset of the netmap_if object */
+				req->nr_rx_rings = na->num_rx_rings;
+				req->nr_tx_rings = na->num_tx_rings;
+				req->nr_rx_slots = na->num_rx_desc;
+				req->nr_tx_slots = na->num_tx_desc;
+				error = netmap_mem_get_info(na->nm_mem, &req->nr_memsize, &memflags,
+					&req->nr_mem_id);
+				if (error) {
+					netmap_do_unregif(priv);
 					break;
 				}
+				if (memflags & NETMAP_MEM_PRIVATE) {
+					*(uint32_t *)(uintptr_t)&nifp->ni_flags |= NI_PRIV_MEM;
+				}
+				for_rx_tx(t) {
+					priv->np_si[t] = nm_si_user(priv, t) ?
+						&na->si[t] : &NMR(na, t)[priv->np_qfirst[t]].si;
+				}
+
+				if (req->nr_extra_bufs) {
+					if (netmap_verbose)
+						D("requested %d extra buffers",
+							req->nr_extra_bufs);
+					req->nr_extra_bufs = netmap_extra_alloc(na,
+						&nifp->ni_bufs_head, req->nr_extra_bufs);
+					if (netmap_verbose)
+						D("got %d extra buffers", req->nr_extra_bufs);
+				}
+				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
+
+				/* store ifp reference so that priv destructor may release it */
+				priv->np_ifp = ifp;
+			} while (0);
+			if (error) {
+				netmap_unget_na(na, ifp);
 			}
+			/* release the reference from netmap_mem_find() or
+			 * netmap_mem_ext_create()
+			 */
+			if (nmd)
+				netmap_mem_put(nmd);
+			NMG_UNLOCK();
+			break;
+		}
 
-			error = netmap_mem_get_info(nmd, &nmr->nr_memsize, &memflags,
-				&nmr->nr_arg2);
-			if (error)
-				break;
-			if (na == NULL) /* only memory info */
-				break;
-			nmr->nr_offset = 0;
-			nmr->nr_rx_slots = nmr->nr_tx_slots = 0;
-			netmap_update_config(na);
-			nmr->nr_rx_rings = na->num_rx_rings;
-			nmr->nr_tx_rings = na->num_tx_rings;
-			nmr->nr_rx_slots = na->num_rx_desc;
-			nmr->nr_tx_slots = na->num_tx_desc;
-		} while (0);
-		netmap_unget_na(na, ifp);
-		NMG_UNLOCK();
-		break;
+		case NETMAP_REQ_PORT_INFO_GET: {
+			struct nmreq_port_info_get *req =
+				(struct nmreq_port_info_get *)hdr;
 
-	case NIOCREGIF:
-		/*
-		 * If nmr->nr_cmd is not zero, this NIOCREGIF is not really
-		 * a regif operation, but a different one, specified by the
-		 * value of nmr->nr_cmd.
-		 */
-		i = nmr->nr_cmd;
-		if (i == NETMAP_BDG_ATTACH || i == NETMAP_BDG_DETACH
-				|| i == NETMAP_BDG_VNET_HDR
-				|| i == NETMAP_BDG_NEWIF
-				|| i == NETMAP_BDG_DELIF
-				|| i == NETMAP_BDG_POLLING_ON
-				|| i == NETMAP_BDG_POLLING_OFF) {
-			/* possibly attach/detach NIC and VALE switch */
-			error = netmap_bdg_ctl(nmr, NULL);
+			NMG_LOCK();
+			do {
+				u_int memflags;
+
+				if (hdr->nr_name[0] != '\0') {
+					/* Build a nmreq_register out of the nmreq_port_info_get,
+					 * so that we can call netmap_get_na(). */
+					struct nmreq_register regreq;
+					nmreq_register_from_nmreq_header(hdr, ®req);
+					regreq.nr_tx_slots = req->nr_tx_slots;
+					regreq.nr_rx_slots = req->nr_rx_slots;
+					regreq.nr_tx_rings = req->nr_tx_rings;
+					regreq.nr_rx_rings = req->nr_rx_rings;
+					regreq.nr_mem_id = req->nr_mem_id;
+
+					/* get a refcount */
+					error = netmap_get_na(®req, &na, &ifp, NULL, 1 /* create */);
+					if (error) {
+						na = NULL;
+						ifp = NULL;
+						break;
+					}
+					nmd = na->nm_mem; /* get memory allocator */
+				} else {
+					nmd = netmap_mem_find(req->nr_mem_id ? req->nr_mem_id : 1);
+					if (nmd == NULL) {
+						error = EINVAL;
+						break;
+					}
+				}
+
+				error = netmap_mem_get_info(nmd, &req->nr_memsize, &memflags,
+					&req->nr_mem_id);
+				if (error)
+					break;
+				if (na == NULL) /* only memory info */
+					break;
+				req->nr_offset = 0;
+				req->nr_rx_slots = req->nr_tx_slots = 0;
+				netmap_update_config(na);
+				req->nr_rx_rings = na->num_rx_rings;
+				req->nr_tx_rings = na->num_tx_rings;
+				req->nr_rx_slots = na->num_rx_desc;
+				req->nr_tx_slots = na->num_tx_desc;
+			} while (0);
+			netmap_unget_na(na, ifp);
+			NMG_UNLOCK();
+			break;
+		}
+
+		case NETMAP_REQ_VALE_ATTACH: {
+			struct nmreq_vale_attach *req =
+				(struct nmreq_vale_attach *)hdr;
+			error = nm_bdg_ctl_attach(req);
+			break;
+		}
+
+		case NETMAP_REQ_VALE_DETACH: {
+			struct nmreq_vale_detach *req =
+				(struct nmreq_vale_detach *)hdr;
+			error = nm_bdg_ctl_detach(req);
+			break;
+		}
+
+		case NETMAP_REQ_VALE_LIST: {
+			struct nmreq_vale_list *req =
+				(struct nmreq_vale_list *)hdr;
+			error = netmap_bdg_list(req);
 			break;
-		} else if (i == NETMAP_PT_HOST_CREATE || i == NETMAP_PT_HOST_DELETE) {
-			/* forward the command to the ptnetmap subsystem */
-			error = ptnetmap_ctl(nmr, priv->np_na);
+		}
+
+		case NETMAP_REQ_PORT_HDR_SET: {
+			struct nmreq_port_hdr *req =
+				(struct nmreq_port_hdr *)hdr;
+			/* Build a nmreq_register out of the nmreq_port_hdr,
+			 * so that we can call netmap_get_bdg_na(). */
+			struct nmreq_register regreq;
+			nmreq_register_from_nmreq_header(hdr, ®req);
+			/* For now we only support virtio-net headers, and only for
+			 * VALE ports, but this may change in future. Valid lengths
+			 * for the virtio-net header are 0 (no header), 10 and 12. */
+			if (req->nr_hdr_len != 0 &&
+				req->nr_hdr_len != sizeof(struct nm_vnet_hdr) &&
+					req->nr_hdr_len != 12) {
+				error = EINVAL;
+				break;
+			}
+			NMG_LOCK();
+			error = netmap_get_bdg_na((struct nmreq_header *)®req,
+							&na, NULL, 0);
+			if (na && !error) {
+				struct netmap_vp_adapter *vpna =
+					(struct netmap_vp_adapter *)na;
+				na->virt_hdr_len = req->nr_hdr_len;
+				if (na->virt_hdr_len) {
+					vpna->mfs = NETMAP_BUF_SIZE(na);
+				}
+				D("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
+				netmap_adapter_put(na);
+			} else if (!na) {
+				error = ENXIO;
+			}
+			NMG_UNLOCK();
 			break;
-		} else if (i == NETMAP_VNET_HDR_GET) {
-			/* get vnet-header length for this netmap port */
+		}
+
+		case NETMAP_REQ_PORT_HDR_GET: {
+			/* Get vnet-header length for this netmap port */
+			struct nmreq_port_hdr *req =
+				(struct nmreq_port_hdr *)hdr;
+			/* Build a nmreq_register out of the nmreq_port_hdr,
+			 * so that we can call netmap_get_bdg_na(). */
+			struct nmreq_register regreq;
 			struct ifnet *ifp;
+			nmreq_register_from_nmreq_header(hdr, ®req);
 
 			NMG_LOCK();
-			error = netmap_get_na(nmr, &na, &ifp, NULL, 0);
+			error = netmap_get_na(®req, &na, &ifp, NULL, 0);
 			if (na && !error) {
-				nmr->nr_arg1 = na->virt_hdr_len;
+				req->nr_hdr_len = na->virt_hdr_len;
 			}
 			netmap_unget_na(na, ifp);
 			NMG_UNLOCK();
 			break;
-		} else if (i == NETMAP_POOLS_INFO_GET) {
-			/* get information from the memory allocator */
+		}
+
+		case NETMAP_REQ_VALE_NEWIF: {
+			struct nmreq_vale_newif *req =
+				(struct nmreq_vale_newif *)hdr;
+			/* Build a nmreq_register out of the nmreq_vale_newif,
+			 * so that we can call netmap_get_bdg_na(). */
+			struct nmreq_register regreq;
+			nmreq_register_from_nmreq_header(hdr, ®req);
+			regreq.nr_tx_slots = req->nr_tx_slots;
+			regreq.nr_rx_slots = req->nr_rx_slots;
+			regreq.nr_tx_rings = req->nr_tx_rings;
+			regreq.nr_rx_rings = req->nr_rx_rings;
+			regreq.nr_mem_id = req->nr_mem_id;
+			error = netmap_vi_create(®req, 0 /* no autodelete */);
+                        /* Write back to the original struct. */
+			req->nr_tx_slots = regreq.nr_tx_slots;
+			req->nr_rx_slots = regreq.nr_rx_slots;
+			req->nr_tx_rings = regreq.nr_tx_rings;
+			req->nr_rx_rings = regreq.nr_rx_rings;
+			req->nr_mem_id = regreq.nr_mem_id;
+			break;
+		}
+
+		case NETMAP_REQ_VALE_DELIF: {
+			struct nmreq_vale_delif *req =
+				(struct nmreq_vale_delif *)hdr;
+			error = nm_vi_destroy(req->nr_hdr.nr_name);
+			break;
+		}
+
+		case NETMAP_REQ_VALE_POLLING_ENABLE:
+		case NETMAP_REQ_VALE_POLLING_DISABLE: {
+			struct nmreq_vale_polling *req =
+				(struct nmreq_vale_polling *)hdr;
+			error = nm_bdg_polling(req);
+			break;
+		}
+
+		case NETMAP_REQ_POOLS_INFO_GET: {
+			struct nmreq_pools_info_get *req =
+				(struct nmreq_pools_info_get *)hdr;
+			/* Get information from the memory allocator */
 			NMG_LOCK();
 			if (priv->np_na && priv->np_na->nm_mem) {
 				struct netmap_mem_d *nmd = priv->np_na->nm_mem;
-				error = netmap_mem_pools_info_get(nmr, nmd);
+				error = netmap_mem_pools_info_get(req, nmd);
 			} else {
 				error = EINVAL;
 			}
 			NMG_UNLOCK();
 			break;
-		} else if (i != 0) {
-			D("nr_cmd must be 0 not %d", i);
-			error = EINVAL;
-			break;
 		}
 
-		/* protect access to priv from concurrent NIOCREGIF */
-		NMG_LOCK();
-		do {
-			u_int memflags;
-
-			if (priv->np_nifp != NULL) {	/* thread already registered */
-				error = EBUSY;
-				break;
-			}
-
-			if (nmr->nr_arg2) {
-				/* find the allocator and get a reference */
-				nmd = netmap_mem_find(nmr->nr_arg2);
-				if (nmd == NULL) {
-					error = EINVAL;
-					break;
-				}
-			}
-			/* find the interface and a reference */
-			error = netmap_get_na(nmr, &na, &ifp, nmd,
-					      1 /* create */); /* keep reference */
-			if (error)
-				break;
-			if (NETMAP_OWNED_BY_KERN(na)) {
-				error = EBUSY;
-				break;
-			}
-
-			if (na->virt_hdr_len && !(nmr->nr_flags & NR_ACCEPT_VNET_HDR)) {
-				error = EIO;
-				break;
-			}
-
-			error = netmap_do_regif(priv, na, nmr->nr_ringid, nmr->nr_flags);
-			if (error) {    /* reg. failed, release priv and ref */
-				break;
-			}
-			nifp = priv->np_nifp;
-			priv->np_td = td; // XXX kqueue, debugging only
-
-			/* return the offset of the netmap_if object */
-			nmr->nr_rx_rings = na->num_rx_rings;
-			nmr->nr_tx_rings = na->num_tx_rings;
-			nmr->nr_rx_slots = na->num_rx_desc;
-			nmr->nr_tx_slots = na->num_tx_desc;
-			error = netmap_mem_get_info(na->nm_mem, &nmr->nr_memsize, &memflags,
-				&nmr->nr_arg2);
-			if (error) {
-				netmap_do_unregif(priv);
-				break;
-			}
-			if (memflags & NETMAP_MEM_PRIVATE) {
-				*(uint32_t *)(uintptr_t)&nifp->ni_flags |= NI_PRIV_MEM;
-			}
-			for_rx_tx(t) {
-				priv->np_si[t] = nm_si_user(priv, t) ?
-					&na->si[t] : &NMR(na, t)[priv->np_qfirst[t]].si;
-			}
-
-			if (nmr->nr_arg3) {
-				if (netmap_verbose)
-					D("requested %d extra buffers", nmr->nr_arg3);
-				nmr->nr_arg3 = netmap_extra_alloc(na,
-					&nifp->ni_bufs_head, nmr->nr_arg3);
-				if (netmap_verbose)
-					D("got %d extra buffers", nmr->nr_arg3);
-			}
-			nmr->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
+		default: {
+			return EINVAL;
+			break;
+		}
+		}
+		break;
+	}
 
-			/* store ifp reference so that priv destructor may release it */
-			priv->np_ifp = ifp;
-		} while (0);
-		if (error) {
-			netmap_unget_na(na, ifp);
+	case NIOCGINFO:
+	case NIOCREGIF: {
+		/* Request for the legacy control API. Convert it to a
+		 * NIOCCTRL request. */
+		struct nmreq *nmr = (struct nmreq *) data;
+		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
+		if (hdr == NULL) { /* out of memory */
+			return ENOMEM;
 		}
-		/* release the reference from netmap_mem_find() or
-		 * netmap_mem_ext_create()
-		 */
-		if (nmd)
-			netmap_mem_put(nmd);
-		NMG_UNLOCK();
+		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
+		if (error == 0) {
+			nmreq_to_legacy(hdr, nmr);
+		}
+		nm_os_free(hdr);
 		break;
+	}
 
 	case NIOCTXSYNC:
 	case NIOCRXSYNC:
@@ -2790,9 +2909,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		break;
 
 #ifdef WITH_VALE
-	case NIOCCONFIG:
-		error = netmap_bdg_config(nmr);
+	case NIOCCONFIG: {
+		struct nm_ifreq *nr = (struct nm_ifreq *)data;
+		error = netmap_bdg_config(nr);
 		break;
+	}
 #endif
 #ifdef __FreeBSD__
 	case FIONBIO:
@@ -2809,6 +2930,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 
 	default:	/* allow device-specific ioctls */
 	    {
+		struct nmreq *nmr = (struct nmreq *)data;
 		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
 		if (ifp == NULL) {
 			error = ENXIO;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index cec5fda3c..c9acb1f81 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1012,11 +1012,16 @@ struct netmap_bwrap_adapter {
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
 };
+int nm_bdg_ctl_attach(struct nmreq_vale_attach *req);
+int nm_bdg_ctl_detach(struct nmreq_vale_detach *req);
+int nm_bdg_polling(struct nmreq_vale_polling *req);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
-int netmap_vi_create(struct nmreq *, int);
+int netmap_vi_create(struct nmreq_register *, int);
+int nm_vi_destroy(const char *name);
+int netmap_bdg_list(struct nmreq_vale_list *req);
 
 #else /* !WITH_VALE */
-#define netmap_vi_create(nmr, a) (EOPNOTSUPP)
+#define netmap_vi_create(req, a) (EOPNOTSUPP)
 #endif /* WITH_VALE */
 
 #ifdef WITH_PIPES
@@ -1373,9 +1378,10 @@ uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *);
  */
 int netmap_attach_common(struct netmap_adapter *);
 /* fill priv->np_[tr]xq{first,last} using the ringid and flags information
- * coming from a struct nmreq
+ * coming from a struct nmreq_register
  */
-int netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags);
+int netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
+			uint16_t nr_ringid, uint64_t nr_flags);
 /* update the ring parameters (number and size of tx and rx rings).
  * It calls the nm_config callback, if available.
  */
@@ -1409,11 +1415,11 @@ void netmap_disable_all_rings(struct ifnet *);
 void netmap_enable_all_rings(struct ifnet *);
 
 int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
-	uint16_t ringid, uint32_t flags);
+		uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags);
 void netmap_do_unregif(struct netmap_priv_d *priv);
 
 u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
-int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
+int netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 		  struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
 void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
@@ -1449,27 +1455,27 @@ u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 #define	NM_BDG_NOPORT		(NM_BDG_MAXPORTS+1)
 
 /* these are redefined in case of no VALE support */
-int netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
+int netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create);
 struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops);
-int netmap_bdg_config(struct nmreq *nmr);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops);
+int netmap_bdg_config(struct nm_ifreq *nifr);
 
 #else /* !WITH_VALE */
 #define	netmap_get_bdg_na(_1, _2, _3, _4)	0
 #define netmap_init_bridges(_1) 0
 #define netmap_uninit_bridges()
-#define	netmap_bdg_ctl(_1, _2)	EINVAL
+#define	netmap_bdg_regops(_1, _2)	EINVAL
 #endif /* !WITH_VALE */
 
 #ifdef WITH_PIPES
 /* max number of pipes per device */
 #define NM_MAXPIPES	64	/* XXX this should probably be a sysctl */
 void netmap_pipe_dealloc(struct netmap_adapter *);
-int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
+int netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create);
 #else /* !WITH_PIPES */
 #define NM_MAXPIPES	0
@@ -1482,8 +1488,9 @@ int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 #endif
 
 #ifdef WITH_MONITOR
-int netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create);
+int netmap_get_monitor_na(struct nmreq_register *req,
+		struct netmap_adapter **na, struct netmap_mem_d *nmd,
+		int create);
 void netmap_monitor_stop(struct netmap_adapter *na);
 #else
 #define netmap_get_monitor_na(nmr, _2, _3, _4) \
@@ -2120,10 +2127,13 @@ struct netmap_pt_host_adapter {
 	int (*parent_nm_notify)(struct netmap_kring *kring, int flags);
 	void *ptns;
 };
-/* ptnetmap HOST routines */
-int netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
-		struct netmap_mem_d * nmd, int create);
-int ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na);
+
+/* ptnetmap host-side routines */
+int netmap_get_pt_host_na(struct nmreq_register *req,
+		struct netmap_adapter **na, struct netmap_mem_d * nmd,
+		int create);
+int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
+
 static inline int
 nm_ptnetmap_host_on(struct netmap_adapter *na)
 {
@@ -2132,7 +2142,7 @@ nm_ptnetmap_host_on(struct netmap_adapter *na)
 #else /* !WITH_PTNETMAP_HOST */
 #define netmap_get_pt_host_na(nmr, _2, _3, _4) \
 	((nmr)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
-#define ptnetmap_ctl(_1, _2)   EINVAL
+#define ptnetmap_ctl(_1, _2, _3)   EINVAL
 #define nm_ptnetmap_host_on(_1)   EINVAL
 #endif /* !WITH_PTNETMAP_HOST */
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1870b8fed..b47c9ec34 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -132,7 +132,7 @@ struct netmap_obj_pool {
 
 struct netmap_mem_ops {
 	int (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*);
-	int  (*nmd_get_info)(struct netmap_mem_d *, u_int *size,
+	int  (*nmd_get_info)(struct netmap_mem_d *, uint64_t *size,
 			u_int *memflags, uint16_t *id);
 
 	vm_paddr_t (*nmd_ofstophys)(struct netmap_mem_d *, vm_ooffset_t);
@@ -215,7 +215,7 @@ netmap_mem_##name(struct netmap_adapter *na, t1 a1) \
 }
 
 NMD_DEFCB1(int, get_lut, struct netmap_lut *);
-NMD_DEFCB3(int, get_info, u_int *, u_int *, uint16_t *);
+NMD_DEFCB3(int, get_info, uint64_t *, u_int *, uint16_t *);
 NMD_DEFCB1(vm_paddr_t, ofstophys, vm_ooffset_t);
 static int netmap_mem_config(struct netmap_mem_d *);
 NMD_DEFCB(int, config);
@@ -763,9 +763,10 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 PMDL
 win32_build_user_vm_map(struct netmap_mem_d* nmd)
 {
-	int i, j;
-	u_int memsize, memflags, ofs = 0;
+	u_int memflags, ofs = 0;
 	PMDL mainMdl, tempMdl;
+	uint64_t memsize;
+	int i, j;
 
 	if (netmap_mem_get_info(nmd, &memsize, &memflags, NULL)) {
 		D("memory not finalised yet");
@@ -834,8 +835,8 @@ netmap_mem2_get_pool_info(struct netmap_mem_d* nmd, u_int pool, u_int *clustsize
 }
 
 static int
-netmap_mem2_get_info(struct netmap_mem_d* nmd, u_int* size, u_int *memflags,
-	nm_memid_t *id)
+netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size,
+			u_int *memflags, nm_memid_t *id)
 {
 	int error = 0;
 	NMA_LOCK(nmd);
@@ -1976,42 +1977,32 @@ struct netmap_mem_ops netmap_mem_global_ops = {
 };
 
 int
-netmap_mem_pools_info_get(struct nmreq *nmr, struct netmap_mem_d *nmd)
+netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
+				struct netmap_mem_d *nmd)
 {
-	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-	struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
-	struct netmap_pools_info pi;
-	unsigned int memsize;
-	uint16_t memid;
 	int ret;
 
-	ret = netmap_mem_get_info(nmd, &memsize, NULL, &memid);
+	ret = netmap_mem_get_info(nmd, &req->nr_memsize, NULL,
+					&req->nr_mem_id);
 	if (ret) {
 		return ret;
 	}
 
-	pi.memsize = memsize;
-	pi.memid = memid;
 	NMA_LOCK(nmd);
-	pi.if_pool_offset = 0;
-	pi.if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal;
-	pi.if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize;
+	req->nr_if_pool_offset = 0;
+	req->nr_if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal;
+	req->nr_if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize;
 
-	pi.ring_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal;
-	pi.ring_pool_objtotal = nmd->pools[NETMAP_RING_POOL].objtotal;
-	pi.ring_pool_objsize = nmd->pools[NETMAP_RING_POOL]._objsize;
+	req->nr_ring_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal;
+	req->nr_ring_pool_objtotal = nmd->pools[NETMAP_RING_POOL].objtotal;
+	req->nr_ring_pool_objsize = nmd->pools[NETMAP_RING_POOL]._objsize;
 
-	pi.buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal +
+	req->nr_buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal +
 			     nmd->pools[NETMAP_RING_POOL].memtotal;
-	pi.buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal;
-	pi.buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize;
+	req->nr_buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal;
+	req->nr_buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize;
 	NMA_UNLOCK(nmd);
 
-	ret = copyout(&pi, upi, sizeof(pi));
-	if (ret) {
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -2125,7 +2116,7 @@ netmap_mem_pt_guest_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut)
 }
 
 static int
-netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, u_int *size,
+netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, uint64_t *size,
 			     u_int *memflags, uint16_t *id)
 {
 	int error = 0;
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 9d19ebd2a..ab7b143f1 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -135,8 +135,9 @@ void 	   netmap_mem_if_delete(struct netmap_adapter *, struct netmap_if *);
 int	   netmap_mem_rings_create(struct netmap_adapter *);
 void	   netmap_mem_rings_delete(struct netmap_adapter *);
 int 	   netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *);
-int	netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
-int	   netmap_mem_get_info(struct netmap_mem_d *, u_int *size, u_int *memflags, uint16_t *id);
+int	   netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
+int	   netmap_mem_get_info(struct netmap_mem_d *, uint64_t *size,
+				u_int *memflags, uint16_t *id);
 ssize_t    netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr);
 struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_int rxd,
 		u_int extra_bufs, u_int npipes, int* error);
@@ -157,7 +158,8 @@ struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16
 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
 #endif /* WITH_PTNETMAP_GUEST */
 
-int netmap_mem_pools_info_get(struct nmreq *, struct netmap_mem_d *);
+int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
+				struct netmap_mem_d *);
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
 #define NETMAP_MEM_IO		0x4	/* the underlying memory is mmapped I/O */
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index e1c63b21c..e6ccfa495 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -824,38 +824,38 @@ netmap_monitor_dtor(struct netmap_adapter *na)
 }
 
 
-/* check if nmr is a request for a monitor adapter that we can satisfy */
+/* check if req is a request for a monitor adapter that we can satisfy */
 int
-netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_monitor_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq pnmr;
+	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_monitor_adapter *mna;
 	struct ifnet *ifp = NULL;
 	int  error;
-	int zcopy = (nmr->nr_flags & NR_ZCOPY_MON);
+	int zcopy = (req->nr_flags & NR_ZCOPY_MON);
 	char monsuff[10] = "";
 
 	if (zcopy) {
-		nmr->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
+		req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
 	}
-	if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
+	if ((req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
 		ND("not a monitor");
 		return 0;
 	}
 	/* this is a request for a monitor adapter */
 
-	ND("flags %x", nmr->nr_flags);
+	ND("flags %x", req->nr_flags);
 
 	/* first, try to find the adapter that we want to monitor
-	 * We use the same nmr, after we have turned off the monitor flags.
+	 * We use the same req, after we have turned off the monitor flags.
 	 * In this way we can potentially monitor everything netmap understands,
 	 * except other monitors.
 	 */
-	memcpy(&pnmr, nmr, sizeof(pnmr));
-	pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
+	memcpy(&preq, req, sizeof(preq));
+	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
+	error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;
@@ -881,7 +881,8 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	mna->priv.np_na = pna;
 
 	/* grab all the rings we need in the parent */
-	error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags);
+	error = netmap_interp_ringid(&mna->priv, req->nr_mode, req->nr_ringid,
+					req->nr_flags);
 	if (error) {
 		D("ringid error");
 		goto free_out;
@@ -892,8 +893,8 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name,
 			monsuff,
 			zcopy ? "z" : "",
-			(nmr->nr_flags & NR_MONITOR_RX) ? "r" : "",
-			(nmr->nr_flags & NR_MONITOR_TX) ? "t" : "");
+			(req->nr_flags & NR_MONITOR_RX) ? "r" : "",
+			(req->nr_flags & NR_MONITOR_TX) ? "t" : "");
 
 	/* the monitor supports the host rings iff the parent does */
 	mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS);
@@ -913,10 +914,10 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	 * the parent rings, but the user may ask for a different
 	 * number
 	 */
-	mna->up.num_tx_desc = nmr->nr_tx_slots;
+	mna->up.num_tx_desc = req->nr_tx_slots;
 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
 			1, NM_MONITOR_MAXSLOTS, NULL);
-	mna->up.num_rx_desc = nmr->nr_rx_slots;
+	mna->up.num_rx_desc = req->nr_rx_slots;
 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
 			1, NM_MONITOR_MAXSLOTS, NULL);
 	if (zcopy) {
@@ -950,7 +951,7 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	}
 
 	/* remember the traffic directions we have to monitor */
-	mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON));
+	mna->flags = (req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON));
 
 	*na = &mna->up;
 	netmap_adapter_get(*na);
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 3b936d96f..7c3c624f9 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -527,34 +527,34 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 }
 
 int
-netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq pnmr;
+	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
-	struct netmap_pipe_adapter *mna, *sna, *req;
+	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
 	u_int pipe_id;
-	int role = nmr->nr_flags & NR_REG_MASK;
+	int role = req->nr_flags;
 	int error, retries = 0;
 
-	ND("flags %x", nmr->nr_flags);
+	ND("flags %x", req->nr_flags);
 
 	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
 		ND("not a pipe");
 		return 0;
 	}
-	role = nmr->nr_flags & NR_REG_MASK;
 
 	/* first, try to find the parent adapter */
-	bzero(&pnmr, sizeof(pnmr));
-	memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ);
+	bzero(&preq, sizeof(preq));
+	memcpy(&preq.nr_hdr.nr_name, req->nr_hdr.nr_name,
+		sizeof(preq.nr_hdr.nr_name));
 	/* pass to parent the requested number of pipes */
-	pnmr.nr_arg1 = nmr->nr_arg1;
+	preq.nr_pipes = req->nr_pipes;
 	for (;;) {
 		int create_error;
 
-		error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
+		error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -564,7 +564,7 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 		ND("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
 		NMG_UNLOCK();
-		create_error = netmap_vi_create(&pnmr, 1 /* autodelete */);
+		create_error = netmap_vi_create(&preq, 1 /* autodelete */);
 		NMG_LOCK();
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
@@ -581,16 +581,16 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 	}
 
 	/* next, lookup the pipe id in the parent list */
-	req = NULL;
-	pipe_id = nmr->nr_ringid & NETMAP_RING_MASK;
+	reqna = NULL;
+	pipe_id = req->nr_ringid;
 	mna = netmap_pipe_find(pna, pipe_id);
 	if (mna) {
 		if (mna->role == role) {
 			ND("found %d directly at %d", pipe_id, mna->parent_slot);
-			req = mna;
+			reqna = mna;
 		} else {
 			ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
-			req = mna->peer;
+			reqna = mna->peer;
 		}
 		/* the pipe we have found already holds a ref to the parent,
                  * so we need to drop the one we got from netmap_get_na()
@@ -631,10 +631,10 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 
 	mna->up.num_tx_rings = 1;
 	mna->up.num_rx_rings = 1;
-	mna->up.num_tx_desc = nmr->nr_tx_slots;
+	mna->up.num_tx_desc = req->nr_tx_slots;
 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
 			1, NM_PIPE_MAXSLOTS, NULL);
-	mna->up.num_rx_desc = nmr->nr_rx_slots;
+	mna->up.num_rx_desc = req->nr_rx_slots;
 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
 			1, NM_PIPE_MAXSLOTS, NULL);
 	error = netmap_attach_common(&mna->up);
@@ -673,11 +673,11 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 		if_ref(ifp);
 
 	if (role == NR_REG_PIPE_MASTER) {
-		req = mna;
+		reqna = mna;
 		mna->peer_ref = 1;
 		netmap_adapter_get(&sna->up);
 	} else {
-		req = sna;
+		reqna = sna;
 		sna->peer_ref = 1;
 		netmap_adapter_get(&mna->up);
 	}
@@ -685,8 +685,8 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 found:
 
 	ND("pipe %d %s at %p", pipe_id,
-		(req->role == NR_REG_PIPE_MASTER ? "master" : "slave"), req);
-	*na = &req->up;
+		(reqna->role == NR_REG_PIPE_MASTER ? "master" : "slave"), reqna);
+	*na = &reqna->up;
 	netmap_adapter_get(*na);
 
 	/* keep the reference to the parent.
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index edb49dc50..df2553d44 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -761,34 +761,6 @@ ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
 	}
 }
 
-static struct ptnetmap_cfg *
-ptnetmap_read_cfg(struct nmreq *nmr)
-{
-	uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1;
-	struct ptnetmap_cfg *cfg;
-	struct ptnetmap_cfg tmp;
-	size_t cfglen;
-
-	if (copyin((const void *)*nmr_ptncfg, &tmp, sizeof(tmp))) {
-		D("Partial copyin() failed");
-		return NULL;
-	}
-
-	cfglen = sizeof(tmp) + tmp.num_rings * tmp.entry_size;
-	cfg = nm_os_malloc(cfglen);
-	if (!cfg) {
-		return NULL;
-	}
-
-	if (copyin((const void *)*nmr_ptncfg, cfg, cfglen)) {
-		D("Full copyin() failed");
-		nm_os_free(cfg);
-		return NULL;
-	}
-
-	return cfg;
-}
-
 static int nm_unused_notify(struct netmap_kring *, int);
 static int nm_pt_host_notify(struct netmap_kring *, int);
 
@@ -941,66 +913,55 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
 
 /*
  * Called by netmap_ioctl().
- * Operation is indicated in nmr->nr_cmd.
+ * Operation is indicated in nr_name.
  *
  * Called without NMG_LOCK.
  */
 int
-ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na)
+ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na)
 {
-    struct netmap_pt_host_adapter *pth_na;
-    struct ptnetmap_cfg *cfg;
-    char *name;
-    int cmd, error = 0;
-
-    name = nmr->nr_name;
-    cmd = nmr->nr_cmd;
+	struct netmap_pt_host_adapter *pth_na;
+	struct ptnetmap_cfg *cfg = NULL;
+	int error = 0;
 
-    DBG(D("name: %s", name));
+	DBG(D("name: %s", nr_name));
 
-    if (!nm_ptnetmap_host_on(na)) {
-        D("ERROR Netmap adapter %p is not a ptnetmap host adapter", na);
-        error = ENXIO;
-        goto done;
-    }
-    pth_na = (struct netmap_pt_host_adapter *)na;
-
-    NMG_LOCK();
-    switch (cmd) {
-    case NETMAP_PT_HOST_CREATE:
-	/* Read hypervisor configuration from userspace. */
-        cfg = ptnetmap_read_cfg(nmr);
-        if (!cfg)
-            break;
-        /* Create ptnetmap state (kctxs, ...) and switch parent
-	 * adapter to ptnetmap mode. */
-        error = ptnetmap_create(pth_na, cfg);
-	nm_os_free(cfg);
-        if (error)
-            break;
-        /* Start kthreads. */
-        error = ptnetmap_start_kctx_workers(pth_na);
-        if (error)
-            ptnetmap_delete(pth_na);
-        break;
-
-    case NETMAP_PT_HOST_DELETE:
-        /* Stop kthreads. */
-        ptnetmap_stop_kctx_workers(pth_na);
-        /* Switch parent adapter back to normal mode and destroy
-	 * ptnetmap state (kthreads, ...). */
-        ptnetmap_delete(pth_na);
-        break;
-
-    default:
-        D("ERROR invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
-        error = EINVAL;
-        break;
-    }
-    NMG_UNLOCK();
+	if (!nm_ptnetmap_host_on(na)) {
+		D("ERROR Netmap adapter %p is not a ptnetmap host adapter",
+			na);
+		return ENXIO;
+	}
+	pth_na = (struct netmap_pt_host_adapter *)na;
+
+	NMG_LOCK();
+	if (create) {
+		/* Read hypervisor configuration from userspace. */
+		/* TODO */
+		if (!cfg) {
+			goto out;
+		}
+		/* Create ptnetmap state (kctxs, ...) and switch parent
+		 * adapter to ptnetmap mode. */
+		error = ptnetmap_create(pth_na, cfg);
+		nm_os_free(cfg);
+		if (error) {
+			goto out;
+		}
+		/* Start kthreads. */
+		error = ptnetmap_start_kctx_workers(pth_na);
+		if (error)
+			ptnetmap_delete(pth_na);
+	} else {
+		/* Stop kthreads. */
+		ptnetmap_stop_kctx_workers(pth_na);
+		/* Switch parent adapter back to normal mode and destroy
+		 * ptnetmap state (kthreads, ...). */
+		ptnetmap_delete(pth_na);
+	}
+out:
+	NMG_UNLOCK();
 
-done:
-    return error;
+	return error;
 }
 
 /* nm_notify callbacks for ptnetmap */
@@ -1187,17 +1148,17 @@ nm_pt_host_dtor(struct netmap_adapter *na)
 
 /* check if nmr is a request for a ptnetmap adapter that we can satisfy */
 int
-netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_pt_host_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-    struct nmreq parent_nmr;
+    struct nmreq_register preq;
     struct netmap_adapter *parent; /* target adapter */
     struct netmap_pt_host_adapter *pth_na;
     struct ifnet *ifp = NULL;
     int error;
 
     /* Check if it is a request for a ptnetmap adapter */
-    if ((nmr->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
+    if ((req->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
         return 0;
     }
 
@@ -1210,12 +1171,12 @@ netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
     }
 
     /* first, try to find the adapter that we want to passthrough
-     * We use the same nmr, after we have turned off the ptnetmap flag.
+     * We use the same req, after we have turned off the ptnetmap flag.
      * In this way we can potentially passthrough everything netmap understands.
      */
-    memcpy(&parent_nmr, nmr, sizeof(parent_nmr));
-    parent_nmr.nr_flags &= ~(NR_PTNETMAP_HOST);
-    error = netmap_get_na(&parent_nmr, &parent, &ifp, nmd, create);
+    memcpy(&preq, req, sizeof(preq));
+    preq.nr_flags &= ~(NR_PTNETMAP_HOST);
+    error = netmap_get_na(&preq, &parent, &ifp, nmd, create);
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index d9faca7ec..40d66249d 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -164,7 +164,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
     "Max batch size to be used in the bridge");
 SYSEND;
 
-static int netmap_vp_create(struct nmreq *, struct ifnet *,
+static int netmap_vp_create(struct nmreq_register *, struct ifnet *,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
 static int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 static int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
@@ -213,15 +213,14 @@ struct nm_bridge {
 
 	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
 
-
 	/*
-	 * The function to decide the destination port.
+	 * Programmable lookup functions to figure out the destination port.
 	 * It returns either of an index of the destination port,
 	 * NM_BDG_BROADCAST to broadcast this packet, or NM_BDG_NOPORT not to
 	 * forward this packet.  ring_nr is the source ring index, and the
 	 * function may overwrite this value to forward this packet to a
 	 * different ring index.
-	 * This function must be set by netmap_bdg_ctl().
+	 * The function is set by netmap_bdg_regops().
 	 */
 	struct netmap_bdg_ops bdg_ops;
 
@@ -558,7 +557,7 @@ netmap_vp_dtor(struct netmap_adapter *na)
 }
 
 /* remove a persistent VALE port from the system */
-static int
+int
 nm_vi_destroy(const char *name)
 {
 	struct ifnet *ifp;
@@ -608,13 +607,14 @@ nm_vi_destroy(const char *name)
 }
 
 static int
-nm_update_info(struct nmreq *nmr, struct netmap_adapter *na)
+nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
 {
-	nmr->nr_rx_rings = na->num_rx_rings;
-	nmr->nr_tx_rings = na->num_tx_rings;
-	nmr->nr_rx_slots = na->num_rx_desc;
-	nmr->nr_tx_slots = na->num_tx_desc;
-	return netmap_mem_get_info(na->nm_mem, &nmr->nr_memsize, NULL, &nmr->nr_arg2);
+	req->nr_rx_rings = na->num_rx_rings;
+	req->nr_tx_rings = na->num_tx_rings;
+	req->nr_rx_slots = na->num_rx_desc;
+	req->nr_tx_slots = na->num_tx_desc;
+	return netmap_mem_get_info(na->nm_mem, &req->nr_memsize, NULL,
+					&req->nr_mem_id);
 }
 
 /*
@@ -622,7 +622,7 @@ nm_update_info(struct nmreq *nmr, struct netmap_adapter *na)
  * The interface will be attached to a bridge later.
  */
 int
-netmap_vi_create(struct nmreq *nmr, int autodelete)
+netmap_vi_create(struct nmreq_register *req, int autodelete)
 {
 	struct ifnet *ifp;
 	struct netmap_vp_adapter *vpna;
@@ -630,14 +630,14 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
 	int error;
 
 	/* don't include VALE prefix */
-	if (!strncmp(nmr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
+	if (!strncmp(req->nr_hdr.nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
 		return EINVAL;
-	ifp = ifunit_ref(nmr->nr_name);
+	ifp = ifunit_ref(req->nr_hdr.nr_name);
 	if (ifp) { /* already exist, cannot create new one */
 		error = EEXIST;
 		NMG_LOCK();
 		if (NM_NA_VALID(ifp)) {
-			int update_err = nm_update_info(nmr, NA(ifp));
+			int update_err = nm_update_info(req, NA(ifp));
 			if (update_err)
 				error = update_err;
 		}
@@ -645,20 +645,20 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
 		if_rele(ifp);
 		return error;
 	}
-	error = nm_os_vi_persist(nmr->nr_name, &ifp);
+	error = nm_os_vi_persist(req->nr_hdr.nr_name, &ifp);
 	if (error)
 		return error;
 
 	NMG_LOCK();
-	if (nmr->nr_arg2) {
-		nmd = netmap_mem_find(nmr->nr_arg2);
+	if (req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
 		if (nmd == NULL) {
 			error = EINVAL;
 			goto err_1;
 		}
 	}
 	/* netmap_vp_create creates a struct netmap_vp_adapter */
-	error = netmap_vp_create(nmr, ifp, nmd, &vpna);
+	error = netmap_vp_create(req, ifp, nmd, &vpna);
 	if (error) {
 		D("error %d", error);
 		goto err_1;
@@ -672,11 +672,11 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
 	}
 	NM_ATTACH_NA(ifp, &vpna->up);
 	/* return the updated info */
-	error = nm_update_info(nmr, &vpna->up);
+	error = nm_update_info(req, &vpna->up);
 	if (error) {
 		goto err_2;
 	}
-	D("returning nr_arg2 %d", nmr->nr_arg2);
+	D("returning nr_mem_id %d", req->nr_mem_id);
 	if (nmd)
 		netmap_mem_put(nmd);
 	NMG_UNLOCK();
@@ -704,10 +704,10 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
  * (*na != NULL && return == 0).
  */
 int
-netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	char *nr_name = nmr->nr_name;
+	char *nr_name = hdr->nr_name;
 	const char *ifname;
 	struct ifnet *ifp = NULL;
 	int error = 0;
@@ -776,14 +776,15 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 		/* Create an ephemeral virtual port
 		 * This block contains all the ephemeral-specific logics
 		 */
-		if (nmr->nr_cmd) {
-			/* nr_cmd must be 0 for a virtual port */
+
+		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
 			error = EINVAL;
 			goto out;
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = netmap_vp_create(nmr, NULL, nmd, &vpna);
+		error = netmap_vp_create((struct nmreq_register *)hdr,
+					NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -795,11 +796,11 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 		struct netmap_adapter *hw;
 
 		/* the vale:nic syntax is only valid for some commands */
-		switch (nmr->nr_cmd) {
-		case NETMAP_BDG_ATTACH:
-		case NETMAP_BDG_DETACH:
-		case NETMAP_BDG_POLLING_ON:
-		case NETMAP_BDG_POLLING_OFF:
+		switch (hdr->nr_reqtype) {
+		case NETMAP_REQ_VALE_ATTACH:
+		case NETMAP_REQ_VALE_DETACH:
+		case NETMAP_REQ_VALE_POLLING_ENABLE:
+		case NETMAP_REQ_VALE_POLLING_DISABLE:
 			break; /* ok */
 		default:
 			error = EINVAL;
@@ -816,8 +817,14 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 			goto out;
 		vpna = hw->na_vp;
 		hostna = hw->na_hostvp;
-		if (nmr->nr_arg1 != NETMAP_BDG_HOST)
-			hostna = NULL;
+		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+			/* Check if we need to skip the host rings. */
+			struct nmreq_vale_attach *areq =
+				(struct nmreq_vale_attach *)hdr;
+			if ((areq->nr_flags & NETMAP_BDG_HOST) == 0) {
+				hostna = NULL;
+			}
+		}
 	}
 
 	BDG_WLOCK(b);
@@ -848,9 +855,9 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 }
 
 
-/* Process NETMAP_BDG_ATTACH */
-static int
-nm_bdg_ctl_attach(struct nmreq *nmr)
+/* Process NETMAP_REQ_VALE_ATTACH. */
+int
+nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 {
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
@@ -858,15 +865,16 @@ nm_bdg_ctl_attach(struct nmreq *nmr)
 
 	NMG_LOCK();
 
-	if (nmr->nr_arg2) {
-		nmd = netmap_mem_find(nmr->nr_arg2);
+	if (req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
 		if (nmd == NULL) {
 			error = EINVAL;
 			goto unlock_exit;
 		}
 	}
 
-	error = netmap_get_bdg_na(nmr, &na, nmd, 1 /* create if not exists */);
+	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
+				nmd, 1 /* create if not exists */);
 	if (error) /* no device */
 		goto unlock_exit;
 
@@ -905,15 +913,16 @@ nm_is_bwrap(struct netmap_adapter *na)
 	return na->nm_register == netmap_bwrap_reg;
 }
 
-/* process NETMAP_BDG_DETACH */
-static int
-nm_bdg_ctl_detach(struct nmreq *nmr)
+/* Process NETMAP_REQ_VALE_DETACH. */
+int
+nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
 {
 	struct netmap_adapter *na;
 	int error;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na(nmr, &na, NULL, 0 /* don't create */);
+	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
+				NULL, 0 /* don't create */);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
 	}
@@ -955,7 +964,7 @@ struct nm_bdg_polling_state {
 	bool configured;
 	bool stopped;
 	struct netmap_bwrap_adapter *bna;
-	u_int reg;
+	uint32_t mode;
 	u_int qfirst;
 	u_int qlast;
 	u_int cpu_from;
@@ -999,7 +1008,8 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
 	kcfg.use_kthread = 1;
 	for (i = 0; i < bps->ncpus; i++) {
 		struct nm_bdg_kthread *t = bps->kthreads + i;
-		int all = (bps->ncpus == 1 && bps->reg == NR_REG_ALL_NIC);
+		int all = (bps->ncpus == 1 &&
+			bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU);
 		int affinity = bps->cpu_from + i;
 
 		t->bps = bps;
@@ -1075,67 +1085,68 @@ nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps)
 }
 
 static int
-get_polling_cfg(struct nmreq *nmr, struct netmap_adapter *na,
-			struct nm_bdg_polling_state *bps)
+get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
+		struct nm_bdg_polling_state *bps)
 {
-	int req_cpus, avail_cpus, core_from;
-	u_int reg, i, qfirst, qlast;
+	unsigned int avail_cpus, core_from;
+	unsigned int qfirst, qlast;
+	uint32_t i = req->nr_first_cpu_id;
+	uint32_t req_cpus = req->nr_num_polling_cpus;
 
 	avail_cpus = nm_os_ncpus();
-	req_cpus = nmr->nr_arg1;
 
 	if (req_cpus == 0) {
 		D("req_cpus must be > 0");
 		return EINVAL;
 	} else if (req_cpus >= avail_cpus) {
-		D("for safety, we need at least one core left in the system");
+		D("Cannot use all the CPUs in the system");
 		return EINVAL;
 	}
-	reg = nmr->nr_flags & NR_REG_MASK;
-	i = nmr->nr_ringid & NETMAP_RING_MASK;
-	/*
-	 * ONE_NIC: dedicate one core to one ring. If multiple cores
-	 *          are specified, consecutive rings are also polled.
-	 *          For example, if ringid=2 and 2 cores are given,
-	 *          ring 2 and 3 are polled by core 2 and 3, respectively.
-	 * ALL_NIC: poll all the rings using a core specified by ringid.
-	 *          the number of cores must be 1.
-	 */
-	if (reg == NR_REG_ONE_NIC) {
+
+	if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) {
+		/* Use a separate core for each ring. If nr_num_polling_cpus>1
+		 * more consecutive rings are polled.
+		 * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2,
+		 * ring 2 and 3 are polled by core 2 and 3, respectively. */
 		if (i + req_cpus > nma_get_nrings(na, NR_RX)) {
-			D("only %d rings exist (ring %u-%u is given)",
-				nma_get_nrings(na, NR_RX), i, i+req_cpus);
+			D("Rings %u-%u not in range (have %d rings)",
+				i, i + req_cpus, nma_get_nrings(na, NR_RX));
 			return EINVAL;
 		}
 		qfirst = i;
 		qlast = qfirst + req_cpus;
 		core_from = qfirst;
-	} else if (reg == NR_REG_ALL_NIC) {
+
+	} else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) {
+		/* Poll all the rings using a core specified by nr_first_cpu_id.
+		 * the number of cores must be 1. */
 		if (req_cpus != 1) {
-			D("ncpus must be 1 not %d for REG_ALL_NIC", req_cpus);
+			D("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
+				"(was %d)", req_cpus);
 			return EINVAL;
 		}
 		qfirst = 0;
 		qlast = nma_get_nrings(na, NR_RX);
 		core_from = i;
 	} else {
-		D("reg must be ALL_NIC or ONE_NIC");
+		D("Invalid polling mode");
 		return EINVAL;
 	}
 
-	bps->reg = reg;
+	bps->mode = req->nr_mode;
 	bps->qfirst = qfirst;
 	bps->qlast = qlast;
 	bps->cpu_from = core_from;
 	bps->ncpus = req_cpus;
 	D("%s qfirst %u qlast %u cpu_from %u ncpus %u",
-		reg == NR_REG_ALL_NIC ? "REG_ALL_NIC" : "REG_ONE_NIC",
+		req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ?
+		"MULTI" : "SINGLE",
 		qfirst, qlast, core_from, req_cpus);
 	return 0;
 }
 
 static int
-nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na)
+nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na)
 {
 	struct nm_bdg_polling_state *bps;
 	struct netmap_bwrap_adapter *bna;
@@ -1153,7 +1164,7 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na)
 	bps->configured = false;
 	bps->stopped = true;
 
-	if (get_polling_cfg(nmr, na, bps)) {
+	if (get_polling_cfg(req, na, bps)) {
 		nm_os_free(bps);
 		return EINVAL;
 	}
@@ -1182,7 +1193,7 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na)
 }
 
 static int
-nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na)
+nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
 {
 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na;
 	struct nm_bdg_polling_state *bps;
@@ -1201,190 +1212,146 @@ nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na)
 	return 0;
 }
 
-/* Called by either user's context (netmap_ioctl())
- * or external kernel modules (e.g., Openvswitch).
- * Operation is indicated in nmr->nr_cmd.
- * NETMAP_BDG_OPS that sets configure/lookup/dtor functions to the bridge
- * requires bdg_ops argument; the other commands ignore this argument.
- *
- * Called without NMG_LOCK.
- */
 int
-netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops)
+nm_bdg_polling(struct nmreq_vale_polling *req)
 {
+	struct netmap_adapter *na = NULL;
+	int error = 0;
+
+	NMG_LOCK();
+	error = netmap_get_bdg_na((struct nmreq_header *)req,
+					&na, NULL, 0);
+	if (na && !error) {
+		if (!nm_is_bwrap(na)) {
+			error = EOPNOTSUPP;
+		} else if (req->nr_hdr.nr_reqtype == NETMAP_BDG_POLLING_ON) {
+			error = nm_bdg_ctl_polling_start(req, na);
+			if (!error)
+				netmap_adapter_get(na);
+		} else {
+			error = nm_bdg_ctl_polling_stop(na);
+			if (!error)
+				netmap_adapter_put(na);
+		}
+		netmap_adapter_put(na);
+	}
+	NMG_UNLOCK();
+
+	return error;
+}
+
+/* Process NETMAP_REQ_VALE_LIST. */
+int
+netmap_bdg_list(struct nmreq_vale_list *req)
+{
+	int namelen = strlen(req->nr_hdr.nr_name);
 	struct nm_bridge *b, *bridges;
-	struct netmap_adapter *na;
 	struct netmap_vp_adapter *vpna;
-	char *name = nmr->nr_name;
-	int cmd = nmr->nr_cmd, namelen = strlen(name);
 	int error = 0, i, j;
 	u_int num_bridges;
 
 	netmap_bns_getbridges(&bridges, &num_bridges);
 
-	switch (cmd) {
-	case NETMAP_BDG_NEWIF:
-		error = netmap_vi_create(nmr, 0 /* no autodelete */);
-		break;
-
-	case NETMAP_BDG_DELIF:
-		error = nm_vi_destroy(nmr->nr_name);
-		break;
-
-	case NETMAP_BDG_ATTACH:
-		error = nm_bdg_ctl_attach(nmr);
-		break;
-
-	case NETMAP_BDG_DETACH:
-		error = nm_bdg_ctl_detach(nmr);
-		break;
-
-	case NETMAP_BDG_LIST:
-		/* this is used to enumerate bridges and ports */
-		if (namelen) { /* look up indexes of bridge and port */
-			if (strncmp(name, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
-				error = EINVAL;
-				break;
-			}
-			NMG_LOCK();
-			b = nm_find_bridge(name, 0 /* don't create */);
-			if (!b) {
-				error = ENOENT;
-				NMG_UNLOCK();
-				break;
-			}
-
-			error = 0;
-			nmr->nr_arg1 = b - bridges; /* bridge index */
-			nmr->nr_arg2 = NM_BDG_NOPORT;
-			for (j = 0; j < b->bdg_active_ports; j++) {
-				i = b->bdg_port_index[j];
-				vpna = b->bdg_ports[i];
-				if (vpna == NULL) {
-					D("---AAAAAAAAARGH-------");
-					continue;
-				}
-				/* the former and the latter identify a
-				 * virtual port and a NIC, respectively
-				 */
-				if (!strcmp(vpna->up.name, name)) {
-					nmr->nr_arg2 = i; /* port index */
-					break;
-				}
-			}
-			NMG_UNLOCK();
-		} else {
-			/* return the first non-empty entry starting from
-			 * bridge nr_arg1 and port nr_arg2.
-			 *
-			 * Users can detect the end of the same bridge by
-			 * seeing the new and old value of nr_arg1, and can
-			 * detect the end of all the bridge by error != 0
-			 */
-			i = nmr->nr_arg1;
-			j = nmr->nr_arg2;
-
-			NMG_LOCK();
-			for (error = ENOENT; i < NM_BRIDGES; i++) {
-				b = bridges + i;
-				for ( ; j < NM_BDG_MAXPORTS; j++) {
-					if (b->bdg_ports[j] == NULL)
-						continue;
-					vpna = b->bdg_ports[j];
-					strncpy(name, vpna->up.name, (size_t)IFNAMSIZ);
-					error = 0;
-					goto out;
-				}
-				j = 0; /* following bridges scan from 0 */
-			}
-		out:
-			nmr->nr_arg1 = i;
-			nmr->nr_arg2 = j;
-			NMG_UNLOCK();
-		}
-		break;
-
-	case NETMAP_BDG_REGOPS: /* XXX this should not be available from userspace */
-		/* register callbacks to the given bridge.
-		 * nmr->nr_name may be just bridge's name (including ':'
-		 * if it is not just NM_NAME).
-		 */
-		if (!bdg_ops) {
-			error = EINVAL;
-			break;
+	/* this is used to enumerate bridges and ports */
+	if (namelen) { /* look up indexes of bridge and port */
+		if (strncmp(req->nr_hdr.nr_name, NM_BDG_NAME,
+					strlen(NM_BDG_NAME))) {
+			return EINVAL;
 		}
 		NMG_LOCK();
-		b = nm_find_bridge(name, 0 /* don't create */);
+		b = nm_find_bridge(req->nr_hdr.nr_name, 0 /* don't create */);
 		if (!b) {
-			error = EINVAL;
-		} else {
-			b->bdg_ops = *bdg_ops;
-		}
-		NMG_UNLOCK();
-		break;
-
-	case NETMAP_BDG_VNET_HDR:
-		/* Valid lengths for the virtio-net header are 0 (no header),
-		   10 and 12. */
-		if (nmr->nr_arg1 != 0 &&
-			nmr->nr_arg1 != sizeof(struct nm_vnet_hdr) &&
-				nmr->nr_arg1 != 12) {
-			error = EINVAL;
-			break;
+			NMG_UNLOCK();
+			return ENOENT;
 		}
-		NMG_LOCK();
-		error = netmap_get_bdg_na(nmr, &na, NULL, 0);
-		if (na && !error) {
-			vpna = (struct netmap_vp_adapter *)na;
-			na->virt_hdr_len = nmr->nr_arg1;
-			if (na->virt_hdr_len) {
-				vpna->mfs = NETMAP_BUF_SIZE(na);
+
+		req->nr_bridge_idx = b - bridges; /* bridge index */
+		req->nr_port_idx = NM_BDG_NOPORT;
+		for (j = 0; j < b->bdg_active_ports; j++) {
+			i = b->bdg_port_index[j];
+			vpna = b->bdg_ports[i];
+			if (vpna == NULL) {
+				D("This should not happen");
+				continue;
+			}
+			/* the former and the latter identify a
+			 * virtual port and a NIC, respectively
+			 */
+			if (!strcmp(vpna->up.name, req->nr_hdr.nr_name)) {
+				req->nr_port_idx = i; /* port index */
+				break;
 			}
-			D("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
-			netmap_adapter_put(na);
-		} else if (!na) {
-			error = ENXIO;
 		}
 		NMG_UNLOCK();
-		break;
+	} else {
+		/* return the first non-empty entry starting from
+		 * bridge nr_arg1 and port nr_arg2.
+		 *
+		 * Users can detect the end of the same bridge by
+		 * seeing the new and old value of nr_arg1, and can
+		 * detect the end of all the bridge by error != 0
+		 */
+		i = req->nr_bridge_idx;
+		j = req->nr_port_idx;
 
-	case NETMAP_BDG_POLLING_ON:
-	case NETMAP_BDG_POLLING_OFF:
 		NMG_LOCK();
-		error = netmap_get_bdg_na(nmr, &na, NULL, 0);
-		if (na && !error) {
-			if (!nm_is_bwrap(na)) {
-				error = EOPNOTSUPP;
-			} else if (cmd == NETMAP_BDG_POLLING_ON) {
-				error = nm_bdg_ctl_polling_start(nmr, na);
-				if (!error)
-					netmap_adapter_get(na);
-			} else {
-				error = nm_bdg_ctl_polling_stop(nmr, na);
-				if (!error)
-					netmap_adapter_put(na);
+		for (error = ENOENT; i < NM_BRIDGES; i++) {
+			b = bridges + i;
+			for ( ; j < NM_BDG_MAXPORTS; j++) {
+				if (b->bdg_ports[j] == NULL)
+					continue;
+				vpna = b->bdg_ports[j];
+				strncpy(req->nr_hdr.nr_name, vpna->up.name,
+					(size_t)IFNAMSIZ);
+				error = 0;
+				goto out;
 			}
-			netmap_adapter_put(na);
+			j = 0; /* following bridges scan from 0 */
 		}
+	out:
+		req->nr_bridge_idx = i;
+		req->nr_port_idx = j;
 		NMG_UNLOCK();
-		break;
+	}
+
+	return error;
+}
+
+/* Called by external kernel modules (e.g., Openvswitch).
+ * to set configure/lookup/dtor functions of a VALE instance.
+ * Register callbacks to the given bridge. 'name' may be just
+ * bridge's name (including ':' if it is not just NM_BDG_NAME).
+ * Called without NMG_LOCK.
+ */
+int
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops)
+{
+	struct nm_bridge *b;
+	int error = 0;
 
-	default:
-		D("invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
+	if (!bdg_ops) {
+		return EINVAL;
+	}
+	NMG_LOCK();
+	b = nm_find_bridge(name, 0 /* don't create */);
+	if (!b) {
 		error = EINVAL;
-		break;
+	} else {
+		b->bdg_ops = *bdg_ops;
 	}
+	NMG_UNLOCK();
+
 	return error;
 }
 
 int
-netmap_bdg_config(struct nmreq *nmr)
+netmap_bdg_config(struct nm_ifreq *nr)
 {
 	struct nm_bridge *b;
 	int error = EINVAL;
 
 	NMG_LOCK();
-	b = nm_find_bridge(nmr->nr_name, 0);
+	b = nm_find_bridge(nr->nifr_name, 0);
 	if (!b) {
 		NMG_UNLOCK();
 		return error;
@@ -1393,7 +1360,7 @@ netmap_bdg_config(struct nmreq *nmr)
 	/* Don't call config() with NMG_LOCK() held */
 	BDG_RLOCK(b);
 	if (b->bdg_ops.config != NULL)
-		error = b->bdg_ops.config((struct nm_ifreq *)nmr);
+		error = b->bdg_ops.config(nr);
 	BDG_RUNLOCK(b);
 	return error;
 }
@@ -2223,7 +2190,7 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
  * Only persistent VALE ports have a non-null ifp.
  */
 static int
-netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
+netmap_vp_create(struct nmreq_register *req, struct ifnet *ifp,
 		struct netmap_mem_d *nmd,
 		struct netmap_vp_adapter **ret)
 {
@@ -2231,6 +2198,7 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
 	struct netmap_adapter *na;
 	int error = 0;
 	u_int npipes = 0;
+	u_int extrabufs = 0;
 
 	vpna = nm_os_malloc(sizeof(*vpna));
 	if (vpna == NULL)
@@ -2239,31 +2207,32 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
  	na = &vpna->up;
 
 	na->ifp = ifp;
-	strncpy(na->name, nmr->nr_name, sizeof(na->name));
+	strncpy(na->name, req->nr_hdr.nr_name, sizeof(na->name));
 
 	/* bound checking */
-	na->num_tx_rings = nmr->nr_tx_rings;
+	na->num_tx_rings = req->nr_tx_rings;
 	nm_bound_var(&na->num_tx_rings, 1, 1, NM_BDG_MAXRINGS, NULL);
-	nmr->nr_tx_rings = na->num_tx_rings; // write back
-	na->num_rx_rings = nmr->nr_rx_rings;
+	req->nr_tx_rings = na->num_tx_rings; /* write back */
+	na->num_rx_rings = req->nr_rx_rings;
 	nm_bound_var(&na->num_rx_rings, 1, 1, NM_BDG_MAXRINGS, NULL);
-	nmr->nr_rx_rings = na->num_rx_rings; // write back
-	nm_bound_var(&nmr->nr_tx_slots, NM_BRIDGE_RINGSIZE,
+	req->nr_rx_rings = na->num_rx_rings; /* write back */
+	nm_bound_var(&req->nr_tx_slots, NM_BRIDGE_RINGSIZE,
 			1, NM_BDG_MAXSLOTS, NULL);
-	na->num_tx_desc = nmr->nr_tx_slots;
-	nm_bound_var(&nmr->nr_rx_slots, NM_BRIDGE_RINGSIZE,
+	na->num_tx_desc = req->nr_tx_slots;
+	nm_bound_var(&req->nr_rx_slots, NM_BRIDGE_RINGSIZE,
 			1, NM_BDG_MAXSLOTS, NULL);
 	/* validate number of pipes. We want at least 1,
 	 * but probably can do with some more.
 	 * So let's use 2 as default (when 0 is supplied)
 	 */
-	npipes = nmr->nr_arg1;
+	npipes = req->nr_pipes;
 	nm_bound_var(&npipes, 2, 1, NM_MAXPIPES, NULL);
-	nmr->nr_arg1 = npipes;	/* write back */
+	req->nr_pipes = npipes;	/* write back */
 	/* validate extra bufs */
-	nm_bound_var(&nmr->nr_arg3, 0, 0,
+	nm_bound_var(&extrabufs, 0, 0,
 			128*NM_BDG_MAXSLOTS, NULL);
-	na->num_rx_desc = nmr->nr_rx_slots;
+	req->nr_extra_bufs = extrabufs; /* write back */
+	na->num_rx_desc = req->nr_rx_slots;
 	/* Set the mfs to a default value, as it is needed on the VALE
 	 * mismatch datapath. XXX We should set it according to the MTU
 	 * known to the kernel. */
@@ -2286,13 +2255,13 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
 	na->nm_krings_create = netmap_vp_krings_create;
 	na->nm_krings_delete = netmap_vp_krings_delete;
 	na->nm_dtor = netmap_vp_dtor;
-	D("nr_arg2 %d", nmr->nr_arg2);
+	D("nr_mem_id %d", req->nr_mem_id);
 	na->nm_mem = nmd ?
 		netmap_mem_get(nmd):
 		netmap_mem_private_new(
 			na->num_tx_rings, na->num_tx_desc,
 			na->num_rx_rings, na->num_rx_desc,
-			nmr->nr_arg3, npipes, &error);
+			req->nr_extra_bufs, npipes, &error);
 	if (na->nm_mem == NULL)
 		goto err;
 	na->nm_bdg_attach = netmap_vp_bdg_attach;
@@ -2751,7 +2720,7 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, nmr->nr_ringid, nmr->nr_flags);
+		error = netmap_do_regif(npriv, na, /* TODO no-host-rings*/ NR_REG_NIC_SW, 0, 0);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3a397d393..e5d24416c 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -400,7 +400,9 @@ struct nmreq_option {
 struct nmreq_header {
 	uint16_t		nr_version;	/* API version */
 	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
-	struct nmreq_option	*options;	/* command-specific options */
+#define NETMAP_REQ_IFNAMSIZ	64
+	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
+	struct nmreq_option	*nr_options;	/* command-specific options */
 };
 
 enum {
@@ -444,15 +446,12 @@ enum {
 	NETMAP_REQ_OPT_EXTMEM = 1,
 };
 
-#define NETMAP_REQ_IFNAMSIZ	64
-
 /*
  * nr_reqtype: NETMAP_REQ_REGISTER
  * Bind (register) a netmap port to this control device.
  */
 struct nmreq_register {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -519,7 +518,6 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  */
 struct nmreq_port_info_get {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* netmap port name */
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -538,7 +536,6 @@ struct nmreq_port_info_get {
  */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* attach the host stack */
@@ -551,7 +548,6 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 /*
@@ -561,7 +557,6 @@ struct nmreq_vale_detach {
 struct nmreq_vale_list {
 	struct nmreq_header nr_hdr;
 	/* Name of the VALE port (valeXXX:YYY) or empty. */
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint16_t	nr_bridge_idx;
 	uint16_t	nr_port_idx;
 };
@@ -572,7 +567,6 @@ struct nmreq_vale_list {
  */
 struct nmreq_port_hdr {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint32_t	nr_hdr_len;
 };
 
@@ -582,7 +576,6 @@ struct nmreq_port_hdr {
  */
 struct nmreq_vale_newif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -596,7 +589,6 @@ struct nmreq_vale_newif {
  */
 struct nmreq_vale_delif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 /*
@@ -605,7 +597,11 @@ struct nmreq_vale_delif {
  */
 struct nmreq_vale_polling {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+	uint32_t	nr_mode;
+#define NETMAP_POLLING_MODE_SINGLE_CPU 1
+#define NETMAP_POLLING_MODE_MULTI_CPU 2
+	uint32_t	nr_first_cpu_id;
+	uint32_t	nr_num_polling_cpus;
 };
 
 /*
@@ -615,9 +611,8 @@ struct nmreq_vale_polling {
  */
 struct nmreq_pools_info_get {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint64_t	nr_memsize;
-	uint64_t	nr_mem_id;
+	uint16_t	nr_mem_id;
 	uint64_t	nr_if_pool_offset;
 	uint32_t	nr_if_pool_objtotal;
 	uint32_t	nr_if_pool_objsize;
@@ -638,7 +633,6 @@ struct nmreq_pools_info_get {
  */
 struct nmreq_vale_ops_register {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 #endif /* _NET_NETMAP_H_ */

From 3c1239d3878d4ae52246a1e1c03cfd13a8dc340b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 10:42:17 +0100
Subject: [PATCH 0359/2207] netmap_virt: remove passthrough commands

They are going to be replaced by an option for NETMAP_REQ_REGISTER.
---
 sys/net/netmap.h      |  6 ------
 sys/net/netmap_virt.h | 21 ---------------------
 2 files changed, 27 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e5d24416c..7b500b129 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -430,12 +430,6 @@ enum {
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
-	/* Enable host-side ptnetmap processing (e.g. start ptnetmap
-	 * kthreads). */
-	NETMAP_REQ_PASSTHROUGH_ENABLE,
-	/* Disable host-side ptnetmap processing (e.g. stop ptnetmap
-	 * kthreads). */
-	NETMAP_REQ_PASSTHROUGH_DISABLE,
 	/* Program a VALE switch by registering custom callbacks. */
 	NETMAP_REQ_VALE_OPS_REGISTER,
 };
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 5fb529ee4..41098a2cb 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -109,27 +109,6 @@ struct ptnetmap_cfgentry_bhyve {
 	} ioctl_data;
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_PASSTHROUGH_ENABLE
- * Enable host-side ptnetmap processing (e.g. start ptnetmap kthreads).
- */
-struct nmreq_passthrough_enable {
-	struct nmreq_header	nr_hdr;
-	/* Userspace pointer to a variable-size struct containing the
-	 * ptnetmap configuration. */
-	struct pnetmap_cfg	*nr_cfg;
-	/* Length of the configuration struct above (in bytes). */
-	uint32_t		nr_cfg_len;
-};
-
-/*
- * nr_reqtype: NETMAP_REQ_PASSTHROUGH_DISABLE
- * Disalbe host-side ptnetmap processing (e.g. stop ptnetmap kthreads).
- */
-struct nmreq_passthrough_disable {
-	struct nmreq_header	nr_hdr;
-};
-
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
  * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.

From a3fec4fcdad83426c60584a4760227b1a0e560be Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 10:53:32 +0100
Subject: [PATCH 0360/2207] move code for legacy API support to a separate file

---
 LINUX/Kbuild.in                |   2 +-
 WINDOWS/Makefile               |   1 +
 WINDOWS/netmap.vcxproj         |   3 +-
 sys/dev/netmap/netmap.c        | 305 ----------------------------
 sys/dev/netmap/netmap_kern.h   |   2 +
 sys/dev/netmap/netmap_legacy.c | 349 +++++++++++++++++++++++++++++++++
 sys/modules/netmap/Makefile    |   1 +
 7 files changed, 356 insertions(+), 307 deletions(-)
 create mode 100644 sys/dev/netmap/netmap_legacy.c

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index f4a861cc6..2617e7502 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,7 +8,7 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
diff --git a/WINDOWS/Makefile b/WINDOWS/Makefile
index 1de23435e..d4184846f 100644
--- a/WINDOWS/Makefile
+++ b/WINDOWS/Makefile
@@ -81,6 +81,7 @@ SRCS	+= netmap_mem2.c
 SRCS	+= netmap_monitor.c
 SRCS	+= netmap_pipe.c
 SRCS	+= netmap_vale.c
+SRCS	+= netmap_legacy.c
 SRCS	+= netmap_windows.c
 SRCS	+= win_glue.c
 
diff --git a/WINDOWS/netmap.vcxproj b/WINDOWS/netmap.vcxproj
index df5a4f626..86fc61fff 100644
--- a/WINDOWS/netmap.vcxproj
+++ b/WINDOWS/netmap.vcxproj
@@ -202,6 +202,7 @@
     
     
     
+    
     
     
   
@@ -218,4 +219,4 @@
   
   
   
-
\ No newline at end of file
+
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c4f44fe61..ed6b37b95 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2182,311 +2182,6 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
-/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
- * (new API). The new struct is dynamically allocated. */
-static struct nmreq_header *
-nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
-{
-	struct nmreq_header *hdr = NULL;
-
-	/* Sanitize nmr->nr_name by adding the string terminator. */
-	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
-		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
-	}
-
-	switch (ioctl_cmd) {
-	case NIOCREGIF: {
-		switch (nmr->nr_cmd) {
-		case 0: {
-			/* Regular NIOCREGIF operation. */
-			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-			req->nr_offset = nmr->nr_offset;
-			req->nr_memsize = nmr->nr_memsize;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
-			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
-				/* Convert the older nmr->nr_ringid (original
-				 * netmap control API) to nmr->nr_flags. */
-				u_int regmode = NR_REG_DEFAULT;
-				if (req->nr_ringid & NETMAP_SW_RING) {
-					regmode = NR_REG_SW;
-				} else if (req->nr_ringid & NETMAP_HW_RING) {
-					regmode = NR_REG_ONE_NIC;
-				} else {
-					regmode = NR_REG_ALL_NIC;
-				}
-				nmr->nr_flags = regmode |
-					(nmr->nr_flags & (~NR_REG_MASK));
-			}
-			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
-			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
-			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
-				req->nr_flags |= NR_NO_TX_POLL;
-			}
-			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
-				req->nr_flags |= NR_DO_RX_POLL;
-			}
-			req->nr_pipes = nmr->nr_arg1;
-			req->nr_extra_bufs = nmr->nr_arg3;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_ATTACH: {
-			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_DETACH: {
-			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_VNET_HDR:
-		case NETMAP_VNET_HDR_GET: {
-			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
-				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
-			req->nr_hdr_len = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_NEWIF : {
-			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_DELIF: {
-			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_POLLING_ON:
-		case NETMAP_BDG_POLLING_OFF: {
-			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
-				NETMAP_REQ_VALE_POLLING_ENABLE :
-				NETMAP_REQ_VALE_POLLING_DISABLE;
-			switch (nmr->nr_flags & NR_REG_MASK) {
-			default:
-				req->nr_mode = 0; /* invalid */
-				break;
-			case NR_REG_ONE_NIC:
-				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
-				break;
-			case NR_REG_ALL_NIC:
-				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
-				break;
-			}
-			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
-			req->nr_num_polling_cpus = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_POOLS_INFO_GET: {
-			/* We could deny this request similar to ptnetmap requests. */
-			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-			/* Most of the fields are for output (see
-			 * nmreq_to_legacy). */
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_PT_HOST_CREATE:
-		case NETMAP_PT_HOST_DELETE: {
-			D("Netmap passthrough not supported yet");
-			return NULL;
-			break;
-		}
-		}
-		break;
-	}
-	case NIOCGINFO: {
-		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
-			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-			req->nr_bridge_idx = nmr->nr_arg1;
-			req->nr_port_idx = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
-		} else {
-			/* Regular NIOCGINFO. */
-			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-			req->nr_offset = nmr->nr_offset;
-			req->nr_memsize = nmr->nr_memsize;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
-		}
-		break;
-	}
-	}
-
-	KASSERT(hdr != NULL, "Invalid NULL netmap request");
-	hdr->nr_version = NETMAP_API; /* new API */
-	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-
-	return hdr;
-oom:
-	D("Failed to allocate memory for nmreq_xyz struct");
-	return NULL;
-}
-
-/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
- * It also frees the nmreq_xyz struct, as it was allocated by
- * nmreq_from_legacy(). */
-static int
-nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
-{
-	int ret = 0;
-	/* Don't bzero 'nmr', we may need the pointers stored into
-	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
-
-	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
-
-	switch (hdr->nr_reqtype) {
-	case NETMAP_REQ_REGISTER: {
-		struct nmreq_register *req = (struct nmreq_register *)hdr;
-		nmr->nr_offset = req->nr_offset;
-		nmr->nr_memsize = req->nr_memsize;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_ringid = req->nr_ringid;
-		if (req->nr_flags & NR_NO_TX_POLL) {
-			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
-		}
-		if (req->nr_flags & NR_DO_RX_POLL) {
-			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
-		}
-		nmr->nr_flags = req->nr_mode | req->nr_flags;
-		nmr->nr_arg1 = req->nr_pipes;
-		nmr->nr_arg3 = req->nr_extra_bufs;
-		break;
-	}
-	case NETMAP_REQ_PORT_INFO_GET: {
-		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
-		nmr->nr_offset = req->nr_offset;
-		nmr->nr_memsize = req->nr_memsize;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		break;
-	}
-	case NETMAP_REQ_VALE_ATTACH: {
-		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_arg1 = req->nr_flags;
-		break;
-	}
-	case NETMAP_REQ_VALE_DETACH: {
-		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
-		(void)req;
-		break;
-	}
-	case NETMAP_REQ_VALE_LIST: {
-		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
-		nmr->nr_arg1 = req->nr_bridge_idx;
-		nmr->nr_arg2 = req->nr_port_idx;
-		break;
-	}
-	case NETMAP_REQ_PORT_HDR_SET:
-	case NETMAP_REQ_PORT_HDR_GET: {
-		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
-		nmr->nr_arg1 = req->nr_hdr_len;
-		break;
-	}
-	case NETMAP_REQ_VALE_NEWIF: {
-		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		break;
-	}
-	case NETMAP_REQ_VALE_DELIF: {
-		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
-		(void)req;
-		break;
-	}
-	case NETMAP_REQ_VALE_POLLING_ENABLE:
-	case NETMAP_REQ_VALE_POLLING_DISABLE: {
-		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
-		switch (req->nr_mode) {
-		default:
-			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
-			break;
-		case NETMAP_POLLING_MODE_MULTI_CPU:
-			nmr->nr_flags = NR_REG_ONE_NIC;
-			break;
-		case NETMAP_POLLING_MODE_SINGLE_CPU:
-			nmr->nr_flags = NR_REG_ALL_NIC;
-			break;
-		}
-		nmr->nr_ringid = req->nr_first_cpu_id;
-		nmr->nr_arg1 = req->nr_num_polling_cpus;
-		break;
-	}
-	case NETMAP_REQ_POOLS_INFO_GET: {
-		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
-		struct netmap_pools_info pi;
-		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
-		pi.memsize = req->nr_memsize;
-		pi.memid = req->nr_mem_id;
-		pi.if_pool_offset = req->nr_if_pool_offset;
-		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
-		pi.if_pool_objsize = req->nr_if_pool_objsize;
-		pi.ring_pool_offset = req->nr_ring_pool_offset;
-		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
-		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
-		pi.buf_pool_offset = req->nr_buf_pool_offset;
-		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
-		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
-		ret = copyout(&pi, upi, sizeof(pi));
-		if (ret) {
-			D("copyout() failed");
-		}
-		break;
-	}
-	}
-
-	return ret;
-}
-
 static void
 nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
 				 struct nmreq_register *regreq)
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c9acb1f81..fd30d47ba 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1516,6 +1516,8 @@ int netmap_get_memory(struct netmap_priv_d* p);
 void netmap_dtor(void *data);
 
 int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
+struct nmreq_header *nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd);
+int nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr);
 
 /* netmap_adapter creation/destruction */
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
new file mode 100644
index 000000000..594bb1b04
--- /dev/null
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2018 Vincenzo Maffione
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(__FreeBSD__)
+#include  /* prerequisite */
+#include 
+#elif defined(linux)
+#include "bsd_glue.h"
+#elif defined(__APPLE__)
+#warning OSX support is only partial
+#include "osx_glue.h"
+#elif defined (_WIN32)
+#include "win_glue.h"
+#endif
+
+/*
+ * common headers
+ */
+#include 
+#include 
+
+/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
+ * (new API). The new struct is dynamically allocated. */
+struct nmreq_header *
+nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
+{
+	struct nmreq_header *hdr = NULL;
+
+	/* Sanitize nmr->nr_name by adding the string terminator. */
+	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
+		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
+	}
+
+	switch (ioctl_cmd) {
+	case NIOCREGIF: {
+		switch (nmr->nr_cmd) {
+		case 0: {
+			/* Regular NIOCREGIF operation. */
+			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
+				/* Convert the older nmr->nr_ringid (original
+				 * netmap control API) to nmr->nr_flags. */
+				u_int regmode = NR_REG_DEFAULT;
+				if (req->nr_ringid & NETMAP_SW_RING) {
+					regmode = NR_REG_SW;
+				} else if (req->nr_ringid & NETMAP_HW_RING) {
+					regmode = NR_REG_ONE_NIC;
+				} else {
+					regmode = NR_REG_ALL_NIC;
+				}
+				nmr->nr_flags = regmode |
+					(nmr->nr_flags & (~NR_REG_MASK));
+			}
+			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
+			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
+				req->nr_flags |= NR_NO_TX_POLL;
+			}
+			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
+				req->nr_flags |= NR_DO_RX_POLL;
+			}
+			req->nr_pipes = nmr->nr_arg1;
+			req->nr_extra_bufs = nmr->nr_arg3;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_ATTACH: {
+			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DETACH: {
+			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_VNET_HDR:
+		case NETMAP_VNET_HDR_GET: {
+			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
+				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
+			req->nr_hdr_len = nmr->nr_arg1;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_NEWIF : {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DELIF: {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_POLLING_ON:
+		case NETMAP_BDG_POLLING_OFF: {
+			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
+				NETMAP_REQ_VALE_POLLING_ENABLE :
+				NETMAP_REQ_VALE_POLLING_DISABLE;
+			switch (nmr->nr_flags & NR_REG_MASK) {
+			default:
+				req->nr_mode = 0; /* invalid */
+				break;
+			case NR_REG_ONE_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
+				break;
+			case NR_REG_ALL_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+				break;
+			}
+			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
+			req->nr_num_polling_cpus = nmr->nr_arg1;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_POOLS_INFO_GET: {
+			/* We could deny this request similar to ptnetmap requests. */
+			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+			/* Most of the fields are for output (see
+			 * nmreq_to_legacy). */
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_PT_HOST_CREATE:
+		case NETMAP_PT_HOST_DELETE: {
+			D("Netmap passthrough not supported yet");
+			return NULL;
+			break;
+		}
+		}
+		break;
+	}
+	case NIOCGINFO: {
+		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
+			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			req->nr_bridge_idx = nmr->nr_arg1;
+			req->nr_port_idx = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+		} else {
+			/* Regular NIOCGINFO. */
+			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+		}
+		break;
+	}
+	}
+
+	KASSERT(hdr != NULL, "Invalid NULL netmap request");
+	hdr->nr_version = NETMAP_API; /* new API */
+	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
+
+	return hdr;
+oom:
+	D("Failed to allocate memory for nmreq_xyz struct");
+	return NULL;
+}
+
+/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
+ * It also frees the nmreq_xyz struct, as it was allocated by
+ * nmreq_from_legacy(). */
+int
+nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
+{
+	int ret = 0;
+	/* Don't bzero 'nmr', we may need the pointers stored into
+	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
+
+	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+
+	switch (hdr->nr_reqtype) {
+	case NETMAP_REQ_REGISTER: {
+		struct nmreq_register *req = (struct nmreq_register *)hdr;
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_ringid = req->nr_ringid;
+		if (req->nr_flags & NR_NO_TX_POLL) {
+			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
+		}
+		if (req->nr_flags & NR_DO_RX_POLL) {
+			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
+		}
+		nmr->nr_flags = req->nr_mode | req->nr_flags;
+		nmr->nr_arg1 = req->nr_pipes;
+		nmr->nr_arg3 = req->nr_extra_bufs;
+		break;
+	}
+	case NETMAP_REQ_PORT_INFO_GET: {
+		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_ATTACH: {
+		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_arg1 = req->nr_flags;
+		break;
+	}
+	case NETMAP_REQ_VALE_DETACH: {
+		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
+		(void)req;
+		break;
+	}
+	case NETMAP_REQ_VALE_LIST: {
+		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
+		nmr->nr_arg1 = req->nr_bridge_idx;
+		nmr->nr_arg2 = req->nr_port_idx;
+		break;
+	}
+	case NETMAP_REQ_PORT_HDR_SET:
+	case NETMAP_REQ_PORT_HDR_GET: {
+		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
+		nmr->nr_arg1 = req->nr_hdr_len;
+		break;
+	}
+	case NETMAP_REQ_VALE_NEWIF: {
+		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_DELIF: {
+		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
+		(void)req;
+		break;
+	}
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+	case NETMAP_REQ_VALE_POLLING_DISABLE: {
+		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
+		switch (req->nr_mode) {
+		default:
+			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
+			break;
+		case NETMAP_POLLING_MODE_MULTI_CPU:
+			nmr->nr_flags = NR_REG_ONE_NIC;
+			break;
+		case NETMAP_POLLING_MODE_SINGLE_CPU:
+			nmr->nr_flags = NR_REG_ALL_NIC;
+			break;
+		}
+		nmr->nr_ringid = req->nr_first_cpu_id;
+		nmr->nr_arg1 = req->nr_num_polling_cpus;
+		break;
+	}
+	case NETMAP_REQ_POOLS_INFO_GET: {
+		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
+		struct netmap_pools_info pi;
+		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
+		pi.memsize = req->nr_memsize;
+		pi.memid = req->nr_mem_id;
+		pi.if_pool_offset = req->nr_if_pool_offset;
+		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
+		pi.if_pool_objsize = req->nr_if_pool_objsize;
+		pi.ring_pool_offset = req->nr_ring_pool_offset;
+		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
+		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
+		pi.buf_pool_offset = req->nr_buf_pool_offset;
+		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
+		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
+		ret = copyout(&pi, upi, sizeof(pi));
+		if (ret) {
+			D("copyout() failed");
+		}
+		break;
+	}
+	}
+
+	return ret;
+}
+
diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index 978a4858e..a17b21dd3 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -21,6 +21,7 @@ SRCS	+= netmap_offloadings.c
 SRCS	+= netmap_pipe.c
 SRCS	+= netmap_monitor.c
 SRCS	+= netmap_pt.c
+SRCS	+= netmap_legacy.c
 SRCS	+= if_ptnet.c
 SRCS	+= opt_inet.h opt_inet6.h
 

From abd2358d9c80f3e4a44256f4cdd3889f5fcfecb1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 11:05:36 +0100
Subject: [PATCH 0361/2207] move more code to netmap_legacy

---
 sys/dev/netmap/netmap.c        | 62 ++-----------------------
 sys/dev/netmap/netmap_kern.h   |  4 +-
 sys/dev/netmap/netmap_legacy.c | 83 +++++++++++++++++++++++++++++++++-
 3 files changed, 87 insertions(+), 62 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ed6b37b95..dbaa11d71 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2516,25 +2516,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		break;
 	}
 
-	case NIOCGINFO:
-	case NIOCREGIF: {
-		/* Request for the legacy control API. Convert it to a
-		 * NIOCCTRL request. */
-		struct nmreq *nmr = (struct nmreq *) data;
-		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
-		if (hdr == NULL) { /* out of memory */
-			return ENOMEM;
-		}
-		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
-		if (error == 0) {
-			nmreq_to_legacy(hdr, nmr);
-		}
-		nm_os_free(hdr);
-		break;
-	}
-
 	case NIOCTXSYNC:
-	case NIOCRXSYNC:
+	case NIOCRXSYNC: {
 		nifp = priv->np_nifp;
 
 		if (nifp == NULL) {
@@ -2602,49 +2585,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		break;
-
-#ifdef WITH_VALE
-	case NIOCCONFIG: {
-		struct nm_ifreq *nr = (struct nm_ifreq *)data;
-		error = netmap_bdg_config(nr);
-		break;
 	}
-#endif
-#ifdef __FreeBSD__
-	case FIONBIO:
-	case FIOASYNC:
-		ND("FIONBIO/FIOASYNC are no-ops");
-		break;
-
-	case BIOCIMMEDIATE:
-	case BIOCGHDRCMPLT:
-	case BIOCSHDRCMPLT:
-	case BIOCSSEESENT:
-		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
-		break;
-
-	default:	/* allow device-specific ioctls */
-	    {
-		struct nmreq *nmr = (struct nmreq *)data;
-		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
-		if (ifp == NULL) {
-			error = ENXIO;
-		} else {
-			struct socket so;
 
-			bzero(&so, sizeof(so));
-			so.so_vnet = ifp->if_vnet;
-			// so->so_proto not null.
-			error = ifioctl(&so, cmd, data, td);
-			if_rele(ifp);
-		}
+	default: {
+		return netmap_ioctl_legacy(priv, cmd, data, td);
 		break;
-	    }
-
-#else /* linux */
-	default:
-		error = EOPNOTSUPP;
-#endif /* linux */
+	}
 	}
 
 	return (error);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index fd30d47ba..0c62b8592 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1516,8 +1516,8 @@ int netmap_get_memory(struct netmap_priv_d* p);
 void netmap_dtor(void *data);
 
 int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
-struct nmreq_header *nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd);
-int nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr);
+int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+			struct thread *td);
 
 /* netmap_adapter creation/destruction */
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 594bb1b04..80e580adb 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -27,6 +27,16 @@
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 #include 
+#include 	/* defines used in kernel.h */
+#include 	/* FIONBIO */
+#include 
+#include  /* sockaddrs */
+#include 
+#include 
+#include 
+#include 		/* BIOCIMMEDIATE */
+#include 	/* bus_dmamap_* */
+#include 
 #elif defined(linux)
 #include "bsd_glue.h"
 #elif defined(__APPLE__)
@@ -44,7 +54,7 @@
 
 /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
  * (new API). The new struct is dynamically allocated. */
-struct nmreq_header *
+static struct nmreq_header *
 nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 {
 	struct nmreq_header *hdr = NULL;
@@ -223,7 +233,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
  * It also frees the nmreq_xyz struct, as it was allocated by
  * nmreq_from_legacy(). */
-int
+static int
 nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
 	int ret = 0;
@@ -347,3 +357,72 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	return ret;
 }
 
+int
+netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+			struct thread *td)
+{
+	int error = 0;
+
+	switch (cmd) {
+	case NIOCGINFO:
+	case NIOCREGIF: {
+		/* Request for the legacy control API. Convert it to a
+		 * NIOCCTRL request. */
+		struct nmreq *nmr = (struct nmreq *) data;
+		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
+		if (hdr == NULL) { /* out of memory */
+			return ENOMEM;
+		}
+		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
+		if (error == 0) {
+			nmreq_to_legacy(hdr, nmr);
+		}
+		nm_os_free(hdr);
+		break;
+	}
+#ifdef WITH_VALE
+	case NIOCCONFIG: {
+		struct nm_ifreq *nr = (struct nm_ifreq *)data;
+		error = netmap_bdg_config(nr);
+		break;
+	}
+#endif
+#ifdef __FreeBSD__
+	case FIONBIO:
+	case FIOASYNC:
+		ND("FIONBIO/FIOASYNC are no-ops");
+		break;
+
+	case BIOCIMMEDIATE:
+	case BIOCGHDRCMPLT:
+	case BIOCSHDRCMPLT:
+	case BIOCSSEESENT:
+		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
+		break;
+
+	default:	/* allow device-specific ioctls */
+	    {
+		struct nmreq *nmr = (struct nmreq *)data;
+		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
+		if (ifp == NULL) {
+			error = ENXIO;
+		} else {
+			struct socket so;
+
+			bzero(&so, sizeof(so));
+			so.so_vnet = ifp->if_vnet;
+			// so->so_proto not null.
+			error = ifioctl(&so, cmd, data, td);
+			if_rele(ifp);
+		}
+		break;
+	    }
+
+#else /* linux */
+	default:
+		error = EOPNOTSUPP;
+#endif /* linux */
+	}
+
+	return error;
+}

From 7c830ba1a9909fd1b881151f72df42dae1a5802c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 11:39:55 +0100
Subject: [PATCH 0362/2207] linux: ioctl: compute the correct size of NIOCCTRL
 requests

---
 LINUX/netmap_linux.c         | 22 ++++++++++++++++++++--
 sys/dev/netmap/netmap.c      | 32 ++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_kern.h |  1 +
 sys/net/netmap.h             |  7 ++++---
 4 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index ea302e363..d91d973ae 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1065,7 +1065,6 @@ linux_netmap_set_channels(struct net_device *dev,
 }
 #endif
 
-
 #ifndef NETMAP_LINUX_HAVE_UNLOCKED_IOCTL
 #define LIN_IOCTL_NAME	.ioctl
 static int
@@ -1081,6 +1080,10 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 	union {
 		struct nm_ifreq ifr;
 		struct nmreq nmr;
+		/* It must follow the largest among the nmreq_xyz structs,
+		 * so that there is enough space for any NIOCCTRL request.
+		 * This is asserted by the BUG_ON() below. */
+		struct nmreq_register req;
 	} arg;
 	size_t argsize = 0;
 
@@ -1091,9 +1094,24 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 	case NIOCCONFIG:
 		argsize = sizeof(arg.ifr);
 		break;
-	default:
+	case NIOCREGIF:
+	case NIOCGINFO:
 		argsize = sizeof(arg.nmr);
 		break;
+	case NIOCCTRL: {
+		/* Look at the value of the nr_reqtype field to know
+		 * how much we need to copy from/to userspace. */
+		size_t peeksize = sizeof(arg.req.nr_hdr.nr_version) +
+				sizeof(arg.req.nr_hdr.nr_reqtype);
+		if (copy_from_user(&arg, (void *)data, peeksize) != 0)
+			return -EFAULT;
+		argsize = nmreq_size_by_type(arg.req.nr_hdr.nr_reqtype);
+		BUG_ON(argsize > sizeof(arg));
+		if (argsize == 0) {
+			return -EINVAL;
+		}
+		break;
+	}
 	}
 	if (argsize) {
 		if (!data)
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index dbaa11d71..703c260f3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2596,6 +2596,38 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	return (error);
 }
 
+size_t
+nmreq_size_by_type(uint16_t nr_reqtype)
+{
+	switch (nr_reqtype) {
+	case NETMAP_REQ_REGISTER:
+		return sizeof(struct nmreq_register);
+	case NETMAP_REQ_PORT_INFO_GET:
+		return sizeof(struct nmreq_port_info_get);
+	case NETMAP_REQ_VALE_ATTACH:
+		return sizeof(struct nmreq_vale_attach);
+	case NETMAP_REQ_VALE_DETACH:
+		return sizeof(struct nmreq_vale_detach);
+	case NETMAP_REQ_VALE_LIST:
+		return sizeof(struct nmreq_vale_list);
+	case NETMAP_REQ_PORT_HDR_SET:
+	case NETMAP_REQ_PORT_HDR_GET:
+		return sizeof(struct nmreq_port_hdr);
+	case NETMAP_REQ_VALE_NEWIF:
+		return sizeof(struct nmreq_vale_newif);
+	case NETMAP_REQ_VALE_DELIF:
+		return sizeof(struct nmreq_vale_delif);
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+	case NETMAP_REQ_VALE_POLLING_DISABLE:
+		return sizeof(struct nmreq_vale_polling);
+	case NETMAP_REQ_POOLS_INFO_GET:
+		return sizeof(struct nmreq_pools_info_get);
+	case NETMAP_REQ_VALE_OPS_REGISTER:
+		return sizeof(struct nmreq_vale_ops_register);
+	}
+	return 0;
+}
+
 
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0c62b8592..0ad7205a2 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1518,6 +1518,7 @@ void netmap_dtor(void *data);
 int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
 int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			struct thread *td);
+size_t nmreq_size_by_type(uint16_t nr_reqtype);
 
 /* netmap_adapter creation/destruction */
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 7b500b129..857dd23fa 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -396,7 +396,8 @@ struct nmreq_option {
 	uint16_t		nro_reqtype;
 };
 
-/* Header common to all requests. */
+/* Header common to all requests. Do not reorder these fields, as we need
+ * the second one (nr_reqtype) to know how much to copy from/to userspace. */
 struct nmreq_header {
 	uint16_t		nr_version;	/* API version */
 	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
@@ -498,8 +499,8 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * Demultiplexing is done using the nr_hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
- * specifying the largest among the nmreq_xyz structs. */
-#define NIOCCTRL	_IOWR('i', 151, struct nmreq_register)
+ * specifying only nmreq_header, and copyin the remainder. */
+#define NIOCCTRL	_IOWR('i', 151, struct nmreq_header)
 
 /* The ioctl commands to sync TX/RX netmap rings. */
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */

From de994afb59039ea435fbd6a3529ca1808af159b5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:05:01 +0100
Subject: [PATCH 0363/2207] nm_pkt_copy: fix compilation warning

---
 sys/net/netmap_user.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 5074b0b60..5c4b27f27 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -279,7 +279,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024)) {
+	if (unlikely(l >= 1024 || (l % 64))) {
 		memcpy(dst, src, l);
 		return;
 	}

From 067f56ea0ceff804930df83f28b226151366028d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:23:21 +0100
Subject: [PATCH 0364/2207] utils: introduce ctrl-api-test

---
 utils/GNUmakefile     |  2 +-
 utils/ctrl-api-test.c | 78 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+), 1 deletion(-)
 create mode 100644 utils/ctrl-api-test.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 8659b0bf8..d98857326 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,6 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm producer
+PROGS	= test_select testmmap test_nm producer ctrl-api-test
 X86PROGS = testlock testcsum
 LIBNETMAP =
 
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
new file mode 100644
index 000000000..650ecbe1f
--- /dev/null
+++ b/utils/ctrl-api-test.c
@@ -0,0 +1,78 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+int
+port_info_get(int fd, const char *ifname)
+{
+	struct nmreq_port_info_get req;
+	int ret;
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL)");
+	}
+	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_tx_slots %u\n", req.nr_tx_slots);
+	printf("nr_rx_slots %u\n", req.nr_rx_slots);
+	printf("nr_tx_rings %u\n", req.nr_tx_rings);
+	printf("nr_rx_rings %u\n", req.nr_rx_rings);
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+
+	return ret;
+}
+
+static void
+usage(const char *prog)
+{
+	printf("%s -i IFNAME\n", prog);
+}
+
+int main(int argc, char **argv)
+{
+	const char *ifname = "ens4";
+	int opt;
+
+	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+		switch (opt) {
+		case 'h':
+			usage(argv[0]);
+			return 0;
+
+		case 'i':
+			ifname = optarg;
+			break;
+
+		default:
+			printf("    Unrecognized option %c\n", opt);
+			usage(argv[0]);
+			return -1;
+		}
+	}
+
+	{
+		int fd;
+		int ret;
+		fd = open("/dev/netmap", O_RDWR);
+		if (fd < 0) {
+			perror("open(/dev/netmap)");
+			return fd;
+		}
+		ret = port_info_get(fd, ifname);
+		return ret;
+	}
+
+	return 0;
+}

From f5891545b62775b26aaa5c66fbddcc86fcfa1bf6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:36:22 +0100
Subject: [PATCH 0365/2207] utils: ctrl-api-test: introduce array of test
 functions

---
 utils/ctrl-api-test.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 650ecbe1f..8118c2ec0 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -9,7 +9,9 @@
 #include 
 #include 
 
-int
+typedef int (*testfunc_t)(int fd, const char *ifname);
+
+static int
 port_info_get(int fd, const char *ifname)
 {
 	struct nmreq_port_info_get req;
@@ -22,6 +24,7 @@ port_info_get(int fd, const char *ifname)
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		return ret;
 	}
 	printf("nr_offset %lu\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
@@ -40,9 +43,13 @@ usage(const char *prog)
 	printf("%s -i IFNAME\n", prog);
 }
 
-int main(int argc, char **argv)
+static testfunc_t tests[] = {port_info_get, NULL};
+
+int
+main(int argc, char **argv)
 {
 	const char *ifname = "ens4";
+	unsigned int i;
 	int opt;
 
 	while ((opt = getopt(argc, argv, "hi:")) != -1) {
@@ -62,7 +69,7 @@ int main(int argc, char **argv)
 		}
 	}
 
-	{
+	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
 		int fd;
 		int ret;
 		fd = open("/dev/netmap", O_RDWR);
@@ -70,7 +77,7 @@ int main(int argc, char **argv)
 			perror("open(/dev/netmap)");
 			return fd;
 		}
-		ret = port_info_get(fd, ifname);
+		ret = tests[i](fd, ifname);
 		return ret;
 	}
 

From eae95510878c3a77778fc8d8206f77ec24340ca0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:55:07 +0100
Subject: [PATCH 0366/2207] utils: ctrl-api-test: add nmreq_register basic test

---
 utils/ctrl-api-test.c | 65 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8118c2ec0..67a606984 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,22 +1,25 @@
-#include 
-#include 
 #include 
-#include 
 #include 
-#include 
-#include 
 #include 
-#include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 typedef int (*testfunc_t)(int fd, const char *ifname);
 
+/* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
 port_info_get(int fd, const char *ifname)
 {
 	struct nmreq_port_info_get req;
 	int ret;
 
+	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ifname);
+
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
@@ -34,7 +37,46 @@ port_info_get(int fd, const char *ifname)
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	return ret;
+	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
+			       req.nr_tx_rings && req.nr_rx_rings &&
+			       req.nr_tx_rings
+		       ? 0
+		       : -1;
+}
+
+/* Single NETMAP_REQ_REGISTER, no use. */
+static int
+port_register(int fd, const char *ifname)
+{
+	struct nmreq_register req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	req.nr_mode	   = NR_REG_NIC_SW;
+	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		return ret;
+	}
+	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_tx_slots %u\n", req.nr_tx_slots);
+	printf("nr_rx_slots %u\n", req.nr_rx_slots);
+	printf("nr_tx_rings %u\n", req.nr_tx_rings);
+	printf("nr_rx_rings %u\n", req.nr_rx_rings);
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+
+	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
+			       req.nr_tx_rings && req.nr_rx_rings &&
+			       req.nr_tx_rings && req.nr_pipes == 0 &&
+			       req.nr_extra_bufs == 0
+		       ? 0
+		       : -1;
 }
 
 static void
@@ -43,7 +85,7 @@ usage(const char *prog)
 	printf("%s -i IFNAME\n", prog);
 }
 
-static testfunc_t tests[] = {port_info_get, NULL};
+static testfunc_t tests[] = {port_info_get, port_register};
 
 int
 main(int argc, char **argv)
@@ -69,7 +111,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
+	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
 		int fd;
 		int ret;
 		fd = open("/dev/netmap", O_RDWR);
@@ -78,7 +120,10 @@ main(int argc, char **argv)
 			return fd;
 		}
 		ret = tests[i](fd, ifname);
-		return ret;
+		if (ret) {
+			printf("Test #%d failed\n", i + 1);
+		}
+		printf("Test #%d successful\n", i + 1);
 	}
 
 	return 0;

From 87b54a821e988184fc552b442aa95dc6d370a708 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 13:06:18 +0100
Subject: [PATCH 0367/2207] vale: nm_bdg_ctl: support optional host rings

---
 sys/dev/netmap/netmap_kern.h |  2 +-
 sys/dev/netmap/netmap_vale.c | 21 +++++++++++++--------
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0ad7205a2..7f973db46 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -789,7 +789,7 @@ struct netmap_adapter {
 	 *      Called with NMG_LOCK held.
 	 */
 	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *);
-	int (*nm_bdg_ctl)(struct netmap_adapter *, int);
+	int (*nm_bdg_ctl)(struct nmreq_header *, struct netmap_adapter *);
 
 	/* adapter used to attach this adapter to a VALE switch (if any) */
 	struct netmap_vp_adapter *na_vp;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 40d66249d..3d15d4e68 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -514,13 +514,14 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 
 /* nm_bdg_ctl callback for VALE ports */
 static int
-netmap_vp_bdg_ctl(struct netmap_adapter *na, int attach)
+netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 	struct nm_bridge *b = vpna->na_bdg;
 
-	if (attach)
+	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		return 0; /* nothing to do */
+	}
 	if (b) {
 		netmap_set_all_rings(na, 0 /* disable */);
 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
@@ -892,7 +893,7 @@ nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 		/* nop for VALE ports. The bwrap needs to put the hwna
 		 * in netmap mode (see netmap_bwrap_bdg_ctl)
 		 */
-		error = na->nm_bdg_ctl(na, 1);
+		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
 		if (error)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
@@ -941,7 +942,7 @@ nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
 		 */
-		error = na->nm_bdg_ctl(na, 0);
+		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
 	}
 
 	netmap_adapter_put(na);
@@ -2702,13 +2703,15 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
  * directed to hwna.
  */
 static int
-netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
+netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 {
 	struct netmap_priv_d *npriv;
 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
 	int error = 0;
 
-	if (attach) {
+	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+		struct nmreq_vale_attach *req =
+			(struct nmreq_vale_attach *)hdr;
 		if (NETMAP_OWNED_BY_ANY(na)) {
 			return EBUSY;
 		}
@@ -2720,7 +2723,9 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, /* TODO no-host-rings*/ NR_REG_NIC_SW, 0, 0);
+		error = netmap_do_regif(npriv, na,
+			(req->nr_flags & NETMAP_BDG_HOST) ? NR_REG_NIC_SW : NR_REG_ALL_NIC,
+			0, 0);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
@@ -2734,8 +2739,8 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 		bna->na_kpriv = NULL;
 		na->na_flags &= ~NAF_BUSY;
 	}
-	return error;
 
+	return error;
 }
 
 /* attach a bridge wrapper to the 'real' device */

From cc390f9251744bbf700c0af4e47370d9e4744208 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 14:59:19 +0100
Subject: [PATCH 0368/2207] utils: ctrl-api-test: fix compilation issue

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 67a606984..f32cdd847 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,8 +1,8 @@
 #include 
 #include 
+#include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 

From 7e9192b7d264d968615d3ab4abe21e0beac7b9c7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 15:15:39 +0100
Subject: [PATCH 0369/2207] utils: ctrl-api-test: introduce TestContext

---
 utils/ctrl-api-test.c | 66 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 50 insertions(+), 16 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index f32cdd847..b2f13a0a1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -9,21 +9,43 @@
 #include 
 #include 
 
-typedef int (*testfunc_t)(int fd, const char *ifname);
+struct TestContext {
+	const char	*ifname;
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	uint16_t	nr_ringid;	/* ring(s) we care about */
+	uint32_t	nr_mode;	/* specify NR_REG_* modes */
+	uint64_t	nr_flags;	/* additional flags (see below) */
+	uint32_t	nr_pipes;	/* number of pipes to create */
+	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
+};
+
+static void
+ctx_reset(struct TestContext *ctx)
+{
+	const char *tmp = ctx->ifname;
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->ifname = tmp;
+}
+
+typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
-port_info_get(int fd, const char *ifname)
+port_info_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_port_info_get req;
 	int ret;
 
-	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ifname);
+	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL)");
@@ -46,18 +68,18 @@ port_info_get(int fd, const char *ifname)
 
 /* Single NETMAP_REQ_REGISTER, no use. */
 static int
-port_register(int fd, const char *ifname)
+port_register(int fd, struct TestContext *ctx)
 {
 	struct nmreq_register req;
 	int ret;
 
-	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ifname);
+	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 	req.nr_mode	   = NR_REG_NIC_SW;
-	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL)");
@@ -71,12 +93,20 @@ port_register(int fd, const char *ifname)
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-			       req.nr_tx_rings && req.nr_rx_rings &&
-			       req.nr_tx_rings && req.nr_pipes == 0 &&
-			       req.nr_extra_bufs == 0
-		       ? 0
-		       : -1;
+	return req.nr_memsize &&
+		((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
+		((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
+		((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
+		((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
+		((!ctx->nr_mem_id && req.nr_mem_id) ||
+			(ctx->nr_mem_id == req.nr_mem_id)) &&
+		(ctx->nr_pipes == req.nr_pipes) &&
+		(ctx->nr_extra_bufs == req.nr_extra_bufs)
+		       ? 0 : -1;
 }
 
 static void
@@ -90,10 +120,13 @@ static testfunc_t tests[] = {port_info_get, port_register};
 int
 main(int argc, char **argv)
 {
-	const char *ifname = "ens4";
+	struct TestContext ctx;
 	unsigned int i;
 	int opt;
 
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.ifname = "ens4";
+
 	while ((opt = getopt(argc, argv, "hi:")) != -1) {
 		switch (opt) {
 		case 'h':
@@ -101,7 +134,7 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'i':
-			ifname = optarg;
+			ctx.ifname = optarg;
 			break;
 
 		default:
@@ -119,7 +152,8 @@ main(int argc, char **argv)
 			perror("open(/dev/netmap)");
 			return fd;
 		}
-		ret = tests[i](fd, ifname);
+		ctx_reset(&ctx);
+		ret = tests[i](fd, &ctx);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 		}

From 09fbcb5ecee3ed8da00a67971a605865ece27c07 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 15:34:28 +0100
Subject: [PATCH 0370/2207] utils: ctrl-api-test: test different values of
 nr_mode

---
 utils/ctrl-api-test.c | 47 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b2f13a0a1..8737f1621 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -73,7 +73,9 @@ port_register(int fd, struct TestContext *ctx)
 	struct nmreq_register req;
 	int ret;
 
-	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
+		"flags=%lx) on '%s'\n", ctx->nr_mode, ctx->nr_ringid,
+		ctx->nr_flags, ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
@@ -92,8 +94,14 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_mode %u\n", req.nr_mode);
+	printf("nr_ringid %u\n", req.nr_ringid);
+	printf("nr_flags %lx\n", req.nr_flags);
 
 	return req.nr_memsize &&
+		(ctx->nr_mode == req.nr_mode) &&
+		(ctx->nr_ringid == req.nr_ringid) &&
+		(ctx->nr_flags == req.nr_flags) &&
 		((!ctx->nr_tx_slots && req.nr_tx_slots) ||
 			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
 		((!ctx->nr_rx_slots && req.nr_rx_slots) ||
@@ -109,13 +117,47 @@ port_register(int fd, struct TestContext *ctx)
 		       ? 0 : -1;
 }
 
+static int
+port_register_hwall_host(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_NIC_SW;
+	return port_register(fd, ctx);
+}
+
+static int
+port_register_host(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_SW;
+	return port_register(fd, ctx);
+}
+
+static int
+port_register_hwall(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	return port_register(fd, ctx);
+}
+
+static int
+port_register_single_ring_couple(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ONE_NIC;
+	ctx->nr_ringid = 0;
+	return port_register(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME\n", prog);
 }
 
-static testfunc_t tests[] = {port_info_get, port_register};
+static testfunc_t tests[] = {
+		port_info_get,
+		port_register_hwall_host,
+		port_register_hwall,
+		port_register_host,
+		port_register_single_ring_couple};
 
 int
 main(int argc, char **argv)
@@ -156,6 +198,7 @@ main(int argc, char **argv)
 		ret = tests[i](fd, &ctx);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
+			return ret;
 		}
 		printf("Test #%d successful\n", i + 1);
 	}

From 79fd38df6bf799dc783192d31486a8fc96f708a8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 16:07:39 +0100
Subject: [PATCH 0371/2207] utils: ctrl-api-test: add tests for VALE_ATTACH and
 VALE_DETACH

---
 sys/net/netmap.h      |  2 +-
 utils/ctrl-api-test.c | 85 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 75 insertions(+), 12 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 857dd23fa..1fcd37b96 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -533,7 +533,7 @@ struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
-#define NETMAP_BDG_HOST		0x1	/* attach the host stack */
+#define NETMAP_BDG_HOST		0x1	/* also  attach the host rings */
 };
 
 /*
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8737f1621..55b96c172 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -11,6 +11,7 @@
 
 struct TestContext {
 	const char	*ifname;
+	const char	*bdgname;
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -26,9 +27,11 @@ struct TestContext {
 static void
 ctx_reset(struct TestContext *ctx)
 {
-	const char *tmp = ctx->ifname;
+	const char *tmp1 = ctx->ifname;
+	const char *tmp2 = ctx->bdgname;
 	memset(ctx, 0, sizeof(*ctx));
-	ctx->ifname = tmp;
+	ctx->ifname = tmp1;
+	ctx->bdgname = tmp2;
 }
 
 typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
@@ -60,10 +63,8 @@ port_info_get(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-			       req.nr_tx_rings && req.nr_rx_rings &&
-			       req.nr_tx_rings
-		       ? 0
-		       : -1;
+		req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings
+		       ? 0 : -1;
 }
 
 /* Single NETMAP_REQ_REGISTER, no use. */
@@ -80,7 +81,16 @@ port_register(int fd, struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	req.nr_mode	   = NR_REG_NIC_SW;
+	req.nr_mem_id	   = ctx->nr_mem_id;
+	req.nr_mode	   = ctx->nr_mode;
+	req.nr_ringid	   = ctx->nr_ringid;
+	req.nr_flags	   = ctx->nr_flags;
+	req.nr_tx_slots	   = ctx->nr_tx_slots;
+	req.nr_rx_slots	   = ctx->nr_rx_slots;
+	req.nr_tx_rings	   = ctx->nr_tx_rings;
+	req.nr_rx_rings	   = ctx->nr_rx_rings;
+	req.nr_pipes	   = ctx->nr_pipes;
+	req.nr_extra_bufs  = ctx->nr_extra_bufs;
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
@@ -94,9 +104,6 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
-	printf("nr_mode %u\n", req.nr_mode);
-	printf("nr_ringid %u\n", req.nr_ringid);
-	printf("nr_flags %lx\n", req.nr_flags);
 
 	return req.nr_memsize &&
 		(ctx->nr_mode == req.nr_mode) &&
@@ -146,6 +153,58 @@ port_register_single_ring_couple(int fd, struct TestContext *ctx)
 	return port_register(fd, ctx);
 }
 
+/* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
+static int
+vale_attach_detach(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_attach req;
+	struct nmreq_vale_detach dreq;
+	char vpname[256];
+	int result = 0;
+	int ret;
+
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
+	req.nr_mem_id = ctx->nr_mem_id;
+	req.nr_flags = ctx->nr_flags;
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
+		return ret;
+	}
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+
+	result = ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
+			(ctx->nr_mem_id == req.nr_mem_id)) &&
+		(ctx->nr_flags == req.nr_flags)
+		       ? 0 : -1;
+
+	memset(&dreq, 0, sizeof(dreq));
+	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
+	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	ret = ioctl(fd, NIOCCTRL, &dreq);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
+		if (result == 0) {
+			result = ret;
+		}
+	}
+
+	return result;
+}
+
+static int
+vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
+{
+	ctx->nr_flags = NETMAP_BDG_HOST;
+	return vale_attach_detach(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -157,7 +216,9 @@ static testfunc_t tests[] = {
 		port_register_hwall_host,
 		port_register_hwall,
 		port_register_host,
-		port_register_single_ring_couple};
+		port_register_single_ring_couple,
+		vale_attach_detach,
+		vale_attach_detach_host_rings};
 
 int
 main(int argc, char **argv)
@@ -168,6 +229,7 @@ main(int argc, char **argv)
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ifname = "ens4";
+	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:")) != -1) {
 		switch (opt) {
@@ -201,6 +263,7 @@ main(int argc, char **argv)
 			return ret;
 		}
 		printf("Test #%d successful\n", i + 1);
+		close(fd);
 	}
 
 	return 0;

From 7684e71c65588fd4aaeda221155079bc7df8d64a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 16:20:50 +0100
Subject: [PATCH 0372/2207] utils: ctrl-api-test: add -j argument

---
 utils/ctrl-api-test.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 55b96c172..33ad1622b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -208,7 +208,7 @@ vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 static void
 usage(const char *prog)
 {
-	printf("%s -i IFNAME\n", prog);
+	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
 static testfunc_t tests[] = {
@@ -225,13 +225,14 @@ main(int argc, char **argv)
 {
 	struct TestContext ctx;
 	unsigned int i;
+	int j = -1;
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ifname = "ens4";
 	ctx.bdgname = "vale1x2";
 
-	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -241,6 +242,10 @@ main(int argc, char **argv)
 			ctx.ifname = optarg;
 			break;
 
+		case 'j':
+			j = atoi(optarg);
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -251,6 +256,9 @@ main(int argc, char **argv)
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
 		int fd;
 		int ret;
+		if (j > 0 && (unsigned)j != i+1) {
+			continue;
+		}
 		fd = open("/dev/netmap", O_RDWR);
 		if (fd < 0) {
 			perror("open(/dev/netmap)");

From 4ce714bfd13fe09e80781f33fc4647c2a731d384 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 16:56:23 +0100
Subject: [PATCH 0373/2207] utils: ctrl-api-test: fix register test on nr_pipes

---
 utils/ctrl-api-test.c | 57 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 51 insertions(+), 6 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 33ad1622b..5bb6f2857 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -22,8 +22,10 @@ struct TestContext {
 	uint64_t	nr_flags;	/* additional flags (see below) */
 	uint32_t	nr_pipes;	/* number of pipes to create */
 	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
+	uint32_t	nr_hdr_len;
 };
 
+#if 0
 static void
 ctx_reset(struct TestContext *ctx)
 {
@@ -33,6 +35,7 @@ ctx_reset(struct TestContext *ctx)
 	ctx->ifname = tmp1;
 	ctx->bdgname = tmp2;
 }
+#endif
 
 typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
 
@@ -104,6 +107,8 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_pipes %u\n", req.nr_pipes);
+	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
 	return req.nr_memsize &&
 		(ctx->nr_mode == req.nr_mode) &&
@@ -119,7 +124,7 @@ port_register(int fd, struct TestContext *ctx)
 			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
 		((!ctx->nr_mem_id && req.nr_mem_id) ||
 			(ctx->nr_mem_id == req.nr_mem_id)) &&
-		(ctx->nr_pipes == req.nr_pipes) &&
+		(!ctx->nr_pipes || (ctx->nr_pipes == req.nr_pipes)) &&
 		(ctx->nr_extra_bufs == req.nr_extra_bufs)
 		       ? 0 : -1;
 }
@@ -164,8 +169,8 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
-	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 
+	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
@@ -184,6 +189,7 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 		(ctx->nr_flags == req.nr_flags)
 		       ? 0 : -1;
 
+	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	memset(&dreq, 0, sizeof(dreq));
 	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
 	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
@@ -205,6 +211,43 @@ vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 	return vale_attach_detach(fd, ctx);
 }
 
+/* NETMAP_REQ_PORT_HDR_SET and NETMAP_REQ_PORT_HDR_GET. */
+static int
+port_hdr_set_and_get(int fd, struct TestContext *ctx)
+{
+	struct nmreq_port_hdr req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	req.nr_hdr_len = ctx->nr_hdr_len;
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
+		return ret;
+	}
+	printf("nr_hdr_len %u\n", req.nr_hdr_len);
+
+	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
+}
+
+static int
+vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
+{
+	int ret;
+	ctx->ifname = "vale:eph0";
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	if ((ret = port_register(fd, ctx))) {
+		return ret;
+	}
+	ctx->nr_hdr_len = 12;
+	return port_hdr_set_and_get(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -218,7 +261,8 @@ static testfunc_t tests[] = {
 		port_register_host,
 		port_register_single_ring_couple,
 		vale_attach_detach,
-		vale_attach_detach_host_rings};
+		vale_attach_detach_host_rings,
+		vale_ephemeral_port_hdr_manipulation};
 
 int
 main(int argc, char **argv)
@@ -229,7 +273,7 @@ main(int argc, char **argv)
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname = "ens4";
+	ctx.ifname = "lo";
 	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
@@ -254,6 +298,7 @@ main(int argc, char **argv)
 	}
 
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+		struct TestContext ctxcopy;
 		int fd;
 		int ret;
 		if (j > 0 && (unsigned)j != i+1) {
@@ -264,8 +309,8 @@ main(int argc, char **argv)
 			perror("open(/dev/netmap)");
 			return fd;
 		}
-		ctx_reset(&ctx);
-		ret = tests[i](fd, &ctx);
+		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
+		ret = tests[i](fd, &ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 			return ret;

From 1ac6dd8d1b66b5f46adb8093a6196f1c8b67b753 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 20:08:44 +0100
Subject: [PATCH 0374/2207] ctrl-api-test: add
 vale_ephemeral_port_hdr_manipulation() test

---
 utils/ctrl-api-test.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5bb6f2857..a37caf1f5 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -211,7 +211,8 @@ vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 	return vale_attach_detach(fd, ctx);
 }
 
-/* NETMAP_REQ_PORT_HDR_SET and NETMAP_REQ_PORT_HDR_GET. */
+/* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
+ * to check that we get the same value. */
 static int
 port_hdr_set_and_get(int fd, struct TestContext *ctx)
 {
@@ -230,6 +231,19 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
 	}
+
+	if (req.nr_hdr_len != ctx->nr_hdr_len) {
+		return -1;
+	}
+
+	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+	req.nr_hdr_len = 0;
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
+		return ret;
+	}
 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
 
 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
@@ -244,8 +258,20 @@ vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 	if ((ret = port_register(fd, ctx))) {
 		return ret;
 	}
+	/* Try to set and get all the acceptable values. */
 	ctx->nr_hdr_len = 12;
-	return port_hdr_set_and_get(fd, ctx);
+	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+		return ret;
+	}
+	ctx->nr_hdr_len = 0;
+	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+		return ret;
+	}
+	ctx->nr_hdr_len = 10;
+	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+		return ret;
+	}
+	return 0;
 }
 
 static void

From 05588450667b7da255629f3ede89a9fd2843fcf3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 23:34:31 +0100
Subject: [PATCH 0375/2207] ctrl-api-test: add test for persistent vale ports

---
 utils/ctrl-api-test.c | 178 +++++++++++++++++++++++++++---------------
 1 file changed, 113 insertions(+), 65 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a37caf1f5..d370b8e4e 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -10,19 +10,19 @@
 #include 
 
 struct TestContext {
-	const char	*ifname;
-	const char	*bdgname;
-	uint32_t	nr_tx_slots;	/* slots in tx rings */
-	uint32_t	nr_rx_slots;	/* slots in rx rings */
-	uint16_t	nr_tx_rings;	/* number of tx rings */
-	uint16_t	nr_rx_rings;	/* number of rx rings */
-	uint16_t	nr_mem_id;	/* id of the memory allocator */
-	uint16_t	nr_ringid;	/* ring(s) we care about */
-	uint32_t	nr_mode;	/* specify NR_REG_* modes */
-	uint64_t	nr_flags;	/* additional flags (see below) */
-	uint32_t	nr_pipes;	/* number of pipes to create */
-	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
-	uint32_t	nr_hdr_len;
+	const char *ifname;
+	const char *bdgname;
+	uint32_t nr_tx_slots;   /* slots in tx rings */
+	uint32_t nr_rx_slots;   /* slots in rx rings */
+	uint16_t nr_tx_rings;   /* number of tx rings */
+	uint16_t nr_rx_rings;   /* number of rx rings */
+	uint16_t nr_mem_id;     /* id of the memory allocator */
+	uint16_t nr_ringid;     /* ring(s) we care about */
+	uint32_t nr_mode;       /* specify NR_REG_* modes */
+	uint64_t nr_flags;      /* additional flags (see below) */
+	uint32_t nr_pipes;      /* number of pipes to create */
+	uint32_t nr_extra_bufs; /* number of requested extra buffers */
+	uint32_t nr_hdr_len;
 };
 
 #if 0
@@ -66,8 +66,10 @@ port_info_get(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-		req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings
-		       ? 0 : -1;
+			       req.nr_tx_rings && req.nr_rx_rings &&
+			       req.nr_tx_rings
+		       ? 0
+		       : -1;
 }
 
 /* Single NETMAP_REQ_REGISTER, no use. */
@@ -78,22 +80,22 @@ port_register(int fd, struct TestContext *ctx)
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
-		"flags=%lx) on '%s'\n", ctx->nr_mode, ctx->nr_ringid,
-		ctx->nr_flags, ctx->ifname);
+	       "flags=%lx) on '%s'\n",
+	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	req.nr_mem_id	   = ctx->nr_mem_id;
+	req.nr_mem_id	 = ctx->nr_mem_id;
 	req.nr_mode	   = ctx->nr_mode;
-	req.nr_ringid	   = ctx->nr_ringid;
-	req.nr_flags	   = ctx->nr_flags;
-	req.nr_tx_slots	   = ctx->nr_tx_slots;
-	req.nr_rx_slots	   = ctx->nr_rx_slots;
-	req.nr_tx_rings	   = ctx->nr_tx_rings;
-	req.nr_rx_rings	   = ctx->nr_rx_rings;
-	req.nr_pipes	   = ctx->nr_pipes;
-	req.nr_extra_bufs  = ctx->nr_extra_bufs;
+	req.nr_ringid	 = ctx->nr_ringid;
+	req.nr_flags	  = ctx->nr_flags;
+	req.nr_tx_slots       = ctx->nr_tx_slots;
+	req.nr_rx_slots       = ctx->nr_rx_slots;
+	req.nr_tx_rings       = ctx->nr_tx_rings;
+	req.nr_rx_rings       = ctx->nr_rx_rings;
+	req.nr_pipes	  = ctx->nr_pipes;
+	req.nr_extra_bufs     = ctx->nr_extra_bufs;
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
@@ -110,23 +112,24 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_pipes %u\n", req.nr_pipes);
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
-	return req.nr_memsize &&
-		(ctx->nr_mode == req.nr_mode) &&
-		(ctx->nr_ringid == req.nr_ringid) &&
-		(ctx->nr_flags == req.nr_flags) &&
-		((!ctx->nr_tx_slots && req.nr_tx_slots) ||
-			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
-		((!ctx->nr_rx_slots && req.nr_rx_slots) ||
-			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
-		((!ctx->nr_tx_rings && req.nr_tx_rings) ||
-			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
-		((!ctx->nr_rx_rings && req.nr_rx_rings) ||
-			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
-		((!ctx->nr_mem_id && req.nr_mem_id) ||
-			(ctx->nr_mem_id == req.nr_mem_id)) &&
-		(!ctx->nr_pipes || (ctx->nr_pipes == req.nr_pipes)) &&
-		(ctx->nr_extra_bufs == req.nr_extra_bufs)
-		       ? 0 : -1;
+	return req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
+			       (ctx->nr_ringid == req.nr_ringid) &&
+			       (ctx->nr_flags == req.nr_flags) &&
+			       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+				(ctx->nr_tx_slots == req.nr_tx_slots)) &&
+			       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+				(ctx->nr_rx_slots == req.nr_rx_slots)) &&
+			       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+				(ctx->nr_tx_rings == req.nr_tx_rings)) &&
+			       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+				(ctx->nr_rx_rings == req.nr_rx_rings)) &&
+			       ((!ctx->nr_mem_id && req.nr_mem_id) ||
+				(ctx->nr_mem_id == req.nr_mem_id)) &&
+			       (!ctx->nr_pipes ||
+				(ctx->nr_pipes == req.nr_pipes)) &&
+			       (ctx->nr_extra_bufs == req.nr_extra_bufs)
+		       ? 0
+		       : -1;
 }
 
 static int
@@ -153,7 +156,7 @@ port_register_hwall(int fd, struct TestContext *ctx)
 static int
 port_register_single_ring_couple(int fd, struct TestContext *ctx)
 {
-	ctx->nr_mode = NR_REG_ONE_NIC;
+	ctx->nr_mode   = NR_REG_ONE_NIC;
 	ctx->nr_ringid = 0;
 	return port_register(fd, ctx);
 }
@@ -176,8 +179,8 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	req.nr_mem_id = ctx->nr_mem_id;
-	req.nr_flags = ctx->nr_flags;
-	ret = ioctl(fd, NIOCCTRL, &req);
+	req.nr_flags  = ctx->nr_flags;
+	ret	   = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -185,15 +188,16 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	result = ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
-			(ctx->nr_mem_id == req.nr_mem_id)) &&
-		(ctx->nr_flags == req.nr_flags)
-		       ? 0 : -1;
+		  (ctx->nr_mem_id == req.nr_mem_id)) &&
+				 (ctx->nr_flags == req.nr_flags)
+			 ? 0
+			 : -1;
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	memset(&dreq, 0, sizeof(dreq));
 	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
 	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	ret = ioctl(fd, NIOCCTRL, &dreq);
+	ret		       = ioctl(fd, NIOCCTRL, &dreq);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		if (result == 0) {
@@ -226,7 +230,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	req.nr_hdr_len = ctx->nr_hdr_len;
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret	    = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -238,8 +242,8 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-	req.nr_hdr_len = 0;
-	ret = ioctl(fd, NIOCCTRL, &req);
+	req.nr_hdr_len	= 0;
+	ret		      = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -253,7 +257,7 @@ static int
 vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 {
 	int ret;
-	ctx->ifname = "vale:eph0";
+	ctx->ifname  = "vale:eph0";
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	if ((ret = port_register(fd, ctx))) {
 		return ret;
@@ -274,21 +278,65 @@ vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 	return 0;
 }
 
+static int
+vale_persistent_port(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_newif req;
+	struct nmreq_vale_delif dreq;
+	int result;
+	int ret;
+
+	ctx->ifname = "per4";
+
+	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	req.nr_mem_id   = ctx->nr_mem_id;
+	req.nr_tx_slots = ctx->nr_tx_slots;
+	req.nr_rx_slots = ctx->nr_rx_slots;
+	req.nr_tx_rings = ctx->nr_tx_rings;
+	req.nr_rx_rings = ctx->nr_rx_rings;
+	ret		= ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
+		return ret;
+	}
+
+	result = vale_attach_detach(fd, ctx);
+
+	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
+	memset(&dreq, 0, sizeof(dreq));
+	memcpy(&dreq.nr_hdr, &req.nr_hdr, sizeof(dreq.nr_hdr));
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+	ret		      = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
+		if (result == 0) {
+			result = ret;
+		}
+	}
+
+	return result;
+}
+
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
-static testfunc_t tests[] = {
-		port_info_get,
-		port_register_hwall_host,
-		port_register_hwall,
-		port_register_host,
-		port_register_single_ring_couple,
-		vale_attach_detach,
-		vale_attach_detach_host_rings,
-		vale_ephemeral_port_hdr_manipulation};
+static testfunc_t tests[] = {port_info_get,
+			     port_register_hwall_host,
+			     port_register_hwall,
+			     port_register_host,
+			     port_register_single_ring_couple,
+			     vale_attach_detach,
+			     vale_attach_detach_host_rings,
+			     vale_ephemeral_port_hdr_manipulation,
+			     vale_persistent_port};
 
 int
 main(int argc, char **argv)
@@ -299,7 +347,7 @@ main(int argc, char **argv)
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname = "lo";
+	ctx.ifname  = "lo";
 	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
@@ -327,7 +375,7 @@ main(int argc, char **argv)
 		struct TestContext ctxcopy;
 		int fd;
 		int ret;
-		if (j > 0 && (unsigned)j != i+1) {
+		if (j > 0 && (unsigned)j != i + 1) {
 			continue;
 		}
 		fd = open("/dev/netmap", O_RDWR);

From bd9aa99b2eb93b1d833413022bcc3eca053ad7e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 10:05:08 +0100
Subject: [PATCH 0376/2207] ctrl-api-test: test for pools_info_get

---
 sys/dev/netmap/netmap.c |  4 ++-
 sys/net/netmap.h        |  5 ++--
 utils/ctrl-api-test.c   | 65 +++++++++++++++++++++++++++++++++++++----
 3 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 703c260f3..9cd937677 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2496,7 +2496,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info_get *req =
 				(struct nmreq_pools_info_get *)hdr;
-			/* Get information from the memory allocator */
+			/* Get information from the memory allocator. This
+			 * netmap device must already be bound to a port.
+			 * Note that hdr->nr_name is ignored. */
 			NMG_LOCK();
 			if (priv->np_na && priv->np_na->nm_mem) {
 				struct netmap_mem_d *nmd = priv->np_na->nm_mem;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 1fcd37b96..531e168b6 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -601,8 +601,9 @@ struct nmreq_vale_polling {
 
 /*
  * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
- * Get info about the pools of a memory allocator (used i.e. by
- * a ptnetmap-enabled hypervisor).
+ * Get info about the pools of the memory allocator of the port bound
+ * to a given netmap control device (used i.e. by a ptnetmap-enabled
+ * hypervisor). The nr_hdr.nr_name field is ignored.
  */
 struct nmreq_pools_info_get {
 	struct nmreq_header nr_hdr;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d370b8e4e..2ba5d1f4a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -54,10 +54,10 @@ port_info_get(int fd, struct TestContext *ctx)
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
-		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
-	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_offset 0x%lx\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
@@ -80,7 +80,7 @@ port_register(int fd, struct TestContext *ctx)
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
-	       "flags=%lx) on '%s'\n",
+	       "flags=0x%lx) on '%s'\n",
 	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
@@ -99,10 +99,10 @@ port_register(int fd, struct TestContext *ctx)
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
-		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
 	}
-	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_offset 0x%lx\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
@@ -305,6 +305,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 		return ret;
 	}
 
+	/* Attach the persistent VALE port to a switch and then detach. */
 	result = vale_attach_detach(fd, ctx);
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
@@ -322,6 +323,57 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	return result;
 }
 
+/* Single NETMAP_REQ_POOLS_INFO_GET. */
+static int
+pools_info_get(int fd, struct TestContext *ctx)
+{
+	struct nmreq_pools_info_get req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
+		return ret;
+	}
+	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_if_pool_offset 0x%lx\n", req.nr_if_pool_offset);
+	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
+	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
+	printf("nr_ring_pool_offset 0x%lx\n", req.nr_if_pool_offset);
+	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
+	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
+	printf("nr_buf_pool_offset 0x%lx\n", req.nr_buf_pool_offset);
+	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
+	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
+
+	return req.nr_memsize && req.nr_if_pool_objtotal &&
+		req.nr_if_pool_objsize && req.nr_ring_pool_objtotal &&
+		req.nr_ring_pool_objsize && req.nr_buf_pool_objtotal &&
+		req.nr_buf_pool_objsize ? 0: -1;
+}
+
+static int
+register_and_pools_info_get(int fd, struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mode = NR_REG_ONE_NIC;
+	ret = port_register(fd, ctx);
+	if (ret) {
+		return ret;
+	}
+	ctx->nr_mem_id = 1;
+
+	return pools_info_get(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -336,7 +388,8 @@ static testfunc_t tests[] = {port_info_get,
 			     vale_attach_detach,
 			     vale_attach_detach_host_rings,
 			     vale_ephemeral_port_hdr_manipulation,
-			     vale_persistent_port};
+			     vale_persistent_port,
+			     register_and_pools_info_get};
 
 int
 main(int argc, char **argv)

From 0615ec2eddf4ec47fb5c2172345b6806e041b606 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 11:10:50 +0100
Subject: [PATCH 0377/2207] utils: ctrl-api-test: fix parsing of -j argument

---
 sys/dev/netmap/netmap_vale.c |  2 +-
 utils/ctrl-api-test.c        | 16 +++++++++++++++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3d15d4e68..b2b4c2e42 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1221,7 +1221,7 @@ nm_bdg_polling(struct nmreq_vale_polling *req)
 
 	NMG_LOCK();
 	error = netmap_get_bdg_na((struct nmreq_header *)req,
-					&na, NULL, 0);
+					&na, NULL, /*create=*/0);
 	if (na && !error) {
 		if (!nm_is_bwrap(na)) {
 			error = EOPNOTSUPP;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 2ba5d1f4a..4ca011bdb 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -364,6 +364,13 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 {
 	int ret;
 
+	ret = pools_info_get(fd, ctx);
+	if (ret == 0) {
+		printf("Failed: POOLS_INFO_GET didn't fail on unbound "
+			"netmap device\n");
+		return -1;
+	}
+
 	ctx->nr_mode = NR_REG_ONE_NIC;
 	ret = port_register(fd, ctx);
 	if (ret) {
@@ -424,11 +431,18 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (j >= 0) {
+		j--; /* one-based --> zero-based */
+		if (j >= (int)(sizeof(tests) / sizeof(tests[0]))) {
+			printf("Error: Test not in range\n");
+			return -1;
+		}
+	}
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
 		struct TestContext ctxcopy;
 		int fd;
 		int ret;
-		if (j > 0 && (unsigned)j != i + 1) {
+		if (j >= 0 && (unsigned)j != i) {
 			continue;
 		}
 		fd = open("/dev/netmap", O_RDWR);

From 1362dbd62e32509f0a8eb989de70d50fea93d030 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 11:43:51 +0100
Subject: [PATCH 0378/2207] utils: ctrl-api-test: add test for POLLING_ENABLE
 and POLLING_DISABLE

---
 sys/net/netmap.h      |   4 +-
 utils/ctrl-api-test.c | 120 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 531e168b6..439fe3ff5 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -425,9 +425,9 @@ enum {
 	NETMAP_REQ_VALE_NEWIF,
 	/* Delete a persistent VALE port. */
 	NETMAP_REQ_VALE_DELIF,
-	/* Enable polling kthread on a VALE port. */
+	/* Enable polling kernel thread(s) on an attached VALE port. */
 	NETMAP_REQ_VALE_POLLING_ENABLE,
-	/* Disable polling kthread on a VALE port. */
+	/* Disable polling kernel thread(s) on an attached VALE port. */
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 4ca011bdb..e51ab2e82 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -22,7 +22,11 @@ struct TestContext {
 	uint64_t nr_flags;      /* additional flags (see below) */
 	uint32_t nr_pipes;      /* number of pipes to create */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
-	uint32_t nr_hdr_len;
+
+	uint32_t nr_hdr_len;	/* for PORT_HDR_SET and PORT_HDR_GET */
+
+	uint32_t nr_first_cpu_id;	/* vale polling */
+	uint32_t nr_num_polling_cpus;	/* vale polling */
 };
 
 #if 0
@@ -161,14 +165,12 @@ port_register_single_ring_couple(int fd, struct TestContext *ctx)
 	return port_register(fd, ctx);
 }
 
-/* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
+/* NETMAP_REQ_VALE_ATTACH */
 static int
-vale_attach_detach(int fd, struct TestContext *ctx)
+vale_attach(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
-	struct nmreq_vale_detach dreq;
 	char vpname[256];
-	int result = 0;
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
@@ -187,25 +189,47 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	}
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	result = ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
+	return ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
 		  (ctx->nr_mem_id == req.nr_mem_id)) &&
 				 (ctx->nr_flags == req.nr_flags)
 			 ? 0
 			 : -1;
+}
+
+/* NETMAP_REQ_VALE_DETACH */
+static int
+vale_detach(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_detach req;
+	char vpname[256];
+	int ret;
+
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
-	memset(&dreq, 0, sizeof(dreq));
-	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
-	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	ret		       = ioctl(fd, NIOCCTRL, &dreq);
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
+	ret		       = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
-		if (result == 0) {
-			result = ret;
-		}
+		return ret;
 	}
 
-	return result;
+	return 0;
+}
+
+/* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
+static int
+vale_attach_detach(int fd, struct TestContext *ctx)
+{
+	int ret;
+	if ((ret = vale_attach(fd, ctx))) {
+		return ret;
+	}
+
+	return vale_detach(fd, ctx);
 }
 
 static int
@@ -381,6 +405,71 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	return pools_info_get(fd, ctx);
 }
 
+/* NETMAP_REQ_VALE_POLLING_ENABLE */
+static int
+vale_polling_enable(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_polling req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+	req.nr_mode = ctx->nr_mode;
+	req.nr_first_cpu_id = ctx->nr_first_cpu_id;
+	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
+		return ret;
+	}
+
+	return (req.nr_mode == ctx->nr_mode &&
+		req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
+		req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
+			? 0 : -1;
+}
+
+/* NETMAP_REQ_VALE_POLLING_DISABLE */
+static int
+vale_polling_disable(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_polling req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int
+vale_polling_enable_disable(int fd, struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+	ctx->nr_num_polling_cpus = 1;
+	ctx->nr_first_cpu_id = 0;
+	if ((ret = vale_polling_enable(fd, ctx))) {
+		return ret;
+	}
+
+	return vale_polling_disable(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -396,7 +485,8 @@ static testfunc_t tests[] = {port_info_get,
 			     vale_attach_detach_host_rings,
 			     vale_ephemeral_port_hdr_manipulation,
 			     vale_persistent_port,
-			     register_and_pools_info_get};
+			     register_and_pools_info_get,
+			     vale_polling_enable_disable};
 
 int
 main(int argc, char **argv)

From 2a121552d886a0d1897e908024e25337c77fe78c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 11:48:43 +0100
Subject: [PATCH 0379/2207] ioctl: let polling enable fail on non-vale ports

---
 sys/dev/netmap/netmap_vale.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index b2b4c2e42..2034c53b6 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1235,6 +1235,9 @@ nm_bdg_polling(struct nmreq_vale_polling *req)
 				netmap_adapter_put(na);
 		}
 		netmap_adapter_put(na);
+	} else if (!na && !error) {
+		/* Not VALE port. */
+		error = EINVAL;
 	}
 	NMG_UNLOCK();
 

From abd634d6305cca90a1b28c9d07c4406ea90add8a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 12:09:27 +0100
Subject: [PATCH 0380/2207] utils: ctrl-api-test: vale polling on attached vale
 port

---
 utils/ctrl-api-test.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index e51ab2e82..d6f51c07a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -410,9 +410,11 @@ static int
 vale_polling_enable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	char vpname[256];
 	int ret;
 
-	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
@@ -420,7 +422,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 	req.nr_mode = ctx->nr_mode;
 	req.nr_first_cpu_id = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
@@ -438,14 +440,16 @@ static int
 vale_polling_disable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	char vpname[256];
 	int ret;
 
-	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
@@ -458,16 +462,26 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 static int
 vale_polling_enable_disable(int fd, struct TestContext *ctx)
 {
-	int ret;
+	int ret = 0;
+
+	if ((ret = vale_attach(fd, ctx))) {
+		return ret;
+	}
 
 	ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
 	ctx->nr_num_polling_cpus = 1;
 	ctx->nr_first_cpu_id = 0;
 	if ((ret = vale_polling_enable(fd, ctx))) {
+		vale_detach(fd, ctx);
 		return ret;
 	}
 
-	return vale_polling_disable(fd, ctx);
+	if ((ret = vale_polling_disable(fd, ctx))) {
+		vale_detach(fd, ctx);
+		return ret;
+	}
+
+	return vale_detach(fd, ctx);
 }
 
 static void

From 973f56f67d5724a86be65ce6e9e51a035f4eb063 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 12:19:33 +0100
Subject: [PATCH 0381/2207] nm_os_kctx_create: remove ptnetmap-specific cfgtype
 parameter

This was causing VALE_POLLING_ENABLE commands to fail.
---
 LINUX/netmap_linux.c            |  8 +-------
 WINDOWS/netmap_windows.c        |  3 +--
 sys/dev/netmap/netmap_freebsd.c |  8 +-------
 sys/dev/netmap/netmap_kern.h    |  1 -
 sys/dev/netmap/netmap_pt.c      | 13 ++++++++++++-
 sys/dev/netmap/netmap_vale.c    |  2 +-
 6 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d91d973ae..a0995899d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1583,17 +1583,11 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 }
 
 struct nm_kctx *
-nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
-		     void *opaque)
+nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	struct nm_kctx *nmk = NULL;
 	int error;
 
-	if (cfgtype != PTNETMAP_CFGTYPE_QEMU) {
-		D("Unsupported cfgtype %u", cfgtype);
-		return NULL;
-	}
-
 	if (!cfg->use_kthread && cfg->notify_fn == NULL) {
 		D("Error: botify function missing with use_htead == 0");
 		return NULL;
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index ee757272b..97b84847c 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -1040,8 +1040,7 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 }
 
 struct nm_kctx *
-nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
-		     void *opaque)
+nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	// TODO
 	return NULL;
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 4cf7f3e14..baf6e78c9 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1131,16 +1131,10 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 }
 
 struct nm_kctx *
-nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
-		     void *opaque)
+nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	struct nm_kctx *nmk = NULL;
 
-	if (cfgtype != PTNETMAP_CFGTYPE_BHYVE) {
-		D("Unsupported cfgtype %u", cfgtype);
-		return NULL;
-	}
-
 	nmk = malloc(sizeof(*nmk),  M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (!nmk)
 		return NULL;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7f973db46..4e5a155d7 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2104,7 +2104,6 @@ struct nm_kctx_cfg {
 };
 /* kthread configuration */
 struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
-					unsigned int cfgtype,
 					void *opaque);
 int nm_os_kctx_worker_start(struct nm_kctx *);
 void nm_os_kctx_worker_stop(struct nm_kctx *);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index df2553d44..baf1023a7 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -676,8 +676,19 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
 	struct nm_kctx_cfg nmk_cfg;
 	unsigned int num_rings;
 	uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
+	unsigned int expected_cfgtype = 0;
 	int k;
 
+#if defined(__FreeBSD__)
+	expected_cfgtype = PTNETMAP_CFGTYPE_BHYVE;
+#elif defined(linux)
+	expected_cfgtype = PTNETMAP_CFGTYPE_QEMU;
+#endif
+	if (cfg->cfgtype != expected_cfgtype) {
+		D("Unsupported cfgtype %u", cfg->cfgtype);
+		return EINVAL;
+	}
+
 	num_rings = pth_na->up.num_tx_rings +
 		    pth_na->up.num_rx_rings;
 
@@ -695,7 +706,7 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
 		}
 
 		ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
-			cfg->cfgtype, cfg_entries + k * cfg->entry_size);
+				cfg_entries + k * cfg->entry_size);
 		if (ptns->kctxs[k] == NULL) {
 			goto err;
 		}
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 2034c53b6..3f111b42f 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1021,7 +1021,7 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
 
 		kcfg.type = i;
 		kcfg.worker_private = t;
-		t->nmk = nm_os_kctx_create(&kcfg, 0, NULL);
+		t->nmk = nm_os_kctx_create(&kcfg, NULL);
 		if (t->nmk == NULL) {
 			goto cleanup;
 		}

From 99dd0f54cb6467c5ae3f320275cd807c5d26588a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Jan 2018 19:54:08 +0100
Subject: [PATCH 0382/2207] newnmreq: separate request header and body to
 support FreeBSD

---
 LINUX/netmap_linux.c            |  20 +---
 WINDOWS/netmap_windows.c        |   2 +-
 sys/dev/netmap/netmap.c         | 150 ++++++++++++++++++-----------
 sys/dev/netmap/netmap_freebsd.c |   2 +-
 sys/dev/netmap/netmap_kern.h    |  45 +++++----
 sys/dev/netmap/netmap_legacy.c  |  95 ++++++++++--------
 sys/dev/netmap/netmap_monitor.c |  13 ++-
 sys/dev/netmap/netmap_pipe.c    |  13 ++-
 sys/dev/netmap/netmap_pt.c      |   7 +-
 sys/dev/netmap/netmap_vale.c    |  79 ++++++++-------
 sys/net/netmap.h                |  39 +-------
 utils/ctrl-api-test.c           | 164 ++++++++++++++++++--------------
 12 files changed, 336 insertions(+), 293 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a0995899d..3e9978368 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1080,10 +1080,7 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 	union {
 		struct nm_ifreq ifr;
 		struct nmreq nmr;
-		/* It must follow the largest among the nmreq_xyz structs,
-		 * so that there is enough space for any NIOCCTRL request.
-		 * This is asserted by the BUG_ON() below. */
-		struct nmreq_register req;
+		struct nmreq_header hdr;
 	} arg;
 	size_t argsize = 0;
 
@@ -1099,17 +1096,7 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 		argsize = sizeof(arg.nmr);
 		break;
 	case NIOCCTRL: {
-		/* Look at the value of the nr_reqtype field to know
-		 * how much we need to copy from/to userspace. */
-		size_t peeksize = sizeof(arg.req.nr_hdr.nr_version) +
-				sizeof(arg.req.nr_hdr.nr_reqtype);
-		if (copy_from_user(&arg, (void *)data, peeksize) != 0)
-			return -EFAULT;
-		argsize = nmreq_size_by_type(arg.req.nr_hdr.nr_reqtype);
-		BUG_ON(argsize > sizeof(arg));
-		if (argsize == 0) {
-			return -EINVAL;
-		}
+		argsize = sizeof(arg.hdr);
 		break;
 	}
 	}
@@ -1120,7 +1107,8 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 		if (copy_from_user(&arg, (void *)data, argsize) != 0)
 			return -EFAULT;
 	}
-	ret = netmap_ioctl(priv, cmd, (caddr_t)&arg, NULL);
+	ret = netmap_ioctl(priv, cmd, (caddr_t)&arg, NULL,
+			   /*nr_body_is_user=*/1);
 	if (data && copy_to_user((void*)data, &arg, argsize) != 0)
 		return -EFAULT;
 	return -ret;
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 97b84847c..9454fbd7e 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -565,7 +565,7 @@ ioctlDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 		}
 
 		ret = netmap_ioctl(priv, irpSp->Parameters.DeviceIoControl.IoControlCode,
-			(caddr_t)&arg, NULL);
+			(caddr_t)&arg, NULL, 1);
 		if (NT_SUCCESS(ret)) {
 			if (data && !NT_SUCCESS(copy_to_user((void*)data, &arg, argsize, Irp))) {
 				DbgPrint("Netmap.sys: ioctl failure/cannot copy data to user");
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9cd937677..b3f45403f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1455,9 +1455,11 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  * a reference to it and return a valid *ifp.
  */
 int
-netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
-	      struct ifnet **ifp, struct netmap_mem_d *nmd, int create)
+netmap_get_na(struct nmreq_header *hdr,
+	      struct netmap_adapter **na, struct ifnet **ifp,
+	      struct netmap_mem_d *nmd, int create)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	int error = 0;
 	struct netmap_adapter *ret = NULL;
 	int nmd_ref = 0;
@@ -1465,6 +1467,10 @@ netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	*na = NULL;     /* default return value */
 	*ifp = NULL;
 
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
 	NMG_LOCK_ASSERT();
 
 	/* if the request contain a memid, try to find the
@@ -1490,23 +1496,22 @@ netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	 */
 
 	/* try to see if this is a ptnetmap port */
-	error = netmap_get_pt_host_na(req, na, nmd, create);
+	error = netmap_get_pt_host_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a monitor port */
-	error = netmap_get_monitor_na(req, na, nmd, create);
+	error = netmap_get_monitor_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a pipe port */
-	error = netmap_get_pipe_na(req, na, nmd, create);
+	error = netmap_get_pipe_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a bridge port */
-	error = netmap_get_bdg_na((struct nmreq_header *)req,
-					na, nmd, create);
+	error = netmap_get_bdg_na(hdr, na, nmd, create);
 	if (error)
 		goto out;
 
@@ -1519,7 +1524,7 @@ netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	 * This may still be a tap, a veth/epair, or even a
 	 * persistent VALE port.
 	 */
-	*ifp = ifunit_ref(req->nr_hdr.nr_name);
+	*ifp = ifunit_ref(hdr->nr_name);
 	if (*ifp == NULL) {
 		error = ENXIO;
 		goto out;
@@ -2182,16 +2187,6 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
-static void
-nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
-				 struct nmreq_register *regreq)
-{
-	bzero(regreq, sizeof(*regreq));
-	memcpy(®req->nr_hdr, hdr, sizeof(regreq->nr_hdr));
-	regreq->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	regreq->nr_hdr.nr_options = NULL;
-}
-
 /*
  * ioctl(2) support for the "netmap" device.
  *
@@ -2206,7 +2201,8 @@ nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
  * Return 0 on success, errno otherwise.
  */
 int
-netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *td)
+netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+		struct thread *td, int nr_body_is_user)
 {
 	struct mbq q;	/* packets from RX hw queues to host stack */
 	struct netmap_adapter *na = NULL;
@@ -2222,6 +2218,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	switch (cmd) {
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
+		size_t nr_body_size = nmreq_size_by_type(hdr->nr_reqtype);
+		/* Original hdr->nr_body to user-space pointer. */
+		char *usr_nr_body = NULL;
+
 		if (hdr->nr_version != NETMAP_API) {
 			D("API mismatch for reqtype %d: got %d need %d",
 				hdr->nr_version,
@@ -2233,13 +2233,38 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 			return EINVAL;
 		}
 
+		if ((nr_body_size && hdr->nr_body == NULL) ||
+			(!nr_body_size && hdr->nr_body != NULL)) {
+			/* Request body expected, but not found; or
+			 * request body found but unexpected. */
+			return EINVAL;
+		}
+
+		if (nr_body_is_user && nr_body_size) {
+			char *ker_nr_body;
+
+			usr_nr_body = hdr->nr_body;
+			/* Make a kernel-space copy of the user-space nr_body.
+			 * It's handy to temporarily replace hdr->nr_body with
+			 * a pointer to the kernel-space nr_body. */
+			ker_nr_body = nm_os_malloc(nr_body_size);
+			if (!ker_nr_body) {
+				return ENOMEM;
+			}
+			if (copyin(usr_nr_body, ker_nr_body, nr_body_size)) {
+				nm_os_free(ker_nr_body);
+				return EFAULT;
+			}
+			hdr->nr_body = ker_nr_body;
+		}
+
 		/* Sanitize hdr->nr_name. */
 		hdr->nr_name[sizeof(hdr->nr_name) - 1] = '\0';
 
 		switch (hdr->nr_reqtype) {
 		case NETMAP_REQ_REGISTER: {
 			struct nmreq_register *req =
-				(struct nmreq_register *)hdr;
+				(struct nmreq_register *)hdr->nr_body;
 			/* Protect access to priv from concurrent requests. */
 			NMG_LOCK();
 			do {
@@ -2259,7 +2284,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 					}
 				}
 				/* find the interface and a reference */
-				error = netmap_get_na(req, &na, &ifp, nmd,
+				error = netmap_get_na(hdr, &na, &ifp, nmd,
 						      1 /* create */); /* keep reference */
 				if (error)
 					break;
@@ -2328,7 +2353,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 
 		case NETMAP_REQ_PORT_INFO_GET: {
 			struct nmreq_port_info_get *req =
-				(struct nmreq_port_info_get *)hdr;
+				(struct nmreq_port_info_get *)hdr->nr_body;
 
 			NMG_LOCK();
 			do {
@@ -2338,7 +2363,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 					/* Build a nmreq_register out of the nmreq_port_info_get,
 					 * so that we can call netmap_get_na(). */
 					struct nmreq_register regreq;
-					nmreq_register_from_nmreq_header(hdr, ®req);
+					bzero(®req, sizeof(regreq));
 					regreq.nr_tx_slots = req->nr_tx_slots;
 					regreq.nr_rx_slots = req->nr_rx_slots;
 					regreq.nr_tx_rings = req->nr_tx_rings;
@@ -2346,7 +2371,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 					regreq.nr_mem_id = req->nr_mem_id;
 
 					/* get a refcount */
-					error = netmap_get_na(®req, &na, &ifp, NULL, 1 /* create */);
+					hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+					hdr->nr_body = ®req;
+					error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
+					hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; /* reset type */
+					hdr->nr_body = req; /* reset nr_body */
 					if (error) {
 						na = NULL;
 						ifp = NULL;
@@ -2381,33 +2410,27 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		case NETMAP_REQ_VALE_ATTACH: {
-			struct nmreq_vale_attach *req =
-				(struct nmreq_vale_attach *)hdr;
-			error = nm_bdg_ctl_attach(req);
+			error = nm_bdg_ctl_attach(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_DETACH: {
-			struct nmreq_vale_detach *req =
-				(struct nmreq_vale_detach *)hdr;
-			error = nm_bdg_ctl_detach(req);
+			error = nm_bdg_ctl_detach(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_LIST: {
-			struct nmreq_vale_list *req =
-				(struct nmreq_vale_list *)hdr;
-			error = netmap_bdg_list(req);
+			error = netmap_bdg_list(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_PORT_HDR_SET: {
 			struct nmreq_port_hdr *req =
-				(struct nmreq_port_hdr *)hdr;
+				(struct nmreq_port_hdr *)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
-			nmreq_register_from_nmreq_header(hdr, ®req);
+			bzero(®req, sizeof(regreq));
 			/* For now we only support virtio-net headers, and only for
 			 * VALE ports, but this may change in future. Valid lengths
 			 * for the virtio-net header are 0 (no header), 10 and 12. */
@@ -2418,8 +2441,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 				break;
 			}
 			NMG_LOCK();
-			error = netmap_get_bdg_na((struct nmreq_header *)®req,
-							&na, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = ®req;
+			error = netmap_get_bdg_na(hdr, &na, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+			hdr->nr_body = req;
 			if (na && !error) {
 				struct netmap_vp_adapter *vpna =
 					(struct netmap_vp_adapter *)na;
@@ -2439,15 +2465,19 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		case NETMAP_REQ_PORT_HDR_GET: {
 			/* Get vnet-header length for this netmap port */
 			struct nmreq_port_hdr *req =
-				(struct nmreq_port_hdr *)hdr;
+				(struct nmreq_port_hdr *)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
 			struct ifnet *ifp;
-			nmreq_register_from_nmreq_header(hdr, ®req);
 
+			bzero(®req, sizeof(regreq));
 			NMG_LOCK();
-			error = netmap_get_na(®req, &na, &ifp, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = ®req;
+			error = netmap_get_na(hdr, &na, &ifp, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+			hdr->nr_body = req;
 			if (na && !error) {
 				req->nr_hdr_len = na->virt_hdr_len;
 			}
@@ -2458,17 +2488,21 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 
 		case NETMAP_REQ_VALE_NEWIF: {
 			struct nmreq_vale_newif *req =
-				(struct nmreq_vale_newif *)hdr;
+				(struct nmreq_vale_newif *)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_vale_newif,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
-			nmreq_register_from_nmreq_header(hdr, ®req);
+			bzero(®req, sizeof(regreq));
 			regreq.nr_tx_slots = req->nr_tx_slots;
 			regreq.nr_rx_slots = req->nr_rx_slots;
 			regreq.nr_tx_rings = req->nr_tx_rings;
 			regreq.nr_rx_rings = req->nr_rx_rings;
 			regreq.nr_mem_id = req->nr_mem_id;
-			error = netmap_vi_create(®req, 0 /* no autodelete */);
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = ®req;
+			error = netmap_vi_create(hdr, 0 /* no autodelete */);
+			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			hdr->nr_body = req;
                         /* Write back to the original struct. */
 			req->nr_tx_slots = regreq.nr_tx_slots;
 			req->nr_rx_slots = regreq.nr_rx_slots;
@@ -2479,23 +2513,19 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		case NETMAP_REQ_VALE_DELIF: {
-			struct nmreq_vale_delif *req =
-				(struct nmreq_vale_delif *)hdr;
-			error = nm_vi_destroy(req->nr_hdr.nr_name);
+			error = nm_vi_destroy(hdr->nr_name);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_POLLING_ENABLE:
 		case NETMAP_REQ_VALE_POLLING_DISABLE: {
-			struct nmreq_vale_polling *req =
-				(struct nmreq_vale_polling *)hdr;
-			error = nm_bdg_polling(req);
+			error = nm_bdg_polling(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info_get *req =
-				(struct nmreq_pools_info_get *)hdr;
+				(struct nmreq_pools_info_get *)hdr->nr_body;
 			/* Get information from the memory allocator. This
 			 * netmap device must already be bound to a port.
 			 * Note that hdr->nr_name is ignored. */
@@ -2511,10 +2541,22 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		default: {
-			return EINVAL;
+			error = EINVAL;
 			break;
 		}
 		}
+		if (nr_body_is_user && nr_body_size) {
+			KASSERT(usr_nr_body && hdr->nr_body,
+				"nr_body pointers must not be NULL");
+			/* Write back request body to userspace and reset the
+			 * user-space pointer. */
+			if (error == 0 && copyout(hdr->nr_body,
+				usr_nr_body, nr_body_size)) {
+				error = EFAULT;
+			}
+			nm_os_free(hdr->nr_body);
+			hdr->nr_body = usr_nr_body;
+		}
 		break;
 	}
 
@@ -2609,7 +2651,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_ATTACH:
 		return sizeof(struct nmreq_vale_attach);
 	case NETMAP_REQ_VALE_DETACH:
-		return sizeof(struct nmreq_vale_detach);
+		return 0;
 	case NETMAP_REQ_VALE_LIST:
 		return sizeof(struct nmreq_vale_list);
 	case NETMAP_REQ_PORT_HDR_SET:
@@ -2618,14 +2660,14 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_NEWIF:
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
-		return sizeof(struct nmreq_vale_delif);
+		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
 		return sizeof(struct nmreq_pools_info_get);
 	case NETMAP_REQ_VALE_OPS_REGISTER:
-		return sizeof(struct nmreq_vale_ops_register);
+		return 0;
 	}
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index baf6e78c9..2108f3edc 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1403,7 +1403,7 @@ freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
 			error = ENXIO;
 		goto out;
 	}
-	error = netmap_ioctl(priv, cmd, data, td);
+	error = netmap_ioctl(priv, cmd, data, td, /*nr_body_is_user=*/1);
 out:
 	CURVNET_RESTORE();
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4e5a155d7..3a0d7e15b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1012,16 +1012,16 @@ struct netmap_bwrap_adapter {
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
 };
-int nm_bdg_ctl_attach(struct nmreq_vale_attach *req);
-int nm_bdg_ctl_detach(struct nmreq_vale_detach *req);
-int nm_bdg_polling(struct nmreq_vale_polling *req);
+int nm_bdg_ctl_attach(struct nmreq_header *hdr);
+int nm_bdg_ctl_detach(struct nmreq_header *hdr);
+int nm_bdg_polling(struct nmreq_header *hdr);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
-int netmap_vi_create(struct nmreq_register *, int);
+int netmap_vi_create(struct nmreq_header *hdr, int);
 int nm_vi_destroy(const char *name);
-int netmap_bdg_list(struct nmreq_vale_list *req);
+int netmap_bdg_list(struct nmreq_header *hdr);
 
 #else /* !WITH_VALE */
-#define netmap_vi_create(req, a) (EOPNOTSUPP)
+#define netmap_vi_create(hdr, a) (EOPNOTSUPP)
 #endif /* WITH_VALE */
 
 #ifdef WITH_PIPES
@@ -1419,8 +1419,8 @@ int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 void netmap_do_unregif(struct netmap_priv_d *priv);
 
 u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
-int netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
-		  struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
+int netmap_get_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
 void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
@@ -1475,26 +1475,25 @@ int netmap_bdg_config(struct nm_ifreq *nifr);
 /* max number of pipes per device */
 #define NM_MAXPIPES	64	/* XXX this should probably be a sysctl */
 void netmap_pipe_dealloc(struct netmap_adapter *);
-int netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create);
+int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+			struct netmap_mem_d *nmd, int create);
 #else /* !WITH_PIPES */
 #define NM_MAXPIPES	0
 #define netmap_pipe_alloc(_1, _2) 	0
 #define netmap_pipe_dealloc(_1)
-#define netmap_get_pipe_na(nmr, _2, _3, _4)	\
-	({ int role__ = (nmr)->nr_flags & NR_REG_MASK; \
+#define netmap_get_pipe_na(hdr, _2, _3, _4)	\
+	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_flags & NR_REG_MASK; \
 	   (role__ == NR_REG_PIPE_MASTER || 	       \
 	    role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
 #endif
 
 #ifdef WITH_MONITOR
-int netmap_get_monitor_na(struct nmreq_register *req,
-		struct netmap_adapter **na, struct netmap_mem_d *nmd,
-		int create);
+int netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create);
 void netmap_monitor_stop(struct netmap_adapter *na);
 #else
-#define netmap_get_monitor_na(nmr, _2, _3, _4) \
-	((nmr)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
+#define netmap_get_monitor_na(hdr, _2, _3, _4) \
+	(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
 #endif
 
 #ifdef CONFIG_NET_NS
@@ -1515,7 +1514,8 @@ void netmap_fini(void);
 int netmap_get_memory(struct netmap_priv_d* p);
 void netmap_dtor(void *data);
 
-int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
+int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+		struct thread *, int nr_body_is_user);
 int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			struct thread *td);
 size_t nmreq_size_by_type(uint16_t nr_reqtype);
@@ -2131,9 +2131,8 @@ struct netmap_pt_host_adapter {
 };
 
 /* ptnetmap host-side routines */
-int netmap_get_pt_host_na(struct nmreq_register *req,
-		struct netmap_adapter **na, struct netmap_mem_d * nmd,
-		int create);
+int netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+			struct netmap_mem_d * nmd, int create);
 int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
 
 static inline int
@@ -2142,8 +2141,8 @@ nm_ptnetmap_host_on(struct netmap_adapter *na)
 	return na && na->na_flags & NAF_PTNETMAP_HOST;
 }
 #else /* !WITH_PTNETMAP_HOST */
-#define netmap_get_pt_host_na(nmr, _2, _3, _4) \
-	((nmr)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
+#define netmap_get_pt_host_na(hdr, _2, _3, _4) \
+	(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
 #define ptnetmap_ctl(_1, _2, _3)   EINVAL
 #define nm_ptnetmap_host_on(_1)   EINVAL
 #endif /* !WITH_PTNETMAP_HOST */
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 80e580adb..4eacb982d 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -57,13 +57,22 @@
 static struct nmreq_header *
 nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 {
-	struct nmreq_header *hdr = NULL;
+	struct nmreq_header *hdr = nm_os_malloc(sizeof(*hdr));
+
+	if (hdr == NULL) {
+		goto oom;
+	}
 
 	/* Sanitize nmr->nr_name by adding the string terminator. */
 	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
 	}
 
+	hdr->nr_version = NETMAP_API; /* new API */
+	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
+	hdr->nr_options = NULL;
+	hdr->nr_body = NULL;
+
 	switch (ioctl_cmd) {
 	case NIOCREGIF: {
 		switch (nmr->nr_cmd) {
@@ -71,7 +80,8 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -104,59 +114,53 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			}
 			req->nr_pipes = nmr->nr_arg1;
 			req->nr_extra_bufs = nmr->nr_arg3;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_ATTACH: {
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 			req->nr_mem_id = nmr->nr_arg2;
 			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_DETACH: {
-			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			hdr = (struct nmreq_header *)req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
 			break;
 		}
 		case NETMAP_BDG_VNET_HDR:
 		case NETMAP_VNET_HDR_GET: {
 			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
+			hdr->nr_body = req;
+			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
 			req->nr_hdr_len = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_NEWIF : {
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
 			req->nr_tx_rings = nmr->nr_tx_rings;
 			req->nr_rx_rings = nmr->nr_rx_rings;
 			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_DELIF: {
-			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-			hdr = (struct nmreq_header *)req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_DELIF;
 			break;
 		}
 		case NETMAP_BDG_POLLING_ON:
 		case NETMAP_BDG_POLLING_OFF: {
 			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
+			hdr->nr_body = req;
+			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
 			switch (nmr->nr_flags & NR_REG_MASK) {
@@ -172,17 +176,16 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			}
 			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
 			req->nr_num_polling_cpus = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_POOLS_INFO_GET: {
 			/* We could deny this request similar to ptnetmap requests. */
 			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
 			/* Most of the fields are for output (see
 			 * nmreq_to_legacy). */
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_PT_HOST_CREATE:
@@ -198,15 +201,16 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
 		} else {
 			/* Regular NIOCGINFO. */
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -214,19 +218,18 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_tx_rings = nmr->nr_tx_rings;
 			req->nr_rx_rings = nmr->nr_rx_rings;
 			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
 		}
 		break;
 	}
 	}
 
-	KASSERT(hdr != NULL, "Invalid NULL netmap request");
-	hdr->nr_version = NETMAP_API; /* new API */
-	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-
 	return hdr;
 oom:
+	if (hdr) {
+		nm_os_free(hdr);
+	}
 	D("Failed to allocate memory for nmreq_xyz struct");
+
 	return NULL;
 }
 
@@ -244,7 +247,8 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
-		struct nmreq_register *req = (struct nmreq_register *)hdr;
+		struct nmreq_register *req =
+			(struct nmreq_register *)hdr->nr_body;
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -265,7 +269,8 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		break;
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
-		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
+		struct nmreq_port_info_get *req =
+			(struct nmreq_port_info_get *)hdr->nr_body;
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -276,30 +281,32 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		break;
 	}
 	case NETMAP_REQ_VALE_ATTACH: {
-		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
+		struct nmreq_vale_attach *req =
+			(struct nmreq_vale_attach *)hdr->nr_body;
 		nmr->nr_arg2 = req->nr_mem_id;
 		nmr->nr_arg1 = req->nr_flags;
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
-		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
-		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_LIST: {
-		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
+		struct nmreq_vale_list *req =
+			(struct nmreq_vale_list *)hdr->nr_body;
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
 	}
 	case NETMAP_REQ_PORT_HDR_SET:
 	case NETMAP_REQ_PORT_HDR_GET: {
-		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
+		struct nmreq_port_hdr *req =
+			(struct nmreq_port_hdr *)hdr->nr_body;
 		nmr->nr_arg1 = req->nr_hdr_len;
 		break;
 	}
 	case NETMAP_REQ_VALE_NEWIF: {
-		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
+		struct nmreq_vale_newif *req =
+			(struct nmreq_vale_newif *)hdr->nr_body;
 		nmr->nr_tx_slots = req->nr_tx_slots;
 		nmr->nr_rx_slots = req->nr_rx_slots;
 		nmr->nr_tx_rings = req->nr_tx_rings;
@@ -308,13 +315,12 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		break;
 	}
 	case NETMAP_REQ_VALE_DELIF: {
-		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
-		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
-		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
+		struct nmreq_vale_polling *req =
+			(struct nmreq_vale_polling *)hdr->nr_body;
 		switch (req->nr_mode) {
 		default:
 			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
@@ -334,7 +340,8 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
 		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
 		struct netmap_pools_info pi;
-		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
+		struct nmreq_pools_info_get *req =
+			(struct nmreq_pools_info_get *)hdr->nr_body;
 		pi.memsize = req->nr_memsize;
 		pi.memid = req->nr_mem_id;
 		pi.if_pool_offset = req->nr_if_pool_offset;
@@ -373,10 +380,14 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		if (hdr == NULL) { /* out of memory */
 			return ENOMEM;
 		}
-		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
+		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td,
+					/*nr_body_is_user=*/0);
 		if (error == 0) {
 			nmreq_to_legacy(hdr, nmr);
 		}
+		if (hdr->nr_body) {
+			nm_os_free(hdr->nr_body);
+		}
 		nm_os_free(hdr);
 		break;
 	}
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index e6ccfa495..ed25f2f11 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -826,9 +826,10 @@ netmap_monitor_dtor(struct netmap_adapter *na)
 
 /* check if req is a request for a monitor adapter that we can satisfy */
 int
-netmap_get_monitor_na(struct nmreq_register *req, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create)
+netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+			struct netmap_mem_d *nmd, int create)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_monitor_adapter *mna;
@@ -846,16 +847,18 @@ netmap_get_monitor_na(struct nmreq_register *req, struct netmap_adapter **na,
 	}
 	/* this is a request for a monitor adapter */
 
-	ND("flags %x", req->nr_flags);
+	ND("flags %lx", req->nr_flags);
 
-	/* first, try to find the adapter that we want to monitor
+	/* First, try to find the adapter that we want to monitor.
 	 * We use the same req, after we have turned off the monitor flags.
 	 * In this way we can potentially monitor everything netmap understands,
 	 * except other monitors.
 	 */
 	memcpy(&preq, req, sizeof(preq));
 	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
+	hdr->nr_body = &preq;
+	error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
+	hdr->nr_body = req;
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 7c3c624f9..6cd990647 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -527,9 +527,10 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 }
 
 int
-netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
+netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
@@ -547,14 +548,14 @@ netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 
 	/* first, try to find the parent adapter */
 	bzero(&preq, sizeof(preq));
-	memcpy(&preq.nr_hdr.nr_name, req->nr_hdr.nr_name,
-		sizeof(preq.nr_hdr.nr_name));
 	/* pass to parent the requested number of pipes */
 	preq.nr_pipes = req->nr_pipes;
 	for (;;) {
 		int create_error;
 
-		error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
+		hdr->nr_body = &preq;
+		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
+		hdr->nr_body = req;
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -564,7 +565,9 @@ netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 		ND("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
 		NMG_UNLOCK();
-		create_error = netmap_vi_create(&preq, 1 /* autodelete */);
+		hdr->nr_body = &preq;
+		create_error = netmap_vi_create(hdr, 1 /* autodelete */);
+		hdr->nr_body = req;
 		NMG_LOCK();
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index baf1023a7..5b7f0c7a2 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1159,9 +1159,10 @@ nm_pt_host_dtor(struct netmap_adapter *na)
 
 /* check if nmr is a request for a ptnetmap adapter that we can satisfy */
 int
-netmap_get_pt_host_na(struct nmreq_register *req, struct netmap_adapter **na,
+netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
+    struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
     struct nmreq_register preq;
     struct netmap_adapter *parent; /* target adapter */
     struct netmap_pt_host_adapter *pth_na;
@@ -1187,7 +1188,9 @@ netmap_get_pt_host_na(struct nmreq_register *req, struct netmap_adapter **na,
      */
     memcpy(&preq, req, sizeof(preq));
     preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    error = netmap_get_na(&preq, &parent, &ifp, nmd, create);
+    hdr->nr_body = &preq;
+    error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
+    hdr->nr_body = req;
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3f111b42f..452d8eeeb 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -164,7 +164,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
     "Max batch size to be used in the bridge");
 SYSEND;
 
-static int netmap_vp_create(struct nmreq_register *, struct ifnet *,
+static int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
 static int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 static int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
@@ -623,17 +623,22 @@ nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
  * The interface will be attached to a bridge later.
  */
 int
-netmap_vi_create(struct nmreq_register *req, int autodelete)
+netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct ifnet *ifp;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_mem_d *nmd = NULL;
 	int error;
 
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
 	/* don't include VALE prefix */
-	if (!strncmp(req->nr_hdr.nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
+	if (!strncmp(hdr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
 		return EINVAL;
-	ifp = ifunit_ref(req->nr_hdr.nr_name);
+	ifp = ifunit_ref(hdr->nr_name);
 	if (ifp) { /* already exist, cannot create new one */
 		error = EEXIST;
 		NMG_LOCK();
@@ -646,7 +651,7 @@ netmap_vi_create(struct nmreq_register *req, int autodelete)
 		if_rele(ifp);
 		return error;
 	}
-	error = nm_os_vi_persist(req->nr_hdr.nr_name, &ifp);
+	error = nm_os_vi_persist(hdr->nr_name, &ifp);
 	if (error)
 		return error;
 
@@ -659,7 +664,7 @@ netmap_vi_create(struct nmreq_register *req, int autodelete)
 		}
 	}
 	/* netmap_vp_create creates a struct netmap_vp_adapter */
-	error = netmap_vp_create(req, ifp, nmd, &vpna);
+	error = netmap_vp_create(hdr, ifp, nmd, &vpna);
 	if (error) {
 		D("error %d", error);
 		goto err_1;
@@ -774,8 +779,8 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	ifname = nr_name + b->bdg_namelen + 1;
 	ifp = ifunit_ref(ifname);
 	if (!ifp) {
-		/* Create an ephemeral virtual port
-		 * This block contains all the ephemeral-specific logics
+		/* Create an ephemeral virtual port.
+		 * This block contains all the ephemeral-specific logic.
 		 */
 
 		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
@@ -784,8 +789,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = netmap_vp_create((struct nmreq_register *)hdr,
-					NULL, nmd, &vpna);
+		error = netmap_vp_create(hdr, NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -821,7 +825,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 			/* Check if we need to skip the host rings. */
 			struct nmreq_vale_attach *areq =
-				(struct nmreq_vale_attach *)hdr;
+				(struct nmreq_vale_attach *)hdr->nr_body;
 			if ((areq->nr_flags & NETMAP_BDG_HOST) == 0) {
 				hostna = NULL;
 			}
@@ -858,8 +862,10 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 /* Process NETMAP_REQ_VALE_ATTACH. */
 int
-nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
+nm_bdg_ctl_attach(struct nmreq_header *hdr)
 {
+	struct nmreq_vale_attach *req =
+		(struct nmreq_vale_attach *)hdr->nr_body;
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
 	int error;
@@ -874,8 +880,7 @@ nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 		}
 	}
 
-	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
-				nmd, 1 /* create if not exists */);
+	error = netmap_get_bdg_na(hdr, &na, nmd, 1 /* create if not exists */);
 	if (error) /* no device */
 		goto unlock_exit;
 
@@ -893,7 +898,7 @@ nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 		/* nop for VALE ports. The bwrap needs to put the hwna
 		 * in netmap mode (see netmap_bwrap_bdg_ctl)
 		 */
-		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
+		error = na->nm_bdg_ctl(hdr, na);
 		if (error)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
@@ -916,14 +921,13 @@ nm_is_bwrap(struct netmap_adapter *na)
 
 /* Process NETMAP_REQ_VALE_DETACH. */
 int
-nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
+nm_bdg_ctl_detach(struct nmreq_header *hdr)
 {
 	struct netmap_adapter *na;
 	int error;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
-				NULL, 0 /* don't create */);
+	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
 	}
@@ -942,7 +946,7 @@ nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
 		 */
-		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
+		error = na->nm_bdg_ctl(hdr, na);
 	}
 
 	netmap_adapter_put(na);
@@ -1214,18 +1218,19 @@ nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
 }
 
 int
-nm_bdg_polling(struct nmreq_vale_polling *req)
+nm_bdg_polling(struct nmreq_header *hdr)
 {
+	struct nmreq_vale_polling *req =
+		(struct nmreq_vale_polling *)hdr->nr_body;
 	struct netmap_adapter *na = NULL;
 	int error = 0;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na((struct nmreq_header *)req,
-					&na, NULL, /*create=*/0);
+	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0);
 	if (na && !error) {
 		if (!nm_is_bwrap(na)) {
 			error = EOPNOTSUPP;
-		} else if (req->nr_hdr.nr_reqtype == NETMAP_BDG_POLLING_ON) {
+		} else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) {
 			error = nm_bdg_ctl_polling_start(req, na);
 			if (!error)
 				netmap_adapter_get(na);
@@ -1246,9 +1251,11 @@ nm_bdg_polling(struct nmreq_vale_polling *req)
 
 /* Process NETMAP_REQ_VALE_LIST. */
 int
-netmap_bdg_list(struct nmreq_vale_list *req)
+netmap_bdg_list(struct nmreq_header *hdr)
 {
-	int namelen = strlen(req->nr_hdr.nr_name);
+	struct nmreq_vale_list *req =
+		(struct nmreq_vale_list *)hdr->nr_body;
+	int namelen = strlen(hdr->nr_name);
 	struct nm_bridge *b, *bridges;
 	struct netmap_vp_adapter *vpna;
 	int error = 0, i, j;
@@ -1258,12 +1265,12 @@ netmap_bdg_list(struct nmreq_vale_list *req)
 
 	/* this is used to enumerate bridges and ports */
 	if (namelen) { /* look up indexes of bridge and port */
-		if (strncmp(req->nr_hdr.nr_name, NM_BDG_NAME,
+		if (strncmp(hdr->nr_name, NM_BDG_NAME,
 					strlen(NM_BDG_NAME))) {
 			return EINVAL;
 		}
 		NMG_LOCK();
-		b = nm_find_bridge(req->nr_hdr.nr_name, 0 /* don't create */);
+		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
 		if (!b) {
 			NMG_UNLOCK();
 			return ENOENT;
@@ -1281,7 +1288,7 @@ netmap_bdg_list(struct nmreq_vale_list *req)
 			/* the former and the latter identify a
 			 * virtual port and a NIC, respectively
 			 */
-			if (!strcmp(vpna->up.name, req->nr_hdr.nr_name)) {
+			if (!strcmp(vpna->up.name, hdr->nr_name)) {
 				req->nr_port_idx = i; /* port index */
 				break;
 			}
@@ -1305,7 +1312,7 @@ netmap_bdg_list(struct nmreq_vale_list *req)
 				if (b->bdg_ports[j] == NULL)
 					continue;
 				vpna = b->bdg_ports[j];
-				strncpy(req->nr_hdr.nr_name, vpna->up.name,
+				strncpy(hdr->nr_name, vpna->up.name,
 					(size_t)IFNAMSIZ);
 				error = 0;
 				goto out;
@@ -2194,16 +2201,20 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
  * Only persistent VALE ports have a non-null ifp.
  */
 static int
-netmap_vp_create(struct nmreq_register *req, struct ifnet *ifp,
-		struct netmap_mem_d *nmd,
-		struct netmap_vp_adapter **ret)
+netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
+		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	int error = 0;
 	u_int npipes = 0;
 	u_int extrabufs = 0;
 
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
 	vpna = nm_os_malloc(sizeof(*vpna));
 	if (vpna == NULL)
 		return ENOMEM;
@@ -2211,7 +2222,7 @@ netmap_vp_create(struct nmreq_register *req, struct ifnet *ifp,
  	na = &vpna->up;
 
 	na->ifp = ifp;
-	strncpy(na->name, req->nr_hdr.nr_name, sizeof(na->name));
+	strncpy(na->name, hdr->nr_name, sizeof(na->name));
 
 	/* bound checking */
 	na->num_tx_rings = req->nr_tx_rings;
@@ -2714,7 +2725,7 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 
 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		struct nmreq_vale_attach *req =
-			(struct nmreq_vale_attach *)hdr;
+			(struct nmreq_vale_attach *)hdr->nr_body;
 		if (NETMAP_OWNED_BY_ANY(na)) {
 			return EBUSY;
 		}
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 439fe3ff5..fb4569b47 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -404,6 +404,7 @@ struct nmreq_header {
 #define NETMAP_REQ_IFNAMSIZ	64
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	struct nmreq_option	*nr_options;	/* command-specific options */
+	void			*nr_body;	/* ptr to nmreq_xyz struct */
 };
 
 enum {
@@ -446,7 +447,6 @@ enum {
  * Bind (register) a netmap port to this control device.
  */
 struct nmreq_register {
-	struct nmreq_header nr_hdr;
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -499,7 +499,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * Demultiplexing is done using the nr_hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
- * specifying only nmreq_header, and copyin the remainder. */
+ * specifying only nmreq_header, and copyin the rest. */
 #define NIOCCTRL	_IOWR('i', 151, struct nmreq_header)
 
 /* The ioctl commands to sync TX/RX netmap rings. */
@@ -512,7 +512,6 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * slots per ring, id of the memory allocator, etc.
  */
 struct nmreq_port_info_get {
-	struct nmreq_header nr_hdr;
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -530,27 +529,16 @@ struct nmreq_port_info_get {
  * port and the VALE switch are specified through the nr_name argument.
  */
 struct nmreq_vale_attach {
-	struct nmreq_header nr_hdr;
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* also  attach the host rings */
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_VALE_DETACH
- * Detach a netmap port from a VALE switch. Both the name of the netmap
- * port and the VALE switch are specified through the nr_name argument.
- */
-struct nmreq_vale_detach {
-	struct nmreq_header nr_hdr;
-};
-
 /*
  * nr_reqtype: NETMAP_REQ_VALE_LIST
  * List the ports of a VALE switch.
  */
 struct nmreq_vale_list {
-	struct nmreq_header nr_hdr;
 	/* Name of the VALE port (valeXXX:YYY) or empty. */
 	uint16_t	nr_bridge_idx;
 	uint16_t	nr_port_idx;
@@ -561,7 +549,6 @@ struct nmreq_vale_list {
  * Set the port header length.
  */
 struct nmreq_port_hdr {
-	struct nmreq_header nr_hdr;
 	uint32_t	nr_hdr_len;
 };
 
@@ -570,7 +557,6 @@ struct nmreq_port_hdr {
  * Create a new persistent VALE port.
  */
 struct nmreq_vale_newif {
-	struct nmreq_header nr_hdr;
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -578,20 +564,11 @@ struct nmreq_vale_newif {
 	uint16_t	nr_mem_id;	/* id of the memory allocator */
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_VALE_DELIF
- * Delete a persistent VALE port.
- */
-struct nmreq_vale_delif {
-	struct nmreq_header nr_hdr;
-};
-
 /*
  * nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
  * Enable or disable polling kthreads on a VALE port.
  */
 struct nmreq_vale_polling {
-	struct nmreq_header nr_hdr;
 	uint32_t	nr_mode;
 #define NETMAP_POLLING_MODE_SINGLE_CPU 1
 #define NETMAP_POLLING_MODE_MULTI_CPU 2
@@ -606,7 +583,6 @@ struct nmreq_vale_polling {
  * hypervisor). The nr_hdr.nr_name field is ignored.
  */
 struct nmreq_pools_info_get {
-	struct nmreq_header nr_hdr;
 	uint64_t	nr_memsize;
 	uint16_t	nr_mem_id;
 	uint64_t	nr_if_pool_offset;
@@ -620,15 +596,4 @@ struct nmreq_pools_info_get {
 	uint32_t	nr_buf_pool_objsize;
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_VALE_OPS_REGISTER
- * Program a VALE switch by registering custom callbacks (e.g.
- * lookup, config and dtor). This netmap request should not
- * be called from userspace programs, but only by kernel
- * modules.
- */
-struct nmreq_vale_ops_register {
-	struct nmreq_header nr_hdr;
-};
-
 #endif /* _NET_NETMAP_H_ */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d6f51c07a..af43f70b1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -23,10 +23,10 @@ struct TestContext {
 	uint32_t nr_pipes;      /* number of pipes to create */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
 
-	uint32_t nr_hdr_len;	/* for PORT_HDR_SET and PORT_HDR_GET */
+	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
 
-	uint32_t nr_first_cpu_id;	/* vale polling */
-	uint32_t nr_num_polling_cpus;	/* vale polling */
+	uint32_t nr_first_cpu_id;     /* vale polling */
+	uint32_t nr_num_polling_cpus; /* vale polling */
 };
 
 #if 0
@@ -43,20 +43,29 @@ ctx_reset(struct TestContext *ctx)
 
 typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
 
+static void
+nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
+{
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->nr_version = NETMAP_API;
+	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
+}
+
 /* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
 port_info_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_port_info_get req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
@@ -81,27 +90,28 @@ static int
 port_register(int fd, struct TestContext *ctx)
 {
 	struct nmreq_register req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
 	       "flags=0x%lx) on '%s'\n",
 	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	req.nr_mem_id	 = ctx->nr_mem_id;
-	req.nr_mode	   = ctx->nr_mode;
-	req.nr_ringid	 = ctx->nr_ringid;
-	req.nr_flags	  = ctx->nr_flags;
-	req.nr_tx_slots       = ctx->nr_tx_slots;
-	req.nr_rx_slots       = ctx->nr_rx_slots;
-	req.nr_tx_rings       = ctx->nr_tx_rings;
-	req.nr_rx_rings       = ctx->nr_rx_rings;
-	req.nr_pipes	  = ctx->nr_pipes;
-	req.nr_extra_bufs     = ctx->nr_extra_bufs;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	req.nr_mem_id     = ctx->nr_mem_id;
+	req.nr_mode       = ctx->nr_mode;
+	req.nr_ringid     = ctx->nr_ringid;
+	req.nr_flags      = ctx->nr_flags;
+	req.nr_tx_slots   = ctx->nr_tx_slots;
+	req.nr_rx_slots   = ctx->nr_rx_slots;
+	req.nr_tx_rings   = ctx->nr_tx_rings;
+	req.nr_rx_rings   = ctx->nr_rx_rings;
+	req.nr_pipes      = ctx->nr_pipes;
+	req.nr_extra_bufs = ctx->nr_extra_bufs;
+	ret		  = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
@@ -170,19 +180,20 @@ static int
 vale_attach(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	req.nr_mem_id = ctx->nr_mem_id;
 	req.nr_flags  = ctx->nr_flags;
-	ret	   = ioctl(fd, NIOCCTRL, &req);
+	ret	   = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -190,28 +201,26 @@ vale_attach(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
-		  (ctx->nr_mem_id == req.nr_mem_id)) &&
-				 (ctx->nr_flags == req.nr_flags)
-			 ? 0
-			 : -1;
+		(ctx->nr_mem_id == req.nr_mem_id)) &&
+			       (ctx->nr_flags == req.nr_flags)
+		       ? 0
+		       : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
 static int
 vale_detach(int fd, struct TestContext *ctx)
 {
-	struct nmreq_vale_detach req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
-	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
-	ret		       = ioctl(fd, NIOCCTRL, &req);
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		return ret;
@@ -245,16 +254,17 @@ static int
 port_hdr_set_and_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_port_hdr req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	req.nr_hdr_len = ctx->nr_hdr_len;
-	ret	    = ioctl(fd, NIOCCTRL, &req);
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -265,9 +275,9 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	}
 
 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-	req.nr_hdr_len	= 0;
-	ret		      = ioctl(fd, NIOCCTRL, &req);
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+	req.nr_hdr_len = 0;
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -281,6 +291,7 @@ static int
 vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 {
 	int ret;
+
 	ctx->ifname  = "vale:eph0";
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	if ((ret = port_register(fd, ctx))) {
@@ -306,7 +317,7 @@ static int
 vale_persistent_port(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_newif req;
-	struct nmreq_vale_delif dreq;
+	struct nmreq_header hdr;
 	int result;
 	int ret;
 
@@ -314,16 +325,16 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	req.nr_mem_id   = ctx->nr_mem_id;
 	req.nr_tx_slots = ctx->nr_tx_slots;
 	req.nr_rx_slots = ctx->nr_rx_slots;
 	req.nr_tx_rings = ctx->nr_tx_rings;
 	req.nr_rx_rings = ctx->nr_rx_rings;
-	ret		= ioctl(fd, NIOCCTRL, &req);
+	ret		= ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		return ret;
@@ -333,10 +344,9 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	result = vale_attach_detach(fd, ctx);
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
-	memset(&dreq, 0, sizeof(dreq));
-	memcpy(&dreq.nr_hdr, &req.nr_hdr, sizeof(dreq.nr_hdr));
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-	ret		      = ioctl(fd, NIOCCTRL, &req);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+	hdr.nr_body    = NULL;
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		if (result == 0) {
@@ -352,15 +362,16 @@ static int
 pools_info_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_pools_info_get req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
 		return ret;
@@ -378,9 +389,13 @@ pools_info_get(int fd, struct TestContext *ctx)
 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
 
 	return req.nr_memsize && req.nr_if_pool_objtotal &&
-		req.nr_if_pool_objsize && req.nr_ring_pool_objtotal &&
-		req.nr_ring_pool_objsize && req.nr_buf_pool_objtotal &&
-		req.nr_buf_pool_objsize ? 0: -1;
+			       req.nr_if_pool_objsize &&
+			       req.nr_ring_pool_objtotal &&
+			       req.nr_ring_pool_objsize &&
+			       req.nr_buf_pool_objtotal &&
+			       req.nr_buf_pool_objsize
+		       ? 0
+		       : -1;
 }
 
 static int
@@ -391,12 +406,12 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	ret = pools_info_get(fd, ctx);
 	if (ret == 0) {
 		printf("Failed: POOLS_INFO_GET didn't fail on unbound "
-			"netmap device\n");
+		       "netmap device\n");
 		return -1;
 	}
 
 	ctx->nr_mode = NR_REG_ONE_NIC;
-	ret = port_register(fd, ctx);
+	ret	  = port_register(fd, ctx);
 	if (ret) {
 		return ret;
 	}
@@ -410,20 +425,21 @@ static int
 vale_polling_enable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-	req.nr_mode = ctx->nr_mode;
-	req.nr_first_cpu_id = ctx->nr_first_cpu_id;
+	req.nr_mode		= ctx->nr_mode;
+	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret			= ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
 		return ret;
@@ -432,7 +448,8 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 	return (req.nr_mode == ctx->nr_mode &&
 		req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
 		req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
-			? 0 : -1;
+		       ? 0
+		       : -1;
 }
 
 /* NETMAP_REQ_VALE_POLLING_DISABLE */
@@ -440,17 +457,18 @@ static int
 vale_polling_disable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
 		return ret;
@@ -468,9 +486,9 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 		return ret;
 	}
 
-	ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+	ctx->nr_mode		 = NETMAP_POLLING_MODE_SINGLE_CPU;
 	ctx->nr_num_polling_cpus = 1;
-	ctx->nr_first_cpu_id = 0;
+	ctx->nr_first_cpu_id     = 0;
 	if ((ret = vale_polling_enable(fd, ctx))) {
 		vale_detach(fd, ctx);
 		return ret;

From 5294527e950960254a2df62607f94eecd1ca9fac Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 12:00:52 +0100
Subject: [PATCH 0383/2207] pipes: take role from req->nr_mode (was
 req->nr_flags)

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 sys/dev/netmap/netmap_pipe.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 3a0d7e15b..583b670b4 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1482,7 +1482,7 @@ int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 #define netmap_pipe_alloc(_1, _2) 	0
 #define netmap_pipe_dealloc(_1)
 #define netmap_get_pipe_na(hdr, _2, _3, _4)	\
-	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_flags & NR_REG_MASK; \
+	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_mode; \
 	   (role__ == NR_REG_PIPE_MASTER || 	       \
 	    role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
 #endif
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 6cd990647..75d181e29 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -536,10 +536,10 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
 	u_int pipe_id;
-	int role = req->nr_flags;
+	int role = req->nr_mode;
 	int error, retries = 0;
 
-	ND("flags %x", req->nr_flags);
+	ND("flags %x", req->nr_mode);
 
 	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
 		ND("not a pipe");

From 3c3c3393649c8dbbc2a599e1c54780b4e8544baa Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 15:47:33 +0100
Subject: [PATCH 0384/2207] freebsd: netmap_legacy: add missing include
 directive

---
 sys/dev/netmap/netmap_legacy.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 4eacb982d..75f3e19a8 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -30,6 +30,7 @@
 #include 	/* defines used in kernel.h */
 #include 	/* FIONBIO */
 #include 
+#include 	/* struct socket */
 #include  /* sockaddrs */
 #include 
 #include 

From 106f7cc53651dae5246d6f36a3dde2964a24a73f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 16:23:02 +0100
Subject: [PATCH 0385/2207] netmap_ioctl: add missing WITH_VALE guards for
 VALE-related operations

---
 sys/dev/netmap/netmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b3f45403f..96709c0c5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2408,7 +2408,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_UNLOCK();
 			break;
 		}
-
+#ifdef WITH_VALE
 		case NETMAP_REQ_VALE_ATTACH: {
 			error = nm_bdg_ctl_attach(hdr);
 			break;
@@ -2522,7 +2522,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			error = nm_bdg_polling(hdr);
 			break;
 		}
-
+#endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info_get *req =
 				(struct nmreq_pools_info_get *)hdr->nr_body;

From 78fb3c38721194cae6043e0f954703b04bcf94fd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 16:30:03 +0100
Subject: [PATCH 0386/2207] netmap.h: remove REGOPS, as it should not be
 available from userspace

---
 sys/dev/netmap/netmap.c | 2 --
 sys/net/netmap.h        | 2 --
 2 files changed, 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 96709c0c5..143dded73 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2666,8 +2666,6 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
 		return sizeof(struct nmreq_pools_info_get);
-	case NETMAP_REQ_VALE_OPS_REGISTER:
-		return 0;
 	}
 	return 0;
 }
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index fb4569b47..dca2950fd 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -432,8 +432,6 @@ enum {
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
-	/* Program a VALE switch by registering custom callbacks. */
-	NETMAP_REQ_VALE_OPS_REGISTER,
 };
 
 enum {

From 6ddbe08892ae0ea0da6c233267785db44f4cb2f9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 21:20:41 +0100
Subject: [PATCH 0387/2207] nmreq_register: remove nr_pipes argument

---
 sys/dev/netmap/netmap_legacy.c | 3 +--
 sys/dev/netmap/netmap_pipe.c   | 6 ++----
 sys/dev/netmap/netmap_vale.c   | 2 --
 sys/net/netmap.h               | 1 -
 utils/ctrl-api-test.c          | 5 -----
 5 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 75f3e19a8..98e0f1046 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -113,7 +113,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
 				req->nr_flags |= NR_DO_RX_POLL;
 			}
-			req->nr_pipes = nmr->nr_arg1;
+			/* nmr->nr_arg1 (nr_pipes) ignored */
 			req->nr_extra_bufs = nmr->nr_arg3;
 			break;
 		}
@@ -265,7 +265,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
 		}
 		nmr->nr_flags = req->nr_mode | req->nr_flags;
-		nmr->nr_arg1 = req->nr_pipes;
 		nmr->nr_arg3 = req->nr_extra_bufs;
 		break;
 	}
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 75d181e29..3d14991aa 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -531,7 +531,6 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
 	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
-	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
@@ -547,12 +546,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	}
 
 	/* first, try to find the parent adapter */
-	bzero(&preq, sizeof(preq));
-	/* pass to parent the requested number of pipes */
-	preq.nr_pipes = req->nr_pipes;
 	for (;;) {
+		struct nmreq_register preq;
 		int create_error;
 
+		bzero(&preq, sizeof(preq)); /* basic register operation */
 		hdr->nr_body = &preq;
 		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
 		hdr->nr_body = req;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 452d8eeeb..5d40d8177 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2240,9 +2240,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	 * but probably can do with some more.
 	 * So let's use 2 as default (when 0 is supplied)
 	 */
-	npipes = req->nr_pipes;
 	nm_bound_var(&npipes, 2, 1, NM_MAXPIPES, NULL);
-	req->nr_pipes = npipes;	/* write back */
 	/* validate extra bufs */
 	nm_bound_var(&extrabufs, 0, 0,
 			128*NM_BDG_MAXSLOTS, NULL);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index dca2950fd..87e98da19 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -479,7 +479,6 @@ struct nmreq_register {
 #define NR_DO_RX_POLL		0x10000
 #define NR_NO_TX_POLL		0x20000
 
-	uint32_t	nr_pipes;	/* number of pipes to create */
 	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
 };
 
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index af43f70b1..94958c2ab 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -20,7 +20,6 @@ struct TestContext {
 	uint16_t nr_ringid;     /* ring(s) we care about */
 	uint32_t nr_mode;       /* specify NR_REG_* modes */
 	uint64_t nr_flags;      /* additional flags (see below) */
-	uint32_t nr_pipes;      /* number of pipes to create */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
 
 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
@@ -109,7 +108,6 @@ port_register(int fd, struct TestContext *ctx)
 	req.nr_rx_slots   = ctx->nr_rx_slots;
 	req.nr_tx_rings   = ctx->nr_tx_rings;
 	req.nr_rx_rings   = ctx->nr_rx_rings;
-	req.nr_pipes      = ctx->nr_pipes;
 	req.nr_extra_bufs = ctx->nr_extra_bufs;
 	ret		  = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -123,7 +121,6 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
-	printf("nr_pipes %u\n", req.nr_pipes);
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
 	return req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
@@ -139,8 +136,6 @@ port_register(int fd, struct TestContext *ctx)
 				(ctx->nr_rx_rings == req.nr_rx_rings)) &&
 			       ((!ctx->nr_mem_id && req.nr_mem_id) ||
 				(ctx->nr_mem_id == req.nr_mem_id)) &&
-			       (!ctx->nr_pipes ||
-				(ctx->nr_pipes == req.nr_pipes)) &&
 			       (ctx->nr_extra_bufs == req.nr_extra_bufs)
 		       ? 0
 		       : -1;

From 24d37a510fa2604f4f81edef1cb9d31cf6dece96 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 22:23:16 +0100
Subject: [PATCH 0388/2207] vale_attach: use nmreq_register to specify port and
 mode

---
 sys/dev/netmap/netmap_legacy.c | 125 +++++++++++++++++++--------------
 sys/dev/netmap/netmap_vale.c   |  18 +++--
 sys/net/netmap.h               |   6 +-
 sys/net/netmap_legacy.h        |   1 +
 utils/ctrl-api-test.c          |  21 +++---
 5 files changed, 101 insertions(+), 70 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 98e0f1046..f8005c820 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -53,6 +53,43 @@
 #include 
 #include 
 
+static void
+nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
+{
+	req->nr_offset = nmr->nr_offset;
+	req->nr_memsize = nmr->nr_memsize;
+	req->nr_tx_slots = nmr->nr_tx_slots;
+	req->nr_rx_slots = nmr->nr_rx_slots;
+	req->nr_tx_rings = nmr->nr_tx_rings;
+	req->nr_rx_rings = nmr->nr_rx_rings;
+	req->nr_mem_id = nmr->nr_arg2;
+	req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+	if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
+		/* Convert the older nmr->nr_ringid (original
+		 * netmap control API) to nmr->nr_flags. */
+		u_int regmode = NR_REG_DEFAULT;
+		if (req->nr_ringid & NETMAP_SW_RING) {
+			regmode = NR_REG_SW;
+		} else if (req->nr_ringid & NETMAP_HW_RING) {
+			regmode = NR_REG_ONE_NIC;
+		} else {
+			regmode = NR_REG_ALL_NIC;
+		}
+		nmr->nr_flags = regmode |
+			(nmr->nr_flags & (~NR_REG_MASK));
+	}
+	req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+	req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
+	if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
+		req->nr_flags |= NR_NO_TX_POLL;
+	}
+	if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
+		req->nr_flags |= NR_DO_RX_POLL;
+	}
+	/* nmr->nr_arg1 (nr_pipes) ignored */
+	req->nr_extra_bufs = nmr->nr_arg3;
+}
+
 /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
  * (new API). The new struct is dynamically allocated. */
 static struct nmreq_header *
@@ -83,38 +120,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			req->nr_offset = nmr->nr_offset;
-			req->nr_memsize = nmr->nr_memsize;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
-			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
-				/* Convert the older nmr->nr_ringid (original
-				 * netmap control API) to nmr->nr_flags. */
-				u_int regmode = NR_REG_DEFAULT;
-				if (req->nr_ringid & NETMAP_SW_RING) {
-					regmode = NR_REG_SW;
-				} else if (req->nr_ringid & NETMAP_HW_RING) {
-					regmode = NR_REG_ONE_NIC;
-				} else {
-					regmode = NR_REG_ALL_NIC;
-				}
-				nmr->nr_flags = regmode |
-					(nmr->nr_flags & (~NR_REG_MASK));
-			}
-			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
-			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
-			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
-				req->nr_flags |= NR_NO_TX_POLL;
-			}
-			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
-				req->nr_flags |= NR_DO_RX_POLL;
-			}
-			/* nmr->nr_arg1 (nr_pipes) ignored */
-			req->nr_extra_bufs = nmr->nr_arg3;
+			nmreq_register_from_legacy(nmr, req);
 			break;
 		}
 		case NETMAP_BDG_ATTACH: {
@@ -122,8 +128,13 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
+			nmreq_register_from_legacy(nmr, &req->reg);
+			/* Fix nr_mode, starting from nr_arg1. */
+			if (nmr->nr_arg1 & NETMAP_BDG_HOST) {
+				req->reg.nr_mode = NR_REG_NIC_SW;
+			} else {
+				req->reg.nr_mode = NR_REG_ALL_NIC;
+			}
 			break;
 		}
 		case NETMAP_BDG_DETACH: {
@@ -234,6 +245,27 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	return NULL;
 }
 
+static void
+nmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr)
+{
+	nmr->nr_offset = req->nr_offset;
+	nmr->nr_memsize = req->nr_memsize;
+	nmr->nr_tx_slots = req->nr_tx_slots;
+	nmr->nr_rx_slots = req->nr_rx_slots;
+	nmr->nr_tx_rings = req->nr_tx_rings;
+	nmr->nr_rx_rings = req->nr_rx_rings;
+	nmr->nr_arg2 = req->nr_mem_id;
+	nmr->nr_ringid = req->nr_ringid;
+	if (req->nr_flags & NR_NO_TX_POLL) {
+		nmr->nr_ringid |= NETMAP_NO_TX_POLL;
+	}
+	if (req->nr_flags & NR_DO_RX_POLL) {
+		nmr->nr_ringid |= NETMAP_DO_RX_POLL;
+	}
+	nmr->nr_flags = req->nr_mode | req->nr_flags;
+	nmr->nr_arg3 = req->nr_extra_bufs;
+}
+
 /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
  * It also frees the nmreq_xyz struct, as it was allocated by
  * nmreq_from_legacy(). */
@@ -250,22 +282,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req =
 			(struct nmreq_register *)hdr->nr_body;
-		nmr->nr_offset = req->nr_offset;
-		nmr->nr_memsize = req->nr_memsize;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_ringid = req->nr_ringid;
-		if (req->nr_flags & NR_NO_TX_POLL) {
-			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
-		}
-		if (req->nr_flags & NR_DO_RX_POLL) {
-			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
-		}
-		nmr->nr_flags = req->nr_mode | req->nr_flags;
-		nmr->nr_arg3 = req->nr_extra_bufs;
+		nmreq_register_to_legacy(req, nmr);
 		break;
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
@@ -283,8 +300,12 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_VALE_ATTACH: {
 		struct nmreq_vale_attach *req =
 			(struct nmreq_vale_attach *)hdr->nr_body;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_arg1 = req->nr_flags;
+		nmreq_register_to_legacy(&req->reg, nmr);
+		if (req->reg.nr_mode == NR_REG_NIC_SW) {
+			nmr->nr_arg1 = NETMAP_BDG_HOST;
+		} else {
+			nmr->nr_arg1 = 0;
+		}
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 5d40d8177..151fb0b5c 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -826,7 +826,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			/* Check if we need to skip the host rings. */
 			struct nmreq_vale_attach *areq =
 				(struct nmreq_vale_attach *)hdr->nr_body;
-			if ((areq->nr_flags & NETMAP_BDG_HOST) == 0) {
+			if (areq->reg.nr_mode != NR_REG_NIC_SW) {
 				hostna = NULL;
 			}
 		}
@@ -872,8 +872,8 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 
 	NMG_LOCK();
 
-	if (req->nr_mem_id) {
-		nmd = netmap_mem_find(req->nr_mem_id);
+	if (req->reg.nr_mem_id) {
+		nmd = netmap_mem_find(req->reg.nr_mem_id);
 		if (nmd == NULL) {
 			error = EINVAL;
 			goto unlock_exit;
@@ -2724,6 +2724,13 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		struct nmreq_vale_attach *req =
 			(struct nmreq_vale_attach *)hdr->nr_body;
+		if (req->reg.nr_ringid != 0 ||
+			(req->reg.nr_mode != NR_REG_ALL_NIC &&
+				req->reg.nr_mode != NR_REG_NIC_SW)) {
+			/* We only support attaching all the NIC rings
+			 * and/or the host stack. */
+			return EINVAL;
+		}
 		if (NETMAP_OWNED_BY_ANY(na)) {
 			return EBUSY;
 		}
@@ -2735,9 +2742,8 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na,
-			(req->nr_flags & NETMAP_BDG_HOST) ? NR_REG_NIC_SW : NR_REG_ALL_NIC,
-			0, 0);
+		error = netmap_do_regif(npriv, na, req->reg.nr_mode,
+					req->reg.nr_ringid, req->reg.nr_flags);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 87e98da19..0d9ff99b0 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -524,11 +524,11 @@ struct nmreq_port_info_get {
  * nr_reqtype: NETMAP_REQ_VALE_ATTACH
  * Attach a netmap port to a VALE switch. Both the name of the netmap
  * port and the VALE switch are specified through the nr_name argument.
+ * The attach operation could need to register a port, so at least
+ * the same arguments are available.
  */
 struct nmreq_vale_attach {
-	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
-	uint16_t	nr_flags;	/* flags (see below) */
-#define NETMAP_BDG_HOST		0x1	/* also  attach the host rings */
+	struct nmreq_register reg;
 };
 
 /*
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 9b961a05a..617666026 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -186,6 +186,7 @@ struct nmreq {
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
 #define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
+#define NETMAP_BDG_HOST		1	/* nr_arg1 value for NETMAP_BDG_ATTACH */
 
 	uint16_t	nr_arg2;	/* id of the memory allocator */
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 94958c2ab..162caab44 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -186,20 +186,22 @@ vale_attach(int fd, struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_mem_id = ctx->nr_mem_id;
-	req.nr_flags  = ctx->nr_flags;
+	req.reg.nr_mem_id = ctx->nr_mem_id;
+	if (ctx->nr_mode == 0) {
+		ctx->nr_mode = NR_REG_ALL_NIC; /* default */;
+	}
+	req.reg.nr_mode = ctx->nr_mode;
 	ret	   = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
 	}
-	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
 
-	return ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
-		(ctx->nr_mem_id == req.nr_mem_id)) &&
-			       (ctx->nr_flags == req.nr_flags)
-		       ? 0
-		       : -1;
+	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
+		(ctx->nr_mem_id == req.reg.nr_mem_id)) &&
+			       (ctx->nr_flags == req.reg.nr_flags)
+		       ? 0 : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
@@ -229,6 +231,7 @@ static int
 vale_attach_detach(int fd, struct TestContext *ctx)
 {
 	int ret;
+
 	if ((ret = vale_attach(fd, ctx))) {
 		return ret;
 	}
@@ -239,7 +242,7 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 static int
 vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 {
-	ctx->nr_flags = NETMAP_BDG_HOST;
+	ctx->nr_mode = NR_REG_NIC_SW;
 	return vale_attach_detach(fd, ctx);
 }
 

From 083012b480aff06288815e7a20652dc3760117bf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 10:35:45 +0100
Subject: [PATCH 0389/2207] pipes: allow for pipe syntax in
 nmreq_header.nr_name

---
 sys/dev/netmap/netmap.c        |  7 +++
 sys/dev/netmap/netmap_kern.h   | 12 ++---
 sys/dev/netmap/netmap_legacy.c | 41 ++++++++++++++---
 sys/dev/netmap/netmap_pipe.c   | 81 ++++++++++++++++++++++------------
 sys/net/netmap.h               |  4 +-
 5 files changed, 102 insertions(+), 43 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 143dded73..8f42fe092 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1471,6 +1471,13 @@ netmap_get_na(struct nmreq_header *hdr,
 		return EINVAL;
 	}
 
+	if (req->nr_mode == NR_REG_PIPE_MASTER ||
+			req->nr_mode == NR_REG_PIPE_SLAVE) {
+		/* Do not accept deprecated pipe modes. */
+		D("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
+		return EINVAL;
+	}
+
 	NMG_LOCK_ASSERT();
 
 	/* if the request contain a memid, try to find the
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 583b670b4..445e260bc 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -825,7 +825,7 @@ struct netmap_adapter {
 	/* Offset of ethernet header for each packet. */
 	u_int virt_hdr_len;
 
-	char name[64];
+	char name[NETMAP_REQ_IFNAMSIZ]; /* used at least by pipes */
 };
 
 static __inline u_int
@@ -1029,10 +1029,12 @@ int netmap_bdg_list(struct nmreq_header *hdr);
 #define NM_MAXPIPES 	64	/* max number of pipes per adapter */
 
 struct netmap_pipe_adapter {
+	/* pipe identifier is up.name */
 	struct netmap_adapter up;
 
-	u_int id; 	/* pipe identifier */
-	int role;	/* either NR_REG_PIPE_MASTER or NR_REG_PIPE_SLAVE */
+#define NM_PIPE_ROLE_MASTER	0x1
+#define NM_PIPE_ROLE_SLAVE	0x2
+	int role;	/* either NM_PIPE_ROLE_MASTER or NM_PIPE_ROLE_SLAVE */
 
 	struct netmap_adapter *parent; /* adapter that owns the memory */
 	struct netmap_pipe_adapter *peer; /* the other end of the pipe */
@@ -1482,9 +1484,7 @@ int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 #define netmap_pipe_alloc(_1, _2) 	0
 #define netmap_pipe_dealloc(_1)
 #define netmap_get_pipe_na(hdr, _2, _3, _4)	\
-	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_mode; \
-	   (role__ == NR_REG_PIPE_MASTER || 	       \
-	    role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
+	((strchr(hdr->nr_name, '{') != NULL || strchr(hdr->nr_name, '}') != NULL) ? EOPNOTSUPP : 0)
 #endif
 
 #ifdef WITH_MONITOR
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index f8005c820..543da2c8f 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -53,8 +53,9 @@
 #include 
 #include 
 
-static void
-nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
+static int
+nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
+				struct nmreq_register *req)
 {
 	req->nr_offset = nmr->nr_offset;
 	req->nr_memsize = nmr->nr_memsize;
@@ -79,6 +80,22 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
 			(nmr->nr_flags & (~NR_REG_MASK));
 	}
 	req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+	/* Fix nr_name, nr_mode and nr_ringid to handle pipe requests. */
+	if (req->nr_mode == NR_REG_PIPE_MASTER ||
+			req->nr_mode == NR_REG_PIPE_SLAVE) {
+		char suffix[10];
+		snprintf(suffix, sizeof(suffix), "%c%d",
+			(req->nr_mode == NR_REG_PIPE_MASTER ? '{' : '}'),
+			req->nr_ringid);
+		if (strlen(hdr->nr_name) + strlen(suffix)
+					>= sizeof(hdr->nr_name)) {
+			/* No space for the pipe suffix. */
+			return ENOBUFS;
+		}
+		strncat(hdr->nr_name, suffix, strlen(suffix));
+		req->nr_mode = NR_REG_ALL_NIC;
+		req->nr_ringid = 0;
+	}
 	req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
 	if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
 		req->nr_flags |= NR_NO_TX_POLL;
@@ -88,6 +105,8 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
 	}
 	/* nmr->nr_arg1 (nr_pipes) ignored */
 	req->nr_extra_bufs = nmr->nr_arg3;
+
+	return 0;
 }
 
 /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
@@ -106,6 +125,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
 	}
 
+	/* First prepare the request header. */
 	hdr->nr_version = NETMAP_API; /* new API */
 	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
 	hdr->nr_options = NULL;
@@ -120,7 +140,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			nmreq_register_from_legacy(nmr, req);
+			if (nmreq_register_from_legacy(nmr, hdr, req)) {
+				goto oom;
+			}
 			break;
 		}
 		case NETMAP_BDG_ATTACH: {
@@ -128,7 +150,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			nmreq_register_from_legacy(nmr, &req->reg);
+			if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
+				goto oom;
+			}
 			/* Fix nr_mode, starting from nr_arg1. */
 			if (nmr->nr_arg1 & NETMAP_BDG_HOST) {
 				req->reg.nr_mode = NR_REG_NIC_SW;
@@ -238,6 +262,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	return hdr;
 oom:
 	if (hdr) {
+		if (hdr->nr_body) {
+			nm_os_free(hdr->nr_body);
+		}
 		nm_os_free(hdr);
 	}
 	D("Failed to allocate memory for nmreq_xyz struct");
@@ -274,9 +301,9 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
 	int ret = 0;
 	/* Don't bzero 'nmr', we may need the pointers stored into
-	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
-
-	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET).
+	 * Actually, we may get rid of all the write-backs that are
+	 * not needed. */
 
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 3d14991aa..f18fa4b80 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -127,14 +127,19 @@ netmap_pipe_dealloc(struct netmap_adapter *na)
 
 /* find a pipe endpoint with the given id among the parent's pipes */
 static struct netmap_pipe_adapter *
-netmap_pipe_find(struct netmap_adapter *parent, u_int pipe_id)
+netmap_pipe_find(struct netmap_adapter *parent, const char *pipe_id)
 {
 	int i;
 	struct netmap_pipe_adapter *na;
 
 	for (i = 0; i < parent->na_next_pipe; i++) {
+		const char *na_pipe_id;
 		na = parent->na_pipes[i];
-		if (na->id == pipe_id) {
+		na_pipe_id = strrchr(na->up.name,
+			na->role == NM_PIPE_ROLE_MASTER ? '{' : '}');
+		KASSERT(na_pipe_id != NULL, "Invalid pipe name");
+		++na_pipe_id;
+		if (!strcmp(na_pipe_id, pipe_id)) {
 			return na;
 		}
 	}
@@ -518,7 +523,7 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 		pna->peer_ref = 0;
 		netmap_adapter_put(&pna->peer->up);
 	}
-	if (pna->role == NR_REG_PIPE_MASTER)
+	if (pna->role == NM_PIPE_ROLE_MASTER)
 		netmap_pipe_remove(pna->parent, pna);
 	if (pna->parent_ifp)
 		if_rele(pna->parent_ifp);
@@ -534,26 +539,48 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
-	u_int pipe_id;
-	int role = req->nr_mode;
+	const char *pipe_id = NULL;
+	int role = 0;
 	int error, retries = 0;
+	char *cbra;
 
-	ND("flags %x", req->nr_mode);
-
-	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
-		ND("not a pipe");
-		return 0;
+	/* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */
+	cbra = strrchr(hdr->nr_name, '{');
+	if (cbra != NULL) {
+		role = NM_PIPE_ROLE_MASTER;
+	} else {
+		cbra = strrchr(hdr->nr_name, '}');
+		if (cbra != NULL) {
+			role = NM_PIPE_ROLE_SLAVE;
+		} else {
+			ND("not a pipe");
+			return 0;
+		}
+	}
+	pipe_id = cbra + 1;
+	if (*pipe_id == '\0' || cbra == hdr->nr_name) {
+		/* Bracket is the last character, so pipe name is missing;
+		 * or bracket is the first character, so base port name
+		 * is missing. */
+		return EINVAL;
+	}
+	if (req->nr_mode != NR_REG_ALL_NIC || req->nr_ringid != 0) {
+		/* Currently we only support opening all the hw rings of
+		 * a pipe. */
+		return EINVAL;
 	}
 
 	/* first, try to find the parent adapter */
 	for (;;) {
-		struct nmreq_register preq;
+		char nr_name_orig[NETMAP_REQ_IFNAMSIZ];
 		int create_error;
 
-		bzero(&preq, sizeof(preq)); /* basic register operation */
-		hdr->nr_body = &preq;
+		/* Temporarily remove the pipe suffix. */
+		strncpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
+		*cbra = '\0';
 		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
-		hdr->nr_body = req;
+		/* Restore the pipe suffix. */
+		strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -562,11 +589,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 		ND("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
+		*cbra = '\0';
 		NMG_UNLOCK();
-		hdr->nr_body = &preq;
 		create_error = netmap_vi_create(hdr, 1 /* autodelete */);
-		hdr->nr_body = req;
 		NMG_LOCK();
+		strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
 				D("failed to create a persistent vale port: %d", create_error);
@@ -583,14 +610,13 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	/* next, lookup the pipe id in the parent list */
 	reqna = NULL;
-	pipe_id = req->nr_ringid;
 	mna = netmap_pipe_find(pna, pipe_id);
 	if (mna) {
 		if (mna->role == role) {
-			ND("found %d directly at %d", pipe_id, mna->parent_slot);
+			ND("found %s directly at %d", pipe_id, mna->parent_slot);
 			reqna = mna;
 		} else {
-			ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
+			ND("found %s indirectly at %d", pipe_id, mna->parent_slot);
 			reqna = mna->peer;
 		}
 		/* the pipe we have found already holds a ref to the parent,
@@ -599,7 +625,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		netmap_unget_na(pna, ifp);
 		goto found;
 	}
-	ND("pipe %d not found, create %d", pipe_id, create);
+	ND("pipe %s not found, create %d", pipe_id, create);
 	if (!create) {
 		error = ENODEV;
 		goto put_out;
@@ -613,10 +639,9 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		error = ENOMEM;
 		goto put_out;
 	}
-	snprintf(mna->up.name, sizeof(mna->up.name), "%s{%d", pna->name, pipe_id);
+	snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id);
 
-	mna->id = pipe_id;
-	mna->role = NR_REG_PIPE_MASTER;
+	mna->role = NM_PIPE_ROLE_MASTER;
 	mna->parent = pna;
 	mna->parent_ifp = ifp;
 
@@ -655,8 +680,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* most fields are the same, copy from master and then fix */
 	*sna = *mna;
 	sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
-	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%d", pna->name, pipe_id);
-	sna->role = NR_REG_PIPE_SLAVE;
+	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
+	sna->role = NM_PIPE_ROLE_SLAVE;
 	error = netmap_attach_common(&sna->up);
 	if (error)
 		goto free_sna;
@@ -673,7 +698,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	if (ifp)
 		if_ref(ifp);
 
-	if (role == NR_REG_PIPE_MASTER) {
+	if (role == NM_PIPE_ROLE_MASTER) {
 		reqna = mna;
 		mna->peer_ref = 1;
 		netmap_adapter_get(&sna->up);
@@ -685,8 +710,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	ND("created master %p and slave %p", mna, sna);
 found:
 
-	ND("pipe %d %s at %p", pipe_id,
-		(reqna->role == NR_REG_PIPE_MASTER ? "master" : "slave"), reqna);
+	ND("pipe %s %s at %p", pipe_id,
+		(reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna);
 	*na = &reqna->up;
 	netmap_adapter_get(*na);
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 0d9ff99b0..d9ee26428 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -488,8 +488,8 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 	NR_REG_SW	= 2,
 	NR_REG_NIC_SW	= 3,
 	NR_REG_ONE_NIC	= 4,
-	NR_REG_PIPE_MASTER = 5,
-	NR_REG_PIPE_SLAVE = 6,
+	NR_REG_PIPE_MASTER = 5, /* deprecated, use "x{y" port name syntax */
+	NR_REG_PIPE_SLAVE = 6,  /* deprecated, use "x}y" port name syntax */
 };
 
 /* A single ioctl number is shared by all the new API command.

From 5908f3397525e0cb788a2d516e8ad1248d713265 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 11:08:06 +0100
Subject: [PATCH 0390/2207] remove obsolete usage of NR_REG_PIPE_{MASTER,SLAVE}

---
 sys/dev/netmap/netmap.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8f42fe092..8085f6544 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1784,8 +1784,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 	enum txrx t;
 	u_int j;
 
-	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC &&
-                    nr_mode != NR_REG_PIPE_MASTER && nr_mode != NR_REG_PIPE_SLAVE) ||
+	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC) ||
 			nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
 		D("Error: only NR_REG_ALL_NIC supported with netmap passthrough");
 		return EINVAL;
@@ -1798,8 +1797,6 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 		}
 		switch (nr_mode) {
 		case NR_REG_ALL_NIC:
-		case NR_REG_PIPE_MASTER:
-		case NR_REG_PIPE_SLAVE:
 			priv->np_qfirst[t] = 0;
 			priv->np_qlast[t] = nma_get_nrings(na, t);
 			ND("ALL/PIPE: %s %d %d", nm_txrx2str(t),

From 5fecfde59d6ee0abd717a52788ffbb4fc137e830 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:05:09 +0100
Subject: [PATCH 0391/2207] utils: ctrl-api-test: test pipe syntax

---
 utils/ctrl-api-test.c | 39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 162caab44..21a1f8d4a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -188,10 +188,10 @@ vale_attach(int fd, struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.reg.nr_mem_id = ctx->nr_mem_id;
 	if (ctx->nr_mode == 0) {
-		ctx->nr_mode = NR_REG_ALL_NIC; /* default */;
+		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
 	}
 	req.reg.nr_mode = ctx->nr_mode;
-	ret	   = ioctl(fd, NIOCCTRL, &hdr);
+	ret		= ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -201,7 +201,8 @@ vale_attach(int fd, struct TestContext *ctx)
 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
 		(ctx->nr_mem_id == req.reg.nr_mem_id)) &&
 			       (ctx->nr_flags == req.reg.nr_flags)
-		       ? 0 : -1;
+		       ? 0
+		       : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
@@ -418,6 +419,36 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	return pools_info_get(fd, ctx);
 }
 
+static int
+pipe_master(int fd, struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeid1");
+	ctx->ifname  = pipe_name;
+	ctx->nr_mode = NR_REG_ONE_NIC;
+
+	if (port_register(fd, ctx) == 0) {
+		printf("pipes should not accept NR_REG_ONE_NIC");
+		return -1;
+	}
+	ctx->nr_mode = NR_REG_ALL_NIC;
+
+	return port_register(fd, ctx);
+}
+
+static int
+pipe_slave(int fd, struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s}%s", ctx->ifname, "pipeid2");
+	ctx->ifname  = pipe_name;
+	ctx->nr_mode = NR_REG_ALL_NIC;
+
+	return port_register(fd, ctx);
+}
+
 /* NETMAP_REQ_VALE_POLLING_ENABLE */
 static int
 vale_polling_enable(int fd, struct TestContext *ctx)
@@ -516,6 +547,8 @@ static testfunc_t tests[] = {port_info_get,
 			     vale_ephemeral_port_hdr_manipulation,
 			     vale_persistent_port,
 			     register_and_pools_info_get,
+			     pipe_master,
+			     pipe_slave,
 			     vale_polling_enable_disable};
 
 int

From 46c82e0a022c2b09864b2c45b65c34576bc7020f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:10:06 +0100
Subject: [PATCH 0392/2207] remove deprecated (and unused)
 NETMAP_POOLS_INFO_GET

---
 sys/dev/netmap/netmap_legacy.c | 33 ---------------------------------
 sys/net/netmap_legacy.h        | 20 --------------------
 sys/net/netmap_virt.h          |  2 +-
 utils/testmmap.c               | 28 ----------------------------
 4 files changed, 1 insertion(+), 82 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 543da2c8f..3ae856602 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -214,16 +214,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_num_polling_cpus = nmr->nr_arg1;
 			break;
 		}
-		case NETMAP_POOLS_INFO_GET: {
-			/* We could deny this request similar to ptnetmap requests. */
-			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			hdr->nr_body = req;
-			hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-			/* Most of the fields are for output (see
-			 * nmreq_to_legacy). */
-			break;
-		}
 		case NETMAP_PT_HOST_CREATE:
 		case NETMAP_PT_HOST_DELETE: {
 			D("Netmap passthrough not supported yet");
@@ -384,29 +374,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		nmr->nr_arg1 = req->nr_num_polling_cpus;
 		break;
 	}
-	case NETMAP_REQ_POOLS_INFO_GET: {
-		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
-		struct netmap_pools_info pi;
-		struct nmreq_pools_info_get *req =
-			(struct nmreq_pools_info_get *)hdr->nr_body;
-		pi.memsize = req->nr_memsize;
-		pi.memid = req->nr_mem_id;
-		pi.if_pool_offset = req->nr_if_pool_offset;
-		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
-		pi.if_pool_objsize = req->nr_if_pool_objsize;
-		pi.ring_pool_offset = req->nr_ring_pool_offset;
-		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
-		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
-		pi.buf_pool_offset = req->nr_buf_pool_offset;
-		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
-		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
-		ret = copyout(&pi, upi, sizeof(pi));
-		if (ret) {
-			D("copyout() failed");
-		}
-		break;
-	}
 	}
 
 	return ret;
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 617666026..c3289093b 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -184,7 +184,6 @@ struct nmreq {
 #define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
 #define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
-#define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
 #define NETMAP_BDG_HOST		1	/* nr_arg1 value for NETMAP_BDG_ATTACH */
 
@@ -196,25 +195,6 @@ struct nmreq {
 	uint32_t	spare2[1];
 };
 
-/*
- * Structure filled-in by the kernel when asked for allocator info
- * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
- * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
- */
-struct netmap_pools_info {
-	uint64_t memsize;	/* same as nmr->nr_memsize */
-	uint32_t memid;		/* same as nmr->nr_arg2 */
-	uint32_t if_pool_offset;
-	uint32_t if_pool_objtotal;
-	uint32_t if_pool_objsize;
-	uint32_t ring_pool_offset;
-	uint32_t ring_pool_objtotal;
-	uint32_t ring_pool_objsize;
-	uint32_t buf_pool_offset;
-	uint32_t buf_pool_objtotal;
-	uint32_t buf_pool_objsize;
-};
-
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 41098a2cb..76f5cbb28 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -111,7 +111,7 @@ struct ptnetmap_cfgentry_bhyve {
 
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
- * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.
+ * or read. Used by NETMAP_PT_HOST_CREATE.
  * XXX deprecated
  */
 static inline void
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 481e41bb1..5da4cea89 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -147,7 +147,6 @@ void do_close()
 #include 
 
 struct nmreq curr_nmr = { .nr_version = NETMAP_API, .nr_flags = NR_REG_ALL_NIC, };
-struct netmap_pools_info curr_pools_info;
 char nmr_name[64];
 
 void parse_nmr_config(char* w, struct nmreq *nmr)
@@ -798,26 +797,6 @@ nmr_arg_error()
 	nmr_arg_unexpected(3);
 }
 
-void
-nmr_pools_info_get()
-{
-	void **pp = (void **)&curr_nmr.nr_arg1;
-	struct netmap_pools_info *upi = *pp;
-
-	printf("arg1+2+3:  %p\n", *pp);
-	printf("    memsize:    %"PRIu64"\n", upi->memsize);
-	printf("    memid:      %"PRIu32"\n", upi->memid);
-	printf("    if off:     %"PRIu32"\n", upi->if_pool_offset);
-	printf("    if tot:     %"PRIu32"\n", upi->if_pool_objtotal);
-	printf("    if siz:     %"PRIu32"\n", upi->if_pool_objsize);
-	printf("    ring off:   %"PRIu32"\n", upi->ring_pool_offset);
-	printf("    ring tot:   %"PRIu32"\n", upi->ring_pool_objtotal);
-	printf("    ring siz:   %"PRIu32"\n", upi->ring_pool_objsize);
-	printf("    buf off:    %"PRIu32"\n", upi->buf_pool_offset);
-	printf("    buf tot:    %"PRIu32"\n", upi->buf_pool_objtotal);
-	printf("    buf siz:    %"PRIu32"\n", upi->buf_pool_objsize);
-}
-
 void
 nmr_arg_extra()
 {
@@ -916,10 +895,6 @@ do_nmr_dump()
 			printf("BDG_POLLING_OFF");
 			arg_interp = nmr_arg_error;
 			break;
-		case NETMAP_POOLS_INFO_GET:
-			printf("POOLS_INFO_GET");
-			arg_interp = nmr_pools_info_get;
-			break;
 		default:
 			printf("???");
 			arg_interp = nmr_arg_error;
@@ -1051,9 +1026,6 @@ do_nmr_cmd()
 		curr_nmr.nr_cmd = NETMAP_PT_HOST_CREATE;
 	} else if (strcmp(arg, "pt-host-delete") == 0) {
 		curr_nmr.nr_cmd = NETMAP_PT_HOST_DELETE;
-	} else if (strcmp(arg, "pools-info-get") == 0) {
-		curr_nmr.nr_cmd = NETMAP_POOLS_INFO_GET;
-		nmreq_pointer_put(&curr_nmr, &curr_pools_info);
 	}
 out:
 	output("cmd=%x", curr_nmr.nr_cmd);

From 86f273187eb778fc2c5fb794b0f7630e7b7decfd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:19:48 +0100
Subject: [PATCH 0393/2207] nmreq_to_legacy: remove useless write-backs

---
 sys/dev/netmap/netmap_legacy.c | 38 +++-------------------------------
 1 file changed, 3 insertions(+), 35 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 3ae856602..a8f510f0e 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -272,14 +272,6 @@ nmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr)
 	nmr->nr_tx_rings = req->nr_tx_rings;
 	nmr->nr_rx_rings = req->nr_rx_rings;
 	nmr->nr_arg2 = req->nr_mem_id;
-	nmr->nr_ringid = req->nr_ringid;
-	if (req->nr_flags & NR_NO_TX_POLL) {
-		nmr->nr_ringid |= NETMAP_NO_TX_POLL;
-	}
-	if (req->nr_flags & NR_DO_RX_POLL) {
-		nmr->nr_ringid |= NETMAP_DO_RX_POLL;
-	}
-	nmr->nr_flags = req->nr_mode | req->nr_flags;
 	nmr->nr_arg3 = req->nr_extra_bufs;
 }
 
@@ -290,11 +282,9 @@ static int
 nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
 	int ret = 0;
-	/* Don't bzero 'nmr', we may need the pointers stored into
-	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET).
-	 * Actually, we may get rid of all the write-backs that are
-	 * not needed. */
 
+	/* We only write-back the fields that the user expects to be
+	 * written back. */
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req =
@@ -318,11 +308,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		struct nmreq_vale_attach *req =
 			(struct nmreq_vale_attach *)hdr->nr_body;
 		nmreq_register_to_legacy(&req->reg, nmr);
-		if (req->reg.nr_mode == NR_REG_NIC_SW) {
-			nmr->nr_arg1 = NETMAP_BDG_HOST;
-		} else {
-			nmr->nr_arg1 = 0;
-		}
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
@@ -352,26 +337,9 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		nmr->nr_arg2 = req->nr_mem_id;
 		break;
 	}
-	case NETMAP_REQ_VALE_DELIF: {
-		break;
-	}
+	case NETMAP_REQ_VALE_DELIF:
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
-		struct nmreq_vale_polling *req =
-			(struct nmreq_vale_polling *)hdr->nr_body;
-		switch (req->nr_mode) {
-		default:
-			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
-			break;
-		case NETMAP_POLLING_MODE_MULTI_CPU:
-			nmr->nr_flags = NR_REG_ONE_NIC;
-			break;
-		case NETMAP_POLLING_MODE_SINGLE_CPU:
-			nmr->nr_flags = NR_REG_ALL_NIC;
-			break;
-		}
-		nmr->nr_ringid = req->nr_first_cpu_id;
-		nmr->nr_arg1 = req->nr_num_polling_cpus;
 		break;
 	}
 	}

From 3331e6d231e7eb47785745baafa7f4732faa1cec Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:43:37 +0100
Subject: [PATCH 0394/2207] netmap.h: add some comments about the new API

---
 sys/net/netmap.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d9ee26428..2936f8e43 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -386,6 +386,79 @@ struct netmap_if {
 /*
  * New API to control netmap control devices. New applications should only use
  * nmreq_xyz structs with the NIOCCTRL ioctl() command.
+ *
+ * NIOCCTRL takes a nmreq_header struct, which contains the required
+ * API version, the name of a netmap port, a command type, and pointers
+ * to request body and options.
+ *
+ *	nr_name	(in)
+ *		The name of the port (em0, valeXXX:YYY, eth0{pn1 etc.)
+ *
+ *	nr_version (in/out)
+ *		Must match NETMAP_API as used in the kernel, error otherwise.
+ *		Always returns the desired value on output.
+ *
+ *	nr_reqtype (in)
+ *		One of the NETMAP_REQ_* command types below
+ *
+ *	nr_body (in)
+ *		Pointer to a command-specific struct, described by one
+ *		of the struct nmreq_xyz below.
+ *
+ *	nr_options (in)
+ *		Command specific options, if any.
+ *
+ * A NETMAP_REQ_REGISTER command activates netmap mode on the netmap
+ * port (e.g. physical interface) specified by nmreq_header.nr_name.
+ * The request body (struct nmreq_register) has several arguments to
+ * specify how the port is to be registered.
+ *
+ *	nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
+ *		On input, non-zero values may be used to reconfigure the port
+ *		according to the requested values, but this is not guaranteed.
+ *		On output the actual values in use are reported.
+ *
+ *	nr_mode (in)
+ *		Indicate what set of rings must be bound to the netmap
+ *		device (e.g. all NIC rings, host rings only, NIC and
+ *		host rings, ...). Values are in NR_REG_*.
+ *
+ *	nr_ringid (in)
+ *		If nr_mode == NR_REG_ONE_NIC (only a single couple of TX/RX
+ *		rings), indicate which NIC TX and/or RX ring is to be bound
+ *		(0..nr_*x_rings-1).
+ *
+ *	nr_flags (in)
+ *		Indicate special options for how to open the port.
+ *
+ *		NR_NO_TX_POLL can be OR-ed to make select()/poll() push
+ *			packets on tx rings only if POLLOUT is set.
+ *			The default is to push any pending packet.
+ *
+ *		NR_DO_RX_POLL can be OR-ed to make select()/poll() release
+ *			packets on rx rings also when POLLIN is NOT set.
+ *			The default is to touch the rx ring only with POLLIN.
+ *			Note that this is the opposite of TX because it
+ *			reflects the common usage.
+ *
+ *		Other options are NR_MONITOR_TX, NR_MONITOR_RX, NR_ZCOPY_MON,
+ *		NR_EXCLUSIVE, NR_RX_RINGS_ONLY, NR_TX_RINGS_ONLY and
+ *		NR_ACCEPT_VNET_HDR.
+ *
+ *	nr_mem_id (in/out)
+ *		The identity of the memory region used.
+ *		On input, 0 means the system decides autonomously,
+ *		other values may try to select a specific region.
+ *		On return the actual value is reported.
+ *		Region '1' is the global allocator, normally shared
+ *		by all interfaces. Other values are private regions.
+ *		If two ports the same region zero-copy is possible.
+ *
+ *	nr_extra_bufs (in/out)
+ *		Number of extra buffers to be allocated.
+ *
+ * The other NETMAP_REQ_* commands are described below.
+ *
  */
 
 /* Header common to all request options. */
@@ -496,10 +569,13 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * Demultiplexing is done using the nr_hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
- * specifying only nmreq_header, and copyin the rest. */
+ * specifying only nmreq_header, and copyin/copyout the rest. */
 #define NIOCCTRL	_IOWR('i', 151, struct nmreq_header)
 
-/* The ioctl commands to sync TX/RX netmap rings. */
+/* The ioctl commands to sync TX/RX netmap rings.
+ * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
+ *	whose identity is set in NIOCREGIF through nr_ringid.
+ *	These are non blocking and take no argument. */
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
 #define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
 

From 2b93963761df3f0b0725507dfe21025687208ace Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 29 Jan 2018 19:49:01 +0100
Subject: [PATCH 0395/2207] newnmreq: copy options from/to userspace

---
 sys/dev/netmap/netmap.c | 170 +++++++++++++++++++++++++++++++++++++---
 sys/net/netmap.h        |   3 +
 2 files changed, 161 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8085f6544..d3b545994 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2191,6 +2191,9 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
+static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
+static int nmreq_copyout(struct nmreq_header *, void *, size_t);
+
 /*
  * ioctl(2) support for the "netmap" device.
  *
@@ -2247,18 +2250,14 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		if (nr_body_is_user && nr_body_size) {
 			char *ker_nr_body;
 
-			usr_nr_body = hdr->nr_body;
 			/* Make a kernel-space copy of the user-space nr_body.
 			 * It's handy to temporarily replace hdr->nr_body with
 			 * a pointer to the kernel-space nr_body. */
-			ker_nr_body = nm_os_malloc(nr_body_size);
+			ker_nr_body = nmreq_copyin(hdr, nr_body_size, &error);
 			if (!ker_nr_body) {
-				return ENOMEM;
-			}
-			if (copyin(usr_nr_body, ker_nr_body, nr_body_size)) {
-				nm_os_free(ker_nr_body);
-				return EFAULT;
+				return error;
 			}
+			usr_nr_body = hdr->nr_body;
 			hdr->nr_body = ker_nr_body;
 		}
 
@@ -2550,16 +2549,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 		}
 		if (nr_body_is_user && nr_body_size) {
+			char *ker_nr_body;
 			KASSERT(usr_nr_body && hdr->nr_body,
 				"nr_body pointers must not be NULL");
 			/* Write back request body to userspace and reset the
 			 * user-space pointer. */
-			if (error == 0 && copyout(hdr->nr_body,
-				usr_nr_body, nr_body_size)) {
-				error = EFAULT;
-			}
-			nm_os_free(hdr->nr_body);
+			ker_nr_body = hdr->nr_body;
 			hdr->nr_body = usr_nr_body;
+			if (error == 0) {
+				error = nmreq_copyout(hdr, ker_nr_body, nr_body_size);
+			}
 		}
 		break;
 	}
@@ -2674,6 +2673,153 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	return 0;
 }
 
+size_t
+nmreq_opt_size_by_type(uint16_t nro_reqtype)
+{
+	return 0;
+}
+
+static void *
+nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
+{
+	size_t bufsz, rqsz;
+	int error;
+	char *ker = NULL, *p;
+	struct nmreq_option **next, *src;
+	struct nmreq_option buf;
+	void **ptrs;
+
+	/* compute the total size of the buffer */
+	rqsz = nmreq_size_by_type(hdr->nr_reqtype);
+	if (rqsz > NETMAP_REQ_MAXSIZE) {
+		error = EMSGSIZE;
+		goto out_err;
+	}
+	bodysz = 2 * sizeof(void *) + rqsz;
+	for (src = hdr->nr_options; src; src = src->nro_next) {
+		size_t optsz;
+		error = copyin(src, &buf, sizeof(*src));
+		if (error)
+			goto out_err;
+		optsz = sizeof(*src);
+		optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
+		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
+			error = EMSGSIZE;
+			goto out_err;
+		}
+		rqsz += optsz;
+		bufsz += optsz + sizeof(void *);
+	}
+
+	bufsz = max(1024UL, roundup_pow_of_two(bodysz));
+	ker = nm_os_malloc(bufsz);
+	if (ker == NULL) {
+		error = ENOMEM;
+		goto out_err;
+	}
+	p = ker;
+
+	/* make a copy of the user pointers */
+	ptrs = (void **)p;
+	*ptrs++ = hdr->nr_body;
+	*ptrs++ = hdr->nr_options;
+	p = (char *)ptrs;
+
+	/* copy the body */
+	error = copyin(hdr->nr_body, p, rqsz);
+	if (error)
+		goto out_err;
+	p += rqsz;
+
+	/* copy the options */
+	next = &hdr->nr_options;
+	src = *next;
+	while (src) {
+		size_t optsz;
+		struct nmreq_option *opt;
+
+		/* copy the option header */
+		ptrs = (void **)p;
+		opt = (struct nmreq_option *)(ptrs + 1);
+		error = copyin(src, opt, sizeof(*src));
+		if (error)
+			goto out_err;
+		/* make a copy of the user next pointer */
+		*ptrs = opt->nro_next;
+		/* overwrite the user pointer with the in-kernel one */
+		*next = opt;
+
+		p = (char *)(opt + 1);
+
+		/* copy the option body */
+		optsz = nmreq_opt_size_by_type(opt->nro_reqtype);
+		if (optsz) {
+			/* the option body follows the option header */
+			error = copyin(src + 1, p, optsz);
+			if (error)
+				goto out_err;
+			p += optsz;
+		}
+
+		/* move to next option */
+		next = &opt->nro_next;
+		src = *next;
+	}
+	/* skip the option list head */
+	return ker + 2 * sizeof(void *);
+
+out_err:
+	if (ker)
+		nm_os_free(ker);
+	if (perror)
+		*perror = error;
+	return NULL;
+}
+
+static int
+nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz)
+{
+	int error = 0;
+	struct nmreq_option *src, *dst;
+	void **ptrs = ker;
+
+	/* copy the body */
+	error = copyout(ker, *(ptrs - 2), bodysz);
+	if (error)
+		goto out;
+
+	/* copy the options */
+	dst = *(ptrs - 1);
+	src = hdr->nr_options;
+	while (src) {
+		size_t optsz;
+		struct nmreq_option *next;
+
+		/* restore the user pointer */
+		next = src->nro_next;
+		ptrs = (void **)src - 1;
+		src->nro_next = *ptrs;
+
+		/* copy the option header */
+		error = copyout(src, dst, sizeof(src));
+		if (error)
+			goto out;
+		       
+		/* copy the option body */
+		optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+		if (optsz) {
+			error = copyout(dst + 1, src + 1, optsz);
+			if (error)
+				goto out;
+		}
+		src = next;
+		dst = *ptrs;
+	}
+
+out:
+	nm_os_free(ker);
+	return error;
+}
 
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 2936f8e43..e90f91afb 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -461,6 +461,9 @@ struct netmap_if {
  *
  */
 
+/* maximum size of a request, including all options */
+#define NETMAP_REQ_MAXSIZE	4096
+
 /* Header common to all request options. */
 struct nmreq_option {
 	/* Pointer ot the next option. */

From 3ae5840b77ed2ba317722096fdf566192ad1b8ec Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 11:57:48 +0100
Subject: [PATCH 0396/2207] nmreq_copyout: release memory also in case of error

---
 sys/dev/netmap/netmap.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d3b545994..4e95194e6 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2192,7 +2192,7 @@ ring_timestamp_set(struct netmap_ring *ring)
 }
 
 static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
-static int nmreq_copyout(struct nmreq_header *, void *, size_t);
+static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
 
 /*
  * ioctl(2) support for the "netmap" device.
@@ -2556,9 +2556,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			 * user-space pointer. */
 			ker_nr_body = hdr->nr_body;
 			hdr->nr_body = usr_nr_body;
-			if (error == 0) {
-				error = nmreq_copyout(hdr, ker_nr_body, nr_body_size);
-			}
+			error = nmreq_copyout(hdr, ker_nr_body, nr_body_size, error);
 		}
 		break;
 	}
@@ -2777,12 +2775,14 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 }
 
 static int
-nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz)
+nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
 {
-	int error = 0;
 	struct nmreq_option *src, *dst;
 	void **ptrs = ker;
 
+	if (error)
+		goto out;
+
 	/* copy the body */
 	error = copyout(ker, *(ptrs - 2), bodysz);
 	if (error)

From cf95fd126086219bb87ce68309cb6d237250a7d8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 16:34:00 +0100
Subject: [PATCH 0397/2207] added nmreq_findoption

---
 sys/dev/netmap/netmap.c      | 14 ++++++++++++++
 sys/dev/netmap/netmap_kern.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4e95194e6..0fae296bc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2193,6 +2193,7 @@ ring_timestamp_set(struct netmap_ring *ring)
 
 static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
 static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
+struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
 
 /*
  * ioctl(2) support for the "netmap" device.
@@ -2247,6 +2248,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			return EINVAL;
 		}
 
+		BUG_ON(!nr_body_is_user && hdr->nr_options);
+
 		if (nr_body_is_user && nr_body_size) {
 			char *ker_nr_body;
 
@@ -2821,6 +2824,17 @@ nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
 	return error;
 }
 
+struct nmreq_option *
+nmreq_findoption(struct nmreq_header *hdr, uint16_t reqtype)
+{
+	struct nmreq_option *opt;
+
+	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+		if (opt->nro_reqtype == reqtype)
+			return opt;
+	return NULL;
+}
+
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
  *
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 445e260bc..83711149f 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2186,4 +2186,6 @@ void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
 #endif /* WITH_PTNETMAP_GUEST */
 
+struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+
 #endif /* _NET_NETMAP_KERN_H_ */

From 172fd8961b2ff18d582e3c15f556ace7a14b475b Mon Sep 17 00:00:00 2001
From: Vitaly 
Date: Fri, 2 Feb 2018 08:00:53 +0300
Subject: [PATCH 0398/2207] Added vmxnet3 support

---
 LINUX/configure                               |   2 +-
 LINUX/dkms/dkms.conf                          |   5 +
 .../vanilla--vmxnet3--10000--99999            |  97 +++
 LINUX/if_vmxnet3_netmap.h                     | 619 ++++++++++++++++++
 4 files changed, 722 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/vanilla--vmxnet3--10000--99999
 create mode 100644 LINUX/if_vmxnet3_netmap.h

diff --git a/LINUX/configure b/LINUX/configure
index 4b627bd6e..e205c23e6 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -107,7 +107,7 @@ subsys enable generic
 
 # available drivers
 driver_avail="r8169.c virtio_net.c forcedeth.c veth.c \
-	e1000 e1000e igb ixgbe ixgbevf i40e"
+	e1000 e1000e igb ixgbe ixgbevf i40e vmxnet3"
 # enabled drivers (bitfield)
 driver=
 drv()
diff --git a/LINUX/dkms/dkms.conf b/LINUX/dkms/dkms.conf
index 16458d86d..a6502be72 100644
--- a/LINUX/dkms/dkms.conf
+++ b/LINUX/dkms/dkms.conf
@@ -45,3 +45,8 @@ DEST_MODULE_LOCATION[7]=/kernel/drivers/net/ethernet/intel/ixgbe/
 BUILT_MODULE_NAME[8]=i40e
 BUILT_MODULE_LOCATION[8]=i40e/
 DEST_MODULE_LOCATION[8]=/kernel/drivers/net/ethernet/intel/i40e/
+
+# vmxnet3 driver
+BUILT_MODULE_NAME[9]=vmxnet3
+BUILT_MODULE_LOCATION[9]=vmxnet3/
+DEST_MODULE_LOCATION[9]=/kernel/drivers/net/vmxnet3/
diff --git a/LINUX/final-patches/vanilla--vmxnet3--10000--99999 b/LINUX/final-patches/vanilla--vmxnet3--10000--99999
new file mode 100644
index 000000000..312d11c3c
--- /dev/null
+++ b/LINUX/final-patches/vanilla--vmxnet3--10000--99999
@@ -0,0 +1,97 @@
+diff -ruN a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
+--- a/vmxnet3/vmxnet3_drv.c	2018-01-26 08:16:40.302737839 +0300
++++ b/vmxnet3/vmxnet3_drv.c	2018-01-26 08:16:40.305737839 +0300
+@@ -24,6 +24,7 @@
+  *
+  */
+ 
++
+ #include 
+ #include 
+ 
+@@ -308,6 +309,11 @@
+ #endif /* __BIG_ENDIAN_BITFIELD  */
+ 
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) || defined(DEV_NETMAP)
++#include "if_vmxnet3_netmap.h"
++#endif
++
++
+ static void
+ vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
+ 		     struct pci_dev *pdev)
+@@ -367,6 +373,14 @@
+ 	int completed = 0;
+ 	union Vmxnet3_GenericDesc *gdesc;
+ 
++#ifdef DEV_NETMAP
++	struct net_device *netdev = adapter->netdev;
++
++	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
++		return 0;
++#endif
++		
++
+ 	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+ 	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
+ 		completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX(
+@@ -1266,6 +1280,15 @@
+ 	struct Vmxnet3_RxDesc rxCmdDesc;
+ 	struct Vmxnet3_RxCompDesc rxComp;
+ #endif
++
++#ifdef DEV_NETMAP
++	u_int total_packets = 0;
++	struct net_device *netdev = adapter->netdev;
++	
++	if (netmap_rx_irq(netdev, 0, &total_packets) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
+ 			  &rxComp);
+ 	while (rcd->gen == rq->comp_ring.gen) {
+@@ -2431,6 +2454,10 @@
+ 		adapter->rx_queue[0].rx_ring[0].size,
+ 		adapter->rx_queue[0].rx_ring[1].size);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_init_buffers(adapter);
++#endif /* DEV_NETMAP */    
++
+ 	vmxnet3_tq_init_all(adapter);
+ 	err = vmxnet3_rq_init_all(adapter);
+ 	if (err) {
+@@ -2476,7 +2503,7 @@
+ 
+ 	/* Apply the rx filter settins last. */
+ 	vmxnet3_set_mc(adapter->netdev);
+-
++    
+ 	/*
+ 	 * Check link state when first activating device. It will start the
+ 	 * tx queue if the link is up.
+@@ -3290,6 +3317,11 @@
+ 		dev_err(&pdev->dev, "Failed to register adapter\n");
+ 		goto err_register;
+ 	}
++    
++    
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_attach(adapter);
++#endif /* DEV_NETMAP */    
+ 
+ 	vmxnet3_check_link(adapter, false);
+ 	return 0;
+@@ -3342,6 +3374,10 @@
+ 	cancel_work_sync(&adapter->work);
+ 
+ 	unregister_netdev(netdev);
++    
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_detach(netdev);
++#endif /* DEV_NETMAP */    
+ 
+ 	vmxnet3_free_intr_resources(adapter);
+ 	vmxnet3_free_pci_resources(adapter);
diff --git a/LINUX/if_vmxnet3_netmap.h b/LINUX/if_vmxnet3_netmap.h
new file mode 100644
index 000000000..cec6060f0
--- /dev/null
+++ b/LINUX/if_vmxnet3_netmap.h
@@ -0,0 +1,619 @@
+
+#ifndef _IF_VMXNET3_NETMAP_H_
+#define _IF_VMXNET3_NETMAP_H_
+
+
+#include 
+#include 
+#include 
+
+#define SOFTC_T	vmxnet3_adapter
+
+
+static int vmxnet3_rq_create_all( struct vmxnet3_adapter* adapter );
+static void vmxnet3_unmap_tx_buf( struct vmxnet3_tx_buf_info* tbi, struct pci_dev* pdev );
+
+
+static int vmxnet3_netmap_reg( struct netmap_adapter* na, int onoff )
+{
+    int err = 0;
+
+    struct ifnet* ifp = na->ifp;
+    struct SOFTC_T* adapter = netdev_priv( ifp );
+
+    /* protect against other reinit */
+    while( test_and_set_bit( VMXNET3_STATE_BIT_RESETTING, &adapter->state ) )
+        usleep_range( 1000, 2000 );
+
+    if( netif_running( adapter->netdev ) )
+    {
+        vmxnet3_quiesce_dev( adapter );
+        vmxnet3_reset_dev( adapter );
+
+        vmxnet3_rq_destroy_all( adapter );
+
+        err = vmxnet3_rq_create_all( adapter );
+        if( err )
+            goto out;
+    }
+
+    /* enable or disable flags and callbacks in na and ifp */
+    if( onoff )
+    {
+        nm_set_native_flags( na );
+    }
+    else
+    {
+        nm_clear_native_flags( na );
+    }
+
+
+    if( netif_running( adapter->netdev ) )
+    {
+        err = vmxnet3_activate_dev( adapter );
+        if( err )
+            goto out;
+    }
+    else
+    {
+        vmxnet3_reset_dev( adapter );
+    }
+
+out:
+    clear_bit( VMXNET3_STATE_BIT_RESETTING, &adapter->state );
+
+    if( err )
+    {
+        vmxnet3_force_close( adapter );
+    }
+
+
+    return 0;
+}
+
+
+static int vmxnet3_netmap_unmap_pkt( u32 eop_idx, struct vmxnet3_tx_queue* tq, struct pci_dev* pdev )
+{
+    int entries = 0;
+
+    //
+    // no out of order completion
+    //
+
+    BUG_ON( tq->buf_info[ eop_idx ].sop_idx != tq->tx_ring.next2comp );
+    BUG_ON( VMXNET3_TXDESC_GET_EOP( &( tq->tx_ring.base[ eop_idx ].txd ) ) != 1 );
+
+    BUG_ON( tq->buf_info[ eop_idx ].skb != NULL );
+
+
+    VMXNET3_INC_RING_IDX_ONLY( eop_idx, tq->tx_ring.size );
+
+    while( tq->tx_ring.next2comp != eop_idx )
+    {
+        vmxnet3_unmap_tx_buf( tq->buf_info + tq->tx_ring.next2comp, pdev );
+
+        //
+        // update next2comp w/o tx_lock. Since we are marking more,
+        // instead of less, tx ring entries avail, the worst case is
+        // that the tx routine incorrectly re-queues a pkt due to
+        // insufficient tx ring entries.
+        //
+        
+        vmxnet3_cmd_ring_adv_next2comp( &tq->tx_ring );
+        entries++;
+    }
+
+
+    return entries;
+}
+
+
+static int vmxnet3_netmap_tq_tx_complete( struct vmxnet3_tx_queue* tq, struct pci_dev* pdev )
+{
+    int completed = 0;
+    union Vmxnet3_GenericDesc* gdesc;
+
+
+    gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+
+    while( VMXNET3_TCD_GET_GEN( &gdesc->tcd ) == tq->comp_ring.gen )
+    {
+        completed += vmxnet3_netmap_unmap_pkt( VMXNET3_TCD_GET_TXIDX( &gdesc->tcd ), tq, pdev );
+
+        vmxnet3_comp_ring_adv_next2proc( &tq->comp_ring );
+        gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+    }
+
+
+    return completed;
+}
+
+
+static int vmxnet3_netmap_txsync( struct netmap_kring* kring, int flags )
+{
+#define  kUseTwoTxDescForPacket     0
+#define  kMinFreeTxDescForPacket    (kUseTwoTxDescForPacket ? 2 : 1)
+
+    struct netmap_adapter* na = kring->na;
+    struct ifnet* ifp = na->ifp;
+    struct netmap_ring* ring = kring->ring;
+
+    u_int n;
+    u_int nm_i;	// index into the netmap ring
+    int completed;
+    u_int deferred = 0;
+    u_int ring_nr = kring->ring_id;
+
+    u_int const lim = kring->nkr_num_slots - 1;
+    u_int const head = kring->rhead;
+
+    union Vmxnet3_GenericDesc* gdesc;
+    struct SOFTC_T* adapter = netdev_priv( ifp );
+    struct vmxnet3_tx_queue* tq = &adapter->tx_queue[ ring_nr ];
+
+
+    if( !netif_carrier_ok( ifp ) )
+        return 0;
+
+    //
+    // Free up the comp_descriptors aggressively
+    //
+
+    completed = vmxnet3_netmap_tq_tx_complete( tq, adapter->pdev );
+
+    //
+    // Reclaim buffers for completed transmissions
+    //
+
+    kring->nr_hwtail = nm_prev( tq->comp_ring.next2proc, tq->comp_ring.size - 1 );
+
+    //
+    // Process new packets to send
+    //
+
+    nm_i = kring->nr_hwcur;
+
+    if( nm_i != head )
+    {
+        for( n = 0; nm_i != head; n++ )
+        {
+            u32 copy_size = 0;
+            int free_cmd_desc_count;
+            unsigned long lock_flags;
+
+            union Vmxnet3_GenericDesc* sop_txd;
+            union Vmxnet3_GenericDesc* eop_txd;
+
+            struct netmap_slot* slot = &ring->slot[ nm_i ];
+            u_int packet_len = slot->len;
+            void* packet_addr = NMB( na, slot );
+
+            slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+
+
+            spin_lock_irqsave( &tq->tx_lock, lock_flags );
+
+            
+            free_cmd_desc_count = vmxnet3_cmd_ring_desc_avail( &tq->tx_ring );
+
+            if( free_cmd_desc_count < kMinFreeTxDescForPacket )
+            {
+                tq->stats.tx_ring_full++;
+                spin_unlock_irqrestore( &tq->tx_lock, lock_flags );
+                break;
+            }
+
+            //
+            // Copy header
+            //
+
+            if( kUseTwoTxDescForPacket )
+            {
+                struct Vmxnet3_TxDataDesc* tdd = 
+                    tdd = tq->data_ring.base + tq->tx_ring.next2fill;
+
+                copy_size = min( (u_int) VMXNET3_HDR_COPY_SIZE, packet_len );
+                memcpy( tdd->data, packet_addr, copy_size );
+            }
+
+            //
+            // Map rest of data
+            //
+
+            {
+                u32 dw2;
+                u32 len;
+                u32 buf_offset;
+                union Vmxnet3_GenericDesc* gdesc;
+                struct vmxnet3_tx_buf_info* tbi = NULL;
+
+                //
+                // use the previous gen bit for the SOP desc
+                //
+
+                dw2 = ( tq->tx_ring.gen ^ 0x1 ) << VMXNET3_TXD_GEN_SHIFT;
+
+                sop_txd = tq->tx_ring.base + tq->tx_ring.next2fill;
+                gdesc = sop_txd;
+
+                //
+                // Setup TX descriptor for the header
+                //
+
+                if( copy_size )
+                {
+                    sop_txd->txd.addr = cpu_to_le64( tq->data_ring.basePA + tq->tx_ring.next2fill * sizeof( struct Vmxnet3_TxDataDesc ) );
+                    sop_txd->dword[ 2 ] = cpu_to_le32( dw2 | copy_size );
+                    sop_txd->dword[ 3 ] = 0;
+
+                    tbi = tq->buf_info + tq->tx_ring.next2fill;
+                    tbi->map_type = VMXNET3_MAP_NONE;
+
+                    vmxnet3_cmd_ring_adv_next2fill( &tq->tx_ring );
+
+                    //
+                    // use the right gen for non-SOP desc
+                    //
+                    
+                    dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+                }
+
+                //
+                // Handle linear part
+                //
+
+                len = packet_len - copy_size;
+                buf_offset = copy_size;
+
+                if( len )
+                {
+                    u32 buf_size;
+
+                    BUG_ON( len > VMXNET3_MAX_TX_BUF_SIZE );
+                    buf_size = len;
+                    dw2 |= len;
+
+                    tbi = tq->buf_info + tq->tx_ring.next2fill;
+                    tbi->map_type = VMXNET3_MAP_SINGLE;
+                    tbi->dma_addr = dma_map_single( &adapter->pdev->dev, packet_addr + buf_offset, buf_size, PCI_DMA_TODEVICE );
+
+                    if( dma_mapping_error( &adapter->pdev->dev, tbi->dma_addr ) )
+                    {
+                        spin_unlock_irqrestore( &tq->tx_lock, lock_flags );
+                        break;
+                    }
+
+                    tbi->len = buf_size;
+
+                    gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
+                    BUG_ON( gdesc->txd.gen == tq->tx_ring.gen );
+
+                    gdesc->txd.addr = cpu_to_le64( tbi->dma_addr );
+                    gdesc->dword[ 2 ] = cpu_to_le32( dw2 );
+                    gdesc->dword[ 3 ] = 0;
+
+                    vmxnet3_cmd_ring_adv_next2fill( &tq->tx_ring );
+                    dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+                }
+
+
+                eop_txd = gdesc;
+
+                tbi->skb = NULL;
+                tbi->sop_idx = sop_txd - tq->tx_ring.base;
+            }
+
+            //
+            // setup the EOP desc
+            //
+
+            eop_txd->dword[ 3 ] = cpu_to_le32( VMXNET3_TXD_CQ | VMXNET3_TXD_EOP );
+
+            //
+            // setup the SOP desc
+            //
+
+            gdesc = sop_txd;
+
+            gdesc->txd.om = 0;
+            gdesc->txd.msscof = 0;
+
+            //
+            // finally flips the GEN bit of the SOP desc
+            //
+
+            gdesc->dword[ 2 ] = cpu_to_le32( le32_to_cpu( gdesc->dword[ 2 ] ) ^ VMXNET3_TXD_GEN );
+
+            deferred++;            
+
+
+            spin_unlock_irqrestore( &tq->tx_lock, lock_flags );
+
+            //
+            // go to the next netmap slot
+            //
+
+            nm_i = nm_next( nm_i, lim );
+        }
+
+        kring->nr_hwcur = head;
+    }
+
+    //
+    // Notify vSwitch that packets are available.
+    //
+
+    if( deferred >= 1 )
+    {
+        VMXNET3_WRITE_BAR0_REG( 
+            adapter,
+            ( VMXNET3_REG_TXPROD + tq->qid * VMXNET3_REG_ALIGN ), 
+            tq->tx_ring.next2fill );
+    }
+
+
+    return 0;
+}
+
+
+static int vmxnet3_netmap_rxsync( struct netmap_kring* kring, int flags )
+{
+    static const u32 rxprod_reg[] = 
+    {
+        VMXNET3_REG_RXPROD, 
+        VMXNET3_REG_RXPROD2
+    };
+
+    u32 num_pkts = 0;
+    u32 netmap_offset = 0;
+    u_int nm_i = 0;	// index into the netmap ring
+
+    struct netmap_adapter* na = kring->na;
+    struct ifnet* ifp = na->ifp;
+    struct netmap_ring* nmring = kring->ring;
+    
+    u_int ring_nr = kring->ring_id;
+    u_int const lim = kring->nkr_num_slots - 1;
+    u_int const head = kring->rhead;
+    int force_update = ( flags & NAF_FORCE_READ ) || kring->nr_kflags & NKR_PENDINTR;
+
+    struct Vmxnet3_RxCompDesc* rcd;
+    struct SOFTC_T* adapter = netdev_priv( ifp );
+    struct vmxnet3_rx_queue* rq = &adapter->rx_queue[ ring_nr ];
+
+
+    if( !netif_carrier_ok( ifp ) )
+        return 0;
+
+    if( head > lim )
+        return netmap_ring_reinit( kring );
+
+    //
+    // First part: import newly received packets.
+    //
+
+    if( netmap_no_pendintr || force_update )
+    {
+        uint32_t hwtail_lim = 
+            nm_prev( kring->nr_hwcur, lim );
+
+
+        nm_i = kring->nr_hwtail;
+
+        vmxnet3_getRxComp( 
+            rcd,
+            &rq->comp_ring.base[ rq->comp_ring.next2proc ].rcd, 
+            &rxComp );
+
+
+        while( rcd->gen == rq->comp_ring.gen && nm_i != hwtail_lim )
+        {
+            u32 idx;
+            u32 ring_idx;
+            int num_to_alloc;
+            void* packet_addr;
+            void* packet_nic_addr;
+            struct netmap_slot* slot;
+            struct Vmxnet3_RxDesc* rxd;
+            struct vmxnet3_rx_buf_info* rbi;
+            struct vmxnet3_cmd_ring* ring = NULL;
+
+            slot = nmring->slot + nm_i;
+            packet_addr = NMB( na, slot );
+
+
+            BUG_ON( rcd->rqID != rq->qid && rcd->rqID != rq->qid2 );
+            idx = rcd->rxdIdx;
+            ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
+            ring = rq->rx_ring + ring_idx;
+            vmxnet3_getRxDesc( rxd, &rq->rx_ring[ ring_idx ].base[ idx ].rxd, &rxCmdDesc );
+            rbi = rq->buf_info[ ring_idx ] + idx;
+            BUG_ON( rxd->addr != rbi->dma_addr || rxd->len != rbi->len );
+
+            if( rcd->eop && rcd->err )
+            {
+                rq->stats.drop_total++;
+                rq->stats.drop_err++;
+
+                if( !rcd->fcs )
+                    rq->stats.drop_fcs++;
+
+                goto rcd_done;
+            }
+
+            if( rcd->sop )
+            {
+                BUG_ON( rxd->btype != VMXNET3_RXD_BTYPE_HEAD || rcd->rqID != rq->qid );
+                BUG_ON( rbi->buf_type != VMXNET3_RX_BUF_SKB );
+
+                if( rcd->len == 0 )
+                {
+                    BUG_ON( !( rcd->sop && rcd->eop ) );
+                    goto rcd_done;
+                }
+
+                packet_nic_addr = rbi->skb->data;
+                memcpy( packet_addr, packet_nic_addr, rcd->len );
+
+                netmap_offset = rcd->len;
+            }
+            else
+            {
+                // non SOP buffer must be type 1 in most cases
+                BUG_ON( rbi->buf_type != VMXNET3_RX_BUF_PAGE );
+                BUG_ON( rxd->btype != VMXNET3_RXD_BTYPE_BODY );
+
+                packet_nic_addr = page_address( rbi->page );
+                memcpy( packet_addr + netmap_offset, packet_nic_addr, rcd->len );
+
+                netmap_offset += rcd->len;
+            }
+
+
+            if( rcd->eop )
+            {
+                slot->len = netmap_offset;
+                slot->flags = 0;
+                
+                num_pkts++;
+                nm_i = nm_next( nm_i, lim );
+            }
+
+
+        rcd_done:
+            ring->next2comp = idx;
+
+            num_to_alloc = vmxnet3_cmd_ring_desc_avail( ring );
+            ring = rq->rx_ring + ring_idx;
+
+            while( num_to_alloc )
+            {
+                vmxnet3_getRxDesc( rxd, &ring->base[ ring->next2fill ].rxd, &rxCmdDesc );
+                BUG_ON( !rxd->addr );
+
+                // Recv desc is ready to be used by the device
+                rxd->gen = ring->gen;
+                vmxnet3_cmd_ring_adv_next2fill( ring );
+                num_to_alloc--;
+            }
+
+            // if needed, update the register
+            if( unlikely( rq->shared->updateRxProd ) )
+            {
+                VMXNET3_WRITE_BAR0_REG( adapter,
+                    rxprod_reg[ ring_idx ] + rq->qid * VMXNET3_REG_ALIGN,
+                    ring->next2fill );
+            }
+
+            vmxnet3_comp_ring_adv_next2proc( &rq->comp_ring );
+            vmxnet3_getRxComp( rcd, &rq->comp_ring.base[ rq->comp_ring.next2proc ].rcd, &rxComp );
+        }
+
+
+		if( num_pkts )
+		{
+			kring->nr_hwtail = nm_i;
+		}
+
+		kring->nr_kflags &= ~NKR_PENDINTR;
+    }
+
+    //
+    // Second part: skip past packets that userspace has released.
+    //
+
+    nm_i = kring->nr_hwcur;
+
+    if( nm_i != head )
+    {
+		int n;
+
+		for( n = 0; nm_i != head; n++ )
+        {
+            struct netmap_slot* slot = &nmring->slot[ nm_i ];
+            uint64_t paddr;
+            void* addr = PNMB( na, slot, &paddr );
+
+            if( addr == NETMAP_BUF_BASE( na ) ) // bad buf
+                goto ring_reset;
+
+            slot->flags &= ~NS_BUF_CHANGED;
+
+            nm_i = nm_next( nm_i, lim );
+        }
+        kring->nr_hwcur = head;
+    }
+
+
+    return 0;
+
+
+ring_reset:
+	return netmap_ring_reinit( kring );	
+}
+
+
+static void vmxnet3_netmap_intr( struct netmap_adapter* na, int onoff )
+{
+    struct ifnet* ifp = na->ifp;
+    struct SOFTC_T* adapter = netdev_priv( ifp );
+
+    if( onoff )
+        vmxnet3_enable_all_intrs( adapter );
+    else
+        vmxnet3_disable_all_intrs( adapter );
+}
+
+
+static void vmxnet3_netmap_init_buffers( struct SOFTC_T* adapter )
+{
+    u32 r;
+    struct ifnet* ifp = adapter->netdev;
+    struct netmap_adapter* na = NA( ifp );
+
+
+    if( !nm_native_on( na ) )
+        return;
+
+
+    for( r = 0; r < na->num_rx_rings; r++ )
+    {
+        (void) netmap_reset( na, NR_RX, r, 0 );
+    }
+
+
+    for( r = 0; r < na->num_tx_rings; r++ )
+    {
+        (void) netmap_reset( na, NR_TX, r, 0 );
+    }
+}
+
+
+static void vmxnet3_netmap_attach( struct SOFTC_T* adapter )
+{
+    struct netmap_adapter na;
+
+    bzero( &na, sizeof( na ) );
+
+    na.ifp = adapter->netdev;
+    na.pdev = &adapter->pdev->dev;
+    na.num_tx_desc = adapter->tx_ring_size;
+    na.num_rx_desc = adapter->rx_ring_size;
+    na.nm_register = vmxnet3_netmap_reg;
+    na.nm_txsync = vmxnet3_netmap_txsync;
+    na.nm_rxsync = vmxnet3_netmap_rxsync;
+    na.num_tx_rings = adapter->num_tx_queues;
+    na.num_rx_rings = adapter->num_rx_queues;
+    na.nm_intr = vmxnet3_netmap_intr;
+
+    netmap_attach( &na );
+}
+
+
+static void vmxnet3_netmap_detach( struct net_device* device )
+{
+    netmap_detach( device );
+}
+
+
+#endif // _IF_VMXNET3_NETMAP_H_

From 6ce7587bc638b4ce09243b290e34212c9426f696 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 16:49:26 +0100
Subject: [PATCH 0399/2207] fail when an option is not recognized

---
 sys/dev/netmap/netmap.c | 27 +++++++++++++++++++++++++++
 sys/net/netmap.h        |  7 ++++++-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0fae296bc..e12ab379f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2194,6 +2194,7 @@ ring_timestamp_set(struct netmap_ring *ring)
 static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
 static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
 struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+static int nmreq_checkoptions(struct nmreq_header *);
 
 /*
  * ioctl(2) support for the "netmap" device.
@@ -2342,6 +2343,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
 
+				error = nmreq_checkoptions(hdr);
+				if (error) {
+					netmap_do_unregif(priv);
+					break;
+				}
+
 				/* store ifp reference so that priv destructor may release it */
 				priv->np_ifp = ifp;
 			} while (0);
@@ -2750,6 +2757,11 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 		/* overwrite the user pointer with the in-kernel one */
 		*next = opt;
 
+		/* initialize the option as not supported.
+		 * Recognized options will update this field.
+		 */
+		opt->nro_status = EOPNOTSUPP;
+
 		p = (char *)(opt + 1);
 
 		/* copy the option body */
@@ -2835,6 +2847,21 @@ nmreq_findoption(struct nmreq_header *hdr, uint16_t reqtype)
 	return NULL;
 }
 
+static int
+nmreq_checkoptions(struct nmreq_header *hdr)
+{
+	struct nmreq_option *opt;
+	/* return error if there is still any option
+	 * marked as not supported
+	 */
+
+	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+		if (opt->nro_status == EOPNOTSUPP)
+			return EOPNOTSUPP;
+
+	return 0;
+}
+
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
  *
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e90f91afb..eb6e29be1 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -469,7 +469,12 @@ struct nmreq_option {
 	/* Pointer ot the next option. */
 	struct nmreq_option	*nro_next;
 	/* Option type. */
-	uint16_t		nro_reqtype;
+	uint32_t		nro_reqtype;
+	/* (out) status of the option:
+	 * 0: recognized and processed
+	 * !=0: errno value
+	 */
+	uint32_t		nro_status;
 };
 
 /* Header common to all requests. Do not reorder these fields, as we need

From 0aa422ff1bdb73ccc5374acfa3979e0237a09eb4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 19:42:29 +0100
Subject: [PATCH 0400/2207] nmreq: hide the pointer swapping details

---
 sys/dev/netmap/netmap.c | 105 +++++++++++++++++++++-------------------
 sys/net/netmap.h        |   1 +
 2 files changed, 56 insertions(+), 50 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e12ab379f..848bca59c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2191,9 +2191,8 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
-static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
-static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
-struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+static int nmreq_copyin(struct nmreq_header *, int);
+static int nmreq_copyout(struct nmreq_header *, int);
 static int nmreq_checkoptions(struct nmreq_header *);
 
 /*
@@ -2227,9 +2226,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	switch (cmd) {
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
-		size_t nr_body_size = nmreq_size_by_type(hdr->nr_reqtype);
-		/* Original hdr->nr_body to user-space pointer. */
-		char *usr_nr_body = NULL;
 
 		if (hdr->nr_version != NETMAP_API) {
 			D("API mismatch for reqtype %d: got %d need %d",
@@ -2242,27 +2238,15 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			return EINVAL;
 		}
 
-		if ((nr_body_size && hdr->nr_body == NULL) ||
-			(!nr_body_size && hdr->nr_body != NULL)) {
-			/* Request body expected, but not found; or
-			 * request body found but unexpected. */
-			return EINVAL;
-		}
-
-		BUG_ON(!nr_body_is_user && hdr->nr_options);
-
-		if (nr_body_is_user && nr_body_size) {
-			char *ker_nr_body;
-
-			/* Make a kernel-space copy of the user-space nr_body.
-			 * It's handy to temporarily replace hdr->nr_body with
-			 * a pointer to the kernel-space nr_body. */
-			ker_nr_body = nmreq_copyin(hdr, nr_body_size, &error);
-			if (!ker_nr_body) {
-				return error;
-			}
-			usr_nr_body = hdr->nr_body;
-			hdr->nr_body = ker_nr_body;
+		/* Make a kernel-space copy of the user-space nr_body.
+		 * For convenince, the nr_body pointer and the pointers
+		 * in the options list will be replaced with their
+		 * kernel-space counterparts. The original pointers are
+                * saved internally and later restored by nmreq_copyout
+                */
+		error = nmreq_copyin(hdr, nr_body_is_user);
+		if (error) {
+			return error;
 		}
 
 		/* Sanitize hdr->nr_name. */
@@ -2558,16 +2542,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 		}
-		if (nr_body_is_user && nr_body_size) {
-			char *ker_nr_body;
-			KASSERT(usr_nr_body && hdr->nr_body,
-				"nr_body pointers must not be NULL");
-			/* Write back request body to userspace and reset the
-			 * user-space pointer. */
-			ker_nr_body = hdr->nr_body;
-			hdr->nr_body = usr_nr_body;
-			error = nmreq_copyout(hdr, ker_nr_body, nr_body_size, error);
-		}
+		/* Write back request body to userspace and reset the
+		 * user-space pointer. */
+		error = nmreq_copyout(hdr, error);
 		break;
 	}
 
@@ -2687,22 +2664,38 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 	return 0;
 }
 
-static void *
-nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
+int
+nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
-	size_t bufsz, rqsz;
+	size_t bufsz, rqsz, bodysz;
 	int error;
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src;
 	struct nmreq_option buf;
 	void **ptrs;
 
+	if (hdr->nr_reserved)
+		return EINVAL;
+
+	hdr->nr_reserved = nr_body_is_user;
+
+	if (!nr_body_is_user)
+		return 0;
+
 	/* compute the total size of the buffer */
 	rqsz = nmreq_size_by_type(hdr->nr_reqtype);
 	if (rqsz > NETMAP_REQ_MAXSIZE) {
 		error = EMSGSIZE;
 		goto out_err;
 	}
+	if ((rqsz && hdr->nr_body == NULL) ||
+		(!rqsz && hdr->nr_body != NULL)) {
+		/* Request body expected, but not found; or
+		 * request body found but unexpected. */
+		error = EINVAL;
+		goto out_err;
+	}
+
 	bodysz = 2 * sizeof(void *) + rqsz;
 	for (src = hdr->nr_options; src; src = src->nro_next) {
 		size_t optsz;
@@ -2737,6 +2730,8 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 	error = copyin(hdr->nr_body, p, rqsz);
 	if (error)
 		goto out_err;
+	/* overwrite the user pointer with the in-kernel one */
+	hdr->nr_body = p;
 	p += rqsz;
 
 	/* copy the options */
@@ -2778,34 +2773,42 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 		next = &opt->nro_next;
 		src = *next;
 	}
-	/* skip the option list head */
-	return ker + 2 * sizeof(void *);
+	return 0;
 
 out_err:
 	if (ker)
 		nm_os_free(ker);
-	if (perror)
-		*perror = error;
-	return NULL;
+	return error;
 }
 
 static int
-nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
+nmreq_copyout(struct nmreq_header *hdr, int error)
 {
 	struct nmreq_option *src, *dst;
-	void **ptrs = ker;
+	void *ker = hdr->nr_body;
+	void **ptrs;
+	size_t bodysz;
+
+	if (!hdr->nr_reserved)
+		return error;
 
 	if (error)
 		goto out;
 
+	/* restore the user pointers in the header */
+	ptrs = (void **)ker;
+	hdr->nr_body = *(ptrs - 2);
+	src = hdr->nr_options;
+	hdr->nr_options = *(ptrs - 1);
+
 	/* copy the body */
-	error = copyout(ker, *(ptrs - 2), bodysz);
+	bodysz = nmreq_size_by_type(hdr->nr_reqtype);
+	error = copyout(ker, hdr->nr_body, bodysz);
 	if (error)
 		goto out;
 
 	/* copy the options */
-	dst = *(ptrs - 1);
-	src = hdr->nr_options;
+	dst = hdr->nr_options;
 	while (src) {
 		size_t optsz;
 		struct nmreq_option *next;
@@ -2831,6 +2834,8 @@ nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
 		dst = *ptrs;
 	}
 
+	hdr->nr_reserved = 0;
+
 out:
 	nm_os_free(ker);
 	return error;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index eb6e29be1..136264228 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -482,6 +482,7 @@ struct nmreq_option {
 struct nmreq_header {
 	uint16_t		nr_version;	/* API version */
 	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+	uint32_t		nr_reserved;	/* must be zero */
 #define NETMAP_REQ_IFNAMSIZ	64
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	struct nmreq_option	*nr_options;	/* command-specific options */

From 041db0a59413164f9907b2d8c3c57c665adfea96 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 30 Jan 2018 17:03:39 +0100
Subject: [PATCH 0401/2207] testmmap: initial support for new API

---
 utils/testmmap.c | 333 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 302 insertions(+), 31 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 5da4cea89..d9a8ff732 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -146,8 +146,9 @@ void do_close()
 #include 
 #include 
 
-struct nmreq curr_nmr = { .nr_version = NETMAP_API, .nr_flags = NR_REG_ALL_NIC, };
-char nmr_name[64];
+/* legacy */
+struct nmreq curr_nmr = { .nr_version = 11, .nr_flags = NR_REG_ALL_NIC, };
+char nmr_name[256];
 
 void parse_nmr_config(char* w, struct nmreq *nmr)
 {
@@ -179,7 +180,7 @@ void parse_nmr_config(char* w, struct nmreq *nmr)
 	}
 }
 
-void do_getinfo()
+void do_getinfo_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -213,7 +214,7 @@ void do_getinfo()
 }
 
 
-void do_regif()
+void do_regif_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -810,7 +811,7 @@ nmr_arg_extra()
 }
 
 void
-do_nmr_dump()
+do_nmr_legacy_dump()
 {
 	u_int ringid = curr_nmr.nr_ringid & NETMAP_RING_MASK;
 	nmr_arg_interp_fun arg_interp;
@@ -953,7 +954,7 @@ do_nmr_dump()
 }
 
 void
-do_nmr_reset()
+do_nmr_legacy_reset()
 {
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
@@ -961,7 +962,7 @@ do_nmr_reset()
 }
 
 void
-do_nmr_name()
+do_nmr_legacy_name()
 {
 	char *name = nextarg();
 	if (name) {
@@ -973,7 +974,7 @@ do_nmr_name()
 }
 
 void
-do_nmr_ringid()
+do_nmr_legacy_ringid()
 {
 	char *arg;
 	uint16_t ringid = curr_nmr.nr_ringid;
@@ -998,7 +999,7 @@ do_nmr_ringid()
 }
 
 void
-do_nmr_cmd()
+do_nmr_legacy_cmd()
 {
 	char *arg = nextarg();
 	if (arg == NULL)
@@ -1032,7 +1033,7 @@ do_nmr_cmd()
 }
 
 void
-do_nmr_flags()
+do_nmr_legacy_flags()
 {
 	char *arg;
 	uint32_t flags = curr_nmr.nr_flags;
@@ -1075,54 +1076,56 @@ do_nmr_flags()
 	output("flags=%x", curr_nmr.nr_flags);
 }
 
-struct cmd_def nmr_commands[] = {
-	{ "dump",	do_nmr_dump },
-	{ "reset",	do_nmr_reset },
-	{ "name",	do_nmr_name },
-	{ "ringid",	do_nmr_ringid },
-	{ "cmd",	do_nmr_cmd },
-	{ "flags",	do_nmr_flags },
+struct cmd_def nmr_legacy_commands[] = {
+	{ "dump",	do_nmr_legacy_dump },
+	{ "reset",	do_nmr_legacy_reset },
+	{ "name",	do_nmr_legacy_name },
+	{ "ringid",	do_nmr_legacy_ringid },
+	{ "cmd",	do_nmr_legacy_cmd },
+	{ "flags",	do_nmr_legacy_flags },
 };
 
-const int N_NMR_CMDS = sizeof(nmr_commands) / sizeof(struct cmd_def);
+const int N_NMR_LEGACY_CMDS = sizeof(nmr_legacy_commands) / sizeof(struct cmd_def);
 
 int
-find_nmr_command(const char *cmd)
+find_nmr_legacy_command(const char *cmd)
 {
-	return _find_command(nmr_commands, N_NMR_CMDS, cmd);
+	return _find_command(nmr_legacy_commands, N_NMR_LEGACY_CMDS, cmd);
 }
 
-#define nmr_arg_update(f) 				\
+#define __nmr_arg_update(nmr, f) 			\
 	({						\
 		int __ret = 0;				\
 		if (strcmp(cmd, #f) == 0) {		\
 			char *arg = nextarg();		\
 			if (arg) {			\
-				curr_nmr.nr_##f = strtol(arg, NULL, 0); \
+				curr_##nmr.nr_##f = strtol(arg, NULL, 0); \
 			}				\
-			output(#f "=%d", curr_nmr.nr_##f);	\
+			output(#f "=%d", curr_##nmr.nr_##f);	\
 			__ret = 1;			\
 		} 					\
 		__ret;					\
 	})
 
+#define nmr_arg_update(f)	__nmr_arg_update(nmr, f)
+
 /* prepare the curr_nmr */
 void
-do_nmr()
+do_nmr_legacy()
 {
 	char *cmd = nextarg();
 	int i;
 
 	if (cmd == NULL) {
-		do_nmr_dump();
+		do_nmr_legacy_dump();
 		return;
 	}
 	if (cmd[0] == '.') {
 		cmd++;
 	} else {
-		i = find_nmr_command(cmd);
-		if (i < N_NMR_CMDS) {
-			nmr_commands[i].f();
+		i = find_nmr_legacy_command(cmd);
+		if (i < N_NMR_LEGACY_CMDS) {
+			nmr_legacy_commands[i].f();
 			return;
 		}
 	}
@@ -1143,14 +1146,280 @@ do_nmr()
 	output("unknown field: %s", cmd);
 }
 
+/****************************************************************
+ * new API							*
+ ****************************************************************/
+
+static struct nmreq_header curr_hdr = { .nr_version = NETMAP_API };
+static struct nmreq_register curr_register;
+static struct nmreq_port_info_get curr_port_info_get;
+static struct nmreq_vale_attach curr_vale_attach;
+static struct nmreq_vale_list curr_vale_list;
+static struct nmreq_port_hdr curr_port_hdr;
+static struct nmreq_vale_newif curr_vale_newif;
+static struct nmreq_vale_polling curr_vale_polling;
+static struct nmreq_pools_info_get curr_pools_info_get;
+
+typedef void (*nmr_body_dump_fun)(void *);
+
+static void
+nmr_body_dump_register(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_port_info_get(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_attach(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_list(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_port_hdr(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_newif(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_polling(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_pools_info_get(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_option_dump(struct nmreq_option *opt)
+{
+	(void)opt;
+}
+
+static void
+do_hdr_dump()
+{
+	struct nmreq_option *opt;
+	nmr_body_dump_fun body_dump = NULL;
+
+	snprintf(nmr_name, NETMAP_REQ_IFNAMSIZ + 1, "%s", curr_hdr.nr_name);
+	nmr_name[NETMAP_REQ_IFNAMSIZ] = '\0';
+	printf("version:   %d\n", curr_hdr.nr_version);
+	printf("reqtype:   %d [", curr_hdr.nr_reqtype);
+	switch (curr_hdr.nr_reqtype) {
+	case NETMAP_REQ_REGISTER:
+		printf("register");
+		body_dump = nmr_body_dump_register;
+		break;
+	case NETMAP_REQ_PORT_INFO_GET:
+		printf("info-get");
+		body_dump = nmr_body_dump_port_info_get;
+		break;
+	case NETMAP_REQ_VALE_ATTACH:
+		printf("vale-attach");
+		body_dump = nmr_body_dump_vale_attach;
+		break;
+	case NETMAP_REQ_VALE_DETACH:
+		printf("vale-detach");
+		break;
+	case NETMAP_REQ_VALE_LIST:
+		printf("vale-list");
+		body_dump = nmr_body_dump_vale_list;
+		break;
+	case NETMAP_REQ_PORT_HDR_SET:
+		printf("port-hdr-set");
+		body_dump = nmr_body_dump_port_hdr;
+		break;
+	case NETMAP_REQ_PORT_HDR_GET:
+		printf("port-hdr-get");
+		body_dump = nmr_body_dump_port_hdr;
+		break;
+	case NETMAP_REQ_VALE_NEWIF:
+		printf("vale-newif");
+		body_dump = nmr_body_dump_vale_newif;
+		break;
+	case NETMAP_REQ_VALE_DELIF:
+		printf("vale-delif");
+		break;
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+		printf("vale-polliing-enable");
+		body_dump = nmr_body_dump_vale_polling;
+		break;
+	case NETMAP_REQ_VALE_POLLING_DISABLE:
+		printf("vale-polling-disable");
+		body_dump = nmr_body_dump_vale_polling;
+		break;
+	case NETMAP_REQ_POOLS_INFO_GET:
+		printf("pools-info-get");
+		body_dump = nmr_body_dump_pools_info_get;
+		break;
+	default:
+		printf("???");
+		break;
+	}
+	printf("]\n");
+	printf("name: %s\n", nmr_name);
+	opt = curr_hdr.nr_options;
+	printf("options:   %p\n", opt);
+	while (opt) {
+		nmr_option_dump(opt);
+		opt = opt->nro_next;
+	}
+	printf("body:	   %p\n", curr_hdr.nr_body);
+	if (body_dump)
+		body_dump(curr_hdr.nr_body);
+}
+
+static void
+do_hdr_reset()
+{
+	memset(&curr_hdr, 0, sizeof(curr_hdr));
+	curr_hdr.nr_version = NETMAP_API;
+}
+
+void
+do_hdr_name()
+{
+	char *name = nextarg();
+	if (name) {
+		strncpy(curr_hdr.nr_name, name, NETMAP_REQ_IFNAMSIZ);
+	}
+	strncpy(nmr_name, curr_hdr.nr_name, NETMAP_REQ_IFNAMSIZ);
+	nmr_name[NETMAP_REQ_IFNAMSIZ] = '\0';
+	output("name=%s", nmr_name);
+}
+
+
+static void
+do_hdr_type()
+{
+	char *type = nextarg();
+
+	if (strcmp(type, "register") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+		curr_hdr.nr_body = &curr_register;
+	} else if (strcmp(type, "info-get") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+		curr_hdr.nr_body = &curr_port_info_get;
+	} else if (strcmp(type, "vale-attach") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+		curr_hdr.nr_body = &curr_vale_attach;
+	} else if (strcmp(type, "vale-detach") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	} else if (strcmp(type, "vale-list") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+		curr_hdr.nr_body = &curr_vale_list;
+	} else if (strcmp(type, "port-hdr-set") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+		curr_hdr.nr_body = &curr_port_hdr;
+	} else if (strcmp(type, "port-hdr-get") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+		curr_hdr.nr_body = &curr_port_hdr;
+	} else if (strcmp(type, "vale-newif") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+		curr_hdr.nr_body = &curr_vale_newif;
+	} else if (strcmp(type, "vale-delif") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+	} else if (strcmp(type, "vale-polliing-enable") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+		curr_hdr.nr_body = &curr_vale_polling;
+	} else if (strcmp(type, "vale-polling-disable") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+		curr_hdr.nr_body = &curr_vale_polling;
+	} else if (strcmp(type, "pools-info-get") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+		curr_hdr.nr_body = &curr_pools_info_get;
+	} else {
+		output("unknown type: %s", type);
+	}
+}
+
+static void
+do_hdr_option()
+{
+}
+
+struct cmd_def hdr_commands[] = {
+	{ "dump",	do_hdr_dump },
+	{ "reset",	do_hdr_reset },
+	{ "name",	do_hdr_name },
+	{ "type",	do_hdr_type },
+	{ "option",	do_hdr_option },
+};
+
+const int N_HDR_CMDS = sizeof(hdr_commands) / sizeof(struct cmd_def);
+
+int
+find_hdr_command(const char *cmd)
+{
+	return _find_command(hdr_commands, N_HDR_CMDS, cmd);
+}
+
+
+
+static void
+do_hdr()
+{
+	char *cmd = nextarg();
+	int i;
+
+	if (cmd == NULL) {
+		do_hdr_dump();
+		return;
+	}
+	i = find_hdr_command(cmd);
+	if (i < N_HDR_CMDS) {
+		hdr_commands[i].f();
+		return;
+	}
+	output("unknown command: %s", cmd);
+}
+
+static void
+do_ctrl()
+{
+	char *arg;
+	int fd, ret;
+
+	arg = nextarg();
+	if (!arg) {
+		fd = last_fd;
+		goto doit;
+	}
+	fd = atoi(arg);
+doit:
+	ret = ioctl(fd, NIOCCTRL, &curr_hdr);
+	output_err(ret, "ioctl(%d, NIOCCTL, %p)=%d", fd, &curr_hdr, ret);
+
+}
 
 
 struct cmd_def commands[] = {
 	{ "open",	do_open,	},
 	{ "close", 	do_close,	},
 #ifdef TEST_NETMAP
-	{ "getinfo",	do_getinfo,	},
-	{ "regif",	do_regif,	},
+	{ "getinfo-legacy",	do_getinfo_legacy,	},
+	{ "regif-legacy",	do_regif_legacy,	},
 	{ "txsync",	do_txsync,	},
 	{ "rxsync",	do_rxsync,	},
 #endif /* TEST_NETMAP */
@@ -1166,7 +1435,9 @@ struct cmd_def commands[] = {
 	{ "ring",       do_ring,        },
 	{ "slot",       do_slot,        },
 	{ "buf",        do_buf,         },
-	{ "nmr",	do_nmr,		}
+	{ "nmr-legacy",	do_nmr_legacy,	},
+	{ "hdr",	do_hdr,		},
+	{ "ctrl",	do_ctrl		}
 };
 
 const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);

From 50c12cabc5d5d3aac0e227d7adca189e4ccebffc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 30 Jan 2018 17:55:09 +0100
Subject: [PATCH 0402/2207] testmmap: initial support for request options

---
 utils/testmmap.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d9a8ff732..1cca4bb8f 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1213,7 +1213,23 @@ nmr_body_dump_pools_info_get(void *b)
 static void
 nmr_option_dump(struct nmreq_option *opt)
 {
-	(void)opt;
+	printf("type: %u [", opt->nro_reqtype);
+	switch (opt->nro_reqtype) {
+	case NETMAP_REQ_OPT_EXTMEM:
+		printf("extmem");
+		break;
+	default:
+#ifdef NETMAP_OPT_DEBUG
+		if (opt->nro_reqtype & NETMAP_REQ_OPT_DEBUG) {
+			printf("debug: %u",
+				(opt->nro_reqtype & ~NETMAP_REQ_OPT_DEBUG));
+			break;
+		}
+#endif /* NETMAP_OPT_DEBUG */
+		printf("???");
+	}
+	printf("]\n");
+	printf("next: %p\n", opt->nro_next);
 }
 
 static void
@@ -1293,8 +1309,15 @@ do_hdr_dump()
 static void
 do_hdr_reset()
 {
+	struct nmreq_option *opt = curr_hdr.nr_options;
+	while (opt) {
+		struct nmreq_option *next = opt->nro_next;
+		free(opt);
+		opt = next;
+	}
 	memset(&curr_hdr, 0, sizeof(curr_hdr));
 	curr_hdr.nr_version = NETMAP_API;
+
 }
 
 void
@@ -1357,6 +1380,29 @@ do_hdr_type()
 static void
 do_hdr_option()
 {
+	char *type;
+	struct nmreq_option **ptr = &curr_hdr.nr_options,
+			    *old = *ptr;
+	size_t sz = sizeof(struct nmreq_option);
+
+	while ( (type = nextarg()) ) {
+		uint16_t reqtype;
+
+		if (strcmp(type, "extmem") == 0) {
+			reqtype = NETMAP_REQ_OPT_EXTMEM;
+#ifdef NETMAP_OPT_DEBUG
+		} else {
+			reqtype = atoi(type) | NETMAP_REQ_OPT_DEBUG;
+#endif /* NETMAP_OPT_DEBUG */
+		}
+		*ptr = malloc(sz);	
+		if (*ptr == NULL) {
+			output_err(-1, "malloc");
+		}
+		(*ptr)->nro_reqtype = reqtype;
+		ptr = &(*ptr)->nro_next;
+	}
+	*ptr = old;
 }
 
 struct cmd_def hdr_commands[] = {

From b3ec54f9042ebc328ca1e1c7b15bf592bdda8a00 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 13:55:04 +0100
Subject: [PATCH 0403/2207] testmmap: register command

---
 utils/testmmap.c | 219 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 204 insertions(+), 15 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 1cca4bb8f..526ea5465 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1093,18 +1093,19 @@ find_nmr_legacy_command(const char *cmd)
 	return _find_command(nmr_legacy_commands, N_NMR_LEGACY_CMDS, cmd);
 }
 
-#define __nmr_arg_update(nmr, f) 			\
-	({						\
-		int __ret = 0;				\
-		if (strcmp(cmd, #f) == 0) {		\
-			char *arg = nextarg();		\
-			if (arg) {			\
-				curr_##nmr.nr_##f = strtol(arg, NULL, 0); \
-			}				\
-			output(#f "=%d", curr_##nmr.nr_##f);	\
-			__ret = 1;			\
-		} 					\
-		__ret;					\
+#define __nmr_arg_update(nmr, f) 					\
+	({								\
+		int __ret = 0;						\
+		if (strcmp(cmd, #f) == 0) {				\
+			char *arg = nextarg();				\
+			if (arg) {					\
+				curr_##nmr.nr_##f = strtol(arg, NULL, 0);\
+			}						\
+			output(#f "=%llu",				\
+				(unsigned long long)curr_##nmr.nr_##f);	\
+			__ret = 1;					\
+		} 							\
+		__ret;							\
 	})
 
 #define nmr_arg_update(f)	__nmr_arg_update(nmr, f)
@@ -1165,7 +1166,194 @@ typedef void (*nmr_body_dump_fun)(void *);
 static void
 nmr_body_dump_register(void *b)
 {
-	(void)b;
+	struct nmreq_register *r = b;
+	int flags = 0;
+	printf("offset:    %"PRIu64"\n", r->nr_offset);
+	printf("memsize:   %"PRIu64" [", r->nr_memsize);
+	if (r->nr_memsize < (1<<20)) {
+		printf("%"PRIu64" KiB", r->nr_memsize >> 10);
+	} else {
+		printf("%"PRIu64" MiB", r->nr_memsize >> 20);
+	}
+	printf("]\n");
+	printf("tx_slots:  %"PRIu16"\n", r->nr_tx_slots);
+	printf("rx_slots:  %"PRIu16"\n", r->nr_rx_slots);
+	printf("tx_rings:  %"PRIu16"\n", r->nr_tx_rings);
+	printf("rx_rings:  %"PRIu16"\n", r->nr_rx_rings);
+	printf("mem_id:    %"PRIu16" [%s memory region]\n", r->nr_mem_id,
+		(r->nr_mem_id == 0 ? "default" :
+		 r->nr_mem_id == 1 ? "global"  : "private"));
+	printf("ringid     %"PRIu16"\n", r->nr_ringid);
+	printf("mode       %"PRIu32" [", r->nr_mode);
+	switch (r->nr_mode) {
+	case NR_REG_DEFAULT:
+		printf("*DEFAULT");
+		break;
+	case NR_REG_ALL_NIC:
+		printf("ALL_NIC");
+		break;
+	case NR_REG_SW:
+		printf("SW");
+		break;
+	case NR_REG_NIC_SW:
+		printf("NIC_SW");
+		break;
+	case NR_REG_ONE_NIC:
+		printf("ONE_NIC(%"PRIu16")", r->nr_ringid);
+		break;
+	case NR_REG_PIPE_MASTER:
+		printf("*PIPE_MASTER(%d)", r->nr_ringid);
+		break;
+	case NR_REG_PIPE_SLAVE:
+		printf("*PIPE_SLAVE(%d)", r->nr_ringid);
+		break;
+	default:
+		printf("???");
+		break;
+	}
+	printf("]\n");
+	printf("flags:     %lx [", r->nr_flags);
+#define pflag(f) if (r->nr_flags & NR_##f) { printf("%s" #f, flags++ ? ", " : ""); }
+	pflag(MONITOR_TX);
+	pflag(MONITOR_RX);
+	pflag(ZCOPY_MON);
+	pflag(EXCLUSIVE);
+	pflag(PTNETMAP_HOST);
+	pflag(RX_RINGS_ONLY);
+	pflag(TX_RINGS_ONLY);
+	pflag(ACCEPT_VNET_HDR);
+	pflag(DO_RX_POLL);
+	pflag(NO_TX_POLL);
+#undef pflag
+	printf("]\n");
+	printf("extra_bufs %"PRIu32"\n", r->nr_extra_bufs);
+}
+
+static void
+do_register_dump()
+{
+	nmr_body_dump_register(&curr_register);
+}
+
+static void
+do_register_reset()
+{
+	memset(&curr_register, 0, sizeof(curr_register));
+}
+
+static void
+do_register_mode()
+{
+	char *mode = nextarg();
+
+	if (mode == NULL)
+		goto out;
+
+	if (strcmp(mode, "default") == 0) {
+		curr_register.nr_mode = NR_REG_DEFAULT;
+	} else if (strcmp(mode, "all-nic") == 0) {
+		curr_register.nr_mode = NR_REG_ALL_NIC;
+	} else if (strcmp(mode, "sw") == 0) {
+		curr_register.nr_mode = NR_REG_SW;
+	} else if (strcmp(mode, "nic-sw") == 0) {
+		curr_register.nr_mode = NR_REG_NIC_SW;
+	} else if (strcmp(mode, "one-nic") == 0) {
+		curr_register.nr_mode = NR_REG_ONE_NIC;
+	} else if (strcmp(mode, "pipe-master") == 0) {
+		curr_register.nr_mode = NR_REG_PIPE_MASTER;
+	} else if (strcmp(mode, "pipe-slave") == 0) {
+		curr_register.nr_mode = NR_REG_PIPE_SLAVE;
+	}
+
+out:
+	output("mode=%"PRIu32, curr_register.nr_mode);
+}
+
+void
+do_register_flags()
+{
+	char *arg;
+	uint64_t flags = curr_register.nr_flags;
+	int n;
+	for (n = 0, arg = nextarg(); arg; arg = nextarg(), n++) {
+		if (strcmp(arg, "monitor-tx") == 0) {
+			flags |= NR_MONITOR_TX;
+		} else if (strcmp(arg, "monitor-rx") == 0) {
+			flags |= NR_MONITOR_RX;
+		} else if (strcmp(arg, "zcopy-mon") == 0) {
+			flags |= NR_ZCOPY_MON;
+		} else if (strcmp(arg, "exclusive") == 0) {
+			flags |= NR_EXCLUSIVE;
+		} else if (strcmp(arg, "ptnetmap-host") == 0) {
+			flags |= NR_PTNETMAP_HOST;
+		} else if (strcmp(arg, "rx-rings-only") == 0) {
+			flags |= NR_RX_RINGS_ONLY;
+		} else if (strcmp(arg, "tx-rings-only") == 0) {
+			flags |= NR_TX_RINGS_ONLY;
+		} else if (strcmp(arg, "accept-vnet-hdr") == 0) {
+			flags |= NR_ACCEPT_VNET_HDR;
+		} else if (strcmp(arg, "do-rx-poll") == 0) {
+			flags |= NR_DO_RX_POLL;
+		} else if (strcmp(arg, "no-tx-poll") == 0) {
+			flags |= NR_NO_TX_POLL;
+		} else if (strcmp(arg, "reset") == 0) {
+			flags = 0;
+		}
+	}
+	if (n)
+		curr_register.nr_flags = flags;
+	output("flags=%lx", curr_register.nr_flags);
+}
+
+struct cmd_def register_commands[] = {
+	{ "dump",	do_register_dump },
+	{ "reset",	do_register_reset },
+	{ "mode",	do_register_mode },
+	{ "flags",	do_register_flags },
+};
+
+const int N_REGISTER_CMDS = sizeof(register_commands) / sizeof(struct cmd_def);
+
+int
+find_register_command(const char *cmd)
+{
+	return _find_command(register_commands, N_REGISTER_CMDS, cmd);
+}
+
+#define register_update(f) __nmr_arg_update(register, f)
+
+void
+do_register()
+{
+	char *cmd = nextarg();
+	int i;
+
+	if (cmd == NULL) {
+		do_register_dump();
+		return;
+	}
+	if (cmd[0] == '.') {
+		cmd++;
+	} else {
+		i = find_register_command(cmd);
+		if (i < N_REGISTER_CMDS) {
+			register_commands[i].f();
+			return;
+		}
+	}
+	if (register_update(offset) 
+	||  register_update(memsize) 
+	||  register_update(tx_slots) 
+	||  register_update(rx_slots) 
+	||  register_update(tx_rings) 
+	||  register_update(rx_rings) 
+	||  register_update(mem_id) 
+	||  register_update(ringid) 
+	||  register_update(mode) 
+	||  register_update(flags)
+	||  register_update(extra_bufs))
+		return;
+	output("unknown field: %s", cmd);
 }
 
 static void
@@ -1392,7 +1580,7 @@ do_hdr_option()
 			reqtype = NETMAP_REQ_OPT_EXTMEM;
 #ifdef NETMAP_OPT_DEBUG
 		} else {
-			reqtype = atoi(type) | NETMAP_REQ_OPT_DEBUG;
+			reqtype = strtol(type, NULL, 0) | NETMAP_REQ_OPT_DEBUG;
 #endif /* NETMAP_OPT_DEBUG */
 		}
 		*ptr = malloc(sz);	
@@ -1483,7 +1671,8 @@ struct cmd_def commands[] = {
 	{ "buf",        do_buf,         },
 	{ "nmr-legacy",	do_nmr_legacy,	},
 	{ "hdr",	do_hdr,		},
-	{ "ctrl",	do_ctrl		}
+	{ "ctrl",	do_ctrl		},
+	{ "register",	do_register	}
 };
 
 const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);

From fad32f057f3af8ba7e859d201d680d37d3f55abf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 14:05:47 +0100
Subject: [PATCH 0404/2207] testmmap: print hdr type after update

---
 utils/testmmap.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 526ea5465..a4aba5f24 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1563,6 +1563,7 @@ do_hdr_type()
 	} else {
 		output("unknown type: %s", type);
 	}
+	output("type=%u", curr_hdr.nr_reqtype);
 }
 
 static void

From b638964e2257b09ebd33e7693c7aa9ba2f1a92cd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Mar 2017 11:26:36 +0100
Subject: [PATCH 0405/2207] extmem: user-supplied netmap memory region

With this feature a user application may allocate its own memory
(e.g., via mmap()) and pass it to netmap while registering (NIOCREGIF)
an interface.  If the interface was not already registered, it will pin
the underlying pages in memory and use them for its own netmap_if's,
netmap_ring's and buffers.

Example usage:

  void *mem = mmap(...);
  /* the user must fill a netmap_pools_info header before passing
   * the region to netmap;
   * the header is used to split the region into netmap_if's,
   * netmap_ring's and buffers
   */
  struct netmap_pools_info *pi = mem;
  pi->ring_pool_objtotal = 100;   /* how many rings */
  pi->buf_pool_objtotal = 100000; /* how many buffers */
  /* etc. */
  struct nmreq req;
  /* other nmreq initializations... */
  nmreq_pointer_put(&req, mem);
  req.nr_cmd = NETMAP_POOLS_CREATE;
  fd = open("/dev/netmap");
  ioctl(fd, NIOCREGIF, &req);
  /* pi is now filled with the actual values used */

Possible uses:
- support of hugepages
- persistent memory (e.g., PASTE)

Bugs:
- while a port is registered in this way, no other application can
  open it, not even on non intersecting sets of rings (this may actually
  be a feature);
- each netmap_if, netmap_ring and buffer needs to be contiguous in
  physical memory; netmap_ring's, in particular, are usually bigger
  than 4KiB and netmap may fail to allocate them if the user pages
  are scattered around; note, however, that this is not a problem
  for the above suggested use-cases;
- nmreq_pointer_put() overwrites nr_arg1, nr_arg2 and nr_arg3; this means
  that extra buffers cannot be asked for in the same NIOCREGIF (one may
  ask for extra buffers in another NIOCREGIF, possibily on a dummy port)
- Linux only (for now)
---
 LINUX/bsd_glue.h             |   5 +
 LINUX/configure              |  49 +++++-
 LINUX/netmap_linux.c         |   2 +
 sys/dev/netmap/netmap.c      |   1 +
 sys/dev/netmap/netmap_kern.h |   3 +
 sys/dev/netmap/netmap_mem2.c | 287 +++++++++++++++++++++++++++++++++--
 sys/dev/netmap/netmap_mem2.h |   8 +
 utils/testmmap.c             |  33 ++++
 8 files changed, 377 insertions(+), 11 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index fafde1f4d..6fbe045e2 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -57,6 +57,7 @@
 
 #include 	// virt_to_phys
 #include 
+#include  // kmap
 
 #define KASSERT(a, b)		BUG_ON(!(a))
 
@@ -180,6 +181,10 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb) {
 #define NM_UNREG_NETDEV_NOTIF(nb)	unregister_netdevice_notifier(nb)
 #endif /* NETMAP_LINUX_HAVE_REG_NOTIF_RH */
 
+#ifndef NETMAP_LINUX_HAVE_PAGE_TO_VIRT
+#define page_to_virt(p) 		phys_to_virt(page_to_phys(p))
+#endif /* NETMAP_LINUX_HAVE_PAGE_TO_VIRT */
+
 /*----------- end of LINUX_VERSION_CODE dependencies ----------*/
 
 /* Type redefinitions. XXX check them */
diff --git a/LINUX/configure b/LINUX/configure
index 4b627bd6e..8e6545188 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -91,7 +91,8 @@ setop()
 }
 
 # available subsystems
-subsystem_avail="vale pipe monitor generic ptnetmap-guest ptnetmap-host sink"
+subsystem_avail="vale pipe monitor generic ptnetmap-guest ptnetmap-host sink \
+	extmem"
 #enabled subsystems (bitfield)
 subsystem=0
 
@@ -305,9 +306,10 @@ Available options:
   --disable-ptnetmap           disable ptnetmap (both guest and host)
   --enable-sink   	       enable the netmap sink device
   --disable-sink   	       disable the netmap sink device
+  --enable-extmem   	       enable the external memory allocators
+  --disable-extmem   	       disable the external memory allocators
   --force-debug	       	       build the modules w/ debug symbols (default)
   --no-force-debug	       build the modules w/ or w/o debug symbols,
-  			       according to the kernel configuration
   --cache=		       dir for reusing/caching of netmap_linux_config.h
 
   --cc=                        C compiler to be used for the apps [$cc]
@@ -1483,6 +1485,49 @@ EOF
 	}
 EOF
 
+# check for get_user_pages_unlocked number of args
+  add_test 'have GUP_4ARGS' <
+
+	long
+	dummy(unsigned long start, unsigned long nr_pages,
+		struct page **pages, unsigned int gup_flags) {
+		return get_user_pages_unlocked(start, nr_pages, pages, gup_flags);
+	}
+EOF
+
+  add_test 'have GUP_5ARGS' <
+
+	long
+	dummy(unsigned long start, unsigned long nr_pages,
+		int write, int force, struct page **pages) {
+		return get_user_pages_unlocked(start, nr_pages, write, force, pages);
+	}
+EOF
+
+  add_test 'have GUP_7ARGS' <
+
+	long
+	dummy(struct task_struct *tsk, struct mm_struct *mm,
+		unsigned long start, unsigned long nr_pages,
+		int write, int force, struct page **pages) {
+		return get_user_pages_unlocked(tsk, mm, start, nr_pages,
+			write, force, pages);
+	}
+EOF
+
+# check for page_to_virt
+  add_test 'have PAGE_TO_VIRT' <
+
+	void *
+	dummy(struct page *page) {
+		return page_to_virt(page);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 3e9978368..a70bc391c 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1014,6 +1014,8 @@ linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
 			(vma->vm_end - vma->vm_start), memsize);
 	if (off + (vma->vm_end - vma->vm_start) > memsize)
 		return -EINVAL;
+	if (memflags & NETMAP_MEM_EXT)
+		return -ENODEV;
 	if (memflags & NETMAP_MEM_IO) {
 		vm_ooffset_t pa;
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 848bca59c..b29b5d154 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3210,6 +3210,7 @@ netmap_attach_common(struct netmap_adapter *na)
 	if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
 		na->if_input = na->ifp->if_input; /* for netmap_send_up */
 	}
+	pa->pdev = na; /* make sure netmap_mem_map() is called */
 #endif /* __FreeBSD__ */
 	if (na->nm_krings_create == NULL) {
 		/* we assume that we have been called by a driver,
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 83711149f..9ec84e579 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -37,6 +37,9 @@
 
 #if defined(linux)
 
+#if defined(CONFIG_NETMAP_EXTMEM)
+#define WITH_EXTMEM
+#endif
 #if  defined(CONFIG_NETMAP_VALE)
 #define WITH_VALE
 #endif
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index b47c9ec34..cbb3848db 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -333,6 +333,7 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 		}
 	}
 
+	ND("%s free %u", p->name, p->objfree);
 	if (p->objfree == 0)
 		return ENOMEM;
 
@@ -664,7 +665,7 @@ nm_free_lut(struct lut_entry *lut, u_int objtotal)
 #endif
 }
 
-#ifdef linux
+#if defined(linux) || defined(_WIN32)
 static struct plut_entry *
 nm_alloc_plut(u_int nobj)
 {
@@ -679,7 +680,7 @@ nm_free_plut(struct plut_entry * lut)
 {
 	vfree(lut);
 }
-#endif
+#endif /* linux or _WIN32 */
 
 
 /*
@@ -999,7 +1000,7 @@ netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr)
 		ssize_t relofs = (ssize_t) vaddr - (ssize_t) base;
 
 		/* Given address, is out of the scope of the current cluster.*/
-		if (vaddr < base || relofs >= p->_clustsize)
+		if (base == NULL || vaddr < base || relofs >= p->_clustsize)
 			continue;
 
 		j = j + relofs / p->_objsize;
@@ -1291,6 +1292,11 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 	int i; /* must be signed */
 	size_t n;
 
+	if (p->lut) {
+		/* already finalized, nothing to do */
+		return 0;
+	}
+
 	/* optimistically assume we have enough memory */
 	p->numclusters = p->_numclusters;
 	p->objtotal = p->_objtotal;
@@ -1475,6 +1481,9 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	for (i = 0; i < lim; i += p->_clustentries) {
 		int j;
 
+		if (p->lut[i].vaddr == NULL)
+			continue;
+
 		error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr,
 				p->lut[i].vaddr, p->_clustsize);
 		if (error)
@@ -1532,19 +1541,21 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
 /*
  * allocator for private memory
  */
-static struct netmap_mem_d *
-_netmap_mem_private_new(struct netmap_obj_params *p, int *perr)
+static void *
+_netmap_mem_private_new(size_t size, struct netmap_obj_params *p, 
+		struct netmap_mem_ops *ops, int *perr)
 {
 	struct netmap_mem_d *d = NULL;
 	int i, err = 0;
 
-	d = nm_os_malloc(sizeof(struct netmap_mem_d));
+	d = nm_os_malloc(size);
 	if (d == NULL) {
 		err = ENOMEM;
 		goto error;
 	}
 
 	*d = nm_blueprint;
+	d->ops = ops;
 
 	err = nm_mem_assign_id(d);
 	if (err)
@@ -1633,7 +1644,7 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 			p[NETMAP_BUF_POOL].num,
 			p[NETMAP_BUF_POOL].size);
 
-	d = _netmap_mem_private_new(p, perr);
+	d = _netmap_mem_private_new(sizeof(*d), p, &netmap_mem_global_ops, perr);
 
 	return d;
 }
@@ -1680,14 +1691,14 @@ netmap_mem2_finalize(struct netmap_mem_d *nmd)
 	int err;
 
 	/* update configuration if changed */
-	if (netmap_mem2_config(nmd))
+	if (netmap_mem_config(nmd))
 		goto out1;
 
 	nmd->active++;
 
 	if (nmd->flags & NETMAP_MEM_FINALIZED) {
 		/* may happen if config is not changed */
-		ND("nothing to do");
+		D("nothing to do");
 		goto out;
 	}
 
@@ -2006,6 +2017,264 @@ netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
 	return 0;
 }
 
+#ifdef WITH_EXTMEM
+struct netmap_mem_ext {
+	struct netmap_mem_d up;
+
+	struct page **pages;
+	int nr_pages;
+};
+
+static void
+netmap_mem_ext_delete(struct netmap_mem_d *d)
+{
+	int i;
+	struct netmap_mem_ext *e =
+		(struct netmap_mem_ext *)d;
+
+	for (i = 0; i < NETMAP_POOLS_NR; i++) {
+		struct netmap_obj_pool *p = &d->pools[i];
+		
+		if (p->lut) {
+			nm_free_lut(p->lut, p->objtotal);
+			p->lut = NULL;
+		}
+	}
+	if (e->pages) {
+		for (i = 0; i < e->nr_pages; i++) {
+			kunmap(e->pages[i]);
+			put_page(e->pages[i]);
+		}
+		nm_os_free(e->pages);
+		e->pages = NULL;
+		e->nr_pages = 0;
+	}
+	netmap_mem2_delete(d);
+}
+
+static int
+netmap_mem_ext_config(struct netmap_mem_d *nmd)
+{
+	return 0;
+}
+
+struct netmap_mem_ops netmap_mem_ext_ops = {
+	.nmd_get_lut = netmap_mem2_get_lut,
+	.nmd_get_info = netmap_mem2_get_info,
+	.nmd_ofstophys = netmap_mem2_ofstophys,
+	.nmd_config = netmap_mem_ext_config,
+	.nmd_finalize = netmap_mem2_finalize,
+	.nmd_deref = netmap_mem2_deref,
+	.nmd_delete = netmap_mem_ext_delete,
+	.nmd_if_offset = netmap_mem2_if_offset,
+	.nmd_if_new = netmap_mem2_if_new,
+	.nmd_if_delete = netmap_mem2_if_delete,
+	.nmd_rings_create = netmap_mem2_rings_create,
+	.nmd_rings_delete = netmap_mem2_rings_delete
+};
+
+struct netmap_mem_d *
+netmap_mem_ext_create(struct nmreq *nmr, int *perror)
+{
+	uintptr_t p = *(uintptr_t *)&nmr->nr_arg1;
+	struct netmap_pools_info pi;
+	int error = 0;
+	unsigned long end, start;
+	int nr_pages, res, i, j;
+	struct page **pages = NULL;
+	struct netmap_mem_ext *nme;
+	char *clust;
+	size_t off;
+
+	error = copyin((void *)p, &pi, sizeof(pi));
+	if (error)
+		goto out;
+
+	// XXX sanity checks
+	if (pi.if_pool_objtotal == 0)
+		pi.if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num;
+	if (pi.if_pool_objsize == 0)
+		pi.if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size;
+	if (pi.ring_pool_objtotal == 0)
+		pi.ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num;
+	if (pi.ring_pool_objsize == 0)
+		pi.ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size;
+	if (pi.buf_pool_objtotal == 0)
+		pi.buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
+	if (pi.buf_pool_objsize == 0)
+		pi.buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
+	D("if %d %d ring %d %d buf %d %d",
+			pi.if_pool_objtotal, pi.if_pool_objsize,
+			pi.ring_pool_objtotal, pi.ring_pool_objsize,
+			pi.buf_pool_objtotal, pi.buf_pool_objsize);
+		
+	end = (p + pi.memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	start = p >> PAGE_SHIFT;
+	nr_pages = end - start;
+
+	pages = nm_os_malloc(nr_pages * sizeof(*pages));
+	if (pages == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			pages,
+			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
+#elif defined(NETMAP_LINUX_HAVE_GUP_5ARGS)
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
+	res = get_user_pages_unlocked(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#else
+	down_read(¤t->mm->mmap_sem);
+	res = get_user_pages(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages,
+			NULL);
+	up_read(¤t->mm->mmap_sem);
+#endif	/* NETMAP_LINUX_GUP */
+
+	if (res < nr_pages) {
+		error = EFAULT;
+		goto out_unmap;
+	}
+
+	nme = nm_os_malloc(sizeof(*nme));
+	if (nme == NULL) {
+		error = ENOMEM;
+		goto out_unmap;
+	}
+
+	nme = _netmap_mem_private_new(sizeof(*nme),
+			(struct netmap_obj_params[]){
+				{ pi.if_pool_objsize, pi.if_pool_objtotal },
+				{ pi.ring_pool_objsize, pi.ring_pool_objtotal },
+				{ pi.buf_pool_objsize, pi.buf_pool_objtotal }},
+			&netmap_mem_ext_ops,
+			&error);
+	if (nme == NULL)
+		goto out_unmap;
+					
+	/* from now on pages will be released by nme destructor;
+	 * we let res = 0 to prevent release in out_unmap below
+	 */
+	res = 0;
+	nme->pages = pages;
+	nme->nr_pages = nr_pages;
+	nme->up.flags |= NETMAP_MEM_EXT;
+
+	clust = kmap(*pages);
+	off = 0;
+	for (i = 0; i < NETMAP_POOLS_NR; i++) {
+		struct netmap_obj_pool *p = &nme->up.pools[i];
+		struct netmap_obj_params *o = &nme->up.params[i];
+
+		p->_objsize = o->size;
+		p->_clustsize = o->size;
+		p->_clustentries = 1;
+
+		p->lut = nm_alloc_lut(o->num);
+		if (p->lut == NULL) {
+			error = ENOMEM;
+			goto out_delete;
+		}
+
+		if (nr_pages == 0) {
+			p->objtotal = 0;
+			p->memtotal = 0;
+			p->objfree = 0;
+			continue;
+		}
+
+		for (j = 0; j < o->num && nr_pages > 0; j++) {
+			size_t noff;
+			size_t skip;
+
+			p->lut[j].vaddr = clust + off;
+			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
+			noff = off + p->_objsize;
+			if (noff < PAGE_SIZE) {
+				off = noff;
+				continue;
+			}
+			ND("too big, recomputing offset...");
+			skip = PAGE_SIZE - (off & PAGE_MASK);
+			while (noff >= PAGE_SIZE) {
+				noff -= skip;
+				pages++;
+				nr_pages--;
+				ND("noff %zu page %p nr_pages %d", noff,
+						page_to_virt(*pages), nr_pages);
+				if (noff > 0 && p->lut[j].vaddr &&
+					(nr_pages == 0 || *pages != *(pages - 1) + 1))
+				{
+					/* out of space or non contiguous,
+					 * drop this object
+					 * */
+					p->lut[j].vaddr = NULL;
+					ND("non contiguous at off %zu, drop", noff);
+				}
+				if (nr_pages == 0)
+					break;
+				skip = PAGE_SIZE;
+			}
+			off = noff;
+			clust = page_to_virt(*pages);
+		}
+		p->objtotal = j;
+		p->numclusters = p->objtotal;
+		p->memtotal = j * p->_objsize;
+		ND("%d memtotal %u", j, p->memtotal);
+	}
+
+	/* skip the first netmap_if, where the pools info reside */
+	{
+		struct netmap_obj_pool *p = &nme->up.pools[NETMAP_IF_POOL];
+		p->lut[0].vaddr = NULL;
+	}
+
+	error = netmap_mem_init_bitmaps(&nme->up);
+	if (error)
+		goto out_delete;
+
+	return &nme->up;
+
+out_delete:
+	netmap_mem_put(&nme->up);
+out_unmap:
+	for (i = 0; i < res; i++)
+		put_page(pages[i]);
+	if (res)
+		nm_os_free(pages);
+out:
+	if (perror)
+		*perror = error;
+	return NULL;
+
+}
+#endif /* WITH_EXTMEM */
+
+
 #ifdef WITH_PTNETMAP_GUEST
 struct mem_pt_if {
 	struct mem_pt_if *next;
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index ab7b143f1..ca3a6240e 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -149,6 +149,13 @@ struct netmap_mem_d* __netmap_mem_get(struct netmap_mem_d *, const char *, int);
 void __netmap_mem_put(struct netmap_mem_d *, const char *, int);
 struct netmap_mem_d* netmap_mem_find(nm_memid_t);
 
+#ifdef WITH_EXTMEM
+struct netmap_mem_d* netmap_mem_ext_create(struct nmreq *, int *);
+#else /* !WITH_EXTMEM */
+#define netmap_mem_ext_create(nmr, _perr) \
+	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
+#endif /* WITH_EXTMEM */
+
 #ifdef WITH_PTNETMAP_GUEST
 struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,
 					     unsigned int nifp_offset,
@@ -163,6 +170,7 @@ int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
 #define NETMAP_MEM_IO		0x4	/* the underlying memory is mmapped I/O */
+#define NETMAP_MEM_EXT		0x10	/* external memory (not remappable) */
 
 uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 
diff --git a/utils/testmmap.c b/utils/testmmap.c
index a4aba5f24..4cb541b05 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -335,6 +335,38 @@ void do_mmap()
 
 }
 
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000
+#endif
+
+void do_anon_mmap()
+{
+	size_t memsize;
+	char *arg;
+	int flags = 0;
+
+	arg = nextarg();
+	if (!arg) {
+		memsize = last_memsize;
+		goto doit;
+	}
+	memsize = atoi(arg);
+	arg = nextarg();
+	if (!arg)
+		goto doit;
+	flags |= MAP_HUGETLB;
+doit:
+	last_mmap_addr = mmap(0, memsize,
+			PROT_WRITE | PROT_READ,
+			MAP_PRIVATE | MAP_ANONYMOUS | flags, -1, 0);
+	if (last_access_addr == NULL)
+		last_access_addr = last_mmap_addr;
+	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
+		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS%s, -1, 0)=%p",
+		memsize, (flags ? "MAP_HUGETLB" : ""), last_mmap_addr);
+
+}
+
 void do_munmap()
 {
 	void *mmap_addr;
@@ -1660,6 +1692,7 @@ struct cmd_def commands[] = {
 #endif /* TEST_NETMAP */
 	{ "dup",	do_dup,		},
 	{ "mmap",	do_mmap,	},
+	{ "anon-mmap",	do_anon_mmap,	},
 	{ "access",	do_access,	},
 	{ "munmap",	do_munmap,	},
 	{ "poll",	do_poll,	},

From d7c8da027240f7f4f2cef68e2f32f89caf3808e8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Dec 2017 11:20:25 +0100
Subject: [PATCH 0406/2207] extmem: userspace support in nm_open()

---
 sys/net/netmap_user.h | 71 +++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 22 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 5c4b27f27..e2c30ca70 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -98,6 +98,7 @@
 #endif /* likely and unlikely */
 
 #include 
+#include  /* nmreq_pointer_get() */
 
 /* helper macro */
 #define _NETMAP_OFFSET(type, ptr, offset) \
@@ -611,6 +612,23 @@ nm_is_identifier(const char *s, const char *e)
 	return 1;
 }
 
+static void
+nm_init_offsets(struct nm_desc *d)
+{
+	struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
+	struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
+	if ((void *)r == (void *)nifp) {
+		/* the descriptor is open for TX only */
+		r = NETMAP_TXRING(nifp, d->first_tx_ring);
+	}
+
+	*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
+	*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
+	*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
+	*(void **)(uintptr_t)&d->buf_end =
+		(char *)d->mem + d->memsize;
+}
+
 #define MAXERRMSG 80
 static int
 nm_parse(const char *ifname, struct nm_desc *d, char *err)
@@ -818,6 +836,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	const struct nm_desc *parent = arg;
 	char errmsg[MAXERRMSG] = "";
 	uint32_t nr_reg;
+	struct netmap_pools_info *pi = NULL;
 
 	if (strncmp(ifname, "netmap:", 7) &&
 			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@@ -838,8 +857,23 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
-	if (req)
+	if (req) {
 		d->req = *req;
+		if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
+			if (IS_NETMAP_DESC(parent) &&
+					(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
+				snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
+				errno = EINVAL;
+				goto fail;
+			}
+		        pi = nmreq_pointer_get(&d->req);
+			if (pi == NULL) {
+				snprintf(errmsg, MAXERRMSG, "missing netmap_pools_info pointer");
+				errno = EINVAL;
+				goto fail;
+			}
+		}
+	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
 		if (nm_parse(ifname, d, errmsg) < 0)
@@ -888,6 +922,19 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
+	if (pi != NULL) {
+		d->mem = pi;
+		d->memsize = pi->memsize;
+		nm_init_offsets(d);
+	} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
+		/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
+	        errno = nm_mmap(d, parent);
+		if (errno) {
+			snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
+			goto fail;
+		}
+	}
+
 	nr_reg = d->req.nr_flags & NR_REG_MASK;
 
 	if (nr_reg == NR_REG_SW) { /* host stack */
@@ -912,13 +959,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->first_rx_ring = d->last_rx_ring = 0;
 	}
 
-        /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
-	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
-	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
-		goto fail;
-	}
-
-
 #ifdef DEBUG_NETMAP_USER
     { /* debugging code */
 	int i;
@@ -996,21 +1036,8 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 		}
 		d->done_mmap = 1;
 	}
-	{
-		struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
-		struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
-		if ((void *)r == (void *)nifp) {
-			/* the descriptor is open for TX only */
-			r = NETMAP_TXRING(nifp, d->first_tx_ring);
-		}
-
-		*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
-		*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
-		*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
-		*(void **)(uintptr_t)&d->buf_end =
-			(char *)d->mem + d->memsize;
-	}
 
+	nm_init_offsets(d);
 	return 0;
 
 fail:

From 744a1aa360c526c38323666fd2aea83dcf69e2a5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 3 Apr 2017 11:50:42 +0200
Subject: [PATCH 0407/2207] testmmap: pools-info command

---
 sys/net/netmap_virt.h |  7 ++++
 utils/testmmap.c      | 79 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 76f5cbb28..3007bbf82 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -121,6 +121,13 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 	*pp = (uintptr_t)userptr;
 }
 
+static inline void *
+nmreq_pointer_get(struct nmreq *nmr)
+{
+	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+	return (void *)*pp;
+}
+
 /* ptnetmap features */
 #define PTNETMAP_F_VNET_HDR        1
 
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 4cb541b05..7d46fb529 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -2,6 +2,7 @@
 
 #include 
 #include 	/* ULONG_MAX */
+#include 
 #include 
 #include 
 #include 
@@ -747,6 +748,84 @@ int _find_command(const struct cmd_def *cmds, int ncmds, const char* cmd)
 	return i;
 }
 
+struct pools_info_field {
+	char *name;
+	size_t off;
+	size_t size;
+};
+#define PIFD(n, f)	{ n, offsetof(struct netmap_pools_info, f), \
+	sizeof(((struct netmap_pools_info *)0)->f) }
+struct pools_info_field pools_info_fields[] = {
+	PIFD("memsize", memsize),
+	PIFD("memid", memid),
+	PIFD("if-off", if_pool_offset),
+	PIFD("if-tot", if_pool_objtotal),
+	PIFD("if-siz", if_pool_objsize),
+	PIFD("ring-off", ring_pool_offset),
+	PIFD("ring-tot", ring_pool_objtotal),
+	PIFD("ring-siz", ring_pool_objsize),
+	PIFD("buf-off", buf_pool_offset),
+	PIFD("buf-tot", buf_pool_objtotal),
+	PIFD("buf-siz", buf_pool_objsize),
+	{ NULL, 0, 0 }
+};
+#define PIF(t, p, o)	(*(t*)((void *)((char *)(p)+(o))))
+void
+pools_info_dump(int tab, struct netmap_pools_info *upi)
+{
+	static const char space[] = "        ";
+	struct pools_info_field *f;
+	for (f = pools_info_fields; f->name; f++) {
+		printf("%.*s%-12s", tab, space, f->name);
+		switch (f->size) {
+		case 8:
+			printf("%"PRIu64"\n", PIF(uint64_t, upi, f->off));
+			break;
+		case 4:
+			printf("%"PRIu32"\n", PIF(uint32_t, upi, f->off));
+			break;
+		case 2:
+			printf("%"PRIu16"\n", PIF(uint16_t, upi, f->off));
+			break;
+		}
+	}
+}
+
+/* prepare the curr_pools_info */
+void
+do_pools_info()
+{
+	char *cmd = nextarg();
+	unsigned long long v;
+
+	if (cmd == NULL) {
+		pools_info_dump(0, &curr_pools_info);
+		return;
+	}
+	struct pools_info_field *f = NULL;
+	for (f = pools_info_fields; f->name; f++) {
+		if (strcmp(f->name, cmd) == 0)
+			break;
+	}
+	if (f == NULL)
+		return;
+	cmd = nextarg();
+	if (cmd == NULL)
+		return;
+	v = strtoll(cmd, NULL, 0);
+	switch (f->size) {
+	case 8:
+		PIF(uint64_t, &curr_pools_info, f->off) = v;
+		break;
+	case 4:
+		PIF(uint32_t, &curr_pools_info, f->off) = v;
+		break;
+	case 2:
+		PIF(uint16_t, &curr_pools_info, f->off) = v;
+		break;
+	}
+}
+
 typedef void (*nmr_arg_interp_fun)();
 
 #define nmr_arg_unexpected(n) \

From d8a57195016cfa2be1e68c5a6bb1f8f7b401267c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Dec 2017 16:20:15 +0100
Subject: [PATCH 0408/2207] testmmap: read and write memory commands

---
 utils/testmmap.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 7d46fb529..d2cd6ec32 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -268,8 +268,7 @@ do_rxsync()
 #endif /* TEST_NETMAP */
 
 
-volatile char tmp1;
-void do_access()
+void do_rd()
 {
 	char *arg = nextarg();
 	char *p;
@@ -283,7 +282,31 @@ void do_access()
 		p = (char *)strtoul((void *)arg, NULL, 0);
 	}
 	last_access_addr = p + 4096;
-	tmp1 = *p;
+	output("%2x", *p);
+}
+
+char *last_wr_byte = "x";
+void do_wr()
+{
+	char *arg = nextarg();
+	char *p;
+	if (!arg) {
+		if (!last_access_addr) {
+			output("missing address");
+			return;
+		}
+		p = last_access_addr;
+		last_access_addr += 4096;
+	} else {
+		p = (char *)strtoul((void *)arg, NULL, 0);
+	}
+	arg = nextarg();
+	if (!arg) {
+		arg = last_wr_byte;
+	}
+	for ( ; arg; arg = nextarg()) {
+		*p++ = strtoul((void *)arg, NULL, 0);
+	}
 }
 
 void do_dup()
@@ -1772,7 +1795,8 @@ struct cmd_def commands[] = {
 	{ "dup",	do_dup,		},
 	{ "mmap",	do_mmap,	},
 	{ "anon-mmap",	do_anon_mmap,	},
-	{ "access",	do_access,	},
+	{ "rd",		do_rd,		},
+	{ "wr",		do_wr,		},
 	{ "munmap",	do_munmap,	},
 	{ "poll",	do_poll,	},
 	{ "expr",	do_expr,	},

From db4392bf7eece7c62b35c9515c6cdc48a2946ae4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Dec 2017 16:22:07 +0100
Subject: [PATCH 0409/2207] testmmap: simplify access to buffers

---
 utils/testmmap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d2cd6ec32..5fcb8fde8 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -753,6 +753,8 @@ do_buf()
 doit:
 	ring = get_ring();
 	buf = NETMAP_BUF(ring, buf_idx);
+	output("buf=%p", buf);
+	last_access_addr = buf;
 	dump_payload(buf, len);
 }
 

From 66eb846f8ff2c0c31e94ff7bdde862d5c5717287 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 3 Jan 2018 23:01:50 +0100
Subject: [PATCH 0410/2207] testmmap: ring and slot field modification

---
 utils/testmmap.c | 97 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 79 insertions(+), 18 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 5fcb8fde8..d88292116 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -556,7 +556,7 @@ get_if()
 
 	/* first arg: if offset */
 	arg = nextarg();
-	if (!arg) {
+	if (!arg || (strcmp(arg, "-") == 0)) {
 		goto doit;
 	}
 	off = strtoul(arg, NULL, 0);
@@ -618,14 +618,9 @@ get_ring()
 	return NETMAP_TXRING(nifp, ringid);
 }
 
-
 void
-do_ring()
+dump_ring(struct netmap_ring *ring)
 {
-	struct netmap_ring *ring;
-
-	ring = get_ring();
-
 	printf("buf_ofs     %"PRId64"\n", ring->buf_ofs);
 	printf("num_slots   %u\n", ring->num_slots);
 	printf("nr_buf_size %u\n", ring->nr_buf_size);
@@ -663,23 +658,46 @@ do_ring()
 }
 
 void
-do_slot()
+do_ring()
 {
 	struct netmap_ring *ring;
-	struct netmap_slot *slot;
-	long int index;
 	char *arg;
+	int upd = -1;
+	unsigned int v;
 
-	/* defaults */
-	index = 0;
+	ring = get_ring();
 
 	arg = nextarg();
-	if (!arg)
-		goto doit;
-	index = strtoll(arg, NULL, 0);
-doit:
-	ring = get_ring();
-	slot = ring->slot + index;
+	if (!arg) {
+		dump_ring(ring);
+		return;
+	}
+	if (strcmp(arg, "head") == 0) {
+		upd = 1;
+	} else if (strcmp(arg, "cur") == 0) {
+		upd = 2;
+	} else if (strcmp(arg, "both") == 0) {
+		upd = 3;
+	} else {
+		return;
+	}
+	arg = nextarg();
+	if (!arg) {
+		v = ring->cur + 1;
+		if (ring->cur >= ring->num_slots)
+			ring->cur = 0;
+	} else {
+		v = strtoul((void *)arg, NULL, 0);
+	}
+	if (upd & 1)
+		ring->head = v;
+	if (upd & 2)
+		ring->cur = v;
+}
+
+void
+dump_slot(struct netmap_slot *slot)
+{
 	printf("buf_idx       %u\n", slot->buf_idx);
 	printf("len           %u\n", slot->len);
 	printf("flags         %x", slot->flags);
@@ -703,12 +721,55 @@ do_slot()
 		if (slot->flags & NS_MOREFRAG) {
 			printf(" MOREFRAG");
 		}
+		if (NS_RFRAGS(slot)) {
+			printf(" fragments=%u", NS_RFRAGS(slot));
+		}
 		printf(" ]");
 	}
 	printf("\n");
 	printf("ptr           %lx\n", (long)slot->ptr);
 }
 
+void
+do_slot()
+{
+	struct netmap_ring *ring;
+	struct netmap_slot *slot;
+	long int index;
+	char *arg;
+
+	/* defaults */
+	index = 0;
+
+	arg = nextarg();
+	if (!arg)
+		goto doit;
+	index = strtoll(arg, NULL, 0);
+doit:
+	ring = get_ring();
+	slot = ring->slot + index;
+	arg = nextarg();
+	if (!arg) {
+		dump_slot(slot);
+		return;
+	}
+	if (strcmp(arg, "buf_idx") == 0) {
+		arg = nextarg();
+		if (!arg) {
+			output("buf_idx=%u", slot->buf_idx);
+			return;
+		}
+		slot->buf_idx = strtoul((void *)arg, NULL, 0);
+	} else if (strcmp(arg, "len") == 0) {
+		arg = nextarg();
+		if (!arg) {
+			output("len=%u", slot->len);
+			return;
+		}
+		slot->len = strtoul((void *)arg, NULL, 0);
+	}
+}
+
 static void
 dump_payload(char *p, int len)
 {

From 0b4cdcb9bf7324a8f48f7b4d52a4d02cf0f2bed0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:15:33 +0100
Subject: [PATCH 0411/2207] extmem: fix access out of bounds

---
 sys/dev/netmap/netmap_mem2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index cbb3848db..b0440cb63 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2239,7 +2239,8 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				skip = PAGE_SIZE;
 			}
 			off = noff;
-			clust = page_to_virt(*pages);
+			if (nr_pages > 0)
+				clust = page_to_virt(*pages);
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;

From 54bacec58734ae2f36c71b91143b2d55aad41aa6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:15:52 +0100
Subject: [PATCH 0412/2207] extmem: always use kmap

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index b0440cb63..7579ff737 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2240,7 +2240,7 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			}
 			off = noff;
 			if (nr_pages > 0)
-				clust = page_to_virt(*pages);
+				clust = kmap(*pages);
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;

From a0df74a7aedf152a888a84c3781a15bf02191501 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:16:31 +0100
Subject: [PATCH 0413/2207] testmmap: fix input of forked processes

---
 utils/testmmap.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d88292116..1ba907ca2 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1980,13 +1980,8 @@ cmd_loop(FILE *input)
 				output_err(-1, "fork");
 				goto clean1;
 			case 0:
-				fclose(stdin);
-				if (dup(p1[0]) < 0) {
-					output_err(-1, "dup");
-					exit(1);
-				}
 				close(p1[1]);
-				stdin = fdopen(0, "r");
+				input = fdopen(p1[0], "r");
 				chan_clear_all(channels, MAX_CHAN);
 				goto out;
 			default:

From 6bcab52a467a2fcff9ed8236d631c65cff4560f5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:16:57 +0100
Subject: [PATCH 0414/2207] testmmap: use MAP_SHARED in anon-mmap

---
 utils/testmmap.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 1ba907ca2..aabb2a81a 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -382,12 +382,12 @@ void do_anon_mmap()
 doit:
 	last_mmap_addr = mmap(0, memsize,
 			PROT_WRITE | PROT_READ,
-			MAP_PRIVATE | MAP_ANONYMOUS | flags, -1, 0);
+			MAP_SHARED | MAP_ANONYMOUS | flags, -1, 0);
 	if (last_access_addr == NULL)
 		last_access_addr = last_mmap_addr;
 	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
-		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS%s, -1, 0)=%p",
-		memsize, (flags ? "MAP_HUGETLB" : ""), last_mmap_addr);
+		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS%s, -1, 0)=%p",
+		memsize, (flags ? "|MAP_HUGETLB" : ""), last_mmap_addr);
 
 }
 

From a9cf5f08a00a9284a41976f2a89646d75d202038 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 18:34:30 +0100
Subject: [PATCH 0415/2207] extmem: use a bitmap to record skipped objects

Pre-allocated objects that cross non-contiguous pages cannot be used.
The previous code skipped these objects may setting their vaddr to NULL
in the lut, but this created bugs in the mmap code.
---
 sys/dev/netmap/netmap_mem2.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 7579ff737..fffb0cee7 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -106,6 +106,7 @@ struct netmap_obj_pool {
 
 	struct lut_entry *lut;  /* virt,phys addresses, objtotal entries */
 	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
+	uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */
 	uint32_t bitmap_slots;	/* number of uint32 entries in bitmap */
 	/* ---------------------------------------------------*/
 
@@ -300,6 +301,12 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	return nmd->lasterr;
 }
 
+static int
+nm_isset(uint32_t *bitmap, u_int i)
+{
+	return bitmap[ (i>>5) ] & ( 1U << (i & 31U) );
+}
+
 
 static int
 netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
@@ -327,10 +334,12 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 	 * free.
 	 */
 	for (j = 0; j < p->objtotal; j++) {
-		if (p->lut[j].vaddr != NULL) {
-			p->bitmap[ (j>>5) ] |=  ( 1U << (j & 31U) );
-			p->objfree++;
+		if (p->invalid_bitmap && nm_isset(p->invalid_bitmap, j)) {
+			D("skipping %s %d", p->name, j);
+			continue;
 		}
+		p->bitmap[ (j>>5) ] |=  ( 1U << (j & 31U) );
+		p->objfree++;
 	}
 
 	ND("%s free %u", p->name, p->objfree);
@@ -1162,6 +1171,9 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 	if (p->bitmap)
 		nm_os_free(p->bitmap);
 	p->bitmap = NULL;
+	if (p->invalid_bitmap)
+		nm_os_free(p->invalid_bitmap);
+	p->invalid_bitmap = NULL;
 	if (p->lut) {
 		u_int i;
 
@@ -1172,8 +1184,7 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 		 * in the lut.
 		 */
 		for (i = 0; i < p->objtotal; i += p->_clustentries) {
-			if (p->lut[i].vaddr)
-				contigfree(p->lut[i].vaddr, p->_clustsize, M_NETMAP);
+			contigfree(p->lut[i].vaddr, p->_clustsize, M_NETMAP);
 		}
 		nm_free_lut(p->lut, p->objtotal);
 	}
@@ -2198,6 +2209,13 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			error = ENOMEM;
 			goto out_delete;
 		}
+		
+		p->bitmap_slots = (o->num + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+		p->invalid_bitmap = nm_os_malloc(sizeof(uint32_t) * p->bitmap_slots);
+		if (p->invalid_bitmap == NULL) {
+			error = ENOMEM;
+			goto out_delete;
+		}
 
 		if (nr_pages == 0) {
 			p->objtotal = 0;
@@ -2225,13 +2243,13 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				nr_pages--;
 				ND("noff %zu page %p nr_pages %d", noff,
 						page_to_virt(*pages), nr_pages);
-				if (noff > 0 && p->lut[j].vaddr &&
+				if (noff > 0 && !nm_isset(p->invalid_bitmap, j) &&
 					(nr_pages == 0 || *pages != *(pages - 1) + 1))
 				{
 					/* out of space or non contiguous,
 					 * drop this object
 					 * */
-					p->lut[j].vaddr = NULL;
+					p->invalid_bitmap[ (j>>5) ] |= 1U << (j & 31U);
 					ND("non contiguous at off %zu, drop", noff);
 				}
 				if (nr_pages == 0)
@@ -2251,7 +2269,7 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	/* skip the first netmap_if, where the pools info reside */
 	{
 		struct netmap_obj_pool *p = &nme->up.pools[NETMAP_IF_POOL];
-		p->lut[0].vaddr = NULL;
+		p->invalid_bitmap[0] |= 1U;
 	}
 
 	error = netmap_mem_init_bitmaps(&nme->up);

From 8d16d6a15f505e1ae7164ca92a9d509503f39e81 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 20:18:17 +0100
Subject: [PATCH 0416/2207] nm_open: do not overwrite arg1-3 if not requested

---
 sys/net/netmap_user.h | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index e2c30ca70..3390944d7 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -873,6 +873,10 @@ nm_open(const char *ifname, const struct nmreq *req,
 				goto fail;
 			}
 		}
+	} else {
+		d->req.nr_arg1 = 4;
+		d->req.nr_arg2 = 0;
+		d->req.nr_arg3 = 0;
 	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
@@ -885,18 +889,18 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
-		if (new_flags & NM_OPEN_ARG1)
+		if (new_flags & NM_OPEN_ARG1) {
 			D("overriding ARG1 %d", parent->req.nr_arg1);
-		d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
-			parent->req.nr_arg1 : 4;
+			d->req.nr_arg1 = parent->req.nr_arg1;
+		}
 		if (new_flags & NM_OPEN_ARG2) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
-			d->req.nr_arg2 =  parent->req.nr_arg2;
+			d->req.nr_arg2 = parent->req.nr_arg2;
 		}
-		if (new_flags & NM_OPEN_ARG3)
+		if (new_flags & NM_OPEN_ARG3) {
 			D("overriding ARG3 %d", parent->req.nr_arg3);
-		d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
-			parent->req.nr_arg3 : 0;
+			d->req.nr_arg3 = parent->req.nr_arg3;
+		}
 		if (new_flags & NM_OPEN_RING_CFG) {
 			D("overriding RING_CFG");
 			d->req.nr_tx_slots = parent->req.nr_tx_slots;

From 3fcb453170310e42f80e08c17fffbf01786777be Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 10:37:19 +0100
Subject: [PATCH 0417/2207] extmem: removed useless allocation

---
 sys/dev/netmap/netmap_mem2.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index fffb0cee7..e57282522 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2170,12 +2170,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 		goto out_unmap;
 	}
 
-	nme = nm_os_malloc(sizeof(*nme));
-	if (nme == NULL) {
-		error = ENOMEM;
-		goto out_unmap;
-	}
-
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){
 				{ pi.if_pool_objsize, pi.if_pool_objtotal },

From 44f7251aa83c9b37eac92638eca095b14b440ab2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 11:55:30 +0100
Subject: [PATCH 0418/2207] extmem: allow sharing of allocator

---
 sys/dev/netmap/netmap_mem2.c | 97 ++++++++++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index e57282522..a5b50f3cb 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1742,12 +1742,21 @@ netmap_mem2_delete(struct netmap_mem_d *nmd)
 		nm_os_free(nmd);
 }
 
+#ifdef WITH_EXTMEM
+/* doubly linekd list of all existing external allocators */
+static struct netmap_mem_ext *netmap_mem_ext_list = NULL;
+NM_MTX_T nm_mem_ext_list_lock;
+#endif /* WITH_EXTMEM */
+
 int
 netmap_mem_init(void)
 {
 	NM_MTX_INIT(nm_mem_list_lock);
 	NMA_LOCK_INIT(&nm_mem);
 	netmap_mem_get(&nm_mem);
+#ifdef WITH_EXTMEM
+	NM_MTX_INIT(nm_mem_ext_list_lock);
+#endif /* WITH_EXTMEM */
 	return (0);
 }
 
@@ -2034,8 +2043,79 @@ struct netmap_mem_ext {
 
 	struct page **pages;
 	int nr_pages;
+	struct netmap_mem_ext *next, *prev;
 };
 
+/* call with nm_mem_list_lock held */
+static void
+netmap_mem_ext_register(struct netmap_mem_ext *e)
+{
+	NM_MTX_LOCK(nm_mem_ext_list_lock);
+	if (netmap_mem_ext_list)
+		netmap_mem_ext_list->prev = e;
+	e->next = netmap_mem_ext_list;
+	netmap_mem_ext_list = e;
+	e->prev = NULL;
+	NM_MTX_UNLOCK(nm_mem_ext_list_lock);
+}
+
+/* call with nm_mem_list_lock held */
+static void
+netmap_mem_ext_unregister(struct netmap_mem_ext *e)
+{
+	if (e->prev)
+		e->prev->next = e->next;
+	else
+		netmap_mem_ext_list = e->next;
+	if (e->next)
+		e->next->prev = e->prev;
+	e->prev = e->next = NULL;
+}
+
+static int
+netmap_mem_ext_same_pages(struct netmap_mem_ext *e, struct page **pages, int nr_pages)
+{
+	int i;
+
+	if (e->nr_pages != nr_pages)
+		return 0;
+
+	for (i = 0; i < nr_pages; i++)
+		if (pages[i] != e->pages[i])
+			return 0;
+
+	return 1;
+}
+
+static struct netmap_mem_ext *
+netmap_mem_ext_search(struct page **pages, int nr_pages)
+{
+	struct netmap_mem_ext *e;
+
+	NM_MTX_LOCK(nm_mem_ext_list_lock);
+	for (e = netmap_mem_ext_list; e; e = e->next) {
+		if (netmap_mem_ext_same_pages(e, pages, nr_pages)) {
+			netmap_mem_get(&e->up);
+			break;
+		}
+	}
+	NM_MTX_UNLOCK(nm_mem_ext_list_lock);
+	return e;
+}
+
+
+static void
+netmap_mem_ext_free_pages(struct page **pages, int nr_pages)
+{
+	int i;
+
+	for (i = 0; i < nr_pages; i++) {
+		kunmap(pages[i]);
+		put_page(pages[i]);
+	}
+	nm_os_free(pages);
+}
+
 static void
 netmap_mem_ext_delete(struct netmap_mem_d *d)
 {
@@ -2043,6 +2123,8 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 	struct netmap_mem_ext *e =
 		(struct netmap_mem_ext *)d;
 
+	netmap_mem_ext_unregister(e);
+
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &d->pools[i];
 		
@@ -2052,11 +2134,7 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 		}
 	}
 	if (e->pages) {
-		for (i = 0; i < e->nr_pages; i++) {
-			kunmap(e->pages[i]);
-			put_page(e->pages[i]);
-		}
-		nm_os_free(e->pages);
+		netmap_mem_ext_free_pages(e->pages, e->nr_pages);
 		e->pages = NULL;
 		e->nr_pages = 0;
 	}
@@ -2170,6 +2248,13 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 		goto out_unmap;
 	}
 
+	nme = netmap_mem_ext_search(pages, nr_pages);
+	if (nme) {
+		netmap_mem_ext_free_pages(pages, nr_pages);
+		return &nme->up;
+	}
+	D("not found, creating new");
+
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){
 				{ pi.if_pool_objsize, pi.if_pool_objtotal },
@@ -2270,6 +2355,8 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	if (error)
 		goto out_delete;
 
+	netmap_mem_ext_register(nme);
+
 	return &nme->up;
 
 out_delete:

From ffd05f5be5c32369a7f0af0841ae6282ca11a1ee Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 19:11:33 +0100
Subject: [PATCH 0419/2207] extmem: added support in nm_open/nm_parse

---
 sys/net/netmap_user.h | 159 +++++++++++++++++++++++++++++++++++++-----
 sys/net/netmap_virt.h |   2 +-
 2 files changed, 143 insertions(+), 18 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 3390944d7..0430fb116 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -351,6 +351,7 @@ enum {
 	NM_OPEN_ARG2 =		0x200000,
 	NM_OPEN_ARG3 =		0x400000,
 	NM_OPEN_RING_CFG =	0x800000, /* tx|rx rings|slots */
+	NM_OPEN_EXTMEM =       0x1000000,
 };
 
 
@@ -630,8 +631,10 @@ nm_init_offsets(struct nm_desc *d)
 }
 
 #define MAXERRMSG 80
+#define NM_PARSE_OK	  	0
+#define NM_PARSE_MEMID 		1
 static int
-nm_parse(const char *ifname, struct nm_desc *d, char *err)
+nm_parse_one(const char *ifname, struct nmreq *d, char **out)
 {
 	int is_vale;
 	const char *port = NULL;
@@ -645,6 +648,13 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 
 	errno = 0;
 
+	if (strncmp(ifname, "netmap:", 7) &&
+			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
+		snprintf(errmsg, MAXERRMSG, "invalid port name: %s", ifname);
+		errno = EINVAL;
+		goto fail;
+	}
+
 	is_vale = (ifname[0] == 'v');
 	if (is_vale) {
 		port = index(ifname, ':');
@@ -675,12 +685,13 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 	}
 
 	namelen = port - ifname;
-	if (namelen >= sizeof(d->req.nr_name)) {
+	if (namelen >= sizeof(d->nr_name)) {
 		snprintf(errmsg, MAXERRMSG, "name too long");
 		goto fail;
 	}
-	memcpy(d->req.nr_name, ifname, namelen);
-	d->req.nr_name[namelen] = '\0';
+	memcpy(d->nr_name, ifname, namelen);
+	d->nr_name[namelen] = '\0';
+	D("name %s", d->nr_name);
 
 	p_state = P_START;
 	nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
@@ -784,15 +795,21 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 			}
 			num = strtol(port, (char **)&port, 10);
 			if (num <= 0) {
-				snprintf(errmsg, MAXERRMSG, "invalid memid %ld, must be >0", num);
-				goto fail;
+				ND("non-numeric memid %s (out = %p)", port, out);
+				if (out == NULL)
+					goto fail;
+				*out = (char *)port;
+				while (*port)
+					port++;
+			} else {
+				nr_arg2 = num;
+				p_state = P_RNGSFXOK;
 			}
-			nr_arg2 = num;
-			p_state = P_RNGSFXOK;
 			break;
 		}
 	}
-	if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) {
+	if (p_state != P_START && p_state != P_RNGSFXOK &&
+	    p_state != P_FLAGSOK && p_state != P_MEMID) {
 		snprintf(errmsg, MAXERRMSG, "unexpected end of port name");
 		goto fail;
 	}
@@ -802,21 +819,106 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
 			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
 
-	d->req.nr_flags |= nr_flags;
-	d->req.nr_ringid |= nr_ringid;
-	d->req.nr_arg2 = nr_arg2;
-
-	d->self = d;
+	d->nr_flags |= nr_flags;
+	d->nr_ringid |= nr_ringid;
+	d->nr_arg2 = nr_arg2;
 
-	return 0;
+	return (p_state == P_MEMID) ? NM_PARSE_MEMID : NM_PARSE_OK;
 fail:
 	if (!errno)
 		errno = EINVAL;
-	if (err)
-		strncpy(err, errmsg, MAXERRMSG);
+	if (out)
+		*out = strdup(errmsg);
 	return -1;
 }
 
+static int
+nm_interp_memid(const char *memid, struct nmreq *req, char **err)
+{
+	int fd = -1;
+	char errmsg[MAXERRMSG] = "";
+	struct nmreq greq;
+	off_t mapsize;
+	struct netmap_pools_info *pi;
+
+	/* first, try to look for a netmap port with this name */
+	fd = open("/dev/netmap", O_RDONLY);
+	if (fd < 0) {
+		snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno));
+		goto fail;
+	}
+	memset(&greq, 0, sizeof(greq));
+	if (nm_parse_one(memid, &greq, err) == NM_PARSE_OK) {
+		greq.nr_version = NETMAP_API;
+		if (ioctl(fd, NIOCGINFO, &greq) < 0) {
+			if (errno == ENOENT || errno == ENXIO)
+				goto try_external;
+			snprintf(errmsg, MAXERRMSG, "cannot getinfo for %s: %s", memid, strerror(errno));
+			goto fail;
+		}
+		req->nr_arg2 = greq.nr_arg2;
+		close(fd);
+		return 0;
+	}
+try_external:
+	D("trying with external memory");
+	close(fd);
+	fd = open(memid, O_RDWR);
+	if (fd < 0) {
+		snprintf(errmsg, MAXERRMSG, "cannot open %s: %s", memid, strerror(errno));
+		goto fail;
+	}
+	mapsize = lseek(fd, 0, SEEK_END);
+	if (mapsize < 0) {
+		snprintf(errmsg, MAXERRMSG, "failed to obtain filesize of %s: %s", memid, strerror(errno));
+		goto fail;
+	}
+	pi = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (pi == MAP_FAILED) {
+		snprintf(errmsg, MAXERRMSG, "cannot map %s: %s", memid, strerror(errno));
+		goto fail;
+	}
+	req->nr_cmd = NETMAP_POOLS_CREATE;
+	pi->memsize = mapsize;
+	nmreq_pointer_put(req, pi);
+	D("mapped %zu bytes at %p from file %s", mapsize, pi, memid);
+	return 0;
+
+fail:
+	D("%s", errmsg);
+	close(fd);
+	if (err && !*err)
+		*err = strdup(errmsg);
+	return errno;
+}
+
+static int
+nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
+{
+	char *err;
+	switch (nm_parse_one(ifname, &d->req, &err)) {
+	case NM_PARSE_OK:
+		D("parse OK");
+		break;
+	case NM_PARSE_MEMID:
+		D("memid: %s", err);
+		errno = nm_interp_memid(err, &d->req, &err);
+		D("errno = %d", errno);
+		if (!errno)
+			break;
+		/* fallthrough */
+	default:
+		D("error");
+		strncpy(errmsg, err, MAXERRMSG);
+		errmsg[MAXERRMSG-1] = '\0';
+		free(err);
+		return -1;
+	}
+	D("parsed name: %s", d->req.nr_name);
+	d->self = d;
+	return 0;
+}
+
 /*
  * Try to open, return descriptor if successful, NULL otherwise.
  * An invalid netmap name will return errno = 0;
@@ -859,6 +961,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (req) {
 		d->req = *req;
+#if 0
 		if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
 			if (IS_NETMAP_DESC(parent) &&
 					(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
@@ -873,6 +976,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 				goto fail;
 			}
 		}
+#endif
 	} else {
 		d->req.nr_arg1 = 4;
 		d->req.nr_arg2 = 0;
@@ -884,11 +988,28 @@ nm_open(const char *ifname, const struct nmreq *req,
 			goto fail;
 	}
 
+	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
+		if (IS_NETMAP_DESC(parent) &&
+				(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
+			snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
+			errno = EINVAL;
+			goto fail;
+		}
+	}
+
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
+		if (new_flags & NM_OPEN_EXTMEM) {
+			if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
+				d->req.nr_cmd = NETMAP_POOLS_CREATE;
+				nmreq_pointer_put(&d->req, nmreq_pointer_get(&parent->req));
+				D("Warning: not overriding arg[1-3] since external memory is being used");
+				new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
+			}
+		}
 		if (new_flags & NM_OPEN_ARG1) {
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 			d->req.nr_arg1 = parent->req.nr_arg1;
@@ -921,6 +1042,10 @@ nm_open(const char *ifname, const struct nmreq *req,
 	/* add the *XPOLL flags */
 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
 
+	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
+		pi = nmreq_pointer_get(&d->req);
+	}
+
 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
 		goto fail;
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 3007bbf82..0c127601f 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -122,7 +122,7 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 }
 
 static inline void *
-nmreq_pointer_get(struct nmreq *nmr)
+nmreq_pointer_get(const struct nmreq *nmr)
 {
 	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
 	return (void *)*pp;

From 848681af0c63b1dab646ee2d58a3429dfac4e72f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 22:51:57 +0100
Subject: [PATCH 0420/2207] extmem: pass extmem flag in pkt-gen

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f51fe7288..62643116e 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2953,7 +2953,7 @@ main(int arc, char **argv)
 	 * reconfigure. We do the open here to have time to reset.
 	 */
 	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
-		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
+		NM_OPEN_ARG3 | NM_OPEN_EXTMEM | NM_OPEN_RING_CFG;
 	if (g.nthreads > 1) {
 		base_nmd.req.nr_flags &= ~NR_REG_MASK;
 		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;

From 278ddd3d3dd7c0d00729fb7359803164e9310813 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 22:52:27 +0100
Subject: [PATCH 0421/2207] netmap_mem_map: prefer objtotal over the internal
 _objtotal

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index a5b50f3cb..7c5e93f1f 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1455,7 +1455,7 @@ static int
 netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 {
 	int error = 0;
-	int i, lim = p->_objtotal;
+	int i, lim = p->objtotal;
 	struct netmap_lut *lut = &na->na_lut;
 
 	if (na->pdev == NULL)

From 9b85b2e66ca9070ed178dff2656be294db99086f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 10 Jan 2018 14:46:13 +0100
Subject: [PATCH 0422/2207] nm_open: disallow recursive memid specification

---
 sys/net/netmap_user.h | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 0430fb116..918a73d3c 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -634,7 +634,7 @@ nm_init_offsets(struct nm_desc *d)
 #define NM_PARSE_OK	  	0
 #define NM_PARSE_MEMID 		1
 static int
-nm_parse_one(const char *ifname, struct nmreq *d, char **out)
+nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 {
 	int is_vale;
 	const char *port = NULL;
@@ -789,7 +789,7 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out)
 			p_state = P_FLAGSOK;
 			break;
 		case P_MEMID:
-			if (nr_arg2 != 0) {
+			if (!memid_allowed) {
 				snprintf(errmsg, MAXERRMSG, "double setting of memid");
 				goto fail;
 			}
@@ -803,6 +803,7 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out)
 					port++;
 			} else {
 				nr_arg2 = num;
+				memid_allowed = 0;
 				p_state = P_RNGSFXOK;
 			}
 			break;
@@ -848,7 +849,7 @@ nm_interp_memid(const char *memid, struct nmreq *req, char **err)
 		goto fail;
 	}
 	memset(&greq, 0, sizeof(greq));
-	if (nm_parse_one(memid, &greq, err) == NM_PARSE_OK) {
+	if (nm_parse_one(memid, &greq, err, 0) == NM_PARSE_OK) {
 		greq.nr_version = NETMAP_API;
 		if (ioctl(fd, NIOCGINFO, &greq) < 0) {
 			if (errno == ENOENT || errno == ENXIO)
@@ -896,7 +897,7 @@ static int
 nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
 {
 	char *err;
-	switch (nm_parse_one(ifname, &d->req, &err)) {
+	switch (nm_parse_one(ifname, &d->req, &err, 1)) {
 	case NM_PARSE_OK:
 		D("parse OK");
 		break;

From 06378b2bdf534a8654a8b7bc7570241576c46d0f Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Mon, 25 Dec 2017 00:37:01 +0900
Subject: [PATCH 0423/2207] mem: large memory size support

---
 LINUX/netmap_linux.c         | 14 ++++++++++++++
 apps/pkt-gen/pkt-gen.c       |  2 +-
 sys/dev/netmap/netmap_kern.h |  2 ++
 sys/dev/netmap/netmap_mem2.c |  4 ++--
 sys/net/netmap_user.h        |  4 ++--
 5 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a70bc391c..698ee044b 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -50,6 +50,15 @@ nm_os_malloc(size_t size)
 	return rv;
 }
 
+void *
+nm_os_vmalloc(size_t size)
+{
+	void *rv = vmalloc(size);
+	if (IS_ERR(rv))
+		return NULL;
+	return rv;
+}
+
 void *
 nm_os_realloc(void *addr, size_t new_size, size_t old_size)
 {
@@ -66,6 +75,11 @@ nm_os_free(void *addr){
 	kfree(addr);
 }
 
+void
+nm_os_vfree(void *addr){
+	vfree(addr);
+}
+
 void
 nm_os_selinfo_init(NM_SELINFO_T *si)
 {
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 62643116e..93db2b565 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2965,7 +2965,7 @@ main(int arc, char **argv)
 		goto out;
 	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %dKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
+	D("mapped %luKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
 
 	if (g.virt_header) {
 		/* Set the virtio-net header length, since the user asked
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 9ec84e579..a4488d410 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -307,8 +307,10 @@ void netmap_undo_zombie(struct ifnet *);
 
 /* os independent alloc/realloc/free */
 void *nm_os_malloc(size_t);
+void *nm_os_vmalloc(size_t);
 void *nm_os_realloc(void *, size_t new_size, size_t old_size);
 void nm_os_free(void *);
+void nm_os_vfree(void *);
 
 /* passes a packet up to the host stack.
  * If the packet is sent (or dropped) immediately it returns NULL,
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 7c5e93f1f..c3a0abafd 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2113,7 +2113,7 @@ netmap_mem_ext_free_pages(struct page **pages, int nr_pages)
 		kunmap(pages[i]);
 		put_page(pages[i]);
 	}
-	nm_os_free(pages);
+	nm_os_vfree(pages);
 }
 
 static void
@@ -2201,7 +2201,7 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	start = p >> PAGE_SHIFT;
 	nr_pages = end - start;
 
-	pages = nm_os_malloc(nr_pages * sizeof(*pages));
+	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
 	if (pages == NULL) {
 		error = ENOMEM;
 		goto out;
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 918a73d3c..9b27797ed 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -113,7 +113,7 @@
 	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
 
 #define NETMAP_BUF(ring, index)				\
-	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
+	((char *)(ring) + (ring)->buf_ofs + ((long)(index)*(ring)->nr_buf_size))
 
 #define NETMAP_BUF_IDX(ring, buf)			\
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
@@ -223,7 +223,7 @@ struct nm_desc {
 	struct nm_desc *self; /* point to self if netmap. */
 	int fd;
 	void *mem;
-	uint32_t memsize;
+	uint64_t memsize;
 	int done_mmap;	/* set if mem is the result of mmap */
 	struct netmap_if * const nifp;
 	uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;

From 88ad845a000f3b49fcbfee21d29a376ea938526f Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Dec 2017 21:04:03 +0900
Subject: [PATCH 0424/2207] unnecessary debug in the master

---
 LINUX/if_e1000_netmap.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 45c8284ed..2c4c7d9c5 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -318,7 +318,6 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]);
 		if (i < 0) // XXX something wrong here, can it really happen ?
 			i += rxr->count;
-		D("i now is %d", i);
 		wmb(); /* Force memory writes to complete */
 		writel(i, hw->hw_addr + rxr->rdt);
 	}

From 3961d30bc4ff53033b4869e0692ccf7de2075e5f Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Dec 2017 21:27:48 +0900
Subject: [PATCH 0425/2207] silence compiler

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 93db2b565..d434a8db1 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1623,7 +1623,7 @@ sender_body(void *data)
 			}
 			m = send_packets(txring, pkt, frame, size, targ->g,
 					 limit, options, frags);
-			ND("limit %d tail %d frags %d m %d",
+			ND("limit %lu tail %d frags %d m %d",
 				limit, txring->tail, frags, m);
 			sent += m;
 			if (m > 0) //XXX-ste: can m be 0?

From 460f7846036795a39ec7b3ac253fca60d056e264 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Jan 2018 12:33:41 +0100
Subject: [PATCH 0426/2207] extmem: don't init bitmaps during creation

Bitmap initialization is already done during netmap_mem_finalize(),
so the action was duplicated.
---
 sys/dev/netmap/netmap_mem2.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c3a0abafd..421592a5e 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2351,10 +2351,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 		p->invalid_bitmap[0] |= 1U;
 	}
 
-	error = netmap_mem_init_bitmaps(&nme->up);
-	if (error)
-		goto out_delete;
-
 	netmap_mem_ext_register(nme);
 
 	return &nme->up;

From d5720e09cf4bc06500c16d7a483b4637d859a49b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Jan 2018 18:19:07 +0100
Subject: [PATCH 0427/2207] nm_open: remove stale code

---
 sys/net/netmap_user.h | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 9b27797ed..c4892cd5a 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -962,22 +962,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (req) {
 		d->req = *req;
-#if 0
-		if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-			if (IS_NETMAP_DESC(parent) &&
-					(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
-				snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
-				errno = EINVAL;
-				goto fail;
-			}
-		        pi = nmreq_pointer_get(&d->req);
-			if (pi == NULL) {
-				snprintf(errmsg, MAXERRMSG, "missing netmap_pools_info pointer");
-				errno = EINVAL;
-				goto fail;
-			}
-		}
-#endif
 	} else {
 		d->req.nr_arg1 = 4;
 		d->req.nr_arg2 = 0;

From 8470b496b86349feff900fb45b6bcfcab2b93dac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Jan 2018 18:22:24 +0100
Subject: [PATCH 0428/2207] nm_open: more sensible handling of NM_OPEN_NO_MMAP

---
 sys/net/netmap_user.h | 57 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 48 insertions(+), 9 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index c4892cd5a..679a31a7a 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -925,8 +925,12 @@ nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
  * An invalid netmap name will return errno = 0;
  * You can pass a pointer to a pre-filled nm_desc to add special
  * parameters. Flags is used as follows
- * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
+ * NM_OPEN_NO_MMAP	use the memory from arg, only
  *			if the nr_arg2 (memory block) matches.
+ *			Special case: if arg is NULL, skip the
+ *			mmap entirely (maybe because you are going
+ *			to do it by yourself, or you plan to call
+ *			nm_mmap() only later)
  * NM_OPEN_ARG1		use req.nr_arg1 from arg
  * NM_OPEN_ARG2		use req.nr_arg2 from arg
  * NM_OPEN_RING_CFG	user ring config from arg
@@ -969,16 +973,50 @@ nm_open(const char *ifname, const struct nmreq *req,
 	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
-		if (nm_parse(ifname, d, errmsg) < 0)
+		char *err;
+		switch (nm_parse_one(ifname, &d->req, &err, 1)) {
+		case NM_PARSE_OK:
+			break;
+		case NM_PARSE_MEMID:
+			if ((new_flags & NM_OPEN_NO_MMAP) &&
+					IS_NETMAP_DESC(parent)) {
+				/* ignore the memid setting, since we are
+				 * going to use the parent's one
+				 */
+				break;
+			}
+			errno = nm_interp_memid(err, &d->req, &err);
+			if (!errno)
+				break;
+			/* fallthrough */
+		default:
+			strncpy(errmsg, err, MAXERRMSG);
+			errmsg[MAXERRMSG-1] = '\0';
+			free(err);
 			goto fail;
+		}
+		d->self = d;
 	}
 
+	/* compatibility checks for POOL_SCREATE and NM_OPEN flags
+	 * the first check may be dropped once we have a larger nreq
+	 */
 	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-		if (IS_NETMAP_DESC(parent) &&
-				(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
-			snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
-			errno = EINVAL;
-			goto fail;
+		if (IS_NETMAP_DESC(parent)) {
+		       	if (new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3)) {
+				snprintf(errmsg, MAXERRMSG,
+						"POOLS_CREATE is incompatibile "
+						"with NM_OPEN_ARG? flags");
+				errno = EINVAL;
+				goto fail;
+			}
+			if (new_flags & NM_OPEN_NO_MMAP) {
+				snprintf(errmsg, MAXERRMSG,
+						"POOLS_CREATE is incompatible "
+						"with NM_OPEN_NO_MMAP flag");
+				errno = EINVAL;
+				goto fail;
+			}
 		}
 	}
 
@@ -999,7 +1037,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 			d->req.nr_arg1 = parent->req.nr_arg1;
 		}
-		if (new_flags & NM_OPEN_ARG2) {
+		if (new_flags & (NM_OPEN_ARG2 | NM_OPEN_NO_MMAP)) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
 			d->req.nr_arg2 = parent->req.nr_arg2;
 		}
@@ -1113,7 +1151,8 @@ nm_close(struct nm_desc *d)
 	 */
 	static void *__xxzt[] __attribute__ ((unused))  =
 		{ (void *)nm_open, (void *)nm_inject,
-		  (void *)nm_dispatch, (void *)nm_nextpkt } ;
+		  (void *)nm_dispatch, (void *)nm_nextpkt,
+	          (void *)nm_parse } ;
 
 	if (d == NULL || d->self != d)
 		return EINVAL;

From 0d8349a96548a1f38efa3c3848f035a2ea48f9ee Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Jan 2018 10:25:09 +0000
Subject: [PATCH 0429/2207] FreeBSD: fix compilation

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b29b5d154..92b26bee9 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3210,7 +3210,7 @@ netmap_attach_common(struct netmap_adapter *na)
 	if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
 		na->if_input = na->ifp->if_input; /* for netmap_send_up */
 	}
-	pa->pdev = na; /* make sure netmap_mem_map() is called */
+	na->pdev = na; /* make sure netmap_mem_map() is called */
 #endif /* __FreeBSD__ */
 	if (na->nm_krings_create == NULL) {
 		/* we assume that we have been called by a driver,

From bbf6c625820ee3ae84eff9e10d42ecdaf0c0c979 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Jan 2018 10:25:37 +0000
Subject: [PATCH 0430/2207] fix const-related warning

---
 sys/net/netmap_virt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 0c127601f..1b8b26cc9 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -124,7 +124,7 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 static inline void *
 nmreq_pointer_get(const struct nmreq *nmr)
 {
-	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+	const uintptr_t *pp = (const uintptr_t *)&nmr->nr_arg1;
 	return (void *)*pp;
 }
 

From 446676cad6e71b87d1d7dd7f955e2204df820fd8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Jan 2018 19:26:48 +0100
Subject: [PATCH 0431/2207] extmem: factorize out os-dependend code

---
 LINUX/netmap_linux.c         | 136 +++++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_mem2.c | 126 +++++++-------------------------
 sys/dev/netmap/netmap_mem2.h |  10 +++
 3 files changed, 171 insertions(+), 101 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 698ee044b..65f49f6f0 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -167,6 +167,142 @@ nm_os_ifnet_fini(void)
 	}
 }
 
+#ifdef WITH_EXTMEM
+struct nm_os_extmem {
+	struct page **pages;
+	int nr_pages;
+	int mapped;
+};
+
+void
+nm_os_extmem_delete(struct nm_os_extmem *e)
+{
+	int i;
+	for (i = 0; i < e->nr_pages; i++) {
+		if (i < e->mapped)
+			kunmap(e->pages[i]);
+		put_page(e->pages[i]);
+	}
+	if (e->pages)
+		nm_os_vfree(e->pages);
+	nm_os_free(e);
+}
+
+char *
+nm_os_extmem_nextpage(struct nm_os_extmem *e)
+{
+	if (e->mapped >= e->nr_pages)
+		return NULL;
+	D("mapping %d/%d", e->mapped, e->nr_pages);
+	return kmap(e->pages[e->mapped++]);
+}
+
+int
+nm_os_extmem_isequal(struct nm_os_extmem *e1, struct nm_os_extmem *e2)
+{
+	int i;
+
+	if (e1->nr_pages != e2->nr_pages)
+		return 0;
+
+	for (i = 0; i < e1->nr_pages; i++)
+		if (e1->pages[i] != e2->pages[i])
+			return 0;
+
+	return 1;
+}
+
+int
+nm_os_extmem_nr_pages(struct nm_os_extmem *e)
+{
+	return e->nr_pages;
+}
+
+
+struct nm_os_extmem *
+nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+{
+	unsigned long end, start;
+	int nr_pages, res;
+	struct nm_os_extmem *e = NULL;
+	int err;
+	struct page **pages;
+
+	end = (p + pi->memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	start = p >> PAGE_SHIFT;
+	nr_pages = end - start;
+
+	e = nm_os_malloc(sizeof(*e));
+	if (e == NULL) {
+		D("failed to allocate os_extmem");
+		err = ENOMEM;
+		goto out;
+	}
+
+	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
+	if (pages == NULL) {
+		D("failed to allocate pages array (nr_pages %d)", nr_pages);
+		err = ENOMEM;
+		goto out;
+	}
+
+	e->pages = pages;
+
+#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			pages,
+			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
+#elif defined(NETMAP_LINUX_HAVE_GUP_5ARGS)
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
+	res = get_user_pages_unlocked(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#else
+	down_read(¤t->mm->mmap_sem);
+	res = get_user_pages(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages,
+			NULL);
+	up_read(¤t->mm->mmap_sem);
+#endif	/* NETMAP_LINUX_GUP */
+
+	e->nr_pages = res;
+
+	if (res < nr_pages) {
+		D("failed to get user pages: res %d nr_pages %d", res, nr_pages);
+		err = EFAULT;
+		goto out;
+	}
+
+	return e;
+
+out:
+	if (e)
+		nm_os_extmem_delete(e);
+	if (perror)
+		*perror = err;
+	return NULL;
+}
+#endif /* WITH_EXTMEM */
+
 #ifdef NETMAP_LINUX_HAVE_IOMMU
 #include 
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 421592a5e..0b23ad672 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2041,8 +2041,7 @@ netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
 struct netmap_mem_ext {
 	struct netmap_mem_d up;
 
-	struct page **pages;
-	int nr_pages;
+	struct nm_os_extmem *os;
 	struct netmap_mem_ext *next, *prev;
 };
 
@@ -2072,29 +2071,14 @@ netmap_mem_ext_unregister(struct netmap_mem_ext *e)
 	e->prev = e->next = NULL;
 }
 
-static int
-netmap_mem_ext_same_pages(struct netmap_mem_ext *e, struct page **pages, int nr_pages)
-{
-	int i;
-
-	if (e->nr_pages != nr_pages)
-		return 0;
-
-	for (i = 0; i < nr_pages; i++)
-		if (pages[i] != e->pages[i])
-			return 0;
-
-	return 1;
-}
-
 static struct netmap_mem_ext *
-netmap_mem_ext_search(struct page **pages, int nr_pages)
+netmap_mem_ext_search(struct nm_os_extmem *os)
 {
 	struct netmap_mem_ext *e;
 
 	NM_MTX_LOCK(nm_mem_ext_list_lock);
 	for (e = netmap_mem_ext_list; e; e = e->next) {
-		if (netmap_mem_ext_same_pages(e, pages, nr_pages)) {
+		if (nm_os_extmem_isequal(e->os, os)) {
 			netmap_mem_get(&e->up);
 			break;
 		}
@@ -2104,18 +2088,6 @@ netmap_mem_ext_search(struct page **pages, int nr_pages)
 }
 
 
-static void
-netmap_mem_ext_free_pages(struct page **pages, int nr_pages)
-{
-	int i;
-
-	for (i = 0; i < nr_pages; i++) {
-		kunmap(pages[i]);
-		put_page(pages[i]);
-	}
-	nm_os_vfree(pages);
-}
-
 static void
 netmap_mem_ext_delete(struct netmap_mem_d *d)
 {
@@ -2133,11 +2105,8 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 			p->lut = NULL;
 		}
 	}
-	if (e->pages) {
-		netmap_mem_ext_free_pages(e->pages, e->nr_pages);
-		e->pages = NULL;
-		e->nr_pages = 0;
-	}
+	if (e->os)
+		nm_os_extmem_delete(e->os);
 	netmap_mem2_delete(d);
 }
 
@@ -2168,12 +2137,12 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	uintptr_t p = *(uintptr_t *)&nmr->nr_arg1;
 	struct netmap_pools_info pi;
 	int error = 0;
-	unsigned long end, start;
-	int nr_pages, res, i, j;
-	struct page **pages = NULL;
+	int i, j;
 	struct netmap_mem_ext *nme;
 	char *clust;
 	size_t off;
+	struct nm_os_extmem *os = NULL;
+	int nr_pages;
 
 	error = copyin((void *)p, &pi, sizeof(pi));
 	if (error)
@@ -2197,60 +2166,15 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			pi.ring_pool_objtotal, pi.ring_pool_objsize,
 			pi.buf_pool_objtotal, pi.buf_pool_objsize);
 		
-	end = (p + pi.memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	start = p >> PAGE_SHIFT;
-	nr_pages = end - start;
-
-	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
-	if (pages == NULL) {
-		error = ENOMEM;
+	os = nm_os_extmem_create(p, &pi, &error);
+	if (os == NULL) {
+		D("os extmem creation failed");
 		goto out;
 	}
 
-#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
-	res = get_user_pages_unlocked(
-			p,
-			nr_pages,
-			pages,
-			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
-#elif defined(NETMAP_LINUX_HAVE_GUP_5ARGS)
-	res = get_user_pages_unlocked(
-			p,
-			nr_pages,
-			1, /* write */
-			0, /* don't force */
-			pages);
-#elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
-	res = get_user_pages_unlocked(
-			current,
-			current->mm,
-			p,
-			nr_pages,
-			1, /* write */
-			0, /* don't force */
-			pages);
-#else
-	down_read(¤t->mm->mmap_sem);
-	res = get_user_pages(
-			current,
-			current->mm,
-			p,
-			nr_pages,
-			1, /* write */
-			0, /* don't force */
-			pages,
-			NULL);
-	up_read(¤t->mm->mmap_sem);
-#endif	/* NETMAP_LINUX_GUP */
-
-	if (res < nr_pages) {
-		error = EFAULT;
-		goto out_unmap;
-	}
-
-	nme = netmap_mem_ext_search(pages, nr_pages);
+	nme = netmap_mem_ext_search(os);
 	if (nme) {
-		netmap_mem_ext_free_pages(pages, nr_pages);
+		nm_os_extmem_delete(os);
 		return &nme->up;
 	}
 	D("not found, creating new");
@@ -2265,15 +2189,17 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	if (nme == NULL)
 		goto out_unmap;
 					
+	nr_pages = nm_os_extmem_nr_pages(os);
+
 	/* from now on pages will be released by nme destructor;
 	 * we let res = 0 to prevent release in out_unmap below
 	 */
-	res = 0;
-	nme->pages = pages;
-	nme->nr_pages = nr_pages;
+	nme->os = os;
+	os = NULL; /* pass ownership */
 	nme->up.flags |= NETMAP_MEM_EXT;
 
-	clust = kmap(*pages);
+
+	clust = nm_os_extmem_nextpage(nme->os);
 	off = 0;
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &nme->up.pools[i];
@@ -2317,13 +2243,15 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			ND("too big, recomputing offset...");
 			skip = PAGE_SIZE - (off & PAGE_MASK);
 			while (noff >= PAGE_SIZE) {
+				char *old_clust = clust;
 				noff -= skip;
-				pages++;
+				clust = nm_os_extmem_nextpage(nme->os);
 				nr_pages--;
 				ND("noff %zu page %p nr_pages %d", noff,
 						page_to_virt(*pages), nr_pages);
 				if (noff > 0 && !nm_isset(p->invalid_bitmap, j) &&
-					(nr_pages == 0 || *pages != *(pages - 1) + 1))
+					(nr_pages == 0 ||
+					 old_clust + PAGE_SIZE != clust))
 				{
 					/* out of space or non contiguous,
 					 * drop this object
@@ -2336,8 +2264,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				skip = PAGE_SIZE;
 			}
 			off = noff;
-			if (nr_pages > 0)
-				clust = kmap(*pages);
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;
@@ -2358,10 +2284,8 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 out_delete:
 	netmap_mem_put(&nme->up);
 out_unmap:
-	for (i = 0; i < res; i++)
-		put_page(pages[i]);
-	if (res)
-		nm_os_free(pages);
+	if (os)
+		nm_os_extmem_delete(os);
 out:
 	if (perror)
 		*perror = error;
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index ca3a6240e..ec014603f 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -174,4 +174,14 @@ int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
 
 uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 
+#ifdef WITH_EXTMEM
+#include 
+struct nm_os_extmem; /* opaque */
+struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct netmap_pools_info *, int *perror);
+char *nm_os_extmem_nextpage(struct nm_os_extmem *);
+int nm_os_extmem_nr_pages(struct nm_os_extmem *);
+int nm_os_extmem_isequal(struct nm_os_extmem *, struct nm_os_extmem *);
+void nm_os_extmem_delete(struct nm_os_extmem *);
+#endif /* WITH_EXTMEM */
+
 #endif

From 241c0e64eb1a4dd9f23415764471ca3528dbbfc2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 26 Jan 2018 18:29:16 +0000
Subject: [PATCH 0432/2207] extmem: fix offset computation

---
 sys/dev/netmap/netmap_mem2.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 0b23ad672..c938630df 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2231,7 +2231,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 
 		for (j = 0; j < o->num && nr_pages > 0; j++) {
 			size_t noff;
-			size_t skip;
 
 			p->lut[j].vaddr = clust + off;
 			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
@@ -2241,10 +2240,9 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				continue;
 			}
 			ND("too big, recomputing offset...");
-			skip = PAGE_SIZE - (off & PAGE_MASK);
 			while (noff >= PAGE_SIZE) {
 				char *old_clust = clust;
-				noff -= skip;
+				noff -= PAGE_SIZE;
 				clust = nm_os_extmem_nextpage(nme->os);
 				nr_pages--;
 				ND("noff %zu page %p nr_pages %d", noff,
@@ -2261,7 +2259,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				}
 				if (nr_pages == 0)
 					break;
-				skip = PAGE_SIZE;
 			}
 			off = noff;
 		}

From 4575a629f8a75554e27f01dc9014ea75787f613a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 26 Jan 2018 18:43:51 +0000
Subject: [PATCH 0433/2207] extmem: FreeBSD support

---
 sys/dev/netmap/netmap_freebsd.c | 110 ++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_kern.h    |   2 +-
 sys/dev/netmap/netmap_mem2.c    |   3 +
 3 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 2108f3edc..0438b0276 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -599,6 +599,116 @@ nm_os_vi_detach(struct ifnet *ifp)
 	if_free(ifp);
 }
 
+#ifdef WITH_EXTMEM
+#include 
+#include 
+struct nm_os_extmem {
+	vm_object_t obj;
+	vm_offset_t kva;
+        vm_offset_t size;
+	vm_pindex_t scan;
+};
+
+void
+nm_os_extmem_delete(struct nm_os_extmem *e)
+{
+	D("freeing %lx bytes", e->size);
+	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
+	nm_os_free(e);
+}
+
+char *
+nm_os_extmem_nextpage(struct nm_os_extmem *e)
+{
+	char *rv = NULL;
+	if (e->scan < e->kva + e->size) {
+		rv = (char *)e->scan;
+		e->scan += PAGE_SIZE;
+	}
+	return rv;
+}
+
+int
+nm_os_extmem_isequal(struct nm_os_extmem *e1, struct nm_os_extmem *e2)
+{
+	return (e1->obj == e1->obj);
+}
+
+int
+nm_os_extmem_nr_pages(struct nm_os_extmem *e)
+{
+	return e->size >> PAGE_SHIFT;
+}
+
+struct nm_os_extmem *
+nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+{
+	vm_map_t map;
+	vm_map_entry_t entry;
+	vm_object_t obj;
+	vm_prot_t prot;
+	vm_pindex_t index;
+	boolean_t wired;
+	struct nm_os_extmem *e = NULL;
+	int rv, error = 0;
+
+	e = nm_os_malloc(sizeof(*e));
+	if (e == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	map = &curthread->td_proc->p_vmspace->vm_map;
+	rv = vm_map_lookup(&map, p, VM_PROT_RW, &entry,
+			&obj, &index, &prot, &wired);
+	if (rv != KERN_SUCCESS) {
+		D("address %lx not found", p);
+		goto out_free;
+	}
+	/* check that we are given the whole vm_object ? */
+	vm_map_lookup_done(map, entry);
+
+	// XXX can we really use obj after releasing the map lock?
+	e->obj = obj;
+	vm_object_reference(obj);
+	/* wire the memory and add the vm_object to the kernel map,
+	 * to make sure that it is not fred even if the processes that
+	 * are mmap()ing it all exit
+	 */
+	e->kva = vm_map_min(kernel_map);
+	e->size = obj->size << PAGE_SHIFT;
+	rv = vm_map_find(kernel_map, obj, 0, &e->kva, e->size, 0,
+			VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
+			VM_PROT_READ | VM_PROT_WRITE, 0);
+	if (rv != KERN_SUCCESS) {
+		D("vm_map_find(%lx) failed", e->size);
+		goto out_rel;
+	}
+	rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,
+			VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+	if (rv != KERN_SUCCESS) {
+		D("vm_map_wire failed");
+		goto out_rem;
+	}
+
+	e->scan = e->kva;
+
+	return e;
+
+out_rem:
+	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
+	e->obj = NULL;
+out_rel:
+	vm_object_deallocate(e->obj);
+out_free:
+	nm_os_free(e);
+out:
+	if (perror)
+		*perror = error;
+	return NULL;
+}
+#endif /* WITH_EXTMEM */
+
 /* ======================== PTNETMAP SUPPORT ========================== */
 
 #ifdef WITH_PTNETMAP_GUEST
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a4488d410..a4ab18bfb 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -75,7 +75,7 @@
 #define WITH_GENERIC
 #define WITH_PTNETMAP_HOST	/* ptnetmap host support */
 #define WITH_PTNETMAP_GUEST	/* ptnetmap guest support */
-
+#define WITH_EXTMEM
 #endif
 
 #if defined(__FreeBSD__)
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c938630df..c2604288e 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2233,6 +2233,9 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			size_t noff;
 
 			p->lut[j].vaddr = clust + off;
+#if !defined(linux) && !defined(_WIN32)
+			p->lut[j].paddr = vtophys(p->lut[j].vaddr);
+#endif
 			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
 			noff = off + p->_objsize;
 			if (noff < PAGE_SIZE) {

From 9b0772ff193307a4e908cbdea84fd586c97d8de6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 16:34:46 +0100
Subject: [PATCH 0434/2207] extmem: parse the option in the new API

---
 LINUX/netmap_linux.c         |  4 +--
 apps/pkt-gen/pkt-gen.c       |  2 +-
 sys/dev/netmap/netmap.c      | 36 +++++++++++++++++++++++----
 sys/dev/netmap/netmap_mem2.c | 48 ++++++++++++++++--------------------
 sys/dev/netmap/netmap_mem2.h |  6 ++---
 sys/net/netmap.h             | 12 ++++++++-
 sys/net/netmap_user.h        | 17 +++++++++++--
 7 files changed, 84 insertions(+), 41 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 65f49f6f0..e2e648faa 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -220,7 +220,7 @@ nm_os_extmem_nr_pages(struct nm_os_extmem *e)
 
 
 struct nm_os_extmem *
-nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 {
 	unsigned long end, start;
 	int nr_pages, res;
@@ -228,7 +228,7 @@ nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
 	int err;
 	struct page **pages;
 
-	end = (p + pi->memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	end = (p + pi->nr_memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	start = p >> PAGE_SHIFT;
 	nr_pages = end - start;
 
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d434a8db1..d07f6daa2 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2965,7 +2965,7 @@ main(int arc, char **argv)
 		goto out;
 	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %luKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
+	D("mapped %"PRIu32"KB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
 
 	if (g.virt_header) {
 		/* Set the virtio-net header length, since the user asked
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 92b26bee9..ddb2c4661 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2260,13 +2260,26 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_LOCK();
 			do {
 				u_int memflags;
+				struct nmreq_option *opt;
 
 				if (priv->np_nifp != NULL) {	/* thread already registered */
 					error = EBUSY;
 					break;
 				}
 
-				if (req->nr_mem_id) {
+#ifdef WITH_EXTMEM
+				opt = nmreq_findoption(hdr, NETMAP_REQ_OPT_EXTMEM);
+				if (opt != NULL) {
+					struct nmreq_opt_extmem *e =
+						(struct nmreq_opt_extmem *)opt;
+					nmd = netmap_mem_ext_create(e->nro_usrptr,
+							&e->nro_info, &error);
+					if (nmd == NULL)
+						break;
+				}
+#endif /* WITH_EXTMEM */
+
+				if (nmd == NULL && req->nr_mem_id) {
 					/* find the allocator and get a reference */
 					nmd = netmap_mem_find(req->nr_mem_id);
 					if (nmd == NULL) {
@@ -2521,8 +2534,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 #endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
-			struct nmreq_pools_info_get *req =
-				(struct nmreq_pools_info_get *)hdr->nr_body;
+			struct nmreq_pools_info *req =
+				(struct nmreq_pools_info *)hdr->nr_body;
 			/* Get information from the memory allocator. This
 			 * netmap device must already be bound to a port.
 			 * Note that hdr->nr_name is ignored. */
@@ -2653,7 +2666,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
-		return sizeof(struct nmreq_pools_info_get);
+		return sizeof(struct nmreq_pools_info);
 	}
 	return 0;
 }
@@ -2661,7 +2674,20 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 size_t
 nmreq_opt_size_by_type(uint16_t nro_reqtype)
 {
-	return 0;
+	size_t rv = sizeof(struct nmreq_option);
+#ifdef NETMAP_REQ_OPT_DEBUG
+	if (nro_reqtype & NETMAP_REQ_OPT_DEBUG)
+		return (nro_reqtype & ~NETMAP_REQ_OPT_DEBUG);
+#endif /* NETMAP_REQ_OPT_DEBUG */
+	switch (nro_reqtype) {
+#ifdef WITH_EXTMEM
+	case NETMAP_REQ_OPT_EXTMEM:
+		rv = sizeof(struct nmreq_opt_extmem);
+		break;
+	}
+#endif /* WITH_EXTMEM */
+	/* subtract the common header */
+	return rv - sizeof(struct nmreq_option);
 }
 
 int
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c2604288e..b72c6f6b6 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2008,7 +2008,7 @@ struct netmap_mem_ops netmap_mem_global_ops = {
 };
 
 int
-netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
+netmap_mem_pools_info_get(struct nmreq_pools_info *req,
 				struct netmap_mem_d *nmd)
 {
 	int ret;
@@ -2132,10 +2132,8 @@ struct netmap_mem_ops netmap_mem_ext_ops = {
 };
 
 struct netmap_mem_d *
-netmap_mem_ext_create(struct nmreq *nmr, int *perror)
+netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 {
-	uintptr_t p = *(uintptr_t *)&nmr->nr_arg1;
-	struct netmap_pools_info pi;
 	int error = 0;
 	int i, j;
 	struct netmap_mem_ext *nme;
@@ -2144,29 +2142,25 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	struct nm_os_extmem *os = NULL;
 	int nr_pages;
 
-	error = copyin((void *)p, &pi, sizeof(pi));
-	if (error)
-		goto out;
-
 	// XXX sanity checks
-	if (pi.if_pool_objtotal == 0)
-		pi.if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num;
-	if (pi.if_pool_objsize == 0)
-		pi.if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size;
-	if (pi.ring_pool_objtotal == 0)
-		pi.ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num;
-	if (pi.ring_pool_objsize == 0)
-		pi.ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size;
-	if (pi.buf_pool_objtotal == 0)
-		pi.buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
-	if (pi.buf_pool_objsize == 0)
-		pi.buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
+	if (pi->nr_if_pool_objtotal == 0)
+		pi->nr_if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num;
+	if (pi->nr_if_pool_objsize == 0)
+		pi->nr_if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size;
+	if (pi->nr_ring_pool_objtotal == 0)
+		pi->nr_ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num;
+	if (pi->nr_ring_pool_objsize == 0)
+		pi->nr_ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size;
+	if (pi->nr_buf_pool_objtotal == 0)
+		pi->nr_buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
+	if (pi->nr_buf_pool_objsize == 0)
+		pi->nr_buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
 	D("if %d %d ring %d %d buf %d %d",
-			pi.if_pool_objtotal, pi.if_pool_objsize,
-			pi.ring_pool_objtotal, pi.ring_pool_objsize,
-			pi.buf_pool_objtotal, pi.buf_pool_objsize);
+			pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize,
+			pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize,
+			pi->nr_buf_pool_objtotal, pi->nr_buf_pool_objsize);
 		
-	os = nm_os_extmem_create(p, &pi, &error);
+	os = nm_os_extmem_create(usrptr, pi, &error);
 	if (os == NULL) {
 		D("os extmem creation failed");
 		goto out;
@@ -2181,9 +2175,9 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){
-				{ pi.if_pool_objsize, pi.if_pool_objtotal },
-				{ pi.ring_pool_objsize, pi.ring_pool_objtotal },
-				{ pi.buf_pool_objsize, pi.buf_pool_objtotal }},
+				{ pi->nr_if_pool_objsize, pi->nr_if_pool_objtotal },
+				{ pi->nr_ring_pool_objsize, pi->nr_ring_pool_objtotal },
+				{ pi->nr_buf_pool_objsize, pi->nr_buf_pool_objtotal }},
 			&netmap_mem_ext_ops,
 			&error);
 	if (nme == NULL)
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index ec014603f..7410bec08 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -150,7 +150,7 @@ void __netmap_mem_put(struct netmap_mem_d *, const char *, int);
 struct netmap_mem_d* netmap_mem_find(nm_memid_t);
 
 #ifdef WITH_EXTMEM
-struct netmap_mem_d* netmap_mem_ext_create(struct nmreq *, int *);
+struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *, int *);
 #else /* !WITH_EXTMEM */
 #define netmap_mem_ext_create(nmr, _perr) \
 	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
@@ -165,7 +165,7 @@ struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16
 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
 #endif /* WITH_PTNETMAP_GUEST */
 
-int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
+int netmap_mem_pools_info_get(struct nmreq_pools_info *,
 				struct netmap_mem_d *);
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
@@ -177,7 +177,7 @@ uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 #ifdef WITH_EXTMEM
 #include 
 struct nm_os_extmem; /* opaque */
-struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct netmap_pools_info *, int *perror);
+struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct nmreq_pools_info *, int *perror);
 char *nm_os_extmem_nextpage(struct nm_os_extmem *);
 int nm_os_extmem_nr_pages(struct nm_os_extmem *);
 int nm_os_extmem_isequal(struct nm_os_extmem *, struct nm_os_extmem *);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 136264228..a1bcc06a9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -664,7 +664,7 @@ struct nmreq_vale_polling {
  * to a given netmap control device (used i.e. by a ptnetmap-enabled
  * hypervisor). The nr_hdr.nr_name field is ignored.
  */
-struct nmreq_pools_info_get {
+struct nmreq_pools_info {
 	uint64_t	nr_memsize;
 	uint16_t	nr_mem_id;
 	uint64_t	nr_if_pool_offset;
@@ -678,4 +678,14 @@ struct nmreq_pools_info_get {
 	uint32_t	nr_buf_pool_objsize;
 };
 
+/*
+ * data for NETMAP_REQ_OPT_* options
+ */
+
+struct nmreq_opt_extmem {
+	struct nmreq_option	nro_opt;	/* common header */
+	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */
+	struct nmreq_pools_info	nro_info;	/* (in/out) */
+};
+
 #endif /* _NET_NETMAP_H_ */
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 679a31a7a..5555a1eb2 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -836,6 +836,7 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 static int
 nm_interp_memid(const char *memid, struct nmreq *req, char **err)
 {
+#if 0
 	int fd = -1;
 	char errmsg[MAXERRMSG] = "";
 	struct nmreq greq;
@@ -891,6 +892,12 @@ nm_interp_memid(const char *memid, struct nmreq *req, char **err)
 	if (err && !*err)
 		*err = strdup(errmsg);
 	return errno;
+#else
+	(void)memid;
+	(void)req;
+	(void)err;
+	return EOPNOTSUPP;
+#endif
 }
 
 static int
@@ -943,7 +950,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	const struct nm_desc *parent = arg;
 	char errmsg[MAXERRMSG] = "";
 	uint32_t nr_reg;
-	struct netmap_pools_info *pi = NULL;
+	struct nmreq_pools_info *pi = NULL;
 
 	if (strncmp(ifname, "netmap:", 7) &&
 			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@@ -998,6 +1005,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->self = d;
 	}
 
+#if 0
 	/* compatibility checks for POOL_SCREATE and NM_OPEN flags
 	 * the first check may be dropped once we have a larger nreq
 	 */
@@ -1019,12 +1027,14 @@ nm_open(const char *ifname, const struct nmreq *req,
 			}
 		}
 	}
+#endif
 
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
+#if 0
 		if (new_flags & NM_OPEN_EXTMEM) {
 			if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
 				d->req.nr_cmd = NETMAP_POOLS_CREATE;
@@ -1033,6 +1043,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 				new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
 			}
 		}
+#endif
 		if (new_flags & NM_OPEN_ARG1) {
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 			d->req.nr_arg1 = parent->req.nr_arg1;
@@ -1065,9 +1076,11 @@ nm_open(const char *ifname, const struct nmreq *req,
 	/* add the *XPOLL flags */
 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
 
+#if 0
 	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
 		pi = nmreq_pointer_get(&d->req);
 	}
+#endif
 
 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
@@ -1076,7 +1089,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (pi != NULL) {
 		d->mem = pi;
-		d->memsize = pi->memsize;
+		d->memsize = pi->nr_memsize;
 		nm_init_offsets(d);
 	} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
 		/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */

From 34cc457936402c0709993eef8d0a3796744d034a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 09:29:44 +0100
Subject: [PATCH 0435/2207] testmmap: fix compilation

---
 sys/net/netmap_user.h |  2 +-
 utils/ctrl-api-test.c |  2 +-
 utils/testmmap.c      | 14 ++++++++------
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 5555a1eb2..9b81abf60 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -980,7 +980,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
-		char *err;
+		char *err = NULL;
 		switch (nm_parse_one(ifname, &d->req, &err, 1)) {
 		case NM_PARSE_OK:
 			break;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 21a1f8d4a..8d9b9cb42 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -360,7 +360,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 static int
 pools_info_get(int fd, struct TestContext *ctx)
 {
-	struct nmreq_pools_info_get req;
+	struct nmreq_pools_info req;
 	struct nmreq_header hdr;
 	int ret;
 
diff --git a/utils/testmmap.c b/utils/testmmap.c
index aabb2a81a..3f8548773 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -839,11 +839,11 @@ struct pools_info_field {
 	size_t off;
 	size_t size;
 };
-#define PIFD(n, f)	{ n, offsetof(struct netmap_pools_info, f), \
-	sizeof(((struct netmap_pools_info *)0)->f) }
+#define PIFD(n, f)	{ n, offsetof(struct nmreq_pools_info, nr_##f), \
+	sizeof(((struct nmreq_pools_info *)0)->nr_##f) }
 struct pools_info_field pools_info_fields[] = {
 	PIFD("memsize", memsize),
-	PIFD("memid", memid),
+	PIFD("mem_id", mem_id),
 	PIFD("if-off", if_pool_offset),
 	PIFD("if-tot", if_pool_objtotal),
 	PIFD("if-siz", if_pool_objsize),
@@ -857,7 +857,7 @@ struct pools_info_field pools_info_fields[] = {
 };
 #define PIF(t, p, o)	(*(t*)((void *)((char *)(p)+(o))))
 void
-pools_info_dump(int tab, struct netmap_pools_info *upi)
+pools_info_dump(int tab, struct nmreq_pools_info *upi)
 {
 	static const char space[] = "        ";
 	struct pools_info_field *f;
@@ -877,6 +877,9 @@ pools_info_dump(int tab, struct netmap_pools_info *upi)
 	}
 }
 
+
+static struct nmreq_pools_info curr_pools_info;
+
 /* prepare the curr_pools_info */
 void
 do_pools_info()
@@ -1356,7 +1359,6 @@ static struct nmreq_vale_list curr_vale_list;
 static struct nmreq_port_hdr curr_port_hdr;
 static struct nmreq_vale_newif curr_vale_newif;
 static struct nmreq_vale_polling curr_vale_polling;
-static struct nmreq_pools_info_get curr_pools_info_get;
 
 typedef void (*nmr_body_dump_fun)(void *);
 
@@ -1756,7 +1758,7 @@ do_hdr_type()
 		curr_hdr.nr_body = &curr_vale_polling;
 	} else if (strcmp(type, "pools-info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-		curr_hdr.nr_body = &curr_pools_info_get;
+		curr_hdr.nr_body = &curr_pools_info;
 	} else {
 		output("unknown type: %s", type);
 	}

From e9b8d5de8ecd9cf906552c007dba166de5e5a7c2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 17:29:33 +0100
Subject: [PATCH 0436/2207] testmmap: nmreq options support

---
 sys/dev/netmap/netmap.c |  1 +
 utils/testmmap.c        | 41 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ddb2c4661..224e97d94 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2274,6 +2274,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						(struct nmreq_opt_extmem *)opt;
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
+					opt->nro_status = error;
 					if (nmd == NULL)
 						break;
 				}
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 3f8548773..adf4a4ae9 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1597,13 +1597,30 @@ nmr_body_dump_pools_info_get(void *b)
 	(void)b;
 }
 
+typedef void (*nmr_option_dump_fun)(struct nmreq_option *);
+
+static void
+nmr_option_dump_extmem(struct nmreq_option *opt)
+{
+	struct nmreq_opt_extmem *e =
+		(struct nmreq_opt_extmem *)opt;
+
+	printf("usrptr: %p\n", (void *)e->nro_usrptr);
+	printf("info:\n");
+	pools_info_dump(4, &e->nro_info);
+}
+
 static void
 nmr_option_dump(struct nmreq_option *opt)
 {
-	printf("type: %u [", opt->nro_reqtype);
+	nmr_option_dump_fun d = NULL;
+
+	printf("next: %p\n", opt->nro_next);
+	printf("type: %"PRIu32" [", opt->nro_reqtype);
 	switch (opt->nro_reqtype) {
 	case NETMAP_REQ_OPT_EXTMEM:
 		printf("extmem");
+		d = nmr_option_dump_extmem;
 		break;
 	default:
 #ifdef NETMAP_OPT_DEBUG
@@ -1616,7 +1633,10 @@ nmr_option_dump(struct nmreq_option *opt)
 		printf("???");
 	}
 	printf("]\n");
-	printf("next: %p\n", opt->nro_next);
+	printf("status: %"PRIu32" [%s]\n", 
+			opt->nro_status, strerror(opt->nro_status));
+	if (d)
+		d(opt);
 }
 
 static void
@@ -1765,6 +1785,17 @@ do_hdr_type()
 	output("type=%u", curr_hdr.nr_reqtype);
 }
 
+typedef void (*nmreq_opt_init)(struct nmreq_option *);
+
+static void
+nmreq_opt_extmem_init(struct nmreq_option *opt)
+{
+	struct nmreq_opt_extmem *e =
+		(struct nmreq_opt_extmem *)opt;
+	e->nro_usrptr = (uint64_t)last_mmap_addr;
+	e->nro_info.nr_memsize = last_memsize;
+}
+
 static void
 do_hdr_option()
 {
@@ -1772,12 +1803,15 @@ do_hdr_option()
 	struct nmreq_option **ptr = &curr_hdr.nr_options,
 			    *old = *ptr;
 	size_t sz = sizeof(struct nmreq_option);
+	nmreq_opt_init init = NULL;
 
 	while ( (type = nextarg()) ) {
 		uint16_t reqtype;
 
 		if (strcmp(type, "extmem") == 0) {
 			reqtype = NETMAP_REQ_OPT_EXTMEM;
+			sz = sizeof(struct nmreq_opt_extmem);
+			init = nmreq_opt_extmem_init;
 #ifdef NETMAP_OPT_DEBUG
 		} else {
 			reqtype = strtol(type, NULL, 0) | NETMAP_REQ_OPT_DEBUG;
@@ -1787,7 +1821,10 @@ do_hdr_option()
 		if (*ptr == NULL) {
 			output_err(-1, "malloc");
 		}
+		memset(*ptr, 0, sz);
 		(*ptr)->nro_reqtype = reqtype;
+		if (init)
+			init(*ptr);
 		ptr = &(*ptr)->nro_next;
 	}
 	*ptr = old;

From 452515f7cab51bcaaf1cc0662574db8a2eeb3256 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 19:05:33 +0100
Subject: [PATCH 0437/2207] nmreq_copyin: do not access userspace memory

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 224e97d94..66fcde594 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2724,7 +2724,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	}
 
 	bodysz = 2 * sizeof(void *) + rqsz;
-	for (src = hdr->nr_options; src; src = src->nro_next) {
+	for (src = hdr->nr_options; src; src = buf.nro_next) {
 		size_t optsz;
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)

From 4f834dcb91667ccea90e22b6e57f190ed36b3fa3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 19:05:54 +0100
Subject: [PATCH 0438/2207] nmreq_copyout: always restore the header

---
 sys/dev/netmap/netmap.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 66fcde594..f2a59a740 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2812,21 +2812,22 @@ static int
 nmreq_copyout(struct nmreq_header *hdr, int error)
 {
 	struct nmreq_option *src, *dst;
-	void *ker = hdr->nr_body;
+	void *ker = hdr->nr_body, *bufstart;
 	void **ptrs;
 	size_t bodysz;
 
 	if (!hdr->nr_reserved)
 		return error;
 
-	if (error)
-		goto out;
-
 	/* restore the user pointers in the header */
-	ptrs = (void **)ker;
-	hdr->nr_body = *(ptrs - 2);
+	ptrs = (void **)ker - 2;
+	bufstart = ptrs;
+	hdr->nr_body = *ptrs++;
 	src = hdr->nr_options;
-	hdr->nr_options = *(ptrs - 1);
+	hdr->nr_options = *ptrs;
+
+	if (error)
+		goto out;
 
 	/* copy the body */
 	bodysz = nmreq_size_by_type(hdr->nr_reqtype);
@@ -2861,10 +2862,10 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 		dst = *ptrs;
 	}
 
-	hdr->nr_reserved = 0;
 
 out:
-	nm_os_free(ker);
+	hdr->nr_reserved = 0;
+	nm_os_free(bufstart);
 	return error;
 }
 

From b116edbf44f6c8f9d91050658c2f3432d5193375 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:00:06 +0100
Subject: [PATCH 0439/2207] nmreq_copyin: fix size computations

---
 sys/dev/netmap/netmap.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f2a59a740..38616a1ce 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2694,7 +2694,7 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 int
 nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
-	size_t bufsz, rqsz, bodysz;
+	size_t rqsz, optsz, bufsz;
 	int error;
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src;
@@ -2723,23 +2723,21 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		goto out_err;
 	}
 
-	bodysz = 2 * sizeof(void *) + rqsz;
+	bufsz = 2 * sizeof(void *) + rqsz;
+	optsz = 0;
 	for (src = hdr->nr_options; src; src = buf.nro_next) {
-		size_t optsz;
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)
 			goto out_err;
-		optsz = sizeof(*src);
+		optsz += sizeof(*src);
 		optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
 		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
 			error = EMSGSIZE;
 			goto out_err;
 		}
-		rqsz += optsz;
 		bufsz += optsz + sizeof(void *);
 	}
 
-	bufsz = max(1024UL, roundup_pow_of_two(bodysz));
 	ker = nm_os_malloc(bufsz);
 	if (ker == NULL) {
 		error = ENOMEM;
@@ -2765,7 +2763,6 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	next = &hdr->nr_options;
 	src = *next;
 	while (src) {
-		size_t optsz;
 		struct nmreq_option *opt;
 
 		/* copy the option header */

From 9bd89566ff15da630ee89805842cf4fa4f22e33d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:00:56 +0100
Subject: [PATCH 0440/2207] nmreq_copyin: restore the user header in case of
 error

---
 sys/dev/netmap/netmap.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 38616a1ce..3c70e7afa 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2704,11 +2704,11 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	if (hdr->nr_reserved)
 		return EINVAL;
 
-	hdr->nr_reserved = nr_body_is_user;
-
 	if (!nr_body_is_user)
 		return 0;
 
+	hdr->nr_reserved = nr_body_is_user;
+
 	/* compute the total size of the buffer */
 	rqsz = nmreq_size_by_type(hdr->nr_reqtype);
 	if (rqsz > NETMAP_REQ_MAXSIZE) {
@@ -2754,7 +2754,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	/* copy the body */
 	error = copyin(hdr->nr_body, p, rqsz);
 	if (error)
-		goto out_err;
+		goto out_restore;
 	/* overwrite the user pointer with the in-kernel one */
 	hdr->nr_body = p;
 	p += rqsz;
@@ -2770,7 +2770,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		opt = (struct nmreq_option *)(ptrs + 1);
 		error = copyin(src, opt, sizeof(*src));
 		if (error)
-			goto out_err;
+			goto out_restore;
 		/* make a copy of the user next pointer */
 		*ptrs = opt->nro_next;
 		/* overwrite the user pointer with the in-kernel one */
@@ -2789,7 +2789,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 			/* the option body follows the option header */
 			error = copyin(src + 1, p, optsz);
 			if (error)
-				goto out_err;
+				goto out_restore;
 			p += optsz;
 		}
 
@@ -2799,9 +2799,13 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	}
 	return 0;
 
+out_restore:
+	ptrs = (void **)ker;
+	hdr->nr_body = *ptrs++;
+	hdr->nr_options = *ptrs++;
+	hdr->nr_reserved = 0;
+	nm_os_free(ker);
 out_err:
-	if (ker)
-		nm_os_free(ker);
 	return error;
 }
 

From a0c129a2c9ef43fcc7b6080165a9ca0d0f686240 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:03:05 +0100
Subject: [PATCH 0441/2207] nmreq_copyout: always copy the option headers

---
 sys/dev/netmap/netmap.c | 46 ++++++++++++++++++++++++-----------------
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3c70e7afa..f009df2fa 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2810,15 +2810,16 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 }
 
 static int
-nmreq_copyout(struct nmreq_header *hdr, int error)
+nmreq_copyout(struct nmreq_header *hdr, int rerror)
 {
 	struct nmreq_option *src, *dst;
 	void *ker = hdr->nr_body, *bufstart;
 	void **ptrs;
 	size_t bodysz;
+	int error;
 
 	if (!hdr->nr_reserved)
-		return error;
+		return rerror;
 
 	/* restore the user pointers in the header */
 	ptrs = (void **)ker - 2;
@@ -2827,14 +2828,15 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 	src = hdr->nr_options;
 	hdr->nr_options = *ptrs;
 
-	if (error)
-		goto out;
-
-	/* copy the body */
-	bodysz = nmreq_size_by_type(hdr->nr_reqtype);
-	error = copyout(ker, hdr->nr_body, bodysz);
-	if (error)
-		goto out;
+	if (!rerror) {
+		/* copy the body */
+		bodysz = nmreq_size_by_type(hdr->nr_reqtype);
+		error = copyout(ker, hdr->nr_body, bodysz);
+		if (error) {
+			rerror = error;
+			goto out;
+		}
+	}
 
 	/* copy the options */
 	dst = hdr->nr_options;
@@ -2847,17 +2849,23 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 		ptrs = (void **)src - 1;
 		src->nro_next = *ptrs;
 
-		/* copy the option header */
+		/* always copy the option header */
 		error = copyout(src, dst, sizeof(src));
-		if (error)
+		if (error) {
+			rerror = error;
 			goto out;
+		}
 		       
-		/* copy the option body */
-		optsz = nmreq_opt_size_by_type(src->nro_reqtype);
-		if (optsz) {
-			error = copyout(dst + 1, src + 1, optsz);
-			if (error)
-				goto out;
+		/* copy the option body only if there was no error */
+		if (!rerror && !src->nro_status) {
+			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+			if (optsz) {
+				error = copyout(dst + 1, src + 1, optsz);
+				if (error) {
+					rerror = error;
+					goto out;
+				}
+			}
 		}
 		src = next;
 		dst = *ptrs;
@@ -2867,7 +2875,7 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 out:
 	hdr->nr_reserved = 0;
 	nm_os_free(bufstart);
-	return error;
+	return rerror;
 }
 
 struct nmreq_option *

From 50dafe8e495a15f5aed15e403850a701353dbe1b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:13:59 +0100
Subject: [PATCH 0442/2207] options: check for duplicates

---
 sys/dev/netmap/netmap.c      | 27 ++++++++++++++++++++++-----
 sys/dev/netmap/netmap_kern.h |  3 ++-
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f009df2fa..762d7f5a0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2268,10 +2268,14 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 #ifdef WITH_EXTMEM
-				opt = nmreq_findoption(hdr, NETMAP_REQ_OPT_EXTMEM);
+				opt = nmreq_findoption(hdr->nr_options, NETMAP_REQ_OPT_EXTMEM);
 				if (opt != NULL) {
 					struct nmreq_opt_extmem *e =
 						(struct nmreq_opt_extmem *)opt;
+
+					error = nmreq_checkduplicate(opt);
+					if (error)
+						break;
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
 					opt->nro_status = error;
@@ -2879,16 +2883,29 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 }
 
 struct nmreq_option *
-nmreq_findoption(struct nmreq_header *hdr, uint16_t reqtype)
+nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
 {
-	struct nmreq_option *opt;
-
-	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+	for ( ; opt; opt = opt->nro_next)
 		if (opt->nro_reqtype == reqtype)
 			return opt;
 	return NULL;
 }
 
+int
+nmreq_checkduplicate(struct nmreq_option *opt) {
+	struct nmreq_option *scan;
+	uint16_t type = opt->nro_reqtype;
+	int dup = 0;
+
+	for (scan = opt->nro_next; scan;
+		scan = nmreq_findoption(scan, type))
+	{
+		dup++;
+		scan->nro_status = EINVAL;
+	}
+	return (dup ? EINVAL : 0);
+}
+
 static int
 nmreq_checkoptions(struct nmreq_header *hdr)
 {
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a4ab18bfb..92846eb86 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2191,6 +2191,7 @@ void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
 #endif /* WITH_PTNETMAP_GUEST */
 
-struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
+int nmreq_checkduplicate(struct nmreq_option *);
 
 #endif /* _NET_NETMAP_KERN_H_ */

From 739e3c75714d6355ecea4c0408ecde11f936bb5e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 17:54:46 +0100
Subject: [PATCH 0443/2207] wip

---
 utils/ctrl-api-test.c | 68 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 55 insertions(+), 13 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8d9b9cb42..20b06dab1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -26,6 +26,7 @@ struct TestContext {
 
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
+	struct nmreq_option *nr_opt; /* list of options */
 };
 
 #if 0
@@ -99,6 +100,7 @@ port_register(int fd, struct TestContext *ctx)
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 	hdr.nr_body    = &req;
+	hdr.nr_options = ctx->nr_opt;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id     = ctx->nr_mem_id;
 	req.nr_mode       = ctx->nr_mode;
@@ -531,25 +533,65 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 	return vale_detach(fd, ctx);
 }
 
+static void
+push_option(struct nmreq_option *opt, struct TestContext *ctx)
+{
+	opt->nro_next = ctx->nr_opt;
+	ctx->nr_opt = opt;
+}
+
+static void
+clear_options(struct TestContext *ctx)
+{
+	ctx->nr_opt = NULL;
+}
+
+static int
+unsupported_option(int fd, struct TestContext *ctx)
+{
+	struct nmreq_option opt, save;
+
+	printf("Testing unsupported option on %s\n", ctx->ifname);
+
+	opt.nro_reqtype = 1234;
+	push_option(&opt, ctx);
+	save = opt;
+
+	if (!port_register_hwall(fd, ctx))
+		return 1;
+
+	clear_options(ctx);
+
+	return opt.nro_reqtype == save.nro_reqtype   &&
+	       opt.nro_next == save.nro_next &&
+	       opt.nro_status == EOPNOTSUPP;
+}
+
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
-static testfunc_t tests[] = {port_info_get,
-			     port_register_hwall_host,
-			     port_register_hwall,
-			     port_register_host,
-			     port_register_single_ring_couple,
-			     vale_attach_detach,
-			     vale_attach_detach_host_rings,
-			     vale_ephemeral_port_hdr_manipulation,
-			     vale_persistent_port,
-			     register_and_pools_info_get,
-			     pipe_master,
-			     pipe_slave,
-			     vale_polling_enable_disable};
+static testfunc_t tests[] = {
+	port_info_get,
+	port_register_hwall_host,
+	port_register_hwall,
+	port_register_host,
+	port_register_single_ring_couple,
+	vale_attach_detach,
+	vale_attach_detach_host_rings,
+	vale_ephemeral_port_hdr_manipulation,
+	vale_persistent_port,
+	register_and_pools_info_get,
+	pipe_master,
+	pipe_slave,
+	vale_polling_enable_disable,
+	unsupported_option
+//	infinite_options,
+//	extmem_option,
+//	duplicate_extmem_options
+};
 
 int
 main(int argc, char **argv)

From 69c43e7b8b4d51eafead948ec8156c254382f59a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 18:26:43 +0100
Subject: [PATCH 0444/2207] nmreq_copyout: fix size of copyout

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 762d7f5a0..5db3455fc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2854,7 +2854,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 		src->nro_next = *ptrs;
 
 		/* always copy the option header */
-		error = copyout(src, dst, sizeof(src));
+		error = copyout(src, dst, sizeof(*src));
 		if (error) {
 			rerror = error;
 			goto out;

From f57cd69f969fc4572100a41bf916cce61c9b18fe Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 3 Feb 2018 08:56:58 +0100
Subject: [PATCH 0445/2207] dkms: add disclaimer

---
 LINUX/dkms/README.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/LINUX/dkms/README.md b/LINUX/dkms/README.md
index b569482b5..16c9e3dfa 100644
--- a/LINUX/dkms/README.md
+++ b/LINUX/dkms/README.md
@@ -1,6 +1,16 @@
 DKMS GUIDE
 ==========
 
+**Disclaimer**
+The dkms build infrastructure is not the official way to build netmap and its
+patched drivers.
+This alternative build system is not actively maintained, so you may need some
+tweaks to make it work on your platform.
+
+Please prefer the standard ./configure && make && make install process to
+build netmap.
+**************
+
 Some prerequisites:
     # apt-get install dkms linux-source linux-headers-$(uname -r) devscripts
 

From bd492bb0a7e2902f99bd1c1cdcc354a6fb2ff412 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:34:31 +0100
Subject: [PATCH 0446/2207] nmreq_copyout: fix direction of copy

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5db3455fc..e8f987a15 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2864,7 +2864,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 		if (!rerror && !src->nro_status) {
 			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
 			if (optsz) {
-				error = copyout(dst + 1, src + 1, optsz);
+				error = copyout(src + 1, dst + 1, optsz);
 				if (error) {
 					rerror = error;
 					goto out;

From 0a1719449c98ab734202314a9b851f28b77cc32e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:53:18 +0100
Subject: [PATCH 0447/2207] extmem: fix scan of duplicate options

---
 LINUX/netmap_linux.c    | 1 -
 sys/dev/netmap/netmap.c | 6 ++++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e2e648faa..8be1ecc85 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -193,7 +193,6 @@ nm_os_extmem_nextpage(struct nm_os_extmem *e)
 {
 	if (e->mapped >= e->nr_pages)
 		return NULL;
-	D("mapping %d/%d", e->mapped, e->nr_pages);
 	return kmap(e->pages[e->mapped++]);
 }
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e8f987a15..87de4ef35 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2274,8 +2274,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						(struct nmreq_opt_extmem *)opt;
 
 					error = nmreq_checkduplicate(opt);
-					if (error)
+					if (error) {
+						opt->nro_status = error;
 						break;
+					}
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
 					opt->nro_status = error;
@@ -2898,7 +2900,7 @@ nmreq_checkduplicate(struct nmreq_option *opt) {
 	int dup = 0;
 
 	for (scan = opt->nro_next; scan;
-		scan = nmreq_findoption(scan, type))
+		scan = nmreq_findoption(scan->nro_next, type))
 	{
 		dup++;
 		scan->nro_status = EINVAL;

From 5cfd9db7f9a9698a6b9fdbc0e93772c6ba01a497 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:54:15 +0100
Subject: [PATCH 0448/2207] mem: prevent mem2 to free extmem clusters

---
 sys/dev/netmap/netmap_mem2.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index b72c6f6b6..def02d3e6 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -108,6 +108,7 @@ struct netmap_obj_pool {
 	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
 	uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */
 	uint32_t bitmap_slots;	/* number of uint32 entries in bitmap */
+	int	alloc_done;	/* we have allocated the memory */
 	/* ---------------------------------------------------*/
 
 	/* limits */
@@ -1174,6 +1175,12 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 	if (p->invalid_bitmap)
 		nm_os_free(p->invalid_bitmap);
 	p->invalid_bitmap = NULL;
+	if (!p->alloc_done) {
+		/* allocation was done by somebody else.
+		 * Let them clean up after themselves.
+		 */
+		return;
+	}
 	if (p->lut) {
 		u_int i;
 
@@ -1193,6 +1200,7 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 	p->memtotal = 0;
 	p->numclusters = 0;
 	p->objfree = 0;
+	p->alloc_done = 0;
 }
 
 /*
@@ -1304,13 +1312,20 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 	size_t n;
 
 	if (p->lut) {
-		/* already finalized, nothing to do */
+		/* if the lut is already there we assume that also all the
+		 * clusters have already been allocated, possibily by somebody
+		 * else (e.g., extmem). In the latter case, the alloc_done flag
+		 * will remain at zero, so that we will not attempt to
+		 * deallocate the clusters by ourselves in
+		 * netmap_reset_obj_allocator.
+		 */
 		return 0;
 	}
 
 	/* optimistically assume we have enough memory */
 	p->numclusters = p->_numclusters;
 	p->objtotal = p->_objtotal;
+	p->alloc_done = 1;
 
 	p->lut = nm_alloc_lut(p->objtotal);
 	if (p->lut == NULL) {

From 57adf5068e2a8427ecfc5d0f94eb9e201580edef Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:54:41 +0100
Subject: [PATCH 0449/2207] extmem: deleted leftovers from old API

---
 sys/dev/netmap/netmap_mem2.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index def02d3e6..ff98d6081 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2205,8 +2205,6 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 	 */
 	nme->os = os;
 	os = NULL; /* pass ownership */
-	nme->up.flags |= NETMAP_MEM_EXT;
-
 
 	clust = nm_os_extmem_nextpage(nme->os);
 	off = 0;
@@ -2280,12 +2278,6 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		ND("%d memtotal %u", j, p->memtotal);
 	}
 
-	/* skip the first netmap_if, where the pools info reside */
-	{
-		struct netmap_obj_pool *p = &nme->up.pools[NETMAP_IF_POOL];
-		p->invalid_bitmap[0] |= 1U;
-	}
-
 	netmap_mem_ext_register(nme);
 
 	return &nme->up;

From d5fa2bbc17493f335f951dff5ec60702a13bd382 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:58:18 +0100
Subject: [PATCH 0450/2207] tests for options and extmem

---
 utils/ctrl-api-test.c | 240 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 230 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 20b06dab1..b65a35a6f 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -7,7 +7,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 
 struct TestContext {
 	const char *ifname;
@@ -546,6 +548,30 @@ clear_options(struct TestContext *ctx)
 	ctx->nr_opt = NULL;
 }
 
+static int
+checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
+{
+	if (opt->nro_next != exp->nro_next) {
+		printf("nro_next %p expected %p\n",
+				opt->nro_next,
+				exp->nro_next);
+		return -1;
+	}
+	if (opt->nro_reqtype != exp->nro_reqtype) {
+		printf("nro_reqtype %u expected %u\n",
+				opt->nro_reqtype,
+				exp->nro_reqtype);
+		return -1;
+	}
+	if (opt->nro_status != exp->nro_status) {
+		printf("nro_status %u expected %u\n",
+				opt->nro_status,
+				exp->nro_status);
+		return -1;
+	}
+	return 0;
+}
+
 static int
 unsupported_option(int fd, struct TestContext *ctx)
 {
@@ -553,19 +579,210 @@ unsupported_option(int fd, struct TestContext *ctx)
 
 	printf("Testing unsupported option on %s\n", ctx->ifname);
 
+	memset(&opt, 0, sizeof(opt));
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
 	save = opt;
 
-	if (!port_register_hwall(fd, ctx))
-		return 1;
+	if (port_register_hwall(fd, ctx) >= 0)
+		return -1;
 
 	clear_options(ctx);
+	save.nro_status = EOPNOTSUPP;
+	return checkoption(&opt, &save);
+}
+
+static int
+infinite_options(int fd, struct TestContext *ctx)
+{
+	struct nmreq_option opt, save;
+
+	printf("Testing infinite list of options on %s\n", ctx->ifname);
+
+	opt.nro_reqtype = 1234;
+	push_option(&opt, ctx);
+	opt.nro_next = &opt;
+	save = opt;
+	if (port_register_hwall(fd, ctx) >= 0)
+		return -1;
+
+	clear_options(ctx);
+	save.nro_status = EOPNOTSUPP;
+	return checkoption(&opt, &save);
+}
+
+#ifdef WITH_EXTMEM
+static int
+change_param(const char *pname, unsigned long newv, unsigned long *poldv)
+{
+#ifdef linux
+	char param[256] = "/sys/module/netmap/parameters/";
+	unsigned long oldv;
+	FILE *f;
 
-	return opt.nro_reqtype == save.nro_reqtype   &&
-	       opt.nro_next == save.nro_next &&
-	       opt.nro_status == EOPNOTSUPP;
+	strncat(param, pname, 256);
+
+	f = fopen(param, "r+");
+	if (f == NULL) {
+		perror(param);
+		return -1;
+	}
+	if (fscanf(f, "%ld", &oldv) != 1) {
+		perror(param);
+		fclose(f);
+		return -1;
+	}
+	if (poldv)
+		*poldv = oldv;
+	rewind(f);
+	if (fprintf(f, "%ld\n", newv) < 0) {
+		perror(param);
+		fclose(f);
+		return -1;
+	}
+	fclose(f);
+	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
+#endif /* linux */
+	return 0;
+}
+
+
+static int
+push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
+{
+	void *addr;
+
+	addr = mmap(NULL, (1U << 22), PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	if (addr == MAP_FAILED) {
+		perror("mmap");
+		return -1;
+	}
+
+	memset(e, 0, sizeof(*e));
+	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
+	e->nro_usrptr = (uint64_t)addr;
+	e->nro_info.nr_memsize = (1U << 22);
+
+	push_option(&e->nro_opt, ctx);
+
+	return 0;
+}
+
+static int
+pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
+{
+	struct nmreq_opt_extmem *e;
+	int ret;
+
+	e = (struct nmreq_opt_extmem *)ctx->nr_opt;
+	ctx->nr_opt = ctx->nr_opt->nro_next;
+
+	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
+		return ret;
+	}
+
+	if (e->nro_usrptr != exp->nro_usrptr) {
+		printf("usrptr %"PRIu64" expected %"PRIu64"\n",
+				e->nro_usrptr,
+				exp->nro_usrptr);
+		return -1;
+	}
+	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
+		printf("memsize %"PRIu64" expected %"PRIu64"\n",
+				e->nro_info.nr_memsize,
+				exp->nro_info.nr_memsize);
+		return -1;
+	}
+
+	if ((ret = munmap((void *)e->nro_usrptr, e->nro_info.nr_memsize)))
+		return ret;
+
+	return 0;
+}
+
+static int
+_extmem_option(int fd, struct TestContext *ctx, int new_rsz)
+{
+	struct nmreq_opt_extmem e, save;
+	int ret;
+	unsigned long old_rsz;
+
+	if ((ret = push_extmem_option(ctx, &e)) < 0)
+		return ret;
+
+	save = e;
+
+	ctx->ifname = "vale0:0";
+	ctx->nr_tx_slots = 16;
+	ctx->nr_rx_slots = 16;
+
+	if ((ret = change_param("priv_ring_size", new_rsz, &old_rsz)))
+		return ret;
+
+	if ((ret = port_register_hwall(fd, ctx)))
+		return ret;
+
+	ret = pop_extmem_option(ctx, &save);
+
+	if (change_param("priv_ring_size", old_rsz, NULL) < 0)
+		return -1;
+
+	return ret;
+}
+
+static int
+extmem_option(int fd, struct TestContext *ctx)
+{
+	printf("Testing extmem option on vale0:0\n");
+
+	return _extmem_option(fd, ctx, 512);
+}
+
+static int
+bad_extmem_option(int fd, struct TestContext *ctx)
+{
+	printf("Testing bad extmem option on vale0:0\n");
+
+	return _extmem_option(fd, ctx, (1<<16)) < 0 ? 0 : -1;
+}
+
+static int
+duplicate_extmem_options(int fd, struct TestContext *ctx)
+{
+	struct nmreq_opt_extmem e1, save1, e2, save2;
+	int ret;
+
+	printf("Testing duplicate extmem option on vale0:0\n");
+
+	if ((ret = push_extmem_option(ctx, &e1)) < 0)
+		return ret;
+
+	if ((ret = push_extmem_option(ctx, &e2)) < 0) {
+		clear_options(ctx);
+		return ret;
+	}
+
+	save1 = e1;
+	save2 = e2;
+
+	ret = port_register_hwall(fd, ctx);
+	if (ret >= 0) {
+		printf("duplicate option not detected\n");
+		return -1;
+	}
+
+	save2.nro_opt.nro_status = EINVAL;
+	if ((ret = pop_extmem_option(ctx, &save2)))
+		return ret;
+
+	save1.nro_opt.nro_status = EINVAL;
+	if ((ret = pop_extmem_option(ctx, &save1)))
+		return ret;
+
+	return 0;
 }
+#endif /* WITH_EXTMEM */
 
 static void
 usage(const char *prog)
@@ -587,10 +804,13 @@ static testfunc_t tests[] = {
 	pipe_master,
 	pipe_slave,
 	vale_polling_enable_disable,
-	unsupported_option
-//	infinite_options,
-//	extmem_option,
-//	duplicate_extmem_options
+	unsupported_option,
+	infinite_options,
+#ifdef WITH_EXTMEM
+	extmem_option,
+	bad_extmem_option,
+	duplicate_extmem_options,
+#endif /* WITH_EXTMEM */
 };
 
 int
@@ -633,7 +853,7 @@ main(int argc, char **argv)
 			return -1;
 		}
 	}
-	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+	for (i = 0; i < sizeof(tests) / sizeof(tests[0]) - 1; i++) {
 		struct TestContext ctxcopy;
 		int fd;
 		int ret;

From ba45ed55fe73748363eee58ce3b344e348a02d94 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 11:32:13 +0100
Subject: [PATCH 0451/2207] vale: reset na pointer on port destruction

---
 sys/dev/netmap/netmap_vale.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 0704e4daa..28d9dda2e 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -547,11 +547,14 @@ netmap_vp_dtor(struct netmap_adapter *na)
 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
 	}
 
-	if (vpna->autodelete && na->ifp != NULL) {
-		ND("releasing %s", na->ifp->if_xname);
-		NMG_UNLOCK();
-		nm_os_vi_detach(na->ifp);
-		NMG_LOCK();
+	if (na->ifp != NULL && !nm_iszombie(na)) {
+		WNA(na->ifp) = NULL;
+		if (vpna->autodelete) {
+			ND("releasing %s", na->ifp->if_xname);
+			NMG_UNLOCK();
+			nm_os_vi_detach(na->ifp);
+			NMG_LOCK();
+		}
 	}
 }
 

From 4d37ce252e0819c38a153b661f26ec16eab05f5b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 18:48:15 +0100
Subject: [PATCH 0452/2207] linux/igb: play nice with ring pointers

---
 LINUX/if_igb_netmap.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 58926a5ea..b8cb56268 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -178,7 +178,6 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 		wmb();	/* synchronize writes to the NIC ring */
 
 		/* (re)start the tx unit up to slot nic_i (excluded) */
-		txr->next_to_use = nic_i;
 		writel(nic_i, txr->tail);
 		mmiowb(); // XXX why do we need this ?
 	}
@@ -255,6 +254,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
+			rxr->next_to_alloc = nic_i;
 			kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
@@ -291,7 +291,6 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 		 * so move nic_i back by one unit
 		 */
 		nic_i = nm_prev(nic_i, lim);
-		rxr->next_to_use = nic_i;
 		writel(nic_i, rxr->tail);
 	}
 
@@ -375,7 +374,6 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 
 	wmb();	/* Force memory writes to complete */
 	ND("%s rxr%d.tail %d", na->name, reg_idx, i);
-	rxr->next_to_use = i;
 	writel(i, rxr->tail);
 	return 1;	// success
 }

From a962bf410f507e66af5dfe7134fb9d5dd075d728 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 18:49:55 +0100
Subject: [PATCH 0453/2207] ignore producer binary

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 6bfcbdefd..9a82bc100 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,3 +73,4 @@ read-vars.mak
 LINUX/scripts/conf
 config.mak
 *.rej
+utils/producer

From 6f4cc1deefecf20c6a025690b0ec9bae0df6cf8a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 6 Feb 2018 09:26:57 +0100
Subject: [PATCH 0454/2207] nmreq options: fix compilation errors
 (!WITH_EXTMEM)

---
 sys/dev/netmap/netmap.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 87de4ef35..198b4cbff 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2260,7 +2260,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_LOCK();
 			do {
 				u_int memflags;
+#ifdef WITH_EXTMEM
 				struct nmreq_option *opt;
+#endif /* WITH_EXTMEM */
 
 				if (priv->np_nifp != NULL) {	/* thread already registered */
 					error = EBUSY;
@@ -2691,8 +2693,8 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 	case NETMAP_REQ_OPT_EXTMEM:
 		rv = sizeof(struct nmreq_opt_extmem);
 		break;
-	}
 #endif /* WITH_EXTMEM */
+	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
 }

From 43af23154ee83158ad4ff097fe7c5d6a6e435c3c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 6 Feb 2018 09:39:28 +0100
Subject: [PATCH 0455/2207] legacy: add missing write back of nmr->nr_name for
 NETMAP_BDG_LIST

---
 sys/dev/netmap/netmap_legacy.c | 1 +
 sys/dev/netmap/netmap_vale.c   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index a8f510f0e..61e924708 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -316,6 +316,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_VALE_LIST: {
 		struct nmreq_vale_list *req =
 			(struct nmreq_vale_list *)hdr->nr_body;
+		strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 151fb0b5c..868ca8cd7 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1312,6 +1312,7 @@ netmap_bdg_list(struct nmreq_header *hdr)
 				if (b->bdg_ports[j] == NULL)
 					continue;
 				vpna = b->bdg_ports[j];
+				/* write back the VALE switch name */
 				strncpy(hdr->nr_name, vpna->up.name,
 					(size_t)IFNAMSIZ);
 				error = 0;

From 6bd62a43b0cdf7a55309d021095f4f32f024855f Mon Sep 17 00:00:00 2001
From: Vitaly 
Date: Wed, 7 Feb 2018 09:50:31 +0300
Subject: [PATCH 0456/2207] Formatted if_vmxnet3_netmap.h

---
 LINUX/if_vmxnet3_netmap.h | 1008 ++++++++++++++++++-------------------
 1 file changed, 491 insertions(+), 517 deletions(-)

diff --git a/LINUX/if_vmxnet3_netmap.h b/LINUX/if_vmxnet3_netmap.h
index cec6060f0..d628d506b 100644
--- a/LINUX/if_vmxnet3_netmap.h
+++ b/LINUX/if_vmxnet3_netmap.h
@@ -2,618 +2,592 @@
 #ifndef _IF_VMXNET3_NETMAP_H_
 #define _IF_VMXNET3_NETMAP_H_
 
-
 #include 
 #include 
 #include 
 
-#define SOFTC_T	vmxnet3_adapter
-
-
-static int vmxnet3_rq_create_all( struct vmxnet3_adapter* adapter );
-static void vmxnet3_unmap_tx_buf( struct vmxnet3_tx_buf_info* tbi, struct pci_dev* pdev );
+#define SOFTC_T vmxnet3_adapter
 
+static int vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter);
+static void vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
+				 struct pci_dev *pdev);
 
-static int vmxnet3_netmap_reg( struct netmap_adapter* na, int onoff )
+static int vmxnet3_netmap_reg(struct netmap_adapter *na, int onoff)
 {
-    int err = 0;
-
-    struct ifnet* ifp = na->ifp;
-    struct SOFTC_T* adapter = netdev_priv( ifp );
-
-    /* protect against other reinit */
-    while( test_and_set_bit( VMXNET3_STATE_BIT_RESETTING, &adapter->state ) )
-        usleep_range( 1000, 2000 );
-
-    if( netif_running( adapter->netdev ) )
-    {
-        vmxnet3_quiesce_dev( adapter );
-        vmxnet3_reset_dev( adapter );
-
-        vmxnet3_rq_destroy_all( adapter );
-
-        err = vmxnet3_rq_create_all( adapter );
-        if( err )
-            goto out;
-    }
-
-    /* enable or disable flags and callbacks in na and ifp */
-    if( onoff )
-    {
-        nm_set_native_flags( na );
-    }
-    else
-    {
-        nm_clear_native_flags( na );
-    }
-
-
-    if( netif_running( adapter->netdev ) )
-    {
-        err = vmxnet3_activate_dev( adapter );
-        if( err )
-            goto out;
-    }
-    else
-    {
-        vmxnet3_reset_dev( adapter );
-    }
-
-out:
-    clear_bit( VMXNET3_STATE_BIT_RESETTING, &adapter->state );
+	int err = 0;
 
-    if( err )
-    {
-        vmxnet3_force_close( adapter );
-    }
+	struct ifnet *ifp = na->ifp;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
 
+	/* protect against other reinit */
+	while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+		usleep_range(1000, 2000);
 
-    return 0;
-}
-
-
-static int vmxnet3_netmap_unmap_pkt( u32 eop_idx, struct vmxnet3_tx_queue* tq, struct pci_dev* pdev )
-{
-    int entries = 0;
+	if (netif_running(adapter->netdev)) {
+		vmxnet3_quiesce_dev(adapter);
+		vmxnet3_reset_dev(adapter);
 
-    //
-    // no out of order completion
-    //
+		vmxnet3_rq_destroy_all(adapter);
 
-    BUG_ON( tq->buf_info[ eop_idx ].sop_idx != tq->tx_ring.next2comp );
-    BUG_ON( VMXNET3_TXDESC_GET_EOP( &( tq->tx_ring.base[ eop_idx ].txd ) ) != 1 );
+		err = vmxnet3_rq_create_all(adapter);
+		if (err)
+			goto out;
+	}
 
-    BUG_ON( tq->buf_info[ eop_idx ].skb != NULL );
+	/* enable or disable flags and callbacks in na and ifp */
+	if (onoff) {
+		nm_set_native_flags(na);
+	} else {
+		nm_clear_native_flags(na);
+	}
 
+	if (netif_running(adapter->netdev)) {
+		err = vmxnet3_activate_dev(adapter);
+		if (err)
+			goto out;
+	} else {
+		vmxnet3_reset_dev(adapter);
+	}
 
-    VMXNET3_INC_RING_IDX_ONLY( eop_idx, tq->tx_ring.size );
-
-    while( tq->tx_ring.next2comp != eop_idx )
-    {
-        vmxnet3_unmap_tx_buf( tq->buf_info + tq->tx_ring.next2comp, pdev );
-
-        //
-        // update next2comp w/o tx_lock. Since we are marking more,
-        // instead of less, tx ring entries avail, the worst case is
-        // that the tx routine incorrectly re-queues a pkt due to
-        // insufficient tx ring entries.
-        //
-        
-        vmxnet3_cmd_ring_adv_next2comp( &tq->tx_ring );
-        entries++;
-    }
-
-
-    return entries;
-}
-
-
-static int vmxnet3_netmap_tq_tx_complete( struct vmxnet3_tx_queue* tq, struct pci_dev* pdev )
-{
-    int completed = 0;
-    union Vmxnet3_GenericDesc* gdesc;
-
-
-    gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
-
-    while( VMXNET3_TCD_GET_GEN( &gdesc->tcd ) == tq->comp_ring.gen )
-    {
-        completed += vmxnet3_netmap_unmap_pkt( VMXNET3_TCD_GET_TXIDX( &gdesc->tcd ), tq, pdev );
-
-        vmxnet3_comp_ring_adv_next2proc( &tq->comp_ring );
-        gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
-    }
+out:
+	clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
 
+	if (err) {
+		vmxnet3_force_close(adapter);
+	}
 
-    return completed;
+	return 0;
 }
 
-
-static int vmxnet3_netmap_txsync( struct netmap_kring* kring, int flags )
+static int vmxnet3_netmap_unmap_pkt(u32 eop_idx, struct vmxnet3_tx_queue *tq,
+				    struct pci_dev *pdev)
 {
-#define  kUseTwoTxDescForPacket     0
-#define  kMinFreeTxDescForPacket    (kUseTwoTxDescForPacket ? 2 : 1)
-
-    struct netmap_adapter* na = kring->na;
-    struct ifnet* ifp = na->ifp;
-    struct netmap_ring* ring = kring->ring;
-
-    u_int n;
-    u_int nm_i;	// index into the netmap ring
-    int completed;
-    u_int deferred = 0;
-    u_int ring_nr = kring->ring_id;
-
-    u_int const lim = kring->nkr_num_slots - 1;
-    u_int const head = kring->rhead;
-
-    union Vmxnet3_GenericDesc* gdesc;
-    struct SOFTC_T* adapter = netdev_priv( ifp );
-    struct vmxnet3_tx_queue* tq = &adapter->tx_queue[ ring_nr ];
-
-
-    if( !netif_carrier_ok( ifp ) )
-        return 0;
-
-    //
-    // Free up the comp_descriptors aggressively
-    //
-
-    completed = vmxnet3_netmap_tq_tx_complete( tq, adapter->pdev );
-
-    //
-    // Reclaim buffers for completed transmissions
-    //
-
-    kring->nr_hwtail = nm_prev( tq->comp_ring.next2proc, tq->comp_ring.size - 1 );
+	int entries = 0;
 
-    //
-    // Process new packets to send
-    //
+	//
+	// no out of order completion
+	//
 
-    nm_i = kring->nr_hwcur;
+	BUG_ON(tq->buf_info[eop_idx].sop_idx != tq->tx_ring.next2comp);
+	BUG_ON(VMXNET3_TXDESC_GET_EOP(&(tq->tx_ring.base[eop_idx].txd)) != 1);
 
-    if( nm_i != head )
-    {
-        for( n = 0; nm_i != head; n++ )
-        {
-            u32 copy_size = 0;
-            int free_cmd_desc_count;
-            unsigned long lock_flags;
+	BUG_ON(tq->buf_info[eop_idx].skb != NULL);
 
-            union Vmxnet3_GenericDesc* sop_txd;
-            union Vmxnet3_GenericDesc* eop_txd;
+	VMXNET3_INC_RING_IDX_ONLY(eop_idx, tq->tx_ring.size);
 
-            struct netmap_slot* slot = &ring->slot[ nm_i ];
-            u_int packet_len = slot->len;
-            void* packet_addr = NMB( na, slot );
+	while (tq->tx_ring.next2comp != eop_idx) {
+		vmxnet3_unmap_tx_buf(tq->buf_info + tq->tx_ring.next2comp,
+				     pdev);
 
-            slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+		//
+		// update next2comp w/o tx_lock. Since we are marking more,
+		// instead of less, tx ring entries avail, the worst case is
+		// that the tx routine incorrectly re-queues a pkt due to
+		// insufficient tx ring entries.
+		//
 
+		vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
+		entries++;
+	}
 
-            spin_lock_irqsave( &tq->tx_lock, lock_flags );
-
-            
-            free_cmd_desc_count = vmxnet3_cmd_ring_desc_avail( &tq->tx_ring );
-
-            if( free_cmd_desc_count < kMinFreeTxDescForPacket )
-            {
-                tq->stats.tx_ring_full++;
-                spin_unlock_irqrestore( &tq->tx_lock, lock_flags );
-                break;
-            }
-
-            //
-            // Copy header
-            //
-
-            if( kUseTwoTxDescForPacket )
-            {
-                struct Vmxnet3_TxDataDesc* tdd = 
-                    tdd = tq->data_ring.base + tq->tx_ring.next2fill;
-
-                copy_size = min( (u_int) VMXNET3_HDR_COPY_SIZE, packet_len );
-                memcpy( tdd->data, packet_addr, copy_size );
-            }
-
-            //
-            // Map rest of data
-            //
-
-            {
-                u32 dw2;
-                u32 len;
-                u32 buf_offset;
-                union Vmxnet3_GenericDesc* gdesc;
-                struct vmxnet3_tx_buf_info* tbi = NULL;
-
-                //
-                // use the previous gen bit for the SOP desc
-                //
-
-                dw2 = ( tq->tx_ring.gen ^ 0x1 ) << VMXNET3_TXD_GEN_SHIFT;
-
-                sop_txd = tq->tx_ring.base + tq->tx_ring.next2fill;
-                gdesc = sop_txd;
-
-                //
-                // Setup TX descriptor for the header
-                //
-
-                if( copy_size )
-                {
-                    sop_txd->txd.addr = cpu_to_le64( tq->data_ring.basePA + tq->tx_ring.next2fill * sizeof( struct Vmxnet3_TxDataDesc ) );
-                    sop_txd->dword[ 2 ] = cpu_to_le32( dw2 | copy_size );
-                    sop_txd->dword[ 3 ] = 0;
-
-                    tbi = tq->buf_info + tq->tx_ring.next2fill;
-                    tbi->map_type = VMXNET3_MAP_NONE;
+	return entries;
+}
 
-                    vmxnet3_cmd_ring_adv_next2fill( &tq->tx_ring );
+static int vmxnet3_netmap_tq_tx_complete(struct vmxnet3_tx_queue *tq,
+					 struct pci_dev *pdev)
+{
+	int completed = 0;
+	union Vmxnet3_GenericDesc *gdesc;
 
-                    //
-                    // use the right gen for non-SOP desc
-                    //
-                    
-                    dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
-                }
+	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
 
-                //
-                // Handle linear part
-                //
+	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
+		completed += vmxnet3_netmap_unmap_pkt(
+			VMXNET3_TCD_GET_TXIDX(&gdesc->tcd), tq, pdev);
 
-                len = packet_len - copy_size;
-                buf_offset = copy_size;
+		vmxnet3_comp_ring_adv_next2proc(&tq->comp_ring);
+		gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+	}
 
-                if( len )
-                {
-                    u32 buf_size;
+	return completed;
+}
 
-                    BUG_ON( len > VMXNET3_MAX_TX_BUF_SIZE );
-                    buf_size = len;
-                    dw2 |= len;
+static int vmxnet3_netmap_txsync(struct netmap_kring *kring, int flags)
+{
+#define kUseTwoTxDescForPacket 0
+#define kMinFreeTxDescForPacket (kUseTwoTxDescForPacket ? 2 : 1)
 
-                    tbi = tq->buf_info + tq->tx_ring.next2fill;
-                    tbi->map_type = VMXNET3_MAP_SINGLE;
-                    tbi->dma_addr = dma_map_single( &adapter->pdev->dev, packet_addr + buf_offset, buf_size, PCI_DMA_TODEVICE );
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
 
-                    if( dma_mapping_error( &adapter->pdev->dev, tbi->dma_addr ) )
-                    {
-                        spin_unlock_irqrestore( &tq->tx_lock, lock_flags );
-                        break;
-                    }
+	u_int n;
+	u_int nm_i; // index into the netmap ring
+	int completed;
+	u_int deferred = 0;
+	u_int ring_nr = kring->ring_id;
 
-                    tbi->len = buf_size;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+
+	union Vmxnet3_GenericDesc *gdesc;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+	struct vmxnet3_tx_queue *tq = &adapter->tx_queue[ring_nr];
+
+	if (!netif_carrier_ok(ifp))
+		return 0;
 
-                    gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
-                    BUG_ON( gdesc->txd.gen == tq->tx_ring.gen );
+	//
+	// Free up the comp_descriptors aggressively
+	//
 
-                    gdesc->txd.addr = cpu_to_le64( tbi->dma_addr );
-                    gdesc->dword[ 2 ] = cpu_to_le32( dw2 );
-                    gdesc->dword[ 3 ] = 0;
+	completed = vmxnet3_netmap_tq_tx_complete(tq, adapter->pdev);
+
+	//
+	// Reclaim buffers for completed transmissions
+	//
+
+	kring->nr_hwtail =
+		nm_prev(tq->comp_ring.next2proc, tq->comp_ring.size - 1);
+
+	//
+	// Process new packets to send
+	//
+
+	nm_i = kring->nr_hwcur;
 
-                    vmxnet3_cmd_ring_adv_next2fill( &tq->tx_ring );
-                    dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
-                }
+	if (nm_i != head) {
+		for (n = 0; nm_i != head; n++) {
+			u32 copy_size = 0;
+			int free_cmd_desc_count;
+			unsigned long lock_flags;
 
+			union Vmxnet3_GenericDesc *sop_txd;
+			union Vmxnet3_GenericDesc *eop_txd;
 
-                eop_txd = gdesc;
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			u_int packet_len = slot->len;
+			void *packet_addr = NMB(na, slot);
+
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+
+			spin_lock_irqsave(&tq->tx_lock, lock_flags);
+
+			free_cmd_desc_count =
+				vmxnet3_cmd_ring_desc_avail(&tq->tx_ring);
+
+			if (free_cmd_desc_count < kMinFreeTxDescForPacket) {
+				tq->stats.tx_ring_full++;
+				spin_unlock_irqrestore(&tq->tx_lock,
+						       lock_flags);
+				break;
+			}
+
+			//
+			// Copy header
+			//
+
+			if (kUseTwoTxDescForPacket) {
+				struct Vmxnet3_TxDataDesc *tdd = tdd =
+					tq->data_ring.base +
+					tq->tx_ring.next2fill;
+
+				copy_size = min((u_int)VMXNET3_HDR_COPY_SIZE,
+						packet_len);
+				memcpy(tdd->data, packet_addr, copy_size);
+			}
+
+			//
+			// Map rest of data
+			//
+
+			{
+				u32 dw2;
+				u32 len;
+				u32 buf_offset;
+				union Vmxnet3_GenericDesc *gdesc;
+				struct vmxnet3_tx_buf_info *tbi = NULL;
+
+				//
+				// use the previous gen bit for the SOP desc
+				//
+
+				dw2 = (tq->tx_ring.gen ^ 0x1)
+				      << VMXNET3_TXD_GEN_SHIFT;
+
+				sop_txd = tq->tx_ring.base +
+					  tq->tx_ring.next2fill;
+				gdesc = sop_txd;
+
+				//
+				// Setup TX descriptor for the header
+				//
+
+				if (copy_size) {
+					sop_txd->txd.addr = cpu_to_le64(
+						tq->data_ring.basePA +
+						tq->tx_ring.next2fill *
+							sizeof(struct
+							       Vmxnet3_TxDataDesc));
+					sop_txd->dword[2] =
+						cpu_to_le32(dw2 | copy_size);
+					sop_txd->dword[3] = 0;
 
-                tbi->skb = NULL;
-                tbi->sop_idx = sop_txd - tq->tx_ring.base;
-            }
+					tbi = tq->buf_info +
+					      tq->tx_ring.next2fill;
+					tbi->map_type = VMXNET3_MAP_NONE;
 
-            //
-            // setup the EOP desc
-            //
+					vmxnet3_cmd_ring_adv_next2fill(
+						&tq->tx_ring);
 
-            eop_txd->dword[ 3 ] = cpu_to_le32( VMXNET3_TXD_CQ | VMXNET3_TXD_EOP );
+					//
+					// use the right gen for non-SOP desc
+					//
+
+					dw2 = tq->tx_ring.gen
+					      << VMXNET3_TXD_GEN_SHIFT;
+				}
+
+				//
+				// Handle linear part
+				//
+
+				len = packet_len - copy_size;
+				buf_offset = copy_size;
+
+				if (len) {
+					u32 buf_size;
+
+					BUG_ON(len > VMXNET3_MAX_TX_BUF_SIZE);
+					buf_size = len;
+					dw2 |= len;
 
-            //
-            // setup the SOP desc
-            //
+					tbi = tq->buf_info +
+					      tq->tx_ring.next2fill;
+					tbi->map_type = VMXNET3_MAP_SINGLE;
+					tbi->dma_addr = dma_map_single(
+						&adapter->pdev->dev,
+						packet_addr + buf_offset,
+						buf_size, PCI_DMA_TODEVICE);
+
+					if (dma_mapping_error(
+						    &adapter->pdev->dev,
+						    tbi->dma_addr)) {
+						spin_unlock_irqrestore(
+							&tq->tx_lock,
+							lock_flags);
+						break;
+					}
+
+					tbi->len = buf_size;
+
+					gdesc = tq->tx_ring.base +
+						tq->tx_ring.next2fill;
+					BUG_ON(gdesc->txd.gen ==
+					       tq->tx_ring.gen);
+
+					gdesc->txd.addr =
+						cpu_to_le64(tbi->dma_addr);
+					gdesc->dword[2] = cpu_to_le32(dw2);
+					gdesc->dword[3] = 0;
+
+					vmxnet3_cmd_ring_adv_next2fill(
+						&tq->tx_ring);
+					dw2 = tq->tx_ring.gen
+					      << VMXNET3_TXD_GEN_SHIFT;
+				}
 
-            gdesc = sop_txd;
+				eop_txd = gdesc;
+
+				tbi->skb = NULL;
+				tbi->sop_idx = sop_txd - tq->tx_ring.base;
+			}
+
+			//
+			// setup the EOP desc
+			//
 
-            gdesc->txd.om = 0;
-            gdesc->txd.msscof = 0;
+			eop_txd->dword[3] =
+				cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP);
 
-            //
-            // finally flips the GEN bit of the SOP desc
-            //
+			//
+			// setup the SOP desc
+			//
 
-            gdesc->dword[ 2 ] = cpu_to_le32( le32_to_cpu( gdesc->dword[ 2 ] ) ^ VMXNET3_TXD_GEN );
+			gdesc = sop_txd;
+
+			gdesc->txd.om = 0;
+			gdesc->txd.msscof = 0;
 
-            deferred++;            
+			//
+			// finally flips the GEN bit of the SOP desc
+			//
 
+			gdesc->dword[2] = cpu_to_le32(
+				le32_to_cpu(gdesc->dword[2]) ^ VMXNET3_TXD_GEN);
 
-            spin_unlock_irqrestore( &tq->tx_lock, lock_flags );
+			deferred++;
 
-            //
-            // go to the next netmap slot
-            //
+			spin_unlock_irqrestore(&tq->tx_lock, lock_flags);
 
-            nm_i = nm_next( nm_i, lim );
-        }
+			//
+			// go to the next netmap slot
+			//
 
-        kring->nr_hwcur = head;
-    }
+			nm_i = nm_next(nm_i, lim);
+		}
 
-    //
-    // Notify vSwitch that packets are available.
-    //
+		kring->nr_hwcur = head;
+	}
 
-    if( deferred >= 1 )
-    {
-        VMXNET3_WRITE_BAR0_REG( 
-            adapter,
-            ( VMXNET3_REG_TXPROD + tq->qid * VMXNET3_REG_ALIGN ), 
-            tq->tx_ring.next2fill );
-    }
+	//
+	// Notify vSwitch that packets are available.
+	//
 
+	if (deferred >= 1) {
+		VMXNET3_WRITE_BAR0_REG(adapter, (VMXNET3_REG_TXPROD +
+						 tq->qid * VMXNET3_REG_ALIGN),
+				       tq->tx_ring.next2fill);
+	}
 
-    return 0;
+	return 0;
 }
 
-
-static int vmxnet3_netmap_rxsync( struct netmap_kring* kring, int flags )
+static int vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 {
-    static const u32 rxprod_reg[] = 
-    {
-        VMXNET3_REG_RXPROD, 
-        VMXNET3_REG_RXPROD2
-    };
-
-    u32 num_pkts = 0;
-    u32 netmap_offset = 0;
-    u_int nm_i = 0;	// index into the netmap ring
-
-    struct netmap_adapter* na = kring->na;
-    struct ifnet* ifp = na->ifp;
-    struct netmap_ring* nmring = kring->ring;
-    
-    u_int ring_nr = kring->ring_id;
-    u_int const lim = kring->nkr_num_slots - 1;
-    u_int const head = kring->rhead;
-    int force_update = ( flags & NAF_FORCE_READ ) || kring->nr_kflags & NKR_PENDINTR;
-
-    struct Vmxnet3_RxCompDesc* rcd;
-    struct SOFTC_T* adapter = netdev_priv( ifp );
-    struct vmxnet3_rx_queue* rq = &adapter->rx_queue[ ring_nr ];
-
-
-    if( !netif_carrier_ok( ifp ) )
-        return 0;
-
-    if( head > lim )
-        return netmap_ring_reinit( kring );
-
-    //
-    // First part: import newly received packets.
-    //
-
-    if( netmap_no_pendintr || force_update )
-    {
-        uint32_t hwtail_lim = 
-            nm_prev( kring->nr_hwcur, lim );
-
-
-        nm_i = kring->nr_hwtail;
-
-        vmxnet3_getRxComp( 
-            rcd,
-            &rq->comp_ring.base[ rq->comp_ring.next2proc ].rcd, 
-            &rxComp );
-
-
-        while( rcd->gen == rq->comp_ring.gen && nm_i != hwtail_lim )
-        {
-            u32 idx;
-            u32 ring_idx;
-            int num_to_alloc;
-            void* packet_addr;
-            void* packet_nic_addr;
-            struct netmap_slot* slot;
-            struct Vmxnet3_RxDesc* rxd;
-            struct vmxnet3_rx_buf_info* rbi;
-            struct vmxnet3_cmd_ring* ring = NULL;
-
-            slot = nmring->slot + nm_i;
-            packet_addr = NMB( na, slot );
-
-
-            BUG_ON( rcd->rqID != rq->qid && rcd->rqID != rq->qid2 );
-            idx = rcd->rxdIdx;
-            ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
-            ring = rq->rx_ring + ring_idx;
-            vmxnet3_getRxDesc( rxd, &rq->rx_ring[ ring_idx ].base[ idx ].rxd, &rxCmdDesc );
-            rbi = rq->buf_info[ ring_idx ] + idx;
-            BUG_ON( rxd->addr != rbi->dma_addr || rxd->len != rbi->len );
-
-            if( rcd->eop && rcd->err )
-            {
-                rq->stats.drop_total++;
-                rq->stats.drop_err++;
-
-                if( !rcd->fcs )
-                    rq->stats.drop_fcs++;
-
-                goto rcd_done;
-            }
-
-            if( rcd->sop )
-            {
-                BUG_ON( rxd->btype != VMXNET3_RXD_BTYPE_HEAD || rcd->rqID != rq->qid );
-                BUG_ON( rbi->buf_type != VMXNET3_RX_BUF_SKB );
-
-                if( rcd->len == 0 )
-                {
-                    BUG_ON( !( rcd->sop && rcd->eop ) );
-                    goto rcd_done;
-                }
-
-                packet_nic_addr = rbi->skb->data;
-                memcpy( packet_addr, packet_nic_addr, rcd->len );
-
-                netmap_offset = rcd->len;
-            }
-            else
-            {
-                // non SOP buffer must be type 1 in most cases
-                BUG_ON( rbi->buf_type != VMXNET3_RX_BUF_PAGE );
-                BUG_ON( rxd->btype != VMXNET3_RXD_BTYPE_BODY );
-
-                packet_nic_addr = page_address( rbi->page );
-                memcpy( packet_addr + netmap_offset, packet_nic_addr, rcd->len );
-
-                netmap_offset += rcd->len;
-            }
-
-
-            if( rcd->eop )
-            {
-                slot->len = netmap_offset;
-                slot->flags = 0;
-                
-                num_pkts++;
-                nm_i = nm_next( nm_i, lim );
-            }
-
+	static const u32 rxprod_reg[] = { VMXNET3_REG_RXPROD,
+					  VMXNET3_REG_RXPROD2 };
+
+	u32 num_pkts = 0;
+	u32 netmap_offset = 0;
+	u_int nm_i = 0; // index into the netmap ring
+
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *nmring = kring->ring;
+
+	u_int ring_nr = kring->ring_id;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	int force_update =
+		(flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+
+	struct Vmxnet3_RxCompDesc *rcd;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+	struct vmxnet3_rx_queue *rq = &adapter->rx_queue[ring_nr];
+
+	if (!netif_carrier_ok(ifp))
+		return 0;
+
+	if (head > lim)
+		return netmap_ring_reinit(kring);
+
+	//
+	// First part: import newly received packets.
+	//
+
+	if (netmap_no_pendintr || force_update) {
+		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
+
+		nm_i = kring->nr_hwtail;
+
+		vmxnet3_getRxComp(
+			rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
+			&rxComp);
+
+		while (rcd->gen == rq->comp_ring.gen && nm_i != hwtail_lim) {
+			u32 idx;
+			u32 ring_idx;
+			int num_to_alloc;
+			void *packet_addr;
+			void *packet_nic_addr;
+			struct netmap_slot *slot;
+			struct Vmxnet3_RxDesc *rxd;
+			struct vmxnet3_rx_buf_info *rbi;
+			struct vmxnet3_cmd_ring *ring = NULL;
+
+			slot = nmring->slot + nm_i;
+			packet_addr = NMB(na, slot);
+
+			BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
+			idx = rcd->rxdIdx;
+			ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
+			ring = rq->rx_ring + ring_idx;
+			vmxnet3_getRxDesc(rxd,
+					  &rq->rx_ring[ring_idx].base[idx].rxd,
+					  &rxCmdDesc);
+			rbi = rq->buf_info[ring_idx] + idx;
+			BUG_ON(rxd->addr != rbi->dma_addr ||
+			       rxd->len != rbi->len);
+
+			if (rcd->eop && rcd->err) {
+				rq->stats.drop_total++;
+				rq->stats.drop_err++;
+
+				if (!rcd->fcs)
+					rq->stats.drop_fcs++;
+
+				goto rcd_done;
+			}
+
+			if (rcd->sop) {
+				BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_HEAD ||
+				       rcd->rqID != rq->qid);
+				BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_SKB);
+
+				if (rcd->len == 0) {
+					BUG_ON(!(rcd->sop && rcd->eop));
+					goto rcd_done;
+				}
+
+				packet_nic_addr = rbi->skb->data;
+				memcpy(packet_addr, packet_nic_addr, rcd->len);
+
+				netmap_offset = rcd->len;
+			} else {
+				// non SOP buffer must be type 1 in most cases
+				BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_PAGE);
+				BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_BODY);
+
+				packet_nic_addr = page_address(rbi->page);
+				memcpy(packet_addr + netmap_offset,
+				       packet_nic_addr, rcd->len);
+
+				netmap_offset += rcd->len;
+			}
+
+			if (rcd->eop) {
+				slot->len = netmap_offset;
+				slot->flags = 0;
+
+				num_pkts++;
+				nm_i = nm_next(nm_i, lim);
+			}
+
+		rcd_done:
+			ring->next2comp = idx;
+
+			num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring);
+			ring = rq->rx_ring + ring_idx;
+
+			while (num_to_alloc) {
+				vmxnet3_getRxDesc(
+					rxd, &ring->base[ring->next2fill].rxd,
+					&rxCmdDesc);
+				BUG_ON(!rxd->addr);
+
+				// Recv desc is ready to be used by the device
+				rxd->gen = ring->gen;
+				vmxnet3_cmd_ring_adv_next2fill(ring);
+				num_to_alloc--;
+			}
+
+			// if needed, update the register
+			if (unlikely(rq->shared->updateRxProd)) {
+				VMXNET3_WRITE_BAR0_REG(
+					adapter,
+					rxprod_reg[ring_idx] +
+						rq->qid * VMXNET3_REG_ALIGN,
+					ring->next2fill);
+			}
+
+			vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
+			vmxnet3_getRxComp(
+				rcd,
+				&rq->comp_ring.base[rq->comp_ring.next2proc]
+					 .rcd,
+				&rxComp);
+		}
 
-        rcd_done:
-            ring->next2comp = idx;
-
-            num_to_alloc = vmxnet3_cmd_ring_desc_avail( ring );
-            ring = rq->rx_ring + ring_idx;
-
-            while( num_to_alloc )
-            {
-                vmxnet3_getRxDesc( rxd, &ring->base[ ring->next2fill ].rxd, &rxCmdDesc );
-                BUG_ON( !rxd->addr );
-
-                // Recv desc is ready to be used by the device
-                rxd->gen = ring->gen;
-                vmxnet3_cmd_ring_adv_next2fill( ring );
-                num_to_alloc--;
-            }
-
-            // if needed, update the register
-            if( unlikely( rq->shared->updateRxProd ) )
-            {
-                VMXNET3_WRITE_BAR0_REG( adapter,
-                    rxprod_reg[ ring_idx ] + rq->qid * VMXNET3_REG_ALIGN,
-                    ring->next2fill );
-            }
-
-            vmxnet3_comp_ring_adv_next2proc( &rq->comp_ring );
-            vmxnet3_getRxComp( rcd, &rq->comp_ring.base[ rq->comp_ring.next2proc ].rcd, &rxComp );
-        }
-
-
-		if( num_pkts )
-		{
+		if (num_pkts) {
 			kring->nr_hwtail = nm_i;
 		}
 
 		kring->nr_kflags &= ~NKR_PENDINTR;
-    }
+	}
 
-    //
-    // Second part: skip past packets that userspace has released.
-    //
+	//
+	// Second part: skip past packets that userspace has released.
+	//
 
-    nm_i = kring->nr_hwcur;
+	nm_i = kring->nr_hwcur;
 
-    if( nm_i != head )
-    {
+	if (nm_i != head) {
 		int n;
 
-		for( n = 0; nm_i != head; n++ )
-        {
-            struct netmap_slot* slot = &nmring->slot[ nm_i ];
-            uint64_t paddr;
-            void* addr = PNMB( na, slot, &paddr );
-
-            if( addr == NETMAP_BUF_BASE( na ) ) // bad buf
-                goto ring_reset;
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &nmring->slot[nm_i];
+			uint64_t paddr;
+			void *addr = PNMB(na, slot, &paddr);
 
-            slot->flags &= ~NS_BUF_CHANGED;
+			if (addr == NETMAP_BUF_BASE(na)) // bad buf
+				goto ring_reset;
 
-            nm_i = nm_next( nm_i, lim );
-        }
-        kring->nr_hwcur = head;
-    }
+			slot->flags &= ~NS_BUF_CHANGED;
 
+			nm_i = nm_next(nm_i, lim);
+		}
+		kring->nr_hwcur = head;
+	}
 
-    return 0;
-
+	return 0;
 
 ring_reset:
-	return netmap_ring_reinit( kring );	
+	return netmap_ring_reinit(kring);
 }
 
-
-static void vmxnet3_netmap_intr( struct netmap_adapter* na, int onoff )
+static void vmxnet3_netmap_intr(struct netmap_adapter *na, int onoff)
 {
-    struct ifnet* ifp = na->ifp;
-    struct SOFTC_T* adapter = netdev_priv( ifp );
+	struct ifnet *ifp = na->ifp;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
 
-    if( onoff )
-        vmxnet3_enable_all_intrs( adapter );
-    else
-        vmxnet3_disable_all_intrs( adapter );
+	if (onoff)
+		vmxnet3_enable_all_intrs(adapter);
+	else
+		vmxnet3_disable_all_intrs(adapter);
 }
 
-
-static void vmxnet3_netmap_init_buffers( struct SOFTC_T* adapter )
+static void vmxnet3_netmap_init_buffers(struct SOFTC_T *adapter)
 {
-    u32 r;
-    struct ifnet* ifp = adapter->netdev;
-    struct netmap_adapter* na = NA( ifp );
-
-
-    if( !nm_native_on( na ) )
-        return;
+	u32 r;
+	struct ifnet *ifp = adapter->netdev;
+	struct netmap_adapter *na = NA(ifp);
 
+	if (!nm_native_on(na))
+		return;
 
-    for( r = 0; r < na->num_rx_rings; r++ )
-    {
-        (void) netmap_reset( na, NR_RX, r, 0 );
-    }
+	for (r = 0; r < na->num_rx_rings; r++) {
+		(void)netmap_reset(na, NR_RX, r, 0);
+	}
 
-
-    for( r = 0; r < na->num_tx_rings; r++ )
-    {
-        (void) netmap_reset( na, NR_TX, r, 0 );
-    }
+	for (r = 0; r < na->num_tx_rings; r++) {
+		(void)netmap_reset(na, NR_TX, r, 0);
+	}
 }
 
-
-static void vmxnet3_netmap_attach( struct SOFTC_T* adapter )
+static void vmxnet3_netmap_attach(struct SOFTC_T *adapter)
 {
-    struct netmap_adapter na;
-
-    bzero( &na, sizeof( na ) );
-
-    na.ifp = adapter->netdev;
-    na.pdev = &adapter->pdev->dev;
-    na.num_tx_desc = adapter->tx_ring_size;
-    na.num_rx_desc = adapter->rx_ring_size;
-    na.nm_register = vmxnet3_netmap_reg;
-    na.nm_txsync = vmxnet3_netmap_txsync;
-    na.nm_rxsync = vmxnet3_netmap_rxsync;
-    na.num_tx_rings = adapter->num_tx_queues;
-    na.num_rx_rings = adapter->num_rx_queues;
-    na.nm_intr = vmxnet3_netmap_intr;
-
-    netmap_attach( &na );
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp = adapter->netdev;
+	na.pdev = &adapter->pdev->dev;
+	na.num_tx_desc = adapter->tx_ring_size;
+	na.num_rx_desc = adapter->rx_ring_size;
+	na.nm_register = vmxnet3_netmap_reg;
+	na.nm_txsync = vmxnet3_netmap_txsync;
+	na.nm_rxsync = vmxnet3_netmap_rxsync;
+	na.num_tx_rings = adapter->num_tx_queues;
+	na.num_rx_rings = adapter->num_rx_queues;
+	na.nm_intr = vmxnet3_netmap_intr;
+
+	netmap_attach(&na);
 }
 
-
-static void vmxnet3_netmap_detach( struct net_device* device )
+static void vmxnet3_netmap_detach(struct net_device *device)
 {
-    netmap_detach( device );
+	netmap_detach(device);
 }
 
-
 #endif // _IF_VMXNET3_NETMAP_H_

From 4c92101b1a8cb3dcb84c0909014a2f5b5f860788 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 7 Feb 2018 10:43:58 +0100
Subject: [PATCH 0457/2207] bdg_lookup_fn_t receives the lookup data structure
 specified during a netmap_bdg_regops through a new void * parameter, the data
 is stored inside the struct netmap_bdg_ops

---
 .gitignore                   | 1 +
 sys/dev/netmap/netmap_kern.h | 5 +++--
 sys/dev/netmap/netmap_vale.c | 5 +++--
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6bfcbdefd..505610489 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 *.mod.c
 *.orig
 .*.swp
+config
 tags
 modules.order
 Module.symvers
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 92846eb86..221cce3a2 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1444,17 +1444,18 @@ int netmap_get_hw_na(struct ifnet *ifp,
  * drop.
  */
 typedef u_int (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
-		struct netmap_vp_adapter *);
+		struct netmap_vp_adapter *, void *lookup_data);
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
 struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
 	bdg_dtor_fn_t	dtor;
+	void *lookup_data;
 };
 
 u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
-		struct netmap_vp_adapter *);
+		struct netmap_vp_adapter *, void *lookup_data);
 
 #define	NM_BRIDGES		8	/* number of bridges */
 #define	NM_BDG_MAXPORTS		254	/* up to 254 */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 868ca8cd7..e10e2de8d 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -379,6 +379,7 @@ nm_find_bridge(const char *name, int create)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
 		b->bdg_ops.lookup = netmap_bdg_learning;
+		/* TODO: add pointer to hash_table to bdg_ops.lookup_data here? (s.duo) */
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -1609,7 +1610,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
  */
 u_int
 netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
-		struct netmap_vp_adapter *na)
+		struct netmap_vp_adapter *na, void *lookup_data)
 {
 	uint8_t *buf = ft->ft_buf;
 	u_int buf_len = ft->ft_len;
@@ -1775,7 +1776,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		   fragment nor at the very beginning of the second. */
 		if (unlikely(na->up.virt_hdr_len > ft[i].ft_len))
 			continue;
-		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na);
+		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na, b->bdg_ops.lookup_data);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)

From 98969d8c23dcd0056d24853487c930ccce941c45 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 7 Feb 2018 16:53:00 +0100
Subject: [PATCH 0458/2207] the lookup data structure is now stored inside
 struct nm_bridge inside ht which is now a void *. netmap_bdg_regops() third
 parameter is now a void **, so we can store the old lookup data structure
 used by the bridge which the external module will have to give back during
 its unloading

---
 sys/dev/netmap/netmap_kern.h |  3 +--
 sys/dev/netmap/netmap_vale.c | 27 ++++++++++++++++++---------
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 221cce3a2..380c59e61 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1451,7 +1451,6 @@ struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
 	bdg_dtor_fn_t	dtor;
-	void *lookup_data;
 };
 
 u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
@@ -1469,7 +1468,7 @@ struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void **lookup_data);
 int netmap_bdg_config(struct nm_ifreq *nifr);
 
 #else /* !WITH_VALE */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index e10e2de8d..a3503a69a 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -223,12 +223,13 @@ struct nm_bridge {
 	 * The function is set by netmap_bdg_regops().
 	 */
 	struct netmap_bdg_ops bdg_ops;
-
-	/* the forwarding table, MAC+ports.
-	 * XXX should be changed to an argument to be passed to
-	 * the lookup function
+	
+	/*
+	 * Contains the data structure used by the bdg_ops.lookup function.
+	 * By default it's a struct nm_hash_ent allocated on attach
+	 * otherwise will contain the data structure received by netmap_bdg_regops().
 	 */
-	struct nm_hash_ent *ht; // allocated on attach
+	void *ht;
 
 #ifdef CONFIG_NET_NS
 	struct net *ns;
@@ -379,7 +380,6 @@ nm_find_bridge(const char *name, int create)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
 		b->bdg_ops.lookup = netmap_bdg_learning;
-		/* TODO: add pointer to hash_table to bdg_ops.lookup_data here? (s.duo) */
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -1335,12 +1335,18 @@ netmap_bdg_list(struct nmreq_header *hdr)
  * Register callbacks to the given bridge. 'name' may be just
  * bridge's name (including ':' if it is not just NM_BDG_NAME).
  * Called without NMG_LOCK.
+ *
+ * If needed the external module will need to free the memory pointed by *lookup_data
+ * netmap_bdg_regops() writes the old lookup data structure add to *lookup_data, the exernal
+ * module will need to restore it on exit
  */
+ 
 int
-netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops)
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void **lookup_data)
 {
 	struct nm_bridge *b;
 	int error = 0;
+	void *old_lookup_data;
 
 	if (!bdg_ops) {
 		return EINVAL;
@@ -1351,6 +1357,9 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops)
 		error = EINVAL;
 	} else {
 		b->bdg_ops = *bdg_ops;
+	    old_lookup_data = b->ht;
+		b->ht = *lookup_data;
+		*lookup_data = old_lookup_data; /* returns old lookup data structure */
 	}
 	NMG_UNLOCK();
 
@@ -1614,7 +1623,7 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 {
 	uint8_t *buf = ft->ft_buf;
 	u_int buf_len = ft->ft_len;
-	struct nm_hash_ent *ht = na->na_bdg->ht;
+	struct nm_hash_ent *ht = lookup_data;
 	uint32_t sh, dh;
 	u_int dst, mysrc = na->bdg_port;
 	uint64_t smac, dmac;
@@ -1776,7 +1785,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		   fragment nor at the very beginning of the second. */
 		if (unlikely(na->up.virt_hdr_len > ft[i].ft_len))
 			continue;
-		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na, b->bdg_ops.lookup_data);
+		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na, b->ht);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)

From c18a4dabbfc87fe87a64c39e9e1e0bc8dbb3be2b Mon Sep 17 00:00:00 2001
From: Vitaly 
Date: Thu, 8 Feb 2018 09:19:09 +0300
Subject: [PATCH 0459/2207] Remove unused file and avoid dma_map_single for
 already mapped TX buffer

---
 .../vanilla--vmxnet3--10000--99999            | 97 -------------------
 LINUX/if_vmxnet3_netmap.h                     | 21 +---
 2 files changed, 5 insertions(+), 113 deletions(-)
 delete mode 100644 LINUX/final-patches/vanilla--vmxnet3--10000--99999

diff --git a/LINUX/final-patches/vanilla--vmxnet3--10000--99999 b/LINUX/final-patches/vanilla--vmxnet3--10000--99999
deleted file mode 100644
index 312d11c3c..000000000
--- a/LINUX/final-patches/vanilla--vmxnet3--10000--99999
+++ /dev/null
@@ -1,97 +0,0 @@
-diff -ruN a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
---- a/vmxnet3/vmxnet3_drv.c	2018-01-26 08:16:40.302737839 +0300
-+++ b/vmxnet3/vmxnet3_drv.c	2018-01-26 08:16:40.305737839 +0300
-@@ -24,6 +24,7 @@
-  *
-  */
- 
-+
- #include 
- #include 
- 
-@@ -308,6 +309,11 @@
- #endif /* __BIG_ENDIAN_BITFIELD  */
- 
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) || defined(DEV_NETMAP)
-+#include "if_vmxnet3_netmap.h"
-+#endif
-+
-+
- static void
- vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
- 		     struct pci_dev *pdev)
-@@ -367,6 +373,14 @@
- 	int completed = 0;
- 	union Vmxnet3_GenericDesc *gdesc;
- 
-+#ifdef DEV_NETMAP
-+	struct net_device *netdev = adapter->netdev;
-+
-+	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
-+		return 0;
-+#endif
-+		
-+
- 	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
- 	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
- 		completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX(
-@@ -1266,6 +1280,15 @@
- 	struct Vmxnet3_RxDesc rxCmdDesc;
- 	struct Vmxnet3_RxCompDesc rxComp;
- #endif
-+
-+#ifdef DEV_NETMAP
-+	u_int total_packets = 0;
-+	struct net_device *netdev = adapter->netdev;
-+	
-+	if (netmap_rx_irq(netdev, 0, &total_packets) != NM_IRQ_PASS)
-+		return 1;
-+#endif /* DEV_NETMAP */
-+
- 	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
- 			  &rxComp);
- 	while (rcd->gen == rq->comp_ring.gen) {
-@@ -2431,6 +2454,10 @@
- 		adapter->rx_queue[0].rx_ring[0].size,
- 		adapter->rx_queue[0].rx_ring[1].size);
- 
-+#ifdef DEV_NETMAP
-+	vmxnet3_netmap_init_buffers(adapter);
-+#endif /* DEV_NETMAP */    
-+
- 	vmxnet3_tq_init_all(adapter);
- 	err = vmxnet3_rq_init_all(adapter);
- 	if (err) {
-@@ -2476,7 +2503,7 @@
- 
- 	/* Apply the rx filter settins last. */
- 	vmxnet3_set_mc(adapter->netdev);
--
-+    
- 	/*
- 	 * Check link state when first activating device. It will start the
- 	 * tx queue if the link is up.
-@@ -3290,6 +3317,11 @@
- 		dev_err(&pdev->dev, "Failed to register adapter\n");
- 		goto err_register;
- 	}
-+    
-+    
-+#ifdef DEV_NETMAP
-+	vmxnet3_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */    
- 
- 	vmxnet3_check_link(adapter, false);
- 	return 0;
-@@ -3342,6 +3374,10 @@
- 	cancel_work_sync(&adapter->work);
- 
- 	unregister_netdev(netdev);
-+    
-+#ifdef DEV_NETMAP
-+	vmxnet3_netmap_detach(netdev);
-+#endif /* DEV_NETMAP */    
- 
- 	vmxnet3_free_intr_resources(adapter);
- 	vmxnet3_free_pci_resources(adapter);
diff --git a/LINUX/if_vmxnet3_netmap.h b/LINUX/if_vmxnet3_netmap.h
index d628d506b..2f3c515e6 100644
--- a/LINUX/if_vmxnet3_netmap.h
+++ b/LINUX/if_vmxnet3_netmap.h
@@ -166,8 +166,10 @@ static int vmxnet3_netmap_txsync(struct netmap_kring *kring, int flags)
 			union Vmxnet3_GenericDesc *eop_txd;
 
 			struct netmap_slot *slot = &ring->slot[nm_i];
+
+			dma_addr_t dma_addr;
 			u_int packet_len = slot->len;
-			void *packet_addr = NMB(na, slot);
+			void *packet_addr = PNMB(na, slot, &dma_addr);
 
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
 
@@ -264,21 +266,8 @@ static int vmxnet3_netmap_txsync(struct netmap_kring *kring, int flags)
 
 					tbi = tq->buf_info +
 					      tq->tx_ring.next2fill;
-					tbi->map_type = VMXNET3_MAP_SINGLE;
-					tbi->dma_addr = dma_map_single(
-						&adapter->pdev->dev,
-						packet_addr + buf_offset,
-						buf_size, PCI_DMA_TODEVICE);
-
-					if (dma_mapping_error(
-						    &adapter->pdev->dev,
-						    tbi->dma_addr)) {
-						spin_unlock_irqrestore(
-							&tq->tx_lock,
-							lock_flags);
-						break;
-					}
-
+					tbi->map_type = VMXNET3_MAP_NONE;
+					tbi->dma_addr = dma_addr + buf_offset;
 					tbi->len = buf_size;
 
 					gdesc = tq->tx_ring.base +

From ec383250f38a054c9f23dfacdb402f5cddfd1a96 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 8 Feb 2018 10:52:26 +0100
Subject: [PATCH 0460/2207] updated .gitignore

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 505610489..bfa115cd2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
 .*.swp
 config
 tags
+cscope.*
 modules.order
 Module.symvers
 .tmp_versions

From 60aa0251dba934d7895c240dd884f929bba0dba1 Mon Sep 17 00:00:00 2001
From: Vitaly 
Date: Thu, 8 Feb 2018 12:54:08 +0300
Subject: [PATCH 0461/2207] Execute netmap_sync_map to flush the cache

---
 LINUX/if_vmxnet3_netmap.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/LINUX/if_vmxnet3_netmap.h b/LINUX/if_vmxnet3_netmap.h
index 2f3c515e6..ba15ed6ee 100644
--- a/LINUX/if_vmxnet3_netmap.h
+++ b/LINUX/if_vmxnet3_netmap.h
@@ -172,6 +172,8 @@ static int vmxnet3_netmap_txsync(struct netmap_kring *kring, int flags)
 			void *packet_addr = PNMB(na, slot, &dma_addr);
 
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			netmap_sync_map(na, (bus_dma_tag_t)na->pdev, &dma_addr,
+					packet_len, NR_TX);
 
 			spin_lock_irqsave(&tq->tx_lock, lock_flags);
 
@@ -446,9 +448,15 @@ static int vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 			}
 
 			if (rcd->eop) {
+				dma_addr_t dma_addr;
+
 				slot->len = netmap_offset;
 				slot->flags = 0;
 
+				PNMB(na, slot, &dma_addr);
+				netmap_sync_map(na, (bus_dma_tag_t)na->pdev,
+						&dma_addr, slot->len, NR_TX);
+
 				num_pkts++;
 				nm_i = nm_next(nm_i, lim);
 			}

From e4134e276d54a44236709360688d633d2a790f6d Mon Sep 17 00:00:00 2001
From: Vitaly 
Date: Thu, 8 Feb 2018 12:58:12 +0300
Subject: [PATCH 0462/2207] Fixed copy/paste error

---
 LINUX/if_vmxnet3_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_vmxnet3_netmap.h b/LINUX/if_vmxnet3_netmap.h
index ba15ed6ee..f3053598a 100644
--- a/LINUX/if_vmxnet3_netmap.h
+++ b/LINUX/if_vmxnet3_netmap.h
@@ -455,7 +455,7 @@ static int vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 				PNMB(na, slot, &dma_addr);
 				netmap_sync_map(na, (bus_dma_tag_t)na->pdev,
-						&dma_addr, slot->len, NR_TX);
+						&dma_addr, slot->len, NR_RX);
 
 				num_pkts++;
 				nm_i = nm_next(nm_i, lim);

From 7b9923ef57c1e0ffac9f1ed759f4cd46b84c9080 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 8 Feb 2018 12:15:54 +0100
Subject: [PATCH 0463/2207] added a pointer inside nm_bridge which always
 points to data used by the default lookup callback.

---
 sys/dev/netmap/netmap_kern.h |  2 +-
 sys/dev/netmap/netmap_vale.c | 25 ++++++++++++-------------
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 380c59e61..574891331 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1468,7 +1468,7 @@ struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void **lookup_data);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup_data);
 int netmap_bdg_config(struct nm_ifreq *nifr);
 
 #else /* !WITH_VALE */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index a3503a69a..7e4d74690 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -226,10 +226,11 @@ struct nm_bridge {
 	
 	/*
 	 * Contains the data structure used by the bdg_ops.lookup function.
-	 * By default it's a struct nm_hash_ent allocated on attach
-	 * otherwise will contain the data structure received by netmap_bdg_regops().
+	 * By default points to *ht which is allocated on attach and used by the default lookup
+	 * otherwise will point to the data structure received by netmap_bdg_regops().
 	 */
-	void *ht;
+    void *lookup_data;
+	struct nm_hash_ent *ht;
 
 #ifdef CONFIG_NET_NS
 	struct net *ns;
@@ -380,6 +381,7 @@ nm_find_bridge(const char *name, int create)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
 		b->bdg_ops.lookup = netmap_bdg_learning;
+		b->lookup_data = b->ht;
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -1335,18 +1337,13 @@ netmap_bdg_list(struct nmreq_header *hdr)
  * Register callbacks to the given bridge. 'name' may be just
  * bridge's name (including ':' if it is not just NM_BDG_NAME).
  * Called without NMG_LOCK.
- *
- * If needed the external module will need to free the memory pointed by *lookup_data
- * netmap_bdg_regops() writes the old lookup data structure add to *lookup_data, the exernal
- * module will need to restore it on exit
  */
  
 int
-netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void **lookup_data)
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup_data)
 {
 	struct nm_bridge *b;
 	int error = 0;
-	void *old_lookup_data;
 
 	if (!bdg_ops) {
 		return EINVAL;
@@ -1357,9 +1354,11 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void **looku
 		error = EINVAL;
 	} else {
 		b->bdg_ops = *bdg_ops;
-	    old_lookup_data = b->ht;
-		b->ht = *lookup_data;
-		*lookup_data = old_lookup_data; /* returns old lookup data structure */
+		if (bdg_ops->lookup == netmap_bdg_learning) {
+		    b->lookup_data = b->ht;
+		} else {
+		    b->lookup_data = lookup_data;
+		}
 	}
 	NMG_UNLOCK();
 
@@ -1785,7 +1784,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		   fragment nor at the very beginning of the second. */
 		if (unlikely(na->up.virt_hdr_len > ft[i].ft_len))
 			continue;
-		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na, b->ht);
+		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na, b->lookup_data);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)

From 4b7e5c584fca0ebaae0920aab1f3293d08a4e541 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 8 Feb 2018 16:18:20 +0100
Subject: [PATCH 0464/2207] calling regops with bdg_ops == NULL resets the
 bridge to its default callbacks

---
 sys/dev/netmap/netmap_vale.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 7e4d74690..091cf0e4a 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -229,7 +229,7 @@ struct nm_bridge {
 	 * By default points to *ht which is allocated on attach and used by the default lookup
 	 * otherwise will point to the data structure received by netmap_bdg_regops().
 	 */
-    void *lookup_data;
+	void *lookup_data;
 	struct nm_hash_ent *ht;
 
 #ifdef CONFIG_NET_NS
@@ -1345,19 +1345,19 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup
 	struct nm_bridge *b;
 	int error = 0;
 
-	if (!bdg_ops) {
-		return EINVAL;
-	}
 	NMG_LOCK();
 	b = nm_find_bridge(name, 0 /* don't create */);
 	if (!b) {
 		error = EINVAL;
 	} else {
-		b->bdg_ops = *bdg_ops;
-		if (bdg_ops->lookup == netmap_bdg_learning) {
-		    b->lookup_data = b->ht;
+		if (!bdg_ops) {
+			bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+			bzero(&b->bdg_ops, sizeof(b->bdg_ops));
+			b->bdg_ops.lookup = netmap_bdg_learning;
+			b->lookup_data = b->ht;
 		} else {
-		    b->lookup_data = lookup_data;
+			b->bdg_ops = *bdg_ops;
+			b->lookup_data = lookup_data;
 		}
 	}
 	NMG_UNLOCK();

From 8d18ad6fa6754f6de23665099ad52506db6836ae Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 8 Nov 2017 18:13:54 +0100
Subject: [PATCH 0465/2207] dedup: first version

Hold-mode logic. Stubs for almost everthing.
---
 apps/dedup/dedup.c | 201 +++++++++++++++++++++++++++++++++++++++++++++
 apps/dedup/dedup.h |  51 ++++++++++++
 2 files changed, 252 insertions(+)
 create mode 100644 apps/dedup/dedup.c
 create mode 100644 apps/dedup/dedup.h

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
new file mode 100644
index 000000000..7a49a9484
--- /dev/null
+++ b/apps/dedup/dedup.c
@@ -0,0 +1,201 @@
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+#include "dedup.h"
+
+void
+dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
+{
+	p->r = v;
+	p->o = v % d->out_ring->num_slots;
+}
+
+static int
+dedup_fifo_full(const struct dedup *d)
+{
+	return (d->fifo_in.r - d->fifo_out.r >= d->fifo_size);
+}
+
+static void
+dedup_hash_remove(struct dedup *d, struct netmap_slot *s)
+{
+	(void)d;
+	(void)s;
+}
+
+static void
+dedup_hash_insert(struct dedup *d, struct netmap_slot *s)
+{
+	(void)d;
+	(void)s;
+}
+
+static int
+dedup_duplicate(struct dedup *d, const struct netmap_slot *s)
+{
+	(void)d;
+	(void)s;
+	return 0;
+}
+
+static void
+dedup_move_in_out(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst)
+{
+	char *rxbuf = NETMAP_BUF(d->in_ring, src->buf_idx);
+	char *txbuf = NETMAP_BUF(d->out_ring, dst->buf_idx);
+	nm_pkt_copy(rxbuf, txbuf, src->len);
+	dst->len = src->len;
+	dst->ptr = src->ptr;
+}
+
+int
+dedup_hold_push_in(struct dedup *d)
+{
+	struct netmap_ring *ri = d->in_ring, *ro = d->out_ring;
+	uint32_t cur;
+	int n, out_space;
+
+	/* packets to input */
+	n = ri->tail - ri->cur;
+	if (n < 0)
+		n += ri->num_slots;
+	/* available space on the output ring */
+	out_space = ro->tail - (ro->head + d->prefetched);
+	if (out_space < 0)
+		out_space += ro->num_slots;
+
+	for (cur = ri->cur; n; cur = nm_ring_next(ri, cur), n--) {
+		struct netmap_slot *src_slot, *dst_slot;
+
+		src_slot = d->in_slot + cur;
+
+		if (dedup_duplicate(d, src_slot))
+			continue;
+
+		/* the packet must go into the FIFO, which is implemented
+		 * in the out ring
+		 */
+		if (out_space == 0)
+			break;
+
+		/* if the FIFO is full, send the oldest packet */
+		if (dedup_fifo_full(d)) {
+			dedup_ptr_inc(d, &d->next_to_send);
+			dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
+			dedup_ptr_inc(d, &d->fifo_out);
+			d->prefetched--;
+		}
+
+		/* move the new packet to the FIFO */
+		dst_slot = d->out_slot + d->fifo_in.o;
+		dedup_move_in_out(d, src_slot, dst_slot);
+		d->prefetched++;
+		out_space--;
+		dedup_ptr_inc(d, &d->fifo_in);
+		dedup_hash_insert(d, dst_slot);
+	}
+	ri->head = ri->cur = cur;
+	ro->head = ro->cur = d->next_to_send.o;
+	return n;
+}
+
+#if 0
+/* dedup_push_in: push new packets through the deduplicator.
+ *
+ * - duplicated packets are dropped
+ * - fresh packets always go into the FIFO first. If they cannot be hold, they
+ *   are also copied to the out ring; if we can hold packets, an incoming fresh
+ *   packet may still cause another packet to be pushed to the out ring, if the
+ *   FIFO is full; if these operations cannot be completed for lack of space,
+ *   the processing stops and the fresh packet is not removed from the input
+ *   queue (XXX this means that it will be checked for duplication again next
+ *   time: we may optmize this by playing with head and cur)
+ */
+int
+dedup_push_in(struct dedup *d)
+{
+	struct nemap_ring *ri = d->in_ring, *ro = d->out_ring;
+	uint32_t cur;
+	int n
+
+	/* packets to input */
+	n = ri->tail - ri->cur;
+	if (n < 0)
+		n += ri->num_slots;
+	/* available space on the output ring
+	 * (note that can_hold == 0 implies prefetch == 0 )
+	 */
+	out_space = ro->tail - (ro->head + d->prefetch);
+	if (out_space < 0)
+		out_space += ro->num_slots;
+
+	for (cur = ri->cur; n; cur = nm_ring_next(ri, cur), n--) {
+		unsigned long next_to_send = d->next_to_send.r;
+		struct netmap_slot *src_slot, *dst_slot;
+
+		src_slot = d->in_slot + cur;
+
+		if (dedup_duplicate(d, src_slot))
+			continue;
+
+		/* if the FIFO is full, remove the oldest */
+		if (dedup_fifo_full(d)) {
+			struct netmap_slot *rem_slot;
+
+			/* we can only send out the packet if it is
+			 * already prefeteched or we have a free slot
+			 * in the output queue
+			 */
+			if (d->prefetch == 0 && out_space == 0)
+				break;
+			dedup_ptr_inc(&d->next_to_send);
+
+			rem_slot = (d->prefetched > 0) ?
+				d->out_slot + d->fifo_out.o :
+				d->spill_slot d->fifo_out.f;
+			dedup_hash_remove(d, rem_slot);
+			dedup_ptr_inc(d, &d->fifo_out);
+		}
+
+		/* move the new packet to the FIFO */
+		if (out_space > 0) {
+			/* put the new packet directly into the output ring */
+			dst_slot = d->out_slot + d->fifo_in.o;
+			d->prefetched++;
+		} else {
+			/* the packet goes into the spill queue.
+			 * It is guaranteed to there be room there, since we have
+			 * removed the oldest packet from the FIFO above
+			 */
+			dst_slot = d->spill + d->fifo_in.f;
+		}
+		// XXX copy-or-swap from src_slot to dst_slot
+		dedup_ptr_inc(d, &d->fifo_in);
+		dedup_hash_insert(d, dst_slot);
+		/* the next packet to send always comes from the FIFO,
+		 * at next_to_send position. If hold > 0 the packet already
+		 * is in the out_ring, otherwise it must be obtained
+		 * from the spill_ring. 
+		 * If hold cannot be increased, we also need to copy the
+		 * packet, whatever the value of the swap-or-copy flag for
+		 * the direction.
+		 */
+		if (d->hold == 0) {
+			if (d->max_hold == 0) {
+				// XXX copy from spill[d->spill_head] to
+				// out_ring[d->out_head]
+			} else {
+				// XXX copy-or-swap from spill[d->spill_head]
+				// to out_ring[d->out_head]
+				d->hold++;
+			}
+		} else {
+			d->hold--;
+		}
+		dedup_ptr_inc(d, &d->next_to_send);
+	}
+	ro->head = ro->cur = d->next_to_send.o;
+	return n;
+}
+#endif
+
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
new file mode 100644
index 000000000..c247253c6
--- /dev/null
+++ b/apps/dedup/dedup.h
@@ -0,0 +1,51 @@
+#ifndef DEDUP_H_
+#define DEDUP_H_
+
+struct dedup_ptr {
+	unsigned long r; /* free running, wraps naturally */
+	unsigned int o;  /* wraps at out_ring-size */
+	unsigned int s;  /* wraps at spill-size */
+};
+
+struct dedup {
+	/* input ring */
+	struct netmap_ring *in_ring;
+	struct netmap_slot *in_slot;
+
+	/* output ring */
+	struct netmap_ring *out_ring;
+	struct netmap_slot *out_slot;
+
+	/* pointers */
+	struct dedup_ptr next_to_send;
+	struct dedup_ptr fifo_in;
+	struct dedup_ptr fifo_out;
+
+	/* how many slots of the FIFO are already in the out_ring,
+	 * starting at next_to_send
+	 */
+	unsigned int prefetched;
+
+	/* configuration */ 
+	unsigned int fifo_size;
+};
+
+void dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v);
+
+static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
+{
+	p->r++;
+	p->o++;
+	if (unlikely(p->o >= d->out_ring->num_slots))
+			p->o = 0;
+#if 0
+	p->f++;
+	if (unlikely(p->f > d->spill_size))
+			p->f = 0;
+#endif
+
+}
+
+int dedup_hold_push_in(struct dedup *d);
+
+#endif

From 7511861cab5de52959a2b93937a314b0e6a900a3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 14 Nov 2017 18:07:48 +0100
Subject: [PATCH 0466/2207] dedup: support zero-copy

---
 apps/dedup/dedup.c | 18 +++++++++++++-----
 apps/dedup/dedup.h |  1 +
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 7a49a9484..1a93c34a1 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -41,11 +41,19 @@ dedup_duplicate(struct dedup *d, const struct netmap_slot *s)
 static void
 dedup_move_in_out(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst)
 {
-	char *rxbuf = NETMAP_BUF(d->in_ring, src->buf_idx);
-	char *txbuf = NETMAP_BUF(d->out_ring, dst->buf_idx);
-	nm_pkt_copy(rxbuf, txbuf, src->len);
-	dst->len = src->len;
-	dst->ptr = src->ptr;
+	if (d->zcopy_in_out) {
+		struct netmap_slot w = *dst;
+		*dst = *src;
+		*src = w;
+		src->flags |= NS_BUF_CHANGED;
+		dst->flags |= NS_BUF_CHANGED;
+	} else {
+		char *rxbuf = NETMAP_BUF(d->in_ring, src->buf_idx);
+		char *txbuf = NETMAP_BUF(d->out_ring, dst->buf_idx);
+		nm_pkt_copy(rxbuf, txbuf, src->len);
+		dst->len = src->len;
+		dst->ptr = src->ptr;
+	}
 }
 
 int
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index c247253c6..5218174c0 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -28,6 +28,7 @@ struct dedup {
 
 	/* configuration */ 
 	unsigned int fifo_size;
+	int	zcopy_in_out;
 };
 
 void dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v);

From 7f7c56231dca2294a8423d163b159665993022f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 11:27:19 +0100
Subject: [PATCH 0467/2207] dedup: remove obsolete prefetched var

---
 apps/dedup/dedup.c | 6 ++----
 apps/dedup/dedup.h | 5 -----
 2 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 1a93c34a1..c6801f1fa 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -68,7 +68,7 @@ dedup_hold_push_in(struct dedup *d)
 	if (n < 0)
 		n += ri->num_slots;
 	/* available space on the output ring */
-	out_space = ro->tail - (ro->head + d->prefetched);
+	out_space = ro->tail - d->fifo_in.o;
 	if (out_space < 0)
 		out_space += ro->num_slots;
 
@@ -91,15 +91,13 @@ dedup_hold_push_in(struct dedup *d)
 			dedup_ptr_inc(d, &d->next_to_send);
 			dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
 			dedup_ptr_inc(d, &d->fifo_out);
-			d->prefetched--;
 		}
 
 		/* move the new packet to the FIFO */
 		dst_slot = d->out_slot + d->fifo_in.o;
 		dedup_move_in_out(d, src_slot, dst_slot);
-		d->prefetched++;
-		out_space--;
 		dedup_ptr_inc(d, &d->fifo_in);
+		out_space--;
 		dedup_hash_insert(d, dst_slot);
 	}
 	ri->head = ri->cur = cur;
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 5218174c0..0a65d13ba 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -21,11 +21,6 @@ struct dedup {
 	struct dedup_ptr fifo_in;
 	struct dedup_ptr fifo_out;
 
-	/* how many slots of the FIFO are already in the out_ring,
-	 * starting at next_to_send
-	 */
-	unsigned int prefetched;
-
 	/* configuration */ 
 	unsigned int fifo_size;
 	int	zcopy_in_out;

From f230e9b257cc3196b998ae53f0fe9791974e16b5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 12:09:14 +0100
Subject: [PATCH 0468/2207] dedup: main loop

---
 apps/dedup/dedup-main.c | 161 ++++++++++++++++++++++++++++++++++++++++
 apps/dedup/dedup.c      |  12 +--
 2 files changed, 167 insertions(+), 6 deletions(-)
 create mode 100644 apps/dedup/dedup-main.c

diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
new file mode 100644
index 000000000..547ad9c69
--- /dev/null
+++ b/apps/dedup/dedup-main.c
@@ -0,0 +1,161 @@
+/*
+ * (C) 2017	Giuseppe Lettieri
+ *
+ * BSD license
+ *
+ */
+
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+#include 
+#include "dedup.h"
+
+int verbose = 0;
+
+static int do_abort = 0;
+static int zerocopy = 1; /* enable zerocopy if possible */
+
+static void
+sigint_h(int sig)
+{
+	(void)sig;	/* UNUSED */
+	do_abort = 1;
+	signal(SIGINT, SIG_DFL);
+}
+
+
+static void
+usage(void)
+{
+	fprintf(stderr,
+		"dedup\n"
+		);
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct pollfd pollfd[2];
+	int ch;
+	struct nm_desc *pa = NULL, *pb = NULL;
+	char *ifa = NULL, *ifb = NULL;
+	int wait_link = 2;
+	int win_size = 10;
+	struct dedup dedup;
+	int n;
+
+	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
+
+	while ((ch = getopt(argc, argv, "hci:vw:W:")) != -1) {
+		switch (ch) {
+		default:
+			D("bad option %c %s", ch, optarg);
+			/* fallthrough */
+		case 'h':
+			usage();
+			break;
+		case 'i':	/* interface */
+			if (ifa == NULL)
+				ifa = optarg;
+			else if (ifb == NULL)
+				ifb = optarg;
+			else
+				D("%s ignored, already have 2 interfaces",
+					optarg);
+			break;
+		case 'c':
+			zerocopy = 0; /* do not zerocopy */
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'w':
+			wait_link = atoi(optarg);
+			break;
+		case 'W':
+			win_size = atoi(optarg);
+			break;
+		}
+
+	}
+
+	if (!ifa || !ifb) {
+		D("missing interface");
+		usage();
+	}
+	pa = nm_open(ifa, NULL, 0, NULL);
+	if (pa == NULL) {
+		D("cannot open %s", ifa);
+		return (1);
+	}
+	if (pa->first_rx_ring != pa->last_rx_ring) {
+		D("%s: too many RX rings (%d)", pa->req.nr_name,
+				pa->last_rx_ring - pa->first_rx_ring + 1);
+		return (1);
+	}
+	/* try to reuse the mmap() of the first interface, if possible */
+	pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa);
+	if (pb == NULL) {
+		D("cannot open %s", ifb);
+		nm_close(pa);
+		return (1);
+	}
+	if (pb->first_tx_ring != pb->last_tx_ring) {
+		D("%s: too many TX rings (%d)", pb->req.nr_name,
+				pb->last_rx_ring - pb->first_rx_ring + 1);
+		nm_close(pa);
+		return (1);
+	}
+	zerocopy = zerocopy && (pa->mem == pb->mem);
+	D("------- zerocopy %ssupported", zerocopy ? "" : "NOT ");
+
+	memset(&dedup, 0, sizeof(dedup));
+	dedup.in_ring = NETMAP_RXRING(pa->nifp, pa->first_rx_ring);
+	dedup.in_slot = dedup.in_ring->slot;
+	dedup.out_ring = NETMAP_TXRING(pb->nifp, pb->first_tx_ring);
+	dedup.out_slot = dedup.out_ring->slot;
+	dedup.fifo_size = win_size;
+	dedup.zcopy_in_out = zerocopy;
+
+	/* setup poll(2) array */
+	memset(pollfd, 0, sizeof(pollfd));
+	pollfd[0].fd = pa->fd;
+	pollfd[1].fd = pb->fd;
+
+	D("Wait %d secs for link to come up...", wait_link);
+	sleep(wait_link);
+	D("Ready to go, %s -> %s", pa->req.nr_name, pb->req.nr_name);
+
+	/* main loop */
+	signal(SIGINT, sigint_h);
+	n = 0;
+	while (!do_abort) {
+		int ret;
+
+		pollfd[0].events = pollfd[1].events = 0;
+		pollfd[0].revents = pollfd[1].revents = 0;
+		pollfd[0].events |= POLLIN;
+		if (n)
+			pollfd[1].events |= POLLOUT;
+		/* poll() also cause kernel to txsync/rxsync the NICs */
+		ret = poll(pollfd, 2, 2500);
+		if (ret <= 0 || verbose)
+		    D("poll %s [0] ev %x %x"
+			     " [1] ev %x %x",
+				ret <= 0 ? "timeout" : "ok",
+				pollfd[0].events,
+				pollfd[0].revents,
+				pollfd[1].events,
+				pollfd[1].revents
+			);
+		dedup.in_ring->cur = dedup.in_ring->tail;
+		n = dedup_hold_push_in(&dedup);
+		dedup.out_ring->cur = dedup.out_ring->head;
+	}
+	nm_close(pb);
+	nm_close(pa);
+
+	return (0);
+}
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index c6801f1fa..7ade28607 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -60,11 +60,11 @@ int
 dedup_hold_push_in(struct dedup *d)
 {
 	struct netmap_ring *ri = d->in_ring, *ro = d->out_ring;
-	uint32_t cur;
+	uint32_t head;
 	int n, out_space;
 
 	/* packets to input */
-	n = ri->tail - ri->cur;
+	n = ri->tail - ri->head;
 	if (n < 0)
 		n += ri->num_slots;
 	/* available space on the output ring */
@@ -72,10 +72,10 @@ dedup_hold_push_in(struct dedup *d)
 	if (out_space < 0)
 		out_space += ro->num_slots;
 
-	for (cur = ri->cur; n; cur = nm_ring_next(ri, cur), n--) {
+	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
 		struct netmap_slot *src_slot, *dst_slot;
 
-		src_slot = d->in_slot + cur;
+		src_slot = d->in_slot + head;
 
 		if (dedup_duplicate(d, src_slot))
 			continue;
@@ -100,8 +100,8 @@ dedup_hold_push_in(struct dedup *d)
 		out_space--;
 		dedup_hash_insert(d, dst_slot);
 	}
-	ri->head = ri->cur = cur;
-	ro->head = ro->cur = d->next_to_send.o;
+	ri->head = head;
+	ro->head = d->next_to_send.o;
 	return n;
 }
 

From 5cbdbc7d6c7524bcf625fca9e7fc3149fc972a88 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 12:09:33 +0100
Subject: [PATCH 0469/2207] dedup: simple makefile

---
 apps/dedup/GNUmakefile | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 apps/dedup/GNUmakefile

diff --git a/apps/dedup/GNUmakefile b/apps/dedup/GNUmakefile
new file mode 100644
index 000000000..a6c2a5838
--- /dev/null
+++ b/apps/dedup/GNUmakefile
@@ -0,0 +1,37 @@
+# For multiple programs using a single source file each,
+# we can just define 'progs' and create custom targets.
+PROGS	=	dedup
+LIBNETMAP =
+
+CLEANFILES = $(PROGS) *.o
+
+SRCDIR ?= ../..
+VPATH = $(SRCDIR)/apps/dedup
+
+NO_MAN=
+CFLAGS = -O2 -pipe
+CFLAGS += -Werror -Wall -Wunused-function
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -Wextra
+
+LDLIBS += -lpthread
+ifeq ($(shell uname),Linux)
+	LDLIBS += -lrt	# on linux
+endif
+
+PREFIX ?= /usr/local
+
+all: $(PROGS)
+
+dedup: dedup.o dedup-main.o
+
+dedup.o: dedup.h
+
+clean:
+	-@rm -rf $(CLEANFILES)
+
+.PHONY: install
+install: $(PROGS:%=install-%)
+
+install-%:
+	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*

From a9efc5e72c8470fccaf42578186b40197484d41c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 15:22:19 +0100
Subject: [PATCH 0470/2207] dedup: remove spill references

---
 apps/dedup/dedup.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 0a65d13ba..011f161b2 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -4,7 +4,6 @@
 struct dedup_ptr {
 	unsigned long r; /* free running, wraps naturally */
 	unsigned int o;  /* wraps at out_ring-size */
-	unsigned int s;  /* wraps at spill-size */
 };
 
 struct dedup {
@@ -34,12 +33,6 @@ static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
 	p->o++;
 	if (unlikely(p->o >= d->out_ring->num_slots))
 			p->o = 0;
-#if 0
-	p->f++;
-	if (unlikely(p->f > d->spill_size))
-			p->f = 0;
-#endif
-
 }
 
 int dedup_hold_push_in(struct dedup *d);

From 187f27a60b7410b46b1914fdee1d5b5c4ad9f8c4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 19:49:46 +0100
Subject: [PATCH 0471/2207] dedup: time-based sliding window

---
 apps/dedup/dedup-main.c | 32 ++++++++++++++++++-------
 apps/dedup/dedup.c      | 53 +++++++++++++++++++++++++++++++++++++----
 apps/dedup/dedup.h      | 17 +++++++++++++
 3 files changed, 89 insertions(+), 13 deletions(-)

diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index 547ad9c69..80c650085 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -42,13 +42,14 @@ main(int argc, char **argv)
 	struct nm_desc *pa = NULL, *pb = NULL;
 	char *ifa = NULL, *ifb = NULL;
 	int wait_link = 2;
-	int win_size = 10;
+	int win_size_usec = 50;
+	unsigned int fifo_size = 10;
 	struct dedup dedup;
 	int n;
 
 	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
 
-	while ((ch = getopt(argc, argv, "hci:vw:W:")) != -1) {
+	while ((ch = getopt(argc, argv, "hci:vw:W:F:")) != -1) {
 		switch (ch) {
 		default:
 			D("bad option %c %s", ch, optarg);
@@ -75,7 +76,10 @@ main(int argc, char **argv)
 			wait_link = atoi(optarg);
 			break;
 		case 'W':
-			win_size = atoi(optarg);
+			win_size_usec = atoi(optarg);
+			break;
+		case 'F':
+			fifo_size = atoi(optarg);
 			break;
 		}
 
@@ -115,8 +119,19 @@ main(int argc, char **argv)
 	dedup.in_ring = NETMAP_RXRING(pa->nifp, pa->first_rx_ring);
 	dedup.in_slot = dedup.in_ring->slot;
 	dedup.out_ring = NETMAP_TXRING(pb->nifp, pb->first_tx_ring);
+	if (fifo_size >= dedup.out_ring->num_slots - 1) {
+		D("fifo_size %u too large (max %u)", fifo_size, dedup.out_ring->num_slots - 1);
+		return (1);
+	}
 	dedup.out_slot = dedup.out_ring->slot;
-	dedup.fifo_size = win_size;
+	if (dedup_init(&dedup, fifo_size) < 0) {
+		D("failed to initialize dedup with fifo_size %u", fifo_size);
+		return (1);
+	}
+	dedup.win_size.tv_sec = win_size_usec / 1000000;
+	dedup.win_size.tv_usec = win_size_usec % 1000000;
+	D("win_size %lld+%lld", (long long) dedup.win_size.tv_sec,
+			(long long) dedup.win_size.tv_usec);
 	dedup.zcopy_in_out = zerocopy;
 
 	/* setup poll(2) array */
@@ -136,11 +151,12 @@ main(int argc, char **argv)
 
 		pollfd[0].events = pollfd[1].events = 0;
 		pollfd[0].revents = pollfd[1].revents = 0;
-		pollfd[0].events |= POLLIN;
-		if (n)
-			pollfd[1].events |= POLLOUT;
+		if (!n)
+			pollfd[0].events = POLLIN;
+		else
+			pollfd[1].events = POLLOUT;
 		/* poll() also cause kernel to txsync/rxsync the NICs */
-		ret = poll(pollfd, 2, 2500);
+		ret = poll(pollfd, 2, 1000);
 		if (ret <= 0 || verbose)
 		    D("poll %s [0] ev %x %x"
 			     " [1] ev %x %x",
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 7ade28607..e5d8ca5ee 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -1,8 +1,19 @@
 #include 
+#include 
 #define NETMAP_WITH_LIBS
 #include 
 #include "dedup.h"
 
+int
+dedup_init(struct dedup *d, unsigned int fifo_size)
+{
+	d->fifo = calloc(fifo_size, sizeof(d->fifo[0]));
+	if (d->fifo == NULL)
+		return -1;
+	d->fifo_size = fifo_size;
+	return 0;
+}
+
 void
 dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
 {
@@ -16,6 +27,12 @@ dedup_fifo_full(const struct dedup *d)
 	return (d->fifo_in.r - d->fifo_out.r >= d->fifo_size);
 }
 
+static int
+dedup_fifo_empty(const struct dedup *d)
+{
+	return (d->fifo_in.r == d->fifo_out.r);
+}
+
 static void
 dedup_hash_remove(struct dedup *d, struct netmap_slot *s)
 {
@@ -56,12 +73,38 @@ dedup_move_in_out(struct dedup *d, struct netmap_slot *src, struct netmap_slot *
 	}
 }
 
+static void
+_dedup_fifo_push_out(struct dedup *d)
+{
+	dedup_ptr_inc(d, &d->next_to_send);
+	dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
+	dedup_ptr_inc(d, &d->fifo_out);
+}
+
+static int
+_dedup_fifo_slide_win(struct dedup *d, int out_space, const struct timeval* now)
+{
+	struct timeval winstart;
+
+	timersub(now, &d->win_size, &winstart);
+
+	while (out_space && !dedup_fifo_empty(d) &&
+			timercmp(&d->fifo[d->fifo_out.f].arrival, &winstart, <)) {
+		_dedup_fifo_push_out(d);
+		out_space--;
+	}
+	return out_space;
+}
+
 int
 dedup_hold_push_in(struct dedup *d)
 {
 	struct netmap_ring *ri = d->in_ring, *ro = d->out_ring;
 	uint32_t head;
 	int n, out_space;
+	struct timeval now;
+
+	gettimeofday(&now, NULL);
 
 	/* packets to input */
 	n = ri->tail - ri->head;
@@ -72,6 +115,8 @@ dedup_hold_push_in(struct dedup *d)
 	if (out_space < 0)
 		out_space += ro->num_slots;
 
+	out_space = _dedup_fifo_slide_win(d, out_space, &now);
+
 	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
 		struct netmap_slot *src_slot, *dst_slot;
 
@@ -87,15 +132,13 @@ dedup_hold_push_in(struct dedup *d)
 			break;
 
 		/* if the FIFO is full, send the oldest packet */
-		if (dedup_fifo_full(d)) {
-			dedup_ptr_inc(d, &d->next_to_send);
-			dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
-			dedup_ptr_inc(d, &d->fifo_out);
-		}
+		if (dedup_fifo_full(d))
+			_dedup_fifo_push_out(d);
 
 		/* move the new packet to the FIFO */
 		dst_slot = d->out_slot + d->fifo_in.o;
 		dedup_move_in_out(d, src_slot, dst_slot);
+		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
 		dedup_ptr_inc(d, &d->fifo_in);
 		out_space--;
 		dedup_hash_insert(d, dst_slot);
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 011f161b2..75455563e 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -1,9 +1,17 @@
 #ifndef DEDUP_H_
 #define DEDUP_H_
 
+#define _BSD_SOURCE
+#include 
+
 struct dedup_ptr {
 	unsigned long r; /* free running, wraps naturally */
 	unsigned int o;  /* wraps at out_ring-size */
+	unsigned int f;  /* wraps at fifo_size */
+};
+
+struct dedup_fifo_entry {
+	struct timeval arrival;
 };
 
 struct dedup {
@@ -15,6 +23,9 @@ struct dedup {
 	struct netmap_ring *out_ring;
 	struct netmap_slot *out_slot;
 
+	/* fifo */
+	struct dedup_fifo_entry *fifo;
+
 	/* pointers */
 	struct dedup_ptr next_to_send;
 	struct dedup_ptr fifo_in;
@@ -22,9 +33,12 @@ struct dedup {
 
 	/* configuration */ 
 	unsigned int fifo_size;
+	struct timeval win_size;
 	int	zcopy_in_out;
 };
 
+int dedup_init(struct dedup *d, unsigned int fifo_size);
+
 void dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v);
 
 static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
@@ -33,6 +47,9 @@ static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
 	p->o++;
 	if (unlikely(p->o >= d->out_ring->num_slots))
 			p->o = 0;
+	p->f++;
+	if (unlikely(p->f >= d->fifo_size))
+			p->f = 0;
 }
 
 int dedup_hold_push_in(struct dedup *d);

From 65fe73998b006284e6b2be0c3fc61fd62581dce8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Nov 2017 22:03:09 +0100
Subject: [PATCH 0472/2207] dedup: init pointer from ring values

---
 LINUX/configure         |  2 +-
 apps/dedup/dedup-main.c | 15 +++++++--------
 apps/dedup/dedup.c      |  9 ++++++++-
 apps/dedup/dedup.h      |  3 ++-
 4 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 4b627bd6e..bcd5fd58e 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -146,7 +146,7 @@ update_drivers() {
 update_drivers
 
 # available apps
-application_avail="pkt-gen bridge lb tlem nmreplay vale-ctl"
+application_avail="pkt-gen bridge lb tlem nmreplay vale-ctl dedup"
 application=0
 app()
 {
diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index 80c650085..d384263c5 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -116,18 +116,17 @@ main(int argc, char **argv)
 	D("------- zerocopy %ssupported", zerocopy ? "" : "NOT ");
 
 	memset(&dedup, 0, sizeof(dedup));
-	dedup.in_ring = NETMAP_RXRING(pa->nifp, pa->first_rx_ring);
-	dedup.in_slot = dedup.in_ring->slot;
-	dedup.out_ring = NETMAP_TXRING(pb->nifp, pb->first_tx_ring);
-	if (fifo_size >= dedup.out_ring->num_slots - 1) {
-		D("fifo_size %u too large (max %u)", fifo_size, dedup.out_ring->num_slots - 1);
-		return (1);
-	}
 	dedup.out_slot = dedup.out_ring->slot;
-	if (dedup_init(&dedup, fifo_size) < 0) {
+	if (dedup_init(&dedup, fifo_size, 
+			NETMAP_RXRING(pa->nifp, pa->first_rx_ring),
+			NETMAP_TXRING(pb->nifp, pb->first_tx_ring)) < 0) {
 		D("failed to initialize dedup with fifo_size %u", fifo_size);
 		return (1);
 	}
+	if (fifo_size >= dedup.out_ring->num_slots - 1) {
+		D("fifo_size %u too large (max %u)", fifo_size, dedup.out_ring->num_slots - 1);
+		return (1);
+	}
 	dedup.win_size.tv_sec = win_size_usec / 1000000;
 	dedup.win_size.tv_usec = win_size_usec % 1000000;
 	D("win_size %lld+%lld", (long long) dedup.win_size.tv_sec,
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index e5d8ca5ee..3763d2f06 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -5,12 +5,19 @@
 #include "dedup.h"
 
 int
-dedup_init(struct dedup *d, unsigned int fifo_size)
+dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, struct netmap_ring *out)
 {
 	d->fifo = calloc(fifo_size, sizeof(d->fifo[0]));
 	if (d->fifo == NULL)
 		return -1;
 	d->fifo_size = fifo_size;
+	d->in_ring = in;
+	d->in_slot = in->slot;
+	d->out_ring = out;
+	d->out_slot = out->slot;
+	dedup_ptr_init(d, &d->next_to_send, out->head);
+	dedup_ptr_init(d, &d->fifo_out, out->head);
+	dedup_ptr_init(d, &d->fifo_in, out->head);
 	return 0;
 }
 
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 75455563e..727080bca 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -37,7 +37,8 @@ struct dedup {
 	int	zcopy_in_out;
 };
 
-int dedup_init(struct dedup *d, unsigned int fifo_size);
+int dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in,
+		struct netmap_ring *out);
 
 void dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v);
 

From f410d03766640a21e6bf0c9d0720998363d5280d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 Nov 2017 22:46:34 +0100
Subject: [PATCH 0473/2207] dedup: fix wrong accounting of out_space

---
 apps/dedup/dedup.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 3763d2f06..f7a66dfbc 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -88,19 +88,17 @@ _dedup_fifo_push_out(struct dedup *d)
 	dedup_ptr_inc(d, &d->fifo_out);
 }
 
-static int
-_dedup_fifo_slide_win(struct dedup *d, int out_space, const struct timeval* now)
+static void
+_dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 {
 	struct timeval winstart;
 
 	timersub(now, &d->win_size, &winstart);
 
-	while (out_space && !dedup_fifo_empty(d) &&
-			timercmp(&d->fifo[d->fifo_out.f].arrival, &winstart, <)) {
+	while (!dedup_fifo_empty(d) &&
+		timercmp(&d->fifo[d->fifo_out.f].arrival, &winstart, <)) {
 		_dedup_fifo_push_out(d);
-		out_space--;
 	}
-	return out_space;
 }
 
 int
@@ -122,7 +120,7 @@ dedup_hold_push_in(struct dedup *d)
 	if (out_space < 0)
 		out_space += ro->num_slots;
 
-	out_space = _dedup_fifo_slide_win(d, out_space, &now);
+	_dedup_fifo_slide_win(d, &now);
 
 	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
 		struct netmap_slot *src_slot, *dst_slot;

From 0bc1e947922b416360f7aa18c828626aa56542d5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 Nov 2017 22:48:59 +0100
Subject: [PATCH 0474/2207] dedup: improve readability

---
 apps/dedup/dedup.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index f7a66dfbc..e67fe2825 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -95,8 +95,12 @@ _dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 
 	timersub(now, &d->win_size, &winstart);
 
-	while (!dedup_fifo_empty(d) &&
-		timercmp(&d->fifo[d->fifo_out.f].arrival, &winstart, <)) {
+	while (!dedup_fifo_empty(d)) {
+		struct dedup_fifo_entry *e = &d->fifo[d->fifo_out.f];
+
+		if (timercmp(&e->arrival, &winstart, <))
+			break;
+
 		_dedup_fifo_push_out(d);
 	}
 }

From a75db43fd66cb58dedfa07d925cd0077537cdac4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 24 Nov 2017 18:41:21 +0100
Subject: [PATCH 0475/2207] dedup: generalized push function

---
 apps/dedup/dedup-main.c |  15 +++--
 apps/dedup/dedup.c      | 133 +++++++++++++++++++++++++++++++++-------
 apps/dedup/dedup.h      |  15 +++--
 3 files changed, 131 insertions(+), 32 deletions(-)

diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index d384263c5..e844260eb 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -112,8 +112,6 @@ main(int argc, char **argv)
 		nm_close(pa);
 		return (1);
 	}
-	zerocopy = zerocopy && (pa->mem == pb->mem);
-	D("------- zerocopy %ssupported", zerocopy ? "" : "NOT ");
 
 	memset(&dedup, 0, sizeof(dedup));
 	dedup.out_slot = dedup.out_ring->slot;
@@ -127,11 +125,16 @@ main(int argc, char **argv)
 		D("fifo_size %u too large (max %u)", fifo_size, dedup.out_ring->num_slots - 1);
 		return (1);
 	}
+	if (dedup_set_hold_packets(&dedup, 1) < 0) {
+		D("failed to set 'hold packets' option");
+		return (1);
+	}
+	dedup.in_memid = pa->req.nr_arg2;
+	dedup.fifo_memid = dedup.out_memid = (zerocopy ? pb->req.nr_arg2 : -1 );
 	dedup.win_size.tv_sec = win_size_usec / 1000000;
 	dedup.win_size.tv_usec = win_size_usec % 1000000;
 	D("win_size %lld+%lld", (long long) dedup.win_size.tv_sec,
 			(long long) dedup.win_size.tv_usec);
-	dedup.zcopy_in_out = zerocopy;
 
 	/* setup poll(2) array */
 	memset(pollfd, 0, sizeof(pollfd));
@@ -147,6 +150,7 @@ main(int argc, char **argv)
 	n = 0;
 	while (!do_abort) {
 		int ret;
+		struct timeval now;
 
 		pollfd[0].events = pollfd[1].events = 0;
 		pollfd[0].revents = pollfd[1].revents = 0;
@@ -156,6 +160,7 @@ main(int argc, char **argv)
 			pollfd[1].events = POLLOUT;
 		/* poll() also cause kernel to txsync/rxsync the NICs */
 		ret = poll(pollfd, 2, 1000);
+		gettimeofday(&now, NULL);
 		if (ret <= 0 || verbose)
 		    D("poll %s [0] ev %x %x"
 			     " [1] ev %x %x",
@@ -165,9 +170,7 @@ main(int argc, char **argv)
 				pollfd[1].events,
 				pollfd[1].revents
 			);
-		dedup.in_ring->cur = dedup.in_ring->tail;
-		n = dedup_hold_push_in(&dedup);
-		dedup.out_ring->cur = dedup.out_ring->head;
+		n = dedup_push_in(&dedup, &now);
 	}
 	nm_close(pb);
 	nm_close(pa);
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index e67fe2825..ba7f5b481 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -4,6 +4,14 @@
 #include 
 #include "dedup.h"
 
+static void
+dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
+{
+	p->r = v;
+	p->o = v % d->out_ring->num_slots;
+}
+
+
 int
 dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, struct netmap_ring *out)
 {
@@ -15,17 +23,37 @@ dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, stru
 	d->in_slot = in->slot;
 	d->out_ring = out;
 	d->out_slot = out->slot;
-	dedup_ptr_init(d, &d->next_to_send, out->head);
 	dedup_ptr_init(d, &d->fifo_out, out->head);
 	dedup_ptr_init(d, &d->fifo_in, out->head);
 	return 0;
 }
 
+int
+dedup_set_hold_packets(struct dedup *d, int hold)
+{
+	if (hold) {
+		d->fifo_slot = d->out_slot;
+		d->next_to_send = &d->fifo_out;
+	} else {
+		d->fifo_slot = calloc(d->fifo_size, sizeof(struct netmap_slot));
+		if (d->fifo_slot == NULL)
+			return -1;
+		d->next_to_send = &d->fifo_in;
+	}
+	return 0;
+}
+
 void
-dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
+dedup_fini(struct dedup *d)
 {
-	p->r = v;
-	p->o = v % d->out_ring->num_slots;
+	if (d->fifo != NULL) {
+		free(d->fifo);
+		d->fifo = NULL;
+	}
+	if (d->fifo_slot != NULL && d->fifo_slot != d->out_slot) {
+		free(d->fifo_slot);
+		d->fifo_slot = NULL;
+	}
 }
 
 static int
@@ -63,9 +91,10 @@ dedup_duplicate(struct dedup *d, const struct netmap_slot *s)
 }
 
 static void
-dedup_move_in_out(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst)
+_transfer_pkt(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst,
+		int zcopy)
 {
-	if (d->zcopy_in_out) {
+	if (zcopy) {
 		struct netmap_slot w = *dst;
 		*dst = *src;
 		*src = w;
@@ -83,7 +112,6 @@ dedup_move_in_out(struct dedup *d, struct netmap_slot *src, struct netmap_slot *
 static void
 _dedup_fifo_push_out(struct dedup *d)
 {
-	dedup_ptr_inc(d, &d->next_to_send);
 	dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
 	dedup_ptr_inc(d, &d->fifo_out);
 }
@@ -105,26 +133,27 @@ _dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 	}
 }
 
+static inline int
+dedup_can_hold(struct dedup *d)
+{
+	return d->fifo_slot == d->out_slot;
+}
+
 int
-dedup_hold_push_in(struct dedup *d)
+dedup_push_in(struct dedup *d, const struct timeval *now)
 {
 	struct netmap_ring *ri = d->in_ring, *ro = d->out_ring;
 	uint32_t head;
 	int n, out_space;
-	struct timeval now;
 
-	gettimeofday(&now, NULL);
+	_dedup_fifo_slide_win(d, now);
 
 	/* packets to input */
 	n = ri->tail - ri->head;
 	if (n < 0)
 		n += ri->num_slots;
 	/* available space on the output ring */
-	out_space = ro->tail - d->fifo_in.o;
-	if (out_space < 0)
-		out_space += ro->num_slots;
-
-	_dedup_fifo_slide_win(d, &now);
+	out_space = nm_ring_space(ro);
 
 	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
 		struct netmap_slot *src_slot, *dst_slot;
@@ -134,19 +163,82 @@ dedup_hold_push_in(struct dedup *d)
 		if (dedup_duplicate(d, src_slot))
 			continue;
 
-		/* the packet must go into the FIFO, which is implemented
-		 * in the out ring
-		 */
 		if (out_space == 0)
 			break;
 
-		/* if the FIFO is full, send the oldest packet */
+		/* if the FIFO is full, remove and possibily send
+		 * the oldest packet
+		 */
 		if (dedup_fifo_full(d))
 			_dedup_fifo_push_out(d);
 
 		/* move the new packet to the FIFO */
-		dst_slot = d->out_slot + d->fifo_in.o;
+		dst_slot = d->fifo_slot + d->fifo_in.o;
+		_transfer_pkt(d, src_slot, dst_slot, d->in_memid == d->fifo_memid);
+		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
+		dedup_ptr_inc(d, &d->fifo_in);
+		dedup_hash_insert(d, dst_slot);
+
+		/* 
+		 * if we cannot hold packets, we need
+		 * to copy the outgoing packet to the out queue
+		 */
+		if (!dedup_can_hold(d)) {
+			_transfer_pkt(d,
+				d->fifo_slot + d->next_to_send->f,
+				d->out_slot + d->next_to_send->o,
+				0 /* force copy */);
+		}
+
+		out_space--;
+	}
+	ri->head = head;
+	ri->cur = ri->tail;
+	ro->head = d->next_to_send->o;
+	ro->cur = dedup_can_hold(d) ? d->fifo_in.o : ro->head;
+	return n;
+}
+
+#if 0
+int
+dedup_push_in(struct dedup *d)
+{
+	struct netmap_ring *ri = d->in_ring, *ro = d->out_ring;
+	uint32_t head;
+	int n, out_space;
+	struct timeval now;
+	struct dedup_ptr *dst = &(d->can_hold ? 
+			d->fifo_in : d->next_to_send);
+
+	gettimeofday(&now, NULL);
+
+	_dedup_fifo_slide_win(d, &now);
+
+	/* packets to input */
+	n = ri->tail - ri->head;
+	if (n < 0)
+		n += ri->num_slots;
+	/* available space on the output ring */
+	out_space = ro->tail - d->next_to_send.o;
+	if (out_space < 0)
+		out_space += ro->num_slots;
+
+	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
+		struct netmap_slot *src_slot, *dst_slot;
+
+		src_slot = d->in_slot + head;
+
+		if (dedup_duplicate(d, src_slot))
+			continue;
+
+		/* if the FIFO is full, send the oldest packet */
+		if (dedup_fifo_full(d))
+			_dedup_fifo_drop(d);
+
+		/* send the new packet */
+		dst_slot = d->out_slot + d->next_to_send.o;
 		dedup_move_in_out(d, src_slot, dst_slot);
+		/* copy or move into the FIFO */
 		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
 		dedup_ptr_inc(d, &d->fifo_in);
 		out_space--;
@@ -157,7 +249,6 @@ dedup_hold_push_in(struct dedup *d)
 	return n;
 }
 
-#if 0
 /* dedup_push_in: push new packets through the deduplicator.
  *
  * - duplicated packets are dropped
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 727080bca..8b8a2756c 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -18,29 +18,32 @@ struct dedup {
 	/* input ring */
 	struct netmap_ring *in_ring;
 	struct netmap_slot *in_slot;
+	int in_memid;
 
 	/* output ring */
 	struct netmap_ring *out_ring;
 	struct netmap_slot *out_slot;
+	int out_memid;
 
 	/* fifo */
 	struct dedup_fifo_entry *fifo;
+	struct netmap_slot *fifo_slot;
+	int fifo_memid;
 
 	/* pointers */
-	struct dedup_ptr next_to_send;
+	struct dedup_ptr *next_to_send;
 	struct dedup_ptr fifo_in;
 	struct dedup_ptr fifo_out;
 
 	/* configuration */ 
 	unsigned int fifo_size;
 	struct timeval win_size;
-	int	zcopy_in_out;
+	int zcopy_in_out;
 };
 
 int dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in,
 		struct netmap_ring *out);
-
-void dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v);
+int dedup_set_hold_packets(struct dedup *d, int hold);
 
 static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
 {
@@ -53,6 +56,8 @@ static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
 			p->f = 0;
 }
 
-int dedup_hold_push_in(struct dedup *d);
+int dedup_push_in(struct dedup *d, const struct timeval *now);
+
+void dedup_fini(struct dedup *d);
 
 #endif

From 31523bea0e73e06a04d0420bba606445bf5fb027 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 27 Nov 2017 16:12:36 +0100
Subject: [PATCH 0476/2207] dedup: support non-hold operation

---
 apps/dedup/dedup-main.c | 29 +++++++++++++++++++++++++----
 apps/dedup/dedup.c      | 40 +++++++++++++++++++++++++++++-----------
 apps/dedup/dedup.h      |  2 +-
 3 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index e844260eb..e9212958e 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -46,10 +46,13 @@ main(int argc, char **argv)
 	unsigned int fifo_size = 10;
 	struct dedup dedup;
 	int n;
+	int hold = 0;
+	struct nmreq base_req;
+	uint32_t buf_head = 0;
 
 	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
 
-	while ((ch = getopt(argc, argv, "hci:vw:W:F:")) != -1) {
+	while ((ch = getopt(argc, argv, "hci:vw:W:F:H")) != -1) {
 		switch (ch) {
 		default:
 			D("bad option %c %s", ch, optarg);
@@ -81,6 +84,9 @@ main(int argc, char **argv)
 		case 'F':
 			fifo_size = atoi(optarg);
 			break;
+		case 'H':
+			hold = 1;
+			break;
 		}
 
 	}
@@ -89,11 +95,23 @@ main(int argc, char **argv)
 		D("missing interface");
 		usage();
 	}
-	pa = nm_open(ifa, NULL, 0, NULL);
+	memset(&base_req, 0, sizeof(base_req));
+	if (!hold) {
+		base_req.nr_arg3 = fifo_size;
+	}
+	pa = nm_open(ifa, &base_req, 0, NULL);
 	if (pa == NULL) {
 		D("cannot open %s", ifa);
 		return (1);
 	}
+	if (!hold) {
+	        if (base_req.nr_arg3 != fifo_size) {
+			D("failed to allocate %u extra buffers", fifo_size);
+			return (1); // XXX failover to copy?
+		} else {
+			buf_head = pa->nifp->ni_bufs_head;
+		}
+	}
 	if (pa->first_rx_ring != pa->last_rx_ring) {
 		D("%s: too many RX rings (%d)", pa->req.nr_name,
 				pa->last_rx_ring - pa->first_rx_ring + 1);
@@ -125,12 +143,15 @@ main(int argc, char **argv)
 		D("fifo_size %u too large (max %u)", fifo_size, dedup.out_ring->num_slots - 1);
 		return (1);
 	}
-	if (dedup_set_hold_packets(&dedup, 1) < 0) {
+	if (dedup_set_fifo_buffers(&dedup, NULL, buf_head) != 0) {
 		D("failed to set 'hold packets' option");
 		return (1);
 	}
+
+	/* enable/disable zerocopy */
 	dedup.in_memid = pa->req.nr_arg2;
-	dedup.fifo_memid = dedup.out_memid = (zerocopy ? pb->req.nr_arg2 : -1 );
+	dedup.out_memid = (zerocopy ? pb->req.nr_arg2 : -1 );
+	dedup.fifo_memid = hold ? dedup.out_memid : dedup.in_memid;
 	dedup.win_size.tv_sec = win_size_usec / 1000000;
 	dedup.win_size.tv_usec = win_size_usec % 1000000;
 	D("win_size %lld+%lld", (long long) dedup.win_size.tv_sec,
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index ba7f5b481..7c1cf1857 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -9,6 +9,7 @@ dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
 {
 	p->r = v;
 	p->o = v % d->out_ring->num_slots;
+	p->f = v % d->fifo_size;
 }
 
 
@@ -28,19 +29,34 @@ dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, stru
 	return 0;
 }
 
-int
-dedup_set_hold_packets(struct dedup *d, int hold)
+uint32_t
+dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_head)
 {
-	if (hold) {
+	uint32_t scan;
+	struct netmap_slot *s;
+	struct netmap_ring *r = ring ? ring : d->in_ring;
+
+	if (buf_head == 0) {
 		d->fifo_slot = d->out_slot;
 		d->next_to_send = &d->fifo_out;
-	} else {
-		d->fifo_slot = calloc(d->fifo_size, sizeof(struct netmap_slot));
-		if (d->fifo_slot == NULL)
-			return -1;
-		d->next_to_send = &d->fifo_in;
+		return 0;
 	}
-	return 0;
+	d->fifo_slot = calloc(d->fifo_size, sizeof(struct netmap_slot));
+	if (d->fifo_slot == NULL)
+		return buf_head;
+	for (scan = buf_head, s = d->fifo_slot;
+	     scan != 0 && s != d->fifo_slot + d->fifo_size;
+             scan = *(uint32_t *)NETMAP_BUF(r, scan), s++) {
+		s->len = r->nr_buf_size;
+		s->buf_idx = scan;
+	}
+	if (s != d->fifo_slot + d->fifo_size) {
+		free(d->fifo_slot);
+		d->fifo_slot = NULL;
+		return buf_head;
+	}
+	d->next_to_send = &d->fifo_in;
+	return scan;
 }
 
 void
@@ -173,10 +189,10 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 			_dedup_fifo_push_out(d);
 
 		/* move the new packet to the FIFO */
-		dst_slot = d->fifo_slot + d->fifo_in.o;
+		dst_slot = d->fifo_slot +
+			(dedup_can_hold(d) ? d->fifo_in.o : d->fifo_in.f);
 		_transfer_pkt(d, src_slot, dst_slot, d->in_memid == d->fifo_memid);
 		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
-		dedup_ptr_inc(d, &d->fifo_in);
 		dedup_hash_insert(d, dst_slot);
 
 		/* 
@@ -190,6 +206,8 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 				0 /* force copy */);
 		}
 
+		dedup_ptr_inc(d, &d->fifo_in);
+
 		out_space--;
 	}
 	ri->head = head;
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 8b8a2756c..f6a17c262 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -43,7 +43,7 @@ struct dedup {
 
 int dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in,
 		struct netmap_ring *out);
-int dedup_set_hold_packets(struct dedup *d, int hold);
+uint32_t dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_head);
 
 static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
 {

From 8705ea3fc0525203296f0d73785881341f28dafa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 27 Nov 2017 17:45:59 +0100
Subject: [PATCH 0477/2207] dedup: free extra buffers at exit

---
 apps/dedup/dedup-main.c | 24 ++++++++++++++++++++----
 apps/dedup/dedup.c      | 32 ++++++++++++++++++++++++++------
 apps/dedup/dedup.h      |  1 +
 3 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index e9212958e..4547b3985 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -34,17 +34,33 @@ usage(void)
 	exit(1);
 }
 
+struct dedup dedup;
+struct nm_desc *pa = NULL, *pb = NULL;
+
+static void
+free_buffers(void)
+{
+	struct netmap_ring *ring;
+
+	if (pa == NULL)
+		return;
+
+	ring = NETMAP_RXRING(pa->nifp, pa->first_rx_ring);
+
+	dedup_get_fifo_buffers(&dedup, ring, &pa->nifp->ni_bufs_head);
+	nm_close(pa);
+	nm_close(pb);
+}
+
 int
 main(int argc, char **argv)
 {
 	struct pollfd pollfd[2];
 	int ch;
-	struct nm_desc *pa = NULL, *pb = NULL;
 	char *ifa = NULL, *ifb = NULL;
 	int wait_link = 2;
 	int win_size_usec = 50;
 	unsigned int fifo_size = 10;
-	struct dedup dedup;
 	int n;
 	int hold = 0;
 	struct nmreq base_req;
@@ -147,6 +163,8 @@ main(int argc, char **argv)
 		D("failed to set 'hold packets' option");
 		return (1);
 	}
+	pa->nifp->ni_bufs_head = 0;
+	atexit(free_buffers);
 
 	/* enable/disable zerocopy */
 	dedup.in_memid = pa->req.nr_arg2;
@@ -193,8 +211,6 @@ main(int argc, char **argv)
 			);
 		n = dedup_push_in(&dedup, &now);
 	}
-	nm_close(pb);
-	nm_close(pa);
 
 	return (0);
 }
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 7c1cf1857..faae58e8e 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -4,6 +4,12 @@
 #include 
 #include "dedup.h"
 
+static inline int
+dedup_can_hold(struct dedup *d)
+{
+	return d->fifo_slot == d->out_slot;
+}
+
 static void
 dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
 {
@@ -59,6 +65,26 @@ dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_h
 	return scan;
 }
 
+void
+dedup_get_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t *buf_head)
+{
+	struct netmap_ring *r = ring ? ring : d->in_ring;
+	unsigned int i;
+
+	if (d->fifo_slot == NULL || dedup_can_hold(d))
+		return;
+
+	for (i = 0; i < d->fifo_size; i++) {
+		struct netmap_slot *s = d->fifo_slot + i;
+		uint32_t *new_head = (uint32_t *)NETMAP_BUF(r, s->buf_idx);
+		
+		*new_head = *buf_head;
+		*buf_head = s->buf_idx;
+	}	
+	free(d->fifo_slot);
+	d->fifo_slot = NULL;
+}
+
 void
 dedup_fini(struct dedup *d)
 {
@@ -149,12 +175,6 @@ _dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 	}
 }
 
-static inline int
-dedup_can_hold(struct dedup *d)
-{
-	return d->fifo_slot == d->out_slot;
-}
-
 int
 dedup_push_in(struct dedup *d, const struct timeval *now)
 {
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index f6a17c262..e39b87698 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -44,6 +44,7 @@ struct dedup {
 int dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in,
 		struct netmap_ring *out);
 uint32_t dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_head);
+void dedup_get_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t *buf_head);
 
 static inline void dedup_ptr_inc(struct dedup *d, struct dedup_ptr *p)
 {

From 7fda4d055ecd0617604f56897051ed108fcc6c63 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 Nov 2017 10:59:51 +0100
Subject: [PATCH 0478/2207] dedup: slightly better slot-swapping

---
 apps/dedup/GNUmakefile | 2 +-
 apps/dedup/dedup.c     | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/apps/dedup/GNUmakefile b/apps/dedup/GNUmakefile
index a6c2a5838..ea68230ef 100644
--- a/apps/dedup/GNUmakefile
+++ b/apps/dedup/GNUmakefile
@@ -9,7 +9,7 @@ SRCDIR ?= ../..
 VPATH = $(SRCDIR)/apps/dedup
 
 NO_MAN=
-CFLAGS = -O2 -pipe
+CFLAGS = -O2 -pipe -g
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
 CFLAGS += -Wextra
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index faae58e8e..a15bc3dec 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -138,10 +138,11 @@ _transfer_pkt(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst,
 {
 	if (zcopy) {
 		struct netmap_slot w = *dst;
+		__builtin_prefetch(dst + 1);
 		*dst = *src;
+		dst->flags |= NS_BUF_CHANGED;
 		*src = w;
 		src->flags |= NS_BUF_CHANGED;
-		dst->flags |= NS_BUF_CHANGED;
 	} else {
 		char *rxbuf = NETMAP_BUF(d->in_ring, src->buf_idx);
 		char *txbuf = NETMAP_BUF(d->out_ring, dst->buf_idx);

From b80edab12bd3e58411015c0d3ec61beea1fc0888 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 Nov 2017 13:55:40 +0100
Subject: [PATCH 0479/2207] dedup: uniform names

---
 apps/dedup/dedup.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index a15bc3dec..3486a1689 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -133,7 +133,7 @@ dedup_duplicate(struct dedup *d, const struct netmap_slot *s)
 }
 
 static void
-_transfer_pkt(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst,
+dedup_transfer_pkt(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst,
 		int zcopy)
 {
 	if (zcopy) {
@@ -153,14 +153,14 @@ _transfer_pkt(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst,
 }
 
 static void
-_dedup_fifo_push_out(struct dedup *d)
+dedup_fifo_push_out(struct dedup *d)
 {
 	dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
 	dedup_ptr_inc(d, &d->fifo_out);
 }
 
 static void
-_dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
+dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 {
 	struct timeval winstart;
 
@@ -172,7 +172,7 @@ _dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 		if (timercmp(&e->arrival, &winstart, <))
 			break;
 
-		_dedup_fifo_push_out(d);
+		dedup_fifo_push_out(d);
 	}
 }
 
@@ -183,7 +183,7 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 	uint32_t head;
 	int n, out_space;
 
-	_dedup_fifo_slide_win(d, now);
+	dedup_fifo_slide_win(d, now);
 
 	/* packets to input */
 	n = ri->tail - ri->head;
@@ -207,12 +207,12 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 		 * the oldest packet
 		 */
 		if (dedup_fifo_full(d))
-			_dedup_fifo_push_out(d);
+			dedup_fifo_push_out(d);
 
 		/* move the new packet to the FIFO */
 		dst_slot = d->fifo_slot +
 			(dedup_can_hold(d) ? d->fifo_in.o : d->fifo_in.f);
-		_transfer_pkt(d, src_slot, dst_slot, d->in_memid == d->fifo_memid);
+		dedup_transfer_pkt(d, src_slot, dst_slot, d->in_memid == d->fifo_memid);
 		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
 		dedup_hash_insert(d, dst_slot);
 
@@ -221,7 +221,7 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 		 * to copy the outgoing packet to the out queue
 		 */
 		if (!dedup_can_hold(d)) {
-			_transfer_pkt(d,
+			dedup_transfer_pkt(d,
 				d->fifo_slot + d->next_to_send->f,
 				d->out_slot + d->next_to_send->o,
 				0 /* force copy */);

From 1cd9cee83e42a8c353a573a3aa24fcbae9e85676 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 Nov 2017 14:13:21 +0100
Subject: [PATCH 0480/2207] dedup: remove stale code

---
 apps/dedup/dedup.c | 150 ---------------------------------------------
 1 file changed, 150 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 3486a1689..8e7ceccf5 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -237,153 +237,3 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 	ro->cur = dedup_can_hold(d) ? d->fifo_in.o : ro->head;
 	return n;
 }
-
-#if 0
-int
-dedup_push_in(struct dedup *d)
-{
-	struct netmap_ring *ri = d->in_ring, *ro = d->out_ring;
-	uint32_t head;
-	int n, out_space;
-	struct timeval now;
-	struct dedup_ptr *dst = &(d->can_hold ? 
-			d->fifo_in : d->next_to_send);
-
-	gettimeofday(&now, NULL);
-
-	_dedup_fifo_slide_win(d, &now);
-
-	/* packets to input */
-	n = ri->tail - ri->head;
-	if (n < 0)
-		n += ri->num_slots;
-	/* available space on the output ring */
-	out_space = ro->tail - d->next_to_send.o;
-	if (out_space < 0)
-		out_space += ro->num_slots;
-
-	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
-		struct netmap_slot *src_slot, *dst_slot;
-
-		src_slot = d->in_slot + head;
-
-		if (dedup_duplicate(d, src_slot))
-			continue;
-
-		/* if the FIFO is full, send the oldest packet */
-		if (dedup_fifo_full(d))
-			_dedup_fifo_drop(d);
-
-		/* send the new packet */
-		dst_slot = d->out_slot + d->next_to_send.o;
-		dedup_move_in_out(d, src_slot, dst_slot);
-		/* copy or move into the FIFO */
-		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
-		dedup_ptr_inc(d, &d->fifo_in);
-		out_space--;
-		dedup_hash_insert(d, dst_slot);
-	}
-	ri->head = head;
-	ro->head = d->next_to_send.o;
-	return n;
-}
-
-/* dedup_push_in: push new packets through the deduplicator.
- *
- * - duplicated packets are dropped
- * - fresh packets always go into the FIFO first. If they cannot be hold, they
- *   are also copied to the out ring; if we can hold packets, an incoming fresh
- *   packet may still cause another packet to be pushed to the out ring, if the
- *   FIFO is full; if these operations cannot be completed for lack of space,
- *   the processing stops and the fresh packet is not removed from the input
- *   queue (XXX this means that it will be checked for duplication again next
- *   time: we may optmize this by playing with head and cur)
- */
-int
-dedup_push_in(struct dedup *d)
-{
-	struct nemap_ring *ri = d->in_ring, *ro = d->out_ring;
-	uint32_t cur;
-	int n
-
-	/* packets to input */
-	n = ri->tail - ri->cur;
-	if (n < 0)
-		n += ri->num_slots;
-	/* available space on the output ring
-	 * (note that can_hold == 0 implies prefetch == 0 )
-	 */
-	out_space = ro->tail - (ro->head + d->prefetch);
-	if (out_space < 0)
-		out_space += ro->num_slots;
-
-	for (cur = ri->cur; n; cur = nm_ring_next(ri, cur), n--) {
-		unsigned long next_to_send = d->next_to_send.r;
-		struct netmap_slot *src_slot, *dst_slot;
-
-		src_slot = d->in_slot + cur;
-
-		if (dedup_duplicate(d, src_slot))
-			continue;
-
-		/* if the FIFO is full, remove the oldest */
-		if (dedup_fifo_full(d)) {
-			struct netmap_slot *rem_slot;
-
-			/* we can only send out the packet if it is
-			 * already prefeteched or we have a free slot
-			 * in the output queue
-			 */
-			if (d->prefetch == 0 && out_space == 0)
-				break;
-			dedup_ptr_inc(&d->next_to_send);
-
-			rem_slot = (d->prefetched > 0) ?
-				d->out_slot + d->fifo_out.o :
-				d->spill_slot d->fifo_out.f;
-			dedup_hash_remove(d, rem_slot);
-			dedup_ptr_inc(d, &d->fifo_out);
-		}
-
-		/* move the new packet to the FIFO */
-		if (out_space > 0) {
-			/* put the new packet directly into the output ring */
-			dst_slot = d->out_slot + d->fifo_in.o;
-			d->prefetched++;
-		} else {
-			/* the packet goes into the spill queue.
-			 * It is guaranteed to there be room there, since we have
-			 * removed the oldest packet from the FIFO above
-			 */
-			dst_slot = d->spill + d->fifo_in.f;
-		}
-		// XXX copy-or-swap from src_slot to dst_slot
-		dedup_ptr_inc(d, &d->fifo_in);
-		dedup_hash_insert(d, dst_slot);
-		/* the next packet to send always comes from the FIFO,
-		 * at next_to_send position. If hold > 0 the packet already
-		 * is in the out_ring, otherwise it must be obtained
-		 * from the spill_ring. 
-		 * If hold cannot be increased, we also need to copy the
-		 * packet, whatever the value of the swap-or-copy flag for
-		 * the direction.
-		 */
-		if (d->hold == 0) {
-			if (d->max_hold == 0) {
-				// XXX copy from spill[d->spill_head] to
-				// out_ring[d->out_head]
-			} else {
-				// XXX copy-or-swap from spill[d->spill_head]
-				// to out_ring[d->out_head]
-				d->hold++;
-			}
-		} else {
-			d->hold--;
-		}
-		dedup_ptr_inc(d, &d->next_to_send);
-	}
-	ro->head = ro->cur = d->next_to_send.o;
-	return n;
-}
-#endif
-

From 93c09c56aa80882dc1cf3e128048a4eb85827534 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 Nov 2017 15:38:09 +0100
Subject: [PATCH 0481/2207] dedup: support more memid cases

---
 apps/dedup/dedup.c | 64 +++++++++++++++++++++++++++-------------------
 apps/dedup/dedup.h |  1 +
 2 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 8e7ceccf5..a6ea345e9 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -43,6 +43,7 @@ dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_h
 	struct netmap_ring *r = ring ? ring : d->in_ring;
 
 	if (buf_head == 0) {
+		d->fifo_ring = d->out_ring;
 		d->fifo_slot = d->out_slot;
 		d->next_to_send = &d->fifo_out;
 		return 0;
@@ -61,6 +62,7 @@ dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_h
 		d->fifo_slot = NULL;
 		return buf_head;
 	}
+	d->fifo_ring = d->in_ring;
 	d->next_to_send = &d->fifo_in;
 	return scan;
 }
@@ -132,23 +134,29 @@ dedup_duplicate(struct dedup *d, const struct netmap_slot *s)
 	return 0;
 }
 
-static void
-dedup_transfer_pkt(struct dedup *d, struct netmap_slot *src, struct netmap_slot *dst,
-		int zcopy)
+static inline void
+dedup_transfer_pkt(struct dedup *d,
+	struct netmap_ring *src_ring,
+	struct netmap_slot *src_slot,
+	struct netmap_ring *dst_ring,
+	struct netmap_slot *dst_slot,
+	int zcopy)
 {
+	(void)d;
+
 	if (zcopy) {
-		struct netmap_slot w = *dst;
-		__builtin_prefetch(dst + 1);
-		*dst = *src;
-		dst->flags |= NS_BUF_CHANGED;
-		*src = w;
-		src->flags |= NS_BUF_CHANGED;
+		struct netmap_slot w = *dst_slot;
+		__builtin_prefetch(dst_slot + 1);
+		*dst_slot = *src_slot;
+		dst_slot->flags |= NS_BUF_CHANGED;
+		*src_slot = w;
+		src_slot->flags |= NS_BUF_CHANGED;
 	} else {
-		char *rxbuf = NETMAP_BUF(d->in_ring, src->buf_idx);
-		char *txbuf = NETMAP_BUF(d->out_ring, dst->buf_idx);
-		nm_pkt_copy(rxbuf, txbuf, src->len);
-		dst->len = src->len;
-		dst->ptr = src->ptr;
+		char *rxbuf = NETMAP_BUF(src_ring, src_slot->buf_idx);
+		char *txbuf = NETMAP_BUF(dst_ring, dst_slot->buf_idx);
+		nm_pkt_copy(rxbuf, txbuf, src_slot->len);
+		dst_slot->len = src_slot->len;
+		dst_slot->ptr = src_slot->ptr;
 	}
 }
 
@@ -209,26 +217,30 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 		if (dedup_fifo_full(d))
 			dedup_fifo_push_out(d);
 
-		/* move the new packet to the FIFO */
-		dst_slot = d->fifo_slot +
-			(dedup_can_hold(d) ? d->fifo_in.o : d->fifo_in.f);
-		dedup_transfer_pkt(d, src_slot, dst_slot, d->in_memid == d->fifo_memid);
+		/* move the new packet to out ring */
+		dst_slot = d->out_slot + d->fifo_in.o;
+		dedup_transfer_pkt(d,
+			d->in_ring,
+			src_slot,
+			d->out_ring,
+			dst_slot,
+			d->in_memid == d->out_memid);
+
+		/* hold/copy/swap the packet in the FIFO ring */
 		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
 		dedup_hash_insert(d, dst_slot);
 
-		/* 
-		 * if we cannot hold packets, we need
-		 * to copy the outgoing packet to the out queue
-		 */
 		if (!dedup_can_hold(d)) {
 			dedup_transfer_pkt(d,
-				d->fifo_slot + d->next_to_send->f,
-				d->out_slot + d->next_to_send->o,
-				0 /* force copy */);
+				(d->in_memid == d->out_memid ? d->out_ring : d->in_ring),
+				(d->in_memid == d->out_memid ? dst_slot : src_slot),
+				d->fifo_ring,
+				d->fifo_slot + d->fifo_in.f,
+				(d->in_memid != d->out_memid &&
+				 d->in_memid == d->fifo_memid));
 		}
 
 		dedup_ptr_inc(d, &d->fifo_in);
-
 		out_space--;
 	}
 	ri->head = head;
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index e39b87698..6e9838a71 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -27,6 +27,7 @@ struct dedup {
 
 	/* fifo */
 	struct dedup_fifo_entry *fifo;
+	struct netmap_ring *fifo_ring;
 	struct netmap_slot *fifo_slot;
 	int fifo_memid;
 

From 94df452e3f926c76d8aa31e6b1479cfa6d28c9bd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 Nov 2017 23:54:32 +0100
Subject: [PATCH 0482/2207] dedup: fix time direction win window slide

---
 apps/dedup/dedup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index a6ea345e9..9e8a66520 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -177,7 +177,7 @@ dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 	while (!dedup_fifo_empty(d)) {
 		struct dedup_fifo_entry *e = &d->fifo[d->fifo_out.f];
 
-		if (timercmp(&e->arrival, &winstart, <))
+		if (timercmp(&winstart, &e->arrival, <=))
 			break;
 
 		dedup_fifo_push_out(d);

From 18cabcaa7736d977859736860f673b0735f0427b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 29 Nov 2017 19:16:37 +0100
Subject: [PATCH 0483/2207] dedup: hash table

---
 apps/dedup/dedup-main.c |   2 +
 apps/dedup/dedup.c      | 134 +++++++++++++++++++++++++++++++++-------
 apps/dedup/dedup.h      |  16 ++++-
 3 files changed, 127 insertions(+), 25 deletions(-)

diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index 4547b3985..82dc0bf51 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -170,6 +170,8 @@ main(int argc, char **argv)
 	dedup.in_memid = pa->req.nr_arg2;
 	dedup.out_memid = (zerocopy ? pb->req.nr_arg2 : -1 );
 	dedup.fifo_memid = hold ? dedup.out_memid : dedup.in_memid;
+	D("memids: in %d out %d fifo %d", dedup.in_memid, dedup.out_memid,
+			dedup.fifo_memid);
 	dedup.win_size.tv_sec = win_size_usec / 1000000;
 	dedup.win_size.tv_usec = win_size_usec % 1000000;
 	D("win_size %lld+%lld", (long long) dedup.win_size.tv_sec,
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 9e8a66520..67b6692e4 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -1,9 +1,11 @@
 #include 
+#include 
 #include 
 #define NETMAP_WITH_LIBS
 #include 
 #include "dedup.h"
 
+
 static inline int
 dedup_can_hold(struct dedup *d)
 {
@@ -22,9 +24,23 @@ dedup_ptr_init(struct dedup *d, struct dedup_ptr *p, unsigned long v)
 int
 dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, struct netmap_ring *out)
 {
+	unsigned int sh;
+
+	if (fifo_size == 0)
+		return -1;
+
 	d->fifo = calloc(fifo_size, sizeof(d->fifo[0]));
 	if (d->fifo == NULL)
 		return -1;
+
+	sh = (unsigned int)(sizeof(fifo_size) * CHAR_BIT - __builtin_clz(fifo_size - 1));
+	D("sh %u size %lu", sh, 1UL << sh);
+	if (sh > sizeof(unsigned short) * CHAR_BIT - 1)
+		goto err;
+	d->hashmap = calloc(1UL << sh, sizeof(struct dedup_hashmap_entry));
+	if (d->hashmap == NULL)
+		goto err;
+	d->hashmap_mask = sh - 1;
 	d->fifo_size = fifo_size;
 	d->in_ring = in;
 	d->in_slot = in->slot;
@@ -33,6 +49,10 @@ dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, stru
 	dedup_ptr_init(d, &d->fifo_out, out->head);
 	dedup_ptr_init(d, &d->fifo_in, out->head);
 	return 0;
+err:
+	free(d->fifo);
+	d->fifo = NULL;
+	return -1;
 }
 
 uint32_t
@@ -98,6 +118,10 @@ dedup_fini(struct dedup *d)
 		free(d->fifo_slot);
 		d->fifo_slot = NULL;
 	}
+	if (d->hashmap != NULL) {
+		free(d->hashmap);
+		d->hashmap = NULL;
+	}
 }
 
 static int
@@ -112,26 +136,82 @@ dedup_fifo_empty(const struct dedup *d)
 	return (d->fifo_in.r == d->fifo_out.r);
 }
 
+static unsigned int
+dedup_hash(const void *buf, size_t len)
+{
+	unsigned int sum = 0;
+	const char *buf_ = buf;
+	while (len--)
+		sum += *buf_++;
+	D("hash %u", sum);
+	return sum;
+}
+
 static void
-dedup_hash_remove(struct dedup *d, struct netmap_slot *s)
+dedup_hashmap_insert(struct dedup *d, unsigned short h)
 {
-	(void)d;
-	(void)s;
+	struct dedup_hashmap_entry *he = d->hashmap + h;
+	struct dedup_fifo_entry *fe = d->fifo + d->fifo_in.f;
+	fe->bucket_next = (he->valid ? d->fifo_in.r - he->bucket_head : 0);
+	fe->hashmap_entry = h;
+	he->bucket_head = d->fifo_in.r;
+	he->valid = 1;
 }
 
 static void
-dedup_hash_insert(struct dedup *d, struct netmap_slot *s)
+dedup_hashmap_remove(struct dedup *d)
 {
-	(void)d;
-	(void)s;
+	struct dedup_fifo_entry *fe = d->fifo + d->fifo_out.f;
+	struct dedup_hashmap_entry *he = d->hashmap + fe->hashmap_entry;
+
+	ND("h %u bucket_head %lu fifo_out.r %lu fifo_out.f %u",
+			fe->hashmap_entry, he->bucket_head,
+			d->fifo_out.r, d->fifo_out.f);
+	if (he->bucket_head == d->fifo_out.r)
+		he->valid = 0;
+	fe->hashmap_entry = 0;
+	fe->bucket_next = 0;
 }
 
-static int
-dedup_duplicate(struct dedup *d, const struct netmap_slot *s)
+static long
+dedup_fresh_packet(struct dedup *d, const struct netmap_slot *s)
 {
-	(void)d;
-	(void)s;
-	return 0;
+	const void *buf = NETMAP_BUF(d->in_ring, s->buf_idx);
+	unsigned int h = dedup_hash(buf, 64);
+	unsigned short i = h & d->hashmap_mask;
+	struct dedup_hashmap_entry *he = d->hashmap + i;
+	unsigned long fi = he->bucket_head;
+	unsigned long fifo_win = d->fifo_in.r - d->fifo_out.r;
+
+	if (!he->valid)
+		return i;
+
+	while (d->fifo_in.r - fi > 0 && d->fifo_in.r - fi <= fifo_win) {
+		struct netmap_slot *fs;
+		const void *fbuf;
+		unsigned long rfi = fi - d->fifo_out.r + d->fifo_out.f;
+		unsigned int delta;
+
+		if (rfi >= d->fifo_size)
+			rfi -= d->fifo_size;
+
+		fs = d->fifo_slot + rfi;
+		ND("checking %lu %lu: lenghts %u %u buf %d", fi, rfi, fs->len, s->len,
+				fs->buf_idx);
+
+		if (fs->len != s->len)
+			goto next;
+		fbuf = NETMAP_BUF(d->fifo_ring, fs->buf_idx);
+		if (memcmp(buf, fbuf, s->len))
+			goto next;
+		return -1;
+	next:
+		delta = d->fifo[rfi].bucket_next;
+		if (delta == 0)
+			break;
+		fi -= delta;
+	}
+	return i;
 }
 
 static inline void
@@ -160,13 +240,6 @@ dedup_transfer_pkt(struct dedup *d,
 	}
 }
 
-static void
-dedup_fifo_push_out(struct dedup *d)
-{
-	dedup_hash_remove(d, &d->out_slot[d->fifo_out.o]);
-	dedup_ptr_inc(d, &d->fifo_out);
-}
-
 static void
 dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 {
@@ -177,10 +250,19 @@ dedup_fifo_slide_win(struct dedup *d, const struct timeval* now)
 	while (!dedup_fifo_empty(d)) {
 		struct dedup_fifo_entry *e = &d->fifo[d->fifo_out.f];
 
+		ND("fifo %u: arrival %llu.%llu winstart %llu.%llu",
+				d->fifo_out.f,
+				(unsigned long long)e->arrival.tv_sec,
+				(unsigned long long)e->arrival.tv_usec,
+				(unsigned long long)winstart.tv_sec,
+				(unsigned long long)winstart.tv_usec);
+
 		if (timercmp(&winstart, &e->arrival, <=))
 			break;
 
-		dedup_fifo_push_out(d);
+		ND("fifo %u: pushing out", d->fifo_out.f);
+		dedup_hashmap_remove(d);
+		dedup_ptr_inc(d, &d->fifo_out);
 	}
 }
 
@@ -202,11 +284,15 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 
 	for (head = ri->head; n; head = nm_ring_next(ri, head), n--) {
 		struct netmap_slot *src_slot, *dst_slot;
+		long h;
 
 		src_slot = d->in_slot + head;
 
-		if (dedup_duplicate(d, src_slot))
+		h = dedup_fresh_packet(d, src_slot);
+		if (h < 0) { /* duplicate */
+			ND("dropping %u", head);
 			continue;
+		}
 
 		if (out_space == 0)
 			break;
@@ -214,8 +300,10 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 		/* if the FIFO is full, remove and possibily send
 		 * the oldest packet
 		 */
-		if (dedup_fifo_full(d))
-			dedup_fifo_push_out(d);
+		if (dedup_fifo_full(d)) {
+			dedup_hashmap_remove(d);
+			dedup_ptr_inc(d, &d->fifo_out);
+		}
 
 		/* move the new packet to out ring */
 		dst_slot = d->out_slot + d->fifo_in.o;
@@ -228,7 +316,6 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 
 		/* hold/copy/swap the packet in the FIFO ring */
 		d->fifo[d->fifo_in.f].arrival = d->in_ring->ts;
-		dedup_hash_insert(d, dst_slot);
 
 		if (!dedup_can_hold(d)) {
 			dedup_transfer_pkt(d,
@@ -240,6 +327,7 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 				 d->in_memid == d->fifo_memid));
 		}
 
+		dedup_hashmap_insert(d, h);
 		dedup_ptr_inc(d, &d->fifo_in);
 		out_space--;
 	}
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 6e9838a71..76697ffd6 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -3,15 +3,23 @@
 
 #define _BSD_SOURCE
 #include 
+#include 
 
 struct dedup_ptr {
 	unsigned long r; /* free running, wraps naturally */
-	unsigned int o;  /* wraps at out_ring-size */
-	unsigned int f;  /* wraps at fifo_size */
+	unsigned short o;  /* wraps at out_ring-size */
+	unsigned short f;  /* wraps at fifo_size */
 };
 
 struct dedup_fifo_entry {
 	struct timeval arrival;
+	unsigned short hashmap_entry;
+	unsigned int bucket_next; /* collision chain */
+};
+
+struct dedup_hashmap_entry {
+	int valid;
+	unsigned long bucket_head;
 };
 
 struct dedup {
@@ -36,6 +44,10 @@ struct dedup {
 	struct dedup_ptr fifo_in;
 	struct dedup_ptr fifo_out;
 
+	/* hash map */
+	struct dedup_hashmap_entry *hashmap;
+	unsigned int hashmap_mask;
+
 	/* configuration */ 
 	unsigned int fifo_size;
 	struct timeval win_size;

From 87dd5489185402c81be38576d19e46bb222afe72 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 2 Dec 2017 17:50:19 +0100
Subject: [PATCH 0484/2207] dedup: hash function

---
 apps/dedup/GNUmakefile       |   1 +
 apps/dedup/dedup-main.c      |  16 ++
 apps/dedup/dedup.c           |  27 ++-
 apps/dedup/dedup.h           |   3 +
 apps/dedup/mark-adler-hash.c | 378 +++++++++++++++++++++++++++++++++++
 5 files changed, 414 insertions(+), 11 deletions(-)
 create mode 100644 apps/dedup/mark-adler-hash.c

diff --git a/apps/dedup/GNUmakefile b/apps/dedup/GNUmakefile
index ea68230ef..07fbb5f28 100644
--- a/apps/dedup/GNUmakefile
+++ b/apps/dedup/GNUmakefile
@@ -13,6 +13,7 @@ CFLAGS = -O2 -pipe -g
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
 CFLAGS += -Wextra
+#CFLAGS += -DDEDUP_HASH_STAT
 
 LDLIBS += -lpthread
 ifeq ($(shell uname),Linux)
diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index 82dc0bf51..1684e5459 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -65,6 +65,9 @@ main(int argc, char **argv)
 	int hold = 0;
 	struct nmreq base_req;
 	uint32_t buf_head = 0;
+#ifdef DEDUP_HASH_STAT
+	time_t last_hash_output = 0;
+#endif
 
 	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
 
@@ -212,6 +215,19 @@ main(int argc, char **argv)
 				pollfd[1].revents
 			);
 		n = dedup_push_in(&dedup, &now);
+#ifdef DEDUP_HASH_STAT
+		if (now.tv_sec != last_hash_output) {
+			unsigned int i;
+
+			last_hash_output = now.tv_sec;
+			printf("buckets: ");
+			for (i = 0; i <= dedup.hashmap_mask; i++) {
+				if  (dedup.hashmap[i].bucket_size)
+					printf("%u: %u, ", i, dedup.hashmap[i].bucket_size);
+			}
+			printf("\n");
+		}
+#endif
 	}
 
 	return (0);
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 67b6692e4..537e0e2fe 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -5,6 +5,9 @@
 #include 
 #include "dedup.h"
 
+#include "mark-adler-hash.c"
+
+static int dedup_sse42;
 
 static inline int
 dedup_can_hold(struct dedup *d)
@@ -33,14 +36,14 @@ dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, stru
 	if (d->fifo == NULL)
 		return -1;
 
-	sh = (unsigned int)(sizeof(fifo_size) * CHAR_BIT - __builtin_clz(fifo_size - 1));
+	sh = (unsigned int)(sizeof(fifo_size) * CHAR_BIT - __builtin_clz(fifo_size - 1)) + 1;
 	D("sh %u size %lu", sh, 1UL << sh);
 	if (sh > sizeof(unsigned short) * CHAR_BIT - 1)
 		goto err;
 	d->hashmap = calloc(1UL << sh, sizeof(struct dedup_hashmap_entry));
 	if (d->hashmap == NULL)
 		goto err;
-	d->hashmap_mask = sh - 1;
+	d->hashmap_mask = (1UL << sh) - 1;
 	d->fifo_size = fifo_size;
 	d->in_ring = in;
 	d->in_slot = in->slot;
@@ -48,6 +51,7 @@ dedup_init(struct dedup *d, unsigned int fifo_size, struct netmap_ring *in, stru
 	d->out_slot = out->slot;
 	dedup_ptr_init(d, &d->fifo_out, out->head);
 	dedup_ptr_init(d, &d->fifo_in, out->head);
+	SSE42(dedup_sse42);
 	return 0;
 err:
 	free(d->fifo);
@@ -136,15 +140,10 @@ dedup_fifo_empty(const struct dedup *d)
 	return (d->fifo_in.r == d->fifo_out.r);
 }
 
-static unsigned int
-dedup_hash(const void *buf, size_t len)
+static inline uint32_t
+dedup_hash(const char *data)
 {
-	unsigned int sum = 0;
-	const char *buf_ = buf;
-	while (len--)
-		sum += *buf_++;
-	D("hash %u", sum);
-	return sum;
+	return dedup_sse42 ? crc32c_hw(0, data, 64) : crc32c_sw(0, data, 64);
 }
 
 static void
@@ -156,6 +155,9 @@ dedup_hashmap_insert(struct dedup *d, unsigned short h)
 	fe->hashmap_entry = h;
 	he->bucket_head = d->fifo_in.r;
 	he->valid = 1;
+#ifdef DEDUP_HASH_STAT
+	he->bucket_size++;
+#endif
 }
 
 static void
@@ -171,13 +173,16 @@ dedup_hashmap_remove(struct dedup *d)
 		he->valid = 0;
 	fe->hashmap_entry = 0;
 	fe->bucket_next = 0;
+#ifdef DEDUP_HASH_STAT
+	he->bucket_size--;
+#endif
 }
 
 static long
 dedup_fresh_packet(struct dedup *d, const struct netmap_slot *s)
 {
 	const void *buf = NETMAP_BUF(d->in_ring, s->buf_idx);
-	unsigned int h = dedup_hash(buf, 64);
+	unsigned int h = dedup_hash(buf);
 	unsigned short i = h & d->hashmap_mask;
 	struct dedup_hashmap_entry *he = d->hashmap + i;
 	unsigned long fi = he->bucket_head;
diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 76697ffd6..31b34cadf 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -19,6 +19,9 @@ struct dedup_fifo_entry {
 
 struct dedup_hashmap_entry {
 	int valid;
+#ifdef DEDUP_HASH_STAT
+	unsigned int bucket_size;
+#endif
 	unsigned long bucket_head;
 };
 
diff --git a/apps/dedup/mark-adler-hash.c b/apps/dedup/mark-adler-hash.c
new file mode 100644
index 000000000..f9b3b6dd2
--- /dev/null
+++ b/apps/dedup/mark-adler-hash.c
@@ -0,0 +1,378 @@
+/* crc32c.c -- compute CRC-32C using the Intel crc32 instruction
+ * Copyright (C) 2013 Mark Adler
+ * Version 1.1  1 Aug 2013  Mark Adler
+ */
+
+/*
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the author be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Mark Adler
+  madler@alumni.caltech.edu
+ */
+
+/* Use hardware CRC instruction on Intel SSE 4.2 processors.  This computes a
+   CRC-32C, *not* the CRC-32 used by Ethernet and zip, gzip, etc.  A software
+   version is provided as a fall-back, as well as for speed comparisons. */
+
+/* Version history:
+   1.0  10 Feb 2013  First version
+   1.1   1 Aug 2013  Correct comments on why three crc instructions in parallel
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* CRC-32C (iSCSI) polynomial in reversed bit order. */
+#define POLY 0x82f63b78
+
+/* Table for a quadword-at-a-time software crc. */
+static pthread_once_t crc32c_once_sw = PTHREAD_ONCE_INIT;
+static uint32_t crc32c_table[8][256];
+
+/* Construct table for software CRC-32C calculation. */
+static void crc32c_init_sw(void)
+{
+    uint32_t n, crc, k;
+
+    for (n = 0; n < 256; n++) {
+        crc = n;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
+        crc32c_table[0][n] = crc;
+    }
+    for (n = 0; n < 256; n++) {
+        crc = crc32c_table[0][n];
+        for (k = 1; k < 8; k++) {
+            crc = crc32c_table[0][crc & 0xff] ^ (crc >> 8);
+            crc32c_table[k][n] = crc;
+        }
+    }
+}
+
+/* Table-driven software version as a fall-back.  This is about 15 times slower
+   than using the hardware instructions.  This assumes little-endian integers,
+   as is the case on Intel processors that the assembler code here is for. */
+static uint32_t crc32c_sw(uint32_t crci, const void *buf, size_t len)
+{
+    const unsigned char *next = buf;
+    uint64_t crc;
+
+    pthread_once(&crc32c_once_sw, crc32c_init_sw);
+    crc = crci ^ 0xffffffff;
+    while (len && ((uintptr_t)next & 7) != 0) {
+        crc = crc32c_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
+        len--;
+    }
+    while (len >= 8) {
+        crc ^= *(uint64_t *)next;
+        crc = crc32c_table[7][crc & 0xff] ^
+              crc32c_table[6][(crc >> 8) & 0xff] ^
+              crc32c_table[5][(crc >> 16) & 0xff] ^
+              crc32c_table[4][(crc >> 24) & 0xff] ^
+              crc32c_table[3][(crc >> 32) & 0xff] ^
+              crc32c_table[2][(crc >> 40) & 0xff] ^
+              crc32c_table[1][(crc >> 48) & 0xff] ^
+              crc32c_table[0][crc >> 56];
+        next += 8;
+        len -= 8;
+    }
+    while (len) {
+        crc = crc32c_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
+        len--;
+    }
+    return (uint32_t)crc ^ 0xffffffff;
+}
+
+/* Multiply a matrix times a vector over the Galois field of two elements,
+   GF(2).  Each element is a bit in an unsigned integer.  mat must have at
+   least as many entries as the power of two for most significant one bit in
+   vec. */
+static inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec)
+{
+    uint32_t sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* Multiply a matrix by itself over GF(2).  Both mat and square must have 32
+   rows. */
+static inline void gf2_matrix_square(uint32_t *square, uint32_t *mat)
+{
+    int n;
+
+    for (n = 0; n < 32; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* Construct an operator to apply len zeros to a crc.  len must be a power of
+   two.  If len is not a power of two, then the result is the same as for the
+   largest power of two less than len.  The result for len == 0 is the same as
+   for len == 1.  A version of this routine could be easily written for any
+   len, but that is not needed for this application. */
+static void crc32c_zeros_op(uint32_t *even, size_t len)
+{
+    int n;
+    uint32_t row;
+    uint32_t odd[32];       /* odd-power-of-two zeros operator */
+
+    /* put operator for one zero bit in odd */
+    odd[0] = POLY;              /* CRC-32C polynomial */
+    row = 1;
+    for (n = 1; n < 32; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* first square will put the operator for one zero byte (eight zero bits),
+       in even -- next square puts operator for two zero bytes in odd, and so
+       on, until len has been rotated down to zero */
+    do {
+        gf2_matrix_square(even, odd);
+        len >>= 1;
+        if (len == 0)
+            return;
+        gf2_matrix_square(odd, even);
+        len >>= 1;
+    } while (len);
+
+    /* answer ended up in odd -- copy to even */
+    for (n = 0; n < 32; n++)
+        even[n] = odd[n];
+}
+
+/* Take a length and build four lookup tables for applying the zeros operator
+   for that length, byte-by-byte on the operand. */
+static void crc32c_zeros(uint32_t zeros[][256], size_t len)
+{
+    uint32_t n;
+    uint32_t op[32];
+
+    crc32c_zeros_op(op, len);
+    for (n = 0; n < 256; n++) {
+        zeros[0][n] = gf2_matrix_times(op, n);
+        zeros[1][n] = gf2_matrix_times(op, n << 8);
+        zeros[2][n] = gf2_matrix_times(op, n << 16);
+        zeros[3][n] = gf2_matrix_times(op, n << 24);
+    }
+}
+
+/* Apply the zeros operator table to crc. */
+static inline uint32_t crc32c_shift(uint32_t zeros[][256], uint32_t crc)
+{
+    return zeros[0][crc & 0xff] ^ zeros[1][(crc >> 8) & 0xff] ^
+           zeros[2][(crc >> 16) & 0xff] ^ zeros[3][crc >> 24];
+}
+
+/* Block sizes for three-way parallel crc computation.  LONG and SHORT must
+   both be powers of two.  The associated string constants must be set
+   accordingly, for use in constructing the assembler instructions. */
+#define LONG 8192
+#define LONGx1 "8192"
+#define LONGx2 "16384"
+#define SHORT 256
+#define SHORTx1 "256"
+#define SHORTx2 "512"
+
+/* Tables for hardware crc that shift a crc by LONG and SHORT zeros. */
+static pthread_once_t crc32c_once_hw = PTHREAD_ONCE_INIT;
+static uint32_t crc32c_long[4][256];
+static uint32_t crc32c_short[4][256];
+
+/* Initialize tables for shifting crcs. */
+static void crc32c_init_hw(void)
+{
+    crc32c_zeros(crc32c_long, LONG);
+    crc32c_zeros(crc32c_short, SHORT);
+}
+
+/* Compute CRC-32C using the Intel hardware instruction. */
+static uint32_t crc32c_hw(uint32_t crc, const void *buf, size_t len)
+{
+    const unsigned char *next = buf;
+    const unsigned char *end;
+    uint64_t crc0, crc1, crc2;      /* need to be 64 bits for crc32q */
+
+    /* populate shift tables the first time through */
+    pthread_once(&crc32c_once_hw, crc32c_init_hw);
+
+    /* pre-process the crc */
+    crc0 = crc ^ 0xffffffff;
+
+    /* compute the crc for up to seven leading bytes to bring the data pointer
+       to an eight-byte boundary */
+    while (len && ((uintptr_t)next & 7) != 0) {
+        __asm__("crc32b\t" "(%1), %0"
+                : "=r"(crc0)
+                : "r"(next), "0"(crc0));
+        next++;
+        len--;
+    }
+
+    /* compute the crc on sets of LONG*3 bytes, executing three independent crc
+       instructions, each on LONG bytes -- this is optimized for the Nehalem,
+       Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a
+       throughput of one crc per cycle, but a latency of three cycles */
+    while (len >= LONG*3) {
+        crc1 = 0;
+        crc2 = 0;
+        end = next + LONG;
+        do {
+            __asm__("crc32q\t" "(%3), %0\n\t"
+                    "crc32q\t" LONGx1 "(%3), %1\n\t"
+                    "crc32q\t" LONGx2 "(%3), %2"
+                    : "=r"(crc0), "=r"(crc1), "=r"(crc2)
+                    : "r"(next), "0"(crc0), "1"(crc1), "2"(crc2));
+            next += 8;
+        } while (next < end);
+        crc0 = crc32c_shift(crc32c_long, crc0) ^ crc1;
+        crc0 = crc32c_shift(crc32c_long, crc0) ^ crc2;
+        next += LONG*2;
+        len -= LONG*3;
+    }
+
+    /* do the same thing, but now on SHORT*3 blocks for the remaining data less
+       than a LONG*3 block */
+    while (len >= SHORT*3) {
+        crc1 = 0;
+        crc2 = 0;
+        end = next + SHORT;
+        do {
+            __asm__("crc32q\t" "(%3), %0\n\t"
+                    "crc32q\t" SHORTx1 "(%3), %1\n\t"
+                    "crc32q\t" SHORTx2 "(%3), %2"
+                    : "=r"(crc0), "=r"(crc1), "=r"(crc2)
+                    : "r"(next), "0"(crc0), "1"(crc1), "2"(crc2));
+            next += 8;
+        } while (next < end);
+        crc0 = crc32c_shift(crc32c_short, crc0) ^ crc1;
+        crc0 = crc32c_shift(crc32c_short, crc0) ^ crc2;
+        next += SHORT*2;
+        len -= SHORT*3;
+    }
+
+    /* compute the crc on the remaining eight-byte units less than a SHORT*3
+       block */
+    end = next + (len - (len & 7));
+    while (next < end) {
+        __asm__("crc32q\t" "(%1), %0"
+                : "=r"(crc0)
+                : "r"(next), "0"(crc0));
+        next += 8;
+    }
+    len &= 7;
+
+    /* compute the crc for up to seven trailing bytes */
+    while (len) {
+        __asm__("crc32b\t" "(%1), %0"
+                : "=r"(crc0)
+                : "r"(next), "0"(crc0));
+        next++;
+        len--;
+    }
+
+    /* return a post-processed crc */
+    return (uint32_t)crc0 ^ 0xffffffff;
+}
+
+/* Check for SSE 4.2.  SSE 4.2 was first supported in Nehalem processors
+   introduced in November, 2008.  This does not check for the existence of the
+   cpuid instruction itself, which was introduced on the 486SL in 1992, so this
+   will fail on earlier x86 processors.  cpuid works on all Pentium and later
+   processors. */
+#define SSE42(have) \
+    do { \
+        uint32_t eax, ecx; \
+        eax = 1; \
+        __asm__("cpuid" \
+                : "=c"(ecx) \
+                : "a"(eax) \
+                : "%ebx", "%edx"); \
+        (have) = (ecx >> 20) & 1; \
+    } while (0)
+
+/* Compute a CRC-32C.  If the crc32 instruction is available, use the hardware
+   version.  Otherwise, use the software version. */
+uint32_t crc32c(uint32_t crc, const void *buf, size_t len)
+{
+    int sse42;
+
+    SSE42(sse42);
+    return sse42 ? crc32c_hw(crc, buf, len) : crc32c_sw(crc, buf, len);
+}
+
+#ifdef TEST
+
+#define SIZE (262144*3)
+#define CHUNK SIZE
+
+int main(int argc, char **argv)
+{
+    char *buf;
+    ssize_t got;
+    size_t off, n;
+    uint32_t crc;
+
+    (void)argv;
+    crc = 0;
+    buf = malloc(SIZE);
+    if (buf == NULL) {
+        fputs("out of memory", stderr);
+        return 1;
+    }
+    while ((got = read(0, buf, SIZE)) > 0) {
+        off = 0;
+        do {
+            n = (size_t)got - off;
+            if (n > CHUNK)
+                n = CHUNK;
+            crc = argc > 1 ? crc32c_sw(crc, buf + off, n) :
+                             crc32c(crc, buf + off, n);
+            off += n;
+        } while (off < (size_t)got);
+    }
+    free(buf);
+    if (got == -1) {
+        fputs("read error\n", stderr);
+        return 1;
+    }
+    printf("%08x\n", crc);
+    return 0;
+}
+
+#endif /* TEST */

From 2fd8293263779185e411e5f4275bfd70d4d7b719 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 3 Jun 2017 14:43:42 +0200
Subject: [PATCH 0485/2207] lb: understand GRE

---
 apps/lb/pkt_hash.c | 40 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index 8fb893ce5..a6f9c0f19 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -138,6 +138,7 @@ sym_hash_fn(uint32_t sip, uint32_t dip, uint16_t sp, uint32_t dp)
 
 	return rc;
 }
+static uint32_t decode_gre_hash(const uint8_t *, uint8_t, uint8_t);
 /*---------------------------------------------------------------------*/
 /**
  ** Parser + hash function for the IPv4 packet
@@ -176,8 +177,11 @@ decode_ip_n_hash(struct ip *iph, uint8_t hash_split, uint8_t seed)
 			rc = decode_ip_n_hash((struct ip *)((uint8_t *)iph + (iph->ip_hl<<2)),
 					      hash_split, seed);
 			break;
-		case IPPROTO_ICMP:
 		case IPPROTO_GRE:
+			rc = decode_gre_hash((uint8_t *)iph + (iph->ip_hl<<2),
+					hash_split, seed);
+			break;
+		case IPPROTO_ICMP:
 		case IPPROTO_ESP:
 		case IPPROTO_PIM:
 		case IPPROTO_IGMP:
@@ -249,8 +253,10 @@ decode_ipv6_n_hash(struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
 			rc = decode_ipv6_n_hash((struct ip6_hdr *)(ipv6h + 1),
 						hash_split, seed);
 			break;
-		case IPPROTO_ICMP:
 		case IPPROTO_GRE:
+			rc = decode_gre_hash((uint8_t *)(ipv6h + 1), hash_split, seed);
+			break;
+		case IPPROTO_ICMP:
 		case IPPROTO_ESP:
 		case IPPROTO_PIM:
 		case IPPROTO_IGMP:
@@ -320,6 +326,7 @@ decode_vlan_n_hash(struct ether_header *ethh, uint8_t hash_split, uint8_t seed)
 	}
 	return rc;
 }
+
 /*---------------------------------------------------------------------*/
 /**
  ** General parser + hash function...
@@ -351,5 +358,34 @@ pkt_hdr_hash(const unsigned char *buffer, uint8_t hash_split, uint8_t seed)
 
 	return rc;
 }
+
+/*---------------------------------------------------------------------*/
+/**
+ ** Parser + hash function for the GRE packet
+ **/
+static uint32_t
+decode_gre_hash(const uint8_t *grehdr, uint8_t hash_split, uint8_t seed)
+{
+	int rc = 0;
+	int len = 4 + 2 * (!!(*grehdr & 1) + /* Checksum */
+			   !!(*grehdr & 4) + /* Key */
+			   !!(*grehdr & 8)); /* Sequence Number */
+	uint16_t proto = ntohs(*(uint16_t *)(void *)(grehdr + 2));
+
+	switch (proto) {
+	case ETHERTYPE_IP:
+		rc = decode_ip_n_hash((struct ip *)(grehdr + len),
+				      hash_split, seed);
+		break;
+	case ETHERTYPE_IPV6:
+		rc = decode_ipv6_n_hash((struct ip6_hdr *)(grehdr + len),
+					hash_split, seed);
+		break;
+	default:
+		/* others */
+		break;
+	}
+	return rc;
+}
 /*---------------------------------------------------------------------*/
 

From ca84e1def804ef8e6418250470481af51b10bd62 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 5 Jun 2017 11:57:06 +0200
Subject: [PATCH 0486/2207] LINUX: ixgbe: implement nm_config callback

---
 LINUX/ixgbe_netmap_linux.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 9c5a03b16..7b039a133 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -734,6 +734,19 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 	return ret;
 }
 
+static int
+ixgbe_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
+		    u_int *rxr, u_int *rxd)
+{
+	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(na->ifp);
+
+	*txr = adapter->num_tx_queues;
+	*rxr = adapter->num_rx_queues;
+	*txd = NM_IXGBE_TX_RING(adapter, 0)->count;
+	*rxd = NM_IXGBE_RX_RING(adapter, 0)->count;
+
+	return 0;
+}
 
 static void ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter);
 /*
@@ -772,6 +785,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.nm_register = ixgbe_netmap_reg;
 	na.nm_krings_create = ixgbe_netmap_krings_create;
 	na.nm_krings_delete = ixgbe_netmap_krings_delete;
+	na.nm_config = ixgbe_netmap_config;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
 	na.nm_intr = ixgbe_netmap_intr;

From df60b767721b2e96a1e1dfa3c6c72b955f55b714 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 5 Jun 2017 12:03:52 +0200
Subject: [PATCH 0487/2207] LINUX: warn user against possible wrong number of
 RX queues

---
 LINUX/netmap_linux.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index db376b065..b14e899fc 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -862,9 +862,13 @@ nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
 	} else
 #endif /* HAVE_SET_CHANNELS */
 	{
-		*txq = *rxq = ifp->real_num_tx_queues;
+		*txq = ifp->real_num_tx_queues;
 #if defined(NETMAP_LINUX_HAVE_REAL_NUM_RX_QUEUES)
 		*rxq = ifp->real_num_rx_queues;
+#else
+		*rxq = 1;
+		nm_prinf("WARNING: netmap will use only the first "
+			 "RX queue of %s\n", ifp->name);
 #endif /* HAVE_REAL_NUM_RX_QUEUES */
 	}
 }

From 56d8985e0f94e2253b06323b37774e37f076c1f6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 9 Jun 2017 17:06:06 +0200
Subject: [PATCH 0488/2207] lb: GRE: added missing routing-bit check

---
 apps/lb/pkt_hash.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index a6f9c0f19..916b94c18 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -368,6 +368,7 @@ decode_gre_hash(const uint8_t *grehdr, uint8_t hash_split, uint8_t seed)
 {
 	int rc = 0;
 	int len = 4 + 2 * (!!(*grehdr & 1) + /* Checksum */
+			   !!(*grehdr & 2) + /* Routing */
 			   !!(*grehdr & 4) + /* Key */
 			   !!(*grehdr & 8)); /* Sequence Number */
 	uint16_t proto = ntohs(*(uint16_t *)(void *)(grehdr + 2));

From 47d804d08e430865107cd90b3fa3098e292315cd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 9 Jun 2017 17:08:45 +0200
Subject: [PATCH 0489/2207] lb: GRE: removed signed->unsigned conversion

---
 apps/lb/pkt_hash.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index 916b94c18..fce820025 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -334,7 +334,7 @@ decode_vlan_n_hash(struct ether_header *ethh, uint8_t hash_split, uint8_t seed)
 uint32_t
 pkt_hdr_hash(const unsigned char *buffer, uint8_t hash_split, uint8_t seed)
 {
-	int rc = 0;
+	uint32_t rc = 0;
 	struct ether_header *ethh = (struct ether_header *)buffer;
 
 	switch (ntohs(ethh->ether_type)) {
@@ -366,7 +366,7 @@ pkt_hdr_hash(const unsigned char *buffer, uint8_t hash_split, uint8_t seed)
 static uint32_t
 decode_gre_hash(const uint8_t *grehdr, uint8_t hash_split, uint8_t seed)
 {
-	int rc = 0;
+	uint32_t rc = 0;
 	int len = 4 + 2 * (!!(*grehdr & 1) + /* Checksum */
 			   !!(*grehdr & 2) + /* Routing */
 			   !!(*grehdr & 4) + /* Key */

From 3456a055923b0b972a73df13d835e606cb5ae30d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 9 Jun 2017 17:23:55 +0200
Subject: [PATCH 0490/2207] lb: GRE: understand Transparent Ethernet Bridging

---
 apps/lb/pkt_hash.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index fce820025..a05344220 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -382,6 +382,9 @@ decode_gre_hash(const uint8_t *grehdr, uint8_t hash_split, uint8_t seed)
 		rc = decode_ipv6_n_hash((struct ip6_hdr *)(grehdr + len),
 					hash_split, seed);
 		break;
+	case 0x6558: /* Transparent Ethernet Bridging */
+		rc = pkt_hdr_hash(grehdr + len, hash_split, seed);
+		break;
 	default:
 		/* others */
 		break;

From 61a9e9881d1a078e9bb4f9cf4d101e1ea7ddc1f5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 8 Feb 2018 17:43:31 +0100
Subject: [PATCH 0491/2207] linux/vmxnet3: patch for the vanilla driver

---
 .../vanilla--vmxnet3--31000--99999            | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 LINUX/final-patches/vanilla--vmxnet3--31000--99999

diff --git a/LINUX/final-patches/vanilla--vmxnet3--31000--99999 b/LINUX/final-patches/vanilla--vmxnet3--31000--99999
new file mode 100644
index 000000000..3909077a5
--- /dev/null
+++ b/LINUX/final-patches/vanilla--vmxnet3--31000--99999
@@ -0,0 +1,83 @@
+diff --git a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
+old mode 100644
+new mode 100755
+index b76f7dc..f87199a
+--- a/vmxnet3/vmxnet3_drv.c
++++ b/vmxnet3/vmxnet3_drv.c
+@@ -308,6 +308,11 @@ static u32 get_bitfield32(const __le32 *bitfield, u32 pos, u32 size)
+ #endif /* __BIG_ENDIAN_BITFIELD  */
+ 
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) || defined(DEV_NETMAP)
++#include "if_vmxnet3_netmap.h"
++#endif
++
++
+ static void
+ vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
+ 		     struct pci_dev *pdev)
+@@ -367,6 +372,14 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
+ 	int completed = 0;
+ 	union Vmxnet3_GenericDesc *gdesc;
+ 
++#ifdef DEV_NETMAP
++	struct net_device *netdev = adapter->netdev;
++
++	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
++		return 0;
++#endif
++		
++
+ 	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+ 	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
+ 		completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX(
+@@ -1164,6 +1177,15 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ 	struct Vmxnet3_RxDesc rxCmdDesc;
+ 	struct Vmxnet3_RxCompDesc rxComp;
+ #endif
++
++#ifdef DEV_NETMAP
++	u_int total_packets = 0;
++	struct net_device *netdev = adapter->netdev;
++	
++	if (netmap_rx_irq(netdev, 0, &total_packets) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
+ 			  &rxComp);
+ 	while (rcd->gen == rq->comp_ring.gen) {
+@@ -2262,6 +2284,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+ 		adapter->rx_queue[0].rx_ring[0].size,
+ 		adapter->rx_queue[0].rx_ring[1].size);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_init_buffers(adapter);
++#endif /* DEV_NETMAP */    
++
+ 	vmxnet3_tq_init_all(adapter);
+ 	err = vmxnet3_rq_init_all(adapter);
+ 	if (err) {
+@@ -3103,6 +3129,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
+ 		goto err_register;
+ 	}
+ 
++    
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_attach(adapter);
++#endif /* DEV_NETMAP */    
++
+ 	vmxnet3_check_link(adapter, false);
+ 	return 0;
+ 
+@@ -3154,6 +3185,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
+ 
+ 	unregister_netdev(netdev);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_detach(netdev);
++#endif /* DEV_NETMAP */    
++
+ 	vmxnet3_free_intr_resources(adapter);
+ 	vmxnet3_free_pci_resources(adapter);
+ #ifdef VMXNET3_RSS

From 64faa9afeb75d70db450a4d70def0d9bb4df6711 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 9 Feb 2018 17:32:14 +0100
Subject: [PATCH 0492/2207] bdg_ops inside struct nm_bridge is now a pointer,
 non-modified bridges point to a global static struct which holds the default
 callbacks

---
 sys/dev/netmap/netmap_vale.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 091cf0e4a..adc54d828 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -186,6 +186,9 @@ struct nm_hash_ent {
 	uint64_t	ports;
 };
 
+/* Holds the default callbacks */
+static struct netmap_bdg_ops default_bdg_ops = {netmap_bdg_learning, NULL, NULL};
+
 /*
  * nm_bridge is a descriptor for a VALE switch.
  * Interfaces for a bridge are all in bdg_ports[].
@@ -222,7 +225,7 @@ struct nm_bridge {
 	 * different ring index.
 	 * The function is set by netmap_bdg_regops().
 	 */
-	struct netmap_bdg_ops bdg_ops;
+	struct netmap_bdg_ops *bdg_ops;
 	
 	/*
 	 * Contains the data structure used by the bdg_ops.lookup function.
@@ -380,7 +383,7 @@ nm_find_bridge(const char *name, int create)
 		for (i = 0; i < NM_BDG_MAXPORTS; i++)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
-		b->bdg_ops.lookup = netmap_bdg_learning;
+		b->bdg_ops = &default_bdg_ops;
 		b->lookup_data = b->ht;
 		NM_BNS_GET(b);
 	}
@@ -496,8 +499,8 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	}
 
 	BDG_WLOCK(b);
-	if (b->bdg_ops.dtor)
-		b->bdg_ops.dtor(b->bdg_ports[s_hw]);
+	if (b->bdg_ops->dtor)
+		b->bdg_ops->dtor(b->bdg_ports[s_hw]);
 	b->bdg_ports[s_hw] = NULL;
 	if (s_sw >= 0) {
 		b->bdg_ports[s_sw] = NULL;
@@ -510,7 +513,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	if (lim == 0) {
 		ND("marking bridge %s as free", b->bdg_basename);
 		nm_os_free(b->ht);
-		bzero(&b->bdg_ops, sizeof(b->bdg_ops));
+		b->bdg_ops = NULL;
 		NM_BNS_PUT(b);
 	}
 }
@@ -1352,11 +1355,10 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup
 	} else {
 		if (!bdg_ops) {
 			bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-			bzero(&b->bdg_ops, sizeof(b->bdg_ops));
-			b->bdg_ops.lookup = netmap_bdg_learning;
+			b->bdg_ops = &default_bdg_ops;
 			b->lookup_data = b->ht;
 		} else {
-			b->bdg_ops = *bdg_ops;
+			b->bdg_ops = bdg_ops;
 			b->lookup_data = lookup_data;
 		}
 	}
@@ -1380,8 +1382,8 @@ netmap_bdg_config(struct nm_ifreq *nr)
 	NMG_UNLOCK();
 	/* Don't call config() with NMG_LOCK() held */
 	BDG_RLOCK(b);
-	if (b->bdg_ops.config != NULL)
-		error = b->bdg_ops.config(nr);
+	if (b->bdg_ops->config != NULL)
+		error = b->bdg_ops->config(nr);
 	BDG_RUNLOCK(b);
 	return error;
 }
@@ -1784,7 +1786,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		   fragment nor at the very beginning of the second. */
 		if (unlikely(na->up.virt_hdr_len > ft[i].ft_len))
 			continue;
-		dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na, b->lookup_data);
+		dst_port = b->bdg_ops->lookup(&ft[i], &dst_ring, na, b->lookup_data);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)

From 2e257494e549bce76d2d18f41dcd753a9168ca91 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 10 Feb 2018 11:27:15 +0100
Subject: [PATCH 0493/2207] freebsd: fix compilation issue introduced by
 r324446

---
 sys/dev/netmap/netmap_generic.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index b2f0227a7..08b8b1ee4 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -166,7 +166,13 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
  * has a KASSERT(), checking that the mbuf dtor function is not NULL.
  */
 
+#if __FreeBSD_version <= 1200050
 static void void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { }
+#else  /* __FreeBSD_version >= 1200051 */
+/* The arg1 and arg2 pointers argument were removed by r324446, which
+ * in included since version 1200051. */
+static void void_mbuf_dtor(struct mbuf *m) { }
+#endif /* __FreeBSD_version >= 1200051 */
 
 #define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
 	(m)->m_ext.ext_free = (fn != NULL) ?		\
@@ -624,7 +630,11 @@ generic_mbuf_destructor(struct mbuf *m)
 	 * txsync. */
 	netmap_generic_irq(na, r, NULL);
 #ifdef __FreeBSD__
+#if __FreeBSD_version <= 1200050
 	void_mbuf_dtor(m, NULL, NULL);
+#else  /* __FreeBSD_version >= 1200051 */
+	void_mbuf_dtor(m);
+#endif /* __FreeBSD_version >= 1200051 */
 #endif
 }
 

From 06c7757cdbac834f80a217d49607c6ab9072055a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 10 Feb 2018 12:27:43 +0100
Subject: [PATCH 0494/2207] linux: ixgbe: use IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT
 macro instead of "2"

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 9c5a03b16..1836b05c3 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -127,7 +127,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
 		reg_idx &= mask;
 	}
-	srrctl = IXGBE_RX_HDR_SIZE << 2;
+	srrctl = IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT;
 	srrctl |= NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
 	D("bufsz: %d srrctl: %d", NETMAP_BUF_SIZE(na),
 		NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);

From e2b6de9c3b25f0f09e8a31479880201138f5d3ce Mon Sep 17 00:00:00 2001
From: Dirk HOFFMANN 
Date: Mon, 12 Feb 2018 12:06:50 +0100
Subject: [PATCH 0495/2207] _BSD_SOURCE is already defined in
 /usr/include/features.h (CentOS 7.4)

---
 apps/dedup/dedup.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/apps/dedup/dedup.h b/apps/dedup/dedup.h
index 31b34cadf..d8e7d88e3 100644
--- a/apps/dedup/dedup.h
+++ b/apps/dedup/dedup.h
@@ -1,7 +1,9 @@
 #ifndef DEDUP_H_
 #define DEDUP_H_
 
+#ifndef _BSD_SOURCE
 #define _BSD_SOURCE
+#endif
 #include 
 #include 
 

From 1df8b0e691a8ba27827d262d45d03b72a2e09278 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 12 Feb 2018 17:07:05 +0100
Subject: [PATCH 0496/2207] nm_bdg_ctl_attach and nm_bdg_ctl_detach exported to
 allow external modules to create ephemeral VALE ports

---
 LINUX/netmap_linux.c         |  4 +++-
 sys/dev/netmap/netmap_vale.c | 15 +++++++--------
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 8be1ecc85..eb34b3f45 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2445,8 +2445,10 @@ EXPORT_SYMBOL(netmap_rx_irq);	        /* default irq handler */
 EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 #ifdef WITH_VALE
 EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
-EXPORT_SYMBOL(netmap_bdg_learning);	/* the default lookup function */
+//EXPORT_SYMBOL(netmap_bdg_learning);	/* the default lookup function */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
+EXPORT_SYMBOL(nm_bdg_ctl_attach);
+EXPORT_SYMBOL(nm_bdg_ctl_detach);
 #endif /* WITH_VALE */
 EXPORT_SYMBOL(netmap_disable_all_rings);
 EXPORT_SYMBOL(netmap_enable_all_rings);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index adc54d828..028904eee 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1352,15 +1352,14 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup
 	b = nm_find_bridge(name, 0 /* don't create */);
 	if (!b) {
 		error = EINVAL;
+	} else if (!bdg_ops) {
+		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+		b->bdg_ops = &default_bdg_ops;
+		b->lookup_data = b->ht;
 	} else {
-		if (!bdg_ops) {
-			bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-			b->bdg_ops = &default_bdg_ops;
-			b->lookup_data = b->ht;
-		} else {
-			b->bdg_ops = bdg_ops;
-			b->lookup_data = lookup_data;
-		}
+		// TODO: check if another module has alredy changed the lookup functions
+		b->bdg_ops = bdg_ops;
+		b->lookup_data = lookup_data;
 	}
 	NMG_UNLOCK();
 

From f2e289ecbe2c6d19d1a485437e2bb970ce1402ca Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Feb 2018 14:11:46 +0100
Subject: [PATCH 0497/2207] pipe: multiple rings

---
 sys/dev/netmap/netmap_pipe.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index f18fa4b80..1b7c84478 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2016 Giuseppe Lettieri
+ * Copyright (C) 2014-2018 Giuseppe Lettieri
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,7 @@
 #ifdef WITH_PIPES
 
 #define NM_PIPE_MAXSLOTS	4096
+#define NM_PIPE_MAXRINGS	256
 
 static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
 SYSBEGIN(vars_pipes);
@@ -564,11 +565,6 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		 * is missing. */
 		return EINVAL;
 	}
-	if (req->nr_mode != NR_REG_ALL_NIC || req->nr_ringid != 0) {
-		/* Currently we only support opening all the hw rings of
-		 * a pipe. */
-		return EINVAL;
-	}
 
 	/* first, try to find the parent adapter */
 	for (;;) {
@@ -655,8 +651,12 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	mna->up.na_flags |= NAF_MEM_OWNER;
 	mna->up.na_lut = pna->na_lut;
 
-	mna->up.num_tx_rings = 1;
-	mna->up.num_rx_rings = 1;
+	mna->up.num_tx_rings = req->nr_tx_rings;
+	nm_bound_var(&mna->up.num_tx_rings, 1,
+			1, NM_PIPE_MAXRINGS, NULL);
+	mna->up.num_rx_rings = req->nr_rx_rings;
+	nm_bound_var(&mna->up.num_rx_rings, 1,
+			1, NM_PIPE_MAXRINGS, NULL);
 	mna->up.num_tx_desc = req->nr_tx_slots;
 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
 			1, NM_PIPE_MAXSLOTS, NULL);
@@ -680,6 +680,9 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* most fields are the same, copy from master and then fix */
 	*sna = *mna;
 	sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
+	/* swap the number of tx/rx rings */
+	sna->up.num_tx_rings = mna->up.num_rx_rings;
+	sna->up.num_rx_rings = mna->up.num_tx_rings;
 	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
 	sna->role = NM_PIPE_ROLE_SLAVE;
 	error = netmap_attach_common(&sna->up);

From a62cc9102190dcbb0170f69e4fb59dc2a82937a9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 13 Feb 2018 18:24:52 +0100
Subject: [PATCH 0498/2207] extmem: remove obsolete userspace support

---
 apps/pkt-gen/pkt-gen.c |   2 +-
 sys/net/netmap_user.h  | 301 ++++++++---------------------------------
 2 files changed, 55 insertions(+), 248 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d07f6daa2..f48a17c96 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2953,7 +2953,7 @@ main(int arc, char **argv)
 	 * reconfigure. We do the open here to have time to reset.
 	 */
 	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
-		NM_OPEN_ARG3 | NM_OPEN_EXTMEM | NM_OPEN_RING_CFG;
+		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
 	if (g.nthreads > 1) {
 		base_nmd.req.nr_flags &= ~NR_REG_MASK;
 		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 9b81abf60..5074b0b60 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -98,7 +98,6 @@
 #endif /* likely and unlikely */
 
 #include 
-#include  /* nmreq_pointer_get() */
 
 /* helper macro */
 #define _NETMAP_OFFSET(type, ptr, offset) \
@@ -113,7 +112,7 @@
 	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
 
 #define NETMAP_BUF(ring, index)				\
-	((char *)(ring) + (ring)->buf_ofs + ((long)(index)*(ring)->nr_buf_size))
+	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
 
 #define NETMAP_BUF_IDX(ring, buf)			\
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
@@ -223,7 +222,7 @@ struct nm_desc {
 	struct nm_desc *self; /* point to self if netmap. */
 	int fd;
 	void *mem;
-	uint64_t memsize;
+	uint32_t memsize;
 	int done_mmap;	/* set if mem is the result of mmap */
 	struct netmap_if * const nifp;
 	uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;
@@ -280,7 +279,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024 || (l % 64))) {
+	if (unlikely(l >= 1024)) {
 		memcpy(dst, src, l);
 		return;
 	}
@@ -351,7 +350,6 @@ enum {
 	NM_OPEN_ARG2 =		0x200000,
 	NM_OPEN_ARG3 =		0x400000,
 	NM_OPEN_RING_CFG =	0x800000, /* tx|rx rings|slots */
-	NM_OPEN_EXTMEM =       0x1000000,
 };
 
 
@@ -613,28 +611,9 @@ nm_is_identifier(const char *s, const char *e)
 	return 1;
 }
 
-static void
-nm_init_offsets(struct nm_desc *d)
-{
-	struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
-	struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
-	if ((void *)r == (void *)nifp) {
-		/* the descriptor is open for TX only */
-		r = NETMAP_TXRING(nifp, d->first_tx_ring);
-	}
-
-	*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
-	*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
-	*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
-	*(void **)(uintptr_t)&d->buf_end =
-		(char *)d->mem + d->memsize;
-}
-
 #define MAXERRMSG 80
-#define NM_PARSE_OK	  	0
-#define NM_PARSE_MEMID 		1
 static int
-nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
+nm_parse(const char *ifname, struct nm_desc *d, char *err)
 {
 	int is_vale;
 	const char *port = NULL;
@@ -648,13 +627,6 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 
 	errno = 0;
 
-	if (strncmp(ifname, "netmap:", 7) &&
-			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
-		snprintf(errmsg, MAXERRMSG, "invalid port name: %s", ifname);
-		errno = EINVAL;
-		goto fail;
-	}
-
 	is_vale = (ifname[0] == 'v');
 	if (is_vale) {
 		port = index(ifname, ':');
@@ -685,13 +657,12 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 	}
 
 	namelen = port - ifname;
-	if (namelen >= sizeof(d->nr_name)) {
+	if (namelen >= sizeof(d->req.nr_name)) {
 		snprintf(errmsg, MAXERRMSG, "name too long");
 		goto fail;
 	}
-	memcpy(d->nr_name, ifname, namelen);
-	d->nr_name[namelen] = '\0';
-	D("name %s", d->nr_name);
+	memcpy(d->req.nr_name, ifname, namelen);
+	d->req.nr_name[namelen] = '\0';
 
 	p_state = P_START;
 	nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
@@ -789,28 +760,21 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 			p_state = P_FLAGSOK;
 			break;
 		case P_MEMID:
-			if (!memid_allowed) {
+			if (nr_arg2 != 0) {
 				snprintf(errmsg, MAXERRMSG, "double setting of memid");
 				goto fail;
 			}
 			num = strtol(port, (char **)&port, 10);
 			if (num <= 0) {
-				ND("non-numeric memid %s (out = %p)", port, out);
-				if (out == NULL)
-					goto fail;
-				*out = (char *)port;
-				while (*port)
-					port++;
-			} else {
-				nr_arg2 = num;
-				memid_allowed = 0;
-				p_state = P_RNGSFXOK;
+				snprintf(errmsg, MAXERRMSG, "invalid memid %ld, must be >0", num);
+				goto fail;
 			}
+			nr_arg2 = num;
+			p_state = P_RNGSFXOK;
 			break;
 		}
 	}
-	if (p_state != P_START && p_state != P_RNGSFXOK &&
-	    p_state != P_FLAGSOK && p_state != P_MEMID) {
+	if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) {
 		snprintf(errmsg, MAXERRMSG, "unexpected end of port name");
 		goto fail;
 	}
@@ -820,124 +784,28 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
 			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
 
-	d->nr_flags |= nr_flags;
-	d->nr_ringid |= nr_ringid;
-	d->nr_arg2 = nr_arg2;
+	d->req.nr_flags |= nr_flags;
+	d->req.nr_ringid |= nr_ringid;
+	d->req.nr_arg2 = nr_arg2;
+
+	d->self = d;
 
-	return (p_state == P_MEMID) ? NM_PARSE_MEMID : NM_PARSE_OK;
+	return 0;
 fail:
 	if (!errno)
 		errno = EINVAL;
-	if (out)
-		*out = strdup(errmsg);
+	if (err)
+		strncpy(err, errmsg, MAXERRMSG);
 	return -1;
 }
 
-static int
-nm_interp_memid(const char *memid, struct nmreq *req, char **err)
-{
-#if 0
-	int fd = -1;
-	char errmsg[MAXERRMSG] = "";
-	struct nmreq greq;
-	off_t mapsize;
-	struct netmap_pools_info *pi;
-
-	/* first, try to look for a netmap port with this name */
-	fd = open("/dev/netmap", O_RDONLY);
-	if (fd < 0) {
-		snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno));
-		goto fail;
-	}
-	memset(&greq, 0, sizeof(greq));
-	if (nm_parse_one(memid, &greq, err, 0) == NM_PARSE_OK) {
-		greq.nr_version = NETMAP_API;
-		if (ioctl(fd, NIOCGINFO, &greq) < 0) {
-			if (errno == ENOENT || errno == ENXIO)
-				goto try_external;
-			snprintf(errmsg, MAXERRMSG, "cannot getinfo for %s: %s", memid, strerror(errno));
-			goto fail;
-		}
-		req->nr_arg2 = greq.nr_arg2;
-		close(fd);
-		return 0;
-	}
-try_external:
-	D("trying with external memory");
-	close(fd);
-	fd = open(memid, O_RDWR);
-	if (fd < 0) {
-		snprintf(errmsg, MAXERRMSG, "cannot open %s: %s", memid, strerror(errno));
-		goto fail;
-	}
-	mapsize = lseek(fd, 0, SEEK_END);
-	if (mapsize < 0) {
-		snprintf(errmsg, MAXERRMSG, "failed to obtain filesize of %s: %s", memid, strerror(errno));
-		goto fail;
-	}
-	pi = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-	if (pi == MAP_FAILED) {
-		snprintf(errmsg, MAXERRMSG, "cannot map %s: %s", memid, strerror(errno));
-		goto fail;
-	}
-	req->nr_cmd = NETMAP_POOLS_CREATE;
-	pi->memsize = mapsize;
-	nmreq_pointer_put(req, pi);
-	D("mapped %zu bytes at %p from file %s", mapsize, pi, memid);
-	return 0;
-
-fail:
-	D("%s", errmsg);
-	close(fd);
-	if (err && !*err)
-		*err = strdup(errmsg);
-	return errno;
-#else
-	(void)memid;
-	(void)req;
-	(void)err;
-	return EOPNOTSUPP;
-#endif
-}
-
-static int
-nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
-{
-	char *err;
-	switch (nm_parse_one(ifname, &d->req, &err, 1)) {
-	case NM_PARSE_OK:
-		D("parse OK");
-		break;
-	case NM_PARSE_MEMID:
-		D("memid: %s", err);
-		errno = nm_interp_memid(err, &d->req, &err);
-		D("errno = %d", errno);
-		if (!errno)
-			break;
-		/* fallthrough */
-	default:
-		D("error");
-		strncpy(errmsg, err, MAXERRMSG);
-		errmsg[MAXERRMSG-1] = '\0';
-		free(err);
-		return -1;
-	}
-	D("parsed name: %s", d->req.nr_name);
-	d->self = d;
-	return 0;
-}
-
 /*
  * Try to open, return descriptor if successful, NULL otherwise.
  * An invalid netmap name will return errno = 0;
  * You can pass a pointer to a pre-filled nm_desc to add special
  * parameters. Flags is used as follows
- * NM_OPEN_NO_MMAP	use the memory from arg, only
+ * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
  *			if the nr_arg2 (memory block) matches.
- *			Special case: if arg is NULL, skip the
- *			mmap entirely (maybe because you are going
- *			to do it by yourself, or you plan to call
- *			nm_mmap() only later)
  * NM_OPEN_ARG1		use req.nr_arg1 from arg
  * NM_OPEN_ARG2		use req.nr_arg2 from arg
  * NM_OPEN_RING_CFG	user ring config from arg
@@ -950,7 +818,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 	const struct nm_desc *parent = arg;
 	char errmsg[MAXERRMSG] = "";
 	uint32_t nr_reg;
-	struct nmreq_pools_info *pi = NULL;
 
 	if (strncmp(ifname, "netmap:", 7) &&
 			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@@ -971,91 +838,31 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
-	if (req) {
+	if (req)
 		d->req = *req;
-	} else {
-		d->req.nr_arg1 = 4;
-		d->req.nr_arg2 = 0;
-		d->req.nr_arg3 = 0;
-	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
-		char *err = NULL;
-		switch (nm_parse_one(ifname, &d->req, &err, 1)) {
-		case NM_PARSE_OK:
-			break;
-		case NM_PARSE_MEMID:
-			if ((new_flags & NM_OPEN_NO_MMAP) &&
-					IS_NETMAP_DESC(parent)) {
-				/* ignore the memid setting, since we are
-				 * going to use the parent's one
-				 */
-				break;
-			}
-			errno = nm_interp_memid(err, &d->req, &err);
-			if (!errno)
-				break;
-			/* fallthrough */
-		default:
-			strncpy(errmsg, err, MAXERRMSG);
-			errmsg[MAXERRMSG-1] = '\0';
-			free(err);
+		if (nm_parse(ifname, d, errmsg) < 0)
 			goto fail;
-		}
-		d->self = d;
 	}
 
-#if 0
-	/* compatibility checks for POOL_SCREATE and NM_OPEN flags
-	 * the first check may be dropped once we have a larger nreq
-	 */
-	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-		if (IS_NETMAP_DESC(parent)) {
-		       	if (new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3)) {
-				snprintf(errmsg, MAXERRMSG,
-						"POOLS_CREATE is incompatibile "
-						"with NM_OPEN_ARG? flags");
-				errno = EINVAL;
-				goto fail;
-			}
-			if (new_flags & NM_OPEN_NO_MMAP) {
-				snprintf(errmsg, MAXERRMSG,
-						"POOLS_CREATE is incompatible "
-						"with NM_OPEN_NO_MMAP flag");
-				errno = EINVAL;
-				goto fail;
-			}
-		}
-	}
-#endif
-
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
-#if 0
-		if (new_flags & NM_OPEN_EXTMEM) {
-			if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
-				d->req.nr_cmd = NETMAP_POOLS_CREATE;
-				nmreq_pointer_put(&d->req, nmreq_pointer_get(&parent->req));
-				D("Warning: not overriding arg[1-3] since external memory is being used");
-				new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
-			}
-		}
-#endif
-		if (new_flags & NM_OPEN_ARG1) {
+		if (new_flags & NM_OPEN_ARG1)
 			D("overriding ARG1 %d", parent->req.nr_arg1);
-			d->req.nr_arg1 = parent->req.nr_arg1;
-		}
-		if (new_flags & (NM_OPEN_ARG2 | NM_OPEN_NO_MMAP)) {
+		d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
+			parent->req.nr_arg1 : 4;
+		if (new_flags & NM_OPEN_ARG2) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
-			d->req.nr_arg2 = parent->req.nr_arg2;
+			d->req.nr_arg2 =  parent->req.nr_arg2;
 		}
-		if (new_flags & NM_OPEN_ARG3) {
+		if (new_flags & NM_OPEN_ARG3)
 			D("overriding ARG3 %d", parent->req.nr_arg3);
-			d->req.nr_arg3 = parent->req.nr_arg3;
-		}
+		d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
+			parent->req.nr_arg3 : 0;
 		if (new_flags & NM_OPEN_RING_CFG) {
 			D("overriding RING_CFG");
 			d->req.nr_tx_slots = parent->req.nr_tx_slots;
@@ -1076,30 +883,11 @@ nm_open(const char *ifname, const struct nmreq *req,
 	/* add the *XPOLL flags */
 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
 
-#if 0
-	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-		pi = nmreq_pointer_get(&d->req);
-	}
-#endif
-
 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
 		goto fail;
 	}
 
-	if (pi != NULL) {
-		d->mem = pi;
-		d->memsize = pi->nr_memsize;
-		nm_init_offsets(d);
-	} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
-		/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
-	        errno = nm_mmap(d, parent);
-		if (errno) {
-			snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
-			goto fail;
-		}
-	}
-
 	nr_reg = d->req.nr_flags & NR_REG_MASK;
 
 	if (nr_reg == NR_REG_SW) { /* host stack */
@@ -1124,6 +912,13 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->first_rx_ring = d->last_rx_ring = 0;
 	}
 
+        /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
+	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
+	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
+		goto fail;
+	}
+
+
 #ifdef DEBUG_NETMAP_USER
     { /* debugging code */
 	int i;
@@ -1164,8 +959,7 @@ nm_close(struct nm_desc *d)
 	 */
 	static void *__xxzt[] __attribute__ ((unused))  =
 		{ (void *)nm_open, (void *)nm_inject,
-		  (void *)nm_dispatch, (void *)nm_nextpkt,
-	          (void *)nm_parse } ;
+		  (void *)nm_dispatch, (void *)nm_nextpkt } ;
 
 	if (d == NULL || d->self != d)
 		return EINVAL;
@@ -1202,8 +996,21 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 		}
 		d->done_mmap = 1;
 	}
+	{
+		struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
+		struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
+		if ((void *)r == (void *)nifp) {
+			/* the descriptor is open for TX only */
+			r = NETMAP_TXRING(nifp, d->first_tx_ring);
+		}
+
+		*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
+		*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
+		*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
+		*(void **)(uintptr_t)&d->buf_end =
+			(char *)d->mem + d->memsize;
+	}
 
-	nm_init_offsets(d);
 	return 0;
 
 fail:

From 54c70213a097889f465a592c3fec1291f8702787 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 14 Feb 2018 17:06:30 +0100
Subject: [PATCH 0499/2207] added port_index inside struct nmreq_vale_attach,
 after an attach request it will contain the index where the port has been
 attacched

---
 sys/dev/netmap/netmap_vale.c | 4 ++++
 sys/net/netmap.h             | 1 +
 2 files changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 028904eee..3a957b906 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -803,6 +803,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		/* shortcut - we can skip get_hw_na(),
 		 * ownership check and nm_bdg_attach()
 		 */
+
 	} else {
 		struct netmap_adapter *hw;
 
@@ -839,6 +840,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	}
 
 	BDG_WLOCK(b);
+	vpna->up.na_vp = vpna;	// TODO: check if this makes sense
 	vpna->bdg_port = cand;
 	ND("NIC  %p to bridge port %d", vpna, cand);
 	/* bind the port to the bridge (virtual ports are not active) */
@@ -877,6 +879,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 	int error;
 
 	NMG_LOCK();
+	req->port_index = NM_BDG_NOPORT;
 
 	if (req->reg.nr_mem_id) {
 		nmd = netmap_mem_find(req->reg.nr_mem_id);
@@ -909,6 +912,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
 	}
+	req->port_index = na->na_vp->bdg_port;
 	NMG_UNLOCK();
 	return 0;
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a1bcc06a9..07ce57d79 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -614,6 +614,7 @@ struct nmreq_port_info_get {
  */
 struct nmreq_vale_attach {
 	struct nmreq_register reg;
+	uint8_t port_index;
 };
 
 /*

From 3442494ab6c7fbce6b9efcc8fc14b35f8b9d4cc7 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 14 Feb 2018 22:23:05 +0100
Subject: [PATCH 0500/2207] vale: prevent attaching a port twice

---
 sys/dev/netmap/netmap_vale.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 5fb4dcbe6..b14f6a5c3 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -863,6 +863,12 @@ nm_bdg_ctl_attach(struct nmreq *nmr)
 		}
 	}
 
+	/* XXX check existing one */
+	error = netmap_get_bdg_na(nmr, &na, nmd, 0);
+	if (!error) {
+		error = EBUSY;
+		goto unref_exit;
+	}
 	error = netmap_get_bdg_na(nmr, &na, nmd, 1 /* create if not exists */);
 	if (error) /* no device */
 		goto unlock_exit;

From d004c95212afb73775dd3241422ddcf3271d1f88 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 15 Feb 2018 16:34:34 +0100
Subject: [PATCH 0501/2207] added struct nmreq_vale_detach;
 nm_bdg_ctl_detach(), nmreq_size_by_type() changed accordingly

---
 sys/dev/netmap/netmap.c      |  2 +-
 sys/dev/netmap/netmap_vale.c |  6 +++++-
 sys/net/netmap.h             | 11 +++++++++++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 198b4cbff..6195910cd 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2661,7 +2661,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_ATTACH:
 		return sizeof(struct nmreq_vale_attach);
 	case NETMAP_REQ_VALE_DETACH:
-		return 0;
+		return sizeof(struct nmreq_vale_detach);
 	case NETMAP_REQ_VALE_LIST:
 		return sizeof(struct nmreq_vale_list);
 	case NETMAP_REQ_PORT_HDR_SET:
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3a957b906..54787f8fd 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -840,7 +840,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	}
 
 	BDG_WLOCK(b);
-	vpna->up.na_vp = vpna;	// TODO: check if this makes sense
+	//vpna->up.na_vp = vpna // TODO: should be moved inside netmap_bwrap_bdg_ctl() ?
 	vpna->bdg_port = cand;
 	ND("NIC  %p to bridge port %d", vpna, cand);
 	/* bind the port to the bridge (virtual ports are not active) */
@@ -933,6 +933,7 @@ nm_is_bwrap(struct netmap_adapter *na)
 int
 nm_bdg_ctl_detach(struct nmreq_header *hdr)
 {
+	struct nmreq_vale_detach *nmreq_det = hdr->nr_body;
 	struct netmap_adapter *na;
 	int error;
 
@@ -952,6 +953,9 @@ nm_bdg_ctl_detach(struct nmreq_header *hdr)
 		netmap_adapter_put(na);
 		goto unlock_exit;
 	}
+
+	nmreq_det->port_index = na->na_vp->bdg_port;
+
 	if (na->nm_bdg_ctl) {
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 07ce57d79..cadf8d25e 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -611,12 +611,23 @@ struct nmreq_port_info_get {
  * port and the VALE switch are specified through the nr_name argument.
  * The attach operation could need to register a port, so at least
  * the same arguments are available.
+ * port_index will contain the index where the port has been attached.
  */
 struct nmreq_vale_attach {
 	struct nmreq_register reg;
 	uint8_t port_index;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_DETACH
+ * Detach a netmap port from a VALE switch. Both the name of the netmap
+ * port and the VALE switch are specified through the nr_name argument.
+ * port_index will contain the index where the port was attached.
+ */
+struct nmreq_vale_detach {
+	uint8_t port_index;
+};
+
 /*
  * nr_reqtype: NETMAP_REQ_VALE_LIST
  * List the ports of a VALE switch.

From fbd24a94b7b9507f5a8468968bc6211adb408c41 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 14 Feb 2018 15:47:47 +0100
Subject: [PATCH 0502/2207] pkt-gen: better output on poll errors

---
 apps/pkt-gen/pkt-gen.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f48a17c96..03f36ed21 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1564,6 +1564,7 @@ sender_body(void *data)
 
 	nifp = targ->nmd->nifp;
 	while (!targ->cancel && (n == 0 || sent < n)) {
+		int rv;
 
 		if (rate_limit && tosend <= 0) {
 			tosend = targ->g->burst;
@@ -1575,17 +1576,18 @@ sender_body(void *data)
 		 * wait for available room in the send queue(s)
 		 */
 #ifdef BUSYWAIT
+		(void)rv;
 		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
 			D("ioctl error on queue %d: %s", targ->me,
 					strerror(errno));
 			goto quit;
 		}
 #else /* !BUSYWAIT */
-		if (poll(&pfd, 1, 2000) <= 0) {
+		if ( (rv = poll(&pfd, 1, 2000)) <= 0) {
 			if (targ->cancel)
 				break;
-			D("poll error/timeout on queue %d: %s", targ->me,
-				strerror(errno));
+			D("poll error on queue %d: %s", targ->me,
+				rv ? strerror(errno) : "timeout");
 			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {
@@ -1884,6 +1886,7 @@ txseq_body(void *data)
 		unsigned int head;
 		int fcnt;
 		uint16_t sum = 0;
+		int rv;
 
 		if (!rate_limit) {
 			budget = targ->g->burst;
@@ -1896,17 +1899,18 @@ txseq_body(void *data)
 
 		/* wait for available room in the send queue */
 #ifdef BUSYWAIT
+		(void)rv;
 		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
 			D("ioctl error on queue %d: %s", targ->me,
 					strerror(errno));
 			goto quit;
 		}
 #else /* !BUSYWAIT */
-		if (poll(&pfd, 1, 2000) <= 0) {
+		if ( (rv = poll(&pfd, 1, 2000)) <= 0) {
 			if (targ->cancel)
 				break;
-			D("poll error/timeout on queue %d: %s", targ->me,
-				strerror(errno));
+			D("poll error on queue %d: %s", targ->me,
+				rv ? strerror(errno) : "timeout");
 			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {

From e48be2cfc887d466e8ab065c6506bee6178fde9c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 16 Feb 2018 14:21:36 +0100
Subject: [PATCH 0503/2207] newnmreq: only use arch-independent types in the
 ABI

---
 sys/dev/netmap/netmap.c        | 70 ++++++++++++++++++----------------
 sys/dev/netmap/netmap_legacy.c | 22 +++++------
 sys/net/netmap.h               |  6 +--
 3 files changed, 51 insertions(+), 47 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 198b4cbff..4f9126c9e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2391,10 +2391,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 					/* get a refcount */
 					hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-					hdr->nr_body = ®req;
+					hdr->nr_body = (uint64_t)®req;
 					error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
 					hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; /* reset type */
-					hdr->nr_body = req; /* reset nr_body */
+					hdr->nr_body = (uint64_t)req; /* reset nr_body */
 					if (error) {
 						na = NULL;
 						ifp = NULL;
@@ -2461,10 +2461,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			}
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
+			hdr->nr_body = (uint64_t)®req;
 			error = netmap_get_bdg_na(hdr, &na, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			if (na && !error) {
 				struct netmap_vp_adapter *vpna =
 					(struct netmap_vp_adapter *)na;
@@ -2493,10 +2493,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			bzero(®req, sizeof(regreq));
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
+			hdr->nr_body = (uint64_t)®req;
 			error = netmap_get_na(hdr, &na, &ifp, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			if (na && !error) {
 				req->nr_hdr_len = na->virt_hdr_len;
 			}
@@ -2518,10 +2518,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			regreq.nr_rx_rings = req->nr_rx_rings;
 			regreq.nr_mem_id = req->nr_mem_id;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
+			hdr->nr_body = (uint64_t)®req;
 			error = netmap_vi_create(hdr, 0 /* no autodelete */);
 			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
                         /* Write back to the original struct. */
 			req->nr_tx_slots = regreq.nr_tx_slots;
 			req->nr_rx_slots = regreq.nr_rx_slots;
@@ -2707,7 +2707,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src;
 	struct nmreq_option buf;
-	void **ptrs;
+	uint64_t *ptrs;
 
 	if (hdr->nr_reserved)
 		return EINVAL;
@@ -2723,8 +2723,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		error = EMSGSIZE;
 		goto out_err;
 	}
-	if ((rqsz && hdr->nr_body == NULL) ||
-		(!rqsz && hdr->nr_body != NULL)) {
+	if ((rqsz && hdr->nr_body == (uint64_t)NULL) ||
+		(!rqsz && hdr->nr_body != (uint64_t)NULL)) {
 		/* Request body expected, but not found; or
 		 * request body found but unexpected. */
 		error = EINVAL;
@@ -2733,7 +2733,9 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 
 	bufsz = 2 * sizeof(void *) + rqsz;
 	optsz = 0;
-	for (src = hdr->nr_options; src; src = buf.nro_next) {
+	for (src = (struct nmreq_option *)hdr->nr_options; src;
+	     src = (struct nmreq_option *)buf.nro_next)
+	{
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)
 			goto out_err;
@@ -2754,27 +2756,27 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	p = ker;
 
 	/* make a copy of the user pointers */
-	ptrs = (void **)p;
+	ptrs = (uint64_t*)p;
 	*ptrs++ = hdr->nr_body;
 	*ptrs++ = hdr->nr_options;
 	p = (char *)ptrs;
 
 	/* copy the body */
-	error = copyin(hdr->nr_body, p, rqsz);
+	error = copyin((void *)hdr->nr_body, p, rqsz);
 	if (error)
 		goto out_restore;
 	/* overwrite the user pointer with the in-kernel one */
-	hdr->nr_body = p;
+	hdr->nr_body = (uint64_t)p;
 	p += rqsz;
 
 	/* copy the options */
-	next = &hdr->nr_options;
+	next = (struct nmreq_option **)&hdr->nr_options;
 	src = *next;
 	while (src) {
 		struct nmreq_option *opt;
 
 		/* copy the option header */
-		ptrs = (void **)p;
+		ptrs = (uint64_t *)p;
 		opt = (struct nmreq_option *)(ptrs + 1);
 		error = copyin(src, opt, sizeof(*src));
 		if (error)
@@ -2802,13 +2804,13 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		}
 
 		/* move to next option */
-		next = &opt->nro_next;
+		next = (struct nmreq_option **)&opt->nro_next;
 		src = *next;
 	}
 	return 0;
 
 out_restore:
-	ptrs = (void **)ker;
+	ptrs = (uint64_t *)ker;
 	hdr->nr_body = *ptrs++;
 	hdr->nr_options = *ptrs++;
 	hdr->nr_reserved = 0;
@@ -2821,8 +2823,8 @@ static int
 nmreq_copyout(struct nmreq_header *hdr, int rerror)
 {
 	struct nmreq_option *src, *dst;
-	void *ker = hdr->nr_body, *bufstart;
-	void **ptrs;
+	void *ker = (void *)hdr->nr_body, *bufstart;
+	uint64_t *ptrs;
 	size_t bodysz;
 	int error;
 
@@ -2830,16 +2832,16 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 		return rerror;
 
 	/* restore the user pointers in the header */
-	ptrs = (void **)ker - 2;
+	ptrs = (uint64_t *)ker - 2;
 	bufstart = ptrs;
 	hdr->nr_body = *ptrs++;
-	src = hdr->nr_options;
+	src = (struct nmreq_option *)hdr->nr_options;
 	hdr->nr_options = *ptrs;
 
 	if (!rerror) {
 		/* copy the body */
 		bodysz = nmreq_size_by_type(hdr->nr_reqtype);
-		error = copyout(ker, hdr->nr_body, bodysz);
+		error = copyout(ker, (void *)hdr->nr_body, bodysz);
 		if (error) {
 			rerror = error;
 			goto out;
@@ -2847,14 +2849,14 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 	}
 
 	/* copy the options */
-	dst = hdr->nr_options;
+	dst = (struct nmreq_option *)hdr->nr_options;
 	while (src) {
 		size_t optsz;
-		struct nmreq_option *next;
+		uint64_t next;
 
 		/* restore the user pointer */
 		next = src->nro_next;
-		ptrs = (void **)src - 1;
+		ptrs = (uint64_t *)src - 1;
 		src->nro_next = *ptrs;
 
 		/* always copy the option header */
@@ -2875,8 +2877,8 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 				}
 			}
 		}
-		src = next;
-		dst = *ptrs;
+		src = (struct nmreq_option *)next;
+		dst = (struct nmreq_option *)*ptrs;
 	}
 
 
@@ -2889,7 +2891,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 struct nmreq_option *
 nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
 {
-	for ( ; opt; opt = opt->nro_next)
+	for ( ; opt; opt = (struct nmreq_option *)opt->nro_next)
 		if (opt->nro_reqtype == reqtype)
 			return opt;
 	return NULL;
@@ -2901,8 +2903,9 @@ nmreq_checkduplicate(struct nmreq_option *opt) {
 	uint16_t type = opt->nro_reqtype;
 	int dup = 0;
 
-	for (scan = opt->nro_next; scan;
-		scan = nmreq_findoption(scan->nro_next, type))
+	for (scan = (struct nmreq_option *)opt->nro_next; scan;
+		scan = nmreq_findoption((struct nmreq_option *)scan->nro_next,
+			type))
 	{
 		dup++;
 		scan->nro_status = EINVAL;
@@ -2918,7 +2921,8 @@ nmreq_checkoptions(struct nmreq_header *hdr)
 	 * marked as not supported
 	 */
 
-	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+	for (opt = (struct nmreq_option *)hdr->nr_options; opt;
+	     opt = (struct nmreq_option *)opt->nro_next)
 		if (opt->nro_status == EOPNOTSUPP)
 			return EOPNOTSUPP;
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 61e924708..65deeaf72 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -128,8 +128,8 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	/* First prepare the request header. */
 	hdr->nr_version = NETMAP_API; /* new API */
 	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-	hdr->nr_options = NULL;
-	hdr->nr_body = NULL;
+	hdr->nr_options = (uint64_t)NULL;
+	hdr->nr_body = (uint64_t)NULL;
 
 	switch (ioctl_cmd) {
 	case NIOCREGIF: {
@@ -138,7 +138,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			if (nmreq_register_from_legacy(nmr, hdr, req)) {
 				goto oom;
@@ -148,7 +148,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_ATTACH: {
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 			if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
 				goto oom;
@@ -169,7 +169,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_VNET_HDR_GET: {
 			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
 			req->nr_hdr_len = nmr->nr_arg1;
@@ -178,7 +178,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_NEWIF : {
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
@@ -195,7 +195,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_POLLING_OFF: {
 			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
@@ -227,7 +227,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
@@ -235,7 +235,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCGINFO. */
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
@@ -253,7 +253,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 oom:
 	if (hdr) {
 		if (hdr->nr_body) {
-			nm_os_free(hdr->nr_body);
+			nm_os_free((void *)hdr->nr_body);
 		}
 		nm_os_free(hdr);
 	}
@@ -370,7 +370,7 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			nmreq_to_legacy(hdr, nmr);
 		}
 		if (hdr->nr_body) {
-			nm_os_free(hdr->nr_body);
+			nm_os_free((void *)hdr->nr_body);
 		}
 		nm_os_free(hdr);
 		break;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a1bcc06a9..06a3b56d3 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -467,7 +467,7 @@ struct netmap_if {
 /* Header common to all request options. */
 struct nmreq_option {
 	/* Pointer ot the next option. */
-	struct nmreq_option	*nro_next;
+	uint64_t		nro_next;
 	/* Option type. */
 	uint32_t		nro_reqtype;
 	/* (out) status of the option:
@@ -485,8 +485,8 @@ struct nmreq_header {
 	uint32_t		nr_reserved;	/* must be zero */
 #define NETMAP_REQ_IFNAMSIZ	64
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
-	struct nmreq_option	*nr_options;	/* command-specific options */
-	void			*nr_body;	/* ptr to nmreq_xyz struct */
+	uint64_t		nr_options;	/* command-specific options */
+	uint64_t		nr_body;	/* ptr to nmreq_xyz struct */
 };
 
 enum {

From 50b27b4f871d65c892ed2e974b76bab04fc550ba Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 16 Feb 2018 14:40:21 +0100
Subject: [PATCH 0504/2207] monitor: fix compilation

---
 sys/dev/netmap/netmap_monitor.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index ed25f2f11..ed8218bd2 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -856,9 +856,9 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	 */
 	memcpy(&preq, req, sizeof(preq));
 	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	hdr->nr_body = &preq;
+	hdr->nr_body = (uint64_t)&preq;
 	error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
-	hdr->nr_body = req;
+	hdr->nr_body = (uint64_t)req;
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;

From b5e71193ab7551d3d6449a6036231a91bd06d9e9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 16 Feb 2018 14:42:51 +0100
Subject: [PATCH 0505/2207] ptnetmap: fix warning

---
 sys/dev/netmap/netmap_pt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 5b7f0c7a2..c90fec7ee 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1188,9 +1188,9 @@ netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
      */
     memcpy(&preq, req, sizeof(preq));
     preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    hdr->nr_body = &preq;
+    hdr->nr_body = (uint64_t)&preq;
     error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
-    hdr->nr_body = req;
+    hdr->nr_body = (uint64_t)req;
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;

From 1a512056d5565b3409b3d2b2edd8416529b5ccf6 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 19 Feb 2018 13:45:22 +0100
Subject: [PATCH 0506/2207] netmap_bdg_mod_private_data() is a new exported
 function which allows external modules to modify the private data given to
 netmap_bdg_regops() (it handles netmap locks internally). nm_bdg_ctl_{attach,
 detach}() now directly cast the netmap_adapter to a netmap_vp_adapter to
 avoid a problem with permanent VALE ports attached to 2 bridges

---
 LINUX/netmap_linux.c         |  2 +-
 sys/dev/netmap/netmap_kern.h |  8 ++++--
 sys/dev/netmap/netmap_vale.c | 55 ++++++++++++++++++++++++++++--------
 3 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index eb34b3f45..5532ac047 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2445,8 +2445,8 @@ EXPORT_SYMBOL(netmap_rx_irq);	        /* default irq handler */
 EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 #ifdef WITH_VALE
 EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
-//EXPORT_SYMBOL(netmap_bdg_learning);	/* the default lookup function */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
+EXPORT_SYMBOL(netmap_bdg_mod_private_data);
 EXPORT_SYMBOL(nm_bdg_ctl_attach);
 EXPORT_SYMBOL(nm_bdg_ctl_detach);
 #endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 574891331..ecb3729bd 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1444,9 +1444,10 @@ int netmap_get_hw_na(struct ifnet *ifp,
  * drop.
  */
 typedef u_int (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
-		struct netmap_vp_adapter *, void *lookup_data);
+		struct netmap_vp_adapter *, void *private_data);
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
+typedef void (*bdg_mod_private_data_fn_t)(void *private_data, void *callback_data);
 struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
@@ -1454,7 +1455,7 @@ struct netmap_bdg_ops {
 };
 
 u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
-		struct netmap_vp_adapter *, void *lookup_data);
+		struct netmap_vp_adapter *, void *private_data);
 
 #define	NM_BRIDGES		8	/* number of bridges */
 #define	NM_BDG_MAXPORTS		254	/* up to 254 */
@@ -1468,7 +1469,8 @@ struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup_data);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data);
+int netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback, void *callback_data);
 int netmap_bdg_config(struct nm_ifreq *nifr);
 
 #else /* !WITH_VALE */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 54787f8fd..6ba731271 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -232,7 +232,7 @@ struct nm_bridge {
 	 * By default points to *ht which is allocated on attach and used by the default lookup
 	 * otherwise will point to the data structure received by netmap_bdg_regops().
 	 */
-	void *lookup_data;
+	void *private_data;
 	struct nm_hash_ent *ht;
 
 #ifdef CONFIG_NET_NS
@@ -384,7 +384,7 @@ nm_find_bridge(const char *name, int create)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
 		b->bdg_ops = &default_bdg_ops;
-		b->lookup_data = b->ht;
+		b->private_data = b->ht;
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -840,7 +840,6 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	}
 
 	BDG_WLOCK(b);
-	//vpna->up.na_vp = vpna // TODO: should be moved inside netmap_bwrap_bdg_ctl() ?
 	vpna->bdg_port = cand;
 	ND("NIC  %p to bridge port %d", vpna, cand);
 	/* bind the port to the bridge (virtual ports are not active) */
@@ -874,6 +873,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 {
 	struct nmreq_vale_attach *req =
 		(struct nmreq_vale_attach *)hdr->nr_body;
+	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
 	int error;
@@ -912,7 +912,8 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
 	}
-	req->port_index = na->na_vp->bdg_port;
+	vpna = (struct netmap_vp_adapter *)na;
+	req->port_index = vpna->bdg_port;
 	NMG_UNLOCK();
 	return 0;
 
@@ -934,6 +935,7 @@ int
 nm_bdg_ctl_detach(struct nmreq_header *hdr)
 {
 	struct nmreq_vale_detach *nmreq_det = hdr->nr_body;
+	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	int error;
 
@@ -954,7 +956,8 @@ nm_bdg_ctl_detach(struct nmreq_header *hdr)
 		goto unlock_exit;
 	}
 
-	nmreq_det->port_index = na->na_vp->bdg_port;
+	vpna = (struct netmap_vp_adapter *)na;
+	nmreq_det->port_index = vpna->bdg_port;
 
 	if (na->nm_bdg_ctl) {
 		/* remove the port from bridge. The bwrap
@@ -1351,7 +1354,7 @@ netmap_bdg_list(struct nmreq_header *hdr)
  */
  
 int
-netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup_data)
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data)
 {
 	struct nm_bridge *b;
 	int error = 0;
@@ -1363,11 +1366,38 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *lookup
 	} else if (!bdg_ops) {
 		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
 		b->bdg_ops = &default_bdg_ops;
-		b->lookup_data = b->ht;
+		b->private_data = b->ht;
 	} else {
-		// TODO: check if another module has alredy changed the lookup functions
+		/* TODO: implement ownership over bridges */
 		b->bdg_ops = bdg_ops;
-		b->lookup_data = lookup_data;
+		b->private_data = private_data;
+	}
+	NMG_UNLOCK();
+
+	return error;
+}
+
+/* Called by external kernel modules (e.g., Openvswitch).
+ * to modify the private data previously given to regops().
+ * 'name' may be just bridge's name (including ':' if it
+ * is not just NM_BDG_NAME).
+ * Called without NMG_LOCK.
+ */
+int
+netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback, void *callback_data)
+{
+	struct nm_bridge *b;
+	int error = 0;
+
+	NMG_LOCK();
+	b = nm_find_bridge(name, 0 /* don't create */);
+	if (!b) {
+		error = EINVAL;
+	} else {
+		/* TODO: implement ownership over bridges */
+		BDG_WLOCK(b);
+		callback(b->private_data, callback_data);
+		BDG_WUNLOCK(b);
 	}
 	NMG_UNLOCK();
 
@@ -1627,11 +1657,11 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
  */
 u_int
 netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
-		struct netmap_vp_adapter *na, void *lookup_data)
+		struct netmap_vp_adapter *na, void *private_data)
 {
 	uint8_t *buf = ft->ft_buf;
 	u_int buf_len = ft->ft_len;
-	struct nm_hash_ent *ht = lookup_data;
+	struct nm_hash_ent *ht = private_data;
 	uint32_t sh, dh;
 	u_int dst, mysrc = na->bdg_port;
 	uint64_t smac, dmac;
@@ -1793,7 +1823,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		   fragment nor at the very beginning of the second. */
 		if (unlikely(na->up.virt_hdr_len > ft[i].ft_len))
 			continue;
-		dst_port = b->bdg_ops->lookup(&ft[i], &dst_ring, na, b->lookup_data);
+		dst_port = b->bdg_ops->lookup(&ft[i], &dst_ring, na, b->private_data);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)
@@ -2836,6 +2866,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	netmap_adapter_get(hwna);
 	hwna->na_private = bna; /* weak reference */
 	hwna->na_vp = &bna->up;
+	bna->up.up.na_vp = &(bna->up);
 
 	if (hwna->na_flags & NAF_HOST_RINGS) {
 		if (hwna->na_flags & NAF_SW_ONLY)

From 5df45a875e46f2c7183ba828a13806f808825e4e Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 19 Feb 2018 17:12:49 +0100
Subject: [PATCH 0507/2207] Created a wrapper 'nm_vi_create()' for the
 netmap_ioctl() NETMAP_REQ_VALE_NEWIF code. Exported nm_vi_create() and
 nm_vi_destroy() to let external modules create and destroy persistent VALE
 ports. The new nr_body for NETMAP_REQ_VALE_DETACH is now allocated inside
 nmreq_from_legacy case NETMAP_BDG_DETACH

---
 LINUX/netmap_linux.c           |  2 ++
 sys/dev/netmap/netmap.c        | 23 +----------------------
 sys/dev/netmap/netmap_kern.h   |  1 +
 sys/dev/netmap/netmap_legacy.c |  1 +
 sys/dev/netmap/netmap_vale.c   | 30 ++++++++++++++++++++++++++++++
 5 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 5532ac047..fea35b6f8 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2449,6 +2449,8 @@ EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
 EXPORT_SYMBOL(netmap_bdg_mod_private_data);
 EXPORT_SYMBOL(nm_bdg_ctl_attach);
 EXPORT_SYMBOL(nm_bdg_ctl_detach);
+EXPORT_SYMBOL(nm_vi_create);
+EXPORT_SYMBOL(nm_vi_destroy);
 #endif /* WITH_VALE */
 EXPORT_SYMBOL(netmap_disable_all_rings);
 EXPORT_SYMBOL(netmap_enable_all_rings);
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6195910cd..1e170f04d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2506,28 +2506,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_VALE_NEWIF: {
-			struct nmreq_vale_newif *req =
-				(struct nmreq_vale_newif *)hdr->nr_body;
-			/* Build a nmreq_register out of the nmreq_vale_newif,
-			 * so that we can call netmap_get_bdg_na(). */
-			struct nmreq_register regreq;
-			bzero(®req, sizeof(regreq));
-			regreq.nr_tx_slots = req->nr_tx_slots;
-			regreq.nr_rx_slots = req->nr_rx_slots;
-			regreq.nr_tx_rings = req->nr_tx_rings;
-			regreq.nr_rx_rings = req->nr_rx_rings;
-			regreq.nr_mem_id = req->nr_mem_id;
-			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
-			error = netmap_vi_create(hdr, 0 /* no autodelete */);
-			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			hdr->nr_body = req;
-                        /* Write back to the original struct. */
-			req->nr_tx_slots = regreq.nr_tx_slots;
-			req->nr_rx_slots = regreq.nr_rx_slots;
-			req->nr_tx_rings = regreq.nr_tx_rings;
-			req->nr_rx_rings = regreq.nr_rx_rings;
-			req->nr_mem_id = regreq.nr_mem_id;
+			error = nm_vi_create(hdr);
 			break;
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index ecb3729bd..88e8e7bc1 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1022,6 +1022,7 @@ int nm_bdg_ctl_detach(struct nmreq_header *hdr);
 int nm_bdg_polling(struct nmreq_header *hdr);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
 int netmap_vi_create(struct nmreq_header *hdr, int);
+int nm_vi_create(struct nmreq_header *);
 int nm_vi_destroy(const char *name);
 int netmap_bdg_list(struct nmreq_header *hdr);
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 61e924708..cdbb87acb 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -163,6 +163,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		}
 		case NETMAP_BDG_DETACH: {
 			hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
+			hdr->nr_body = nm_os_malloc(sizeof(struct nmreq_vale_detach));
 			break;
 		}
 		case NETMAP_BDG_VNET_HDR:
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 6ba731271..befcfd2fa 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -563,6 +563,36 @@ netmap_vp_dtor(struct netmap_adapter *na)
 	}
 }
 
+/* creates a persistent VALE port */
+int
+nm_vi_create(struct nmreq_header *hdr)
+{
+	struct nmreq_vale_newif *req =
+		(struct nmreq_vale_newif *)hdr->nr_body;
+	int error = 0;
+	/* Build a nmreq_register out of the nmreq_vale_newif,
+	 * so that we can call netmap_get_bdg_na(). */
+	struct nmreq_register regreq;
+	bzero(®req, sizeof(regreq));
+	regreq.nr_tx_slots = req->nr_tx_slots;
+	regreq.nr_rx_slots = req->nr_rx_slots;
+	regreq.nr_tx_rings = req->nr_tx_rings;
+	regreq.nr_rx_rings = req->nr_rx_rings;
+	regreq.nr_mem_id = req->nr_mem_id;
+	hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+	hdr->nr_body = ®req;
+	error = netmap_vi_create(hdr, 0 /* no autodelete */);
+	hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+	hdr->nr_body = req;
+        /* Write back to the original struct. */
+	req->nr_tx_slots = regreq.nr_tx_slots;
+	req->nr_rx_slots = regreq.nr_rx_slots;
+	req->nr_tx_rings = regreq.nr_tx_rings;
+	req->nr_rx_rings = regreq.nr_rx_rings;
+	req->nr_mem_id = regreq.nr_mem_id;
+	return error;
+}
+
 /* remove a persistent VALE port from the system */
 int
 nm_vi_destroy(const char *name)

From ced6989a4c5d78e8122bb5be65b9f4fe13acd816 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 19 Feb 2018 19:06:54 +0100
Subject: [PATCH 0508/2207] linux: configure: build dedup program only on
 x86_64

---
 LINUX/configure | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 7640a09af..38a291231 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -146,7 +146,11 @@ update_drivers() {
 update_drivers
 
 # available apps
-application_avail="pkt-gen bridge lb tlem nmreplay vale-ctl dedup"
+application_avail="pkt-gen bridge lb tlem nmreplay vale-ctl"
+if [ $(uname -m) == "x86_64" ]; then
+    # dedup uses inline x86_64 assembly
+    application_avail="${application_avail} dedup"
+fi
 application=0
 app()
 {

From 3d34d5899bd1c206694a02bcc180a2ca96abd0be Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 19 Feb 2018 22:59:16 +0100
Subject: [PATCH 0509/2207] linux: configure: use the existing infrastructure
 to disable dedup if not x86_64

---
 LINUX/configure | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 38a291231..eee930b20 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -146,11 +146,7 @@ update_drivers() {
 update_drivers
 
 # available apps
-application_avail="pkt-gen bridge lb tlem nmreplay vale-ctl"
-if [ $(uname -m) == "x86_64" ]; then
-    # dedup uses inline x86_64 assembly
-    application_avail="${application_avail} dedup"
-fi
+application_avail="pkt-gen bridge lb tlem nmreplay vale-ctl dedup"
 application=0
 app()
 {
@@ -645,6 +641,13 @@ rm -f config.log
 
 exec 2>> config.log
 
+appl_arch=$($cc -dumpmachine | cut -d '-' -f 1)
+echo "Application arch is $appl_arch"
+if [ $appl_arch != "x86_64" ]; then
+    # dedup uses inline x86_64 assembly
+    app disable dedup
+fi
+
 ################################
 # check for sane configuration
 ################################

From 7c6e9affed91d72366d29b8b093e082f5d0d8136 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 20 Feb 2018 14:28:49 +0100
Subject: [PATCH 0510/2207] Changed port index type to uint32_t.
 netmap_bdg_regops() now takes a BDG_WLOCK() while modifying the callback
 pointer

---
 sys/dev/netmap/netmap_vale.c | 16 ++++++++++++----
 sys/net/netmap.h             |  6 +++---
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index befcfd2fa..fc576e5d6 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -755,7 +755,8 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	int error = 0;
 	struct netmap_vp_adapter *vpna, *hostna = NULL;
 	struct nm_bridge *b;
-	int i, j, cand = -1, cand2 = -1;
+	uint32_t i, j;
+	uint32_t cand = NM_BDG_NOPORT, cand2 = NM_BDG_NOPORT;
 	int needed;
 
 	*na = NULL;     /* default return value */
@@ -1394,13 +1395,20 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *privat
 	if (!b) {
 		error = EINVAL;
 	} else if (!bdg_ops) {
+		BDG_WLOCK(b);
 		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
 		b->bdg_ops = &default_bdg_ops;
 		b->private_data = b->ht;
+		BDG_WUNLOCK(b);
 	} else {
-		/* TODO: implement ownership over bridges */
-		b->bdg_ops = bdg_ops;
-		b->private_data = private_data;
+		BDG_WLOCK(b);
+		if (b->bdg_ops != &default_bdg_ops) {
+			error = EINVAL;
+		} else {
+			b->bdg_ops = bdg_ops;
+			b->private_data = private_data;
+		}
+		BDG_WUNLOCK(b);
 	}
 	NMG_UNLOCK();
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index cadf8d25e..f15e4b832 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -615,7 +615,7 @@ struct nmreq_port_info_get {
  */
 struct nmreq_vale_attach {
 	struct nmreq_register reg;
-	uint8_t port_index;
+	uint32_t port_index;
 };
 
 /*
@@ -625,7 +625,7 @@ struct nmreq_vale_attach {
  * port_index will contain the index where the port was attached.
  */
 struct nmreq_vale_detach {
-	uint8_t port_index;
+	uint32_t port_index;
 };
 
 /*
@@ -635,7 +635,7 @@ struct nmreq_vale_detach {
 struct nmreq_vale_list {
 	/* Name of the VALE port (valeXXX:YYY) or empty. */
 	uint16_t	nr_bridge_idx;
-	uint16_t	nr_port_idx;
+	uint32_t	nr_port_idx;
 };
 
 /*

From 2565efa2bedc27c42cd350564da7cf1f113a6606 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:19:00 +0100
Subject: [PATCH 0511/2207] utils: fix various compilation issues

---
 sys/net/netmap_user.h |   4 +-
 utils/ctrl-api-test.c |  72 +++--
 utils/testmmap.c      | 654 +++++++++++++++++++++++-------------------
 3 files changed, 393 insertions(+), 337 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 5074b0b60..e12b19de7 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -270,8 +270,6 @@ struct nm_desc {
  * to multiple of 64 bytes and is often faster than dealing
  * with other odd sizes. We assume there is enough room
  * in the source and destination buffers.
- *
- * XXX only for multiples of 64 bytes, non overlapped.
  */
 static inline void
 nm_pkt_copy(const void *_src, void *_dst, int l)
@@ -279,7 +277,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024)) {
+	if (unlikely(l >= 1024 || l % 64)) {
 		memcpy(dst, src, l);
 		return;
 	}
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b65a35a6f..d58f81dac 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,15 +1,15 @@
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 
 struct TestContext {
 	const char *ifname;
@@ -28,7 +28,7 @@ struct TestContext {
 
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
-	struct nmreq_option *nr_opt; /* list of options */
+	struct nmreq_option *nr_opt;  /* list of options */
 };
 
 #if 0
@@ -65,7 +65,7 @@ port_info_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -101,8 +101,8 @@ port_register(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	hdr.nr_body    = &req;
-	hdr.nr_options = ctx->nr_opt;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_options = (uint64_t)(uintptr_t)ctx->nr_opt;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id     = ctx->nr_mem_id;
 	req.nr_mode       = ctx->nr_mode;
@@ -188,7 +188,7 @@ vale_attach(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.reg.nr_mem_id = ctx->nr_mem_id;
 	if (ctx->nr_mode == 0) {
@@ -264,7 +264,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr_len = ctx->nr_hdr_len;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
@@ -330,7 +330,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id   = ctx->nr_mem_id;
 	req.nr_tx_slots = ctx->nr_tx_slots;
@@ -348,7 +348,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-	hdr.nr_body    = NULL;
+	hdr.nr_body    = (uint64_t)(uintptr_t)NULL;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
@@ -372,7 +372,7 @@ pools_info_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -433,7 +433,7 @@ pipe_master(int fd, struct TestContext *ctx)
 	ctx->nr_mode = NR_REG_ONE_NIC;
 
 	if (port_register(fd, ctx) == 0) {
-		printf("pipes should not accept NR_REG_ONE_NIC");
+		printf("pipes should not accept NR_REG_ONE_NIC\n");
 		return -1;
 	}
 	ctx->nr_mode = NR_REG_ALL_NIC;
@@ -467,7 +467,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mode		= ctx->nr_mode;
 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
@@ -499,7 +499,7 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -538,8 +538,8 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 static void
 push_option(struct nmreq_option *opt, struct TestContext *ctx)
 {
-	opt->nro_next = ctx->nr_opt;
-	ctx->nr_opt = opt;
+	opt->nro_next = (uint64_t)(uintptr_t)ctx->nr_opt;
+	ctx->nr_opt   = opt;
 }
 
 static void
@@ -552,21 +552,18 @@ static int
 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
 {
 	if (opt->nro_next != exp->nro_next) {
-		printf("nro_next %p expected %p\n",
-				opt->nro_next,
-				exp->nro_next);
+		printf("nro_next %p expected %p\n", (void *)opt->nro_next,
+		       (void *)exp->nro_next);
 		return -1;
 	}
 	if (opt->nro_reqtype != exp->nro_reqtype) {
-		printf("nro_reqtype %u expected %u\n",
-				opt->nro_reqtype,
-				exp->nro_reqtype);
+		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
+		       exp->nro_reqtype);
 		return -1;
 	}
 	if (opt->nro_status != exp->nro_status) {
-		printf("nro_status %u expected %u\n",
-				opt->nro_status,
-				exp->nro_status);
+		printf("nro_status %u expected %u\n", opt->nro_status,
+		       exp->nro_status);
 		return -1;
 	}
 	return 0;
@@ -601,8 +598,8 @@ infinite_options(int fd, struct TestContext *ctx)
 
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
-	opt.nro_next = &opt;
-	save = opt;
+	opt.nro_next = (uint64_t)(uintptr_t)&opt;
+	save	 = opt;
 	if (port_register_hwall(fd, ctx) >= 0)
 		return -1;
 
@@ -646,14 +643,13 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 	return 0;
 }
 
-
 static int
 push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 {
 	void *addr;
 
 	addr = mmap(NULL, (1U << 22), PROT_READ | PROT_WRITE,
-			MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+		    MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 	if (addr == MAP_FAILED) {
 		perror("mmap");
 		return -1;
@@ -661,7 +657,7 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 
 	memset(e, 0, sizeof(*e));
 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
-	e->nro_usrptr = (uint64_t)addr;
+	e->nro_usrptr	  = (uint64_t)addr;
 	e->nro_info.nr_memsize = (1U << 22);
 
 	push_option(&e->nro_opt, ctx);
@@ -675,7 +671,7 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	struct nmreq_opt_extmem *e;
 	int ret;
 
-	e = (struct nmreq_opt_extmem *)ctx->nr_opt;
+	e	   = (struct nmreq_opt_extmem *)ctx->nr_opt;
 	ctx->nr_opt = ctx->nr_opt->nro_next;
 
 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
@@ -683,15 +679,13 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	}
 
 	if (e->nro_usrptr != exp->nro_usrptr) {
-		printf("usrptr %"PRIu64" expected %"PRIu64"\n",
-				e->nro_usrptr,
-				exp->nro_usrptr);
+		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
+		       e->nro_usrptr, exp->nro_usrptr);
 		return -1;
 	}
 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
-		printf("memsize %"PRIu64" expected %"PRIu64"\n",
-				e->nro_info.nr_memsize,
-				exp->nro_info.nr_memsize);
+		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
+		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
 		return -1;
 	}
 
@@ -713,7 +707,7 @@ _extmem_option(int fd, struct TestContext *ctx, int new_rsz)
 
 	save = e;
 
-	ctx->ifname = "vale0:0";
+	ctx->ifname      = "vale0:0";
 	ctx->nr_tx_slots = 16;
 	ctx->nr_rx_slots = 16;
 
@@ -744,7 +738,7 @@ bad_extmem_option(int fd, struct TestContext *ctx)
 {
 	printf("Testing bad extmem option on vale0:0\n");
 
-	return _extmem_option(fd, ctx, (1<<16)) < 0 ? 0 : -1;
+	return _extmem_option(fd, ctx, (1 << 16)) < 0 ? 0 : -1;
 }
 
 static int
diff --git a/utils/testmmap.c b/utils/testmmap.c
index adf4a4ae9..ef38bf284 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1,30 +1,30 @@
 #define TEST_NETMAP
 
+#include 
+#include 
+#include  /* O_RDWR */
 #include 
-#include 	/* ULONG_MAX */
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
-#include 
-#include 
+#include   /* PROT_* */
+#include  /* ULONG_MAX */
 #include 
 #include 
-#include 	/* PROT_* */
-#include 	/* O_RDWR */
-#include 
-#include 
-#include 
-
+#include 
 
 #define MAX_VARS 100
 
 char *variables[MAX_VARS];
 int curr_var;
 
-#define VAR_FAILED ((void*)1)
+#define VAR_FAILED ((void *)1)
 
-char *firstarg(char *buf)
+char *
+firstarg(char *buf)
 {
 	int v;
 	char *arg = strtok(buf, " \t\n");
@@ -33,7 +33,7 @@ char *firstarg(char *buf)
 		return NULL;
 	if (arg[0] != '$' && arg[0] != '?')
 		return arg;
-	v = atoi(arg+1);
+	v = atoi(arg + 1);
 	if (v < 0 || v >= MAX_VARS)
 		return "";
 	ret = variables[v];
@@ -49,45 +49,49 @@ char *firstarg(char *buf)
 	return ret;
 }
 
-char *nextarg()
+char *
+nextarg()
 {
 	return firstarg(NULL);
 }
 
-char *restofline()
+char *
+restofline()
 {
 	return strtok(NULL, "\n");
 }
 
-void resetvar(int v, char *b)
+void
+resetvar(int v, char *b)
 {
 	if (variables[v] != VAR_FAILED)
 		free(variables[v]);
 	variables[v] = b;
 }
 
-#define outecho(format, args...) \
-	do {\
-		printf("%u:%lu: " format "\n", getpid(), (unsigned long) pthread_self(), ##args);\
-		fflush(stdout);\
+#define outecho(format, args...)                                               \
+	do {                                                                   \
+		printf("%u:%lu: " format "\n", getpid(),                       \
+		       (unsigned long)pthread_self(), ##args);                 \
+		fflush(stdout);                                                \
 	} while (0)
 
-#define output(format, args...) \
-	do {\
-		resetvar(curr_var, (char*)malloc(1024));\
-		snprintf(variables[curr_var], 1024, format, ##args);\
-		outecho(format, ##args);\
+#define output(format, args...)                                                \
+	do {                                                                   \
+		resetvar(curr_var, (char *)malloc(1024));                      \
+		snprintf(variables[curr_var], 1024, format, ##args);           \
+		outecho(format, ##args);                                       \
 	} while (0)
 
-#define output_err(ret, format, args...)\
-	do {\
-		if ((ret) < 0) {\
-			resetvar(curr_var, VAR_FAILED);\
-			outecho(format, ##args);\
-			outecho("error: %s", strerror(errno));\
-		} else {\
-			output(format, ##args);\
-		}\
+#define output_err(ret, format, args...)                                       \
+	do {                                                                   \
+		if ((ret) < 0) {                                               \
+			resetvar(curr_var, VAR_FAILED);                        \
+			outecho(format, ##args);                               \
+			outecho("error: %s", strerror(errno));                 \
+		} else {                                                       \
+			output(format, ##args);                                \
+		}                                                              \
 	} while (0)
 
 struct chan {
@@ -96,7 +100,8 @@ struct chan {
 	pthread_t tid;
 };
 
-int chan_search_free(struct chan* c[], int max)
+int
+chan_search_free(struct chan *c[], int max)
 {
 	int i;
 
@@ -106,7 +111,8 @@ int chan_search_free(struct chan* c[], int max)
 	return i;
 }
 
-void chan_clear_all(struct chan *c[], int max)
+void
+chan_clear_all(struct chan *c[], int max)
 {
 	int i;
 
@@ -119,46 +125,51 @@ void chan_clear_all(struct chan *c[], int max)
 	}
 }
 
-int last_fd = -1;
-size_t last_memsize = 0;
-void* last_mmap_addr = NULL;
-char* last_access_addr = NULL;
-
+int last_fd	    = -1;
+size_t last_memsize    = 0;
+void *last_mmap_addr   = NULL;
+char *last_access_addr = NULL;
 
-void do_open()
+void
+do_open()
 {
 	last_fd = open("/dev/netmap", O_RDWR);
 	output_err(last_fd, "open(\"/dev/netmap\", O_RDWR)=%d", last_fd);
 }
 
-void do_close()
+void
+do_close()
 {
 	int ret, fd;
 	char *arg = nextarg();
-	fd = arg ? atoi(arg) : last_fd;
-	ret = close(fd);
+	fd	= arg ? atoi(arg) : last_fd;
+	ret       = close(fd);
 	output_err(ret, "close(%d)=%d", fd, ret);
 }
 
 #ifdef TEST_NETMAP
-#include 
-#include 
 #include 
 #include 
 #include 
+#include 
+#include 
 
 /* legacy */
-struct nmreq curr_nmr = { .nr_version = 11, .nr_flags = NR_REG_ALL_NIC, };
+struct nmreq curr_nmr = {
+	.nr_version = 11,
+	.nr_flags   = NR_REG_ALL_NIC,
+};
 char nmr_name[256];
 
-void parse_nmr_config(char* w, struct nmreq *nmr)
+void
+parse_nmr_config(char *w, struct nmreq *nmr)
 {
 	char *tok;
 	int i, v;
 
 	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
 	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
-	if (w == NULL || ! *w)
+	if (w == NULL || !*w)
 		return;
 	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
 		v = atoi(tok);
@@ -181,7 +192,8 @@ void parse_nmr_config(char* w, struct nmreq *nmr)
 	}
 }
 
-void do_getinfo_legacy()
+void
+do_getinfo_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -208,14 +220,14 @@ void do_getinfo_legacy()
 	parse_nmr_config(arg, &curr_nmr);
 
 doit:
-	ret = ioctl(fd, NIOCGINFO, &curr_nmr);
+	ret	  = ioctl(fd, NIOCGINFO, &curr_nmr);
 	last_memsize = curr_nmr.nr_memsize;
 	output_err(ret, "ioctl(%d, NIOCGINFO) for %s: region %d memsize=%zu",
-		fd, name, curr_nmr.nr_arg2, last_memsize);
+		   fd, name, curr_nmr.nr_arg2, last_memsize);
 }
 
-
-void do_regif_legacy()
+void
+do_regif_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -229,7 +241,7 @@ void do_regif_legacy()
 
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
-	curr_nmr.nr_flags = NR_REG_ALL_NIC;
+	curr_nmr.nr_flags   = NR_REG_ALL_NIC;
 	strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name));
 
 	arg = nextarg();
@@ -242,18 +254,18 @@ void do_regif_legacy()
 	parse_nmr_config(arg, &curr_nmr);
 
 doit:
-	ret = ioctl(fd, NIOCREGIF, &curr_nmr);
+	ret	  = ioctl(fd, NIOCREGIF, &curr_nmr);
 	last_memsize = curr_nmr.nr_memsize;
 	output_err(ret, "ioctl(%d, NIOCREGIF) for %s: region %d memsize=%zu",
-		fd, name, curr_nmr.nr_arg2, last_memsize);
+		   fd, name, curr_nmr.nr_arg2, last_memsize);
 }
 
 void
 do_txsync()
 {
 	char *arg = nextarg();
-	int fd = arg ? atoi(arg) : last_fd;
-	int ret = ioctl(fd, NIOCTXSYNC, NULL);
+	int fd    = arg ? atoi(arg) : last_fd;
+	int ret   = ioctl(fd, NIOCTXSYNC, NULL);
 	output_err(ret, "ioctl(%d, NIOCTXSYNC)=%d", fd, ret);
 }
 
@@ -261,14 +273,14 @@ void
 do_rxsync()
 {
 	char *arg = nextarg();
-	int fd = arg ? atoi(arg) : last_fd;
-	int ret = ioctl(fd, NIOCRXSYNC, NULL);
+	int fd    = arg ? atoi(arg) : last_fd;
+	int ret   = ioctl(fd, NIOCRXSYNC, NULL);
 	output_err(ret, "ioctl(%d, NIOCRXSYNC)=%d", fd, ret);
 }
 #endif /* TEST_NETMAP */
 
-
-void do_rd()
+void
+do_rd()
 {
 	char *arg = nextarg();
 	char *p;
@@ -286,7 +298,8 @@ void do_rd()
 }
 
 char *last_wr_byte = "x";
-void do_wr()
+void
+do_wr()
 {
 	char *arg = nextarg();
 	char *p;
@@ -304,15 +317,16 @@ void do_wr()
 	if (!arg) {
 		arg = last_wr_byte;
 	}
-	for ( ; arg; arg = nextarg()) {
+	for (; arg; arg = nextarg()) {
 		*p++ = strtoul((void *)arg, NULL, 0);
 	}
 }
 
-void do_dup()
+void
+do_dup()
 {
 	char *arg = nextarg();
-	int fd = last_fd;
+	int fd    = last_fd;
 	int ret;
 
 	if (arg) {
@@ -320,10 +334,10 @@ void do_dup()
 	}
 	ret = dup(fd);
 	output_err(ret, "dup(%d)=%d", fd, ret);
-
 }
 
-void do_mmap()
+void
+do_mmap()
 {
 	size_t memsize;
 	off_t off = 0;
@@ -333,37 +347,36 @@ void do_mmap()
 	arg = nextarg();
 	if (!arg) {
 		memsize = last_memsize;
-		fd = last_fd;
+		fd      = last_fd;
 		goto doit;
 	}
 	memsize = atoi(arg);
-	arg = nextarg();
+	arg     = nextarg();
 	if (!arg) {
 		fd = last_fd;
 		goto doit;
 	}
-	fd = atoi(arg);
+	fd  = atoi(arg);
 	arg = nextarg();
 	if (arg) {
 		off = (off_t)atol(arg);
 	}
 doit:
-	last_mmap_addr = mmap(0, memsize,
-			PROT_WRITE | PROT_READ,
-			MAP_SHARED, fd, off);
+	last_mmap_addr =
+		mmap(0, memsize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, off);
 	if (last_access_addr == NULL)
 		last_access_addr = last_mmap_addr;
 	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
-		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED, %d, %jd)=%p",
-		memsize, fd, (intmax_t)off, last_mmap_addr);
-
+		   "mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED, %d, %jd)=%p",
+		   memsize, fd, (intmax_t)off, last_mmap_addr);
 }
 
 #ifndef MAP_HUGETLB
 #define MAP_HUGETLB 0x40000
 #endif
 
-void do_anon_mmap()
+void
+do_anon_mmap()
 {
 	size_t memsize;
 	char *arg;
@@ -375,23 +388,23 @@ void do_anon_mmap()
 		goto doit;
 	}
 	memsize = atoi(arg);
-	arg = nextarg();
+	arg     = nextarg();
 	if (!arg)
 		goto doit;
 	flags |= MAP_HUGETLB;
 doit:
-	last_mmap_addr = mmap(0, memsize,
-			PROT_WRITE | PROT_READ,
-			MAP_SHARED | MAP_ANONYMOUS | flags, -1, 0);
+	last_mmap_addr = mmap(0, memsize, PROT_WRITE | PROT_READ,
+			      MAP_SHARED | MAP_ANONYMOUS | flags, -1, 0);
 	if (last_access_addr == NULL)
 		last_access_addr = last_mmap_addr;
 	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
-		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS%s, -1, 0)=%p",
-		memsize, (flags ? "|MAP_HUGETLB" : ""), last_mmap_addr);
-
+		   "mmap(0, %zu, PROT_WRITE|PROT_READ, "
+		   "MAP_SHARED|MAP_ANONYMOUS%s, -1, 0)=%p",
+		   memsize, (flags ? "|MAP_HUGETLB" : ""), last_mmap_addr);
 }
 
-void do_munmap()
+void
+do_munmap()
 {
 	void *mmap_addr;
 	size_t memsize;
@@ -401,11 +414,11 @@ void do_munmap()
 	arg = nextarg();
 	if (!arg) {
 		mmap_addr = last_mmap_addr;
-		memsize = last_memsize;
+		memsize   = last_memsize;
 		goto doit;
 	}
-	mmap_addr = (void*)strtoul(arg, NULL, 0);
-	arg = nextarg();
+	mmap_addr = (void *)strtoul(arg, NULL, 0);
+	arg       = nextarg();
 	if (!arg) {
 		memsize = last_memsize;
 		goto doit;
@@ -416,7 +429,8 @@ void do_munmap()
 	output_err(ret, "munmap(%p, %zu)=%d", mmap_addr, memsize, ret);
 }
 
-void do_poll()
+void
+do_poll()
 {
 	/* timeout fd fd... */
 	nfds_t nfds = 0, allocated_fds = 10, i;
@@ -433,11 +447,12 @@ void do_poll()
 		output_err(-1, "out of memory");
 		return;
 	}
-	while ( (arg = nextarg()) ) {
+	while ((arg = nextarg())) {
 		if (nfds >= allocated_fds) {
 			struct pollfd *new_fds;
 			allocated_fds *= 2;
-			new_fds = realloc(fds, allocated_fds * sizeof(struct pollfd));
+			new_fds = realloc(fds, allocated_fds *
+						       sizeof(struct pollfd));
 			if (new_fds == NULL) {
 				free(fds);
 				output_err(-1, "out of memory");
@@ -445,25 +460,23 @@ void do_poll()
 			}
 			fds = new_fds;
 		}
-		fds[nfds].fd = atoi(arg);
+		fds[nfds].fd     = atoi(arg);
 		fds[nfds].events = POLLIN;
 		nfds++;
 	}
 	ret = poll(fds, nfds, timeout);
 	for (i = 0; i < nfds; i++) {
 		output("poll(%d)=%s%s%s%s%s", fds[i].fd,
-			(fds[i].revents & POLLIN) ? "IN  " : "-   ",
-			(fds[i].revents & POLLOUT)? "OUT " : "-   ",
-			(fds[i].revents & POLLERR)? "ERR " : "-   ",
-			(fds[i].revents & POLLHUP)? "HUP " : "-   ",
-			(fds[i].revents & POLLNVAL)?"NVAL" : "-");
-
+		       (fds[i].revents & POLLIN) ? "IN  " : "-   ",
+		       (fds[i].revents & POLLOUT) ? "OUT " : "-   ",
+		       (fds[i].revents & POLLERR) ? "ERR " : "-   ",
+		       (fds[i].revents & POLLHUP) ? "HUP " : "-   ",
+		       (fds[i].revents & POLLNVAL) ? "NVAL" : "-");
 	}
 	output_err(ret, "poll(...)=%d", ret);
 	free(fds);
 }
 
-
 void
 do_expr()
 {
@@ -473,7 +486,7 @@ do_expr()
 	int err = 0;
 
 	stack[10] = ULONG_MAX;
-	while ( (arg = nextarg()) ) {
+	while ((arg = nextarg())) {
 		errno = 0;
 		char *rest;
 		unsigned long n = strtoul(arg, &rest, 0);
@@ -488,7 +501,7 @@ do_expr()
 		if (top <= 8) {
 			unsigned long n1 = stack[top++];
 			unsigned long n2 = stack[top++];
-			unsigned long r = 0;
+			unsigned long r  = 0;
 			switch (arg[0]) {
 			case '+':
 				r = n1 + n2;
@@ -504,7 +517,7 @@ do_expr()
 					r = n1 / n2;
 				else {
 					errno = EDOM;
-					err = -1;
+					err   = -1;
 				}
 				break;
 			default:
@@ -520,8 +533,6 @@ do_expr()
 	output_err(err, "expr=%lu", stack[top]);
 }
 
-
-
 void
 do_echo()
 {
@@ -539,7 +550,7 @@ do_vars()
 		const char *v = variables[i];
 		if (v == NULL)
 			continue;
-		printf("?%d\t%s\n", i, v == VAR_FAILED ?  "FAILED" : v);
+		printf("?%d\t%s\n", i, v == VAR_FAILED ? "FAILED" : v);
 	}
 }
 
@@ -551,7 +562,7 @@ get_if()
 	char *arg;
 
 	/* defaults */
-	off = curr_nmr.nr_offset;
+	off       = curr_nmr.nr_offset;
 	mmap_addr = last_mmap_addr;
 
 	/* first arg: if offset */
@@ -565,7 +576,7 @@ get_if()
 	if (!arg) {
 		goto doit;
 	}
-	mmap_addr = (void*)strtoul(arg, NULL, 0);
+	mmap_addr = (void *)strtoul(arg, NULL, 0);
 doit:
 	return NETMAP_IF(mmap_addr, off);
 }
@@ -621,7 +632,7 @@ get_ring()
 void
 dump_ring(struct netmap_ring *ring)
 {
-	printf("buf_ofs     %"PRId64"\n", ring->buf_ofs);
+	printf("buf_ofs     %" PRId64 "\n", ring->buf_ofs);
 	printf("num_slots   %u\n", ring->num_slots);
 	printf("nr_buf_size %u\n", ring->nr_buf_size);
 	printf("ringid      %d\n", ring->ringid);
@@ -653,8 +664,8 @@ dump_ring(struct netmap_ring *ring)
 		printf(" ]");
 	}
 	printf("\n");
-	printf("ts          %ld:%ld\n",
-			(long int)ring->ts.tv_sec, (long int)ring->ts.tv_usec);
+	printf("ts          %ld:%ld\n", (long int)ring->ts.tv_sec,
+	       (long int)ring->ts.tv_usec);
 }
 
 void
@@ -748,7 +759,7 @@ do_slot()
 doit:
 	ring = get_ring();
 	slot = ring->slot + index;
-	arg = nextarg();
+	arg  = nextarg();
 	if (!arg) {
 		dump_slot(slot);
 		return;
@@ -777,15 +788,15 @@ dump_payload(char *p, int len)
 	int i, j, i0;
 
 	/* hexdump routine */
-	for (i = 0; i < len; ) {
+	for (i = 0; i < len;) {
 		memset(buf, sizeof(buf), ' ');
 		sprintf(buf, "%5d: ", i);
 		i0 = i;
-		for (j=0; j < 16 && i < len; i++, j++)
-			sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i]));
+		for (j = 0; j < 16 && i < len; i++, j++)
+			sprintf(buf + 7 + j * 3, "%02x ", (uint8_t)(p[i]));
 		i = i0;
-		for (j=0; j < 16 && i < len; i++, j++)
-			sprintf(buf+7+j + 48, "%c",
+		for (j = 0; j < 16 && i < len; i++, j++)
+			sprintf(buf + 7 + j + 48, "%c",
 				isprint(p[i]) ? p[i] : '.');
 		printf("%s\n", buf);
 	}
@@ -800,7 +811,7 @@ do_buf()
 
 	/* defaults */
 	buf_idx = 2;
-	len = 64;
+	len     = 64;
 
 	arg = nextarg();
 	if (!arg)
@@ -813,7 +824,7 @@ do_buf()
 	len = strtoll(arg, NULL, 0);
 doit:
 	ring = get_ring();
-	buf = NETMAP_BUF(ring, buf_idx);
+	buf  = NETMAP_BUF(ring, buf_idx);
 	output("buf=%p", buf);
 	last_access_addr = buf;
 	dump_payload(buf, len);
@@ -824,7 +835,8 @@ struct cmd_def {
 	void (*f)(void);
 };
 
-int _find_command(const struct cmd_def *cmds, int ncmds, const char* cmd)
+int
+_find_command(const struct cmd_def *cmds, int ncmds, const char *cmd)
 {
 	int i;
 	for (i = 0; i < ncmds; i++) {
@@ -839,8 +851,11 @@ struct pools_info_field {
 	size_t off;
 	size_t size;
 };
-#define PIFD(n, f)	{ n, offsetof(struct nmreq_pools_info, nr_##f), \
-	sizeof(((struct nmreq_pools_info *)0)->nr_##f) }
+#define PIFD(n, f)                                                             \
+	{                                                                      \
+		n, offsetof(struct nmreq_pools_info, nr_##f),                  \
+			sizeof(((struct nmreq_pools_info *)0)->nr_##f)         \
+	}
 struct pools_info_field pools_info_fields[] = {
 	PIFD("memsize", memsize),
 	PIFD("mem_id", mem_id),
@@ -853,9 +868,8 @@ struct pools_info_field pools_info_fields[] = {
 	PIFD("buf-off", buf_pool_offset),
 	PIFD("buf-tot", buf_pool_objtotal),
 	PIFD("buf-siz", buf_pool_objsize),
-	{ NULL, 0, 0 }
-};
-#define PIF(t, p, o)	(*(t*)((void *)((char *)(p)+(o))))
+	{NULL, 0, 0}};
+#define PIF(t, p, o) (*(t *)((void *)((char *)(p) + (o))))
 void
 pools_info_dump(int tab, struct nmreq_pools_info *upi)
 {
@@ -865,19 +879,18 @@ pools_info_dump(int tab, struct nmreq_pools_info *upi)
 		printf("%.*s%-12s", tab, space, f->name);
 		switch (f->size) {
 		case 8:
-			printf("%"PRIu64"\n", PIF(uint64_t, upi, f->off));
+			printf("%" PRIu64 "\n", PIF(uint64_t, upi, f->off));
 			break;
 		case 4:
-			printf("%"PRIu32"\n", PIF(uint32_t, upi, f->off));
+			printf("%" PRIu32 "\n", PIF(uint32_t, upi, f->off));
 			break;
 		case 2:
-			printf("%"PRIu16"\n", PIF(uint16_t, upi, f->off));
+			printf("%" PRIu16 "\n", PIF(uint16_t, upi, f->off));
 			break;
 		}
 	}
 }
 
-
 static struct nmreq_pools_info curr_pools_info;
 
 /* prepare the curr_pools_info */
@@ -917,9 +930,9 @@ do_pools_info()
 
 typedef void (*nmr_arg_interp_fun)();
 
-#define nmr_arg_unexpected(n) \
-	printf("arg%d:      %d%s\n", n, curr_nmr.nr_arg ## n, \
-		(curr_nmr.nr_arg ## n ? "???" : ""))
+#define nmr_arg_unexpected(n)                                                  \
+	printf("arg%d:      %d%s\n", n, curr_nmr.nr_arg##n,                    \
+	       (curr_nmr.nr_arg##n ? "???" : ""))
 
 void
 nmr_arg_bdg_attach()
@@ -1002,12 +1015,13 @@ void
 nmr_arg_extra()
 {
 	printf("arg1:      %d [%sextra rings]\n", curr_nmr.nr_arg1,
-		(curr_nmr.nr_arg1 ? "" : "no "));
+	       (curr_nmr.nr_arg1 ? "" : "no "));
 	printf("arg2:      %d [%s memory allocator]\n", curr_nmr.nr_arg2,
-		(curr_nmr.nr_arg2 == 0 ? "default" :
-		 curr_nmr.nr_arg2 == 1 ? "global"  : "private"));
+	       (curr_nmr.nr_arg2 == 0
+			? "default"
+			: curr_nmr.nr_arg2 == 1 ? "global" : "private"));
 	printf("arg3:      %d [%sextra buffers]\n", curr_nmr.nr_arg3,
-		(curr_nmr.nr_arg3 ? "" : "no "));
+	       (curr_nmr.nr_arg3 ? "" : "no "));
 }
 
 void
@@ -1022,7 +1036,7 @@ do_nmr_legacy_dump()
 	printf("version:   %d\n", curr_nmr.nr_version);
 	printf("offset:    %d\n", curr_nmr.nr_offset);
 	printf("memsize:   %d [", curr_nmr.nr_memsize);
-	if (curr_nmr.nr_memsize < (1<<20)) {
+	if (curr_nmr.nr_memsize < (1 << 20)) {
 		printf("%d KiB", curr_nmr.nr_memsize >> 10);
 	} else {
 		printf("%d MiB", curr_nmr.nr_memsize >> 20);
@@ -1158,7 +1172,7 @@ do_nmr_legacy_reset()
 {
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
-	curr_nmr.nr_flags = NR_REG_ALL_NIC;
+	curr_nmr.nr_flags   = NR_REG_ALL_NIC;
 }
 
 void
@@ -1277,15 +1291,13 @@ do_nmr_legacy_flags()
 }
 
 struct cmd_def nmr_legacy_commands[] = {
-	{ "dump",	do_nmr_legacy_dump },
-	{ "reset",	do_nmr_legacy_reset },
-	{ "name",	do_nmr_legacy_name },
-	{ "ringid",	do_nmr_legacy_ringid },
-	{ "cmd",	do_nmr_legacy_cmd },
-	{ "flags",	do_nmr_legacy_flags },
+	{"dump", do_nmr_legacy_dump}, {"reset", do_nmr_legacy_reset},
+	{"name", do_nmr_legacy_name}, {"ringid", do_nmr_legacy_ringid},
+	{"cmd", do_nmr_legacy_cmd},   {"flags", do_nmr_legacy_flags},
 };
 
-const int N_NMR_LEGACY_CMDS = sizeof(nmr_legacy_commands) / sizeof(struct cmd_def);
+const int N_NMR_LEGACY_CMDS =
+	sizeof(nmr_legacy_commands) / sizeof(struct cmd_def);
 
 int
 find_nmr_legacy_command(const char *cmd)
@@ -1293,22 +1305,22 @@ find_nmr_legacy_command(const char *cmd)
 	return _find_command(nmr_legacy_commands, N_NMR_LEGACY_CMDS, cmd);
 }
 
-#define __nmr_arg_update(nmr, f) 					\
-	({								\
-		int __ret = 0;						\
-		if (strcmp(cmd, #f) == 0) {				\
-			char *arg = nextarg();				\
-			if (arg) {					\
-				curr_##nmr.nr_##f = strtol(arg, NULL, 0);\
-			}						\
-			output(#f "=%llu",				\
-				(unsigned long long)curr_##nmr.nr_##f);	\
-			__ret = 1;					\
-		} 							\
-		__ret;							\
+#define __nmr_arg_update(nmr, f)                                               \
+	({                                                                     \
+		int __ret = 0;                                                 \
+		if (strcmp(cmd, #f) == 0) {                                    \
+			char *arg = nextarg();                                 \
+			if (arg) {                                             \
+				curr_##nmr.nr_##f = strtol(arg, NULL, 0);      \
+			}                                                      \
+			output(#f "=%llu",                                     \
+			       (unsigned long long)curr_##nmr.nr_##f);         \
+			__ret = 1;                                             \
+		}                                                              \
+		__ret;                                                         \
 	})
 
-#define nmr_arg_update(f)	__nmr_arg_update(nmr, f)
+#define nmr_arg_update(f) __nmr_arg_update(nmr, f)
 
 /* prepare the curr_nmr */
 void
@@ -1330,18 +1342,12 @@ do_nmr_legacy()
 			return;
 		}
 	}
-	if (nmr_arg_update(version) ||
-	    nmr_arg_update(offset) ||
-	    nmr_arg_update(memsize) ||
-	    nmr_arg_update(tx_slots) ||
-	    nmr_arg_update(rx_slots) ||
-	    nmr_arg_update(tx_rings) ||
-	    nmr_arg_update(rx_rings) ||
-	    nmr_arg_update(ringid) ||
-	    nmr_arg_update(cmd) ||
-	    nmr_arg_update(arg1) ||
-	    nmr_arg_update(arg2) ||
-	    nmr_arg_update(arg3) ||
+	if (nmr_arg_update(version) || nmr_arg_update(offset) ||
+	    nmr_arg_update(memsize) || nmr_arg_update(tx_slots) ||
+	    nmr_arg_update(rx_slots) || nmr_arg_update(tx_rings) ||
+	    nmr_arg_update(rx_rings) || nmr_arg_update(ringid) ||
+	    nmr_arg_update(cmd) || nmr_arg_update(arg1) ||
+	    nmr_arg_update(arg2) || nmr_arg_update(arg3) ||
 	    nmr_arg_update(flags))
 		return;
 	output("unknown field: %s", cmd);
@@ -1351,7 +1357,7 @@ do_nmr_legacy()
  * new API							*
  ****************************************************************/
 
-static struct nmreq_header curr_hdr = { .nr_version = NETMAP_API };
+static struct nmreq_header curr_hdr = {.nr_version = NETMAP_API};
 static struct nmreq_register curr_register;
 static struct nmreq_port_info_get curr_port_info_get;
 static struct nmreq_vale_attach curr_vale_attach;
@@ -1366,24 +1372,24 @@ static void
 nmr_body_dump_register(void *b)
 {
 	struct nmreq_register *r = b;
-	int flags = 0;
-	printf("offset:    %"PRIu64"\n", r->nr_offset);
-	printf("memsize:   %"PRIu64" [", r->nr_memsize);
-	if (r->nr_memsize < (1<<20)) {
-		printf("%"PRIu64" KiB", r->nr_memsize >> 10);
+	int flags		 = 0;
+	printf("offset:    %" PRIu64 "\n", r->nr_offset);
+	printf("memsize:   %" PRIu64 " [", r->nr_memsize);
+	if (r->nr_memsize < (1 << 20)) {
+		printf("%" PRIu64 " KiB", r->nr_memsize >> 10);
 	} else {
-		printf("%"PRIu64" MiB", r->nr_memsize >> 20);
+		printf("%" PRIu64 " MiB", r->nr_memsize >> 20);
 	}
 	printf("]\n");
-	printf("tx_slots:  %"PRIu16"\n", r->nr_tx_slots);
-	printf("rx_slots:  %"PRIu16"\n", r->nr_rx_slots);
-	printf("tx_rings:  %"PRIu16"\n", r->nr_tx_rings);
-	printf("rx_rings:  %"PRIu16"\n", r->nr_rx_rings);
-	printf("mem_id:    %"PRIu16" [%s memory region]\n", r->nr_mem_id,
-		(r->nr_mem_id == 0 ? "default" :
-		 r->nr_mem_id == 1 ? "global"  : "private"));
-	printf("ringid     %"PRIu16"\n", r->nr_ringid);
-	printf("mode       %"PRIu32" [", r->nr_mode);
+	printf("tx_slots:  %" PRIu16 "\n", r->nr_tx_slots);
+	printf("rx_slots:  %" PRIu16 "\n", r->nr_rx_slots);
+	printf("tx_rings:  %" PRIu16 "\n", r->nr_tx_rings);
+	printf("rx_rings:  %" PRIu16 "\n", r->nr_rx_rings);
+	printf("mem_id:    %" PRIu16 " [%s memory region]\n", r->nr_mem_id,
+	       (r->nr_mem_id == 0 ? "default"
+				  : r->nr_mem_id == 1 ? "global" : "private"));
+	printf("ringid     %" PRIu16 "\n", r->nr_ringid);
+	printf("mode       %" PRIu32 " [", r->nr_mode);
 	switch (r->nr_mode) {
 	case NR_REG_DEFAULT:
 		printf("*DEFAULT");
@@ -1398,7 +1404,7 @@ nmr_body_dump_register(void *b)
 		printf("NIC_SW");
 		break;
 	case NR_REG_ONE_NIC:
-		printf("ONE_NIC(%"PRIu16")", r->nr_ringid);
+		printf("ONE_NIC(%" PRIu16 ")", r->nr_ringid);
 		break;
 	case NR_REG_PIPE_MASTER:
 		printf("*PIPE_MASTER(%d)", r->nr_ringid);
@@ -1412,7 +1418,10 @@ nmr_body_dump_register(void *b)
 	}
 	printf("]\n");
 	printf("flags:     %lx [", r->nr_flags);
-#define pflag(f) if (r->nr_flags & NR_##f) { printf("%s" #f, flags++ ? ", " : ""); }
+#define pflag(f)                                                               \
+	if (r->nr_flags & NR_##f) {                                            \
+		printf("%s" #f, flags++ ? ", " : "");                          \
+	}
 	pflag(MONITOR_TX);
 	pflag(MONITOR_RX);
 	pflag(ZCOPY_MON);
@@ -1425,7 +1434,7 @@ nmr_body_dump_register(void *b)
 	pflag(NO_TX_POLL);
 #undef pflag
 	printf("]\n");
-	printf("extra_bufs %"PRIu32"\n", r->nr_extra_bufs);
+	printf("extra_bufs %" PRIu32 "\n", r->nr_extra_bufs);
 }
 
 static void
@@ -1465,7 +1474,7 @@ do_register_mode()
 	}
 
 out:
-	output("mode=%"PRIu32, curr_register.nr_mode);
+	output("mode=%" PRIu32, curr_register.nr_mode);
 }
 
 void
@@ -1505,10 +1514,10 @@ do_register_flags()
 }
 
 struct cmd_def register_commands[] = {
-	{ "dump",	do_register_dump },
-	{ "reset",	do_register_reset },
-	{ "mode",	do_register_mode },
-	{ "flags",	do_register_flags },
+	{"dump", do_register_dump},
+	{"reset", do_register_reset},
+	{"mode", do_register_mode},
+	{"flags", do_register_flags},
 };
 
 const int N_REGISTER_CMDS = sizeof(register_commands) / sizeof(struct cmd_def);
@@ -1540,17 +1549,12 @@ do_register()
 			return;
 		}
 	}
-	if (register_update(offset) 
-	||  register_update(memsize) 
-	||  register_update(tx_slots) 
-	||  register_update(rx_slots) 
-	||  register_update(tx_rings) 
-	||  register_update(rx_rings) 
-	||  register_update(mem_id) 
-	||  register_update(ringid) 
-	||  register_update(mode) 
-	||  register_update(flags)
-	||  register_update(extra_bufs))
+	if (register_update(offset) || register_update(memsize) ||
+	    register_update(tx_slots) || register_update(rx_slots) ||
+	    register_update(tx_rings) || register_update(rx_rings) ||
+	    register_update(mem_id) || register_update(ringid) ||
+	    register_update(mode) || register_update(flags) ||
+	    register_update(extra_bufs))
 		return;
 	output("unknown field: %s", cmd);
 }
@@ -1602,8 +1606,7 @@ typedef void (*nmr_option_dump_fun)(struct nmreq_option *);
 static void
 nmr_option_dump_extmem(struct nmreq_option *opt)
 {
-	struct nmreq_opt_extmem *e =
-		(struct nmreq_opt_extmem *)opt;
+	struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)opt;
 
 	printf("usrptr: %p\n", (void *)e->nro_usrptr);
 	printf("info:\n");
@@ -1615,8 +1618,8 @@ nmr_option_dump(struct nmreq_option *opt)
 {
 	nmr_option_dump_fun d = NULL;
 
-	printf("next: %p\n", opt->nro_next);
-	printf("type: %"PRIu32" [", opt->nro_reqtype);
+	printf("next: %p\n", (void *)opt->nro_next);
+	printf("type: %" PRIu32 " [", opt->nro_reqtype);
 	switch (opt->nro_reqtype) {
 	case NETMAP_REQ_OPT_EXTMEM:
 		printf("extmem");
@@ -1626,15 +1629,15 @@ nmr_option_dump(struct nmreq_option *opt)
 #ifdef NETMAP_OPT_DEBUG
 		if (opt->nro_reqtype & NETMAP_REQ_OPT_DEBUG) {
 			printf("debug: %u",
-				(opt->nro_reqtype & ~NETMAP_REQ_OPT_DEBUG));
+			       (opt->nro_reqtype & ~NETMAP_REQ_OPT_DEBUG));
 			break;
 		}
 #endif /* NETMAP_OPT_DEBUG */
 		printf("???");
 	}
 	printf("]\n");
-	printf("status: %"PRIu32" [%s]\n", 
-			opt->nro_status, strerror(opt->nro_status));
+	printf("status: %" PRIu32 " [%s]\n", opt->nro_status,
+	       strerror(opt->nro_status));
 	if (d)
 		d(opt);
 }
@@ -1702,29 +1705,29 @@ do_hdr_dump()
 	}
 	printf("]\n");
 	printf("name: %s\n", nmr_name);
-	opt = curr_hdr.nr_options;
+	opt = (struct nmreq_option *)curr_hdr.nr_options;
 	printf("options:   %p\n", opt);
 	while (opt) {
 		nmr_option_dump(opt);
-		opt = opt->nro_next;
+		opt = (struct nmreq_option *)opt->nro_next;
 	}
-	printf("body:	   %p\n", curr_hdr.nr_body);
+	printf("body:	   %p\n", (void *)curr_hdr.nr_body);
 	if (body_dump)
-		body_dump(curr_hdr.nr_body);
+		body_dump((void *)curr_hdr.nr_body);
 }
 
 static void
 do_hdr_reset()
 {
-	struct nmreq_option *opt = curr_hdr.nr_options;
+	struct nmreq_option *opt = (struct nmreq_option *)curr_hdr.nr_options;
 	while (opt) {
-		struct nmreq_option *next = opt->nro_next;
+		struct nmreq_option *next =
+			(struct nmreq_option *)opt->nro_next;
 		free(opt);
 		opt = next;
 	}
 	memset(&curr_hdr, 0, sizeof(curr_hdr));
 	curr_hdr.nr_version = NETMAP_API;
-
 }
 
 void
@@ -1739,7 +1742,6 @@ do_hdr_name()
 	output("name=%s", nmr_name);
 }
 
-
 static void
 do_hdr_type()
 {
@@ -1747,38 +1749,38 @@ do_hdr_type()
 
 	if (strcmp(type, "register") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-		curr_hdr.nr_body = &curr_register;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_register;
 	} else if (strcmp(type, "info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-		curr_hdr.nr_body = &curr_port_info_get;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_info_get;
 	} else if (strcmp(type, "vale-attach") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-		curr_hdr.nr_body = &curr_vale_attach;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_attach;
 	} else if (strcmp(type, "vale-detach") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	} else if (strcmp(type, "vale-list") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-		curr_hdr.nr_body = &curr_vale_list;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_list;
 	} else if (strcmp(type, "port-hdr-set") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-		curr_hdr.nr_body = &curr_port_hdr;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_hdr;
 	} else if (strcmp(type, "port-hdr-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-		curr_hdr.nr_body = &curr_port_hdr;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_hdr;
 	} else if (strcmp(type, "vale-newif") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-		curr_hdr.nr_body = &curr_vale_newif;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_newif;
 	} else if (strcmp(type, "vale-delif") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	} else if (strcmp(type, "vale-polliing-enable") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-		curr_hdr.nr_body = &curr_vale_polling;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_polling;
 	} else if (strcmp(type, "vale-polling-disable") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-		curr_hdr.nr_body = &curr_vale_polling;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_polling;
 	} else if (strcmp(type, "pools-info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-		curr_hdr.nr_body = &curr_pools_info;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_pools_info;
 	} else {
 		output("unknown type: %s", type);
 	}
@@ -1790,34 +1792,34 @@ typedef void (*nmreq_opt_init)(struct nmreq_option *);
 static void
 nmreq_opt_extmem_init(struct nmreq_option *opt)
 {
-	struct nmreq_opt_extmem *e =
-		(struct nmreq_opt_extmem *)opt;
-	e->nro_usrptr = (uint64_t)last_mmap_addr;
-	e->nro_info.nr_memsize = last_memsize;
+	struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)opt;
+	e->nro_usrptr		   = (uint64_t)last_mmap_addr;
+	e->nro_info.nr_memsize     = last_memsize;
 }
 
 static void
 do_hdr_option()
 {
 	char *type;
-	struct nmreq_option **ptr = &curr_hdr.nr_options,
+	struct nmreq_option **ptr = (struct nmreq_option **)&curr_hdr
+					    .nr_options,
 			    *old = *ptr;
-	size_t sz = sizeof(struct nmreq_option);
-	nmreq_opt_init init = NULL;
+	size_t sz		 = sizeof(struct nmreq_option);
+	nmreq_opt_init init      = NULL;
 
-	while ( (type = nextarg()) ) {
+	while ((type = nextarg())) {
 		uint16_t reqtype;
 
 		if (strcmp(type, "extmem") == 0) {
 			reqtype = NETMAP_REQ_OPT_EXTMEM;
-			sz = sizeof(struct nmreq_opt_extmem);
-			init = nmreq_opt_extmem_init;
+			sz      = sizeof(struct nmreq_opt_extmem);
+			init    = nmreq_opt_extmem_init;
 #ifdef NETMAP_OPT_DEBUG
 		} else {
 			reqtype = strtol(type, NULL, 0) | NETMAP_REQ_OPT_DEBUG;
 #endif /* NETMAP_OPT_DEBUG */
 		}
-		*ptr = malloc(sz);	
+		*ptr = malloc(sz);
 		if (*ptr == NULL) {
 			output_err(-1, "malloc");
 		}
@@ -1825,17 +1827,14 @@ do_hdr_option()
 		(*ptr)->nro_reqtype = reqtype;
 		if (init)
 			init(*ptr);
-		ptr = &(*ptr)->nro_next;
+		ptr = (struct nmreq_option **)&(*ptr)->nro_next;
 	}
 	*ptr = old;
 }
 
 struct cmd_def hdr_commands[] = {
-	{ "dump",	do_hdr_dump },
-	{ "reset",	do_hdr_reset },
-	{ "name",	do_hdr_name },
-	{ "type",	do_hdr_type },
-	{ "option",	do_hdr_option },
+	{"dump", do_hdr_dump}, {"reset", do_hdr_reset},   {"name", do_hdr_name},
+	{"type", do_hdr_type}, {"option", do_hdr_option},
 };
 
 const int N_HDR_CMDS = sizeof(hdr_commands) / sizeof(struct cmd_def);
@@ -1846,8 +1845,6 @@ find_hdr_command(const char *cmd)
 	return _find_command(hdr_commands, N_HDR_CMDS, cmd);
 }
 
-
-
 static void
 do_hdr()
 {
@@ -1881,49 +1878,113 @@ do_ctrl()
 doit:
 	ret = ioctl(fd, NIOCCTRL, &curr_hdr);
 	output_err(ret, "ioctl(%d, NIOCCTL, %p)=%d", fd, &curr_hdr, ret);
-
 }
 
-
-struct cmd_def commands[] = {
-	{ "open",	do_open,	},
-	{ "close", 	do_close,	},
+struct cmd_def commands[] = {{
+				     "open",
+				     do_open,
+			     },
+			     {
+				     "close",
+				     do_close,
+			     },
 #ifdef TEST_NETMAP
-	{ "getinfo-legacy",	do_getinfo_legacy,	},
-	{ "regif-legacy",	do_regif_legacy,	},
-	{ "txsync",	do_txsync,	},
-	{ "rxsync",	do_rxsync,	},
+			     {
+				     "getinfo-legacy",
+				     do_getinfo_legacy,
+			     },
+			     {
+				     "regif-legacy",
+				     do_regif_legacy,
+			     },
+			     {
+				     "txsync",
+				     do_txsync,
+			     },
+			     {
+				     "rxsync",
+				     do_rxsync,
+			     },
 #endif /* TEST_NETMAP */
-	{ "dup",	do_dup,		},
-	{ "mmap",	do_mmap,	},
-	{ "anon-mmap",	do_anon_mmap,	},
-	{ "rd",		do_rd,		},
-	{ "wr",		do_wr,		},
-	{ "munmap",	do_munmap,	},
-	{ "poll",	do_poll,	},
-	{ "expr",	do_expr,	},
-	{ "echo",	do_echo,	},
-	{ "vars",	do_vars,	},
-	{ "if",         do_if,          },
-	{ "ring",       do_ring,        },
-	{ "slot",       do_slot,        },
-	{ "buf",        do_buf,         },
-	{ "nmr-legacy",	do_nmr_legacy,	},
-	{ "hdr",	do_hdr,		},
-	{ "ctrl",	do_ctrl		},
-	{ "register",	do_register	}
-};
+			     {
+				     "dup",
+				     do_dup,
+			     },
+			     {
+				     "mmap",
+				     do_mmap,
+			     },
+			     {
+				     "anon-mmap",
+				     do_anon_mmap,
+			     },
+			     {
+				     "rd",
+				     do_rd,
+			     },
+			     {
+				     "wr",
+				     do_wr,
+			     },
+			     {
+				     "munmap",
+				     do_munmap,
+			     },
+			     {
+				     "poll",
+				     do_poll,
+			     },
+			     {
+				     "expr",
+				     do_expr,
+			     },
+			     {
+				     "echo",
+				     do_echo,
+			     },
+			     {
+				     "vars",
+				     do_vars,
+			     },
+			     {
+				     "if",
+				     do_if,
+			     },
+			     {
+				     "ring",
+				     do_ring,
+			     },
+			     {
+				     "slot",
+				     do_slot,
+			     },
+			     {
+				     "buf",
+				     do_buf,
+			     },
+			     {
+				     "nmr-legacy",
+				     do_nmr_legacy,
+			     },
+			     {
+				     "hdr",
+				     do_hdr,
+			     },
+			     {"ctrl", do_ctrl},
+			     {"register", do_register}};
 
 const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);
 
-int find_command(const char* cmd)
+int
+find_command(const char *cmd)
 {
 	return _find_command(commands, N_CMDS, cmd);
 }
 
 #define MAX_CHAN 10
 
-void prompt(FILE *f)
+void
+prompt(FILE *f)
 {
 	if (isatty(fileno(f))) {
 		printf("> ");
@@ -1932,18 +1993,18 @@ void prompt(FILE *f)
 
 struct chan *channels[MAX_CHAN];
 
-void*
+void *
 thread_cmd_loop(void *arg)
 {
 	char buf[1024];
-	FILE *in = (FILE*)arg;
+	FILE *in = (FILE *)arg;
 
 	while (fgets(buf, 1024, in)) {
 		char *cmd;
 		int i;
 
 		cmd = firstarg(buf);
-		i = find_command(cmd);
+		i   = find_command(cmd);
 		if (i < N_CMDS) {
 			commands[i].f();
 			continue;
@@ -1954,7 +2015,8 @@ thread_cmd_loop(void *arg)
 	return NULL;
 }
 
-void do_exit()
+void
+do_exit()
 {
 	output("quit");
 }
@@ -1989,16 +2051,17 @@ cmd_loop(FILE *input)
 		}
 
 		if (strcmp(cmd, "fork") == 0) {
-			int slot = chan_search_free(channels, MAX_CHAN);
+			int slot       = chan_search_free(channels, MAX_CHAN);
 			struct chan *c = NULL;
 			pid_t pid;
-			int p1[2] = { -1, -1};
+			int p1[2] = {-1, -1};
 
 			if (slot == MAX_CHAN) {
 				output("too many channels");
 				continue;
 			}
-			c = channels[slot] = (struct chan*)malloc(sizeof(struct chan));
+			c = channels[slot] =
+				(struct chan *)malloc(sizeof(struct chan));
 			if (c == NULL) {
 				output_err(-1, "malloc");
 				continue;
@@ -2053,7 +2116,7 @@ cmd_loop(FILE *input)
 				output("invalid slot: %s", cmd);
 				continue;
 			}
-			c = channels[slot];
+			c   = channels[slot];
 			ret = kill(c->pid, SIGTERM);
 			output_err(ret, "kill(%d, SIGTERM)=%d", c->pid, ret);
 			if (ret != -1) {
@@ -2065,10 +2128,10 @@ cmd_loop(FILE *input)
 			continue;
 		}
 		if (strcmp(cmd, "thread") == 0) {
-			int slot = chan_search_free(channels, MAX_CHAN);
+			int slot       = chan_search_free(channels, MAX_CHAN);
 			struct chan *c = NULL;
 			pthread_t tid;
-			int p1[2] = { -1, -1};
+			int p1[2] = {-1, -1};
 			int ret;
 			FILE *in = NULL;
 
@@ -2076,7 +2139,8 @@ cmd_loop(FILE *input)
 				output("too many channels");
 				continue;
 			}
-			c = channels[slot] = (struct chan*)malloc(sizeof(struct chan));
+			c = channels[slot] =
+				(struct chan *)malloc(sizeof(struct chan));
 			bzero(c, sizeof(*c));
 			if (pipe(p1) < 0) {
 				output_err(-1, "pipe");
@@ -2094,7 +2158,7 @@ cmd_loop(FILE *input)
 			}
 			ret = pthread_create(&tid, NULL, thread_cmd_loop, in);
 			output_err(ret, "pthread_create() tid=%lu slot=%d",
-				(unsigned long) tid, slot);
+				   (unsigned long)tid, slot);
 			if (ret < 0)
 				goto clean2;
 			c->pid = getpid();
@@ -2125,7 +2189,7 @@ cmd_loop(FILE *input)
 			fclose(c->out);
 			ret = pthread_join(c->tid, NULL);
 			output_err(ret, "pthread_join(%lu)=%d",
-				(unsigned long) c->tid, ret);
+				   (unsigned long)c->tid, ret);
 			if (ret > 0) {
 				free(c);
 				channels[slot] = NULL;
@@ -2163,7 +2227,7 @@ main(int argc, char **argv)
 	if (argc > 1) {
 		for (i = 1; i < argc; i++) {
 			FILE *f;
-		       	if (!strcmp(argv[i], "-")) {
+			if (!strcmp(argv[i], "-")) {
 				f = stdin;
 			} else {
 				f = fopen(argv[i], "r");

From f8ee9608d4c86c2fffcc0f0536893d2e107d3504 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:30:25 +0100
Subject: [PATCH 0512/2207] pipes: fix integration test #12

---
 sys/dev/netmap/netmap_pipe.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 1b7c84478..a0ad22c28 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -566,6 +566,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		return EINVAL;
 	}
 
+	if (req->nr_mode != NR_REG_ALL_NIC) {
+		/* For pipes we currently accept only NR_REG_ALL_NIC. */
+		return EINVAL;
+	}
+
 	/* first, try to find the parent adapter */
 	for (;;) {
 		char nr_name_orig[NETMAP_REQ_IFNAMSIZ];

From 4bff95ba733b94da36741bcb1ee238585ad1d617 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:52:06 +0100
Subject: [PATCH 0513/2207] pipes: accept NR_REG_ONE_NIC but don't accept modes
 involving sw rings

---
 sys/dev/netmap/netmap_pipe.c | 4 ++--
 utils/ctrl-api-test.c        | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index a0ad22c28..6270d692b 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -566,8 +566,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		return EINVAL;
 	}
 
-	if (req->nr_mode != NR_REG_ALL_NIC) {
-		/* For pipes we currently accept only NR_REG_ALL_NIC. */
+	if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) {
+		/* We only accept modes involving hardware rings. */
 		return EINVAL;
 	}
 
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d58f81dac..98a513b1e 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -430,10 +430,10 @@ pipe_master(int fd, struct TestContext *ctx)
 
 	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeid1");
 	ctx->ifname  = pipe_name;
-	ctx->nr_mode = NR_REG_ONE_NIC;
+	ctx->nr_mode = NR_REG_NIC_SW;
 
 	if (port_register(fd, ctx) == 0) {
-		printf("pipes should not accept NR_REG_ONE_NIC\n");
+		printf("pipes should not accept NR_REG_NIC_SW\n");
 		return -1;
 	}
 	ctx->nr_mode = NR_REG_ALL_NIC;

From b6a25d92b6c7965d7b98ab60e00690a5efe703d8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:57:37 +0100
Subject: [PATCH 0514/2207] ci: add control api tests

---
 ci/run-integration-tests | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 3d51146fb..6357471e8 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -1,6 +1,16 @@
 #!/bin/bash -eu
 
 sudo modprobe netmap
+
+# Run control API tests
+pushd .
+cd utils
+make
+sudo ./ctrl-api-test
+popd
+
+# Transmit some packets into VALE ports or pipes, using pkt-gen
 sudo pkt-gen -i vale:x -f tx -n 100 -w0
 sudo pkt-gen -i netmap:pipe{3 -f tx -n 65 -w0
+
 sudo rmmod netmap

From 752482f07f42e2f3d5d3874b25ab5d195aea6766 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 21 Feb 2018 15:14:03 +0100
Subject: [PATCH 0515/2207] bdg_mod_private_data_fn_t type changed,
 netmap_bdg_mod_private_data() changed accordingly

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 sys/dev/netmap/netmap_vale.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 88e8e7bc1..30521965c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1448,7 +1448,7 @@ typedef u_int (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
 		struct netmap_vp_adapter *, void *private_data);
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
-typedef void (*bdg_mod_private_data_fn_t)(void *private_data, void *callback_data);
+typedef int (*bdg_mod_private_data_fn_t)(void **private_data, void *callback_data);
 struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index e63638197..f26a9920f 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1440,7 +1440,7 @@ netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback
 	} else {
 		/* TODO: implement ownership over bridges */
 		BDG_WLOCK(b);
-		callback(b->private_data, callback_data);
+		error = callback((void **)(&b->private_data), callback_data);
 		BDG_WUNLOCK(b);
 	}
 	NMG_UNLOCK();

From bb3212815c1be4c3c1fa75d1c379786a80b74b35 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Feb 2018 16:20:43 +0100
Subject: [PATCH 0516/2207] netmap_reset: remove obsolete code

---
 sys/dev/netmap/netmap.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2d4a6b88e..aca2be900 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3289,16 +3289,6 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 			kring->nr_hwtail -= lim + 1;
 	}
 
-#if 0 // def linux
-	/* XXX check that the mappings are correct */
-	/* need ring_nr, adapter->pdev, direction */
-	buffer_info->dma = dma_map_single(&pdev->dev, addr, adapter->rx_buffer_len, DMA_FROM_DEVICE);
-	if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
-		D("error mapping rx netmap buffer %d", i);
-		// XXX fix error handling
-	}
-
-#endif /* linux */
 	/*
 	 * Wakeup on the individual and global selwait
 	 * We do the wakeup here, but the ring is not yet reconfigured.

From 2ffbd1aee8de75c830bfc20c2e91b245c184f460 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Feb 2018 19:44:19 +0100
Subject: [PATCH 0517/2207] scripts: np: document about git tags

---
 LINUX/scripts/np | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 175f6feb3..ef7f5761e 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -4,6 +4,8 @@
 ## Initial setup: 
 ##
 ## - a git clone of netmap/linux with all the netmap-* branches created (GITDIR)
+##   (also make sure that you have all the git tags in place; you may need to
+##    git fetch --tags from https://github.com/torvalds/linux.git)
 ##
 ## - a directory where the linux trees for each major version of linux can 
 ##   be extracted (LINUX_SOURCES)

From 8e46cdd129a449f53e70818af8155c8d2c9d15c5 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 22 Feb 2018 15:19:20 +0100
Subject: [PATCH 0518/2207] exclusive mode for regops()'ed bridges

---
 sys/dev/netmap/netmap.c        |   4 +-
 sys/dev/netmap/netmap_kern.h   |  12 ++--
 sys/dev/netmap/netmap_legacy.c |   2 +-
 sys/dev/netmap/netmap_vale.c   | 128 ++++++++++++++++++++++++++-------
 4 files changed, 114 insertions(+), 32 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 059fbda4f..851e36f68 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2429,12 +2429,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 #ifdef WITH_VALE
 		case NETMAP_REQ_VALE_ATTACH: {
-			error = nm_bdg_ctl_attach(hdr);
+			error = nm_bdg_ctl_attach(hdr, NULL /* userspace request */);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_DETACH: {
-			error = nm_bdg_ctl_detach(hdr);
+			error = nm_bdg_ctl_detach(hdr, NULL /* userspace request */);
 			break;
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 30521965c..682e74d01 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1017,8 +1017,9 @@ struct netmap_bwrap_adapter {
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
 };
-int nm_bdg_ctl_attach(struct nmreq_header *hdr);
-int nm_bdg_ctl_detach(struct nmreq_header *hdr);
+struct netmap_bdg_ops; /* forward */
+int nm_bdg_ctl_attach(struct nmreq_header *hdr, struct netmap_bdg_ops *);
+int nm_bdg_ctl_detach(struct nmreq_header *hdr, struct netmap_bdg_ops *);
 int nm_bdg_polling(struct nmreq_header *hdr);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
 int netmap_vi_create(struct nmreq_header *hdr, int);
@@ -1444,7 +1445,7 @@ int netmap_get_hw_na(struct ifnet *ifp,
  * NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 to indicate
  * drop.
  */
-typedef u_int (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
+typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
 		struct netmap_vp_adapter *, void *private_data);
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
@@ -1455,7 +1456,7 @@ struct netmap_bdg_ops {
 	bdg_dtor_fn_t	dtor;
 };
 
-u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
+uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *, void *private_data);
 
 #define	NM_BRIDGES		8	/* number of bridges */
@@ -1470,7 +1471,8 @@ struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data);
+#define NM_BDG_EXCLUSIVE	2
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, uint8_t bdg_flags);
 int netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback, void *callback_data);
 int netmap_bdg_config(struct nm_ifreq *nifr);
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 71363474e..aeb1802b4 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -163,7 +163,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		}
 		case NETMAP_BDG_DETACH: {
 			hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			hdr->nr_body = nm_os_malloc(sizeof(struct nmreq_vale_detach));
+			hdr->nr_body = (uint64_t)nm_os_malloc(sizeof(struct nmreq_vale_detach));
 			break;
 		}
 		case NETMAP_BDG_VNET_HDR:
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index f26a9920f..259b7c682 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -206,13 +206,13 @@ struct nm_bridge {
 	/* XXX what is the proper alignment/layout ? */
 	BDG_RWLOCK_T	bdg_lock;	/* protects bdg_ports */
 	int		bdg_namelen;
-	uint32_t	bdg_active_ports; /* 0 means free */
+	uint32_t	bdg_active_ports;
 	char		bdg_basename[IFNAMSIZ];
 
 	/* Indexes of active ports (up to active_ports)
 	 * and all other remaining ports.
 	 */
-	uint8_t		bdg_port_index[NM_BDG_MAXPORTS];
+	uint32_t	bdg_port_index[NM_BDG_MAXPORTS];
 
 	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
 
@@ -235,6 +235,14 @@ struct nm_bridge {
 	void *private_data;
 	struct nm_hash_ent *ht;
 
+	/* currently used to specify if the bridge is free and if it has been put
+	 * in exclusive mode by an external module, see netmap_bdg_regops().
+	 * NM_BDG_EXCLUSIVE == 2 (defined in netmap_kern.h)
+	 */
+#define NM_BDG_ACTIVE	1
+	uint8_t			bdg_flags;
+
+
 #ifdef CONFIG_NET_NS
 	struct net *ns;
 #endif /* CONFIG_NET_NS */
@@ -357,7 +365,7 @@ nm_find_bridge(const char *name, int create)
 	for (i = 0; i < num_bridges; i++) {
 		struct nm_bridge *x = bridges + i;
 
-		if (x->bdg_active_ports == 0) {
+		if (!(x->bdg_flags & NM_BDG_ACTIVE)) {
 			if (create && b == NULL)
 				b = x;	/* record empty slot */
 		} else if (x->bdg_namelen != namelen) {
@@ -385,6 +393,7 @@ nm_find_bridge(const char *name, int create)
 		/* set the default function */
 		b->bdg_ops = &default_bdg_ops;
 		b->private_data = b->ht;
+		b->bdg_flags = NM_BDG_ACTIVE;
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -514,10 +523,20 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 		ND("marking bridge %s as free", b->bdg_basename);
 		nm_os_free(b->ht);
 		b->bdg_ops = NULL;
+		b->bdg_flags = 0; /* marks bridge as free */
 		NM_BNS_PUT(b);
 	}
 }
 
+static void
+netmap_bdg_free(struct nm_bridge *b)
+{
+	uint32_t i;
+	for (i = 0; i < b->bdg_active_ports; ++i) {
+		netmap_bdg_detach_common(b, b->bdg_port_index[i], -1);
+	}
+}
+
 /* nm_bdg_ctl callback for VALE ports */
 static int
 netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
@@ -580,10 +599,10 @@ nm_vi_create(struct nmreq_header *hdr)
 	regreq.nr_rx_rings = req->nr_rx_rings;
 	regreq.nr_mem_id = req->nr_mem_id;
 	hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-	hdr->nr_body = ®req;
+	hdr->nr_body = (uint64_t)®req;
 	error = netmap_vi_create(hdr, 0 /* no autodelete */);
 	hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	hdr->nr_body = req;
+	hdr->nr_body = (uint64_t)req;
         /* Write back to the original struct. */
 	req->nr_tx_slots = regreq.nr_tx_slots;
 	req->nr_rx_slots = regreq.nr_rx_slots;
@@ -898,19 +917,28 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 }
 
 
-/* Process NETMAP_REQ_VALE_ATTACH. */
+/* Process NETMAP_REQ_VALE_ATTACH.
+ * bdg_ops is used to check ownership over a bridge in exclusive mode,
+ * see netmap_bdg_regops() to se how it works.
+ */
 int
-nm_bdg_ctl_attach(struct nmreq_header *hdr)
+nm_bdg_ctl_attach(struct nmreq_header *hdr, struct netmap_bdg_ops *bdg_ops)
 {
 	struct nmreq_vale_attach *req =
 		(struct nmreq_vale_attach *)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
+	struct nm_bridge *b = NULL;
 	int error;
 
 	NMG_LOCK();
-	req->port_index = NM_BDG_NOPORT;
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+	if (b && (b->bdg_flags & NM_BDG_EXCLUSIVE) && b->bdg_ops != bdg_ops) {
+		error = EACCES;
+		goto unlock_exit;
+	}
 
 	if (req->reg.nr_mem_id) {
 		nmd = netmap_mem_find(req->reg.nr_mem_id);
@@ -927,8 +955,9 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 		goto unref_exit;
 	}
 	error = netmap_get_bdg_na(hdr, &na, nmd, 1 /* create if not exists */);
-	if (error) /* no device */
+	if (error) /* no device */ {
 		goto unlock_exit;
+	}
 
 	if (na == NULL) { /* VALE prefix missing */
 		error = EINVAL;
@@ -967,16 +996,27 @@ nm_is_bwrap(struct netmap_adapter *na)
 	return na->nm_register == netmap_bwrap_reg;
 }
 
-/* Process NETMAP_REQ_VALE_DETACH. */
+/* Process NETMAP_REQ_VALE_DETACH.
+ * bdg_ops is used to check ownership over a bridge in exclusive mode,
+ * see netmap_bdg_regops() to se how it works.
+ */
 int
-nm_bdg_ctl_detach(struct nmreq_header *hdr)
+nm_bdg_ctl_detach(struct nmreq_header *hdr, struct netmap_bdg_ops *bdg_ops)
 {
-	struct nmreq_vale_detach *nmreq_det = hdr->nr_body;
+	struct nmreq_vale_detach *nmreq_det = (void *)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
+	struct nm_bridge *b = NULL;
 	int error;
 
 	NMG_LOCK();
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+	if (b && (b->bdg_flags & NM_BDG_EXCLUSIVE) && b->bdg_ops != bdg_ops) {
+		error = EACCES;
+		goto unlock_exit;
+	}
+
 	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
@@ -1387,37 +1427,77 @@ netmap_bdg_list(struct nmreq_header *hdr)
  * to set configure/lookup/dtor functions of a VALE instance.
  * Register callbacks to the given bridge. 'name' may be just
  * bridge's name (including ':' if it is not just NM_BDG_NAME).
+ *
+ * bdg_flags at the moment only supports NM_BDG_EXCLUSIVE which can be specified
+ * only for not yet existing bridges (they will be created during the regops).
+ * Exclusive mode allows only the external module which regops()'ed the bridge
+ * to attach and detach its ports.
+ * The permission check is made through the second parameter of nm_bdg_ctl_attach()
+ * and nm_bdg_ctl_detach(), which for bridges with the NM_BDG_EXCLUSIVE flag is
+ * compared against the netmap_bdg_ops pointer of the bridge.
+ *
  * Called without NMG_LOCK.
  */
  
 int
-netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data)
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, uint8_t flags)
 {
 	struct nm_bridge *b;
 	int error = 0;
 
 	NMG_LOCK();
 	b = nm_find_bridge(name, 0 /* don't create */);
-	if (!b) {
-		error = EINVAL;
-	} else if (!bdg_ops) {
-		BDG_WLOCK(b);
-		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-		b->bdg_ops = &default_bdg_ops;
-		b->private_data = b->ht;
-		BDG_WUNLOCK(b);
+	if (!bdg_ops) {
+		/* resetting the bridge, it must exists */
+		if (!b) {
+			error = EINVAL;
+			goto unlock_regops;
+		}
+
+		if (b->bdg_active_ports == 0 && (b->bdg_flags & NM_BDG_EXCLUSIVE)) {
+			/* bridges in exclusive mode are created without ports attached
+			 * therefore we might receive a reset regops() while the
+			 * bridge is effectively empty, in this case we free the bridge
+			 */
+			netmap_bdg_free(b);
+		} else {
+			BDG_WLOCK(b);
+			bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+			b->bdg_ops = &default_bdg_ops;
+			b->private_data = b->ht;
+			b->bdg_flags &= ~NM_BDG_EXCLUSIVE;
+			BDG_WUNLOCK(b);
+		}
 	} else {
+		/* modifying the bridge, if NM_BDG_EXCLUSIVE is set the bridge cannot have
+		 * ports alredy attached (aka we need to create it on the spot)
+		 */
+		if (flags & NM_BDG_EXCLUSIVE) {
+			if (b) {
+				error = EINVAL;
+				goto unlock_regops;
+			}
+
+			b = nm_find_bridge(name, 1 /* create */);
+		}
+		if (!b) {
+			error = (flags & NM_BDG_EXCLUSIVE) ? ENOMEM : EINVAL;
+			goto unlock_regops;
+		}
+
 		BDG_WLOCK(b);
 		if (b->bdg_ops != &default_bdg_ops) {
 			error = EINVAL;
 		} else {
-			b->bdg_ops = bdg_ops;
 			b->private_data = private_data;
+			b->bdg_flags |= flags;
+			b->bdg_ops = bdg_ops;
 		}
 		BDG_WUNLOCK(b);
 	}
-	NMG_UNLOCK();
 
+unlock_regops:
+	NMG_UNLOCK();
 	return error;
 }
 
@@ -1699,7 +1779,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
  * and then returns the destination port index, and the
  * ring in *dst_ring (at the moment, always use ring 0)
  */
-u_int
+uint32_t
 netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *na, void *private_data)
 {

From c20442bcd7c330165a17541e11024a03b02fc6f5 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 22 Feb 2018 17:07:01 +0100
Subject: [PATCH 0519/2207] fixed array type inside netmap_bdg_detach_common()

---
 sys/dev/netmap/netmap_vale.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 259b7c682..5808c4cf1 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -468,7 +468,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 {
 	int s_hw = hw, s_sw = sw;
 	int i, lim =b->bdg_active_ports;
-	uint8_t tmp[NM_BDG_MAXPORTS];
+	uint32_t tmp[NM_BDG_MAXPORTS];
 
 	/*
 	New algorithm:

From 676304aafd316d68e6d78ce90b657a5c9457e269 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 23 Feb 2018 17:19:25 +0100
Subject: [PATCH 0520/2207] nm_bdg_flush() searches the nm_bdg_fwd where the
 virtio header ends and directly passes that to the lookup function,
 netmap_bdg_learning() changed accordingly

---
 sys/dev/netmap/netmap_kern.h |  2 +-
 sys/dev/netmap/netmap_vale.c | 34 ++++++++++++++++++----------------
 2 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 682e74d01..69b703dfa 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2000,7 +2000,7 @@ void nm_os_mitigation_cleanup(struct nm_generic_mit *mit);
 struct nm_bdg_fwd {	/* forwarding entry for a bridge */
 	void *ft_buf;		/* netmap or indirect buffer */
 	uint8_t ft_frags;	/* how many fragments (only on 1st frag) */
-	uint8_t _ft_port;	/* dst port (unused) */
+	uint16_t ft_offset;	/* dst port (unused) */
 	uint16_t ft_flags;	/* flags, e.g. indirect */
 	uint16_t ft_len;	/* src fragment len */
 	uint16_t ft_next;	/* next packet to same destination */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 5808c4cf1..70cdeebb7 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1640,6 +1640,7 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end)
 
 		ft[ft_i].ft_len = slot->len;
 		ft[ft_i].ft_flags = slot->flags;
+		ft[ft_i].ft_offset = 0;
 
 		ND("flags is 0x%x", slot->flags);
 		/* we do not use the buf changed flag, but we still need to reset it */
@@ -1791,18 +1792,9 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 	uint64_t smac, dmac;
 	uint8_t indbuf[12];
 
-	/* safety check, unfortunately we have many cases */
-	if (buf_len >= 14 + na->up.virt_hdr_len) {
-		/* virthdr + mac_hdr in the same slot */
-		buf += na->up.virt_hdr_len;
-		buf_len -= na->up.virt_hdr_len;
-	} else if (buf_len == na->up.virt_hdr_len && ft->ft_flags & NS_MOREFRAG) {
-		/* only header in first fragment */
-		ft++;
-		buf = ft->ft_buf;
-		buf_len = ft->ft_len;
-	} else {
-		RD(5, "invalid buf format, length %d", buf_len);
+	buf = ft->ft_buf + ft->ft_offset;
+	buf_len = ft->ft_len - ft->ft_offset;
+	if (buf_len < 14) {
 		return NM_BDG_NOPORT;
 	}
 
@@ -1941,13 +1933,23 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		uint8_t dst_ring = ring_nr; /* default, same ring as origin */
 		uint16_t dst_port, d_i;
 		struct nm_bdg_q *d;
+		struct nm_bdg_fwd *start_ft = NULL;
 
 		ND("slot %d frags %d", i, ft[i].ft_frags);
-		/* Drop the packet if the virtio-net header is not into the first
-		   fragment nor at the very beginning of the second. */
-		if (unlikely(na->up.virt_hdr_len > ft[i].ft_len))
+
+		if (na->up.virt_hdr_len < ft[i].ft_len) {
+			ft[i].ft_offset = na->up.virt_hdr_len;
+			start_ft = &ft[i];
+		} else if (unlikely(na->up.virt_hdr_len == ft[i].ft_len && ft[i].ft_flags & NS_MOREFRAG)) {
+			ft[i].ft_offset = ft[i].ft_len;
+			start_ft = &ft[i+1];
+		} else {
+			/* Drop the packet if the virtio-net header is not into the first
+			 * fragment nor at the very beginning of the second.
+			 */
 			continue;
-		dst_port = b->bdg_ops->lookup(&ft[i], &dst_ring, na, b->private_data);
+		}
+		dst_port = b->bdg_ops->lookup(start_ft, &dst_ring, na, b->private_data);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)

From f1a75e59525b92d8f164b3802f9878bbf2a13e7d Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 23 Feb 2018 19:41:00 +0100
Subject: [PATCH 0521/2207] updated ctrl-api-test.c to reflect detach changes

---
 utils/ctrl-api-test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 98a513b1e..cfe6b2922 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -214,6 +214,7 @@ static int
 vale_detach(int fd, struct TestContext *ctx)
 {
 	struct nmreq_header hdr;
+	struct nmreq_vale_detach req;
 	char vpname[256];
 	int ret;
 
@@ -222,6 +223,7 @@ vale_detach(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	hdr.nr_body = (uint64_t)(uintptr_t)&req;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");

From 82ba395c48abe3b94676ae42b53213cc6a5f0200 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 24 Feb 2018 15:57:56 +0100
Subject: [PATCH 0522/2207] linux: emulated netmap: change qdisc using netlink

---
 LINUX/netmap_linux.c            | 205 +++++++++++++++++---------------
 sys/dev/netmap/netmap_freebsd.c |  14 ++-
 sys/dev/netmap/netmap_generic.c |  23 +---
 3 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index b14e899fc..66f706ca7 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 #ifdef NETMAP_LINUX_HAVE_SCHED_MM
 #include 
 #endif /* NETMAP_LINUX_HAVE_SCHED_MM */
@@ -415,19 +416,22 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 #else /* HAVE_RX_REGISTER */
     struct netmap_adapter *na = &gna->up.up;
     struct ifnet *ifp = netmap_generic_getifp(gna);
+    int ret = 0;
 
     if (!ifp) {
         D("Failed to get ifp");
         return -EBUSY;
     }
 
+    nm_os_ifnet_lock();
     if (intercept) {
-        return -netdev_rx_handler_register(ifp,
+        ret = -netdev_rx_handler_register(ifp,
                 &linux_generic_rx_handler, na);
     } else {
         netdev_rx_handler_unregister(ifp);
-        return 0;
     }
+    nm_os_ifnet_unlock();
+    return ret;
 #endif /* HAVE_RX_REGISTER */
 }
 
@@ -557,15 +561,22 @@ generic_qdisc_dequeue(struct Qdisc *qdisc)
 	return m;
 }
 
+static struct mbuf *
+generic_qdisc_peek(struct Qdisc *qdisc)
+{
+	return qdisc_peek_head(qdisc);
+}
+
 static struct Qdisc_ops
 generic_qdisc_ops __read_mostly = {
-	.id		= "netmap_generic",
+	.id		= "netmapemu",
 	.priv_size	= sizeof(struct nm_generic_qdisc),
+	.enqueue	= generic_qdisc_enqueue,
+	.dequeue	= generic_qdisc_dequeue,
+	.peek		= generic_qdisc_peek,
 	.init		= generic_qdisc_init,
 	.reset		= qdisc_reset_queue,
 	.change		= generic_qdisc_init,
-	.enqueue	= generic_qdisc_enqueue,
-	.dequeue	= generic_qdisc_dequeue,
 	.dump		= NULL,
 	.owner		= THIS_MODULE,
 };
@@ -573,108 +584,79 @@ generic_qdisc_ops __read_mostly = {
 static int
 nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 {
-	struct netmap_adapter *na = &gna->up.up;
+	const char *qdisc_name = intercept ? generic_qdisc_ops.id : "pfifo";
 	struct ifnet *ifp = netmap_generic_getifp(gna);
-	struct nm_generic_qdisc *qdiscopt = NULL;
-	struct Qdisc *fqdisc = NULL;
-	struct nlattr *nla = NULL;
-	struct netdev_queue *txq;
-	unsigned int i;
+	struct socket *sock = NULL;
+	struct sockaddr_nl saddr = {
+		.nl_family = AF_NETLINK,
+		.nl_groups = 0,
+		.nl_pid = 0,
+	};
+	int ret = 0;
 
 	if (!gna->txqdisc) {
 		return 0;
 	}
 
-	if (intercept) {
-		nla = kmalloc(nla_attr_size(sizeof(*qdiscopt)),
-				GFP_KERNEL);
-		if (!nla) {
-			D("Failed to allocate netlink attribute");
-			return -1;
-		}
-		nla->nla_type = RTM_NEWQDISC;
-		nla->nla_len = nla_attr_size(sizeof(*qdiscopt));
-		qdiscopt = (struct nm_generic_qdisc *)nla_data(nla);
-		memset(qdiscopt, 0, sizeof(*qdiscopt));
-		qdiscopt->limit = na->num_tx_desc;
-	}
-
-	if (ifp->flags & IFF_UP) {
-		dev_deactivate(ifp);
-	}
-
-	/* Replace the current qdiscs with our own. */
-	for (i = 0; i < ifp->real_num_tx_queues; i++) {
-		struct Qdisc *nqdisc = NULL;
-		struct Qdisc *oqdisc;
-		int err;
-
-		txq = netdev_get_tx_queue(ifp, i);
-
-		if (intercept) {
-			/* This takes a refcount to netmap module, alloc the
-			 * qdisc and calls the init() op with NULL netlink
-			 * attribute. */
-			nqdisc = qdisc_create_dflt(
-#ifndef NETMAP_LINUX_QDISC_CREATE_DFLT_3ARGS
-					ifp,
-#endif  /* NETMAP_LINUX_QDISC_CREATE_DFLT_3ARGS */
-					txq, &generic_qdisc_ops,
-					TC_H_UNSPEC);
-			if (!nqdisc) {
-				D("Failed to create qdisc");
-				goto qdisc_create;
-			}
-			fqdisc = fqdisc ?: nqdisc;
-
-			/* Call the change() op passing a valid netlink
-			 * attribute. This is used to set the queue idx. */
-			qdiscopt->qidx = i;
-			err = nqdisc->ops->change(nqdisc, nla);
-			if (err) {
-				D("Failed to init qdisc");
-				goto qdisc_create;
-			}
-		}
-
-		oqdisc = dev_graft_qdisc(txq, nqdisc);
-		/* We can call this also with
-		 * odisc == &noop_qdisc, since the noop
-		 * qdisc has the TCQ_F_BUILTIN flag set,
-		 * and so qdisc_destroy will skip it. */
-		qdisc_destroy(oqdisc);
+	ret = sock_create_kern(current->nsproxy->net_ns, AF_NETLINK, SOCK_RAW,
+				NETLINK_ROUTE, &sock);
+	if (ret) {
+		D("Failed to create netlink socket (err=%d)", ret);
+		return -ret;
 	}
 
-	kfree(nla);
-
-	if (ifp->qdisc) {
-		qdisc_destroy(ifp->qdisc);
-	}
-	if (intercept) {
-#ifdef NETMAP_LINUX_HAVE_REFCOUNT_T
-		refcount_inc(&fqdisc->refcnt);
-#else  /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
-		atomic_inc(&fqdisc->refcnt);
-#endif /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
-		ifp->qdisc = fqdisc;
-	} else {
-		ifp->qdisc = &noop_qdisc;
+	ret = kernel_bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
+	if (ret) {
+		D("Failed to bind() netlink socket (err=%d)", ret);
+		goto release;
 	}
 
-	if (ifp->flags & IFF_UP) {
-		dev_activate(ifp);
-	}
-
-	return 0;
-
-qdisc_create:
-	if (nla) {
-		kfree(nla);
+	{
+		struct msghdr msg = {
+			.msg_name = (struct sockaddr *)&saddr,
+			.msg_namelen = sizeof(saddr),
+			.msg_flags = /* MSG_DONTWAIT */0,
+		};
+		struct {
+			struct nlmsghdr hdr;
+			struct tcmsg tcmsg;
+			char buf[64];
+		} nlreq = {
+			.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
+			.hdr.nlmsg_type = RTM_NEWQDISC,
+			.hdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_REPLACE|NLM_F_CREATE,
+			.hdr.nlmsg_seq = 1,
+			.hdr.nlmsg_pid = 0,
+			.tcmsg.tcm_family = AF_UNSPEC,
+			.tcmsg.tcm_ifindex = ifp->ifindex,
+			.tcmsg.tcm_handle = 0,
+			.tcmsg.tcm_parent = TC_H_ROOT,
+			.tcmsg.tcm_info = 0,
+		};
+		struct nlattr *attr;
+		struct iovec iov;
+
+		attr = (struct nlattr *)(((void *)&nlreq.hdr) +
+					 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
+		attr->nla_len = NLA_HDRLEN + strlen(qdisc_name) + 1;
+		attr->nla_type = TCA_KIND;
+		strcpy(((void *)attr) + NLA_HDRLEN, qdisc_name);
+		nlreq.hdr.nlmsg_len = NLMSG_ALIGN(nlreq.hdr.nlmsg_len) +
+					NLA_ALIGN(attr->nla_len);
+
+		iov.iov_base = (void *)&nlreq;
+		iov.iov_len = nlreq.hdr.nlmsg_len;
+		ret = kernel_sendmsg(sock, &msg, (struct kvec *)&iov, 1,
+					iov.iov_len);
+		if (ret != iov.iov_len) {
+			D("Failed to sendmsg to netlink socket (err=%d)", ret);
+			goto release;
+		}
+		ret = 0;
 	}
-
-	nm_os_catch_qdisc(gna, 0);
-
-	return -1;
+release:
+	sock_release(sock);
+	return -ret;
 }
 
 /* Must be called under rtnl. */
@@ -695,6 +677,8 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 		return err;
 	}
 
+	nm_os_ifnet_lock();
+
 	if (intercept) {
 		/*
 		 * Save the old pointer to the netdev_ops,
@@ -720,6 +704,8 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 		ifp->netdev_ops = (void *)na->if_transmit;
 	}
 
+	nm_os_ifnet_unlock();
+
 	return 0;
 }
 
@@ -2042,7 +2028,7 @@ netmap_sink_init(void)
 
 	netdev = alloc_etherdev(0);
 	if (!netdev) {
-		return ENOMEM;
+		return -ENOMEM;
 	}
 	netdev->netdev_ops = &nm_sink_netdev_ops ;
 	strncpy(netdev->name, "nmsink", sizeof(netdev->name) - 1);
@@ -2102,20 +2088,41 @@ static int linux_netmap_init(void)
 
 	err = ptnetmap_guest_init();
 	if (err) {
-		return err;
+		goto netmap_fini;
 	}
 #ifdef WITH_SINK
 	err = netmap_sink_init();
 	if (err) {
-		D("Warning: could not init netmap sink interface");
+		D("Error: could not init netmap sink interface");
+		goto ptnetmap_fini;
 	}
 #endif /* WITH_SINK */
+#ifdef WITH_GENERIC
+	err = register_qdisc(&generic_qdisc_ops);
+	if (err) {
+		D("Error: failed to register qdisc for emulated netmap (err=%d)", err);
+		goto sink_fini;
+	}
+#endif /* WITH_GENERIC */
 	return 0;
+
+sink_fini:
+#ifdef WITH_SINK
+	netmap_sink_fini();
+ptnetmap_fini:
+#endif /* WITH_SINK */
+        ptnetmap_guest_fini();
+netmap_fini:
+	netmap_fini();
+	return err;
 }
 
 
 static void linux_netmap_fini(void)
 {
+#ifdef WITH_GENERIC
+	unregister_qdisc(&generic_qdisc_ops);
+#endif /* WITH_GENERIC */
 #ifdef WITH_SINK
 	netmap_sink_fini();
 #endif /* WITH_SINK */
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 4cf7f3e14..742dbb32e 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -292,24 +292,30 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 {
 	struct netmap_adapter *na = &gna->up.up;
 	struct ifnet *ifp = na->ifp;
+	int ret = 0;
 
+	nm_os_ifnet_lock();
 	if (intercept) {
 		if (gna->save_if_input) {
 			D("cannot intercept again");
-			return EINVAL; /* already set */
+			ret = EINVAL; /* already set */
+			goto out;
 		}
 		gna->save_if_input = ifp->if_input;
 		ifp->if_input = freebsd_generic_rx_handler;
 	} else {
 		if (!gna->save_if_input){
 			D("cannot restore");
-			return EINVAL;  /* not saved */
+			ret = EINVAL;  /* not saved */
+			goto out;
 		}
 		ifp->if_input = gna->save_if_input;
 		gna->save_if_input = NULL;
 	}
+out:
+	nm_os_ifnet_unlock();
 
-	return 0;
+	return ret;
 }
 
 
@@ -325,12 +331,14 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 	struct netmap_adapter *na = &gna->up.up;
 	struct ifnet *ifp = netmap_generic_getifp(gna);
 
+	nm_os_ifnet_lock();
 	if (intercept) {
 		na->if_transmit = ifp->if_transmit;
 		ifp->if_transmit = netmap_transmit;
 	} else {
 		ifp->if_transmit = na->if_transmit;
 	}
+	nm_os_ifnet_unlock();
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 08b8b1ee4..95f4e993f 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -84,8 +84,6 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap_generic.c 274353 2014-11-10 20:19
 #include 
 #include 
 
-#define rtnl_lock()	ND("rtnl_lock called")
-#define rtnl_unlock()	ND("rtnl_unlock called")
 #define MBUF_RXQ(m)	((m)->m_pkthdr.flowid)
 #define smp_mb()
 
@@ -204,8 +202,6 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 
 #include "win_glue.h"
 
-#define rtnl_lock()	ND("rtnl_lock called")
-#define rtnl_unlock()	ND("rtnl_unlock called")
 #define MBUF_TXQ(m) 	0//((m)->m_pkthdr.flowid)
 #define MBUF_RXQ(m)	    0//((m)->m_pkthdr.flowid)
 #define smp_mb()		//XXX: to be correctly defined
@@ -214,7 +210,6 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 
 #include "bsd_glue.h"
 
-#include     /* rtnl_[un]lock() */
 #include       /* struct ethtool_ops, get_ringparam */
 #include 
 
@@ -343,17 +338,13 @@ generic_netmap_unregister(struct netmap_adapter *na)
 	int i, r;
 
 	if (na->active_fds == 0) {
-		rtnl_lock();
-
 		na->na_flags &= ~NAF_NETMAP_ON;
 
-		/* Release packet steering control. */
-		nm_os_catch_tx(gna, 0);
-
 		/* Stop intercepting packets on the RX path. */
 		nm_os_catch_rx(gna, 0);
 
-		rtnl_unlock();
+		/* Release packet steering control. */
+		nm_os_catch_tx(gna, 0);
 	}
 
 	for_each_rx_kring_h(r, kring, na) {
@@ -514,24 +505,20 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 	}
 
 	if (na->active_fds == 0) {
-		rtnl_lock();
-
 		/* Prepare to intercept incoming traffic. */
 		error = nm_os_catch_rx(gna, 1);
 		if (error) {
 			D("nm_os_catch_rx(1) failed (%d)", error);
-			goto register_handler;
+			goto free_tx_pools;
 		}
 
-		/* Make netmap control the packet steering. */
+		/* Let netmap control the packet steering. */
 		error = nm_os_catch_tx(gna, 1);
 		if (error) {
 			D("nm_os_catch_tx(1) failed (%d)", error);
 			goto catch_rx;
 		}
 
-		rtnl_unlock();
-
 		na->na_flags |= NAF_NETMAP_ON;
 
 #ifdef RATE_GENERIC
@@ -552,8 +539,6 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 	/* Here (na->active_fds == 0) holds. */
 catch_rx:
 	nm_os_catch_rx(gna, 0);
-register_handler:
-	rtnl_unlock();
 free_tx_pools:
 	for_each_tx_kring(r, kring, na) {
 		mtx_destroy(&kring->tx_event_lock);

From 6e42440f1127b3ba6657c1dc944d1fbf72541137 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 24 Feb 2018 17:04:46 +0100
Subject: [PATCH 0523/2207] linux: catch qdisc: add support for multiqueue
 devices

---
 LINUX/netmap_linux.c | 139 +++++++++++++++++++++++++++----------------
 1 file changed, 87 insertions(+), 52 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 66f706ca7..8cea87415 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -582,21 +582,39 @@ generic_qdisc_ops __read_mostly = {
 };
 
 static int
-nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
+tc_configure(struct ifnet *ifp, const char *qdisc_name,
+		uint32_t parent, uint32_t handle)
 {
-	const char *qdisc_name = intercept ? generic_qdisc_ops.id : "pfifo";
-	struct ifnet *ifp = netmap_generic_getifp(gna);
-	struct socket *sock = NULL;
 	struct sockaddr_nl saddr = {
 		.nl_family = AF_NETLINK,
 		.nl_groups = 0,
 		.nl_pid = 0,
 	};
-	int ret = 0;
-
-	if (!gna->txqdisc) {
-		return 0;
-	}
+	struct msghdr msg = {
+		.msg_name = (struct sockaddr *)&saddr,
+		.msg_namelen = sizeof(saddr),
+		.msg_flags = /* MSG_DONTWAIT */0,
+	};
+	struct {
+		struct nlmsghdr hdr;
+		struct tcmsg tcmsg;
+		char buf[64];
+	} nlreq = {
+		.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
+		.hdr.nlmsg_type = RTM_NEWQDISC,
+		.hdr.nlmsg_flags = NLM_F_REQUEST|/*NLM_F_ACK|*/NLM_F_REPLACE|NLM_F_CREATE,
+		.hdr.nlmsg_seq = 1,
+		.hdr.nlmsg_pid = 0,
+		.tcmsg.tcm_family = AF_UNSPEC,
+		.tcmsg.tcm_ifindex = ifp->ifindex,
+		.tcmsg.tcm_handle = handle,
+		.tcmsg.tcm_parent = parent,
+		.tcmsg.tcm_info = 0,
+	};
+	struct socket *sock = NULL;
+	struct nlattr *attr;
+	struct iovec iov;
+	int ret;
 
 	ret = sock_create_kern(current->nsproxy->net_ns, AF_NETLINK, SOCK_RAW,
 				NETLINK_ROUTE, &sock);
@@ -605,58 +623,75 @@ nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 		return -ret;
 	}
 
+
 	ret = kernel_bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
 	if (ret) {
 		D("Failed to bind() netlink socket (err=%d)", ret);
 		goto release;
 	}
 
-	{
-		struct msghdr msg = {
-			.msg_name = (struct sockaddr *)&saddr,
-			.msg_namelen = sizeof(saddr),
-			.msg_flags = /* MSG_DONTWAIT */0,
-		};
-		struct {
-			struct nlmsghdr hdr;
-			struct tcmsg tcmsg;
-			char buf[64];
-		} nlreq = {
-			.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
-			.hdr.nlmsg_type = RTM_NEWQDISC,
-			.hdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_REPLACE|NLM_F_CREATE,
-			.hdr.nlmsg_seq = 1,
-			.hdr.nlmsg_pid = 0,
-			.tcmsg.tcm_family = AF_UNSPEC,
-			.tcmsg.tcm_ifindex = ifp->ifindex,
-			.tcmsg.tcm_handle = 0,
-			.tcmsg.tcm_parent = TC_H_ROOT,
-			.tcmsg.tcm_info = 0,
-		};
-		struct nlattr *attr;
-		struct iovec iov;
-
-		attr = (struct nlattr *)(((void *)&nlreq.hdr) +
-					 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
-		attr->nla_len = NLA_HDRLEN + strlen(qdisc_name) + 1;
-		attr->nla_type = TCA_KIND;
-		strcpy(((void *)attr) + NLA_HDRLEN, qdisc_name);
-		nlreq.hdr.nlmsg_len = NLMSG_ALIGN(nlreq.hdr.nlmsg_len) +
-					NLA_ALIGN(attr->nla_len);
-
-		iov.iov_base = (void *)&nlreq;
-		iov.iov_len = nlreq.hdr.nlmsg_len;
-		ret = kernel_sendmsg(sock, &msg, (struct kvec *)&iov, 1,
-					iov.iov_len);
-		if (ret != iov.iov_len) {
-			D("Failed to sendmsg to netlink socket (err=%d)", ret);
-			goto release;
-		}
-		ret = 0;
+	attr = (struct nlattr *)(((void *)&nlreq.hdr) +
+				 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
+	attr->nla_len = NLA_HDRLEN + strlen(qdisc_name) + 1;
+	attr->nla_type = TCA_KIND;
+	strcpy(((void *)attr) + NLA_HDRLEN, qdisc_name);
+	nlreq.hdr.nlmsg_len = NLMSG_ALIGN(nlreq.hdr.nlmsg_len) +
+				NLA_ALIGN(attr->nla_len);
+
+	iov.iov_base = (void *)&nlreq;
+	iov.iov_len = nlreq.hdr.nlmsg_len;
+	ret = kernel_sendmsg(sock, &msg, (struct kvec *)&iov, 1,
+				iov.iov_len);
+	if (ret != iov.iov_len) {
+		D("Failed to sendmsg to netlink socket (err=%d)", ret);
+		ret = -EINVAL;
+		goto release;
 	}
+	ret = 0;
+
+	D("ifp %s qdisc %s parent %u handle %u", ifp->name, qdisc_name, parent, handle);
+
 release:
 	sock_release(sock);
-	return -ret;
+
+	return ret;
+}
+
+static int
+nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
+{
+	struct ifnet *ifp = netmap_generic_getifp(gna);
+	struct netmap_adapter *na = &gna->up.up;
+	bool multiqueue = (na->num_tx_rings > 1);
+	const char *qdisc_name;
+	static uint32_t root_handle_cnt = 18;
+	uint32_t root_handle = multiqueue ? root_handle_cnt++ : 0;
+	int ret = 0;
+
+	if (!gna->txqdisc) {
+		return 0;
+	}
+
+	qdisc_name = multiqueue ? "mq" :
+			(intercept ? generic_qdisc_ops.id : "pfifo");
+	/* Configure root qdisc.
+	 * sudo tc qdisc replace dev ifp->name root handle @root_handle: qdisc_name */
+	ret = tc_configure(ifp, qdisc_name, /*parent=*/TC_H_ROOT,
+				/*handle=*/root_handle << 16);
+	if (ret) {
+		return -ret;
+	}
+	if (intercept && multiqueue) {
+		/* Configure per-queue qdisc. */
+		int i;
+		qdisc_name = (intercept ? generic_qdisc_ops.id : "pfifo");
+		for (i = 0; i < na->num_tx_rings; i++) {
+			tc_configure(ifp, qdisc_name,
+				/*parent=*/(root_handle << 16) | (i+1),
+				/*handle=*/0);
+		}
+	}
+	return 0;
 }
 
 /* Must be called under rtnl. */

From 0d96e93e051f91a63d7e77e9b901f44ea764ee33 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 24 Feb 2018 18:42:17 +0100
Subject: [PATCH 0524/2207] linux: emulated: add support for netmapemu qdisc
 option

---
 LINUX/netmap_linux.c | 49 +++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 19 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 8cea87415..2b669ba95 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -476,7 +476,6 @@ generic_ndo_start_xmit(struct mbuf *m, struct ifnet *ifp)
 }
 
 struct nm_generic_qdisc {
-	unsigned int qidx;
 	unsigned int limit;
 };
 
@@ -489,21 +488,18 @@ generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt)
 	 * always use our priv->limit, for simplicity. */
 
 	priv = qdisc_priv(qdisc);
-	priv->qidx = 0;
 	priv->limit = 1024; /* This is going to be overridden. */
 
 	if (opt) {
-		struct nm_generic_qdisc *qdiscopt = nla_data(opt);
+		uint32_t *limit = nla_data(opt);
 
-		if (nla_len(opt) < sizeof(*qdiscopt)) {
+		if (nla_len(opt) < sizeof(*limit)) {
 			D("Invalid netlink attribute");
 			return EINVAL;
 		}
 
-		priv->qidx = qdiscopt->qidx;
-		priv->limit = qdiscopt->limit;
-		D("Qdisc #%d initialized with max_len = %u", priv->qidx,
-				                             priv->limit);
+		priv->limit = *limit;
+		D("Qdisc initialized with max_len = %u", priv->limit);
 	}
 
 	/* Qdisc bypassing is not an option for now.
@@ -583,7 +579,7 @@ generic_qdisc_ops __read_mostly = {
 
 static int
 tc_configure(struct ifnet *ifp, const char *qdisc_name,
-		uint32_t parent, uint32_t handle)
+		uint32_t parent, uint32_t handle, uint32_t limit)
 {
 	struct sockaddr_nl saddr = {
 		.nl_family = AF_NETLINK,
@@ -598,7 +594,7 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 	struct {
 		struct nlmsghdr hdr;
 		struct tcmsg tcmsg;
-		char buf[64];
+		char buf[100];
 	} nlreq = {
 		.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
 		.hdr.nlmsg_type = RTM_NEWQDISC,
@@ -612,7 +608,8 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 		.tcmsg.tcm_info = 0,
 	};
 	struct socket *sock = NULL;
-	struct nlattr *attr;
+	struct nlattr *attr_kind;
+	struct nlattr *attr_opt;
 	struct iovec iov;
 	int ret;
 
@@ -630,13 +627,25 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 		goto release;
 	}
 
-	attr = (struct nlattr *)(((void *)&nlreq.hdr) +
+	/* Push TCA_KIND attr. */
+	attr_kind = (struct nlattr *)(((void *)&nlreq.hdr) +
 				 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
-	attr->nla_len = NLA_HDRLEN + strlen(qdisc_name) + 1;
-	attr->nla_type = TCA_KIND;
-	strcpy(((void *)attr) + NLA_HDRLEN, qdisc_name);
+	attr_kind->nla_len = NLA_HDRLEN + strlen(qdisc_name) + 1;
+	attr_kind->nla_type = TCA_KIND;
+	strcpy(((void *)attr_kind) + NLA_HDRLEN, qdisc_name);
 	nlreq.hdr.nlmsg_len = NLMSG_ALIGN(nlreq.hdr.nlmsg_len) +
-				NLA_ALIGN(attr->nla_len);
+				NLA_ALIGN(attr_kind->nla_len);
+
+	if (limit > 0) {
+		/* Push TCA_OPTIONS attr. */
+		attr_opt = (struct nlattr *)(((void *)&nlreq.hdr) +
+					 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
+		attr_opt->nla_len = NLA_HDRLEN + sizeof(uint32_t);
+		attr_opt->nla_type = TCA_OPTIONS;
+		*((uint32_t *)(((void *)attr_opt) + NLA_HDRLEN)) = limit;
+		nlreq.hdr.nlmsg_len = NLMSG_ALIGN(nlreq.hdr.nlmsg_len) +
+					NLA_ALIGN(attr_opt->nla_len);
+	}
 
 	iov.iov_base = (void *)&nlreq;
 	iov.iov_len = nlreq.hdr.nlmsg_len;
@@ -663,9 +672,10 @@ nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 	struct ifnet *ifp = netmap_generic_getifp(gna);
 	struct netmap_adapter *na = &gna->up.up;
 	bool multiqueue = (na->num_tx_rings > 1);
-	const char *qdisc_name;
 	static uint32_t root_handle_cnt = 18;
 	uint32_t root_handle = multiqueue ? root_handle_cnt++ : 0;
+	uint32_t limit = (!multiqueue && intercept) ? na->num_tx_desc : 0;
+	const char *qdisc_name;
 	int ret = 0;
 
 	if (!gna->txqdisc) {
@@ -677,7 +687,7 @@ nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 	/* Configure root qdisc.
 	 * sudo tc qdisc replace dev ifp->name root handle @root_handle: qdisc_name */
 	ret = tc_configure(ifp, qdisc_name, /*parent=*/TC_H_ROOT,
-				/*handle=*/root_handle << 16);
+				/*handle=*/root_handle << 16, limit);
 	if (ret) {
 		return -ret;
 	}
@@ -685,10 +695,11 @@ nm_os_catch_qdisc(struct netmap_generic_adapter *gna, int intercept)
 		/* Configure per-queue qdisc. */
 		int i;
 		qdisc_name = (intercept ? generic_qdisc_ops.id : "pfifo");
+		limit = na->num_tx_desc;
 		for (i = 0; i < na->num_tx_rings; i++) {
 			tc_configure(ifp, qdisc_name,
 				/*parent=*/(root_handle << 16) | (i+1),
-				/*handle=*/0);
+				/*handle=*/0, limit);
 		}
 	}
 	return 0;

From 063a7c548cf538e64afab878e31c6ba016a7d4f2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 24 Feb 2018 18:54:51 +0100
Subject: [PATCH 0525/2207] linux: configure: add SOCK_CREATE_KERN_NETNS test

This is needed to distinguish two versions of socket_create_kern();
one has an additional first argument (struct net *).
---
 LINUX/configure      | 16 +++++++---------
 LINUX/netmap_linux.c |  7 +++++--
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index eee930b20..e26db83cc 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1275,17 +1275,15 @@ EOF
 	}
 EOF
 
-  # arguments of qdisc_create_dflt (either 3 or 4)
-  add_test 'define QDISC_CREATE_DFLT_3ARGS' <
+  # first argument of sock_create_kern() is a 'struct net*'
+  add_test 'define SOCK_CREATE_KERN_NETNS' <
 
-	struct Qdisc *
-	dummy(struct netdev_queue *dev_queue,
-	      struct Qdisc_ops* ops,
-	      unsigned int parent_id)
+	int
+	dummy(void)
 	{
-		return qdisc_create_dflt(dev_queue,
-					 ops, parent_id);
+		struct net *net = NULL;
+		return sock_create_kern(net, 0, 0, 0, NULL);
 	}
 EOF
 
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 2b669ba95..d148290e0 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -613,8 +613,11 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 	struct iovec iov;
 	int ret;
 
-	ret = sock_create_kern(current->nsproxy->net_ns, AF_NETLINK, SOCK_RAW,
-				NETLINK_ROUTE, &sock);
+	ret = sock_create_kern(
+#ifdef NETMAP_LINUX_SOCK_CREATE_KERN_NETNS
+				current->nsproxy->net_ns,
+#endif /* NETMAP_LINUX_SOCK_CREATE_KERN_NETNS  */
+				AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
 	if (ret) {
 		D("Failed to create netlink socket (err=%d)", ret);
 		return -ret;

From df49fa40781a09152f86b706fd3274cbb3b9634d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 11:02:59 +0100
Subject: [PATCH 0526/2207] linux: tc_configure: don't check iov_len after
 sendmsg

It may be changed by sendmsg(), at least in some kernel versions.
---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d148290e0..81c30b29c 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -654,7 +654,7 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 	iov.iov_len = nlreq.hdr.nlmsg_len;
 	ret = kernel_sendmsg(sock, &msg, (struct kvec *)&iov, 1,
 				iov.iov_len);
-	if (ret != iov.iov_len) {
+	if (ret != nlreq.hdr.nlmsg_len) {
 		D("Failed to sendmsg to netlink socket (err=%d)", ret);
 		ret = -EINVAL;
 		goto release;

From aab0e2dac8685c3aa867c5de445dd808efe9feea Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 26 Feb 2018 11:24:41 +0100
Subject: [PATCH 0527/2207] removed an unlikely()

---
 sys/dev/netmap/netmap_vale.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 70cdeebb7..8a99b3af2 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1940,7 +1940,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		if (na->up.virt_hdr_len < ft[i].ft_len) {
 			ft[i].ft_offset = na->up.virt_hdr_len;
 			start_ft = &ft[i];
-		} else if (unlikely(na->up.virt_hdr_len == ft[i].ft_len && ft[i].ft_flags & NS_MOREFRAG)) {
+		} else if (na->up.virt_hdr_len == ft[i].ft_len && ft[i].ft_flags & NS_MOREFRAG) {
 			ft[i].ft_offset = ft[i].ft_len;
 			start_ft = &ft[i+1];
 		} else {

From 063a1aa11941349361f9dad1c1d1ca36c70bbf88 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 17:50:13 +0100
Subject: [PATCH 0528/2207] linux: ixgbe: use hw_flags to distinguish from
 "flags"

---
 LINUX/ixgbe_netmap_linux.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 7b039a133..1d8d4d87b 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -339,20 +339,20 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			union ixgbe_adv_tx_desc *curr = NM_IXGBE_TX_DESC(txr, nic_i);
-			int flags = (slot->flags & NS_REPORT ||
+			int hw_flags = (slot->flags & NS_REPORT ||
 				nic_i == 0 || nic_i == report_frequency
 				) ? IXGBE_TXD_CMD_RS : 0;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
 			if (!(slot->flags & NS_MOREFRAG))
-				flags |= IXGBE_TXD_CMD_EOP;
+				hw_flags |= IXGBE_TXD_CMD_EOP;
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
 			/* Fill the slot in the NIC ring. */
 			curr->read.buffer_addr = htole64(paddr);
 			curr->read.olinfo_status = htole32(len << IXGBE_ADVTXD_PAYLEN_SHIFT);
-			curr->read.cmd_type_len = htole32(len | flags |
+			curr->read.cmd_type_len = htole32(len | hw_flags |
 				IXGBE_ADVTXD_DTYP_DATA | IXGBE_ADVTXD_DCMD_DEXT |
 				IXGBE_ADVTXD_DCMD_IFCS);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);

From 1c4238a6fdca486a56b32d60a7a416017cbb85d1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 17:55:34 +0100
Subject: [PATCH 0529/2207] linux: ixgbe: remove obsolete comment

---
 LINUX/ixgbe_netmap_linux.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 1d8d4d87b..97a7a339c 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -313,10 +313,6 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * need to update the buffer's physical address in the NIC slot
 	 * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
 	 *
-	 * The netmap_reload_map() calls is especially expensive,
-	 * even when (as in this case) the tag is 0, so do only
-	 * when the buffer has actually changed.
-	 *
 	 * If possible do not set the report/intr bit on all slots,
 	 * but only a few times per ring or when NS_REPORT is set.
 	 *

From 7192c2b2691c69fb742754102544a53bcfb5f5fe Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 18:42:55 +0100
Subject: [PATCH 0530/2207] linux: e1000: txsync: add support for NS_MOREFRAG

---
 LINUX/if_e1000_netmap.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 45c8284ed..72d672f7d 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -127,25 +127,26 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
-			int flags = (slot->flags & NS_REPORT ||
+			int hw_flags = (slot->flags & NS_REPORT ||
 				nic_i == 0 || nic_i == report_frequency) ?
 				E1000_TXD_CMD_RS : 0;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
+			if (!(slot->flags & NS_MOREFRAG)) {
+				hw_flags |= E1000_TXD_CMD_EOP;
+			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				/* buffer has changed, reload map */
-				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_addr, paddr);
 				curr->buffer_addr = htole64(paddr);
 			}
-			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
 			curr->lower.data = htole32(adapter->txd_cmd |
-				len | flags |
-				E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS);
+				len | hw_flags | E1000_TXD_CMD_IFCS);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -254,7 +255,6 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
 				goto ring_reset;
 			if (slot->flags & NS_BUF_CHANGED) {
-				// netmap_reload_map(...)
 				curr->buffer_addr = htole64(paddr);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}

From 0c2b39bb9a80c93134c1fd8d02ee0e7eca458c15 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 18:45:44 +0100
Subject: [PATCH 0531/2207] linux: e1000: rxsync: add support for NS_MOREFRAG

---
 LINUX/if_e1000_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 72d672f7d..8915912e2 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -227,7 +227,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			slot = ring->slot + nm_i;
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->length) - 4;
-			slot->flags = 0;
+			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);

From ffcd7208c162ef2fc6a7b0ed90a3e255c0aeb879 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 26 Feb 2018 19:36:42 +0100
Subject: [PATCH 0532/2207] linux/ixgbe: patch for Intel v5.3.6

---
 LINUX/final-patches/intel--ixgbe--5.3.6 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.3.6

diff --git a/LINUX/final-patches/intel--ixgbe--5.3.6 b/LINUX/final-patches/intel--ixgbe--5.3.6
new file mode 100644
index 000000000..6d666377f
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.3.6
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 545489a..e085666 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 83076bf..7a1fd02 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -734,6 +734,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -752,6 +769,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2033,6 +2061,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3320,6 +3358,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3967,6 +4009,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11231,6 +11277,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11276,6 +11326,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 85caffe2f4bf899d8d7bea6d0b64c850658bcf2f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 26 Feb 2018 19:58:07 +0100
Subject: [PATCH 0533/2207] linux/ixgbevf: patch for Intel v4.3.4

---
 LINUX/final-patches/intel--ixgbevf--4.3.4 | 177 ++++++++++++++++++++++
 1 file changed, 177 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.3.4

diff --git a/LINUX/final-patches/intel--ixgbevf--4.3.4 b/LINUX/final-patches/intel--ixgbevf--4.3.4
new file mode 100644
index 000000000..fbaf49ddf
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.3.4
@@ -0,0 +1,177 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index c8d39f4..e16565a 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 84b281c..cf6004b 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1192,6 +1220,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1825,6 +1863,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1835,7 +1877,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+- 
++
+ /**
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+@@ -2012,6 +2054,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4969,8 +5015,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5010,6 +5058,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index b780c4c..dfd74ed 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 527d3fed7a1dfb428e57bc260e4ee977c627d0ec Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 11:07:47 +0100
Subject: [PATCH 0534/2207] linux: qdisc_init: sanity check for 'limit'

---
 LINUX/netmap_linux.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 81c30b29c..54c4eeae8 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -493,13 +493,11 @@ generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt)
 	if (opt) {
 		uint32_t *limit = nla_data(opt);
 
-		if (nla_len(opt) < sizeof(*limit)) {
+		if (nla_len(opt) < sizeof(*limit) || *limit <= 0) {
 			D("Invalid netlink attribute");
 			return EINVAL;
 		}
-
 		priv->limit = *limit;
-		D("Qdisc initialized with max_len = %u", priv->limit);
 	}
 
 	/* Qdisc bypassing is not an option for now.

From 708a7cca46d9c30eb3794e8bf10f9079fcc1003d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 11:31:18 +0100
Subject: [PATCH 0535/2207] netmap_user.h: fix compilation issue on
 nm_pkt_copy()

---
 sys/net/netmap_user.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 5074b0b60..e12b19de7 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -270,8 +270,6 @@ struct nm_desc {
  * to multiple of 64 bytes and is often faster than dealing
  * with other odd sizes. We assume there is enough room
  * in the source and destination buffers.
- *
- * XXX only for multiples of 64 bytes, non overlapped.
  */
 static inline void
 nm_pkt_copy(const void *_src, void *_dst, int l)
@@ -279,7 +277,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024)) {
+	if (unlikely(l >= 1024 || l % 64)) {
 		memcpy(dst, src, l);
 		return;
 	}

From 77f289eb6427599bd6cb82fd9a4af38e5818082e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 16:21:14 +0100
Subject: [PATCH 0536/2207] tc_configure: fix NULL pointer bug

---
 LINUX/netmap_linux.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 54c4eeae8..a2d06f800 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -613,7 +613,8 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 
 	ret = sock_create_kern(
 #ifdef NETMAP_LINUX_SOCK_CREATE_KERN_NETNS
-				current->nsproxy->net_ns,
+				current->nsproxy ?
+					current->nsproxy->net_ns : &init_net,
 #endif /* NETMAP_LINUX_SOCK_CREATE_KERN_NETNS  */
 				AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
 	if (ret) {

From 4a97f41f290d758fb490cacbf2213c8023074588 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 18:45:07 +0100
Subject: [PATCH 0537/2207] utils: move 'producer' to X86PROGS

---
 utils/GNUmakefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 8659b0bf8..a32ab1147 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,7 +1,7 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm producer
-X86PROGS = testlock testcsum
+PROGS	= test_select testmmap test_nm
+X86PROGS = testlock testcsum producer
 LIBNETMAP =
 
 CLEANFILES = $(PROGS) $(X86PROGS) *.o

From c477d5ef65d6884b63c2b468ad911224c5cb162b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 10:12:47 +0100
Subject: [PATCH 0538/2207] linux: e1000: use adapter->txd_cmd only on the EOP
 descriptor

This is needed because adapter->txd_cmd contains the EOP indicator.
---
 LINUX/if_e1000_netmap.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 8915912e2..89958e26e 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -134,7 +134,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
-				hw_flags |= E1000_TXD_CMD_EOP;
+				hw_flags |= adapter->txd_cmd;
 			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				/* buffer has changed, reload map */
@@ -145,8 +145,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
-			curr->lower.data = htole32(adapter->txd_cmd |
-				len | hw_flags | E1000_TXD_CMD_IFCS);
+			curr->lower.data = htole32(len | hw_flags | E1000_TXD_CMD_IFCS);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}

From 6a24113ce86f2173af490282e271fa5bb59d440c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 10:52:24 +0100
Subject: [PATCH 0539/2207] linux: e1000: remove unused NS_REPORT logic

No functional change, as the corresponding hardware bit was
unconditionally set.
---
 LINUX/if_e1000_netmap.h | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 89958e26e..f6d5e2ec8 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -100,8 +100,6 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
-	/* generate an interrupt approximately every half ring */
-	u_int report_frequency = kring->nkr_num_slots >> 1;
 
 	/* device-specific */
 	struct SOFTC_T *adapter = netdev_priv(ifp);
@@ -127,14 +125,15 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
-			int hw_flags = (slot->flags & NS_REPORT ||
-				nic_i == 0 || nic_i == report_frequency) ?
-				E1000_TXD_CMD_RS : 0;
+			int hw_flags = E1000_TXD_CMD_IFCS;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
 				hw_flags |= adapter->txd_cmd;
+				/* For now E1000_TXD_CMD_RS is always set.
+				 * We may set it only if NS_REPORT is set or
+				 * at least once every half ring. */
 			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				/* buffer has changed, reload map */
@@ -145,7 +144,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
-			curr->lower.data = htole32(len | hw_flags | E1000_TXD_CMD_IFCS);
+			curr->lower.data = htole32(len | hw_flags);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}

From c5f374a5f002c13b796434805bd7d58218662e33 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 28 Feb 2018 16:16:59 +0100
Subject: [PATCH 0540/2207] External modules now can create bridges in
 exclusive mode (only they can attach and detach stuff from them), added
 authentication parameter to every VALE exported function. Changed
 nm_vale_validate() logic.

---
 LINUX/netmap_linux.c         |   4 +-
 sys/dev/netmap/netmap_kern.h |  14 ++-
 sys/dev/netmap/netmap_vale.c | 211 +++++++++++++++++++++--------------
 3 files changed, 139 insertions(+), 90 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 5e78ba459..56d7d5980 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2450,7 +2450,9 @@ EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 #ifdef WITH_VALE
 EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
-EXPORT_SYMBOL(netmap_bdg_mod_private_data);
+EXPORT_SYMBOL(nm_bdg_update_private_data);
+EXPORT_SYMBOL(netmap_bdg_create);
+EXPORT_SYMBOL(netmap_bdg_destroy);
 EXPORT_SYMBOL(nm_bdg_ctl_attach);
 EXPORT_SYMBOL(nm_bdg_ctl_detach);
 EXPORT_SYMBOL(nm_vi_create);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 69b703dfa..cdd5f5264 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1017,9 +1017,8 @@ struct netmap_bwrap_adapter {
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
 };
-struct netmap_bdg_ops; /* forward */
-int nm_bdg_ctl_attach(struct nmreq_header *hdr, struct netmap_bdg_ops *);
-int nm_bdg_ctl_detach(struct nmreq_header *hdr, struct netmap_bdg_ops *);
+int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
+int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_polling(struct nmreq_header *hdr);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
 int netmap_vi_create(struct nmreq_header *hdr, int);
@@ -1449,7 +1448,7 @@ typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
 		struct netmap_vp_adapter *, void *private_data);
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
-typedef int (*bdg_mod_private_data_fn_t)(void **private_data, void *callback_data);
+typedef int (*bdg_update_private_data_fn_t)(void **private_data, void *callback_data);
 struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
@@ -1472,9 +1471,12 @@ void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
 #define NM_BDG_EXCLUSIVE	2
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, uint8_t bdg_flags);
-int netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback, void *callback_data);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
+int nm_bdg_update_private_data(const char *name, void *auth_token,
+	bdg_update_private_data_fn_t callback, void *callback_data);
 int netmap_bdg_config(struct nm_ifreq *nifr);
+void *netmap_bdg_create(const char *bdg_name, int *return_status);
+int netmap_bdg_destroy(const char *bdg_name, void *auth_token);
 
 #else /* !WITH_VALE */
 #define	netmap_get_bdg_na(_1, _2, _3, _4)	0
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 8a99b3af2..2332b8597 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -202,12 +202,13 @@ static struct netmap_bdg_ops default_bdg_ops = {netmap_bdg_learning, NULL, NULL}
  * bdg_lock protects accesses to the bdg_ports array.
  * This is a rw lock (or equivalent).
  */
+#define NM_BDG_IFNAMSIZ IFNAMSIZ
 struct nm_bridge {
 	/* XXX what is the proper alignment/layout ? */
 	BDG_RWLOCK_T	bdg_lock;	/* protects bdg_ports */
 	int		bdg_namelen;
 	uint32_t	bdg_active_ports;
-	char		bdg_basename[IFNAMSIZ];
+	char		bdg_basename[NM_BDG_IFNAMSIZ];
 
 	/* Indexes of active ports (up to active_ports)
 	 * and all other remaining ports.
@@ -319,18 +320,17 @@ nm_vale_name_validate(const char *name)
 		return -1;
 	}
 
-	for (i = 0; name[i]; i++) {
+	for (i = 0; i < NM_BDG_IFNAMSIZ && name[i]; i++) {
 		if (name[i] == ':') {
-			if (colon_pos != -1) {
-				return -1;
-			}
 			colon_pos = i;
+			break;
 		} else if (!nm_is_id_char(name[i])) {
 			return -1;
 		}
 	}
 
-	if (i >= IFNAMSIZ) {
+	if (strlen(name) - colon_pos > IFNAMSIZ) {
+		/* interface name too long */
 		return -1;
 	}
 
@@ -365,7 +365,7 @@ nm_find_bridge(const char *name, int create)
 	for (i = 0; i < num_bridges; i++) {
 		struct nm_bridge *x = bridges + i;
 
-		if (!(x->bdg_flags & NM_BDG_ACTIVE)) {
+		if ((x->bdg_flags & NM_BDG_ACTIVE) + x->bdg_active_ports == 0) {
 			if (create && b == NULL)
 				b = x;	/* record empty slot */
 		} else if (x->bdg_namelen != namelen) {
@@ -393,7 +393,7 @@ nm_find_bridge(const char *name, int create)
 		/* set the default function */
 		b->bdg_ops = &default_bdg_ops;
 		b->private_data = b->ht;
-		b->bdg_flags = NM_BDG_ACTIVE;
+		b->bdg_flags = 0;
 		NM_BNS_GET(b);
 	}
 	return b;
@@ -519,7 +519,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	BDG_WUNLOCK(b);
 
 	ND("now %d active ports", lim);
-	if (lim == 0) {
+	if ((b->bdg_flags & NM_BDG_ACTIVE) + lim == 0) {
 		ND("marking bridge %s as free", b->bdg_basename);
 		nm_os_free(b->ht);
 		b->bdg_ops = NULL;
@@ -528,15 +528,94 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	}
 }
 
-static void
-netmap_bdg_free(struct nm_bridge *b)
+static inline void * 
+nm_bdg_get_auth_token(struct nm_bridge *b)
+{
+	return b->ht;
+}
+
+/* bridge not in exclusive mode ==> always valid
+ * bridge in exclusive mode (created through netmap_bdg_create()) ==> check authentication token
+ */
+static inline int
+nm_bdg_valid_auth_token(struct nm_bridge *b, void *auth_token)
+{
+	return !(b->bdg_flags & NM_BDG_EXCLUSIVE) || b->ht == auth_token;
+}
+
+/* Allows external modules to create bridges in exclusive mode,
+ * returns the authentication token that the external module will need
+ * to provide during nm_bdg_ctl_{attach, detach}() operations.
+ * Successfully executed if ret != NULL and *return_status == 0.
+ */
+void *
+netmap_bdg_create(const char *bdg_name, int *return_status)
+{
+	struct nm_bridge *b = NULL;
+	void *ret = NULL;
+
+	NMG_LOCK();
+	b = nm_find_bridge(bdg_name, 0 /* don't create */);
+	if (b) {
+		*return_status = EEXIST;
+		goto unlock_bdg_create;
+	}
+
+	b = nm_find_bridge(bdg_name, 1 /* create */);
+	if (!b) {
+		*return_status = ENOMEM;
+		goto unlock_bdg_create;
+	}
+
+	b->bdg_flags |= NM_BDG_ACTIVE | NM_BDG_EXCLUSIVE;
+	ret = nm_bdg_get_auth_token(b);
+	*return_status = 0;
+
+unlock_bdg_create:
+	NMG_UNLOCK();
+	return ret;
+}
+
+/* Allows external modules to destroy a bridge created through
+ * netmap_bdg_create(), the bridge must be empty.
+ */
+int
+netmap_bdg_destroy(const char *bdg_name, void *auth_token)
 {
-	uint32_t i;
-	for (i = 0; i < b->bdg_active_ports; ++i) {
-		netmap_bdg_detach_common(b, b->bdg_port_index[i], -1);
+	struct nm_bridge *b = NULL;
+	int ret = 0;
+
+	NMG_LOCK();
+	b = nm_find_bridge(bdg_name, 0 /* don't create */);
+	if (!b) {
+		ret = ENXIO;
+		goto unlock_bdg_free;
 	}
+
+
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		ret = EACCES;
+		goto unlock_bdg_free;
+	}
+	if (!(b->bdg_flags & NM_BDG_EXCLUSIVE)) {
+		ret = EINVAL;
+		goto unlock_bdg_free;
+	}
+	if (b->bdg_active_ports != 0) {
+		ret = EINVAL;
+		goto unlock_bdg_free;
+	}
+
+	b->bdg_flags &= ~(NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE);
+	netmap_bdg_detach_common(b, -1, -1);
+
+unlock_bdg_free:
+	NMG_UNLOCK();
+	return ret;
 }
 
+
+
 /* nm_bdg_ctl callback for VALE ports */
 static int
 netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
@@ -918,11 +997,9 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 
 /* Process NETMAP_REQ_VALE_ATTACH.
- * bdg_ops is used to check ownership over a bridge in exclusive mode,
- * see netmap_bdg_regops() to se how it works.
  */
 int
-nm_bdg_ctl_attach(struct nmreq_header *hdr, struct netmap_bdg_ops *bdg_ops)
+nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 {
 	struct nmreq_vale_attach *req =
 		(struct nmreq_vale_attach *)hdr->nr_body;
@@ -935,7 +1012,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr, struct netmap_bdg_ops *bdg_ops)
 	NMG_LOCK();
 	/* permission check for modified bridges */
 	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
-	if (b && (b->bdg_flags & NM_BDG_EXCLUSIVE) && b->bdg_ops != bdg_ops) {
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
 		error = EACCES;
 		goto unlock_exit;
 	}
@@ -997,11 +1074,9 @@ nm_is_bwrap(struct netmap_adapter *na)
 }
 
 /* Process NETMAP_REQ_VALE_DETACH.
- * bdg_ops is used to check ownership over a bridge in exclusive mode,
- * see netmap_bdg_regops() to se how it works.
  */
 int
-nm_bdg_ctl_detach(struct nmreq_header *hdr, struct netmap_bdg_ops *bdg_ops)
+nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
 {
 	struct nmreq_vale_detach *nmreq_det = (void *)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
@@ -1012,7 +1087,7 @@ nm_bdg_ctl_detach(struct nmreq_header *hdr, struct netmap_bdg_ops *bdg_ops)
 	NMG_LOCK();
 	/* permission check for modified bridges */
 	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
-	if (b && (b->bdg_flags & NM_BDG_EXCLUSIVE) && b->bdg_ops != bdg_ops) {
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
 		error = EACCES;
 		goto unlock_exit;
 	}
@@ -1428,73 +1503,38 @@ netmap_bdg_list(struct nmreq_header *hdr)
  * Register callbacks to the given bridge. 'name' may be just
  * bridge's name (including ':' if it is not just NM_BDG_NAME).
  *
- * bdg_flags at the moment only supports NM_BDG_EXCLUSIVE which can be specified
- * only for not yet existing bridges (they will be created during the regops).
- * Exclusive mode allows only the external module which regops()'ed the bridge
- * to attach and detach its ports.
- * The permission check is made through the second parameter of nm_bdg_ctl_attach()
- * and nm_bdg_ctl_detach(), which for bridges with the NM_BDG_EXCLUSIVE flag is
- * compared against the netmap_bdg_ops pointer of the bridge.
- *
  * Called without NMG_LOCK.
  */
  
 int
-netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, uint8_t flags)
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token)
 {
 	struct nm_bridge *b;
 	int error = 0;
 
 	NMG_LOCK();
 	b = nm_find_bridge(name, 0 /* don't create */);
-	if (!bdg_ops) {
-		/* resetting the bridge, it must exists */
-		if (!b) {
-			error = EINVAL;
-			goto unlock_regops;
-		}
+	if (!b) {
+		error = ENXIO;
+		goto unlock_regops;
+	}
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_regops;
+	}
 
-		if (b->bdg_active_ports == 0 && (b->bdg_flags & NM_BDG_EXCLUSIVE)) {
-			/* bridges in exclusive mode are created without ports attached
-			 * therefore we might receive a reset regops() while the
-			 * bridge is effectively empty, in this case we free the bridge
-			 */
-			netmap_bdg_free(b);
-		} else {
-			BDG_WLOCK(b);
-			bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-			b->bdg_ops = &default_bdg_ops;
-			b->private_data = b->ht;
-			b->bdg_flags &= ~NM_BDG_EXCLUSIVE;
-			BDG_WUNLOCK(b);
-		}
+	BDG_WLOCK(b);
+	if (!bdg_ops) {
+		/* resetting the bridge */
+		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+		b->bdg_ops = &default_bdg_ops;
+		b->private_data = b->ht;
 	} else {
-		/* modifying the bridge, if NM_BDG_EXCLUSIVE is set the bridge cannot have
-		 * ports alredy attached (aka we need to create it on the spot)
-		 */
-		if (flags & NM_BDG_EXCLUSIVE) {
-			if (b) {
-				error = EINVAL;
-				goto unlock_regops;
-			}
-
-			b = nm_find_bridge(name, 1 /* create */);
-		}
-		if (!b) {
-			error = (flags & NM_BDG_EXCLUSIVE) ? ENOMEM : EINVAL;
-			goto unlock_regops;
-		}
-
-		BDG_WLOCK(b);
-		if (b->bdg_ops != &default_bdg_ops) {
-			error = EINVAL;
-		} else {
-			b->private_data = private_data;
-			b->bdg_flags |= flags;
-			b->bdg_ops = bdg_ops;
-		}
-		BDG_WUNLOCK(b);
+		/* modifying the bridge */
+		b->private_data = private_data;
+		b->bdg_ops = bdg_ops;
 	}
+	BDG_WUNLOCK(b);
 
 unlock_regops:
 	NMG_UNLOCK();
@@ -1508,7 +1548,8 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *privat
  * Called without NMG_LOCK.
  */
 int
-netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback, void *callback_data)
+nm_bdg_update_private_data(const char *name, void *auth_token,
+	bdg_update_private_data_fn_t callback, void *callback_data)
 {
 	struct nm_bridge *b;
 	int error = 0;
@@ -1517,14 +1558,18 @@ netmap_bdg_mod_private_data(const char *name, bdg_mod_private_data_fn_t callback
 	b = nm_find_bridge(name, 0 /* don't create */);
 	if (!b) {
 		error = EINVAL;
-	} else {
-		/* TODO: implement ownership over bridges */
-		BDG_WLOCK(b);
-		error = callback((void **)(&b->private_data), callback_data);
-		BDG_WUNLOCK(b);
+		goto unlock_update_priv;
 	}
-	NMG_UNLOCK();
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_update_priv;
+	}
+	BDG_WLOCK(b);
+	error = callback((&b->private_data), callback_data);
+	BDG_WUNLOCK(b);
 
+unlock_update_priv:
+	NMG_UNLOCK();
 	return error;
 }
 

From 3a158b8ed359d56c41824e32b6ab8f04c9a72978 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 17:01:20 +0100
Subject: [PATCH 0541/2207] linux: e1000: add missing dma_rmb() in rxsync

---
 LINUX/if_e1000_netmap.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index f6d5e2ec8..ca0eca72c 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -221,6 +221,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
+			dma_rmb(); /* read descriptor after status DD */
 
 			slot = ring->slot + nm_i;
 			PNMB(na, slot, &paddr);

From 22e9fc09fd0131f65deeef068690e54be38b3f63 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 19:56:29 +0100
Subject: [PATCH 0542/2207] linux: igb: add support for NS_MOREFRAG

---
 LINUX/if_igb_netmap.h | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index b8cb56268..ef80e8bee 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -125,8 +125,6 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 	struct SOFTC_T *adapter = netdev_priv(ifp);
 	struct igb_ring* txr = adapter->tx_ring[ring_nr];
 
-	rmb();	// XXX not in ixgbe ?
-
 	/*
 	 * First part: process new packets to send.
 	 */
@@ -148,17 +146,16 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 			/* device-specific */
 			union e1000_adv_tx_desc *curr =
 			    E1000_TX_DESC_ADV(*txr, nic_i);
-			int flags = (slot->flags & NS_REPORT ||
+			int hw_flags = (slot->flags & NS_REPORT ||
 				nic_i == 0 || nic_i == report_frequency) ?
 				E1000_TXD_CMD_RS : 0;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
-			if (slot->flags & NS_BUF_CHANGED) {
-				/* buffer has changed, reload map */
-				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
+			if (!(slot->flags & NS_MOREFRAG)) {
+				hw_flags |= E1000_TXD_CMD_EOP;
 			}
-			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
@@ -167,9 +164,9 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 			curr->read.olinfo_status =
 			    htole32(olinfo_status |
                                 (len<< E1000_ADVTXD_PAYLEN_SHIFT));
-			curr->read.cmd_type_len = htole32(len | flags |
+			curr->read.cmd_type_len = htole32(len | hw_flags |
 				E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_DEXT |
-				E1000_ADVTXD_DCMD_IFCS | E1000_TXD_CMD_EOP);
+				E1000_ADVTXD_DCMD_IFCS);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -179,7 +176,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		/* (re)start the tx unit up to slot nic_i (excluded) */
 		writel(nic_i, txr->tail);
-		mmiowb(); // XXX why do we need this ?
+		mmiowb();
 	}
 
 	/*
@@ -245,9 +242,10 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
+			dma_rmb(); /* read descriptor after status DD */
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->wb.upper.length);
-			slot->flags = 0;
+			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -276,7 +274,6 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 				goto ring_reset;
 
 			if (slot->flags & NS_BUF_CHANGED) {
-				// netmap_reload_map(pdev, DMA_FROM_DEVICE, old_paddr, addr);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
 			curr->read.pkt_addr = htole64(paddr);

From 0da504d28b914f0d4f6a68c00ecdaa4c0ff25908 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 15:25:56 +0100
Subject: [PATCH 0543/2207] netmap_hw_adapter: use ifdef for linux-only data
 structures

---
 sys/dev/netmap/netmap_kern.h | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index ea8e8ffc1..9d0977d9f 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -131,13 +131,10 @@ struct nm_selinfo {
 };
 
 
-/* Linux structs, not used in FreeBSD. */
-struct net_device_ops {
-};
-struct ethtool_ops {
-};
 struct hrtimer {
+    /* Not used in FreeBSD. */
 };
+
 #define NM_BNS_GET(b)
 #define NM_BNS_PUT(b)
 
@@ -201,14 +198,6 @@ struct hrtimer {
 #define NETMAP_KERNEL_XCHANGE_POINTERS		_IO('i', 180)
 #define NETMAP_KERNEL_SEND_SHUTDOWN_SIGNAL	_IO_direct('i', 195)
 
-/* Empty data structures are not allowed by MSVC compiler, so
- * we workaround. */
-struct net_device_ops{
-	char data[1];
-};
-typedef struct ethtool_ops{
-	char data[1];
-};
 typedef struct hrtimer{
 	KTIMER timer;
 	BOOLEAN active;
@@ -903,8 +892,10 @@ struct netmap_vp_adapter {	/* VALE software port */
 struct netmap_hw_adapter {	/* physical device */
 	struct netmap_adapter up;
 
-	struct net_device_ops nm_ndo; /* Linux only */
-	struct ethtool_ops    nm_eto; /* Linux only */
+#ifdef linux
+	struct net_device_ops nm_ndo;
+	struct ethtool_ops    nm_eto;
+#endif
 	const struct ethtool_ops*   save_ethtool;
 
 	int (*nm_hw_register)(struct netmap_adapter *, int onoff);
@@ -1282,12 +1273,12 @@ nm_set_native_flags(struct netmap_adapter *na)
 	ifp->if_transmit = netmap_transmit;
 #elif defined (_WIN32)
 	(void)ifp; /* prevent a warning */
-#else
+#elif defined (linux)
 	na->if_transmit = (void *)ifp->netdev_ops;
 	ifp->netdev_ops = &((struct netmap_hw_adapter *)na)->nm_ndo;
 	((struct netmap_hw_adapter *)na)->save_ethtool = ifp->ethtool_ops;
 	ifp->ethtool_ops = &((struct netmap_hw_adapter*)na)->nm_eto;
-#endif
+#endif /* linux */
 	nm_update_hostrings_mode(na);
 }
 

From 153e6ecbb1bb57efd48441f6338651a2eccf6f5b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 16:42:19 +0100
Subject: [PATCH 0544/2207] linux: prevent MTU from changing while in netmap
 mode

---
 LINUX/bsd_glue.h        | 6 +++++-
 LINUX/netmap_linux.c    | 6 ++++++
 sys/dev/netmap/netmap.c | 1 +
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index fafde1f4d..d20eb6ec4 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -120,8 +120,9 @@ extern struct net init_net;
 #define netdev_ops	hard_start_xmit
 struct net_device_ops {
 	int (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev);
+	int (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
 };
-#endif /* NETDEV_OPS */
+#endif /* !NETDEV_OPS */
 
 #ifndef NETMAP_LINUX_HAVE_NETDEV_TX_T
 #define netdev_tx_t	int
@@ -299,6 +300,9 @@ void if_rele(struct net_device *ifp);
 /* hook to send from user space */
 netdev_tx_t linux_netmap_start_xmit(struct sk_buff *, struct net_device *);
 
+/* prevent MTU changes while in netmap mode */
+int linux_netmap_change_mtu(struct net_device *dev, int new_mtu);
+
 /* prevent ring params change while in netmap mode */
 int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *);
 #ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a2d06f800..d8f30d212 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1083,6 +1083,12 @@ linux_netmap_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	return (NETDEV_TX_OK);
 }
 
+int
+linux_netmap_change_mtu(struct net_device *dev, int new_mtu)
+{
+	return -EBUSY;
+}
+
 /* while in netmap mode, we cannot tolerate any change in the
  * number of rx/tx rings and descriptors
  */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index aca2be900..bade0687b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3004,6 +3004,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 #endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
 	}
 	hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit;
+	hwna->nm_ndo.ndo_change_mtu = linux_netmap_change_mtu;
 	if (ifp->ethtool_ops) {
 		hwna->nm_eto = *ifp->ethtool_ops;
 	}

From e943705a9d15b1fd6ce9eea006928456c41748be Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 17:53:08 +0100
Subject: [PATCH 0545/2207] netmap mem: export netmap_mem_bufsize()

---
 sys/dev/netmap/netmap_mem2.c | 7 +++++--
 sys/dev/netmap/netmap_mem2.h | 1 +
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1870b8fed..20e0e5644 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1010,8 +1010,11 @@ netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr)
 	    vaddr, p->name);
 }
 
-#define netmap_mem_bufsize(n)	\
-	((n)->pools[NETMAP_BUF_POOL]._objsize)
+unsigned
+netmap_mem_bufsize(struct netmap_mem_d *nmd)
+{
+	return nmd->pools[NETMAP_BUF_POOL]._objsize;
+}
 
 #define netmap_if_malloc(n, len)	netmap_obj_malloc(&(n)->pools[NETMAP_IF_POOL], len, NULL, NULL)
 #define netmap_if_free(n, v)		netmap_obj_free_va(&(n)->pools[NETMAP_IF_POOL], (v))
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 9d19ebd2a..4daedbe61 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -147,6 +147,7 @@ void	   netmap_mem_delete(struct netmap_mem_d *);
 struct netmap_mem_d* __netmap_mem_get(struct netmap_mem_d *, const char *, int);
 void __netmap_mem_put(struct netmap_mem_d *, const char *, int);
 struct netmap_mem_d* netmap_mem_find(nm_memid_t);
+unsigned netmap_mem_bufsize(struct netmap_mem_d *nmd);
 
 #ifdef WITH_PTNETMAP_GUEST
 struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,

From 89dad97ca7362a69a59bf175cff42d1b98289edb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 17:53:29 +0100
Subject: [PATCH 0546/2207] netmap_do_regif: check that buf_size is consistent
 with MTU

---
 sys/dev/netmap/netmap.c      | 20 +++++++++++++++++---
 sys/dev/netmap/netmap_kern.h |  5 ++---
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bade0687b..c5110468b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2081,10 +2081,24 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	if (na->active_fds == 0) {
 		/*
 		 * If this is the first registration of the adapter,
-		 * create the  in-kernel view of the netmap rings,
-		 * the netmap krings.
+		 * perform sanity checks and create the in-kernel view
+		 * of the netmap rings (the netmap krings).
 		 */
-
+#ifdef linux
+		if (na->ifp) {
+			/* This netmap adapter is attached to an ifnet.
+			 * Check that netmap buffer size is at least as
+			 * big as device MTU. */
+			if (netmap_mem_bufsize(na->nm_mem) < na->ifp->mtu) {
+				D("Error: netmap buf_size (%u) smaller "
+					"than device MTU (%u)",
+					netmap_mem_bufsize(na->nm_mem),
+					na->ifp->mtu);
+				error = EINVAL;
+				goto err;
+			}
+		}
+#endif /* linux */
 		/*
 		 * Depending on the adapter, this may also create
 		 * the netmap rings themselves
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 9d0977d9f..4c6e72ad7 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -702,9 +702,8 @@ struct netmap_adapter {
 	/* copy of if_input for netmap_send_up() */
 	void     (*if_input)(struct ifnet *, struct mbuf *);
 
-	/* references to the ifnet and device routines, used by
-	 * the generic netmap functions.
-	 */
+	/* Back reference to the parent ifnet struct. Used for
+	 * hardware ports (emulated netmap included). */
 	struct ifnet *ifp; /* adapter is ifp->if_softc */
 
 	/*---- callbacks for this netmap adapter -----*/

From 1802b97c4d00b8070f7e47692147ea216b3d98c9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 19:09:25 +0100
Subject: [PATCH 0547/2207] introduce nm_os_ifnet_mtu()

---
 LINUX/netmap_linux.c            | 6 ++++++
 WINDOWS/netmap_windows.c        | 6 ++++++
 sys/dev/netmap/netmap.c         | 8 ++++----
 sys/dev/netmap/netmap_freebsd.c | 6 ++++++
 sys/dev/netmap/netmap_kern.h    | 2 ++
 5 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d8f30d212..56a3ded8a 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -154,6 +154,12 @@ nm_os_ifnet_fini(void)
 	}
 }
 
+unsigned
+nm_os_ifnet_mtu(struct ifnet *ifp)
+{
+	return ifp->mtu;
+}
+
 #ifdef NETMAP_LINUX_HAVE_IOMMU
 #include 
 
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index ee757272b..16523ab5e 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -927,6 +927,12 @@ nm_os_ifnet_fini(void)
 
 }
 
+unsigned
+nm_os_ifnet_mtu(struct ifnet *ifp)
+{
+       return 1500; /* XXX hardwired */
+}
+
 /*
  * Mitigation support
  */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c5110468b..86099d031 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2084,21 +2084,21 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 * perform sanity checks and create the in-kernel view
 		 * of the netmap rings (the netmap krings).
 		 */
-#ifdef linux
 		if (na->ifp) {
 			/* This netmap adapter is attached to an ifnet.
 			 * Check that netmap buffer size is at least as
 			 * big as device MTU. */
-			if (netmap_mem_bufsize(na->nm_mem) < na->ifp->mtu) {
+			if (netmap_mem_bufsize(na->nm_mem) <
+					nm_os_ifnet_mtu(na->ifp)) {
 				D("Error: netmap buf_size (%u) smaller "
 					"than device MTU (%u)",
 					netmap_mem_bufsize(na->nm_mem),
-					na->ifp->mtu);
+					nm_os_ifnet_mtu(na->ifp));
 				error = EINVAL;
 				goto err;
 			}
 		}
-#endif /* linux */
+
 		/*
 		 * Depending on the adapter, this may also create
 		 * the netmap rings themselves
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 742dbb32e..96caf8468 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -171,6 +171,12 @@ nm_os_ifnet_fini(void)
                 nm_ifnet_dh_tag);
 }
 
+unsigned
+nm_os_ifnet_mtu(struct ifnet *ifp)
+{
+       return ifp->if_data.ifi_mtu;
+}
+
 rawsum_t
 nm_os_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum)
 {
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4c6e72ad7..e79249829 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -285,6 +285,8 @@ void nm_os_ifnet_fini(void);
 void nm_os_ifnet_lock(void);
 void nm_os_ifnet_unlock(void);
 
+unsigned nm_os_ifnet_mtu(struct ifnet *ifp);
+
 void nm_os_get_module(void);
 void nm_os_put_module(void);
 

From 1cc1075f0d19d12d9b67ca28800c5cf85fd9b555 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Feb 2018 15:55:34 +0100
Subject: [PATCH 0548/2207] netmap_do_regif: fix reference leak on memory
 allocator

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 86099d031..0e3412d1f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2095,7 +2095,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 					netmap_mem_bufsize(na->nm_mem),
 					nm_os_ifnet_mtu(na->ifp));
 				error = EINVAL;
-				goto err;
+				goto err_drop_mem;
 			}
 		}
 

From 5351abe6ab574167380f3a7c2800d75617c98e7b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Feb 2018 17:06:05 +0100
Subject: [PATCH 0549/2207] linux: if_e1000e_netmap.h: minor improvements

---
 LINUX/if_e1000e_netmap.h | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index e9f66b17b..3845c9545 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -62,9 +62,10 @@ char netmap_e1000e_driver_name[] = "e1000e" NETMAP_LINUX_DRIVER_SUFFIX;
 #define	NM_E1R_RX_LENGTH	length
 #endif /* up to 3.2.x */
 
+/* Macros to write to the head and tail registers of TX and RX rings. */
 #ifndef NETMAP_LINUX_HAVE_E1000E_HWADDR
-#define NM_WR_TX_TAIL(_x)	writel(_x, txr->tail)	// XXX tx_ring
-#define	NM_WR_RX_TAIL(_x)	writel(_x, rxr->tail)	// XXX rx_ring
+#define NM_WR_TX_TAIL(_x)	writel(_x, txr->tail)
+#define	NM_WR_RX_TAIL(_x)	writel(_x, rxr->tail)
 #define	NM_RD_TX_HEAD()		readl(txr->head)
 #else
 #define NM_WR_TX_TAIL(_x)	writel(_x, adapter->hw.hw_addr + txr->tail)
@@ -177,19 +178,22 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		wmb();	/* synchronize writes to the NIC ring */
 
-		txr->next_to_use = nic_i;
+		txr->next_to_use = nic_i; /* for consistency */
 		NM_WR_TX_TAIL(nic_i);
-		mmiowb(); // XXX where do we need this ?
+		mmiowb(); /* needed after writing to TX ring tail */
 	}
 
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
-		/* record completed transmissions using TDH */
-		nic_i = NM_RD_TX_HEAD();	// XXX could scan descriptors ?
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		/* Record completed transmissions using TDH.
+		 * Alternative approach would be to scan descriptors and read
+		 * the DD bit until we found one that is not set. */
+		nic_i = NM_RD_TX_HEAD();
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			/* This should never happen. */
+			D("Warning: TDH wrap %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		txr->next_to_clean = nic_i;
@@ -285,7 +289,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			nic_i = nm_next(nic_i, lim);
 		}
 		kring->nr_hwcur = head;
-		rxr->next_to_use = nic_i; // XXX not really used
+		rxr->next_to_use = nic_i; /* for consistency */
 		wmb();
 		/*
 		 * IMPORTANT: we must leave one free slot in the ring,
@@ -306,7 +310,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 /* diagnostic routine to catch errors */
 static void e1000e_no_rx_alloc(struct SOFTC_T *a, int n)
 {
-	D("e1000->alloc_rx_buf should not be called");
+	D("Error: alloc_rx_buf() should not be called");
 }
 
 
@@ -331,14 +335,11 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		/* initialize the RX ring for netmap mode */
 		adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc;
 		for (i = 0; i < rxr->count; i++) {
-			// XXX the skb check and cleanup can go away
 			struct e1000_buffer *bi = &rxr->buffer_info[i];
 			si = netmap_idx_n2k(&na->rx_rings[0], i);
 			PNMB(na, slot + si, &paddr);
 			if (bi->skb)
-				D("rx buf %d was set", i);
-			bi->skb = NULL; // XXX leak if set
-			// netmap_load_map(...)
+				D("Warning: rx skb still set on slot #%d", i);
 			E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr);
 		}
 		rxr->next_to_use = 0;
@@ -354,7 +355,6 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		for (i = 0; i < na->num_tx_desc; i++) {
 			si = netmap_idx_n2k(&na->tx_rings[0], i);
 			PNMB(na, slot + si, &paddr);
-			// netmap_load_map(...)
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
 		}
 	}

From 65e89dd4f1eb6422c0812d4dee6c8ab045111903 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Feb 2018 18:28:04 +0100
Subject: [PATCH 0550/2207] linux: e1000, ixgbe: remove obsolete comments about
 netmap_load_map()

---
 LINUX/if_e1000_netmap.h    | 2 --
 LINUX/ixgbe_netmap_linux.h | 1 -
 2 files changed, 3 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index ca0eca72c..3dd6169f7 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -308,7 +308,6 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		for (i = 0; i < rxr->count; i++) {
 			si = netmap_idx_n2k(&na->rx_rings[r], i);
 			PNMB(na, slot + si, &paddr);
-			// netmap_load_map(...)
 			E1000_RX_DESC(*rxr, i)->buffer_addr = htole64(paddr);
 		}
 
@@ -333,7 +332,6 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		for (i = 0; i < na->num_tx_desc; i++) {
 			si = netmap_idx_n2k(&na->tx_rings[r], i);
 			PNMB(na, slot + si, &paddr);
-			// netmap_load_map(...)
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
 		}
 	}
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 97a7a339c..50abe24cf 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -656,7 +656,6 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 		union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(ring, i);
 		uint64_t paddr;
 		PNMB(na, slot + si, &paddr);
-		// netmap_load_map(rxr->ptag, rxbuf->pmap, addr);
 		/* Update descriptor */
 		curr->read.pkt_addr = htole64(paddr);
 		curr->wb.upper.length = 0;

From 00bccf4b6c6739d3551ad0670ccfc307470f2a64 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Feb 2018 21:14:59 +0100
Subject: [PATCH 0551/2207] linux: update e1000e patches with support for RX
 jumbo frames

---
 .../vanilla--e1000e--20620--30100             | 19 +++++++++++++++----
 .../vanilla--e1000e--30100--30400             | 19 +++++++++++++++----
 .../vanilla--e1000e--30400--30900             | 19 +++++++++++++++----
 .../vanilla--e1000e--30900--99999             | 19 +++++++++++++++----
 4 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/LINUX/final-patches/vanilla--e1000e--20620--30100 b/LINUX/final-patches/vanilla--e1000e--20620--30100
index 85fb9c8e4..631ed11c6 100644
--- a/LINUX/final-patches/vanilla--e1000e--20620--30100
+++ b/LINUX/final-patches/vanilla--e1000e--20620--30100
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index fad8f9e..cd4abfd 100644
+index fad8f9ea0043..4f8fc3f6507c 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -87,6 +87,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -35,7 +35,18 @@ index fad8f9e..cd4abfd 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -2632,6 +2644,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -910,6 +922,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes=0, total_rx_packets=0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(netdev, 0, work_done))
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC(*rx_ring, i);
+ 	buffer_info = &rx_ring->buffer_info[i];
+@@ -2632,6 +2648,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  	e1000_configure_tx(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -46,7 +57,7 @@ index fad8f9e..cd4abfd 100644
  	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring));
  }
  
-@@ -5227,6 +5243,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+@@ -5227,6 +5247,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
  	if (err)
  		goto err_register;
  
@@ -56,7 +67,7 @@ index fad8f9e..cd4abfd 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -5300,6 +5319,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+@@ -5300,6 +5323,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--e1000e--30100--30400 b/LINUX/final-patches/vanilla--e1000e--30100--30400
index 7163c8fbf..0b49fb49e 100644
--- a/LINUX/final-patches/vanilla--e1000e--30100--30400
+++ b/LINUX/final-patches/vanilla--e1000e--30100--30400
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 2198e61..588f1ec 100644
+index 2198e615f241..3c95b385bfee 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -452,6 +452,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -35,7 +35,18 @@ index 2198e61..588f1ec 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -3177,6 +3189,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -1355,6 +1367,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes=0, total_rx_packets=0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(netdev, 0, work_done))
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC(*rx_ring, i);
+ 	buffer_info = &rx_ring->buffer_info[i];
+@@ -3177,6 +3193,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  	e1000_configure_tx(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -46,7 +57,7 @@ index 2198e61..588f1ec 100644
  	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring),
  			      GFP_KERNEL);
  }
-@@ -6147,6 +6163,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+@@ -6147,6 +6167,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
  	if (err)
  		goto err_register;
  
@@ -56,7 +67,7 @@ index 2198e61..588f1ec 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6234,6 +6253,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+@@ -6234,6 +6257,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--e1000e--30400--30900 b/LINUX/final-patches/vanilla--e1000e--30400--30900
index 8c8534cf5..b0c28a433 100644
--- a/LINUX/final-patches/vanilla--e1000e--30400--30900
+++ b/LINUX/final-patches/vanilla--e1000e--30400--30900
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 9520a6a..bf94805 100644
+index 9520a6ac1f30..6abd65519fd4 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -467,6 +467,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -35,7 +35,18 @@ index 9520a6a..bf94805 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -3358,6 +3370,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -1433,6 +1445,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes=0, total_rx_packets=0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(netdev, 0, work_done))
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -3358,6 +3374,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  		e1000e_setup_rss_hash(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -46,7 +57,7 @@ index 9520a6a..bf94805 100644
  	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
  }
  
-@@ -6417,6 +6433,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+@@ -6417,6 +6437,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
  	if (err)
  		goto err_register;
  
@@ -56,7 +67,7 @@ index 9520a6a..bf94805 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6504,6 +6523,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+@@ -6504,6 +6527,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--e1000e--30900--99999 b/LINUX/final-patches/vanilla--e1000e--30900--99999
index 742729b4f..b844a5f20 100644
--- a/LINUX/final-patches/vanilla--e1000e--30900--99999
+++ b/LINUX/final-patches/vanilla--e1000e--30900--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 7e615e2..32ce408 100644
+index 7e615e2bf7e6..361401a7a46c 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -473,6 +473,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -35,7 +35,18 @@ index 7e615e2..32ce408 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -3685,6 +3697,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -1502,6 +1514,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes=0, total_rx_packets=0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(netdev, 0, work_done))
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -3685,6 +3701,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  		e1000e_setup_rss_hash(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -46,7 +57,7 @@ index 7e615e2..32ce408 100644
  	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
  }
  
-@@ -6768,6 +6784,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -6768,6 +6788,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	if (err)
  		goto err_register;
  
@@ -56,7 +67,7 @@ index 7e615e2..32ce408 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6866,6 +6885,10 @@ static void e1000_remove(struct pci_dev *pdev)
+@@ -6866,6 +6889,10 @@ static void e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  

From 8bfc0a1595a3de2b5cf91625143945117f7cbeb3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 22 Feb 2018 18:24:38 +0100
Subject: [PATCH 0552/2207] e1000e: keep packet-split disabled with netmap

---
 .../vanilla--e1000e--20620--30100             | 19 +++++++++++++++----
 .../vanilla--e1000e--30100--30400             | 19 +++++++++++++++----
 .../vanilla--e1000e--30400--30900             | 19 +++++++++++++++----
 .../vanilla--e1000e--30900--99999             | 19 +++++++++++++++----
 4 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/LINUX/final-patches/vanilla--e1000e--20620--30100 b/LINUX/final-patches/vanilla--e1000e--20620--30100
index 631ed11c6..133852ab1 100644
--- a/LINUX/final-patches/vanilla--e1000e--20620--30100
+++ b/LINUX/final-patches/vanilla--e1000e--20620--30100
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index fad8f9ea0043..4f8fc3f6507c 100644
+index fad8f9ea0043..e109db98e6ea 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -87,6 +87,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -46,7 +46,18 @@ index fad8f9ea0043..4f8fc3f6507c 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC(*rx_ring, i);
  	buffer_info = &rx_ring->buffer_info[i];
-@@ -2632,6 +2648,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -2379,6 +2395,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
+ 		adapter->rx_ps_pages = pages;
+ 	else
+ 		adapter->rx_ps_pages = 0;
++#ifdef DEV_NETMAP
++       /* Keep packet-split disabled with netmap. */
++       adapter->rx_ps_pages = 0;
++#endif /* DEV_NETMAP */
+ 
+ 	if (adapter->rx_ps_pages) {
+ 		/* Configure extra packet-split registers */
+@@ -2632,6 +2652,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  	e1000_configure_tx(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -57,7 +68,7 @@ index fad8f9ea0043..4f8fc3f6507c 100644
  	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring));
  }
  
-@@ -5227,6 +5247,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+@@ -5227,6 +5251,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
  	if (err)
  		goto err_register;
  
@@ -67,7 +78,7 @@ index fad8f9ea0043..4f8fc3f6507c 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -5300,6 +5323,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+@@ -5300,6 +5327,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--e1000e--30100--30400 b/LINUX/final-patches/vanilla--e1000e--30100--30400
index 0b49fb49e..22777f7cc 100644
--- a/LINUX/final-patches/vanilla--e1000e--30100--30400
+++ b/LINUX/final-patches/vanilla--e1000e--30100--30400
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 2198e615f241..3c95b385bfee 100644
+index 2198e615f241..408d54a7c02f 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -452,6 +452,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -46,7 +46,18 @@ index 2198e615f241..3c95b385bfee 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC(*rx_ring, i);
  	buffer_info = &rx_ring->buffer_info[i];
-@@ -3177,6 +3193,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -2908,6 +2924,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
+ 		adapter->rx_ps_pages = pages;
+ 	else
+ 		adapter->rx_ps_pages = 0;
++#ifdef DEV_NETMAP
++       /* Keep packet-split disabled with netmap. */
++       adapter->rx_ps_pages = 0;
++#endif /* DEV_NETMAP */
+ 
+ 	if (adapter->rx_ps_pages) {
+ 		u32 psrctl = 0;
+@@ -3177,6 +3197,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  	e1000_configure_tx(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -57,7 +68,7 @@ index 2198e615f241..3c95b385bfee 100644
  	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring),
  			      GFP_KERNEL);
  }
-@@ -6147,6 +6167,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+@@ -6147,6 +6171,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
  	if (err)
  		goto err_register;
  
@@ -67,7 +78,7 @@ index 2198e615f241..3c95b385bfee 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6234,6 +6257,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+@@ -6234,6 +6261,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--e1000e--30400--30900 b/LINUX/final-patches/vanilla--e1000e--30400--30900
index b0c28a433..977ef0464 100644
--- a/LINUX/final-patches/vanilla--e1000e--30400--30900
+++ b/LINUX/final-patches/vanilla--e1000e--30400--30900
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 9520a6ac1f30..6abd65519fd4 100644
+index 9520a6ac1f30..244e75747e16 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -467,6 +467,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -46,7 +46,18 @@ index 9520a6ac1f30..6abd65519fd4 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -3358,6 +3374,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -2976,6 +2992,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
+ 		adapter->rx_ps_pages = pages;
+ 	else
+ 		adapter->rx_ps_pages = 0;
++#ifdef DEV_NETMAP
++	/* Keep packet-split disabled with netmap. */
++	adapter->rx_ps_pages = 0;
++#endif /* DEV_NETMAP */
+ 
+ 	if (adapter->rx_ps_pages) {
+ 		u32 psrctl = 0;
+@@ -3358,6 +3378,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  		e1000e_setup_rss_hash(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -57,7 +68,7 @@ index 9520a6ac1f30..6abd65519fd4 100644
  	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
  }
  
-@@ -6417,6 +6437,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+@@ -6417,6 +6441,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
  	if (err)
  		goto err_register;
  
@@ -67,7 +78,7 @@ index 9520a6ac1f30..6abd65519fd4 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6504,6 +6527,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+@@ -6504,6 +6531,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--e1000e--30900--99999 b/LINUX/final-patches/vanilla--e1000e--30900--99999
index b844a5f20..2b82b74b1 100644
--- a/LINUX/final-patches/vanilla--e1000e--30900--99999
+++ b/LINUX/final-patches/vanilla--e1000e--30900--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 7e615e2bf7e6..361401a7a46c 100644
+index 7e615e2bf7e6..9b2b1945c6d2 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -473,6 +473,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -46,7 +46,18 @@ index 7e615e2bf7e6..361401a7a46c 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -3685,6 +3701,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -3087,6 +3103,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
+ 		adapter->rx_ps_pages = pages;
+ 	else
+ 		adapter->rx_ps_pages = 0;
++#ifdef DEV_NETMAP
++	/* Keep packet-split disabled with netmap. */
++	adapter->rx_ps_pages = 0;
++#endif /* DEV_NETMAP */
+ 
+ 	if (adapter->rx_ps_pages) {
+ 		u32 psrctl = 0;
+@@ -3685,6 +3705,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  		e1000e_setup_rss_hash(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -57,7 +68,7 @@ index 7e615e2bf7e6..361401a7a46c 100644
  	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
  }
  
-@@ -6768,6 +6788,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -6768,6 +6792,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	if (err)
  		goto err_register;
  
@@ -67,7 +78,7 @@ index 7e615e2bf7e6..361401a7a46c 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6866,6 +6889,10 @@ static void e1000_remove(struct pci_dev *pdev)
+@@ -6866,6 +6893,10 @@ static void e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  

From 7856f0757bd8c600a54ef0459ecbd0e840d5b18d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 17:04:21 +0100
Subject: [PATCH 0553/2207] netmap_mem_map: warn about failures in
 netmap_map_load()

---
 sys/dev/netmap/netmap_mem2.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 20e0e5644..1d8aa65f2 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1479,8 +1479,10 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 
 		error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr,
 				p->lut[i].vaddr, p->_clustsize);
-		if (error)
+		if (error) {
+			D("Failed to map cluster #%d from the %s pool", i, p->name);
 			break;
+		}
 
 		for (j = 1; j < p->_clustentries; j++) {
 			lut->plut[i + j].paddr = lut->plut[i + j - 1].paddr + p->_objsize;

From ee86ed988c1a0936d18c87b3d18a3338c0071983 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 17:33:19 +0100
Subject: [PATCH 0554/2207] linux: e1000e_rxsync: add support for NS_MOREFRAG

---
 LINUX/if_e1000e_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 3845c9545..ce32f3193 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -253,7 +253,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 				break;
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
-			slot->flags = 0;
+			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr,
 					slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);

From e836cfc553ae77d51f5ab74cafd006e000cfbd99 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 17:52:57 +0100
Subject: [PATCH 0555/2207] linux: e1000e_txsync: add support for NS_MOREFRAG

---
 LINUX/if_e1000e_netmap.h | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index ce32f3193..6b5be24ce 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -155,21 +155,22 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
-			int flags = (slot->flags & NS_REPORT ||
+			int hw_flags = (slot->flags & NS_REPORT ||
 				nic_i == 0 || nic_i == report_frequency) ?
 				E1000_TXD_CMD_RS : 0;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
+			if (!(slot->flags & NS_MOREFRAG))
+				hw_flags |= E1000_TXD_CMD_EOP;
 			if (slot->flags & NS_BUF_CHANGED) {
 				curr->buffer_addr = htole64(paddr);
 			}
-			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
-			curr->lower.data = htole32(adapter->txd_cmd | len | flags |
-				E1000_TXD_CMD_EOP);
+			curr->lower.data = htole32(adapter->txd_cmd | len | hw_flags);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);

From a23cda49c637c384305d1d8c71bc18bf74bb0c07 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 26 Feb 2018 19:57:13 +0100
Subject: [PATCH 0556/2207] linux: upgrade e1000 patches to support jumbo
 frames

---
 ...20--31200 => vanilla--e1000--20620--99999} | 20 ++++-
 .../vanilla--e1000--31200--99999              | 75 -------------------
 2 files changed, 18 insertions(+), 77 deletions(-)
 rename LINUX/final-patches/{vanilla--e1000--20620--31200 => vanilla--e1000--20620--99999} (77%)
 delete mode 100644 LINUX/final-patches/vanilla--e1000--31200--99999

diff --git a/LINUX/final-patches/vanilla--e1000--20620--31200 b/LINUX/final-patches/vanilla--e1000--20620--99999
similarity index 77%
rename from LINUX/final-patches/vanilla--e1000--20620--31200
rename to LINUX/final-patches/vanilla--e1000--20620--99999
index 0d8bb0577..b6d431c66 100644
--- a/LINUX/final-patches/vanilla--e1000--20620--31200
+++ b/LINUX/final-patches/vanilla--e1000--20620--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index bcd192c..013f528 100644
+index bcd192ca47b0..1e1a6b61ece4 100644
 --- a/e1000/e1000_main.c
 +++ b/e1000/e1000_main.c
 @@ -190,6 +190,10 @@ static struct pci_error_handlers e1000_err_handler = {
@@ -57,7 +57,23 @@ index bcd192c..013f528 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -3795,6 +3815,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
+@@ -3614,6 +3634,15 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes=0, total_rx_packets=0;
+ 
++#ifdef DEV_NETMAP
++       int nm_irq = netmap_rx_irq(netdev, 0, work_done);
++       if (nm_irq != NM_IRQ_PASS) {
++               if (nm_irq == NM_IRQ_RESCHED) {
++                       *work_done = work_to_do;
++               }
++               return 1;
++       }
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC(*rx_ring, i);
+ 	buffer_info = &rx_ring->buffer_info[i];
+@@ -3795,6 +3824,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
  	bool cleaned = false;
  	unsigned int total_rx_bytes=0, total_rx_packets=0;
  
diff --git a/LINUX/final-patches/vanilla--e1000--31200--99999 b/LINUX/final-patches/vanilla--e1000--31200--99999
deleted file mode 100644
index eeca93fd1..000000000
--- a/LINUX/final-patches/vanilla--e1000--31200--99999
+++ /dev/null
@@ -1,75 +0,0 @@
-diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index 24f3986..c28425f 100644
---- a/e1000/e1000_main.c
-+++ b/e1000/e1000_main.c
-@@ -200,6 +200,10 @@ static const struct pci_error_handlers e1000_err_handler = {
- 	.resume = e1000_io_resume,
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- static struct pci_driver e1000_driver = {
- 	.name     = e1000_driver_name,
- 	.id_table = e1000_pci_tbl,
-@@ -395,6 +399,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
- 	e1000_configure_tx(adapter);
- 	e1000_setup_rctl(adapter);
- 	e1000_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	if (e1000_netmap_init_buffers(adapter))
-+		return;
-+#endif /* DEV_NETMAP */
- 	/* call E1000_DESC_UNUSED which always leaves
- 	 * at least 1 descriptor unused to make sure
- 	 * next_to_use != next_to_clean
-@@ -1213,6 +1221,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 
- 	e1000_vlan_filter_on_off(adapter, false);
- 
-+#ifdef DEV_NETMAP
-+	e1000_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	/* print bus type/speed/width info */
- 	e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
- 	       ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
-@@ -1277,6 +1289,10 @@ static void e1000_remove(struct pci_dev *pdev)
- 
- 	kfree(adapter->tx_ring);
- 	kfree(adapter->rx_ring);
-+	
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
- 
- 	if (hw->mac_type == e1000_ce4100)
- 		iounmap(hw->ce4100_gbe_mdio_base_virt);
-@@ -3841,6 +3857,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
- 	unsigned int total_tx_bytes=0, total_tx_packets=0;
- 	unsigned int bytes_compl = 0, pkts_compl = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
-+		return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -4355,6 +4375,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes=0, total_rx_packets=0;
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		if (nm_irq == NM_IRQ_RESCHED) {
-+			*work_done = work_to_do;
-+		}
-+		return 1;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];

From 744f3f3fb169b9d7cb433cefc2ccb6292f3d4595 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 09:26:58 +0100
Subject: [PATCH 0557/2207] add NAF_MOREFRAG to support the MTU sanity check in
 netmap_do_regif()

---
 sys/dev/netmap/netmap.c      | 21 ++++++++++++++-------
 sys/dev/netmap/netmap_kern.h |  1 +
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0e3412d1f..1cddb05af 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2084,14 +2084,21 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 * perform sanity checks and create the in-kernel view
 		 * of the netmap rings (the netmap krings).
 		 */
-		if (na->ifp) {
-			/* This netmap adapter is attached to an ifnet.
-			 * Check that netmap buffer size is at least as
-			 * big as device MTU. */
-			if (netmap_mem_bufsize(na->nm_mem) <
+		if (na->ifp && netmap_mem_bufsize(na->nm_mem) <
 					nm_os_ifnet_mtu(na->ifp)) {
-				D("Error: netmap buf_size (%u) smaller "
-					"than device MTU (%u)",
+			/* This netmap adapter is attached to an ifnet.
+			 * If netmap buffer size is smaller than device
+			 * MTU we need to make sure that the adapter
+			 * supports NS_MOREFRAG. */
+			if (na->na_flags & NAF_MOREFRAG) {
+				nm_prinf("netmap buf_size (%u) < device "
+					"MTU (%u): application may need "
+					"to use NS_MOREFRAG",
+					netmap_mem_bufsize(na->nm_mem),
+					nm_os_ifnet_mtu(na->ifp));
+			} else {
+				nm_prerr("Error: netmap buf_size (%u) < "
+					"device MTU (%u)",
 					netmap_mem_bufsize(na->nm_mem),
 					nm_os_ifnet_mtu(na->ifp));
 				error = EINVAL;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e79249829..5663e4f4a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -664,6 +664,7 @@ struct netmap_adapter {
 #define NAF_HOST_RINGS  64	/* the adapter supports the host rings */
 #define NAF_FORCE_NATIVE 128	/* the adapter is always NATIVE */
 #define NAF_PTNETMAP_HOST 256	/* the adapter supports ptnetmap in the host */
+#define NAF_MOREFRAG	512	/* the adapter supports NS_MOREFRAG */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
 				  * cannot be registered from userspace

From 509a967a7314105f8b22e994a22328bd78ca539c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 09:41:59 +0100
Subject: [PATCH 0558/2207] linux: e1000,e1000e,ixgbe: expose NAF_MOREFRAG flag

---
 LINUX/if_e1000_netmap.h    | 1 +
 LINUX/if_e1000e_netmap.h   | 1 +
 LINUX/ixgbe_netmap_linux.h | 1 +
 3 files changed, 3 insertions(+)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 3dd6169f7..7eb1a4142 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -348,6 +348,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
+	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = adapter->tx_ring[0].count;
 	na.num_rx_desc = adapter->rx_ring[0].count;
 	na.nm_register = e1000_netmap_reg;
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 6b5be24ce..58f40b87a 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -372,6 +372,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
+	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = adapter->tx_ring->count;
 	na.num_rx_desc = adapter->rx_ring->count;
 	na.nm_register = e1000_netmap_reg;
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 50abe24cf..f42f2da21 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -773,6 +773,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
+	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = NM_IXGBE_TX_RING(adapter, 0)->count;
 	na.num_rx_desc = NM_IXGBE_RX_RING(adapter, 0)->count;
 	na.nm_txsync = ixgbe_netmap_txsync;

From 426e40262200a92578f7f483793f2bedae9d10c4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 10:12:54 +0100
Subject: [PATCH 0559/2207] linux: i40e: txsync: add support for NS_MOREFRAG

---
 LINUX/i40e_netmap_linux.h | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 4f356e9a2..659901a67 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -365,7 +365,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			struct i40e_tx_desc *curr = I40E_TX_DESC(txr, nic_i);
-			u64 flags = (slot->flags & NS_REPORT ||
+			u64 hw_flags = (slot->flags & NS_REPORT ||
 				nic_i == 0 || nic_i == report_frequency) ?
 				((u64)I40E_TX_DESC_CMD_RS << I40E_TXD_QW1_CMD_SHIFT) : 0;
 
@@ -375,20 +375,24 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
+			if (!(slot->flags & NS_MOREFRAG)) {
+				hw_flags |= ((u64)(I40E_TX_DESC_CMD_EOP) << I40E_TXD_QW1_CMD_SHIFT);
+			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				/* buffer has changed, reload map */
 				//netmap_reload_map(na, txr->dma.tag, txbuf->map, addr);
 			}
-			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
-			/* Fill the slot in the NIC ring. */
-			/* Use legacy descriptor, they are faster? */
+			/* Fill the slot in the NIC ring.
+			 * (we should investigate if using legacy descriptors
+			 * is faster). */
 			curr->buffer_addr = htole64(paddr);
 			curr->cmd_type_offset_bsz = htole64(
 			    ((u64)len << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
-			    flags |
-			    ((u64)(I40E_TX_DESC_CMD_ICRC | I40E_TX_DESC_CMD_EOP) << I40E_TXD_QW1_CMD_SHIFT)
-			  ); // XXX more ?
+			    hw_flags |
+			    ((u64)(I40E_TX_DESC_CMD_ICRC) << I40E_TXD_QW1_CMD_SHIFT)
+			  ); /* more flags may be needed */
 
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);

From 69ac8851299f3db7f732173fb2a7c6160e8296de Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 10:15:44 +0100
Subject: [PATCH 0560/2207] linux: i40e: expose NAF_MOREFRAG

---
 LINUX/i40e_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 659901a67..226d6902d 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -247,7 +247,7 @@ i40e_netmap_attach(struct i40e_vsi *vsi)
 
 	na.ifp = vsi->netdev;
 	na.pdev = &vsi->back->pdev->dev;
-	// XXX check that queues is set.
+	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = NM_I40E_TX_RING(vsi, 0)->count;
 	na.num_rx_desc = NM_I40E_RX_RING(vsi, 0)->count;
 	na.nm_txsync = i40e_netmap_txsync;

From a4d9767e05e9bf2444517e5015ba6f1cd6c43f40 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 11:29:36 +0100
Subject: [PATCH 0561/2207] utils: add program for functional tests

---
 utils/GNUmakefile  |   2 +-
 utils/functional.c | 206 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 207 insertions(+), 1 deletion(-)
 create mode 100644 utils/functional.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index a32ab1147..b121f1f8d 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,6 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm
+PROGS	= test_select testmmap test_nm functional
 X86PROGS = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/functional.c b/utils/functional.c
new file mode 100644
index 000000000..c2079a765
--- /dev/null
+++ b/utils/functional.c
@@ -0,0 +1,206 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+
+#define ETH_ADDR_LEN 6
+
+struct Global {
+	struct nm_desc *nmd;
+	const char *ifname;
+	unsigned wait_secs;
+#define MAX_PKT_SIZE 65536
+	char pktm[MAX_PKT_SIZE]; /* packet model */
+	unsigned pktm_len;       /* packet model len */
+	char src_mac[ETH_ADDR_LEN];
+	char dst_mac[ETH_ADDR_LEN];
+	uint32_t src_ip;
+	uint32_t dst_ip;
+	uint16_t src_port;
+	uint16_t dst_port;
+	char filler;
+};
+
+static void
+fill_packet_field(struct Global *g, unsigned offset, const char *content,
+		  unsigned content_len)
+{
+	if (offset + content_len > sizeof(g->pktm)) {
+		printf("Packet layout overflow: %u + %u > %lu\n", offset,
+		       content_len, sizeof(g->pktm));
+		exit(EXIT_FAILURE);
+	}
+
+	memcpy(g->pktm + offset, content, content_len);
+}
+
+static void
+fill_packet_8bit(struct Global *g, unsigned offset, uint8_t val)
+{
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_16bit(struct Global *g, unsigned offset, uint16_t val)
+{
+	val = htons(val);
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_32bit(struct Global *g, unsigned offset, uint32_t val)
+{
+	val = htonl(val);
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+build_packet(struct Global *g)
+{
+	unsigned ofs = 0, hdrofs = 0;
+
+	memset(g->pktm, 0, sizeof(g->pktm));
+	printf("%s: starting at ofs %u\n", __func__, ofs);
+
+	hdrofs = ofs;
+	/* Ethernet destination and source MAC address plus ethertype. */
+	fill_packet_field(g, ofs, g->dst_mac, ETH_ADDR_LEN);
+	ofs += ETH_ADDR_LEN;
+	fill_packet_field(g, ofs, g->src_mac, ETH_ADDR_LEN);
+	ofs += ETH_ADDR_LEN;
+	fill_packet_16bit(g, ofs, ETHERTYPE_IP);
+	ofs += 2;
+	printf("%s: eth done, ofs %u\n", __func__, ofs);
+
+	hdrofs = ofs;
+	/* First byte of IP header. */
+	fill_packet_8bit(g, ofs,
+			 (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
+	ofs += 1;
+	/* Skip QoS byte. */
+	ofs += 1;
+	/* Total length. */
+	fill_packet_16bit(g, ofs, g->pktm_len - hdrofs);
+	ofs += 2;
+	/* Skip identification field. */
+	ofs += 2;
+	/* Offset (and flags) field. */
+	fill_packet_16bit(g, ofs, IP_DF);
+	ofs += 2;
+	/* TTL. */
+	fill_packet_8bit(g, ofs, IPDEFTTL);
+	ofs += 1;
+	/* Protocol. */
+	fill_packet_8bit(g, ofs, IPPROTO_UDP);
+	ofs += 1;
+	/* Skip checksum for now. */
+	ofs += 2;
+	/* Source IP address. */
+	fill_packet_32bit(g, ofs, g->src_ip);
+	ofs += 4;
+	/* Dst IP address. */
+	fill_packet_32bit(g, ofs, g->dst_ip);
+	ofs += 4;
+	printf("%s: ip done, ofs %u\n", __func__, ofs);
+
+	hdrofs = ofs;
+	/* UDP source port. */
+	fill_packet_16bit(g, ofs, g->src_port);
+	ofs += 2;
+	/* UDP source port. */
+	fill_packet_16bit(g, ofs, g->dst_port);
+	ofs += 2;
+	/* UDP length (UDP header + data). */
+	fill_packet_16bit(g, ofs, g->pktm_len - hdrofs);
+	ofs += 2;
+	/* Skip checksum for now. */
+	ofs += 2;
+	printf("%s: udp done, ofs %u\n", __func__, ofs);
+
+	/* Fill UDP payload. */
+	for (; ofs < g->pktm_len; ofs++) {
+		fill_packet_8bit(g, ofs, g->filler);
+	}
+}
+
+static struct Global _g;
+
+static void
+usage(void)
+{
+	printf("usage: ./functional [-h]\n"
+	       "-i NETMAP_PORT\n"
+	       "[-l PACKET_LEN (=6)]\n"
+	       "[-w WAIT_LINK_SECS (=0)]\n");
+}
+
+int
+main(int argc, char **argv)
+{
+	struct Global *g = &_g;
+	int opt;
+	int i;
+
+	g->ifname    = NULL;
+	g->nmd       = NULL;
+	g->wait_secs = 0;
+	g->pktm_len  = 60;
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		g->src_mac[i] = 0x00;
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		g->dst_mac[i] = 0xFF;
+	g->src_ip = 0x0A000005; /* 10.0.0.5 */
+	g->dst_ip = 0x0A000007; /* 10.0.0.7 */
+	g->filler = 'a';
+
+	while ((opt = getopt(argc, argv, "hi:w:l:")) != -1) {
+		switch (opt) {
+		case 'h':
+			usage();
+			return 0;
+
+		case 'i':
+			g->ifname = optarg;
+			break;
+
+		case 'w':
+			g->wait_secs = atoi(optarg);
+			break;
+
+		case 'l':
+			g->pktm_len = atoi(optarg);
+			break;
+
+		default:
+			printf("    Unrecognized option %c\n", opt);
+			usage();
+			return -1;
+		}
+	}
+
+	if (!g->ifname) {
+		printf("Missing ifname\n");
+		usage();
+		return -1;
+	}
+
+	g->nmd = nm_open(g->ifname, NULL, 0, NULL);
+	if (g->nmd == NULL) {
+		printf("Failed to nm_open(%s)\n", g->ifname);
+		return -1;
+	}
+
+	build_packet(g);
+
+	nm_close(g->nmd);
+
+	return 0;
+}

From 7b0edb5ba38af87c4bda7629e0d33473db3096cd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 13:05:55 +0100
Subject: [PATCH 0562/2207] utils: functional: add checksum support

---
 utils/functional.c | 82 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 75 insertions(+), 7 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index c2079a765..873a1a040 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -62,15 +62,53 @@ fill_packet_32bit(struct Global *g, unsigned offset, uint32_t val)
 	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
 }
 
+/* Compute the checksum of the given ip header. */
+static uint32_t
+checksum(const void *data, uint16_t len, uint32_t sum)
+{
+	const uint8_t *addr = data;
+	uint32_t i;
+
+	/* Checksum all the pairs of bytes first... */
+	for (i = 0; i < (len & ~1U); i += 2) {
+		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+	/*
+	 * If there's a single byte left over, checksum it, too.
+	 * Network byte order is big-endian, so the remaining byte is
+	 * the high byte.
+	 */
+	if (i < len) {
+		sum += addr[i] << 8;
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+	return sum;
+}
+
+static uint16_t
+wrapsum(uint32_t sum)
+{
+	sum = ~sum & 0xFFFF;
+	return sum; /* htons() is called by fill_16bit */
+}
+
 static void
 build_packet(struct Global *g)
 {
-	unsigned ofs = 0, hdrofs = 0;
+	unsigned ofs = 0;
+	unsigned ethofs;
+	unsigned ipofs;
+	unsigned udpofs;
+	unsigned pldofs;
 
 	memset(g->pktm, 0, sizeof(g->pktm));
 	printf("%s: starting at ofs %u\n", __func__, ofs);
 
-	hdrofs = ofs;
+	ethofs = ofs;
+	(void)ethofs;
 	/* Ethernet destination and source MAC address plus ethertype. */
 	fill_packet_field(g, ofs, g->dst_mac, ETH_ADDR_LEN);
 	ofs += ETH_ADDR_LEN;
@@ -80,7 +118,7 @@ build_packet(struct Global *g)
 	ofs += 2;
 	printf("%s: eth done, ofs %u\n", __func__, ofs);
 
-	hdrofs = ofs;
+	ipofs = ofs;
 	/* First byte of IP header. */
 	fill_packet_8bit(g, ofs,
 			 (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
@@ -88,7 +126,7 @@ build_packet(struct Global *g)
 	/* Skip QoS byte. */
 	ofs += 1;
 	/* Total length. */
-	fill_packet_16bit(g, ofs, g->pktm_len - hdrofs);
+	fill_packet_16bit(g, ofs, g->pktm_len - ipofs);
 	ofs += 2;
 	/* Skip identification field. */
 	ofs += 2;
@@ -109,9 +147,13 @@ build_packet(struct Global *g)
 	/* Dst IP address. */
 	fill_packet_32bit(g, ofs, g->dst_ip);
 	ofs += 4;
+	/* Now put the checksum. */
+	fill_packet_16bit(
+		g, ipofs + 10,
+		wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
 	printf("%s: ip done, ofs %u\n", __func__, ofs);
 
-	hdrofs = ofs;
+	udpofs = ofs;
 	/* UDP source port. */
 	fill_packet_16bit(g, ofs, g->src_port);
 	ofs += 2;
@@ -119,16 +161,40 @@ build_packet(struct Global *g)
 	fill_packet_16bit(g, ofs, g->dst_port);
 	ofs += 2;
 	/* UDP length (UDP header + data). */
-	fill_packet_16bit(g, ofs, g->pktm_len - hdrofs);
+	fill_packet_16bit(g, ofs, g->pktm_len - udpofs);
 	ofs += 2;
-	/* Skip checksum for now. */
+	/* Skip the UDP checksum for now. */
 	ofs += 2;
 	printf("%s: udp done, ofs %u\n", __func__, ofs);
 
 	/* Fill UDP payload. */
+	pldofs = ofs;
 	for (; ofs < g->pktm_len; ofs++) {
 		fill_packet_8bit(g, ofs, g->filler);
 	}
+
+	/* Put the UDP checksum now.
+	 * Magic: taken from sbin/dhclient/packet.c */
+	fill_packet_16bit(
+		g, udpofs + 6,
+		wrapsum(checksum(
+			g->pktm + udpofs,
+			sizeof(struct udphdr),     /* udp header */
+			checksum(g->pktm + pldofs, /* udp payload */
+				 g->pktm_len - pldofs,
+				 checksum(g->pktm + ipofs +
+						  12, /* pseudo header */
+					  2 * 4,
+					  IPPROTO_UDP +
+						  (uint32_t)ntohs(g->pktm_len -
+								  udpofs))))));
+}
+
+static int
+tx_one(struct Global *g)
+{
+	(void)g;
+	return 0;
 }
 
 static struct Global _g;
@@ -200,6 +266,8 @@ main(int argc, char **argv)
 
 	build_packet(g);
 
+	tx_one(g);
+
 	nm_close(g->nmd);
 
 	return 0;

From f0920098fd8cc82ccd9d31594b3f0daa84eaa9ad Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 15:33:15 +0100
Subject: [PATCH 0563/2207] utils: functional: implement tx_one

---
 utils/functional.c | 59 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 46 insertions(+), 13 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 873a1a040..b6061dd07 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #define NETMAP_WITH_LIBS
 #include 
 
@@ -64,7 +65,7 @@ fill_packet_32bit(struct Global *g, unsigned offset, uint32_t val)
 
 /* Compute the checksum of the given ip header. */
 static uint32_t
-checksum(const void *data, uint16_t len, uint32_t sum)
+checksum(const void *data, uint16_t len, uint32_t sum /* host endianness */)
 {
 	const uint8_t *addr = data;
 	uint32_t i;
@@ -89,10 +90,10 @@ checksum(const void *data, uint16_t len, uint32_t sum)
 }
 
 static uint16_t
-wrapsum(uint32_t sum)
+wrapsum(uint32_t sum /* host endianness */)
 {
 	sum = ~sum & 0xFFFF;
-	return sum; /* htons() is called by fill_16bit */
+	return sum; /* host endianness */
 }
 
 static void
@@ -172,28 +173,60 @@ build_packet(struct Global *g)
 	for (; ofs < g->pktm_len; ofs++) {
 		fill_packet_8bit(g, ofs, g->filler);
 	}
+	printf("%s: payload done, ofs %u\n", __func__, ofs);
 
 	/* Put the UDP checksum now.
 	 * Magic: taken from sbin/dhclient/packet.c */
 	fill_packet_16bit(
 		g, udpofs + 6,
 		wrapsum(checksum(
-			g->pktm + udpofs,
-			sizeof(struct udphdr),     /* udp header */
-			checksum(g->pktm + pldofs, /* udp payload */
+			/* udp header */ g->pktm + udpofs,
+			sizeof(struct udphdr),
+			checksum(/* udp payload */ g->pktm + pldofs,
 				 g->pktm_len - pldofs,
-				 checksum(g->pktm + ipofs +
-						  12, /* pseudo header */
-					  2 * 4,
-					  IPPROTO_UDP +
-						  (uint32_t)ntohs(g->pktm_len -
-								  udpofs))))));
+				 checksum(/* pseudo header */ g->pktm + ipofs +
+						  12,
+					  2 * sizeof(g->src_ip),
+					  IPPROTO_UDP + (uint32_t)(g->pktm_len -
+								   udpofs))))));
 }
 
 static int
 tx_one(struct Global *g)
 {
-	(void)g;
+	struct nm_desc *nmd = g->nmd;
+	unsigned int i;
+
+	for (;;) {
+		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+			struct netmap_slot *slot = &ring->slot[ring->head];
+			char *buf = NETMAP_BUF(ring, slot->buf_idx);
+
+			if (nm_ring_empty(ring)) {
+				continue;
+			}
+			if (g->pktm_len > ring->nr_buf_size) {
+				/* Sanity check. */
+				printf("Error: len (%u) > netmap_buf_size "
+				       "(%u)\n",
+				       g->pktm_len, ring->nr_buf_size);
+				exit(EXIT_FAILURE);
+			}
+			memcpy(buf, g->pktm, g->pktm_len);
+			slot->len   = g->pktm_len;
+			slot->flags = NS_REPORT;
+			ring->head = ring->cur = ring->head + 1;
+			ioctl(nmd->fd, NIOCTXSYNC, NULL);
+			printf("packet pushed to the TX ring\n");
+			return 0;
+		}
+
+		/* Retry after a short while. */
+		usleep(100000);
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+
 	return 0;
 }
 

From 0cf681b370859c03f785ff7308b261f4c214441e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 16:03:08 +0100
Subject: [PATCH 0564/2207] utils: functional: implement rx_one()

---
 utils/functional.c | 49 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index b6061dd07..507d4e129 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -18,9 +18,13 @@ struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
 	unsigned wait_secs;
+
 #define MAX_PKT_SIZE 65536
 	char pktm[MAX_PKT_SIZE]; /* packet model */
-	unsigned pktm_len;       /* packet model len */
+	unsigned pktm_len;       /* packet model length */
+	char pktr[MAX_PKT_SIZE]; /* packet received */
+	unsigned pktr_len;       /* length of received packet */
+
 	char src_mac[ETH_ADDR_LEN];
 	char dst_mac[ETH_ADDR_LEN];
 	uint32_t src_ip;
@@ -218,7 +222,47 @@ tx_one(struct Global *g)
 			slot->flags = NS_REPORT;
 			ring->head = ring->cur = ring->head + 1;
 			ioctl(nmd->fd, NIOCTXSYNC, NULL);
-			printf("packet pushed to the TX ring\n");
+			printf("packet (%u bytes) transmitted to TX ring #%d\n",
+			       slot->len, i);
+			return 0;
+		}
+
+		/* Retry after a short while. */
+		usleep(100000);
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+
+	return 0;
+}
+
+static int
+rx_one(struct Global *g)
+{
+	struct nm_desc *nmd = g->nmd;
+	unsigned int i;
+
+	for (;;) {
+		for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+			struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+			struct netmap_slot *slot = &ring->slot[ring->head];
+			char *buf = NETMAP_BUF(ring, slot->buf_idx);
+
+			if (nm_ring_empty(ring)) {
+				continue;
+			}
+			if (ring->nr_buf_size > sizeof(g->pktr)) {
+				/* Sanity check. */
+				printf("Error: netmap_buf_size (%u) > "
+				       "receive_buf_size (%lu)\n",
+				       ring->nr_buf_size, sizeof(g->pktr));
+				exit(EXIT_FAILURE);
+			}
+			memcpy(g->pktr, buf, slot->len);
+			g->pktr_len = slot->len;
+			ring->head = ring->cur = ring->head + 1;
+			ioctl(nmd->fd, NIOCRXSYNC, NULL);
+			printf("packet (%u bytes) received from RX ring #%d\n",
+			       g->pktr_len, i);
 			return 0;
 		}
 
@@ -300,6 +344,7 @@ main(int argc, char **argv)
 	build_packet(g);
 
 	tx_one(g);
+	rx_one(g);
 
 	nm_close(g->nmd);
 

From 653c237d2c08ff3aa95ff4d6f064ee61a0e6ca8f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 16:33:20 +0100
Subject: [PATCH 0565/2207] utils: functional: implement rx_check()

---
 utils/functional.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/utils/functional.c b/utils/functional.c
index 507d4e129..6265333f8 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -268,7 +268,31 @@ rx_one(struct Global *g)
 
 		/* Retry after a short while. */
 		usleep(100000);
-		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+		ioctl(nmd->fd, NIOCRXSYNC, NULL);
+	}
+
+	return 0;
+}
+
+static int
+rx_check(struct Global *g)
+{
+	unsigned i;
+
+	if (g->pktr_len != g->pktm_len) {
+		printf("Received packet length (%u) different from "
+		       "expected (%u bytes)\n",
+		       g->pktr_len, g->pktm_len);
+		return -1;
+	}
+
+	for (i = 0; i < g->pktr_len; i++) {
+		if (g->pktr[i] != g->pktm[i]) {
+			printf("Received packet differs from model at "
+			       "offset %u (%x!=%x)\n",
+			       i, g->pktr[i], g->pktm[i]);
+			return -1;
+		}
 	}
 
 	return 0;
@@ -345,6 +369,9 @@ main(int argc, char **argv)
 
 	tx_one(g);
 	rx_one(g);
+	if (rx_check(g)) {
+		exit(EXIT_FAILURE);
+	}
 
 	nm_close(g->nmd);
 

From 804f1161113fd06e8b2c6f0cf1f7eecb0bea80c1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 16:43:12 +0100
Subject: [PATCH 0566/2207] utils: functional: add receive timeout

---
 utils/functional.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 6265333f8..9fd16b1b0 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -17,7 +17,8 @@
 struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
-	unsigned wait_secs;
+	unsigned wait_link_secs; /* wait for link */
+	unsigned timeout_secs;   /* receive timeout */
 
 #define MAX_PKT_SIZE 65536
 	char pktm[MAX_PKT_SIZE]; /* packet model */
@@ -232,6 +233,7 @@ tx_one(struct Global *g)
 		ioctl(nmd->fd, NIOCTXSYNC, NULL);
 	}
 
+	/* never reached */
 	return 0;
 }
 
@@ -239,6 +241,8 @@ static int
 rx_one(struct Global *g)
 {
 	struct nm_desc *nmd = g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
 	unsigned int i;
 
 	for (;;) {
@@ -266,8 +270,14 @@ rx_one(struct Global *g)
 			return 0;
 		}
 
+		if (elapsed_ms / 1000 > g->timeout_secs) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+
 		/* Retry after a short while. */
-		usleep(100000);
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
 		ioctl(nmd->fd, NIOCRXSYNC, NULL);
 	}
 
@@ -316,10 +326,10 @@ main(int argc, char **argv)
 	int opt;
 	int i;
 
-	g->ifname    = NULL;
-	g->nmd       = NULL;
-	g->wait_secs = 0;
-	g->pktm_len  = 60;
+	g->ifname	 = NULL;
+	g->nmd		  = NULL;
+	g->wait_link_secs = 0;
+	g->pktm_len       = 60;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		g->src_mac[i] = 0x00;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
@@ -339,7 +349,7 @@ main(int argc, char **argv)
 			break;
 
 		case 'w':
-			g->wait_secs = atoi(optarg);
+			g->wait_link_secs = atoi(optarg);
 			break;
 
 		case 'l':
@@ -364,13 +374,18 @@ main(int argc, char **argv)
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		return -1;
 	}
+	if (g->wait_link_secs > 0) {
+		sleep(g->wait_link_secs);
+	}
 
 	build_packet(g);
 
 	tx_one(g);
-	rx_one(g);
+	if (rx_one(g)) {
+		return -1;
+	}
 	if (rx_check(g)) {
-		exit(EXIT_FAILURE);
+		return -1;
 	}
 
 	nm_close(g->nmd);

From d47d07d1582a1000f4980390b2bc16c993a3e29a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 17:06:53 +0100
Subject: [PATCH 0567/2207] utils: functional: add support for NS_MOREFRAG

---
 utils/functional.c | 70 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 56 insertions(+), 14 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 9fd16b1b0..50716d41e 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -1,3 +1,29 @@
+/*
+ * A tool for functional testing netmap transmission and reception.
+ *
+ * Copyright (C) 2018 Vincenzo Maffione. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 #include 
 #include 
 #include 
@@ -196,6 +222,7 @@ build_packet(struct Global *g)
 								   udpofs))))));
 }
 
+/* Transmit a single packet using any TX ring. */
 static int
 tx_one(struct Global *g)
 {
@@ -221,7 +248,7 @@ tx_one(struct Global *g)
 			memcpy(buf, g->pktm, g->pktm_len);
 			slot->len   = g->pktm_len;
 			slot->flags = NS_REPORT;
-			ring->head = ring->cur = ring->head + 1;
+			ring->head = ring->cur = nm_ring_next(ring, ring->head);
 			ioctl(nmd->fd, NIOCTXSYNC, NULL);
 			printf("packet (%u bytes) transmitted to TX ring #%d\n",
 			       slot->len, i);
@@ -237,6 +264,7 @@ tx_one(struct Global *g)
 	return 0;
 }
 
+/* Receive a single packet from any RX ring. */
 static int
 rx_one(struct Global *g)
 {
@@ -248,25 +276,39 @@ rx_one(struct Global *g)
 	for (;;) {
 		for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
-			struct netmap_slot *slot = &ring->slot[ring->head];
-			char *buf = NETMAP_BUF(ring, slot->buf_idx);
+			unsigned int head	= ring->head;
+			unsigned int frags       = 0;
 
 			if (nm_ring_empty(ring)) {
 				continue;
 			}
-			if (ring->nr_buf_size > sizeof(g->pktr)) {
-				/* Sanity check. */
-				printf("Error: netmap_buf_size (%u) > "
-				       "receive_buf_size (%lu)\n",
-				       ring->nr_buf_size, sizeof(g->pktr));
-				exit(EXIT_FAILURE);
+
+			g->pktr_len = 0;
+			for (;;) {
+				struct netmap_slot *slot = &ring->slot[head];
+				char *buf = NETMAP_BUF(ring, slot->buf_idx);
+
+				if (g->pktr_len + slot->len > sizeof(g->pktr)) {
+					/* Sanity check. */
+					printf("Error: received packet too "
+					       "large "
+					       "(>= %u bytes) ",
+					       g->pktr_len + slot->len);
+					exit(EXIT_FAILURE);
+				}
+				memcpy(g->pktr + g->pktr_len, buf, slot->len);
+				g->pktr_len += slot->len;
+				head = nm_ring_next(ring, head);
+				frags++;
+				if (!(slot->flags & NS_MOREFRAG)) {
+					break;
+				}
 			}
-			memcpy(g->pktr, buf, slot->len);
-			g->pktr_len = slot->len;
-			ring->head = ring->cur = ring->head + 1;
+			ring->head = ring->cur = head;
 			ioctl(nmd->fd, NIOCRXSYNC, NULL);
-			printf("packet (%u bytes) received from RX ring #%d\n",
-			       g->pktr_len, i);
+			printf("packet (%u bytes, %u frags) received from RX "
+			       "ring #%d\n",
+			       g->pktr_len, frags, i);
 			return 0;
 		}
 

From 5defaa40ca43adec3b4e3ecec7ca362520670b9d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 17:26:11 +0100
Subject: [PATCH 0568/2207] utils: functional: tx_one(): add support for
 NS_MOREFRAG

---
 utils/functional.c | 74 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 17 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 50716d41e..ada395902 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -24,6 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+#include 
 #include 
 #include 
 #include 
@@ -51,6 +52,7 @@ struct Global {
 	unsigned pktm_len;       /* packet model length */
 	char pktr[MAX_PKT_SIZE]; /* packet received */
 	unsigned pktr_len;       /* length of received packet */
+	unsigned max_frag_size;  /* max bytes per netmap TX slot */
 
 	char src_mac[ETH_ADDR_LEN];
 	char dst_mac[ETH_ADDR_LEN];
@@ -222,6 +224,18 @@ build_packet(struct Global *g)
 								   udpofs))))));
 }
 
+static unsigned
+tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
+{
+	unsigned avail_per_slot = ring->nr_buf_size;
+
+	if (max_frag_size < avail_per_slot) {
+		avail_per_slot = max_frag_size;
+	}
+
+	return nm_ring_space(ring) * avail_per_slot;
+}
+
 /* Transmit a single packet using any TX ring. */
 static int
 tx_one(struct Global *g)
@@ -232,26 +246,46 @@ tx_one(struct Global *g)
 	for (;;) {
 		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
-			struct netmap_slot *slot = &ring->slot[ring->head];
-			char *buf = NETMAP_BUF(ring, slot->buf_idx);
+			unsigned head		 = ring->head;
+			unsigned frags		 = 0;
+			unsigned ofs		 = 0;
 
-			if (nm_ring_empty(ring)) {
+			if (tx_bytes_avail(ring, g->max_frag_size) <
+			    g->pktm_len) {
 				continue;
 			}
-			if (g->pktm_len > ring->nr_buf_size) {
-				/* Sanity check. */
-				printf("Error: len (%u) > netmap_buf_size "
-				       "(%u)\n",
-				       g->pktm_len, ring->nr_buf_size);
-				exit(EXIT_FAILURE);
+
+			for (;;) {
+				struct netmap_slot *slot = &ring->slot[head];
+				char *buf = NETMAP_BUF(ring, slot->buf_idx);
+				unsigned copysize = g->pktm_len - ofs;
+
+				if (copysize > ring->nr_buf_size) {
+					copysize = ring->nr_buf_size;
+				}
+				if (copysize > g->max_frag_size) {
+					copysize = g->max_frag_size;
+				}
+
+				memcpy(buf, g->pktm + ofs, copysize);
+				ofs += copysize;
+				slot->len   = copysize;
+				slot->flags = NS_MOREFRAG;
+				head	= nm_ring_next(ring, head);
+				frags++;
+				if (ofs >= g->pktm_len) {
+					/* Last fragment. */
+					assert(ofs == g->pktm_len);
+					slot->flags = NS_REPORT;
+					break;
+				}
 			}
-			memcpy(buf, g->pktm, g->pktm_len);
-			slot->len   = g->pktm_len;
-			slot->flags = NS_REPORT;
-			ring->head = ring->cur = nm_ring_next(ring, ring->head);
+
+			ring->head = ring->cur = head;
 			ioctl(nmd->fd, NIOCTXSYNC, NULL);
-			printf("packet (%u bytes) transmitted to TX ring #%d\n",
-			       slot->len, i);
+			printf("packet (%u bytes, %u frags) transmitted to TX "
+			       "ring #%d\n",
+			       g->pktm_len, frags, i);
 			return 0;
 		}
 
@@ -357,7 +391,8 @@ usage(void)
 {
 	printf("usage: ./functional [-h]\n"
 	       "-i NETMAP_PORT\n"
-	       "[-l PACKET_LEN (=6)]\n"
+	       "[-l PACKET_LEN (=60)]\n"
+	       "[-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	       "[-w WAIT_LINK_SECS (=0)]\n");
 }
 
@@ -372,6 +407,7 @@ main(int argc, char **argv)
 	g->nmd		  = NULL;
 	g->wait_link_secs = 0;
 	g->pktm_len       = 60;
+	g->max_frag_size  = ~0U; /* unlimited */
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		g->src_mac[i] = 0x00;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
@@ -380,7 +416,7 @@ main(int argc, char **argv)
 	g->dst_ip = 0x0A000007; /* 10.0.0.7 */
 	g->filler = 'a';
 
-	while ((opt = getopt(argc, argv, "hi:w:l:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:w:l:F:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -398,6 +434,10 @@ main(int argc, char **argv)
 			g->pktm_len = atoi(optarg);
 			break;
 
+		case 'F':
+			g->max_frag_size = atoi(optarg);
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();

From 4b1947cea7679d862dac720c8eee063dcdc8e302 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 17:33:03 +0100
Subject: [PATCH 0569/2207] utils: functional: add support for transmit timeout

---
 utils/functional.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index ada395902..328095f42 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -45,7 +45,7 @@ struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
 	unsigned wait_link_secs; /* wait for link */
-	unsigned timeout_secs;   /* receive timeout */
+	unsigned timeout_secs;   /* transmit/receive timeout */
 
 #define MAX_PKT_SIZE 65536
 	char pktm[MAX_PKT_SIZE]; /* packet model */
@@ -241,6 +241,8 @@ static int
 tx_one(struct Global *g)
 {
 	struct nm_desc *nmd = g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
 	unsigned int i;
 
 	for (;;) {
@@ -289,8 +291,14 @@ tx_one(struct Global *g)
 			return 0;
 		}
 
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+
 		/* Retry after a short while. */
-		usleep(100000);
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
 		ioctl(nmd->fd, NIOCTXSYNC, NULL);
 	}
 
@@ -346,7 +354,7 @@ rx_one(struct Global *g)
 			return 0;
 		}
 
-		if (elapsed_ms / 1000 > g->timeout_secs) {
+		if (elapsed_ms > g->timeout_secs * 1000) {
 			printf("%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -393,6 +401,7 @@ usage(void)
 	       "-i NETMAP_PORT\n"
 	       "[-l PACKET_LEN (=60)]\n"
 	       "[-F MAX_FRAGMENT_SIZE (=inf)]\n"
+	       "[-T TIMEOUT_SECS (=2)]\n"
 	       "[-w WAIT_LINK_SECS (=0)]\n");
 }
 
@@ -405,6 +414,7 @@ main(int argc, char **argv)
 
 	g->ifname	 = NULL;
 	g->nmd		  = NULL;
+	g->timeout_secs   = 2;
 	g->wait_link_secs = 0;
 	g->pktm_len       = 60;
 	g->max_frag_size  = ~0U; /* unlimited */
@@ -416,7 +426,7 @@ main(int argc, char **argv)
 	g->dst_ip = 0x0A000007; /* 10.0.0.7 */
 	g->filler = 'a';
 
-	while ((opt = getopt(argc, argv, "hi:w:l:F:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:w:l:F:T:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -438,6 +448,10 @@ main(int argc, char **argv)
 			g->max_frag_size = atoi(optarg);
 			break;
 
+		case 'T':
+			g->timeout_secs = atoi(optarg);
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();

From d8354c8a0eb8f935f4449a35accbbaa64ad10cc7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 18:14:58 +0100
Subject: [PATCH 0570/2207] utils: functional: add support for multiple events

---
 utils/functional.c | 127 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 106 insertions(+), 21 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 328095f42..7ac547e10 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -41,6 +41,15 @@
 
 #define ETH_ADDR_LEN 6
 
+struct Event {
+	unsigned evtype;
+#define EVENT_TYPE_RX 0x1
+#define EVENT_TYPE_TX 0x2
+	unsigned pkt_len;
+	char filler;
+	unsigned num;
+};
+
 struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
@@ -61,6 +70,10 @@ struct Global {
 	uint16_t src_port;
 	uint16_t dst_port;
 	char filler;
+
+#define MAX_EVENTS 64
+	unsigned num_events;
+	struct Event events[MAX_EVENTS];
 };
 
 static void
@@ -392,17 +405,67 @@ rx_check(struct Global *g)
 	return 0;
 }
 
+static int
+parse_event(const char *opt, unsigned event_type, struct Event *event)
+{
+	char *strbuf = strdup(opt);
+	char *save   = strbuf;
+	int more;
+	char *c;
+
+	if (!strbuf || strlen(strbuf) == 0) {
+		goto err;
+	}
+
+	event->evtype = event_type;
+	event->filler = 'a';
+	event->num    = 1;
+
+	for (c = strbuf; *c != '\0' && *c != ':'; c++) {
+	}
+	more	   = (*c == ':');
+	*c	     = '\0';
+	event->pkt_len = atoi(strbuf);
+	if (more) {
+		strbuf = c + 1;
+		for (c = strbuf; *c != '\0' && *c != ':'; c++) {
+		}
+		more	  = (*c == ':');
+		*c	    = '\0';
+		event->filler = strbuf[0];
+	}
+	if (more) {
+		strbuf = c + 1;
+		for (c = strbuf; *c != '\0'; c++) {
+		}
+		event->num = atoi(strbuf);
+	}
+#if 0
+	printf("parsed %u:%c:%u\n", event->pkt_len, event->filler, event->num);
+#endif
+	return 0;
+err:
+	free(save);
+	return -1;
+}
+
 static struct Global _g;
 
 static void
 usage(void)
 {
 	printf("usage: ./functional [-h]\n"
-	       "-i NETMAP_PORT\n"
-	       "[-l PACKET_LEN (=60)]\n"
-	       "[-F MAX_FRAGMENT_SIZE (=inf)]\n"
-	       "[-T TIMEOUT_SECS (=2)]\n"
-	       "[-w WAIT_LINK_SECS (=0)]\n");
+	       "    -i NETMAP_PORT\n"
+	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
+	       "    [-T TIMEOUT_SECS (=2)]\n"
+	       "    [-w WAIT_LINK_SECS (=0)]\n"
+	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
+	       "LEN bytes)]\n"
+	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
+	       "with size LEN bytes)]\n"
+	       "\nExample:\n"
+	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
+	       "40:b:2\n");
 }
 
 int
@@ -410,7 +473,7 @@ main(int argc, char **argv)
 {
 	struct Global *g = &_g;
 	int opt;
-	int i;
+	unsigned int i;
 
 	g->ifname	 = NULL;
 	g->nmd		  = NULL;
@@ -422,11 +485,12 @@ main(int argc, char **argv)
 		g->src_mac[i] = 0x00;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		g->dst_mac[i] = 0xFF;
-	g->src_ip = 0x0A000005; /* 10.0.0.5 */
-	g->dst_ip = 0x0A000007; /* 10.0.0.7 */
-	g->filler = 'a';
+	g->src_ip     = 0x0A000005; /* 10.0.0.5 */
+	g->dst_ip     = 0x0A000007; /* 10.0.0.7 */
+	g->filler     = 'a';
+	g->num_events = 0;
 
-	while ((opt = getopt(argc, argv, "hi:w:l:F:T:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -440,10 +504,6 @@ main(int argc, char **argv)
 			g->wait_link_secs = atoi(optarg);
 			break;
 
-		case 'l':
-			g->pktm_len = atoi(optarg);
-			break;
-
 		case 'F':
 			g->max_frag_size = atoi(optarg);
 			break;
@@ -452,6 +512,19 @@ main(int argc, char **argv)
 			g->timeout_secs = atoi(optarg);
 			break;
 
+		case 't':
+		case 'r':
+			if (parse_event(optarg,
+					(opt == 't') ? EVENT_TYPE_TX
+						     : EVENT_TYPE_RX,
+					g->events + g->num_events)) {
+				printf("Invalid event syntax '%s'\n", optarg);
+				usage();
+				return -1;
+			}
+			g->num_events++;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();
@@ -474,14 +547,26 @@ main(int argc, char **argv)
 		sleep(g->wait_link_secs);
 	}
 
-	build_packet(g);
+	for (i = 0; i < g->num_events; i++) {
+		const struct Event *e = g->events + i;
 
-	tx_one(g);
-	if (rx_one(g)) {
-		return -1;
-	}
-	if (rx_check(g)) {
-		return -1;
+		g->filler   = e->filler;
+		g->pktm_len = e->pkt_len;
+		build_packet(g);
+
+		if (e->evtype == EVENT_TYPE_TX) {
+			if (tx_one(g)) {
+				return -1;
+			}
+
+		} else if (e->evtype == EVENT_TYPE_RX) {
+			if (rx_one(g)) {
+				return -1;
+			}
+			if (rx_check(g)) {
+				return -1;
+			}
+		}
 	}
 
 	nm_close(g->nmd);

From 723686d61d70830c906e1953eead118f69666ba7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 18:17:50 +0100
Subject: [PATCH 0571/2207] utils: functional: add sanity checks

---
 utils/functional.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/utils/functional.c b/utils/functional.c
index 7ac547e10..ff4790a06 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -514,6 +514,11 @@ main(int argc, char **argv)
 
 		case 't':
 		case 'r':
+			if (g->num_events >= MAX_EVENTS) {
+				printf("Too many events\n");
+				return -1;
+			}
+
 			if (parse_event(optarg,
 					(opt == 't') ? EVENT_TYPE_TX
 						     : EVENT_TYPE_RX,
@@ -538,6 +543,12 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	if (g->num_events < 1) {
+		printf("No transmit/receive events specified\n");
+		usage();
+		return -1;
+	}
+
 	g->nmd = nm_open(g->ifname, NULL, 0, NULL);
 	if (g->nmd == NULL) {
 		printf("Failed to nm_open(%s)\n", g->ifname);

From 6502aa1ca6a44d476f8529bac94136ddbc122a16 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 18:26:34 +0100
Subject: [PATCH 0572/2207] utils: functional: improve logs

---
 utils/functional.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index ff4790a06..0fa0f50fa 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -396,8 +396,8 @@ rx_check(struct Global *g)
 	for (i = 0; i < g->pktr_len; i++) {
 		if (g->pktr[i] != g->pktm[i]) {
 			printf("Received packet differs from model at "
-			       "offset %u (%x!=%x)\n",
-			       i, g->pktr[i], g->pktm[i]);
+			       "offset %u (0x%02x!=0x%02x)\n",
+			       i, g->pktr[i], (uint8_t)g->pktm[i]);
 			return -1;
 		}
 	}
@@ -457,7 +457,7 @@ usage(void)
 	printf("usage: ./functional [-h]\n"
 	       "    -i NETMAP_PORT\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
-	       "    [-T TIMEOUT_SECS (=2)]\n"
+	       "    [-T TIMEOUT_SECS (=5)]\n"
 	       "    [-w WAIT_LINK_SECS (=0)]\n"
 	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
 	       "LEN bytes)]\n"
@@ -477,7 +477,7 @@ main(int argc, char **argv)
 
 	g->ifname	 = NULL;
 	g->nmd		  = NULL;
-	g->timeout_secs   = 2;
+	g->timeout_secs   = 5;
 	g->wait_link_secs = 0;
 	g->pktm_len       = 60;
 	g->max_frag_size  = ~0U; /* unlimited */

From 28e2549a8d633dfdefa702d006daee8b77df32b1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 18:52:23 +0100
Subject: [PATCH 0573/2207] utils: functional: add support for Event::num

---
 utils/functional.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 0fa0f50fa..e6ec27b2e 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -560,22 +560,25 @@ main(int argc, char **argv)
 
 	for (i = 0; i < g->num_events; i++) {
 		const struct Event *e = g->events + i;
+		unsigned j;
 
 		g->filler   = e->filler;
 		g->pktm_len = e->pkt_len;
 		build_packet(g);
 
-		if (e->evtype == EVENT_TYPE_TX) {
-			if (tx_one(g)) {
-				return -1;
-			}
+		for (j = 0; j < e->num; j++) {
+			if (e->evtype == EVENT_TYPE_TX) {
+				if (tx_one(g)) {
+					return -1;
+				}
 
-		} else if (e->evtype == EVENT_TYPE_RX) {
-			if (rx_one(g)) {
-				return -1;
-			}
-			if (rx_check(g)) {
-				return -1;
+			} else if (e->evtype == EVENT_TYPE_RX) {
+				if (rx_one(g)) {
+					return -1;
+				}
+				if (rx_check(g)) {
+					return -1;
+				}
 			}
 		}
 	}

From 271a9a75d2c8000678d7fb2dc501c9efc3f1943c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 19:12:02 +0100
Subject: [PATCH 0574/2207] utils: functional: add option to ignore packets

---
 utils/functional.c | 51 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 43 insertions(+), 8 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index e6ec27b2e..06168604c 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #define NETMAP_WITH_LIBS
 #include 
@@ -53,8 +54,9 @@ struct Event {
 struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
-	unsigned wait_link_secs; /* wait for link */
-	unsigned timeout_secs;   /* transmit/receive timeout */
+	unsigned wait_link_secs;    /* wait for link */
+	unsigned timeout_secs;      /* transmit/receive timeout */
+	int ignore_if_not_matching; /* ignore certain received packets */
 
 #define MAX_PKT_SIZE 65536
 	char pktm[MAX_PKT_SIZE]; /* packet model */
@@ -319,6 +321,24 @@ tx_one(struct Global *g)
 	return 0;
 }
 
+/* If -I option is specified, we want to ignore frames that don't match
+ * our expected ethernet header.
+ * This function currently assumes that Ethernet header starts from
+ * the beginning of the packet buffers. */
+static int
+ignore_received_frame(struct Global *g)
+{
+	if (!g->ignore_if_not_matching) {
+		return 0; /* don't ignore */
+	}
+
+	if (g->pktr_len < 14 || memcmp(g->pktm, g->pktr, 14) != 0) {
+		return 1; /* ignore */
+	}
+
+	return 0; /* don't ignore */
+}
+
 /* Receive a single packet from any RX ring. */
 static int
 rx_one(struct Global *g)
@@ -329,6 +349,7 @@ rx_one(struct Global *g)
 	unsigned int i;
 
 	for (;;) {
+	again:
 		for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
 			unsigned int head	= ring->head;
@@ -361,7 +382,15 @@ rx_one(struct Global *g)
 			}
 			ring->head = ring->cur = head;
 			ioctl(nmd->fd, NIOCRXSYNC, NULL);
-			printf("packet (%u bytes, %u frags) received from RX "
+			if (ignore_received_frame(g)) {
+				printf("(ignoring packet with %u bytes and "
+				       "%u frags received from RX ring #%d)\n",
+				       g->pktr_len, frags, i);
+				elapsed_ms = 0;
+				goto again;
+			}
+			printf("packet (%u bytes, %u frags) received "
+			       "from RX "
 			       "ring #%d\n",
 			       g->pktr_len, frags, i);
 			return 0;
@@ -463,6 +492,7 @@ usage(void)
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	       "with size LEN bytes)]\n"
+	       "-I (ignore ethernet frames with src and dst MAC not matching)\n"
 	       "\nExample:\n"
 	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
 	       "40:b:2\n");
@@ -485,12 +515,13 @@ main(int argc, char **argv)
 		g->src_mac[i] = 0x00;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		g->dst_mac[i] = 0xFF;
-	g->src_ip     = 0x0A000005; /* 10.0.0.5 */
-	g->dst_ip     = 0x0A000007; /* 10.0.0.7 */
-	g->filler     = 'a';
-	g->num_events = 0;
+	g->src_ip		  = 0x0A000005; /* 10.0.0.5 */
+	g->dst_ip		  = 0x0A000007; /* 10.0.0.7 */
+	g->filler		  = 'a';
+	g->num_events		  = 0;
+	g->ignore_if_not_matching = /*false=*/0;
 
-	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:I")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -530,6 +561,10 @@ main(int argc, char **argv)
 			g->num_events++;
 			break;
 
+		case 'I':
+			g->ignore_if_not_matching = 1;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();

From 0115f0c468ee90815f2ae5a9f39d513d7a2d79e0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Feb 2018 19:15:06 +0100
Subject: [PATCH 0575/2207] utils: functional: add -v option

---
 utils/functional.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 06168604c..14cd5a23f 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -57,6 +57,7 @@ struct Global {
 	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
+	int verbose;
 
 #define MAX_PKT_SIZE 65536
 	char pktm[MAX_PKT_SIZE]; /* packet model */
@@ -154,7 +155,9 @@ build_packet(struct Global *g)
 	unsigned pldofs;
 
 	memset(g->pktm, 0, sizeof(g->pktm));
-	printf("%s: starting at ofs %u\n", __func__, ofs);
+	if (g->verbose) {
+		printf("%s: starting at ofs %u\n", __func__, ofs);
+	}
 
 	ethofs = ofs;
 	(void)ethofs;
@@ -165,7 +168,9 @@ build_packet(struct Global *g)
 	ofs += ETH_ADDR_LEN;
 	fill_packet_16bit(g, ofs, ETHERTYPE_IP);
 	ofs += 2;
-	printf("%s: eth done, ofs %u\n", __func__, ofs);
+	if (g->verbose) {
+		printf("%s: eth done, ofs %u\n", __func__, ofs);
+	}
 
 	ipofs = ofs;
 	/* First byte of IP header. */
@@ -200,7 +205,9 @@ build_packet(struct Global *g)
 	fill_packet_16bit(
 		g, ipofs + 10,
 		wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
-	printf("%s: ip done, ofs %u\n", __func__, ofs);
+	if (g->verbose) {
+		printf("%s: ip done, ofs %u\n", __func__, ofs);
+	}
 
 	udpofs = ofs;
 	/* UDP source port. */
@@ -214,14 +221,18 @@ build_packet(struct Global *g)
 	ofs += 2;
 	/* Skip the UDP checksum for now. */
 	ofs += 2;
-	printf("%s: udp done, ofs %u\n", __func__, ofs);
+	if (g->verbose) {
+		printf("%s: udp done, ofs %u\n", __func__, ofs);
+	}
 
 	/* Fill UDP payload. */
 	pldofs = ofs;
 	for (; ofs < g->pktm_len; ofs++) {
 		fill_packet_8bit(g, ofs, g->filler);
 	}
-	printf("%s: payload done, ofs %u\n", __func__, ofs);
+	if (g->verbose) {
+		printf("%s: payload done, ofs %u\n", __func__, ofs);
+	}
 
 	/* Put the UDP checksum now.
 	 * Magic: taken from sbin/dhclient/packet.c */
@@ -492,7 +503,8 @@ usage(void)
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	       "with size LEN bytes)]\n"
-	       "-I (ignore ethernet frames with src and dst MAC not matching)\n"
+	       "-I (ignore ethernet frames with unmatching header)\n"
+	       "-v (increment verbosity level)\n"
 	       "\nExample:\n"
 	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
 	       "40:b:2\n");
@@ -520,8 +532,9 @@ main(int argc, char **argv)
 	g->filler		  = 'a';
 	g->num_events		  = 0;
 	g->ignore_if_not_matching = /*false=*/0;
+	g->verbose		  = 0;
 
-	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:I")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:Iv")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -565,6 +578,10 @@ main(int argc, char **argv)
 			g->ignore_if_not_matching = 1;
 			break;
 
+		case 'v':
+			g->verbose++;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();

From f36790f754ac866691e6be32660f7240c49c9b90 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 09:52:11 +0100
Subject: [PATCH 0576/2207] utils: functional: fix usage

---
 utils/functional.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 14cd5a23f..ef53711ef 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -503,8 +503,8 @@ usage(void)
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	       "with size LEN bytes)]\n"
-	       "-I (ignore ethernet frames with unmatching header)\n"
-	       "-v (increment verbosity level)\n"
+	       "    [-I (ignore ethernet frames with unmatching Ethernet header)]\n"
+	       "    [-v (increment verbosity level)]\n"
 	       "\nExample:\n"
 	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
 	       "40:b:2\n");

From e4f8d026eaae268797689165d8c796b0385b42ff Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 10:19:54 +0100
Subject: [PATCH 0577/2207] linux: e1000e: use adapter->txd_cmd only on the EOP
 descriptor

This is needed because adapter->txd_cmd contains the EOP indicator.
---
 LINUX/if_e1000e_netmap.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 58f40b87a..4b420aa0f 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -161,8 +161,9 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
-			if (!(slot->flags & NS_MOREFRAG))
-				hw_flags |= E1000_TXD_CMD_EOP;
+			if (!(slot->flags & NS_MOREFRAG)) {
+				hw_flags |= adapter->txd_cmd;
+			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				curr->buffer_addr = htole64(paddr);
 			}
@@ -170,7 +171,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
-			curr->lower.data = htole32(adapter->txd_cmd | len | hw_flags);
+			curr->lower.data = htole32(len | hw_flags | E1000_TXD_CMD_IFCS);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);

From 45398760b1d6227875ba90fac629cd9d35ecb60f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 11:58:54 +0100
Subject: [PATCH 0578/2207] linux: e1000e: remove unused NS_REPORT logic

No functional change, as the corresponding hardware bit was
unconditionally set.
---
 LINUX/if_e1000_netmap.h  |  1 -
 LINUX/if_e1000e_netmap.h | 11 +++++------
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 7eb1a4142..8159a2d76 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -136,7 +136,6 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 				 * at least once every half ring. */
 			}
 			if (slot->flags & NS_BUF_CHANGED) {
-				/* buffer has changed, reload map */
 				curr->buffer_addr = htole64(paddr);
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 4b420aa0f..ec0c68146 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -128,8 +128,6 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
-	/* generate an interrupt approximately every half ring */
-	u_int report_frequency = kring->nkr_num_slots >> 1;
 
 	/* device-specific */
 	struct SOFTC_T *adapter = netdev_priv(ifp);
@@ -155,14 +153,15 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
-			int hw_flags = (slot->flags & NS_REPORT ||
-				nic_i == 0 || nic_i == report_frequency) ?
-				E1000_TXD_CMD_RS : 0;
+			int hw_flags = E1000_TXD_CMD_IFCS;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
 				hw_flags |= adapter->txd_cmd;
+				/* For now E1000_TXD_CMD_RS is always set.
+				 * We may set it only if NS_REPORT is set or
+				 * at least once every half ring. */
 			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				curr->buffer_addr = htole64(paddr);
@@ -171,7 +170,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
-			curr->lower.data = htole32(len | hw_flags | E1000_TXD_CMD_IFCS);
+			curr->lower.data = htole32(len | hw_flags);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);

From 4a13cf850419fb99ed07595de69bb0d4deaf69eb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 12:44:44 +0100
Subject: [PATCH 0579/2207] regif: upgrade sanity check on MTU, netmap buf
 size, and hw receive length

---
 sys/dev/netmap/netmap.c | 63 +++++++++++++++++++++++++++++------------
 1 file changed, 45 insertions(+), 18 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1cddb05af..0dc4ed711 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2084,25 +2084,52 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 * perform sanity checks and create the in-kernel view
 		 * of the netmap rings (the netmap krings).
 		 */
-		if (na->ifp && netmap_mem_bufsize(na->nm_mem) <
-					nm_os_ifnet_mtu(na->ifp)) {
-			/* This netmap adapter is attached to an ifnet.
-			 * If netmap buffer size is smaller than device
-			 * MTU we need to make sure that the adapter
-			 * supports NS_MOREFRAG. */
-			if (na->na_flags & NAF_MOREFRAG) {
-				nm_prinf("netmap buf_size (%u) < device "
-					"MTU (%u): application may need "
-					"to use NS_MOREFRAG",
-					netmap_mem_bufsize(na->nm_mem),
-					nm_os_ifnet_mtu(na->ifp));
+		if (na->ifp) {
+			/* This netmap adapter is attached to an ifnet. */
+			unsigned nbs = netmap_mem_bufsize(na->nm_mem);
+			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
+			/* The maximum amount of bytes that a single
+			 * receive or transmit NIC descriptor can hold. */
+			unsigned hw_max_slot_len = 4096;
+
+			if (mtu <= hw_max_slot_len) {
+				/* The MTU fits a single NIC slot. We only
+				 * Need to check that netmap buffers are
+				 * large enough to hold an MTU. NS_MOREFRAG
+				 * cannot be used in this case. */
+				if (nbs < mtu) {
+					nm_prerr("error: netmap buf size (%u) "
+						"< device MTU (%u)", nbs, mtu);
+					error = EINVAL;
+					goto err_drop_mem;
+				}
 			} else {
-				nm_prerr("Error: netmap buf_size (%u) < "
-					"device MTU (%u)",
-					netmap_mem_bufsize(na->nm_mem),
-					nm_os_ifnet_mtu(na->ifp));
-				error = EINVAL;
-				goto err_drop_mem;
+				/* More NIC slots may be needed to receive
+				 * or transmit a single packet. Check that
+				 * the adapter supports NS_MOREFRAG and that
+				 * netmap buffers are large enough to hold
+				 * the maximum per-slot size. */
+				if (!(na->na_flags & NAF_MOREFRAG)) {
+					nm_prerr("error: large MTU (%d) needed "
+						"but %s does not support "
+						"NS_MOREFRAG", mtu,
+						na->ifp->name);
+					error = EINVAL;
+					goto err_drop_mem;
+				} else if (nbs < hw_max_slot_len) {
+					nm_prerr("error: using NS_MOREFRAG on "
+						"%s requires netmap buf size "
+						">= %u", na->ifp->name,
+						hw_max_slot_len);
+					error = EINVAL;
+					goto err_drop_mem;
+				} else {
+					nm_prinf("info: netmap application on "
+						"%s needs to support "
+						"NS_MOREFRAG "
+						"(MTU=%u,netmap_buf_size=%u",
+						na->ifp->name, mtu, nbs);
+				}
 			}
 		}
 

From 423de4643ae4cbd05d196d8bc24fb45c85a90133 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 15:08:18 +0100
Subject: [PATCH 0580/2207] utils: functional: log ignored packets only if
 verbose

---
 sys/dev/netmap/netmap.c |  2 +-
 utils/functional.c      | 13 +++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0dc4ed711..ecc3aa2ba 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2127,7 +2127,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 					nm_prinf("info: netmap application on "
 						"%s needs to support "
 						"NS_MOREFRAG "
-						"(MTU=%u,netmap_buf_size=%u",
+						"(MTU=%u,netmap_buf_size=%u)",
 						na->ifp->name, mtu, nbs);
 				}
 			}
diff --git a/utils/functional.c b/utils/functional.c
index ef53711ef..31ed5b905 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -394,9 +394,13 @@ rx_one(struct Global *g)
 			ring->head = ring->cur = head;
 			ioctl(nmd->fd, NIOCRXSYNC, NULL);
 			if (ignore_received_frame(g)) {
-				printf("(ignoring packet with %u bytes and "
-				       "%u frags received from RX ring #%d)\n",
-				       g->pktr_len, frags, i);
+				if (g->verbose) {
+					printf("(ignoring packet with %u bytes "
+					       "and "
+					       "%u frags received from RX ring "
+					       "#%d)\n",
+					       g->pktr_len, frags, i);
+				}
 				elapsed_ms = 0;
 				goto again;
 			}
@@ -503,7 +507,8 @@ usage(void)
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	       "with size LEN bytes)]\n"
-	       "    [-I (ignore ethernet frames with unmatching Ethernet header)]\n"
+	       "    [-I (ignore ethernet frames with unmatching Ethernet "
+	       "header)]\n"
 	       "    [-v (increment verbosity level)]\n"
 	       "\nExample:\n"
 	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "

From 923cda266a537c151975ee02fa8e027bdfdfcb39 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 16:09:12 +0100
Subject: [PATCH 0581/2207] utils: functional: add support for pause events

---
 utils/functional.c | 124 +++++++++++++++++++++++++++++++++------------
 1 file changed, 93 insertions(+), 31 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 31ed5b905..2c8975f3a 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -46,15 +46,20 @@ struct Event {
 	unsigned evtype;
 #define EVENT_TYPE_RX 0x1
 #define EVENT_TYPE_TX 0x2
+#define EVENT_TYPE_PAUSE 0x3
+	unsigned num; /* > 1 if repeated event */
+
+	/* Tx and Rx event. */
 	unsigned pkt_len;
 	char filler;
-	unsigned num;
+
+	/* Pause event. */
+	unsigned long long usecs;
 };
 
 struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
-	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
 	int verbose;
@@ -450,15 +455,16 @@ rx_check(struct Global *g)
 }
 
 static int
-parse_event(const char *opt, unsigned event_type, struct Event *event)
+parse_txrx_event(const char *opt, unsigned event_type, struct Event *event)
 {
 	char *strbuf = strdup(opt);
 	char *save   = strbuf;
 	int more;
 	char *c;
+	int ret = -1;
 
 	if (!strbuf || strlen(strbuf) == 0) {
-		goto err;
+		goto out;
 	}
 
 	event->evtype = event_type;
@@ -470,6 +476,9 @@ parse_event(const char *opt, unsigned event_type, struct Event *event)
 	more	   = (*c == ':');
 	*c	     = '\0';
 	event->pkt_len = atoi(strbuf);
+	if (event->pkt_len == 0) {
+		goto out;
+	}
 	if (more) {
 		strbuf = c + 1;
 		for (c = strbuf; *c != '\0' && *c != ':'; c++) {
@@ -483,14 +492,55 @@ parse_event(const char *opt, unsigned event_type, struct Event *event)
 		for (c = strbuf; *c != '\0'; c++) {
 		}
 		event->num = atoi(strbuf);
+		if (event->num == 0) {
+			goto out;
+		}
 	}
+
+	ret = 0;
 #if 0
 	printf("parsed %u:%c:%u\n", event->pkt_len, event->filler, event->num);
 #endif
-	return 0;
-err:
+out:
+	if (save) {
+		free(save);
+	}
+	return ret;
+}
+
+static int
+parse_pause_event(const char *opt, struct Event *event)
+{
+	char *strbuf = strdup(opt);
+	char *save   = strbuf;
+	unsigned mul = 1000000;
+	int ret      = -1;
+
+	while (*strbuf != '\0' && isdigit(*strbuf)) {
+		strbuf++;
+	}
+	if (!strcmp(strbuf, "us")) {
+		mul = 1;
+	} else if (!strcmp(strbuf, "ms")) {
+		mul = 1000;
+	} else if (strcmp(strbuf, "s") && strcmp(strbuf, "")) {
+		goto out;
+	}
+
+	event->evtype = EVENT_TYPE_PAUSE;
+	event->usecs  = atoi(save);
+	if (event->usecs == 0) {
+		goto out;
+	}
+	event->usecs *= mul;
+	event->num = 1;
+	ret	= 0;
+out:
+#if 0
+	printf("parsed %llu usecs\n", event->usecs);
+#endif
 	free(save);
-	return -1;
+	return ret;
 }
 
 static struct Global _g;
@@ -502,11 +552,11 @@ usage(void)
 	       "    -i NETMAP_PORT\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	       "    [-T TIMEOUT_SECS (=5)]\n"
-	       "    [-w WAIT_LINK_SECS (=0)]\n"
 	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
-	       "with size LEN bytes)]\n"
+	       "with size LEN bytes)\n"
+	       "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
 	       "    [-I (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
 	       "    [-v (increment verbosity level)]\n"
@@ -522,12 +572,11 @@ main(int argc, char **argv)
 	int opt;
 	unsigned int i;
 
-	g->ifname	 = NULL;
-	g->nmd		  = NULL;
-	g->timeout_secs   = 5;
-	g->wait_link_secs = 0;
-	g->pktm_len       = 60;
-	g->max_frag_size  = ~0U; /* unlimited */
+	g->ifname	= NULL;
+	g->nmd		 = NULL;
+	g->timeout_secs  = 5;
+	g->pktm_len      = 60;
+	g->max_frag_size = ~0U; /* unlimited */
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		g->src_mac[i] = 0x00;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
@@ -539,7 +588,7 @@ main(int argc, char **argv)
 	g->ignore_if_not_matching = /*false=*/0;
 	g->verbose		  = 0;
 
-	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:Iv")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:F:T:t:r:Ivp:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -549,10 +598,6 @@ main(int argc, char **argv)
 			g->ifname = optarg;
 			break;
 
-		case 'w':
-			g->wait_link_secs = atoi(optarg);
-			break;
-
 		case 'F':
 			g->max_frag_size = atoi(optarg);
 			break;
@@ -563,21 +608,32 @@ main(int argc, char **argv)
 
 		case 't':
 		case 'r':
+		case 'p': {
+			int ret = 0;
+
 			if (g->num_events >= MAX_EVENTS) {
 				printf("Too many events\n");
 				return -1;
 			}
 
-			if (parse_event(optarg,
+			if (opt == 'p') {
+				ret = parse_pause_event(
+					optarg, g->events + g->num_events);
+			} else {
+				ret = parse_txrx_event(
+					optarg,
 					(opt == 't') ? EVENT_TYPE_TX
 						     : EVENT_TYPE_RX,
-					g->events + g->num_events)) {
+					g->events + g->num_events);
+			}
+			if (ret) {
 				printf("Invalid event syntax '%s'\n", optarg);
 				usage();
 				return -1;
 			}
 			g->num_events++;
 			break;
+		}
 
 		case 'I':
 			g->ignore_if_not_matching = 1;
@@ -601,7 +657,7 @@ main(int argc, char **argv)
 	}
 
 	if (g->num_events < 1) {
-		printf("No transmit/receive events specified\n");
+		printf("No transmit/receive/pause events specified\n");
 		usage();
 		return -1;
 	}
@@ -611,31 +667,37 @@ main(int argc, char **argv)
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		return -1;
 	}
-	if (g->wait_link_secs > 0) {
-		sleep(g->wait_link_secs);
-	}
 
 	for (i = 0; i < g->num_events; i++) {
 		const struct Event *e = g->events + i;
 		unsigned j;
 
-		g->filler   = e->filler;
-		g->pktm_len = e->pkt_len;
-		build_packet(g);
+		if (e->evtype == EVENT_TYPE_TX || e->evtype == EVENT_TYPE_RX) {
+			g->filler   = e->filler;
+			g->pktm_len = e->pkt_len;
+			build_packet(g);
+		}
 
 		for (j = 0; j < e->num; j++) {
-			if (e->evtype == EVENT_TYPE_TX) {
+			switch (e->evtype) {
+			case EVENT_TYPE_TX:
 				if (tx_one(g)) {
 					return -1;
 				}
+				break;
 
-			} else if (e->evtype == EVENT_TYPE_RX) {
+			case EVENT_TYPE_RX:
 				if (rx_one(g)) {
 					return -1;
 				}
 				if (rx_check(g)) {
 					return -1;
 				}
+				break;
+
+			case EVENT_TYPE_PAUSE:
+				usleep(e->usecs);
+				break;
 			}
 		}
 	}

From 8f8de57fd12b8f05971b9a116fc9aa6373334db7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 16:19:11 +0100
Subject: [PATCH 0582/2207] utils: functional: add -C option to run the events
 many times

---
 utils/functional.c | 70 +++++++++++++++++++++++++++-------------------
 1 file changed, 42 insertions(+), 28 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 2c8975f3a..f9cad203d 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -82,6 +82,7 @@ struct Global {
 #define MAX_EVENTS 64
 	unsigned num_events;
 	struct Event events[MAX_EVENTS];
+	unsigned num_loops;
 };
 
 static void
@@ -560,6 +561,7 @@ usage(void)
 	       "    [-I (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
 	       "    [-v (increment verbosity level)]\n"
+	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	       "\nExample:\n"
 	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
 	       "40:b:2\n");
@@ -569,8 +571,8 @@ int
 main(int argc, char **argv)
 {
 	struct Global *g = &_g;
+	unsigned int i, c;
 	int opt;
-	unsigned int i;
 
 	g->ifname	= NULL;
 	g->nmd		 = NULL;
@@ -587,8 +589,9 @@ main(int argc, char **argv)
 	g->num_events		  = 0;
 	g->ignore_if_not_matching = /*false=*/0;
 	g->verbose		  = 0;
+	g->num_loops		  = 1;
 
-	while ((opt = getopt(argc, argv, "hi:F:T:t:r:Ivp:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -643,6 +646,14 @@ main(int argc, char **argv)
 			g->verbose++;
 			break;
 
+		case 'C':
+			g->num_loops = atoi(optarg);
+			if (g->num_loops == 0) {
+				printf("Invalid -C option '%s'\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();
@@ -668,36 +679,39 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	for (i = 0; i < g->num_events; i++) {
-		const struct Event *e = g->events + i;
-		unsigned j;
+	for (c = 0; c < g->num_loops; c++) {
+		for (i = 0; i < g->num_events; i++) {
+			const struct Event *e = g->events + i;
+			unsigned j;
 
-		if (e->evtype == EVENT_TYPE_TX || e->evtype == EVENT_TYPE_RX) {
-			g->filler   = e->filler;
-			g->pktm_len = e->pkt_len;
-			build_packet(g);
-		}
+			if (e->evtype == EVENT_TYPE_TX ||
+			    e->evtype == EVENT_TYPE_RX) {
+				g->filler   = e->filler;
+				g->pktm_len = e->pkt_len;
+				build_packet(g);
+			}
 
-		for (j = 0; j < e->num; j++) {
-			switch (e->evtype) {
-			case EVENT_TYPE_TX:
-				if (tx_one(g)) {
-					return -1;
-				}
-				break;
+			for (j = 0; j < e->num; j++) {
+				switch (e->evtype) {
+				case EVENT_TYPE_TX:
+					if (tx_one(g)) {
+						return -1;
+					}
+					break;
 
-			case EVENT_TYPE_RX:
-				if (rx_one(g)) {
-					return -1;
-				}
-				if (rx_check(g)) {
-					return -1;
-				}
-				break;
+				case EVENT_TYPE_RX:
+					if (rx_one(g)) {
+						return -1;
+					}
+					if (rx_check(g)) {
+						return -1;
+					}
+					break;
 
-			case EVENT_TYPE_PAUSE:
-				usleep(e->usecs);
-				break;
+				case EVENT_TYPE_PAUSE:
+					usleep(e->usecs);
+					break;
+				}
 			}
 		}
 	}

From 80ee6c1a87d45390d27aad40ed3938d87386cbdb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 16:25:18 +0100
Subject: [PATCH 0583/2207] utils: functional: restore -w option

---
 utils/functional.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index f9cad203d..589965c6d 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -60,6 +60,7 @@ struct Event {
 struct Global {
 	struct nm_desc *nmd;
 	const char *ifname;
+	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
 	int verbose;
@@ -553,6 +554,7 @@ usage(void)
 	       "    -i NETMAP_PORT\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	       "    [-T TIMEOUT_SECS (=5)]\n"
+	       "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
 	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
@@ -574,11 +576,12 @@ main(int argc, char **argv)
 	unsigned int i, c;
 	int opt;
 
-	g->ifname	= NULL;
-	g->nmd		 = NULL;
-	g->timeout_secs  = 5;
-	g->pktm_len      = 60;
-	g->max_frag_size = ~0U; /* unlimited */
+	g->ifname	 = NULL;
+	g->nmd		  = NULL;
+	g->wait_link_secs = 0;
+	g->timeout_secs   = 5;
+	g->pktm_len       = 60;
+	g->max_frag_size  = ~0U; /* unlimited */
 	for (i = 0; i < ETH_ADDR_LEN; i++)
 		g->src_mac[i] = 0x00;
 	for (i = 0; i < ETH_ADDR_LEN; i++)
@@ -591,7 +594,7 @@ main(int argc, char **argv)
 	g->verbose		  = 0;
 	g->num_loops		  = 1;
 
-	while ((opt = getopt(argc, argv, "hi:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -605,6 +608,10 @@ main(int argc, char **argv)
 			g->max_frag_size = atoi(optarg);
 			break;
 
+		case 'w':
+			g->wait_link_secs = atoi(optarg);
+			break;
+
 		case 'T':
 			g->timeout_secs = atoi(optarg);
 			break;
@@ -679,6 +686,10 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	if (g->wait_link_secs > 0) {
+		sleep(g->wait_link_secs);
+	}
+
 	for (c = 0; c < g->num_loops; c++) {
 		for (i = 0; i < g->num_events; i++) {
 			const struct Event *e = g->events + i;

From 454ecf90fbe542d51ad0396310b036236a4d4475 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 16:58:36 +0100
Subject: [PATCH 0584/2207] linux: e1000e: add missing dma_rmb() in rxsync

---
 LINUX/if_e1000e_netmap.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index ec0c68146..5ae381bb8 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -252,6 +252,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
+			dma_rmb();  /* read descriptor after status DD */
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
 			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);

From 3a25265b4fcd0b78e6ff8a50a229ef3c8e583f21 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 17:57:45 +0100
Subject: [PATCH 0585/2207] utils: functional: check for truncated packets

---
 utils/functional.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/utils/functional.c b/utils/functional.c
index 589965c6d..e87b9d0d5 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -372,6 +372,7 @@ rx_one(struct Global *g)
 			struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
 			unsigned int head	= ring->head;
 			unsigned int frags       = 0;
+			int truncated		 = 0;
 
 			if (nm_ring_empty(ring)) {
 				continue;
@@ -397,6 +398,16 @@ rx_one(struct Global *g)
 				if (!(slot->flags & NS_MOREFRAG)) {
 					break;
 				}
+				if (head == ring->tail) {
+					printf("warning: truncated packet "
+					       "(len=%u)\n",
+					       g->pktr_len);
+					truncated = 1;
+					break;
+				}
+			}
+			if (truncated) {
+				continue; /* skip this ring */
 			}
 			ring->head = ring->cur = head;
 			ioctl(nmd->fd, NIOCRXSYNC, NULL);

From eb60c6738f1a96e9621fc763fa9e76125ec0a133 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Feb 2018 19:58:58 +0100
Subject: [PATCH 0586/2207] linux: igb: expose NAF_MOREFRAG

---
 LINUX/if_igb_netmap.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index ef80e8bee..000ff9a96 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -385,6 +385,7 @@ igb_netmap_attach(struct SOFTC_T *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
+	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = adapter->tx_ring_count;
 	na.num_rx_desc = adapter->rx_ring_count;
 	na.nm_register = igb_netmap_reg;

From 29687330f5b8e86126e00c8023068e25487662f9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Mar 2018 13:29:38 +0100
Subject: [PATCH 0587/2207] vale: do not scan fake rings while registering

---
 sys/dev/netmap/netmap_vale.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 882c18c6f..0aaa6e42a 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1599,7 +1599,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 		BDG_WLOCK(vpna->na_bdg);
 	if (onoff) {
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < netmap_real_rings(na, t); i++) {
 				struct netmap_kring *kring = &NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring))
@@ -1615,7 +1615,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 		if (na->active_fds == 0)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < netmap_real_rings(na, t); i++) {
 				struct netmap_kring *kring = &NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring))

From 924411cd02d680cec3b67fdf2dc47eb567255b10 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Mar 2018 16:29:53 +0100
Subject: [PATCH 0588/2207] bwrap: clean-up the hwna plut on unregister

---
 sys/dev/netmap/netmap_vale.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 0aaa6e42a..ad234a076 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2541,6 +2541,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 			hwna->rx_rings[i].save_notify = NULL;
 		}
 		hwna->na_lut.lut = NULL;
+		hwna->na_lut.plut = NULL;
 		hwna->na_lut.objtotal = 0;
 		hwna->na_lut.objsize = 0;
 

From f61ed508b1f8bf454af8c852aa26e6cddd95acfa Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 16:20:20 +0100
Subject: [PATCH 0589/2207] netmap.h: introduce new control API: struct
 nmreq_register

---
 sys/dev/netmap/netmap.c |   2 +-
 sys/net/netmap.h        | 116 ++++++++++++++++++++++++++++------------
 2 files changed, 83 insertions(+), 35 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ecc3aa2ba..5d55b8226 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -260,7 +260,7 @@ ports attached to the switch)
  *
  *  Any network interface known to the system (including a persistent VALE
  *  port) can be attached to a VALE switch by issuing the
- *  NETMAP_BDG_ATTACH subcommand. After the attachment, persistent VALE ports
+ *  NETMAP_REQ_VALE_ATTACH command. After the attachment, persistent VALE ports
  *  look exactly like ephemeral VALE ports (as created in step 2 above).  The
  *  attachment of other interfaces, instead, requires the creation of a
  *  netmap_bwrap_adapter.  Moreover, the attached interface must be put in
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a85bb3004..71c7ed6c3 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -367,7 +367,6 @@ struct netmap_if {
 };
 
 
-#ifndef NIOCREGIF
 /*
  * ioctl names and related fields
  *
@@ -532,40 +531,12 @@ struct nmreq {
 
 	uint16_t	nr_arg2;
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
-	uint32_t	nr_flags;
+	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
+#define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */
 	/* various modes, extends nr_ringid */
 	uint32_t	spare2[1];
 };
 
-#define NR_REG_MASK		0xf /* values for nr_flags */
-enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
-	NR_REG_ALL_NIC	= 1,
-	NR_REG_SW	= 2,
-	NR_REG_NIC_SW	= 3,
-	NR_REG_ONE_NIC	= 4,
-	NR_REG_PIPE_MASTER = 5,
-	NR_REG_PIPE_SLAVE = 6,
-};
-/* monitor uses the NR_REG to select the rings to monitor */
-#define NR_MONITOR_TX	0x100
-#define NR_MONITOR_RX	0x200
-#define NR_ZCOPY_MON	0x400
-/* request exclusive access to the selected rings */
-#define NR_EXCLUSIVE	0x800
-/* request ptnetmap host support */
-#define NR_PASSTHROUGH_HOST	NR_PTNETMAP_HOST /* deprecated */
-#define NR_PTNETMAP_HOST	0x1000
-#define NR_RX_RINGS_ONLY	0x2000
-#define NR_TX_RINGS_ONLY	0x4000
-/* Applications set this flag if they are able to deal with virtio-net headers,
- * that is send/receive frames that start with a virtio-net header.
- * If not set, NIOCREGIF will fail with netmap ports that require applications
- * to use those headers. If the flag is set, the application can use the
- * NETMAP_VNET_HDR_GET command to figure out the header length. */
-#define NR_ACCEPT_VNET_HDR	0x8000
-
-#define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
-
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
@@ -591,11 +562,11 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 #define NETMAP_GETSOCKOPT _IO('i', 141)
 
 
-//These linknames are for the Netmap Core Driver
+/* These linknames are for the Netmap Core Driver */
 #define NETMAP_NT_DEVICE_NAME			L"\\Device\\NETMAP"
 #define NETMAP_DOS_DEVICE_NAME			L"\\DosDevices\\netmap"
 
-//Definition of a structure used to pass a virtual address within an IOCTL
+/* Definition of a structure used to pass a virtual address within an IOCTL */
 typedef struct _MEMORY_ENTRY {
 	PVOID       pUsermodeVirtualAddress;
 } MEMORY_ENTRY, *PMEMORY_ENTRY;
@@ -619,9 +590,86 @@ typedef struct _POLL_REQUEST_DATA {
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
 #define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
 #define NIOCCONFIG	_IOWR('i',150, struct nm_ifreq) /* for ext. modules */
-#endif /* !NIOCREGIF */
 
 
+/*
+ * New API to control netmap control devices, deprecating 'struct nmreq',
+ * NIOCREGIF, NIOCGINFO and NIOCCONFIG. New applications should only use
+ * nmreq_xyz structs.
+ */
+
+/* Header common to all requests. */
+struct nmreq_header {
+	uint16_t	nr_version;	/* API version */
+	uint16_t	nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+};
+
+enum {
+	/* Register a netmap port with the device. */
+	NETMAP_REQ_REGISTER = 1,
+	NETMAP_REQ_VALE_ATTACH,
+};
+
+/* Bind (register) a netmap port to this control device. */
+struct nmreq_register {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
+	uint64_t	nr_offset;	/* nifp offset in the shared region */
+	uint64_t	nr_memsize;	/* size of the shared region */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	uint16_t	nr_ringid;	/* ring(s) we care about */
+	uint32_t	nr_mode;	/* specify NR_REG_* modes */
+
+	uint64_t	nr_flags;	/* additional flags (see below) */
+/* monitors use nr_ringid and nr_mode to select the rings to monitor */
+#define NR_MONITOR_TX	0x100
+#define NR_MONITOR_RX	0x200
+#define NR_ZCOPY_MON	0x400
+/* request exclusive access to the selected rings */
+#define NR_EXCLUSIVE	0x800
+/* request ptnetmap host support */
+#define NR_PASSTHROUGH_HOST	NR_PTNETMAP_HOST /* deprecated */
+#define NR_PTNETMAP_HOST	0x1000
+#define NR_RX_RINGS_ONLY	0x2000
+#define NR_TX_RINGS_ONLY	0x4000
+/* Applications set this flag if they are able to deal with virtio-net headers,
+ * that is send/receive frames that start with a virtio-net header.
+ * If not set, NIOCREGIF will fail with netmap ports that require applications
+ * to use those headers. If the flag is set, the application can use the
+ * NETMAP_VNET_HDR_GET command to figure out the header length. */
+#define NR_ACCEPT_VNET_HDR	0x8000
+/* The following two have the same meaning of NETMAP_NO_TX_POLL and
+ * NETMAP_DO_RX_POLL. */
+#define NR_DO_RX_POLL		0x10000
+#define NR_NO_TX_POLL		0x20000
+
+	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
+	uint8_t         nr_spare[64];
+};
+
+/* Valid values for nmreq_register.nr_mode (see above). */
+enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
+	NR_REG_ALL_NIC	= 1,
+	NR_REG_SW	= 2,
+	NR_REG_NIC_SW	= 3,
+	NR_REG_ONE_NIC	= 4,
+	NR_REG_PIPE_MASTER = 5,
+	NR_REG_PIPE_SLAVE = 6,
+};
+
+#define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
+
+struct nmreq_vale_attach {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+};
+
 /*
  * Helper functions for kernel and userspace
  */

From 9ef45706ba38b0d63a7bba3d1503ffb6212100c2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 16:28:25 +0100
Subject: [PATCH 0590/2207] na_bdg_ctl: remove unused (and obsoleted) struct
 nmreq argument

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 sys/dev/netmap/netmap_vale.c | 9 ++++-----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 5663e4f4a..257d9654a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -780,7 +780,7 @@ struct netmap_adapter {
 	 *      Called with NMG_LOCK held.
 	 */
 	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *);
-	int (*nm_bdg_ctl)(struct netmap_adapter *, struct nmreq *, int);
+	int (*nm_bdg_ctl)(struct netmap_adapter *, int);
 
 	/* adapter used to attach this adapter to a VALE switch (if any) */
 	struct netmap_vp_adapter *na_vp;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index ad234a076..aaee3667b 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -515,12 +515,11 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 
 /* nm_bdg_ctl callback for VALE ports */
 static int
-netmap_vp_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach)
+netmap_vp_bdg_ctl(struct netmap_adapter *na, int attach)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 	struct nm_bridge *b = vpna->na_bdg;
 
-	(void)nmr;	// XXX merge ?
 	if (attach)
 		return 0; /* nothing to do */
 	if (b) {
@@ -891,7 +890,7 @@ nm_bdg_ctl_attach(struct nmreq *nmr)
 		/* nop for VALE ports. The bwrap needs to put the hwna
 		 * in netmap mode (see netmap_bwrap_bdg_ctl)
 		 */
-		error = na->nm_bdg_ctl(na, nmr, 1);
+		error = na->nm_bdg_ctl(na, 1);
 		if (error)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
@@ -939,7 +938,7 @@ nm_bdg_ctl_detach(struct nmreq *nmr)
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
 		 */
-		error = na->nm_bdg_ctl(na, nmr, 0);
+		error = na->nm_bdg_ctl(na, 0);
 	}
 
 	netmap_adapter_put(na);
@@ -2741,7 +2740,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
  * directed to hwna.
  */
 static int
-netmap_bwrap_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach)
+netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 {
 	struct netmap_priv_d *npriv;
 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;

From feda2daecac9c61a0d3564db29993289729c1281 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 17:06:29 +0100
Subject: [PATCH 0591/2207] netmap.h: introduce nmreq_* commands for bridge
 operations

---
 sys/net/netmap.h | 76 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 55 insertions(+), 21 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 71c7ed6c3..2dceb570a 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -324,6 +324,18 @@ struct netmap_ring {
 	 * Enables the NS_FORWARD slot flag for the ring.
 	 */
 
+/*
+ * Helper functions for kernel and userspace
+ */
+
+/*
+ * check if space is available in the ring.
+ */
+static inline int
+nm_ring_empty(struct netmap_ring *ring)
+{
+	return (ring->cur == ring->tail);
+}
 
 /*
  * Netmap representation of an interface and its queue(s).
@@ -527,7 +539,6 @@ struct nmreq {
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
 #define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
-#define NETMAP_BDG_HOST		1	/* attach the host stack on ATTACH */
 
 	uint16_t	nr_arg2;
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
@@ -537,6 +548,17 @@ struct nmreq {
 	uint32_t	spare2[1];
 };
 
+/*
+ * Opaque structure that is passed to an external kernel
+ * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
+ * bridge port (at this point ephemeral VALE interface).
+ */
+#define NM_IFRDATA_LEN 256
+struct nm_ifreq {
+	char nifr_name[IFNAMSIZ];
+	char data[NM_IFRDATA_LEN];
+};
+
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
@@ -607,10 +629,18 @@ struct nmreq_header {
 enum {
 	/* Register a netmap port with the device. */
 	NETMAP_REQ_REGISTER = 1,
+	/* Attach a netmap port to a VALE switch. */
 	NETMAP_REQ_VALE_ATTACH,
+	/* Detach a netmap port from a VALE switch. */
+	NETMAP_REQ_VALE_DETACH,
+	/* List the ports attached to a VALE switch. */
+	NETMAP_REQ_VALE_LIST,
 };
 
-/* Bind (register) a netmap port to this control device. */
+/*
+ * nr_reqtype: NETMAP_REQ_REGISTER
+ * Bind (register) a netmap port to this control device.
+ */
 struct nmreq_register {
 	struct nmreq_header nr_hdr;
 	char		nr_name[64];	/* name of the netmap port */
@@ -664,34 +694,38 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_ATTACH
+ * Attach a netmap port to a VALE switch. Both the name of the netmap
+ * port and the VALE switch are specified through the nr_name argument.
+ */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
-	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	char		nr_name[128];	/* name in the form valeXXX:YYY */
+	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
+	uint16_t	nr_flags;	/* flags (see below) */
+#define NETMAP_BDG_HOST		0x1	/* attach the host stack */
 };
 
 /*
- * Helper functions for kernel and userspace
- */
-
-/*
- * check if space is available in the ring.
+ * nr_reqtype: NETMAP_REQ_VALE_DETACH
+ * Detach a netmap port from a VALE switch. Both the name of the netmap
+ * port and the VALE switch are specified through the nr_name argument.
  */
-static inline int
-nm_ring_empty(struct netmap_ring *ring)
-{
-	return (ring->cur == ring->tail);
-}
+struct nmreq_vale_detach {
+	struct nmreq_header nr_hdr;
+	char		nr_name[128];	/* name in the form valeXXX:YYY */
+};
 
 /*
- * Opaque structure that is passed to an external kernel
- * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
- * bridge port (at this point ephemeral VALE interface).
+ * nr_reqtype: NETMAP_REQ_VALE_LIST
+ * List the ports of a VALE switch.
  */
-#define NM_IFRDATA_LEN 256
-struct nm_ifreq {
-	char nifr_name[IFNAMSIZ];
-	char data[NM_IFRDATA_LEN];
+struct nmreq_vale_list {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the VALE switch or empty */
+	uint16_t	nr_bridge_idx;
+	uint16_t	nr_port_idx;
 };
 
 #endif /* _NET_NETMAP_H_ */

From 252f8c9b7c13ea51ea106159db06139ea4cd3712 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 17:31:56 +0100
Subject: [PATCH 0592/2207] netmap.h: introduce nmreq_* structs to handle
 persistent VALE ports

---
 sys/net/netmap.h | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 2dceb570a..44ccbe5b6 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -635,6 +635,12 @@ enum {
 	NETMAP_REQ_VALE_DETACH,
 	/* List the ports attached to a VALE switch. */
 	NETMAP_REQ_VALE_LIST,
+	/* Set the port header length (was virtio-net header length). */
+	NETMAP_REQ_SET_PORT_HDR,
+	/* Create a new persistent VALE port. */
+	NETMAP_REQ_VALE_NEWIF,
+	/* Delete a persistent VALE port. */
+	NETMAP_REQ_VALE_DELIF,
 };
 
 /*
@@ -701,7 +707,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[128];	/* name in the form valeXXX:YYY */
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* attach the host stack */
@@ -714,7 +720,7 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[128];	/* name in the form valeXXX:YYY */
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
 };
 
 /*
@@ -728,4 +734,36 @@ struct nmreq_vale_list {
 	uint16_t	nr_port_idx;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_SET_PORT_HDR
+ * Set the port header length.
+ */
+struct nmreq_set_port_hdr {
+	struct nmreq_header nr_hdr;
+	uint32_t	nr_hdr_len;
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_NEWIF
+ * Create a new persistent VALE port.
+ */
+struct nmreq_vale_newif {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_DELIF
+ * Delete a persistent VALE port.
+ */
+struct nmreq_vale_delif {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name in the form valeXXX:YYY */
+};
+
 #endif /* _NET_NETMAP_H_ */

From fe6ab0d22e988b12ce4e84e74eea08367ba98a69 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 17:36:36 +0100
Subject: [PATCH 0593/2207] netmap.h: introduce nmreq_* structs for vnet header
 set/get

---
 sys/net/netmap.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 44ccbe5b6..4b7acf1d2 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -636,7 +636,9 @@ enum {
 	/* List the ports attached to a VALE switch. */
 	NETMAP_REQ_VALE_LIST,
 	/* Set the port header length (was virtio-net header length). */
-	NETMAP_REQ_SET_PORT_HDR,
+	NETMAP_REQ_PORT_HDR_SET,
+	/* Get the port header length (was virtio-net header length). */
+	NETMAP_REQ_PORT_HDR_GET,
 	/* Create a new persistent VALE port. */
 	NETMAP_REQ_VALE_NEWIF,
 	/* Delete a persistent VALE port. */
@@ -735,11 +737,22 @@ struct nmreq_vale_list {
 };
 
 /*
- * nr_reqtype: NETMAP_REQ_SET_PORT_HDR
+ * nr_reqtype: NETMAP_REQ_PORT_HDR_SET
  * Set the port header length.
  */
 struct nmreq_set_port_hdr {
 	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
+	uint32_t	nr_hdr_len;
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_PORT_HDR_GET
+ * Get the port header length.
+ */
+struct nmreq_get_port_hdr {
+	struct nmreq_header nr_hdr;
+	char		nr_name[64];	/* name of the netmap port */
 	uint32_t	nr_hdr_len;
 };
 

From b32335730f8abc3fa1e3c481eebf9b4aa80d822e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 18:28:54 +0100
Subject: [PATCH 0594/2207] netmap.h, netmap_virt.h: introduce nmreq_* structs
 for netmap passthrough

---
 sys/net/netmap.h      | 74 +++++++++++++++++++++++++++++++------------
 sys/net/netmap_virt.h | 24 +++++++++++++-
 2 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 4b7acf1d2..06d9dcc18 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -529,7 +529,6 @@ struct nmreq {
 #define NETMAP_BDG_REGOPS	3	/* register bridge callbacks */
 #define NETMAP_BDG_LIST		4	/* get bridge's info */
 #define NETMAP_BDG_VNET_HDR     5       /* set the port virtio-net-hdr length */
-#define NETMAP_BDG_OFFSET	NETMAP_BDG_VNET_HDR	/* deprecated alias */
 #define NETMAP_BDG_NEWIF	6	/* create a virtual port */
 #define NETMAP_BDG_DELIF	7	/* destroy a virtual port */
 #define NETMAP_PT_HOST_CREATE	8	/* create ptnetmap kthreads */
@@ -643,15 +642,29 @@ enum {
 	NETMAP_REQ_VALE_NEWIF,
 	/* Delete a persistent VALE port. */
 	NETMAP_REQ_VALE_DELIF,
+	/* Enable polling kthread on a VALE port. */
+	NETMAP_REQ_VALE_POLLING_ENABLE,
+	/* Disable polling kthread on a VALE port. */
+	NETMAP_REQ_VALE_POLLING_DISABLE,
+	/* Get info about the pools of a memory allocator. */
+	NETMAP_REQ_POOLS_INFO_GET,
+	/* Enable host-side ptnetmap processing (e.g. start ptnetmap
+	 * kthreads). */
+	NETMAP_REQ_PASSTHROUGH_ENABLE,
+	/* Disable host-side ptnetmap processing (e.g. stop ptnetmap
+	 * kthreads). */
+	NETMAP_REQ_PASSTHROUGH_DISABLE,
 };
 
+#define NETMAP_REQ_IFNAMSIZ	64
+
 /*
  * nr_reqtype: NETMAP_REQ_REGISTER
  * Bind (register) a netmap port to this control device.
  */
 struct nmreq_register {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -709,7 +722,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* attach the host stack */
@@ -722,7 +735,7 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 /*
@@ -731,28 +744,19 @@ struct nmreq_vale_detach {
  */
 struct nmreq_vale_list {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the VALE switch or empty */
+	/* Name of the VALE port (valeXXX:YYY) or empty. */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint16_t	nr_bridge_idx;
 	uint16_t	nr_port_idx;
 };
 
 /*
- * nr_reqtype: NETMAP_REQ_PORT_HDR_SET
+ * nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
  * Set the port header length.
  */
-struct nmreq_set_port_hdr {
+struct nmreq_port_hdr {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
-	uint32_t	nr_hdr_len;
-};
-
-/*
- * nr_reqtype: NETMAP_REQ_PORT_HDR_GET
- * Get the port header length.
- */
-struct nmreq_get_port_hdr {
-	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name of the netmap port */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint32_t	nr_hdr_len;
 };
 
@@ -762,7 +766,7 @@ struct nmreq_get_port_hdr {
  */
 struct nmreq_vale_newif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -776,7 +780,37 @@ struct nmreq_vale_newif {
  */
 struct nmreq_vale_delif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[64];	/* name in the form valeXXX:YYY */
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
+ * Enable or disable polling kthreads on a VALE port.
+ */
+struct nmreq_vale_polling {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
+ * Get info about the pools of a memory allocator (used i.e. by
+ * a ptnetmap-enabled hypervisor).
+ */
+struct nmreq_pools_info_get {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];
+	uint64_t	nr_memsize;
+	uint64_t	nr_mem_id;
+	uint64_t	nr_if_pool_offset;
+	uint32_t	nr_if_pool_objtotal;
+	uint32_t	nr_if_pool_objsize;
+	uint64_t	nr_ring_pool_offset;
+	uint32_t	nr_ring_pool_objtotal;
+	uint32_t	nr_ring_pool_objsize;
+	uint64_t	nr_buf_pool_offset;
+	uint32_t	nr_buf_pool_objtotal;
+	uint32_t	nr_buf_pool_objsize;
 };
 
 #endif /* _NET_NETMAP_H_ */
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index a520a16dc..7b1f769d8 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -109,10 +109,31 @@ struct ptnetmap_cfgentry_bhyve {
 	} ioctl_data;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_PASSTHROUGH_ENABLE
+ * Enable host-side ptnetmap processing (e.g. start ptnetmap kthreads).
+ */
+struct nmreq_passthrough_enable {
+	struct nmreq_header	nr_hdr;
+	/* Userspace pointer to a variable-size struct containing the
+	 * ptnetmap configuration. */
+	struct pnetmap_cfg	*nr_cfg;
+	/* Length of the configuration struct above (in bytes). */
+	uint32_t		nr_cfg_len;
+};
+
+/*
+ * nr_reqtype: NETMAP_REQ_PASSTHROUGH_DISABLE
+ * Disalbe host-side ptnetmap processing (e.g. stop ptnetmap kthreads).
+ */
+struct nmreq_passthrough_disable {
+	struct nmreq_header	nr_hdr;
+};
+
 /*
  * Structure filled-in by the kernel when asked for allocator info
  * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
- * ptnetmap.
+ * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
  */
 struct netmap_pools_info {
 	uint64_t memsize;	/* same as nmr->nr_memsize */
@@ -131,6 +152,7 @@ struct netmap_pools_info {
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
  * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.
+ * XXX deprecated
  */
 static inline void
 nmreq_pointer_put(struct nmreq *nmr, void *userptr)

From 7b54185b66cd0a8188191532f1cd73081c8634be Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 18:37:25 +0100
Subject: [PATCH 0595/2207] netmap.h: add missing nmreq_vale_ops_register

---
 sys/net/netmap.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 06d9dcc18..5d2473fc7 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -654,6 +654,8 @@ enum {
 	/* Disable host-side ptnetmap processing (e.g. stop ptnetmap
 	 * kthreads). */
 	NETMAP_REQ_PASSTHROUGH_DISABLE,
+	/* Program a VALE switch by registering custom callbacks. */
+	NETMAP_REQ_VALE_OPS_REGISTER,
 };
 
 #define NETMAP_REQ_IFNAMSIZ	64
@@ -813,4 +815,16 @@ struct nmreq_pools_info_get {
 	uint32_t	nr_buf_pool_objsize;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_VALE_OPS_REGISTER
+ * Program a VALE switch by registering custom callbacks (e.g.
+ * lookup, config and dtor). This netmap request should not
+ * be called from userspace programs, but only by kernel
+ * modules.
+ */
+struct nmreq_vale_ops_register {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+};
+
 #endif /* _NET_NETMAP_H_ */

From 74f2f409a7d2d25f40dcce17c845a275598a8009 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 18:57:15 +0100
Subject: [PATCH 0596/2207] netmap.h: add missing struct to replace NIOCGINFO

---
 sys/net/netmap.h | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 5d2473fc7..d8393032b 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -614,9 +614,8 @@ typedef struct _POLL_REQUEST_DATA {
 
 
 /*
- * New API to control netmap control devices, deprecating 'struct nmreq',
- * NIOCREGIF, NIOCGINFO and NIOCCONFIG. New applications should only use
- * nmreq_xyz structs.
+ * New API to control netmap control devices. New applications should only use
+ * nmreq_xyz structs with the NIOCCTRL ioctl() command.
  */
 
 /* Header common to all requests. */
@@ -628,6 +627,8 @@ struct nmreq_header {
 enum {
 	/* Register a netmap port with the device. */
 	NETMAP_REQ_REGISTER = 1,
+	/* Get information from a netmap port. */
+	NETMAP_REQ_PORT_INFO_GET,
 	/* Attach a netmap port to a VALE switch. */
 	NETMAP_REQ_VALE_ATTACH,
 	/* Detach a netmap port from a VALE switch. */
@@ -715,6 +716,30 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 	NR_REG_PIPE_SLAVE = 6,
 };
 
+/* A single ioctl number is shared by all the new API command.
+ * Demultiplexing is done using the nr_hdr.nr_reqtype field.
+ * FreeBSD uses the size value embedded in the _IOWR to determine
+ * how much to copy in/out, so we define the ioctl() command
+ * specifying the largest among the nmreq_xyz structs. */
+#define NIOCCTRL	_IOWR('i', 151, struct nmreq_register)
+
+/*
+ * nr_reqtype: NETMAP_REQ_PORT_INFO_GET
+ * Get information about a netmap port, including number of rings.
+ * slots per ring, id of the memory allocator, etc.
+ */
+struct nmreq_port_info_get {
+	struct nmreq_header nr_hdr;
+	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* netmap port name */
+	uint64_t	nr_offset;	/* nifp offset in the shared region */
+	uint64_t	nr_memsize;	/* size of the shared region */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+};
+
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
 /*

From e83776caaab9692ba30d0a5574cb9e12a45b23d0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 22 Jan 2018 19:11:21 +0100
Subject: [PATCH 0597/2207] nmreq: move legacy definitions in a separate file
 to improve readability

---
 LINUX/netmap.mak.in     |   1 +
 sys/net/netmap.h        | 242 ++-----------------------------------
 sys/net/netmap_legacy.h | 260 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 234 deletions(-)
 create mode 100644 sys/net/netmap_legacy.h

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index ce71bc972..4e2a5b30f 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -133,6 +133,7 @@ install-headers:
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap.h
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_user.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_user.h
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_virt.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_virt.h
+	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_legacy.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_legacy.h
 
 MAN_PREFIX := $(INCLUDE_PREFIX)
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d8393032b..9ceb6ee66 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -378,240 +378,10 @@ struct netmap_if {
 	const ssize_t	ring_ofs[0];
 };
 
-
-/*
- * ioctl names and related fields
- *
- * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
- *	whose identity is set in NIOCREGIF through nr_ringid.
- *	These are non blocking and take no argument.
- *
- * NIOCGINFO takes a struct ifreq, the interface name is the input,
- *	the outputs are number of queues and number of descriptor
- *	for each queue (useful to set number of threads etc.).
- *	The info returned is only advisory and may change before
- *	the interface is bound to a file descriptor.
- *
- * NIOCREGIF takes an interface name within a struct nmre,
- *	and activates netmap mode on the interface (if possible).
- *
- * The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
- * can pass it down to other NIC-related ioctls.
- *
- * The actual argument (struct nmreq) has a number of options to request
- * different functions.
- * The following are used in NIOCREGIF when nr_cmd == 0:
- *
- * nr_name	(in)
- *	The name of the port (em0, valeXXX:YYY, etc.)
- *	limited to IFNAMSIZ for backward compatibility.
- *
- * nr_version	(in/out)
- *	Must match NETMAP_API as used in the kernel, error otherwise.
- *	Always returns the desired value on output.
- *
- * nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
- *	On input, non-zero values may be used to reconfigure the port
- *	according to the requested values, but this is not guaranteed.
- *	On output the actual values in use are reported.
- *
- * nr_ringid (in)
- *	Indicates how rings should be bound to the file descriptors.
- *	If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
- *	are used to indicate the ring number, and nr_flags specifies
- *	the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
- *
- *	NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
- *	If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
- *	the binding as follows:
- *	0 (default)			binds all physical rings
- *	NETMAP_HW_RING | ring number	binds a single ring pair
- *	NETMAP_SW_RING			binds only the host tx/rx rings
- *
- *	NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
- *		packets on tx rings only if POLLOUT is set.
- *		The default is to push any pending packet.
- *
- *	NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
- *		packets on rx rings also when POLLIN is NOT set.
- *		The default is to touch the rx ring only with POLLIN.
- *		Note that this is the opposite of TX because it
- *		reflects the common usage.
- *
- *	NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
- *	NETMAP_PRIV_MEM is set on return for ports that do not use
- *		the global memory allocator.
- *		This information is not significant and applications
- *		should look at the region id in nr_arg2
- *
- * nr_flags	is the recommended mode to indicate which rings should
- *		be bound to a file descriptor. Values are NR_REG_*
- *
- * nr_arg1 (in)	The number of extra rings to be reserved.
- *		Especially when allocating a VALE port the system only
- *		allocates the amount of memory needed for the port.
- *		If more shared memory rings are desired (e.g. for pipes),
- *		the first invocation for the same basename/allocator
- *		should specify a suitable number. Memory cannot be
- *		extended after the first allocation without closing
- *		all ports on the same region.
- *
- * nr_arg2 (in/out) The identity of the memory region used.
- *		On input, 0 means the system decides autonomously,
- *		other values may try to select a specific region.
- *		On return the actual value is reported.
- *		Region '1' is the global allocator, normally shared
- *		by all interfaces. Other values are private regions.
- *		If two ports the same region zero-copy is possible.
- *
- * nr_arg3 (in/out)	number of extra buffers to be allocated.
- *
- *
- *
- * nr_cmd (in)	if non-zero indicates a special command:
- *	NETMAP_BDG_ATTACH	 and nr_name = vale*:ifname
- *		attaches the NIC to the switch; nr_ringid specifies
- *		which rings to use. Used by vale-ctl -a ...
- *	    nr_arg1 = NETMAP_BDG_HOST also attaches the host port
- *		as in vale-ctl -h ...
- *
- *	NETMAP_BDG_DETACH	and nr_name = vale*:ifname
- *		disconnects a previously attached NIC.
- *		Used by vale-ctl -d ...
- *
- *	NETMAP_BDG_LIST
- *		list the configuration of VALE switches.
- *
- *	NETMAP_BDG_VNET_HDR
- *		Set the virtio-net header length used by the client
- *		of a VALE switch port.
- *
- *	NETMAP_BDG_NEWIF
- *		create a persistent VALE port with name nr_name.
- *		Used by vale-ctl -n ...
- *
- *	NETMAP_BDG_DELIF
- *		delete a persistent VALE port. Used by vale-ctl -d ...
- *
- * nr_arg1, nr_arg2, nr_arg3  (in/out)		command specific
- *
- *
- *
- */
-
-
-/*
- * struct nmreq overlays a struct ifreq (just the name)
- */
-struct nmreq {
-	char		nr_name[IFNAMSIZ];
-	uint32_t	nr_version;	/* API version */
-	uint32_t	nr_offset;	/* nifp offset in the shared region */
-	uint32_t	nr_memsize;	/* size of the shared region */
-	uint32_t	nr_tx_slots;	/* slots in tx rings */
-	uint32_t	nr_rx_slots;	/* slots in rx rings */
-	uint16_t	nr_tx_rings;	/* number of tx rings */
-	uint16_t	nr_rx_rings;	/* number of rx rings */
-
-	uint16_t	nr_ringid;	/* ring(s) we care about */
-#define NETMAP_HW_RING		0x4000	/* single NIC ring pair */
-#define NETMAP_SW_RING		0x2000	/* only host ring pair */
-
-#define NETMAP_RING_MASK	0x0fff	/* the ring number */
-
-#define NETMAP_NO_TX_POLL	0x1000	/* no automatic txsync on poll */
-
-#define NETMAP_DO_RX_POLL	0x8000	/* DO automatic rxsync on poll */
-
-	uint16_t	nr_cmd;
-#define NETMAP_BDG_ATTACH	1	/* attach the NIC */
-#define NETMAP_BDG_DETACH	2	/* detach the NIC */
-#define NETMAP_BDG_REGOPS	3	/* register bridge callbacks */
-#define NETMAP_BDG_LIST		4	/* get bridge's info */
-#define NETMAP_BDG_VNET_HDR     5       /* set the port virtio-net-hdr length */
-#define NETMAP_BDG_NEWIF	6	/* create a virtual port */
-#define NETMAP_BDG_DELIF	7	/* destroy a virtual port */
-#define NETMAP_PT_HOST_CREATE	8	/* create ptnetmap kthreads */
-#define NETMAP_PT_HOST_DELETE	9	/* delete ptnetmap kthreads */
-#define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
-#define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
-#define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
-#define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
-	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
-
-	uint16_t	nr_arg2;
-	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
-	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
-#define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */
-	/* various modes, extends nr_ringid */
-	uint32_t	spare2[1];
-};
-
-/*
- * Opaque structure that is passed to an external kernel
- * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
- * bridge port (at this point ephemeral VALE interface).
- */
-#define NM_IFRDATA_LEN 256
-struct nm_ifreq {
-	char nifr_name[IFNAMSIZ];
-	char data[NM_IFRDATA_LEN];
-};
-
-#ifdef _WIN32
-/*
- * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
- * in ws2def.h but not sure if they are in the form we need.
- * We therefore redefine them in a convenient way to use for DeviceIoControl
- * signatures.
- */
-#undef _IO	// ws2def.h
-#define _WIN_NM_IOCTL_TYPE 40000
-#define _IO(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
-		METHOD_BUFFERED, FILE_ANY_ACCESS  )
-#define _IO_direct(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
-		METHOD_OUT_DIRECT, FILE_ANY_ACCESS  )
-
-#define _IOWR(_c, _n, _s)	_IO(_c, _n)
-
-/* We havesome internal sysctl in addition to the externally visible ones */
-#define NETMAP_MMAP _IO_direct('i', 160)	// note METHOD_OUT_DIRECT
-#define NETMAP_POLL _IO('i', 162)
-
-/* and also two setsockopt for sysctl emulation */
-#define NETMAP_SETSOCKOPT _IO('i', 140)
-#define NETMAP_GETSOCKOPT _IO('i', 141)
-
-
-/* These linknames are for the Netmap Core Driver */
-#define NETMAP_NT_DEVICE_NAME			L"\\Device\\NETMAP"
-#define NETMAP_DOS_DEVICE_NAME			L"\\DosDevices\\netmap"
-
-/* Definition of a structure used to pass a virtual address within an IOCTL */
-typedef struct _MEMORY_ENTRY {
-	PVOID       pUsermodeVirtualAddress;
-} MEMORY_ENTRY, *PMEMORY_ENTRY;
-
-typedef struct _POLL_REQUEST_DATA {
-	int events;
-	int timeout;
-	int revents;
-} POLL_REQUEST_DATA;
-
-#endif /* _WIN32 */
-
-/*
- * FreeBSD uses the size value embedded in the _IOWR to determine
- * how much to copy in/out. So we need it to match the actual
- * data structure we pass. We put some spares in the structure
- * to ease compatibility with other versions
- */
-#define NIOCGINFO	_IOWR('i', 145, struct nmreq) /* return IF info */
-#define NIOCREGIF	_IOWR('i', 146, struct nmreq) /* interface register */
-#define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
-#define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
-#define NIOCCONFIG	_IOWR('i',150, struct nm_ifreq) /* for ext. modules */
-
+/* Legacy interface to interact with a netmap control device.
+ * Included for backward compatibility. The user should not include this
+ * file directly. */
+#include "netmap_legacy.h"
 
 /*
  * New API to control netmap control devices. New applications should only use
@@ -723,6 +493,10 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * specifying the largest among the nmreq_xyz structs. */
 #define NIOCCTRL	_IOWR('i', 151, struct nmreq_register)
 
+/* The ioctl commands to sync TX/RX netmap rings. */
+#define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
+#define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
+
 /*
  * nr_reqtype: NETMAP_REQ_PORT_INFO_GET
  * Get information about a netmap port, including number of rings.
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
new file mode 100644
index 000000000..19121173b
--- /dev/null
+++ b/sys/net/netmap_legacy.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``S IS''AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _NET_NETMAP_LEGACY_H_
+#define _NET_NETMAP_LEGACY_H_
+
+/*
+ * ioctl names and related fields
+ *
+ * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
+ *	whose identity is set in NIOCREGIF through nr_ringid.
+ *	These are non blocking and take no argument.
+ *
+ * NIOCGINFO takes a struct ifreq, the interface name is the input,
+ *	the outputs are number of queues and number of descriptor
+ *	for each queue (useful to set number of threads etc.).
+ *	The info returned is only advisory and may change before
+ *	the interface is bound to a file descriptor.
+ *
+ * NIOCREGIF takes an interface name within a struct nmre,
+ *	and activates netmap mode on the interface (if possible).
+ *
+ * The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
+ * can pass it down to other NIC-related ioctls.
+ *
+ * The actual argument (struct nmreq) has a number of options to request
+ * different functions.
+ * The following are used in NIOCREGIF when nr_cmd == 0:
+ *
+ * nr_name	(in)
+ *	The name of the port (em0, valeXXX:YYY, etc.)
+ *	limited to IFNAMSIZ for backward compatibility.
+ *
+ * nr_version	(in/out)
+ *	Must match NETMAP_API as used in the kernel, error otherwise.
+ *	Always returns the desired value on output.
+ *
+ * nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
+ *	On input, non-zero values may be used to reconfigure the port
+ *	according to the requested values, but this is not guaranteed.
+ *	On output the actual values in use are reported.
+ *
+ * nr_ringid (in)
+ *	Indicates how rings should be bound to the file descriptors.
+ *	If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
+ *	are used to indicate the ring number, and nr_flags specifies
+ *	the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
+ *
+ *	NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
+ *	If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
+ *	the binding as follows:
+ *	0 (default)			binds all physical rings
+ *	NETMAP_HW_RING | ring number	binds a single ring pair
+ *	NETMAP_SW_RING			binds only the host tx/rx rings
+ *
+ *	NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
+ *		packets on tx rings only if POLLOUT is set.
+ *		The default is to push any pending packet.
+ *
+ *	NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
+ *		packets on rx rings also when POLLIN is NOT set.
+ *		The default is to touch the rx ring only with POLLIN.
+ *		Note that this is the opposite of TX because it
+ *		reflects the common usage.
+ *
+ *	NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
+ *	NETMAP_PRIV_MEM is set on return for ports that do not use
+ *		the global memory allocator.
+ *		This information is not significant and applications
+ *		should look at the region id in nr_arg2
+ *
+ * nr_flags	is the recommended mode to indicate which rings should
+ *		be bound to a file descriptor. Values are NR_REG_*
+ *
+ * nr_arg1 (in)	The number of extra rings to be reserved.
+ *		Especially when allocating a VALE port the system only
+ *		allocates the amount of memory needed for the port.
+ *		If more shared memory rings are desired (e.g. for pipes),
+ *		the first invocation for the same basename/allocator
+ *		should specify a suitable number. Memory cannot be
+ *		extended after the first allocation without closing
+ *		all ports on the same region.
+ *
+ * nr_arg2 (in/out) The identity of the memory region used.
+ *		On input, 0 means the system decides autonomously,
+ *		other values may try to select a specific region.
+ *		On return the actual value is reported.
+ *		Region '1' is the global allocator, normally shared
+ *		by all interfaces. Other values are private regions.
+ *		If two ports the same region zero-copy is possible.
+ *
+ * nr_arg3 (in/out)	number of extra buffers to be allocated.
+ *
+ *
+ *
+ * nr_cmd (in)	if non-zero indicates a special command:
+ *	NETMAP_BDG_ATTACH	 and nr_name = vale*:ifname
+ *		attaches the NIC to the switch; nr_ringid specifies
+ *		which rings to use. Used by vale-ctl -a ...
+ *	    nr_arg1 = NETMAP_BDG_HOST also attaches the host port
+ *		as in vale-ctl -h ...
+ *
+ *	NETMAP_BDG_DETACH	and nr_name = vale*:ifname
+ *		disconnects a previously attached NIC.
+ *		Used by vale-ctl -d ...
+ *
+ *	NETMAP_BDG_LIST
+ *		list the configuration of VALE switches.
+ *
+ *	NETMAP_BDG_VNET_HDR
+ *		Set the virtio-net header length used by the client
+ *		of a VALE switch port.
+ *
+ *	NETMAP_BDG_NEWIF
+ *		create a persistent VALE port with name nr_name.
+ *		Used by vale-ctl -n ...
+ *
+ *	NETMAP_BDG_DELIF
+ *		delete a persistent VALE port. Used by vale-ctl -d ...
+ *
+ * nr_arg1, nr_arg2, nr_arg3  (in/out)		command specific
+ *
+ *
+ *
+ */
+
+
+/*
+ * struct nmreq overlays a struct ifreq (just the name)
+ */
+struct nmreq {
+	char		nr_name[IFNAMSIZ];
+	uint32_t	nr_version;	/* API version */
+	uint32_t	nr_offset;	/* nifp offset in the shared region */
+	uint32_t	nr_memsize;	/* size of the shared region */
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+
+	uint16_t	nr_ringid;	/* ring(s) we care about */
+#define NETMAP_HW_RING		0x4000	/* single NIC ring pair */
+#define NETMAP_SW_RING		0x2000	/* only host ring pair */
+
+#define NETMAP_RING_MASK	0x0fff	/* the ring number */
+
+#define NETMAP_NO_TX_POLL	0x1000	/* no automatic txsync on poll */
+
+#define NETMAP_DO_RX_POLL	0x8000	/* DO automatic rxsync on poll */
+
+	uint16_t	nr_cmd;
+#define NETMAP_BDG_ATTACH	1	/* attach the NIC */
+#define NETMAP_BDG_DETACH	2	/* detach the NIC */
+#define NETMAP_BDG_REGOPS	3	/* register bridge callbacks */
+#define NETMAP_BDG_LIST		4	/* get bridge's info */
+#define NETMAP_BDG_VNET_HDR     5       /* set the port virtio-net-hdr length */
+#define NETMAP_BDG_NEWIF	6	/* create a virtual port */
+#define NETMAP_BDG_DELIF	7	/* destroy a virtual port */
+#define NETMAP_PT_HOST_CREATE	8	/* create ptnetmap kthreads */
+#define NETMAP_PT_HOST_DELETE	9	/* delete ptnetmap kthreads */
+#define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
+#define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
+#define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
+#define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
+	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
+
+	uint16_t	nr_arg2;
+	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
+	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
+#define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */
+	/* various modes, extends nr_ringid */
+	uint32_t	spare2[1];
+};
+
+#ifdef _WIN32
+/*
+ * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
+ * in ws2def.h but not sure if they are in the form we need.
+ * We therefore redefine them in a convenient way to use for DeviceIoControl
+ * signatures.
+ */
+#undef _IO	// ws2def.h
+#define _WIN_NM_IOCTL_TYPE 40000
+#define _IO(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
+		METHOD_BUFFERED, FILE_ANY_ACCESS  )
+#define _IO_direct(_c, _n)	CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
+		METHOD_OUT_DIRECT, FILE_ANY_ACCESS  )
+
+#define _IOWR(_c, _n, _s)	_IO(_c, _n)
+
+/* We havesome internal sysctl in addition to the externally visible ones */
+#define NETMAP_MMAP _IO_direct('i', 160)	// note METHOD_OUT_DIRECT
+#define NETMAP_POLL _IO('i', 162)
+
+/* and also two setsockopt for sysctl emulation */
+#define NETMAP_SETSOCKOPT _IO('i', 140)
+#define NETMAP_GETSOCKOPT _IO('i', 141)
+
+
+/* These linknames are for the Netmap Core Driver */
+#define NETMAP_NT_DEVICE_NAME			L"\\Device\\NETMAP"
+#define NETMAP_DOS_DEVICE_NAME			L"\\DosDevices\\netmap"
+
+/* Definition of a structure used to pass a virtual address within an IOCTL */
+typedef struct _MEMORY_ENTRY {
+	PVOID       pUsermodeVirtualAddress;
+} MEMORY_ENTRY, *PMEMORY_ENTRY;
+
+typedef struct _POLL_REQUEST_DATA {
+	int events;
+	int timeout;
+	int revents;
+} POLL_REQUEST_DATA;
+#endif /* _WIN32 */
+
+/*
+ * Opaque structure that is passed to an external kernel
+ * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
+ * bridge port (at this point ephemeral VALE interface).
+ */
+#define NM_IFRDATA_LEN 256
+struct nm_ifreq {
+	char nifr_name[IFNAMSIZ];
+	char data[NM_IFRDATA_LEN];
+};
+
+/*
+ * FreeBSD uses the size value embedded in the _IOWR to determine
+ * how much to copy in/out. So we need it to match the actual
+ * data structure we pass. We put some spares in the structure
+ * to ease compatibility with other versions
+ */
+#define NIOCGINFO	_IOWR('i', 145, struct nmreq) /* return IF info */
+#define NIOCREGIF	_IOWR('i', 146, struct nmreq) /* interface register */
+#define NIOCCONFIG	_IOWR('i',150, struct nm_ifreq) /* for ext. modules */
+
+#endif /* _NET_NETMAP_LEGACY_H_ */

From 5c2b14240293693ac04b4786f8b1cd001ae7b85f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Jan 2018 17:17:45 +0100
Subject: [PATCH 0598/2207] newnmreq: introduce nmreq_from_legacy()

---
 sys/dev/netmap/netmap.c | 77 ++++++++++++++++++++++++++++++++++++++---
 sys/net/netmap.h        |  4 +--
 sys/net/netmap_legacy.h |  2 +-
 3 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5d55b8226..6affbdb84 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2240,16 +2240,75 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
+/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
+ * (new API). The new struct is dynamically allocated. */
+static struct nmreq_header *
+nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
+{
+	/* Sanitize nmr->nr_name by adding the string terminator. */
+	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
+		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
+	}
+
+	switch (ioctl_cmd) {
+	case NIOCREGIF: {
+		switch (nmr->nr_cmd) {
+		case 0: {
+			/* Regular NIOCREGIF operation. */
+			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
+			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
+				req->nr_flags |= NR_NO_TX_POLL;
+			}
+			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
+				req->nr_flags |= NR_DO_RX_POLL;
+			}
+			req->nr_pipes = nmr->nr_arg1;
+			req->nr_extra_bufs = nmr->nr_arg3;
+			return (struct nmreq_header *)req;
+			break;
+		}
+		}
+		break;
+	}
+	}
+
+	return NULL;
+oom:
+	D("Failed to allocate memory for nmreq_xyz struct");
+	return NULL;
+}
+
+/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
+ * It also frees the nmreq_xyz struct, as it was allocated by
+ * nmreq_from_legacy(). */
+static void
+nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
+{
+	nm_os_free(hdr);
+}
 
 /*
  * ioctl(2) support for the "netmap" device.
  *
  * Following a list of accepted commands:
- * - NIOCGINFO
+ * - NIOCCTRL		device control API
+ * - NIOCTXSYNC		sync TX rings
+ * - NIOCRXSYNC		sync RX rings
  * - SIOCGIFADDR	just for convenience
- * - NIOCREGIF
- * - NIOCTXSYNC
- * - NIOCRXSYNC
+ * - NIOCGINFO		deprecated (legacy API)
+ * - NIOCREGIF		deprecated (legacy API)
  *
  * Return 0 on success, errno otherwise.
  */
@@ -2284,6 +2343,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	}
 
 	switch (cmd) {
+	case NIOCCTRL: {
+		struct nmreq_header *hdr = (struct nmreq_header *)data;
+
+		switch (hdr->nr_reqtype) {
+		default: {
+			break;
+		}
+		}
+		break;
+	}
 	case NIOCGINFO:		/* return capabilities etc */
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			error = netmap_bdg_ctl(nmr, NULL);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 9ceb6ee66..16905a574 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -39,7 +39,7 @@
 #ifndef _NET_NETMAP_H_
 #define _NET_NETMAP_H_
 
-#define	NETMAP_API	11		/* current API version */
+#define	NETMAP_API	12		/* current API version */
 
 #define	NETMAP_MIN_API	11		/* min and max versions accepted */
 #define	NETMAP_MAX_API	15
@@ -472,8 +472,8 @@ struct nmreq_register {
 #define NR_DO_RX_POLL		0x10000
 #define NR_NO_TX_POLL		0x20000
 
+	uint32_t	nr_pipes;	/* number of pipes to create */
 	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
-	uint8_t         nr_spare[64];
 };
 
 /* Valid values for nmreq_register.nr_mode (see above). */
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 19121173b..c5f94980b 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -187,7 +187,7 @@ struct nmreq {
 #define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
 
-	uint16_t	nr_arg2;
+	uint16_t	nr_arg2;	/* id of the memory allocator */
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
 	uint32_t	nr_flags;	/* specify NR_REG_* mode and other flags */
 #define NR_REG_MASK		0xf /* to extract NR_REG_* mode from nr_flags */

From 87fc03e3de70dd036b7c475a18f6893874d607c7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Jan 2018 17:32:55 +0100
Subject: [PATCH 0599/2207] netmap.h: introduce struct nmreq_option

---
 sys/net/netmap.h | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 16905a574..3a397d393 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -388,10 +388,19 @@ struct netmap_if {
  * nmreq_xyz structs with the NIOCCTRL ioctl() command.
  */
 
+/* Header common to all request options. */
+struct nmreq_option {
+	/* Pointer ot the next option. */
+	struct nmreq_option	*nro_next;
+	/* Option type. */
+	uint16_t		nro_reqtype;
+};
+
 /* Header common to all requests. */
 struct nmreq_header {
-	uint16_t	nr_version;	/* API version */
-	uint16_t	nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+	uint16_t		nr_version;	/* API version */
+	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+	struct nmreq_option	*options;	/* command-specific options */
 };
 
 enum {
@@ -429,6 +438,12 @@ enum {
 	NETMAP_REQ_VALE_OPS_REGISTER,
 };
 
+enum {
+	/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
+	 * from user-space allocated memory pools (e.g. hugepages). */
+	NETMAP_REQ_OPT_EXTMEM = 1,
+};
+
 #define NETMAP_REQ_IFNAMSIZ	64
 
 /*

From 23176147b6a15578062e8dc961f8cc17b9a315fb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Jan 2018 18:53:27 +0100
Subject: [PATCH 0600/2207] nmreq_from_legacy: support several vale commands

---
 sys/dev/netmap/netmap.c | 59 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6affbdb84..e59bbb8b1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2245,6 +2245,8 @@ ring_timestamp_set(struct netmap_ring *ring)
 static struct nmreq_header *
 nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 {
+	struct nmreq_header *hdr = NULL;
+
 	/* Sanitize nmr->nr_name by adding the string terminator. */
 	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
@@ -2257,6 +2259,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
@@ -2276,7 +2279,57 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			}
 			req->nr_pipes = nmr->nr_arg1;
 			req->nr_extra_bufs = nmr->nr_arg3;
-			return (struct nmreq_header *)req;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_ATTACH: {
+			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DETACH: {
+			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_VNET_HDR:
+		case NETMAP_VNET_HDR_GET: {
+			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
+				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_hdr_len = nmr->nr_arg1;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_NEWIF : {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DELIF: {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		}
@@ -2284,7 +2337,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	}
 	}
 
-	return NULL;
+	hdr->nr_version = NETMAP_API; /* new API */
+
+	return hdr;
 oom:
 	D("Failed to allocate memory for nmreq_xyz struct");
 	return NULL;

From a0ab197be3c45c2e4eb478261361aef3bc07b3ef Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 17:15:52 +0100
Subject: [PATCH 0601/2207] nmreq_from_legacy: support missing commands

ptnetmap configuration commands are not supported for now, as
they will be supported through a nmreq_register option.
---
 sys/dev/netmap/netmap.c | 53 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e59bbb8b1..6254e6775 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2332,6 +2332,59 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
+		case NETMAP_BDG_POLLING_ON:
+		case NETMAP_BDG_POLLING_OFF: {
+			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
+				NETMAP_REQ_VALE_POLLING_ENABLE :
+				NETMAP_REQ_VALE_POLLING_DISABLE;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_POOLS_INFO_GET: {
+			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			/* Most of the fields are for output (see
+			 * nmreq_to_legacy). */
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_PT_HOST_CREATE:
+		case NETMAP_PT_HOST_DELETE: {
+			D("Netmap passthrough not supported yet");
+			return NULL;
+			break;
+		}
+		}
+		break;
+	}
+	case NIOCGINFO: {
+		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
+			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_bridge_idx = nmr->nr_arg1;
+			req->nr_port_idx = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+		} else {
+			/* Regular NIOCGINFO. */
+			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
 		}
 		break;
 	}

From 90943353fe7bd4f97027a31e644acf0604238703 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 17:58:18 +0100
Subject: [PATCH 0602/2207] implement nmreq_to_legacy() to convert nmreq_xyx to
 legacy nmreq

---
 sys/dev/netmap/netmap.c | 117 +++++++++++++++++++++++++++++++++++++++-
 sys/net/netmap_legacy.h |  19 +++++++
 sys/net/netmap_virt.h   |  19 -------
 3 files changed, 134 insertions(+), 21 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6254e6775..315648320 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2344,6 +2344,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			break;
 		}
 		case NETMAP_POOLS_INFO_GET: {
+			/* We could deny this request similar to ptnetmap requests. */
 			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
@@ -2373,7 +2374,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			hdr = (struct nmreq_header *)req;
 		} else {
 			/* Regular NIOCGINFO. */
-			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
@@ -2401,10 +2402,122 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
  * It also frees the nmreq_xyz struct, as it was allocated by
  * nmreq_from_legacy(). */
-static void
+static int
 nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
+	int ret = 0;
+	/* Don't bzero 'nmr', we may need the pointers stored into
+	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
+
+	switch (hdr->nr_reqtype) {
+	case NETMAP_REQ_REGISTER: {
+		struct nmreq_register *req = (struct nmreq_register *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_ringid = req->nr_ringid;
+		if (req->nr_flags & NR_NO_TX_POLL) {
+			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
+		}
+		if (req->nr_flags & NR_DO_RX_POLL) {
+			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
+		}
+		nmr->nr_flags = req->nr_mode | req->nr_flags;
+		nmr->nr_arg1 = req->nr_pipes;
+		nmr->nr_arg3 = req->nr_extra_bufs;
+		break;
+	}
+	case NETMAP_REQ_PORT_INFO_GET: {
+		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_ATTACH: {
+		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_arg1 = req->nr_flags;
+		break;
+	}
+	case NETMAP_REQ_VALE_DETACH: {
+		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		break;
+	}
+	case NETMAP_REQ_VALE_LIST: {
+		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_arg1 = req->nr_bridge_idx;
+		nmr->nr_arg2 = req->nr_port_idx;
+		break;
+	}
+	case NETMAP_REQ_PORT_HDR_SET:
+	case NETMAP_REQ_PORT_HDR_GET: {
+		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_arg1 = req->nr_hdr_len;
+		break;
+	}
+	case NETMAP_REQ_VALE_NEWIF: {
+		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_DELIF: {
+		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		break;
+	}
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+	case NETMAP_REQ_VALE_POLLING_DISABLE: {
+		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		break;
+	}
+	case NETMAP_REQ_POOLS_INFO_GET: {
+		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
+		struct netmap_pools_info pi;
+		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
+		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		pi.memsize = req->nr_memsize;
+		pi.memid = req->nr_mem_id;
+		pi.if_pool_offset = req->nr_if_pool_offset;
+		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
+		pi.if_pool_objsize = req->nr_if_pool_objsize;
+		pi.ring_pool_offset = req->nr_ring_pool_offset;
+		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
+		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
+		pi.buf_pool_offset = req->nr_buf_pool_offset;
+		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
+		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
+		ret = copyout(&pi, upi, sizeof(pi));
+		if (ret) {
+			D("copyout() failed");
+		}
+		break;
+	}
+	}
+
 	nm_os_free(hdr);
+	return ret;
 }
 
 /*
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index c5f94980b..9b961a05a 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -195,6 +195,25 @@ struct nmreq {
 	uint32_t	spare2[1];
 };
 
+/*
+ * Structure filled-in by the kernel when asked for allocator info
+ * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
+ * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
+ */
+struct netmap_pools_info {
+	uint64_t memsize;	/* same as nmr->nr_memsize */
+	uint32_t memid;		/* same as nmr->nr_arg2 */
+	uint32_t if_pool_offset;
+	uint32_t if_pool_objtotal;
+	uint32_t if_pool_objsize;
+	uint32_t ring_pool_offset;
+	uint32_t ring_pool_objtotal;
+	uint32_t ring_pool_objsize;
+	uint32_t buf_pool_offset;
+	uint32_t buf_pool_objtotal;
+	uint32_t buf_pool_objsize;
+};
+
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 7b1f769d8..5fb529ee4 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -130,25 +130,6 @@ struct nmreq_passthrough_disable {
 	struct nmreq_header	nr_hdr;
 };
 
-/*
- * Structure filled-in by the kernel when asked for allocator info
- * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
- * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
- */
-struct netmap_pools_info {
-	uint64_t memsize;	/* same as nmr->nr_memsize */
-	uint32_t memid;		/* same as nmr->nr_arg2 */
-	uint32_t if_pool_offset;
-	uint32_t if_pool_objtotal;
-	uint32_t if_pool_objsize;
-	uint32_t ring_pool_offset;
-	uint32_t ring_pool_objtotal;
-	uint32_t ring_pool_objsize;
-	uint32_t buf_pool_offset;
-	uint32_t buf_pool_objtotal;
-	uint32_t buf_pool_objsize;
-};
-
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
  * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.

From 132905738989b07e0956345a39a2861b7a273535 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 18:23:13 +0100
Subject: [PATCH 0603/2207] nmreq_from_legacy: support original netmap API
 (NR_REG_DEFAULT)

---
 sys/dev/netmap/netmap.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 315648320..9b4956c8a 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2269,6 +2269,20 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_rx_rings = nmr->nr_rx_rings;
 			req->nr_mem_id = nmr->nr_arg2;
 			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
+				/* Convert the older nmr->nr_ringid (original
+				 * netmap control API) to nmr->nr_flags. */
+				u_int regmode = NR_REG_DEFAULT;
+				if (req->nr_ringid & NETMAP_SW_RING) {
+					regmode = NR_REG_SW;
+				} else if (req->nr_ringid & NETMAP_HW_RING) {
+					regmode = NR_REG_ONE_NIC;
+				} else {
+					regmode = NR_REG_ALL_NIC;
+				}
+				nmr->nr_flags = regmode |
+					(nmr->nr_flags & (~NR_REG_MASK));
+			}
 			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
 			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
 			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {

From 5d3c7cc1cba131243708a48ec15d9dc30b6877ca Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Jan 2018 19:49:35 +0100
Subject: [PATCH 0604/2207] large refactor to use new request structs
 internally

---
 LINUX/netmap_linux.c            |   7 +-
 sys/dev/netmap/netmap.c         | 590 +++++++++++++++++++-------------
 sys/dev/netmap/netmap_kern.h    |  46 ++-
 sys/dev/netmap/netmap_mem2.c    |  51 ++-
 sys/dev/netmap/netmap_mem2.h    |   8 +-
 sys/dev/netmap/netmap_monitor.c |  35 +-
 sys/dev/netmap/netmap_pipe.c    |  42 +--
 sys/dev/netmap/netmap_pt.c      | 135 +++-----
 sys/dev/netmap/netmap_vale.c    | 453 ++++++++++++------------
 sys/net/netmap.h                |  24 +-
 10 files changed, 721 insertions(+), 670 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 56a3ded8a..564b4a8a5 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1032,8 +1032,9 @@ static int
 linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
 {
 	int error = 0;
-	unsigned long off;
-	u_int memsize, memflags;
+	uint64_t off;
+	unsigned int memflags;
+	uint64_t memsize;
 	struct netmap_priv_d *priv = f->private_data;
 	struct netmap_adapter *na = priv->np_na;
 	/*
@@ -2363,7 +2364,7 @@ EXPORT_SYMBOL(netmap_reset);		/* ring init routines */
 EXPORT_SYMBOL(netmap_rx_irq);	        /* default irq handler */
 EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 #ifdef WITH_VALE
-EXPORT_SYMBOL(netmap_bdg_ctl);		/* bridge configuration routine */
+EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
 EXPORT_SYMBOL(netmap_bdg_learning);	/* the default lookup function */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
 #endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9b4956c8a..81e98dd94 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1441,7 +1441,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  * MUST BE CALLED UNDER NMG_LOCK()
  *
  * Get a refcounted reference to a netmap adapter attached
- * to the interface specified by nmr.
+ * to the interface specified by req.
  * This is always called in the execution of an ioctl().
  *
  * Return ENXIO if the interface specified by the request does
@@ -1451,11 +1451,11 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  * could not be allocated.
  * If successful, hold a reference to the netmap adapter.
  *
- * If the interface specified by nmr is a system one, also keep
+ * If the interface specified by req is a system one, also keep
  * a reference to it and return a valid *ifp.
  */
 int
-netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	      struct ifnet **ifp, struct netmap_mem_d *nmd, int create)
 {
 	int error = 0;
@@ -1470,8 +1470,8 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
 	/* if the request contain a memid, try to find the
 	 * corresponding memory region
 	 */
-	if (nmd == NULL && nmr->nr_arg2) {
-		nmd = netmap_mem_find(nmr->nr_arg2);
+	if (nmd == NULL && req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
 		if (nmd == NULL)
 			return EINVAL;
 		/* keep the rereference */
@@ -1490,22 +1490,23 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
 	 */
 
 	/* try to see if this is a ptnetmap port */
-	error = netmap_get_pt_host_na(nmr, na, nmd, create);
+	error = netmap_get_pt_host_na(req, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a monitor port */
-	error = netmap_get_monitor_na(nmr, na, nmd, create);
+	error = netmap_get_monitor_na(req, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a pipe port */
-	error = netmap_get_pipe_na(nmr, na, nmd, create);
+	error = netmap_get_pipe_na(req, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a bridge port */
-	error = netmap_get_bdg_na(nmr, na, nmd, create);
+	error = netmap_get_bdg_na((struct nmreq_header *)req,
+					na, nmd, create);
 	if (error)
 		goto out;
 
@@ -1518,7 +1519,7 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
 	 * This may still be a tap, a veth/epair, or even a
 	 * persistent VALE port.
 	 */
-	*ifp = ifunit_ref(nmr->nr_name);
+	*ifp = ifunit_ref(req->nr_hdr.nr_name);
 	if (*ifp == NULL) {
 		error = ENXIO;
 		goto out;
@@ -1763,39 +1764,27 @@ netmap_ring_reinit(struct netmap_kring *kring)
  *
  */
 int
-netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags)
+netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
+			uint16_t nr_ringid, uint64_t nr_flags)
 {
 	struct netmap_adapter *na = priv->np_na;
-	u_int j, i = ringid & NETMAP_RING_MASK;
-	u_int reg = flags & NR_REG_MASK;
 	int excluded_direction[] = { NR_TX_RINGS_ONLY, NR_RX_RINGS_ONLY };
 	enum txrx t;
+	u_int j;
 
-	if (reg == NR_REG_DEFAULT) {
-		/* convert from old ringid to flags */
-		if (ringid & NETMAP_SW_RING) {
-			reg = NR_REG_SW;
-		} else if (ringid & NETMAP_HW_RING) {
-			reg = NR_REG_ONE_NIC;
-		} else {
-			reg = NR_REG_ALL_NIC;
-		}
-		D("deprecated API, old ringid 0x%x -> ringid %x reg %d", ringid, i, reg);
-	}
-
-	if ((flags & NR_PTNETMAP_HOST) && ((reg != NR_REG_ALL_NIC &&
-                    reg != NR_REG_PIPE_MASTER && reg != NR_REG_PIPE_SLAVE) ||
-			flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
+	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC &&
+                    nr_mode != NR_REG_PIPE_MASTER && nr_mode != NR_REG_PIPE_SLAVE) ||
+			nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
 		D("Error: only NR_REG_ALL_NIC supported with netmap passthrough");
 		return EINVAL;
 	}
 
 	for_rx_tx(t) {
-		if (flags & excluded_direction[t]) {
+		if (nr_flags & excluded_direction[t]) {
 			priv->np_qfirst[t] = priv->np_qlast[t] = 0;
 			continue;
 		}
-		switch (reg) {
+		switch (nr_mode) {
 		case NR_REG_ALL_NIC:
 		case NR_REG_PIPE_MASTER:
 		case NR_REG_PIPE_SLAVE:
@@ -1810,20 +1799,21 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
 				D("host rings not supported");
 				return EINVAL;
 			}
-			priv->np_qfirst[t] = (reg == NR_REG_SW ?
+			priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
 				nma_get_nrings(na, t) : 0);
 			priv->np_qlast[t] = nma_get_nrings(na, t) + 1;
-			ND("%s: %s %d %d", reg == NR_REG_SW ? "SW" : "NIC+SW",
+			ND("%s: %s %d %d", nr_mode == NR_REG_SW ? "SW" : "NIC+SW",
 				nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		case NR_REG_ONE_NIC:
-			if (i >= na->num_tx_rings && i >= na->num_rx_rings) {
-				D("invalid ring id %d", i);
+			if (nr_ringid >= na->num_tx_rings &&
+					nr_ringid >= na->num_rx_rings) {
+				D("invalid ring id %d", nr_ringid);
 				return EINVAL;
 			}
 			/* if not enough rings, use the first one */
-			j = i;
+			j = nr_ringid;
 			if (j >= nma_get_nrings(na, t))
 				j = 0;
 			priv->np_qfirst[t] = j;
@@ -1832,11 +1822,11 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		default:
-			D("invalid regif type %d", reg);
+			D("invalid regif type %d", nr_mode);
 			return EINVAL;
 		}
 	}
-	priv->np_flags = (flags & ~NR_REG_MASK) | reg;
+	priv->np_flags = nr_flags | nr_mode; // TODO
 
 	/* Allow transparent forwarding mode in the host --> nic
 	 * direction only if all the TX hw rings have been opened. */
@@ -1852,7 +1842,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
 			priv->np_qlast[NR_TX],
 			priv->np_qfirst[NR_RX],
 			priv->np_qlast[NR_RX],
-			i);
+			nr_ringid);
 	}
 	return 0;
 }
@@ -1863,18 +1853,19 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags
  * for all rings is the same as a single ring.
  */
 static int
-netmap_set_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags)
+netmap_set_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
+		uint16_t nr_ringid, uint64_t nr_flags)
 {
 	struct netmap_adapter *na = priv->np_na;
 	int error;
 	enum txrx t;
 
-	error = netmap_interp_ringid(priv, ringid, flags);
+	error = netmap_interp_ringid(priv, nr_mode, nr_ringid, nr_flags);
 	if (error) {
 		return error;
 	}
 
-	priv->np_txpoll = (ringid & NETMAP_NO_TX_POLL) ? 0 : 1;
+	priv->np_txpoll = (nr_flags & NR_NO_TX_POLL) ? 0 : 1;
 
 	/* optimization: count the users registered for more than
 	 * one ring, which are the ones sleeping on the global queue.
@@ -1977,7 +1968,6 @@ netmap_krings_put(struct netmap_priv_d *priv)
 			priv->np_qfirst[NR_RX],
 			priv->np_qlast[MR_RX]);
 
-
 	for_rx_tx(t) {
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
 			kring = &NMR(na, t)[i];
@@ -2062,7 +2052,7 @@ netmap_krings_put(struct netmap_priv_d *priv)
  */
 int
 netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
-	uint16_t ringid, uint32_t flags)
+	uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags)
 {
 	struct netmap_if *nifp = NULL;
 	int error;
@@ -2071,7 +2061,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	/* ring configuration may have changed, fetch from the card */
 	netmap_update_config(na);
 	priv->np_na = na;     /* store the reference */
-	error = netmap_set_ringid(priv, ringid, flags);
+	error = netmap_set_ringid(priv, nr_mode, nr_ringid, nr_flags);
 	if (error)
 		goto err;
 	error = netmap_mem_finalize(na->nm_mem, na);
@@ -2260,7 +2250,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -2300,7 +2289,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_mem_id = nmr->nr_arg2;
 			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
 			hdr = (struct nmreq_header *)req;
@@ -2310,7 +2298,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
@@ -2320,7 +2307,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_hdr_len = nmr->nr_arg1;
 			hdr = (struct nmreq_header *)req;
 			break;
@@ -2329,7 +2315,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
 			req->nr_tx_rings = nmr->nr_tx_rings;
@@ -2342,7 +2327,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
@@ -2353,7 +2337,19 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
+			switch (nmr->nr_flags & NR_REG_MASK) {
+			default:
+				req->nr_mode = 0; /* invalid */
+				break;
+			case NR_REG_ONE_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
+				break;
+			case NR_REG_ALL_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+				break;
+			}
+			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
+			req->nr_num_polling_cpus = nmr->nr_arg1;
 			hdr = (struct nmreq_header *)req;
 			break;
 		}
@@ -2362,7 +2358,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			/* Most of the fields are for output (see
 			 * nmreq_to_legacy). */
 			hdr = (struct nmreq_header *)req;
@@ -2382,7 +2377,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
 			hdr = (struct nmreq_header *)req;
@@ -2391,7 +2385,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
 			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-			strncpy(req->nr_name, nmr->nr_name, sizeof(req->nr_name));
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -2405,7 +2398,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	}
 	}
 
+	KASSERT(hdr != NULL, "Invalid NULL netmap request");
 	hdr->nr_version = NETMAP_API; /* new API */
+	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
 
 	return hdr;
 oom:
@@ -2423,10 +2418,11 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	/* Don't bzero 'nmr', we may need the pointers stored into
 	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
 
+	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req = (struct nmreq_register *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -2448,7 +2444,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
 		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -2460,19 +2455,17 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_VALE_ATTACH: {
 		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg2 = req->nr_mem_id;
 		nmr->nr_arg1 = req->nr_flags;
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
 		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_LIST: {
 		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
@@ -2480,13 +2473,11 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_PORT_HDR_SET:
 	case NETMAP_REQ_PORT_HDR_GET: {
 		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_hdr_len;
 		break;
 	}
 	case NETMAP_REQ_VALE_NEWIF: {
 		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_tx_slots = req->nr_tx_slots;
 		nmr->nr_rx_slots = req->nr_rx_slots;
 		nmr->nr_tx_rings = req->nr_tx_rings;
@@ -2496,13 +2487,25 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_VALE_DELIF: {
 		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
 		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
+		switch (req->nr_mode) {
+		default:
+			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
+			break;
+		case NETMAP_POLLING_MODE_MULTI_CPU:
+			nmr->nr_flags = NR_REG_ONE_NIC;
+			break;
+		case NETMAP_POLLING_MODE_SINGLE_CPU:
+			nmr->nr_flags = NR_REG_ALL_NIC;
+			break;
+		}
+		nmr->nr_ringid = req->nr_first_cpu_id;
+		nmr->nr_arg1 = req->nr_num_polling_cpus;
 		break;
 	}
 	case NETMAP_REQ_POOLS_INFO_GET: {
@@ -2510,7 +2513,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
 		struct netmap_pools_info pi;
 		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
-		strncpy(nmr->nr_name, req->nr_name, sizeof(nmr->nr_name));
 		pi.memsize = req->nr_memsize;
 		pi.memid = req->nr_mem_id;
 		pi.if_pool_offset = req->nr_if_pool_offset;
@@ -2530,10 +2532,19 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	}
 
-	nm_os_free(hdr);
 	return ret;
 }
 
+static void
+nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
+				 struct nmreq_register *regreq)
+{
+	bzero(regreq, sizeof(*regreq));
+	memcpy(®req->nr_hdr, hdr, sizeof(regreq->nr_hdr));
+	regreq->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	regreq->nr_hdr.nr_options = NULL;
+}
+
 /*
  * ioctl(2) support for the "netmap" device.
  *
@@ -2551,7 +2562,6 @@ int
 netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *td)
 {
 	struct mbq q;	/* packets from RX hw queues to host stack */
-	struct nmreq *nmr = (struct nmreq *) data;
 	struct netmap_adapter *na = NULL;
 	struct netmap_mem_d *nmd = NULL;
 	struct ifnet *ifp = NULL;
@@ -2562,210 +2572,319 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	int sync_flags;
 	enum txrx t;
 
-	if (cmd == NIOCGINFO || cmd == NIOCREGIF) {
-		/* truncate name */
-		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
-		if (nmr->nr_version != NETMAP_API) {
-			D("API mismatch for %s got %d need %d",
-				nmr->nr_name,
-				nmr->nr_version, NETMAP_API);
-			nmr->nr_version = NETMAP_API;
-		}
-		if (nmr->nr_version < NETMAP_MIN_API ||
-		    nmr->nr_version > NETMAP_MAX_API) {
-			return EINVAL;
-		}
-	}
-
 	switch (cmd) {
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
-
-		switch (hdr->nr_reqtype) {
-		default: {
-			break;
-		}
+		if (hdr->nr_version != NETMAP_API) {
+			D("API mismatch for reqtype %d: got %d need %d",
+				hdr->nr_version,
+				hdr->nr_version, NETMAP_API);
+			hdr->nr_version = NETMAP_API;
 		}
-		break;
-	}
-	case NIOCGINFO:		/* return capabilities etc */
-		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
-			error = netmap_bdg_ctl(nmr, NULL);
-			break;
+		if (hdr->nr_version < NETMAP_MIN_API ||
+		    hdr->nr_version > NETMAP_MAX_API) {
+			return EINVAL;
 		}
 
-		NMG_LOCK();
-		do {
-			/* memsize is always valid */
-			u_int memflags;
+		/* Sanitize hdr->nr_name. */
+		hdr->nr_name[sizeof(hdr->nr_name) - 1] = '\0';
+
+		switch (hdr->nr_reqtype) {
+		case NETMAP_REQ_REGISTER: {
+			struct nmreq_register *req =
+				(struct nmreq_register *)hdr;
+			/* Protect access to priv from concurrent requests. */
+			NMG_LOCK();
+			do {
+				u_int memflags;
+
+				if (priv->np_nifp != NULL) {	/* thread already registered */
+					error = EBUSY;
+					break;
+				}
 
-			if (nmr->nr_name[0] != '\0') {
+				if (req->nr_mem_id) {
+					/* find the allocator and get a reference */
+					nmd = netmap_mem_find(req->nr_mem_id);
+					if (nmd == NULL) {
+						error = EINVAL;
+						break;
+					}
+				}
+				/* find the interface and a reference */
+				error = netmap_get_na(req, &na, &ifp, nmd,
+						      1 /* create */); /* keep reference */
+				if (error)
+					break;
+				if (NETMAP_OWNED_BY_KERN(na)) {
+					error = EBUSY;
+					break;
+				}
 
-				/* get a refcount */
-				error = netmap_get_na(nmr, &na, &ifp, NULL, 1 /* create */);
-				if (error) {
-					na = NULL;
-					ifp = NULL;
+				if (na->virt_hdr_len && !(req->nr_flags & NR_ACCEPT_VNET_HDR)) {
+					error = EIO;
 					break;
 				}
-				nmd = na->nm_mem; /* get memory allocator */
-			} else {
-				nmd = netmap_mem_find(nmr->nr_arg2 ? nmr->nr_arg2 : 1);
-				if (nmd == NULL) {
-					error = EINVAL;
+
+				error = netmap_do_regif(priv, na, req->nr_mode,
+							req->nr_ringid, req->nr_flags);
+				if (error) {    /* reg. failed, release priv and ref */
 					break;
 				}
+				nifp = priv->np_nifp;
+				priv->np_td = td; /* for debugging purposes */
+
+				/* return the offset of the netmap_if object */
+				req->nr_rx_rings = na->num_rx_rings;
+				req->nr_tx_rings = na->num_tx_rings;
+				req->nr_rx_slots = na->num_rx_desc;
+				req->nr_tx_slots = na->num_tx_desc;
+				error = netmap_mem_get_info(na->nm_mem, &req->nr_memsize, &memflags,
+					&req->nr_mem_id);
+				if (error) {
+					netmap_do_unregif(priv);
+					break;
+				}
+				if (memflags & NETMAP_MEM_PRIVATE) {
+					*(uint32_t *)(uintptr_t)&nifp->ni_flags |= NI_PRIV_MEM;
+				}
+				for_rx_tx(t) {
+					priv->np_si[t] = nm_si_user(priv, t) ?
+						&na->si[t] : &NMR(na, t)[priv->np_qfirst[t]].si;
+				}
+
+				if (req->nr_extra_bufs) {
+					if (netmap_verbose)
+						D("requested %d extra buffers",
+							req->nr_extra_bufs);
+					req->nr_extra_bufs = netmap_extra_alloc(na,
+						&nifp->ni_bufs_head, req->nr_extra_bufs);
+					if (netmap_verbose)
+						D("got %d extra buffers", req->nr_extra_bufs);
+				}
+				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
+
+				/* store ifp reference so that priv destructor may release it */
+				priv->np_ifp = ifp;
+			} while (0);
+			if (error) {
+				netmap_unget_na(na, ifp);
 			}
+			/* release the reference from netmap_mem_find() or
+			 * netmap_mem_ext_create()
+			 */
+			if (nmd)
+				netmap_mem_put(nmd);
+			NMG_UNLOCK();
+			break;
+		}
 
-			error = netmap_mem_get_info(nmd, &nmr->nr_memsize, &memflags,
-				&nmr->nr_arg2);
-			if (error)
-				break;
-			if (na == NULL) /* only memory info */
-				break;
-			nmr->nr_offset = 0;
-			nmr->nr_rx_slots = nmr->nr_tx_slots = 0;
-			netmap_update_config(na);
-			nmr->nr_rx_rings = na->num_rx_rings;
-			nmr->nr_tx_rings = na->num_tx_rings;
-			nmr->nr_rx_slots = na->num_rx_desc;
-			nmr->nr_tx_slots = na->num_tx_desc;
-		} while (0);
-		netmap_unget_na(na, ifp);
-		NMG_UNLOCK();
-		break;
+		case NETMAP_REQ_PORT_INFO_GET: {
+			struct nmreq_port_info_get *req =
+				(struct nmreq_port_info_get *)hdr;
 
-	case NIOCREGIF:
-		/*
-		 * If nmr->nr_cmd is not zero, this NIOCREGIF is not really
-		 * a regif operation, but a different one, specified by the
-		 * value of nmr->nr_cmd.
-		 */
-		i = nmr->nr_cmd;
-		if (i == NETMAP_BDG_ATTACH || i == NETMAP_BDG_DETACH
-				|| i == NETMAP_BDG_VNET_HDR
-				|| i == NETMAP_BDG_NEWIF
-				|| i == NETMAP_BDG_DELIF
-				|| i == NETMAP_BDG_POLLING_ON
-				|| i == NETMAP_BDG_POLLING_OFF) {
-			/* possibly attach/detach NIC and VALE switch */
-			error = netmap_bdg_ctl(nmr, NULL);
+			NMG_LOCK();
+			do {
+				u_int memflags;
+
+				if (hdr->nr_name[0] != '\0') {
+					/* Build a nmreq_register out of the nmreq_port_info_get,
+					 * so that we can call netmap_get_na(). */
+					struct nmreq_register regreq;
+					nmreq_register_from_nmreq_header(hdr, ®req);
+					regreq.nr_tx_slots = req->nr_tx_slots;
+					regreq.nr_rx_slots = req->nr_rx_slots;
+					regreq.nr_tx_rings = req->nr_tx_rings;
+					regreq.nr_rx_rings = req->nr_rx_rings;
+					regreq.nr_mem_id = req->nr_mem_id;
+
+					/* get a refcount */
+					error = netmap_get_na(®req, &na, &ifp, NULL, 1 /* create */);
+					if (error) {
+						na = NULL;
+						ifp = NULL;
+						break;
+					}
+					nmd = na->nm_mem; /* get memory allocator */
+				} else {
+					nmd = netmap_mem_find(req->nr_mem_id ? req->nr_mem_id : 1);
+					if (nmd == NULL) {
+						error = EINVAL;
+						break;
+					}
+				}
+
+				error = netmap_mem_get_info(nmd, &req->nr_memsize, &memflags,
+					&req->nr_mem_id);
+				if (error)
+					break;
+				if (na == NULL) /* only memory info */
+					break;
+				req->nr_offset = 0;
+				req->nr_rx_slots = req->nr_tx_slots = 0;
+				netmap_update_config(na);
+				req->nr_rx_rings = na->num_rx_rings;
+				req->nr_tx_rings = na->num_tx_rings;
+				req->nr_rx_slots = na->num_rx_desc;
+				req->nr_tx_slots = na->num_tx_desc;
+			} while (0);
+			netmap_unget_na(na, ifp);
+			NMG_UNLOCK();
+			break;
+		}
+
+		case NETMAP_REQ_VALE_ATTACH: {
+			struct nmreq_vale_attach *req =
+				(struct nmreq_vale_attach *)hdr;
+			error = nm_bdg_ctl_attach(req);
+			break;
+		}
+
+		case NETMAP_REQ_VALE_DETACH: {
+			struct nmreq_vale_detach *req =
+				(struct nmreq_vale_detach *)hdr;
+			error = nm_bdg_ctl_detach(req);
+			break;
+		}
+
+		case NETMAP_REQ_VALE_LIST: {
+			struct nmreq_vale_list *req =
+				(struct nmreq_vale_list *)hdr;
+			error = netmap_bdg_list(req);
 			break;
-		} else if (i == NETMAP_PT_HOST_CREATE || i == NETMAP_PT_HOST_DELETE) {
-			/* forward the command to the ptnetmap subsystem */
-			error = ptnetmap_ctl(nmr, priv->np_na);
+		}
+
+		case NETMAP_REQ_PORT_HDR_SET: {
+			struct nmreq_port_hdr *req =
+				(struct nmreq_port_hdr *)hdr;
+			/* Build a nmreq_register out of the nmreq_port_hdr,
+			 * so that we can call netmap_get_bdg_na(). */
+			struct nmreq_register regreq;
+			nmreq_register_from_nmreq_header(hdr, ®req);
+			/* For now we only support virtio-net headers, and only for
+			 * VALE ports, but this may change in future. Valid lengths
+			 * for the virtio-net header are 0 (no header), 10 and 12. */
+			if (req->nr_hdr_len != 0 &&
+				req->nr_hdr_len != sizeof(struct nm_vnet_hdr) &&
+					req->nr_hdr_len != 12) {
+				error = EINVAL;
+				break;
+			}
+			NMG_LOCK();
+			error = netmap_get_bdg_na((struct nmreq_header *)®req,
+							&na, NULL, 0);
+			if (na && !error) {
+				struct netmap_vp_adapter *vpna =
+					(struct netmap_vp_adapter *)na;
+				na->virt_hdr_len = req->nr_hdr_len;
+				if (na->virt_hdr_len) {
+					vpna->mfs = NETMAP_BUF_SIZE(na);
+				}
+				D("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
+				netmap_adapter_put(na);
+			} else if (!na) {
+				error = ENXIO;
+			}
+			NMG_UNLOCK();
 			break;
-		} else if (i == NETMAP_VNET_HDR_GET) {
-			/* get vnet-header length for this netmap port */
+		}
+
+		case NETMAP_REQ_PORT_HDR_GET: {
+			/* Get vnet-header length for this netmap port */
+			struct nmreq_port_hdr *req =
+				(struct nmreq_port_hdr *)hdr;
+			/* Build a nmreq_register out of the nmreq_port_hdr,
+			 * so that we can call netmap_get_bdg_na(). */
+			struct nmreq_register regreq;
 			struct ifnet *ifp;
+			nmreq_register_from_nmreq_header(hdr, ®req);
 
 			NMG_LOCK();
-			error = netmap_get_na(nmr, &na, &ifp, NULL, 0);
+			error = netmap_get_na(®req, &na, &ifp, NULL, 0);
 			if (na && !error) {
-				nmr->nr_arg1 = na->virt_hdr_len;
+				req->nr_hdr_len = na->virt_hdr_len;
 			}
 			netmap_unget_na(na, ifp);
 			NMG_UNLOCK();
 			break;
-		} else if (i == NETMAP_POOLS_INFO_GET) {
-			/* get information from the memory allocator */
+		}
+
+		case NETMAP_REQ_VALE_NEWIF: {
+			struct nmreq_vale_newif *req =
+				(struct nmreq_vale_newif *)hdr;
+			/* Build a nmreq_register out of the nmreq_vale_newif,
+			 * so that we can call netmap_get_bdg_na(). */
+			struct nmreq_register regreq;
+			nmreq_register_from_nmreq_header(hdr, ®req);
+			regreq.nr_tx_slots = req->nr_tx_slots;
+			regreq.nr_rx_slots = req->nr_rx_slots;
+			regreq.nr_tx_rings = req->nr_tx_rings;
+			regreq.nr_rx_rings = req->nr_rx_rings;
+			regreq.nr_mem_id = req->nr_mem_id;
+			error = netmap_vi_create(®req, 0 /* no autodelete */);
+                        /* Write back to the original struct. */
+			req->nr_tx_slots = regreq.nr_tx_slots;
+			req->nr_rx_slots = regreq.nr_rx_slots;
+			req->nr_tx_rings = regreq.nr_tx_rings;
+			req->nr_rx_rings = regreq.nr_rx_rings;
+			req->nr_mem_id = regreq.nr_mem_id;
+			break;
+		}
+
+		case NETMAP_REQ_VALE_DELIF: {
+			struct nmreq_vale_delif *req =
+				(struct nmreq_vale_delif *)hdr;
+			error = nm_vi_destroy(req->nr_hdr.nr_name);
+			break;
+		}
+
+		case NETMAP_REQ_VALE_POLLING_ENABLE:
+		case NETMAP_REQ_VALE_POLLING_DISABLE: {
+			struct nmreq_vale_polling *req =
+				(struct nmreq_vale_polling *)hdr;
+			error = nm_bdg_polling(req);
+			break;
+		}
+
+		case NETMAP_REQ_POOLS_INFO_GET: {
+			struct nmreq_pools_info_get *req =
+				(struct nmreq_pools_info_get *)hdr;
+			/* Get information from the memory allocator */
 			NMG_LOCK();
 			if (priv->np_na && priv->np_na->nm_mem) {
 				struct netmap_mem_d *nmd = priv->np_na->nm_mem;
-				error = netmap_mem_pools_info_get(nmr, nmd);
+				error = netmap_mem_pools_info_get(req, nmd);
 			} else {
 				error = EINVAL;
 			}
 			NMG_UNLOCK();
 			break;
-		} else if (i != 0) {
-			D("nr_cmd must be 0 not %d", i);
-			error = EINVAL;
-			break;
 		}
 
-		/* protect access to priv from concurrent NIOCREGIF */
-		NMG_LOCK();
-		do {
-			u_int memflags;
-
-			if (priv->np_nifp != NULL) {	/* thread already registered */
-				error = EBUSY;
-				break;
-			}
-
-			if (nmr->nr_arg2) {
-				/* find the allocator and get a reference */
-				nmd = netmap_mem_find(nmr->nr_arg2);
-				if (nmd == NULL) {
-					error = EINVAL;
-					break;
-				}
-			}
-			/* find the interface and a reference */
-			error = netmap_get_na(nmr, &na, &ifp, nmd,
-					      1 /* create */); /* keep reference */
-			if (error)
-				break;
-			if (NETMAP_OWNED_BY_KERN(na)) {
-				error = EBUSY;
-				break;
-			}
-
-			if (na->virt_hdr_len && !(nmr->nr_flags & NR_ACCEPT_VNET_HDR)) {
-				error = EIO;
-				break;
-			}
-
-			error = netmap_do_regif(priv, na, nmr->nr_ringid, nmr->nr_flags);
-			if (error) {    /* reg. failed, release priv and ref */
-				break;
-			}
-			nifp = priv->np_nifp;
-			priv->np_td = td; // XXX kqueue, debugging only
-
-			/* return the offset of the netmap_if object */
-			nmr->nr_rx_rings = na->num_rx_rings;
-			nmr->nr_tx_rings = na->num_tx_rings;
-			nmr->nr_rx_slots = na->num_rx_desc;
-			nmr->nr_tx_slots = na->num_tx_desc;
-			error = netmap_mem_get_info(na->nm_mem, &nmr->nr_memsize, &memflags,
-				&nmr->nr_arg2);
-			if (error) {
-				netmap_do_unregif(priv);
-				break;
-			}
-			if (memflags & NETMAP_MEM_PRIVATE) {
-				*(uint32_t *)(uintptr_t)&nifp->ni_flags |= NI_PRIV_MEM;
-			}
-			for_rx_tx(t) {
-				priv->np_si[t] = nm_si_user(priv, t) ?
-					&na->si[t] : &NMR(na, t)[priv->np_qfirst[t]].si;
-			}
-
-			if (nmr->nr_arg3) {
-				if (netmap_verbose)
-					D("requested %d extra buffers", nmr->nr_arg3);
-				nmr->nr_arg3 = netmap_extra_alloc(na,
-					&nifp->ni_bufs_head, nmr->nr_arg3);
-				if (netmap_verbose)
-					D("got %d extra buffers", nmr->nr_arg3);
-			}
-			nmr->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
+		default: {
+			return EINVAL;
+			break;
+		}
+		}
+		break;
+	}
 
-			/* store ifp reference so that priv destructor may release it */
-			priv->np_ifp = ifp;
-		} while (0);
-		if (error) {
-			netmap_unget_na(na, ifp);
+	case NIOCGINFO:
+	case NIOCREGIF: {
+		/* Request for the legacy control API. Convert it to a
+		 * NIOCCTRL request. */
+		struct nmreq *nmr = (struct nmreq *) data;
+		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
+		if (hdr == NULL) { /* out of memory */
+			return ENOMEM;
 		}
-		/* release the reference from netmap_mem_find() or
-		 * netmap_mem_ext_create()
-		 */
-		if (nmd)
-			netmap_mem_put(nmd);
-		NMG_UNLOCK();
+		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
+		if (error == 0) {
+			nmreq_to_legacy(hdr, nmr);
+		}
+		nm_os_free(hdr);
 		break;
+	}
 
 	case NIOCTXSYNC:
 	case NIOCRXSYNC:
@@ -2838,9 +2957,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		break;
 
 #ifdef WITH_VALE
-	case NIOCCONFIG:
-		error = netmap_bdg_config(nmr);
+	case NIOCCONFIG: {
+		struct nm_ifreq *nr = (struct nm_ifreq *)data;
+		error = netmap_bdg_config(nr);
 		break;
+	}
 #endif
 #ifdef __FreeBSD__
 	case FIONBIO:
@@ -2857,6 +2978,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 
 	default:	/* allow device-specific ioctls */
 	    {
+		struct nmreq *nmr = (struct nmreq *)data;
 		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
 		if (ifp == NULL) {
 			error = ENXIO;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 257d9654a..421f9c417 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1005,11 +1005,16 @@ struct netmap_bwrap_adapter {
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
 };
+int nm_bdg_ctl_attach(struct nmreq_vale_attach *req);
+int nm_bdg_ctl_detach(struct nmreq_vale_detach *req);
+int nm_bdg_polling(struct nmreq_vale_polling *req);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
-int netmap_vi_create(struct nmreq *, int);
+int netmap_vi_create(struct nmreq_register *, int);
+int nm_vi_destroy(const char *name);
+int netmap_bdg_list(struct nmreq_vale_list *req);
 
 #else /* !WITH_VALE */
-#define netmap_vi_create(nmr, a) (EOPNOTSUPP)
+#define netmap_vi_create(req, a) (EOPNOTSUPP)
 #endif /* WITH_VALE */
 
 #ifdef WITH_PIPES
@@ -1366,9 +1371,10 @@ uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *);
  */
 int netmap_attach_common(struct netmap_adapter *);
 /* fill priv->np_[tr]xq{first,last} using the ringid and flags information
- * coming from a struct nmreq
+ * coming from a struct nmreq_register
  */
-int netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags);
+int netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
+			uint16_t nr_ringid, uint64_t nr_flags);
 /* update the ring parameters (number and size of tx and rx rings).
  * It calls the nm_config callback, if available.
  */
@@ -1402,11 +1408,11 @@ void netmap_disable_all_rings(struct ifnet *);
 void netmap_enable_all_rings(struct ifnet *);
 
 int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
-	uint16_t ringid, uint32_t flags);
+		uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags);
 void netmap_do_unregif(struct netmap_priv_d *priv);
 
 u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
-int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
+int netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 		  struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
 void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
@@ -1442,27 +1448,27 @@ u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 #define	NM_BDG_NOPORT		(NM_BDG_MAXPORTS+1)
 
 /* these are redefined in case of no VALE support */
-int netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
+int netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create);
 struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops);
-int netmap_bdg_config(struct nmreq *nmr);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops);
+int netmap_bdg_config(struct nm_ifreq *nifr);
 
 #else /* !WITH_VALE */
 #define	netmap_get_bdg_na(_1, _2, _3, _4)	0
 #define netmap_init_bridges(_1) 0
 #define netmap_uninit_bridges()
-#define	netmap_bdg_ctl(_1, _2)	EINVAL
+#define	netmap_bdg_regops(_1, _2)	EINVAL
 #endif /* !WITH_VALE */
 
 #ifdef WITH_PIPES
 /* max number of pipes per device */
 #define NM_MAXPIPES	64	/* XXX this should probably be a sysctl */
 void netmap_pipe_dealloc(struct netmap_adapter *);
-int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
+int netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create);
 #else /* !WITH_PIPES */
 #define NM_MAXPIPES	0
@@ -1475,8 +1481,9 @@ int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 #endif
 
 #ifdef WITH_MONITOR
-int netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create);
+int netmap_get_monitor_na(struct nmreq_register *req,
+		struct netmap_adapter **na, struct netmap_mem_d *nmd,
+		int create);
 void netmap_monitor_stop(struct netmap_adapter *na);
 #else
 #define netmap_get_monitor_na(nmr, _2, _3, _4) \
@@ -2113,10 +2120,13 @@ struct netmap_pt_host_adapter {
 	int (*parent_nm_notify)(struct netmap_kring *kring, int flags);
 	void *ptns;
 };
-/* ptnetmap HOST routines */
-int netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
-		struct netmap_mem_d * nmd, int create);
-int ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na);
+
+/* ptnetmap host-side routines */
+int netmap_get_pt_host_na(struct nmreq_register *req,
+		struct netmap_adapter **na, struct netmap_mem_d * nmd,
+		int create);
+int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
+
 static inline int
 nm_ptnetmap_host_on(struct netmap_adapter *na)
 {
@@ -2125,7 +2135,7 @@ nm_ptnetmap_host_on(struct netmap_adapter *na)
 #else /* !WITH_PTNETMAP_HOST */
 #define netmap_get_pt_host_na(nmr, _2, _3, _4) \
 	((nmr)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
-#define ptnetmap_ctl(_1, _2)   EINVAL
+#define ptnetmap_ctl(_1, _2, _3)   EINVAL
 #define nm_ptnetmap_host_on(_1)   EINVAL
 #endif /* !WITH_PTNETMAP_HOST */
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1d8aa65f2..f05bfb96c 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -132,7 +132,7 @@ struct netmap_obj_pool {
 
 struct netmap_mem_ops {
 	int (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*);
-	int  (*nmd_get_info)(struct netmap_mem_d *, u_int *size,
+	int  (*nmd_get_info)(struct netmap_mem_d *, uint64_t *size,
 			u_int *memflags, uint16_t *id);
 
 	vm_paddr_t (*nmd_ofstophys)(struct netmap_mem_d *, vm_ooffset_t);
@@ -215,7 +215,7 @@ netmap_mem_##name(struct netmap_adapter *na, t1 a1) \
 }
 
 NMD_DEFCB1(int, get_lut, struct netmap_lut *);
-NMD_DEFCB3(int, get_info, u_int *, u_int *, uint16_t *);
+NMD_DEFCB3(int, get_info, uint64_t *, u_int *, uint16_t *);
 NMD_DEFCB1(vm_paddr_t, ofstophys, vm_ooffset_t);
 static int netmap_mem_config(struct netmap_mem_d *);
 NMD_DEFCB(int, config);
@@ -763,9 +763,10 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 PMDL
 win32_build_user_vm_map(struct netmap_mem_d* nmd)
 {
-	int i, j;
-	u_int memsize, memflags, ofs = 0;
+	u_int memflags, ofs = 0;
 	PMDL mainMdl, tempMdl;
+	uint64_t memsize;
+	int i, j;
 
 	if (netmap_mem_get_info(nmd, &memsize, &memflags, NULL)) {
 		D("memory not finalised yet");
@@ -834,8 +835,8 @@ netmap_mem2_get_pool_info(struct netmap_mem_d* nmd, u_int pool, u_int *clustsize
 }
 
 static int
-netmap_mem2_get_info(struct netmap_mem_d* nmd, u_int* size, u_int *memflags,
-	nm_memid_t *id)
+netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size,
+			u_int *memflags, nm_memid_t *id)
 {
 	int error = 0;
 	NMA_LOCK(nmd);
@@ -1981,42 +1982,32 @@ struct netmap_mem_ops netmap_mem_global_ops = {
 };
 
 int
-netmap_mem_pools_info_get(struct nmreq *nmr, struct netmap_mem_d *nmd)
+netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
+				struct netmap_mem_d *nmd)
 {
-	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-	struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
-	struct netmap_pools_info pi;
-	unsigned int memsize;
-	uint16_t memid;
 	int ret;
 
-	ret = netmap_mem_get_info(nmd, &memsize, NULL, &memid);
+	ret = netmap_mem_get_info(nmd, &req->nr_memsize, NULL,
+					&req->nr_mem_id);
 	if (ret) {
 		return ret;
 	}
 
-	pi.memsize = memsize;
-	pi.memid = memid;
 	NMA_LOCK(nmd);
-	pi.if_pool_offset = 0;
-	pi.if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal;
-	pi.if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize;
+	req->nr_if_pool_offset = 0;
+	req->nr_if_pool_objtotal = nmd->pools[NETMAP_IF_POOL].objtotal;
+	req->nr_if_pool_objsize = nmd->pools[NETMAP_IF_POOL]._objsize;
 
-	pi.ring_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal;
-	pi.ring_pool_objtotal = nmd->pools[NETMAP_RING_POOL].objtotal;
-	pi.ring_pool_objsize = nmd->pools[NETMAP_RING_POOL]._objsize;
+	req->nr_ring_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal;
+	req->nr_ring_pool_objtotal = nmd->pools[NETMAP_RING_POOL].objtotal;
+	req->nr_ring_pool_objsize = nmd->pools[NETMAP_RING_POOL]._objsize;
 
-	pi.buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal +
+	req->nr_buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal +
 			     nmd->pools[NETMAP_RING_POOL].memtotal;
-	pi.buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal;
-	pi.buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize;
+	req->nr_buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal;
+	req->nr_buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize;
 	NMA_UNLOCK(nmd);
 
-	ret = copyout(&pi, upi, sizeof(pi));
-	if (ret) {
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -2130,7 +2121,7 @@ netmap_mem_pt_guest_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut)
 }
 
 static int
-netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, u_int *size,
+netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, uint64_t *size,
 			     u_int *memflags, uint16_t *id)
 {
 	int error = 0;
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 4daedbe61..1467a60e7 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -135,8 +135,9 @@ void 	   netmap_mem_if_delete(struct netmap_adapter *, struct netmap_if *);
 int	   netmap_mem_rings_create(struct netmap_adapter *);
 void	   netmap_mem_rings_delete(struct netmap_adapter *);
 int 	   netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *);
-int	netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
-int	   netmap_mem_get_info(struct netmap_mem_d *, u_int *size, u_int *memflags, uint16_t *id);
+int	   netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
+int	   netmap_mem_get_info(struct netmap_mem_d *, uint64_t *size,
+				u_int *memflags, uint16_t *id);
 ssize_t    netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr);
 struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_int rxd,
 		u_int extra_bufs, u_int npipes, int* error);
@@ -158,7 +159,8 @@ struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16
 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
 #endif /* WITH_PTNETMAP_GUEST */
 
-int netmap_mem_pools_info_get(struct nmreq *, struct netmap_mem_d *);
+int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
+				struct netmap_mem_d *);
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
 #define NETMAP_MEM_IO		0x4	/* the underlying memory is mmapped I/O */
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index e1c63b21c..e6ccfa495 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -824,38 +824,38 @@ netmap_monitor_dtor(struct netmap_adapter *na)
 }
 
 
-/* check if nmr is a request for a monitor adapter that we can satisfy */
+/* check if req is a request for a monitor adapter that we can satisfy */
 int
-netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_monitor_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq pnmr;
+	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_monitor_adapter *mna;
 	struct ifnet *ifp = NULL;
 	int  error;
-	int zcopy = (nmr->nr_flags & NR_ZCOPY_MON);
+	int zcopy = (req->nr_flags & NR_ZCOPY_MON);
 	char monsuff[10] = "";
 
 	if (zcopy) {
-		nmr->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
+		req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
 	}
-	if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
+	if ((req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
 		ND("not a monitor");
 		return 0;
 	}
 	/* this is a request for a monitor adapter */
 
-	ND("flags %x", nmr->nr_flags);
+	ND("flags %x", req->nr_flags);
 
 	/* first, try to find the adapter that we want to monitor
-	 * We use the same nmr, after we have turned off the monitor flags.
+	 * We use the same req, after we have turned off the monitor flags.
 	 * In this way we can potentially monitor everything netmap understands,
 	 * except other monitors.
 	 */
-	memcpy(&pnmr, nmr, sizeof(pnmr));
-	pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
+	memcpy(&preq, req, sizeof(preq));
+	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
+	error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;
@@ -881,7 +881,8 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	mna->priv.np_na = pna;
 
 	/* grab all the rings we need in the parent */
-	error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags);
+	error = netmap_interp_ringid(&mna->priv, req->nr_mode, req->nr_ringid,
+					req->nr_flags);
 	if (error) {
 		D("ringid error");
 		goto free_out;
@@ -892,8 +893,8 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name,
 			monsuff,
 			zcopy ? "z" : "",
-			(nmr->nr_flags & NR_MONITOR_RX) ? "r" : "",
-			(nmr->nr_flags & NR_MONITOR_TX) ? "t" : "");
+			(req->nr_flags & NR_MONITOR_RX) ? "r" : "",
+			(req->nr_flags & NR_MONITOR_TX) ? "t" : "");
 
 	/* the monitor supports the host rings iff the parent does */
 	mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS);
@@ -913,10 +914,10 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	 * the parent rings, but the user may ask for a different
 	 * number
 	 */
-	mna->up.num_tx_desc = nmr->nr_tx_slots;
+	mna->up.num_tx_desc = req->nr_tx_slots;
 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
 			1, NM_MONITOR_MAXSLOTS, NULL);
-	mna->up.num_rx_desc = nmr->nr_rx_slots;
+	mna->up.num_rx_desc = req->nr_rx_slots;
 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
 			1, NM_MONITOR_MAXSLOTS, NULL);
 	if (zcopy) {
@@ -950,7 +951,7 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
 	}
 
 	/* remember the traffic directions we have to monitor */
-	mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON));
+	mna->flags = (req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON));
 
 	*na = &mna->up;
 	netmap_adapter_get(*na);
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 3b936d96f..7c3c624f9 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -527,34 +527,34 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 }
 
 int
-netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq pnmr;
+	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
-	struct netmap_pipe_adapter *mna, *sna, *req;
+	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
 	u_int pipe_id;
-	int role = nmr->nr_flags & NR_REG_MASK;
+	int role = req->nr_flags;
 	int error, retries = 0;
 
-	ND("flags %x", nmr->nr_flags);
+	ND("flags %x", req->nr_flags);
 
 	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
 		ND("not a pipe");
 		return 0;
 	}
-	role = nmr->nr_flags & NR_REG_MASK;
 
 	/* first, try to find the parent adapter */
-	bzero(&pnmr, sizeof(pnmr));
-	memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ);
+	bzero(&preq, sizeof(preq));
+	memcpy(&preq.nr_hdr.nr_name, req->nr_hdr.nr_name,
+		sizeof(preq.nr_hdr.nr_name));
 	/* pass to parent the requested number of pipes */
-	pnmr.nr_arg1 = nmr->nr_arg1;
+	preq.nr_pipes = req->nr_pipes;
 	for (;;) {
 		int create_error;
 
-		error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
+		error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -564,7 +564,7 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 		ND("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
 		NMG_UNLOCK();
-		create_error = netmap_vi_create(&pnmr, 1 /* autodelete */);
+		create_error = netmap_vi_create(&preq, 1 /* autodelete */);
 		NMG_LOCK();
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
@@ -581,16 +581,16 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 	}
 
 	/* next, lookup the pipe id in the parent list */
-	req = NULL;
-	pipe_id = nmr->nr_ringid & NETMAP_RING_MASK;
+	reqna = NULL;
+	pipe_id = req->nr_ringid;
 	mna = netmap_pipe_find(pna, pipe_id);
 	if (mna) {
 		if (mna->role == role) {
 			ND("found %d directly at %d", pipe_id, mna->parent_slot);
-			req = mna;
+			reqna = mna;
 		} else {
 			ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
-			req = mna->peer;
+			reqna = mna->peer;
 		}
 		/* the pipe we have found already holds a ref to the parent,
                  * so we need to drop the one we got from netmap_get_na()
@@ -631,10 +631,10 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 
 	mna->up.num_tx_rings = 1;
 	mna->up.num_rx_rings = 1;
-	mna->up.num_tx_desc = nmr->nr_tx_slots;
+	mna->up.num_tx_desc = req->nr_tx_slots;
 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
 			1, NM_PIPE_MAXSLOTS, NULL);
-	mna->up.num_rx_desc = nmr->nr_rx_slots;
+	mna->up.num_rx_desc = req->nr_rx_slots;
 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
 			1, NM_PIPE_MAXSLOTS, NULL);
 	error = netmap_attach_common(&mna->up);
@@ -673,11 +673,11 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 		if_ref(ifp);
 
 	if (role == NR_REG_PIPE_MASTER) {
-		req = mna;
+		reqna = mna;
 		mna->peer_ref = 1;
 		netmap_adapter_get(&sna->up);
 	} else {
-		req = sna;
+		reqna = sna;
 		sna->peer_ref = 1;
 		netmap_adapter_get(&mna->up);
 	}
@@ -685,8 +685,8 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
 found:
 
 	ND("pipe %d %s at %p", pipe_id,
-		(req->role == NR_REG_PIPE_MASTER ? "master" : "slave"), req);
-	*na = &req->up;
+		(reqna->role == NR_REG_PIPE_MASTER ? "master" : "slave"), reqna);
+	*na = &reqna->up;
 	netmap_adapter_get(*na);
 
 	/* keep the reference to the parent.
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index edb49dc50..df2553d44 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -761,34 +761,6 @@ ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
 	}
 }
 
-static struct ptnetmap_cfg *
-ptnetmap_read_cfg(struct nmreq *nmr)
-{
-	uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1;
-	struct ptnetmap_cfg *cfg;
-	struct ptnetmap_cfg tmp;
-	size_t cfglen;
-
-	if (copyin((const void *)*nmr_ptncfg, &tmp, sizeof(tmp))) {
-		D("Partial copyin() failed");
-		return NULL;
-	}
-
-	cfglen = sizeof(tmp) + tmp.num_rings * tmp.entry_size;
-	cfg = nm_os_malloc(cfglen);
-	if (!cfg) {
-		return NULL;
-	}
-
-	if (copyin((const void *)*nmr_ptncfg, cfg, cfglen)) {
-		D("Full copyin() failed");
-		nm_os_free(cfg);
-		return NULL;
-	}
-
-	return cfg;
-}
-
 static int nm_unused_notify(struct netmap_kring *, int);
 static int nm_pt_host_notify(struct netmap_kring *, int);
 
@@ -941,66 +913,55 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
 
 /*
  * Called by netmap_ioctl().
- * Operation is indicated in nmr->nr_cmd.
+ * Operation is indicated in nr_name.
  *
  * Called without NMG_LOCK.
  */
 int
-ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na)
+ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na)
 {
-    struct netmap_pt_host_adapter *pth_na;
-    struct ptnetmap_cfg *cfg;
-    char *name;
-    int cmd, error = 0;
-
-    name = nmr->nr_name;
-    cmd = nmr->nr_cmd;
+	struct netmap_pt_host_adapter *pth_na;
+	struct ptnetmap_cfg *cfg = NULL;
+	int error = 0;
 
-    DBG(D("name: %s", name));
+	DBG(D("name: %s", nr_name));
 
-    if (!nm_ptnetmap_host_on(na)) {
-        D("ERROR Netmap adapter %p is not a ptnetmap host adapter", na);
-        error = ENXIO;
-        goto done;
-    }
-    pth_na = (struct netmap_pt_host_adapter *)na;
-
-    NMG_LOCK();
-    switch (cmd) {
-    case NETMAP_PT_HOST_CREATE:
-	/* Read hypervisor configuration from userspace. */
-        cfg = ptnetmap_read_cfg(nmr);
-        if (!cfg)
-            break;
-        /* Create ptnetmap state (kctxs, ...) and switch parent
-	 * adapter to ptnetmap mode. */
-        error = ptnetmap_create(pth_na, cfg);
-	nm_os_free(cfg);
-        if (error)
-            break;
-        /* Start kthreads. */
-        error = ptnetmap_start_kctx_workers(pth_na);
-        if (error)
-            ptnetmap_delete(pth_na);
-        break;
-
-    case NETMAP_PT_HOST_DELETE:
-        /* Stop kthreads. */
-        ptnetmap_stop_kctx_workers(pth_na);
-        /* Switch parent adapter back to normal mode and destroy
-	 * ptnetmap state (kthreads, ...). */
-        ptnetmap_delete(pth_na);
-        break;
-
-    default:
-        D("ERROR invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
-        error = EINVAL;
-        break;
-    }
-    NMG_UNLOCK();
+	if (!nm_ptnetmap_host_on(na)) {
+		D("ERROR Netmap adapter %p is not a ptnetmap host adapter",
+			na);
+		return ENXIO;
+	}
+	pth_na = (struct netmap_pt_host_adapter *)na;
+
+	NMG_LOCK();
+	if (create) {
+		/* Read hypervisor configuration from userspace. */
+		/* TODO */
+		if (!cfg) {
+			goto out;
+		}
+		/* Create ptnetmap state (kctxs, ...) and switch parent
+		 * adapter to ptnetmap mode. */
+		error = ptnetmap_create(pth_na, cfg);
+		nm_os_free(cfg);
+		if (error) {
+			goto out;
+		}
+		/* Start kthreads. */
+		error = ptnetmap_start_kctx_workers(pth_na);
+		if (error)
+			ptnetmap_delete(pth_na);
+	} else {
+		/* Stop kthreads. */
+		ptnetmap_stop_kctx_workers(pth_na);
+		/* Switch parent adapter back to normal mode and destroy
+		 * ptnetmap state (kthreads, ...). */
+		ptnetmap_delete(pth_na);
+	}
+out:
+	NMG_UNLOCK();
 
-done:
-    return error;
+	return error;
 }
 
 /* nm_notify callbacks for ptnetmap */
@@ -1187,17 +1148,17 @@ nm_pt_host_dtor(struct netmap_adapter *na)
 
 /* check if nmr is a request for a ptnetmap adapter that we can satisfy */
 int
-netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_pt_host_na(struct nmreq_register *req, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-    struct nmreq parent_nmr;
+    struct nmreq_register preq;
     struct netmap_adapter *parent; /* target adapter */
     struct netmap_pt_host_adapter *pth_na;
     struct ifnet *ifp = NULL;
     int error;
 
     /* Check if it is a request for a ptnetmap adapter */
-    if ((nmr->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
+    if ((req->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
         return 0;
     }
 
@@ -1210,12 +1171,12 @@ netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
     }
 
     /* first, try to find the adapter that we want to passthrough
-     * We use the same nmr, after we have turned off the ptnetmap flag.
+     * We use the same req, after we have turned off the ptnetmap flag.
      * In this way we can potentially passthrough everything netmap understands.
      */
-    memcpy(&parent_nmr, nmr, sizeof(parent_nmr));
-    parent_nmr.nr_flags &= ~(NR_PTNETMAP_HOST);
-    error = netmap_get_na(&parent_nmr, &parent, &ifp, nmd, create);
+    memcpy(&preq, req, sizeof(preq));
+    preq.nr_flags &= ~(NR_PTNETMAP_HOST);
+    error = netmap_get_na(&preq, &parent, &ifp, nmd, create);
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index aaee3667b..8529afb9a 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -164,7 +164,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
     "Max batch size to be used in the bridge");
 SYSEND;
 
-static int netmap_vp_create(struct nmreq *, struct ifnet *,
+static int netmap_vp_create(struct nmreq_register *, struct ifnet *,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
 static int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 static int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
@@ -213,15 +213,14 @@ struct nm_bridge {
 
 	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
 
-
 	/*
-	 * The function to decide the destination port.
+	 * Programmable lookup functions to figure out the destination port.
 	 * It returns either of an index of the destination port,
 	 * NM_BDG_BROADCAST to broadcast this packet, or NM_BDG_NOPORT not to
 	 * forward this packet.  ring_nr is the source ring index, and the
 	 * function may overwrite this value to forward this packet to a
 	 * different ring index.
-	 * This function must be set by netmap_bdg_ctl().
+	 * The function is set by netmap_bdg_regops().
 	 */
 	struct netmap_bdg_ops bdg_ops;
 
@@ -558,7 +557,7 @@ netmap_vp_dtor(struct netmap_adapter *na)
 }
 
 /* remove a persistent VALE port from the system */
-static int
+int
 nm_vi_destroy(const char *name)
 {
 	struct ifnet *ifp;
@@ -608,13 +607,14 @@ nm_vi_destroy(const char *name)
 }
 
 static int
-nm_update_info(struct nmreq *nmr, struct netmap_adapter *na)
+nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
 {
-	nmr->nr_rx_rings = na->num_rx_rings;
-	nmr->nr_tx_rings = na->num_tx_rings;
-	nmr->nr_rx_slots = na->num_rx_desc;
-	nmr->nr_tx_slots = na->num_tx_desc;
-	return netmap_mem_get_info(na->nm_mem, &nmr->nr_memsize, NULL, &nmr->nr_arg2);
+	req->nr_rx_rings = na->num_rx_rings;
+	req->nr_tx_rings = na->num_tx_rings;
+	req->nr_rx_slots = na->num_rx_desc;
+	req->nr_tx_slots = na->num_tx_desc;
+	return netmap_mem_get_info(na->nm_mem, &req->nr_memsize, NULL,
+					&req->nr_mem_id);
 }
 
 /*
@@ -622,7 +622,7 @@ nm_update_info(struct nmreq *nmr, struct netmap_adapter *na)
  * The interface will be attached to a bridge later.
  */
 int
-netmap_vi_create(struct nmreq *nmr, int autodelete)
+netmap_vi_create(struct nmreq_register *req, int autodelete)
 {
 	struct ifnet *ifp;
 	struct netmap_vp_adapter *vpna;
@@ -630,14 +630,14 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
 	int error;
 
 	/* don't include VALE prefix */
-	if (!strncmp(nmr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
+	if (!strncmp(req->nr_hdr.nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
 		return EINVAL;
-	ifp = ifunit_ref(nmr->nr_name);
+	ifp = ifunit_ref(req->nr_hdr.nr_name);
 	if (ifp) { /* already exist, cannot create new one */
 		error = EEXIST;
 		NMG_LOCK();
 		if (NM_NA_VALID(ifp)) {
-			int update_err = nm_update_info(nmr, NA(ifp));
+			int update_err = nm_update_info(req, NA(ifp));
 			if (update_err)
 				error = update_err;
 		}
@@ -645,20 +645,20 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
 		if_rele(ifp);
 		return error;
 	}
-	error = nm_os_vi_persist(nmr->nr_name, &ifp);
+	error = nm_os_vi_persist(req->nr_hdr.nr_name, &ifp);
 	if (error)
 		return error;
 
 	NMG_LOCK();
-	if (nmr->nr_arg2) {
-		nmd = netmap_mem_find(nmr->nr_arg2);
+	if (req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
 		if (nmd == NULL) {
 			error = EINVAL;
 			goto err_1;
 		}
 	}
 	/* netmap_vp_create creates a struct netmap_vp_adapter */
-	error = netmap_vp_create(nmr, ifp, nmd, &vpna);
+	error = netmap_vp_create(req, ifp, nmd, &vpna);
 	if (error) {
 		D("error %d", error);
 		goto err_1;
@@ -672,11 +672,11 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
 	}
 	NM_ATTACH_NA(ifp, &vpna->up);
 	/* return the updated info */
-	error = nm_update_info(nmr, &vpna->up);
+	error = nm_update_info(req, &vpna->up);
 	if (error) {
 		goto err_2;
 	}
-	D("returning nr_arg2 %d", nmr->nr_arg2);
+	D("returning nr_mem_id %d", req->nr_mem_id);
 	if (nmd)
 		netmap_mem_put(nmd);
 	NMG_UNLOCK();
@@ -704,10 +704,10 @@ netmap_vi_create(struct nmreq *nmr, int autodelete)
  * (*na != NULL && return == 0).
  */
 int
-netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
+netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	char *nr_name = nmr->nr_name;
+	char *nr_name = hdr->nr_name;
 	const char *ifname;
 	struct ifnet *ifp = NULL;
 	int error = 0;
@@ -776,14 +776,15 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 		/* Create an ephemeral virtual port
 		 * This block contains all the ephemeral-specific logics
 		 */
-		if (nmr->nr_cmd) {
-			/* nr_cmd must be 0 for a virtual port */
+
+		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
 			error = EINVAL;
 			goto out;
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = netmap_vp_create(nmr, NULL, nmd, &vpna);
+		error = netmap_vp_create((struct nmreq_register *)hdr,
+					NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -795,11 +796,11 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 		struct netmap_adapter *hw;
 
 		/* the vale:nic syntax is only valid for some commands */
-		switch (nmr->nr_cmd) {
-		case NETMAP_BDG_ATTACH:
-		case NETMAP_BDG_DETACH:
-		case NETMAP_BDG_POLLING_ON:
-		case NETMAP_BDG_POLLING_OFF:
+		switch (hdr->nr_reqtype) {
+		case NETMAP_REQ_VALE_ATTACH:
+		case NETMAP_REQ_VALE_DETACH:
+		case NETMAP_REQ_VALE_POLLING_ENABLE:
+		case NETMAP_REQ_VALE_POLLING_DISABLE:
 			break; /* ok */
 		default:
 			error = EINVAL;
@@ -816,8 +817,14 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 			goto out;
 		vpna = hw->na_vp;
 		hostna = hw->na_hostvp;
-		if (nmr->nr_arg1 != NETMAP_BDG_HOST)
-			hostna = NULL;
+		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+			/* Check if we need to skip the host rings. */
+			struct nmreq_vale_attach *areq =
+				(struct nmreq_vale_attach *)hdr;
+			if ((areq->nr_flags & NETMAP_BDG_HOST) == 0) {
+				hostna = NULL;
+			}
+		}
 	}
 
 	BDG_WLOCK(b);
@@ -848,9 +855,9 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
 }
 
 
-/* Process NETMAP_BDG_ATTACH */
-static int
-nm_bdg_ctl_attach(struct nmreq *nmr)
+/* Process NETMAP_REQ_VALE_ATTACH. */
+int
+nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 {
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
@@ -858,21 +865,22 @@ nm_bdg_ctl_attach(struct nmreq *nmr)
 
 	NMG_LOCK();
 
-	if (nmr->nr_arg2) {
-		nmd = netmap_mem_find(nmr->nr_arg2);
+	if (req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
 		if (nmd == NULL) {
 			error = EINVAL;
 			goto unlock_exit;
 		}
 	}
 
-	/* XXX check existing one */
-	error = netmap_get_bdg_na(nmr, &na, nmd, 0);
+	/* check for existing one */
+	error = netmap_get_bdg_na((struct nmreq_header *)req, &na, nmd, 0);
 	if (!error) {
 		error = EBUSY;
 		goto unref_exit;
 	}
-	error = netmap_get_bdg_na(nmr, &na, nmd, 1 /* create if not exists */);
+	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
+				nmd, 1 /* create if not exists */);
 	if (error) /* no device */
 		goto unlock_exit;
 
@@ -911,15 +919,16 @@ nm_is_bwrap(struct netmap_adapter *na)
 	return na->nm_register == netmap_bwrap_reg;
 }
 
-/* process NETMAP_BDG_DETACH */
-static int
-nm_bdg_ctl_detach(struct nmreq *nmr)
+/* Process NETMAP_REQ_VALE_DETACH. */
+int
+nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
 {
 	struct netmap_adapter *na;
 	int error;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na(nmr, &na, NULL, 0 /* don't create */);
+	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
+				NULL, 0 /* don't create */);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
 	}
@@ -961,7 +970,7 @@ struct nm_bdg_polling_state {
 	bool configured;
 	bool stopped;
 	struct netmap_bwrap_adapter *bna;
-	u_int reg;
+	uint32_t mode;
 	u_int qfirst;
 	u_int qlast;
 	u_int cpu_from;
@@ -1005,7 +1014,8 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
 	kcfg.use_kthread = 1;
 	for (i = 0; i < bps->ncpus; i++) {
 		struct nm_bdg_kthread *t = bps->kthreads + i;
-		int all = (bps->ncpus == 1 && bps->reg == NR_REG_ALL_NIC);
+		int all = (bps->ncpus == 1 &&
+			bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU);
 		int affinity = bps->cpu_from + i;
 
 		t->bps = bps;
@@ -1081,67 +1091,68 @@ nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps)
 }
 
 static int
-get_polling_cfg(struct nmreq *nmr, struct netmap_adapter *na,
-			struct nm_bdg_polling_state *bps)
+get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
+		struct nm_bdg_polling_state *bps)
 {
-	int req_cpus, avail_cpus, core_from;
-	u_int reg, i, qfirst, qlast;
+	unsigned int avail_cpus, core_from;
+	unsigned int qfirst, qlast;
+	uint32_t i = req->nr_first_cpu_id;
+	uint32_t req_cpus = req->nr_num_polling_cpus;
 
 	avail_cpus = nm_os_ncpus();
-	req_cpus = nmr->nr_arg1;
 
 	if (req_cpus == 0) {
 		D("req_cpus must be > 0");
 		return EINVAL;
 	} else if (req_cpus >= avail_cpus) {
-		D("for safety, we need at least one core left in the system");
+		D("Cannot use all the CPUs in the system");
 		return EINVAL;
 	}
-	reg = nmr->nr_flags & NR_REG_MASK;
-	i = nmr->nr_ringid & NETMAP_RING_MASK;
-	/*
-	 * ONE_NIC: dedicate one core to one ring. If multiple cores
-	 *          are specified, consecutive rings are also polled.
-	 *          For example, if ringid=2 and 2 cores are given,
-	 *          ring 2 and 3 are polled by core 2 and 3, respectively.
-	 * ALL_NIC: poll all the rings using a core specified by ringid.
-	 *          the number of cores must be 1.
-	 */
-	if (reg == NR_REG_ONE_NIC) {
+
+	if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) {
+		/* Use a separate core for each ring. If nr_num_polling_cpus>1
+		 * more consecutive rings are polled.
+		 * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2,
+		 * ring 2 and 3 are polled by core 2 and 3, respectively. */
 		if (i + req_cpus > nma_get_nrings(na, NR_RX)) {
-			D("only %d rings exist (ring %u-%u is given)",
-				nma_get_nrings(na, NR_RX), i, i+req_cpus);
+			D("Rings %u-%u not in range (have %d rings)",
+				i, i + req_cpus, nma_get_nrings(na, NR_RX));
 			return EINVAL;
 		}
 		qfirst = i;
 		qlast = qfirst + req_cpus;
 		core_from = qfirst;
-	} else if (reg == NR_REG_ALL_NIC) {
+
+	} else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) {
+		/* Poll all the rings using a core specified by nr_first_cpu_id.
+		 * the number of cores must be 1. */
 		if (req_cpus != 1) {
-			D("ncpus must be 1 not %d for REG_ALL_NIC", req_cpus);
+			D("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
+				"(was %d)", req_cpus);
 			return EINVAL;
 		}
 		qfirst = 0;
 		qlast = nma_get_nrings(na, NR_RX);
 		core_from = i;
 	} else {
-		D("reg must be ALL_NIC or ONE_NIC");
+		D("Invalid polling mode");
 		return EINVAL;
 	}
 
-	bps->reg = reg;
+	bps->mode = req->nr_mode;
 	bps->qfirst = qfirst;
 	bps->qlast = qlast;
 	bps->cpu_from = core_from;
 	bps->ncpus = req_cpus;
 	D("%s qfirst %u qlast %u cpu_from %u ncpus %u",
-		reg == NR_REG_ALL_NIC ? "REG_ALL_NIC" : "REG_ONE_NIC",
+		req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ?
+		"MULTI" : "SINGLE",
 		qfirst, qlast, core_from, req_cpus);
 	return 0;
 }
 
 static int
-nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na)
+nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na)
 {
 	struct nm_bdg_polling_state *bps;
 	struct netmap_bwrap_adapter *bna;
@@ -1159,7 +1170,7 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na)
 	bps->configured = false;
 	bps->stopped = true;
 
-	if (get_polling_cfg(nmr, na, bps)) {
+	if (get_polling_cfg(req, na, bps)) {
 		nm_os_free(bps);
 		return EINVAL;
 	}
@@ -1188,7 +1199,7 @@ nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na)
 }
 
 static int
-nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na)
+nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
 {
 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na;
 	struct nm_bdg_polling_state *bps;
@@ -1207,190 +1218,146 @@ nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na)
 	return 0;
 }
 
-/* Called by either user's context (netmap_ioctl())
- * or external kernel modules (e.g., Openvswitch).
- * Operation is indicated in nmr->nr_cmd.
- * NETMAP_BDG_OPS that sets configure/lookup/dtor functions to the bridge
- * requires bdg_ops argument; the other commands ignore this argument.
- *
- * Called without NMG_LOCK.
- */
 int
-netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops)
+nm_bdg_polling(struct nmreq_vale_polling *req)
 {
+	struct netmap_adapter *na = NULL;
+	int error = 0;
+
+	NMG_LOCK();
+	error = netmap_get_bdg_na((struct nmreq_header *)req,
+					&na, NULL, 0);
+	if (na && !error) {
+		if (!nm_is_bwrap(na)) {
+			error = EOPNOTSUPP;
+		} else if (req->nr_hdr.nr_reqtype == NETMAP_BDG_POLLING_ON) {
+			error = nm_bdg_ctl_polling_start(req, na);
+			if (!error)
+				netmap_adapter_get(na);
+		} else {
+			error = nm_bdg_ctl_polling_stop(na);
+			if (!error)
+				netmap_adapter_put(na);
+		}
+		netmap_adapter_put(na);
+	}
+	NMG_UNLOCK();
+
+	return error;
+}
+
+/* Process NETMAP_REQ_VALE_LIST. */
+int
+netmap_bdg_list(struct nmreq_vale_list *req)
+{
+	int namelen = strlen(req->nr_hdr.nr_name);
 	struct nm_bridge *b, *bridges;
-	struct netmap_adapter *na;
 	struct netmap_vp_adapter *vpna;
-	char *name = nmr->nr_name;
-	int cmd = nmr->nr_cmd, namelen = strlen(name);
 	int error = 0, i, j;
 	u_int num_bridges;
 
 	netmap_bns_getbridges(&bridges, &num_bridges);
 
-	switch (cmd) {
-	case NETMAP_BDG_NEWIF:
-		error = netmap_vi_create(nmr, 0 /* no autodelete */);
-		break;
-
-	case NETMAP_BDG_DELIF:
-		error = nm_vi_destroy(nmr->nr_name);
-		break;
-
-	case NETMAP_BDG_ATTACH:
-		error = nm_bdg_ctl_attach(nmr);
-		break;
-
-	case NETMAP_BDG_DETACH:
-		error = nm_bdg_ctl_detach(nmr);
-		break;
-
-	case NETMAP_BDG_LIST:
-		/* this is used to enumerate bridges and ports */
-		if (namelen) { /* look up indexes of bridge and port */
-			if (strncmp(name, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
-				error = EINVAL;
-				break;
-			}
-			NMG_LOCK();
-			b = nm_find_bridge(name, 0 /* don't create */);
-			if (!b) {
-				error = ENOENT;
-				NMG_UNLOCK();
-				break;
-			}
-
-			error = 0;
-			nmr->nr_arg1 = b - bridges; /* bridge index */
-			nmr->nr_arg2 = NM_BDG_NOPORT;
-			for (j = 0; j < b->bdg_active_ports; j++) {
-				i = b->bdg_port_index[j];
-				vpna = b->bdg_ports[i];
-				if (vpna == NULL) {
-					D("---AAAAAAAAARGH-------");
-					continue;
-				}
-				/* the former and the latter identify a
-				 * virtual port and a NIC, respectively
-				 */
-				if (!strcmp(vpna->up.name, name)) {
-					nmr->nr_arg2 = i; /* port index */
-					break;
-				}
-			}
-			NMG_UNLOCK();
-		} else {
-			/* return the first non-empty entry starting from
-			 * bridge nr_arg1 and port nr_arg2.
-			 *
-			 * Users can detect the end of the same bridge by
-			 * seeing the new and old value of nr_arg1, and can
-			 * detect the end of all the bridge by error != 0
-			 */
-			i = nmr->nr_arg1;
-			j = nmr->nr_arg2;
-
-			NMG_LOCK();
-			for (error = ENOENT; i < NM_BRIDGES; i++) {
-				b = bridges + i;
-				for ( ; j < NM_BDG_MAXPORTS; j++) {
-					if (b->bdg_ports[j] == NULL)
-						continue;
-					vpna = b->bdg_ports[j];
-					strncpy(name, vpna->up.name, (size_t)IFNAMSIZ);
-					error = 0;
-					goto out;
-				}
-				j = 0; /* following bridges scan from 0 */
-			}
-		out:
-			nmr->nr_arg1 = i;
-			nmr->nr_arg2 = j;
-			NMG_UNLOCK();
-		}
-		break;
-
-	case NETMAP_BDG_REGOPS: /* XXX this should not be available from userspace */
-		/* register callbacks to the given bridge.
-		 * nmr->nr_name may be just bridge's name (including ':'
-		 * if it is not just NM_NAME).
-		 */
-		if (!bdg_ops) {
-			error = EINVAL;
-			break;
+	/* this is used to enumerate bridges and ports */
+	if (namelen) { /* look up indexes of bridge and port */
+		if (strncmp(req->nr_hdr.nr_name, NM_BDG_NAME,
+					strlen(NM_BDG_NAME))) {
+			return EINVAL;
 		}
 		NMG_LOCK();
-		b = nm_find_bridge(name, 0 /* don't create */);
+		b = nm_find_bridge(req->nr_hdr.nr_name, 0 /* don't create */);
 		if (!b) {
-			error = EINVAL;
-		} else {
-			b->bdg_ops = *bdg_ops;
-		}
-		NMG_UNLOCK();
-		break;
-
-	case NETMAP_BDG_VNET_HDR:
-		/* Valid lengths for the virtio-net header are 0 (no header),
-		   10 and 12. */
-		if (nmr->nr_arg1 != 0 &&
-			nmr->nr_arg1 != sizeof(struct nm_vnet_hdr) &&
-				nmr->nr_arg1 != 12) {
-			error = EINVAL;
-			break;
+			NMG_UNLOCK();
+			return ENOENT;
 		}
-		NMG_LOCK();
-		error = netmap_get_bdg_na(nmr, &na, NULL, 0);
-		if (na && !error) {
-			vpna = (struct netmap_vp_adapter *)na;
-			na->virt_hdr_len = nmr->nr_arg1;
-			if (na->virt_hdr_len) {
-				vpna->mfs = NETMAP_BUF_SIZE(na);
+
+		req->nr_bridge_idx = b - bridges; /* bridge index */
+		req->nr_port_idx = NM_BDG_NOPORT;
+		for (j = 0; j < b->bdg_active_ports; j++) {
+			i = b->bdg_port_index[j];
+			vpna = b->bdg_ports[i];
+			if (vpna == NULL) {
+				D("This should not happen");
+				continue;
+			}
+			/* the former and the latter identify a
+			 * virtual port and a NIC, respectively
+			 */
+			if (!strcmp(vpna->up.name, req->nr_hdr.nr_name)) {
+				req->nr_port_idx = i; /* port index */
+				break;
 			}
-			D("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
-			netmap_adapter_put(na);
-		} else if (!na) {
-			error = ENXIO;
 		}
 		NMG_UNLOCK();
-		break;
+	} else {
+		/* return the first non-empty entry starting from
+		 * bridge nr_arg1 and port nr_arg2.
+		 *
+		 * Users can detect the end of the same bridge by
+		 * seeing the new and old value of nr_arg1, and can
+		 * detect the end of all the bridge by error != 0
+		 */
+		i = req->nr_bridge_idx;
+		j = req->nr_port_idx;
 
-	case NETMAP_BDG_POLLING_ON:
-	case NETMAP_BDG_POLLING_OFF:
 		NMG_LOCK();
-		error = netmap_get_bdg_na(nmr, &na, NULL, 0);
-		if (na && !error) {
-			if (!nm_is_bwrap(na)) {
-				error = EOPNOTSUPP;
-			} else if (cmd == NETMAP_BDG_POLLING_ON) {
-				error = nm_bdg_ctl_polling_start(nmr, na);
-				if (!error)
-					netmap_adapter_get(na);
-			} else {
-				error = nm_bdg_ctl_polling_stop(nmr, na);
-				if (!error)
-					netmap_adapter_put(na);
+		for (error = ENOENT; i < NM_BRIDGES; i++) {
+			b = bridges + i;
+			for ( ; j < NM_BDG_MAXPORTS; j++) {
+				if (b->bdg_ports[j] == NULL)
+					continue;
+				vpna = b->bdg_ports[j];
+				strncpy(req->nr_hdr.nr_name, vpna->up.name,
+					(size_t)IFNAMSIZ);
+				error = 0;
+				goto out;
 			}
-			netmap_adapter_put(na);
+			j = 0; /* following bridges scan from 0 */
 		}
+	out:
+		req->nr_bridge_idx = i;
+		req->nr_port_idx = j;
 		NMG_UNLOCK();
-		break;
+	}
+
+	return error;
+}
+
+/* Called by external kernel modules (e.g., Openvswitch).
+ * to set configure/lookup/dtor functions of a VALE instance.
+ * Register callbacks to the given bridge. 'name' may be just
+ * bridge's name (including ':' if it is not just NM_BDG_NAME).
+ * Called without NMG_LOCK.
+ */
+int
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops)
+{
+	struct nm_bridge *b;
+	int error = 0;
 
-	default:
-		D("invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
+	if (!bdg_ops) {
+		return EINVAL;
+	}
+	NMG_LOCK();
+	b = nm_find_bridge(name, 0 /* don't create */);
+	if (!b) {
 		error = EINVAL;
-		break;
+	} else {
+		b->bdg_ops = *bdg_ops;
 	}
+	NMG_UNLOCK();
+
 	return error;
 }
 
 int
-netmap_bdg_config(struct nmreq *nmr)
+netmap_bdg_config(struct nm_ifreq *nr)
 {
 	struct nm_bridge *b;
 	int error = EINVAL;
 
 	NMG_LOCK();
-	b = nm_find_bridge(nmr->nr_name, 0);
+	b = nm_find_bridge(nr->nifr_name, 0);
 	if (!b) {
 		NMG_UNLOCK();
 		return error;
@@ -1399,7 +1366,7 @@ netmap_bdg_config(struct nmreq *nmr)
 	/* Don't call config() with NMG_LOCK() held */
 	BDG_RLOCK(b);
 	if (b->bdg_ops.config != NULL)
-		error = b->bdg_ops.config((struct nm_ifreq *)nmr);
+		error = b->bdg_ops.config(nr);
 	BDG_RUNLOCK(b);
 	return error;
 }
@@ -2229,7 +2196,7 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
  * Only persistent VALE ports have a non-null ifp.
  */
 static int
-netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
+netmap_vp_create(struct nmreq_register *req, struct ifnet *ifp,
 		struct netmap_mem_d *nmd,
 		struct netmap_vp_adapter **ret)
 {
@@ -2237,6 +2204,7 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
 	struct netmap_adapter *na;
 	int error = 0;
 	u_int npipes = 0;
+	u_int extrabufs = 0;
 
 	vpna = nm_os_malloc(sizeof(*vpna));
 	if (vpna == NULL)
@@ -2245,31 +2213,32 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
  	na = &vpna->up;
 
 	na->ifp = ifp;
-	strncpy(na->name, nmr->nr_name, sizeof(na->name));
+	strncpy(na->name, req->nr_hdr.nr_name, sizeof(na->name));
 
 	/* bound checking */
-	na->num_tx_rings = nmr->nr_tx_rings;
+	na->num_tx_rings = req->nr_tx_rings;
 	nm_bound_var(&na->num_tx_rings, 1, 1, NM_BDG_MAXRINGS, NULL);
-	nmr->nr_tx_rings = na->num_tx_rings; // write back
-	na->num_rx_rings = nmr->nr_rx_rings;
+	req->nr_tx_rings = na->num_tx_rings; /* write back */
+	na->num_rx_rings = req->nr_rx_rings;
 	nm_bound_var(&na->num_rx_rings, 1, 1, NM_BDG_MAXRINGS, NULL);
-	nmr->nr_rx_rings = na->num_rx_rings; // write back
-	nm_bound_var(&nmr->nr_tx_slots, NM_BRIDGE_RINGSIZE,
+	req->nr_rx_rings = na->num_rx_rings; /* write back */
+	nm_bound_var(&req->nr_tx_slots, NM_BRIDGE_RINGSIZE,
 			1, NM_BDG_MAXSLOTS, NULL);
-	na->num_tx_desc = nmr->nr_tx_slots;
-	nm_bound_var(&nmr->nr_rx_slots, NM_BRIDGE_RINGSIZE,
+	na->num_tx_desc = req->nr_tx_slots;
+	nm_bound_var(&req->nr_rx_slots, NM_BRIDGE_RINGSIZE,
 			1, NM_BDG_MAXSLOTS, NULL);
 	/* validate number of pipes. We want at least 1,
 	 * but probably can do with some more.
 	 * So let's use 2 as default (when 0 is supplied)
 	 */
-	npipes = nmr->nr_arg1;
+	npipes = req->nr_pipes;
 	nm_bound_var(&npipes, 2, 1, NM_MAXPIPES, NULL);
-	nmr->nr_arg1 = npipes;	/* write back */
+	req->nr_pipes = npipes;	/* write back */
 	/* validate extra bufs */
-	nm_bound_var(&nmr->nr_arg3, 0, 0,
+	nm_bound_var(&extrabufs, 0, 0,
 			128*NM_BDG_MAXSLOTS, NULL);
-	na->num_rx_desc = nmr->nr_rx_slots;
+	req->nr_extra_bufs = extrabufs; /* write back */
+	na->num_rx_desc = req->nr_rx_slots;
 	/* Set the mfs to a default value, as it is needed on the VALE
 	 * mismatch datapath. XXX We should set it according to the MTU
 	 * known to the kernel. */
@@ -2292,13 +2261,13 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp,
 	na->nm_krings_create = netmap_vp_krings_create;
 	na->nm_krings_delete = netmap_vp_krings_delete;
 	na->nm_dtor = netmap_vp_dtor;
-	D("nr_arg2 %d", nmr->nr_arg2);
+	D("nr_mem_id %d", req->nr_mem_id);
 	na->nm_mem = nmd ?
 		netmap_mem_get(nmd):
 		netmap_mem_private_new(
 			na->num_tx_rings, na->num_tx_desc,
 			na->num_rx_rings, na->num_rx_desc,
-			nmr->nr_arg3, npipes, &error);
+			req->nr_extra_bufs, npipes, &error);
 	if (na->nm_mem == NULL)
 		goto err;
 	na->nm_bdg_attach = netmap_vp_bdg_attach;
@@ -2758,7 +2727,7 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, nmr->nr_ringid, nmr->nr_flags);
+		error = netmap_do_regif(npriv, na, /* TODO no-host-rings*/ NR_REG_NIC_SW, 0, 0);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3a397d393..e5d24416c 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -400,7 +400,9 @@ struct nmreq_option {
 struct nmreq_header {
 	uint16_t		nr_version;	/* API version */
 	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
-	struct nmreq_option	*options;	/* command-specific options */
+#define NETMAP_REQ_IFNAMSIZ	64
+	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
+	struct nmreq_option	*nr_options;	/* command-specific options */
 };
 
 enum {
@@ -444,15 +446,12 @@ enum {
 	NETMAP_REQ_OPT_EXTMEM = 1,
 };
 
-#define NETMAP_REQ_IFNAMSIZ	64
-
 /*
  * nr_reqtype: NETMAP_REQ_REGISTER
  * Bind (register) a netmap port to this control device.
  */
 struct nmreq_register {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -519,7 +518,6 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  */
 struct nmreq_port_info_get {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ]; /* netmap port name */
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -538,7 +536,6 @@ struct nmreq_port_info_get {
  */
 struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* attach the host stack */
@@ -551,7 +548,6 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 /*
@@ -561,7 +557,6 @@ struct nmreq_vale_detach {
 struct nmreq_vale_list {
 	struct nmreq_header nr_hdr;
 	/* Name of the VALE port (valeXXX:YYY) or empty. */
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint16_t	nr_bridge_idx;
 	uint16_t	nr_port_idx;
 };
@@ -572,7 +567,6 @@ struct nmreq_vale_list {
  */
 struct nmreq_port_hdr {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint32_t	nr_hdr_len;
 };
 
@@ -582,7 +576,6 @@ struct nmreq_port_hdr {
  */
 struct nmreq_vale_newif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -596,7 +589,6 @@ struct nmreq_vale_newif {
  */
 struct nmreq_vale_delif {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 /*
@@ -605,7 +597,11 @@ struct nmreq_vale_delif {
  */
 struct nmreq_vale_polling {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
+	uint32_t	nr_mode;
+#define NETMAP_POLLING_MODE_SINGLE_CPU 1
+#define NETMAP_POLLING_MODE_MULTI_CPU 2
+	uint32_t	nr_first_cpu_id;
+	uint32_t	nr_num_polling_cpus;
 };
 
 /*
@@ -615,9 +611,8 @@ struct nmreq_vale_polling {
  */
 struct nmreq_pools_info_get {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];
 	uint64_t	nr_memsize;
-	uint64_t	nr_mem_id;
+	uint16_t	nr_mem_id;
 	uint64_t	nr_if_pool_offset;
 	uint32_t	nr_if_pool_objtotal;
 	uint32_t	nr_if_pool_objsize;
@@ -638,7 +633,6 @@ struct nmreq_pools_info_get {
  */
 struct nmreq_vale_ops_register {
 	struct nmreq_header nr_hdr;
-	char		nr_name[NETMAP_REQ_IFNAMSIZ];	/* valeXXX:YYY */
 };
 
 #endif /* _NET_NETMAP_H_ */

From 2f81a2ce2789328130dbff091a089404435894c5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 10:42:17 +0100
Subject: [PATCH 0605/2207] netmap_virt: remove passthrough commands

They are going to be replaced by an option for NETMAP_REQ_REGISTER.
---
 sys/net/netmap.h      |  6 ------
 sys/net/netmap_virt.h | 21 ---------------------
 2 files changed, 27 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e5d24416c..7b500b129 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -430,12 +430,6 @@ enum {
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
-	/* Enable host-side ptnetmap processing (e.g. start ptnetmap
-	 * kthreads). */
-	NETMAP_REQ_PASSTHROUGH_ENABLE,
-	/* Disable host-side ptnetmap processing (e.g. stop ptnetmap
-	 * kthreads). */
-	NETMAP_REQ_PASSTHROUGH_DISABLE,
 	/* Program a VALE switch by registering custom callbacks. */
 	NETMAP_REQ_VALE_OPS_REGISTER,
 };
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 5fb529ee4..41098a2cb 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -109,27 +109,6 @@ struct ptnetmap_cfgentry_bhyve {
 	} ioctl_data;
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_PASSTHROUGH_ENABLE
- * Enable host-side ptnetmap processing (e.g. start ptnetmap kthreads).
- */
-struct nmreq_passthrough_enable {
-	struct nmreq_header	nr_hdr;
-	/* Userspace pointer to a variable-size struct containing the
-	 * ptnetmap configuration. */
-	struct pnetmap_cfg	*nr_cfg;
-	/* Length of the configuration struct above (in bytes). */
-	uint32_t		nr_cfg_len;
-};
-
-/*
- * nr_reqtype: NETMAP_REQ_PASSTHROUGH_DISABLE
- * Disalbe host-side ptnetmap processing (e.g. stop ptnetmap kthreads).
- */
-struct nmreq_passthrough_disable {
-	struct nmreq_header	nr_hdr;
-};
-
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
  * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.

From 724a0cbbb08e851b0c0c61647577bfd120fd710d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 10:53:32 +0100
Subject: [PATCH 0606/2207] move code for legacy API support to a separate file

---
 LINUX/Kbuild.in                |   2 +-
 WINDOWS/Makefile               |   1 +
 WINDOWS/netmap.vcxproj         |   3 +-
 sys/dev/netmap/netmap.c        | 305 ----------------------------
 sys/dev/netmap/netmap_kern.h   |   2 +
 sys/dev/netmap/netmap_legacy.c | 349 +++++++++++++++++++++++++++++++++
 sys/modules/netmap/Makefile    |   1 +
 7 files changed, 356 insertions(+), 307 deletions(-)
 create mode 100644 sys/dev/netmap/netmap_legacy.c

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index f4a861cc6..2617e7502 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,7 +8,7 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
diff --git a/WINDOWS/Makefile b/WINDOWS/Makefile
index 1de23435e..d4184846f 100644
--- a/WINDOWS/Makefile
+++ b/WINDOWS/Makefile
@@ -81,6 +81,7 @@ SRCS	+= netmap_mem2.c
 SRCS	+= netmap_monitor.c
 SRCS	+= netmap_pipe.c
 SRCS	+= netmap_vale.c
+SRCS	+= netmap_legacy.c
 SRCS	+= netmap_windows.c
 SRCS	+= win_glue.c
 
diff --git a/WINDOWS/netmap.vcxproj b/WINDOWS/netmap.vcxproj
index df5a4f626..86fc61fff 100644
--- a/WINDOWS/netmap.vcxproj
+++ b/WINDOWS/netmap.vcxproj
@@ -202,6 +202,7 @@
     
     
     
+    
     
     
   
@@ -218,4 +219,4 @@
   
   
   
-
\ No newline at end of file
+
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 81e98dd94..cd10223f8 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2230,311 +2230,6 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
-/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
- * (new API). The new struct is dynamically allocated. */
-static struct nmreq_header *
-nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
-{
-	struct nmreq_header *hdr = NULL;
-
-	/* Sanitize nmr->nr_name by adding the string terminator. */
-	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
-		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
-	}
-
-	switch (ioctl_cmd) {
-	case NIOCREGIF: {
-		switch (nmr->nr_cmd) {
-		case 0: {
-			/* Regular NIOCREGIF operation. */
-			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-			req->nr_offset = nmr->nr_offset;
-			req->nr_memsize = nmr->nr_memsize;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
-			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
-				/* Convert the older nmr->nr_ringid (original
-				 * netmap control API) to nmr->nr_flags. */
-				u_int regmode = NR_REG_DEFAULT;
-				if (req->nr_ringid & NETMAP_SW_RING) {
-					regmode = NR_REG_SW;
-				} else if (req->nr_ringid & NETMAP_HW_RING) {
-					regmode = NR_REG_ONE_NIC;
-				} else {
-					regmode = NR_REG_ALL_NIC;
-				}
-				nmr->nr_flags = regmode |
-					(nmr->nr_flags & (~NR_REG_MASK));
-			}
-			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
-			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
-			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
-				req->nr_flags |= NR_NO_TX_POLL;
-			}
-			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
-				req->nr_flags |= NR_DO_RX_POLL;
-			}
-			req->nr_pipes = nmr->nr_arg1;
-			req->nr_extra_bufs = nmr->nr_arg3;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_ATTACH: {
-			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_DETACH: {
-			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_VNET_HDR:
-		case NETMAP_VNET_HDR_GET: {
-			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
-				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
-			req->nr_hdr_len = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_NEWIF : {
-			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_DELIF: {
-			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_BDG_POLLING_ON:
-		case NETMAP_BDG_POLLING_OFF: {
-			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
-				NETMAP_REQ_VALE_POLLING_ENABLE :
-				NETMAP_REQ_VALE_POLLING_DISABLE;
-			switch (nmr->nr_flags & NR_REG_MASK) {
-			default:
-				req->nr_mode = 0; /* invalid */
-				break;
-			case NR_REG_ONE_NIC:
-				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
-				break;
-			case NR_REG_ALL_NIC:
-				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
-				break;
-			}
-			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
-			req->nr_num_polling_cpus = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_POOLS_INFO_GET: {
-			/* We could deny this request similar to ptnetmap requests. */
-			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-			/* Most of the fields are for output (see
-			 * nmreq_to_legacy). */
-			hdr = (struct nmreq_header *)req;
-			break;
-		}
-		case NETMAP_PT_HOST_CREATE:
-		case NETMAP_PT_HOST_DELETE: {
-			D("Netmap passthrough not supported yet");
-			return NULL;
-			break;
-		}
-		}
-		break;
-	}
-	case NIOCGINFO: {
-		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
-			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-			req->nr_bridge_idx = nmr->nr_arg1;
-			req->nr_port_idx = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
-		} else {
-			/* Regular NIOCGINFO. */
-			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-			req->nr_offset = nmr->nr_offset;
-			req->nr_memsize = nmr->nr_memsize;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
-		}
-		break;
-	}
-	}
-
-	KASSERT(hdr != NULL, "Invalid NULL netmap request");
-	hdr->nr_version = NETMAP_API; /* new API */
-	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-
-	return hdr;
-oom:
-	D("Failed to allocate memory for nmreq_xyz struct");
-	return NULL;
-}
-
-/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
- * It also frees the nmreq_xyz struct, as it was allocated by
- * nmreq_from_legacy(). */
-static int
-nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
-{
-	int ret = 0;
-	/* Don't bzero 'nmr', we may need the pointers stored into
-	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
-
-	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
-
-	switch (hdr->nr_reqtype) {
-	case NETMAP_REQ_REGISTER: {
-		struct nmreq_register *req = (struct nmreq_register *)hdr;
-		nmr->nr_offset = req->nr_offset;
-		nmr->nr_memsize = req->nr_memsize;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_ringid = req->nr_ringid;
-		if (req->nr_flags & NR_NO_TX_POLL) {
-			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
-		}
-		if (req->nr_flags & NR_DO_RX_POLL) {
-			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
-		}
-		nmr->nr_flags = req->nr_mode | req->nr_flags;
-		nmr->nr_arg1 = req->nr_pipes;
-		nmr->nr_arg3 = req->nr_extra_bufs;
-		break;
-	}
-	case NETMAP_REQ_PORT_INFO_GET: {
-		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
-		nmr->nr_offset = req->nr_offset;
-		nmr->nr_memsize = req->nr_memsize;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		break;
-	}
-	case NETMAP_REQ_VALE_ATTACH: {
-		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_arg1 = req->nr_flags;
-		break;
-	}
-	case NETMAP_REQ_VALE_DETACH: {
-		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
-		(void)req;
-		break;
-	}
-	case NETMAP_REQ_VALE_LIST: {
-		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
-		nmr->nr_arg1 = req->nr_bridge_idx;
-		nmr->nr_arg2 = req->nr_port_idx;
-		break;
-	}
-	case NETMAP_REQ_PORT_HDR_SET:
-	case NETMAP_REQ_PORT_HDR_GET: {
-		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
-		nmr->nr_arg1 = req->nr_hdr_len;
-		break;
-	}
-	case NETMAP_REQ_VALE_NEWIF: {
-		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		break;
-	}
-	case NETMAP_REQ_VALE_DELIF: {
-		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
-		(void)req;
-		break;
-	}
-	case NETMAP_REQ_VALE_POLLING_ENABLE:
-	case NETMAP_REQ_VALE_POLLING_DISABLE: {
-		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
-		switch (req->nr_mode) {
-		default:
-			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
-			break;
-		case NETMAP_POLLING_MODE_MULTI_CPU:
-			nmr->nr_flags = NR_REG_ONE_NIC;
-			break;
-		case NETMAP_POLLING_MODE_SINGLE_CPU:
-			nmr->nr_flags = NR_REG_ALL_NIC;
-			break;
-		}
-		nmr->nr_ringid = req->nr_first_cpu_id;
-		nmr->nr_arg1 = req->nr_num_polling_cpus;
-		break;
-	}
-	case NETMAP_REQ_POOLS_INFO_GET: {
-		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
-		struct netmap_pools_info pi;
-		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
-		pi.memsize = req->nr_memsize;
-		pi.memid = req->nr_mem_id;
-		pi.if_pool_offset = req->nr_if_pool_offset;
-		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
-		pi.if_pool_objsize = req->nr_if_pool_objsize;
-		pi.ring_pool_offset = req->nr_ring_pool_offset;
-		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
-		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
-		pi.buf_pool_offset = req->nr_buf_pool_offset;
-		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
-		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
-		ret = copyout(&pi, upi, sizeof(pi));
-		if (ret) {
-			D("copyout() failed");
-		}
-		break;
-	}
-	}
-
-	return ret;
-}
-
 static void
 nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
 				 struct nmreq_register *regreq)
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 421f9c417..8010b1dc8 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1509,6 +1509,8 @@ int netmap_get_memory(struct netmap_priv_d* p);
 void netmap_dtor(void *data);
 
 int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
+struct nmreq_header *nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd);
+int nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr);
 
 /* netmap_adapter creation/destruction */
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
new file mode 100644
index 000000000..594bb1b04
--- /dev/null
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2018 Vincenzo Maffione
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(__FreeBSD__)
+#include  /* prerequisite */
+#include 
+#elif defined(linux)
+#include "bsd_glue.h"
+#elif defined(__APPLE__)
+#warning OSX support is only partial
+#include "osx_glue.h"
+#elif defined (_WIN32)
+#include "win_glue.h"
+#endif
+
+/*
+ * common headers
+ */
+#include 
+#include 
+
+/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
+ * (new API). The new struct is dynamically allocated. */
+struct nmreq_header *
+nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
+{
+	struct nmreq_header *hdr = NULL;
+
+	/* Sanitize nmr->nr_name by adding the string terminator. */
+	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
+		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
+	}
+
+	switch (ioctl_cmd) {
+	case NIOCREGIF: {
+		switch (nmr->nr_cmd) {
+		case 0: {
+			/* Regular NIOCREGIF operation. */
+			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
+				/* Convert the older nmr->nr_ringid (original
+				 * netmap control API) to nmr->nr_flags. */
+				u_int regmode = NR_REG_DEFAULT;
+				if (req->nr_ringid & NETMAP_SW_RING) {
+					regmode = NR_REG_SW;
+				} else if (req->nr_ringid & NETMAP_HW_RING) {
+					regmode = NR_REG_ONE_NIC;
+				} else {
+					regmode = NR_REG_ALL_NIC;
+				}
+				nmr->nr_flags = regmode |
+					(nmr->nr_flags & (~NR_REG_MASK));
+			}
+			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
+			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
+				req->nr_flags |= NR_NO_TX_POLL;
+			}
+			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
+				req->nr_flags |= NR_DO_RX_POLL;
+			}
+			req->nr_pipes = nmr->nr_arg1;
+			req->nr_extra_bufs = nmr->nr_arg3;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_ATTACH: {
+			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			req->nr_mem_id = nmr->nr_arg2;
+			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DETACH: {
+			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_VNET_HDR:
+		case NETMAP_VNET_HDR_GET: {
+			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
+				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
+			req->nr_hdr_len = nmr->nr_arg1;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_NEWIF : {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_DELIF: {
+			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_BDG_POLLING_ON:
+		case NETMAP_BDG_POLLING_OFF: {
+			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
+				NETMAP_REQ_VALE_POLLING_ENABLE :
+				NETMAP_REQ_VALE_POLLING_DISABLE;
+			switch (nmr->nr_flags & NR_REG_MASK) {
+			default:
+				req->nr_mode = 0; /* invalid */
+				break;
+			case NR_REG_ONE_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
+				break;
+			case NR_REG_ALL_NIC:
+				req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+				break;
+			}
+			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
+			req->nr_num_polling_cpus = nmr->nr_arg1;
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_POOLS_INFO_GET: {
+			/* We could deny this request similar to ptnetmap requests. */
+			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+			/* Most of the fields are for output (see
+			 * nmreq_to_legacy). */
+			hdr = (struct nmreq_header *)req;
+			break;
+		}
+		case NETMAP_PT_HOST_CREATE:
+		case NETMAP_PT_HOST_DELETE: {
+			D("Netmap passthrough not supported yet");
+			return NULL;
+			break;
+		}
+		}
+		break;
+	}
+	case NIOCGINFO: {
+		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
+			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			req->nr_bridge_idx = nmr->nr_arg1;
+			req->nr_port_idx = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+		} else {
+			/* Regular NIOCGINFO. */
+			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
+			if (!req) { goto oom; }
+			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			req->nr_offset = nmr->nr_offset;
+			req->nr_memsize = nmr->nr_memsize;
+			req->nr_tx_slots = nmr->nr_tx_slots;
+			req->nr_rx_slots = nmr->nr_rx_slots;
+			req->nr_tx_rings = nmr->nr_tx_rings;
+			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_mem_id = nmr->nr_arg2;
+			hdr = (struct nmreq_header *)req;
+		}
+		break;
+	}
+	}
+
+	KASSERT(hdr != NULL, "Invalid NULL netmap request");
+	hdr->nr_version = NETMAP_API; /* new API */
+	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
+
+	return hdr;
+oom:
+	D("Failed to allocate memory for nmreq_xyz struct");
+	return NULL;
+}
+
+/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
+ * It also frees the nmreq_xyz struct, as it was allocated by
+ * nmreq_from_legacy(). */
+int
+nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
+{
+	int ret = 0;
+	/* Don't bzero 'nmr', we may need the pointers stored into
+	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
+
+	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+
+	switch (hdr->nr_reqtype) {
+	case NETMAP_REQ_REGISTER: {
+		struct nmreq_register *req = (struct nmreq_register *)hdr;
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_ringid = req->nr_ringid;
+		if (req->nr_flags & NR_NO_TX_POLL) {
+			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
+		}
+		if (req->nr_flags & NR_DO_RX_POLL) {
+			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
+		}
+		nmr->nr_flags = req->nr_mode | req->nr_flags;
+		nmr->nr_arg1 = req->nr_pipes;
+		nmr->nr_arg3 = req->nr_extra_bufs;
+		break;
+	}
+	case NETMAP_REQ_PORT_INFO_GET: {
+		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
+		nmr->nr_offset = req->nr_offset;
+		nmr->nr_memsize = req->nr_memsize;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_ATTACH: {
+		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
+		nmr->nr_arg2 = req->nr_mem_id;
+		nmr->nr_arg1 = req->nr_flags;
+		break;
+	}
+	case NETMAP_REQ_VALE_DETACH: {
+		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
+		(void)req;
+		break;
+	}
+	case NETMAP_REQ_VALE_LIST: {
+		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
+		nmr->nr_arg1 = req->nr_bridge_idx;
+		nmr->nr_arg2 = req->nr_port_idx;
+		break;
+	}
+	case NETMAP_REQ_PORT_HDR_SET:
+	case NETMAP_REQ_PORT_HDR_GET: {
+		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
+		nmr->nr_arg1 = req->nr_hdr_len;
+		break;
+	}
+	case NETMAP_REQ_VALE_NEWIF: {
+		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
+		nmr->nr_tx_slots = req->nr_tx_slots;
+		nmr->nr_rx_slots = req->nr_rx_slots;
+		nmr->nr_tx_rings = req->nr_tx_rings;
+		nmr->nr_rx_rings = req->nr_rx_rings;
+		nmr->nr_arg2 = req->nr_mem_id;
+		break;
+	}
+	case NETMAP_REQ_VALE_DELIF: {
+		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
+		(void)req;
+		break;
+	}
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+	case NETMAP_REQ_VALE_POLLING_DISABLE: {
+		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
+		switch (req->nr_mode) {
+		default:
+			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
+			break;
+		case NETMAP_POLLING_MODE_MULTI_CPU:
+			nmr->nr_flags = NR_REG_ONE_NIC;
+			break;
+		case NETMAP_POLLING_MODE_SINGLE_CPU:
+			nmr->nr_flags = NR_REG_ALL_NIC;
+			break;
+		}
+		nmr->nr_ringid = req->nr_first_cpu_id;
+		nmr->nr_arg1 = req->nr_num_polling_cpus;
+		break;
+	}
+	case NETMAP_REQ_POOLS_INFO_GET: {
+		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
+		struct netmap_pools_info pi;
+		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
+		pi.memsize = req->nr_memsize;
+		pi.memid = req->nr_mem_id;
+		pi.if_pool_offset = req->nr_if_pool_offset;
+		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
+		pi.if_pool_objsize = req->nr_if_pool_objsize;
+		pi.ring_pool_offset = req->nr_ring_pool_offset;
+		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
+		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
+		pi.buf_pool_offset = req->nr_buf_pool_offset;
+		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
+		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
+		ret = copyout(&pi, upi, sizeof(pi));
+		if (ret) {
+			D("copyout() failed");
+		}
+		break;
+	}
+	}
+
+	return ret;
+}
+
diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index 978a4858e..a17b21dd3 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -21,6 +21,7 @@ SRCS	+= netmap_offloadings.c
 SRCS	+= netmap_pipe.c
 SRCS	+= netmap_monitor.c
 SRCS	+= netmap_pt.c
+SRCS	+= netmap_legacy.c
 SRCS	+= if_ptnet.c
 SRCS	+= opt_inet.h opt_inet6.h
 

From e4c276c725e3f3a0361e5afe41ec599d518dfc1d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 11:05:36 +0100
Subject: [PATCH 0607/2207] move more code to netmap_legacy

---
 sys/dev/netmap/netmap.c        | 62 ++-----------------------
 sys/dev/netmap/netmap_kern.h   |  4 +-
 sys/dev/netmap/netmap_legacy.c | 83 +++++++++++++++++++++++++++++++++-
 3 files changed, 87 insertions(+), 62 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index cd10223f8..5021cfcb5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2564,25 +2564,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		break;
 	}
 
-	case NIOCGINFO:
-	case NIOCREGIF: {
-		/* Request for the legacy control API. Convert it to a
-		 * NIOCCTRL request. */
-		struct nmreq *nmr = (struct nmreq *) data;
-		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
-		if (hdr == NULL) { /* out of memory */
-			return ENOMEM;
-		}
-		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
-		if (error == 0) {
-			nmreq_to_legacy(hdr, nmr);
-		}
-		nm_os_free(hdr);
-		break;
-	}
-
 	case NIOCTXSYNC:
-	case NIOCRXSYNC:
+	case NIOCRXSYNC: {
 		nifp = priv->np_nifp;
 
 		if (nifp == NULL) {
@@ -2650,49 +2633,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		break;
-
-#ifdef WITH_VALE
-	case NIOCCONFIG: {
-		struct nm_ifreq *nr = (struct nm_ifreq *)data;
-		error = netmap_bdg_config(nr);
-		break;
 	}
-#endif
-#ifdef __FreeBSD__
-	case FIONBIO:
-	case FIOASYNC:
-		ND("FIONBIO/FIOASYNC are no-ops");
-		break;
-
-	case BIOCIMMEDIATE:
-	case BIOCGHDRCMPLT:
-	case BIOCSHDRCMPLT:
-	case BIOCSSEESENT:
-		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
-		break;
-
-	default:	/* allow device-specific ioctls */
-	    {
-		struct nmreq *nmr = (struct nmreq *)data;
-		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
-		if (ifp == NULL) {
-			error = ENXIO;
-		} else {
-			struct socket so;
 
-			bzero(&so, sizeof(so));
-			so.so_vnet = ifp->if_vnet;
-			// so->so_proto not null.
-			error = ifioctl(&so, cmd, data, td);
-			if_rele(ifp);
-		}
+	default: {
+		return netmap_ioctl_legacy(priv, cmd, data, td);
 		break;
-	    }
-
-#else /* linux */
-	default:
-		error = EOPNOTSUPP;
-#endif /* linux */
+	}
 	}
 
 	return (error);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8010b1dc8..6779b1c58 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1509,8 +1509,8 @@ int netmap_get_memory(struct netmap_priv_d* p);
 void netmap_dtor(void *data);
 
 int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
-struct nmreq_header *nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd);
-int nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr);
+int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+			struct thread *td);
 
 /* netmap_adapter creation/destruction */
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 594bb1b04..80e580adb 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -27,6 +27,16 @@
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 #include 
+#include 	/* defines used in kernel.h */
+#include 	/* FIONBIO */
+#include 
+#include  /* sockaddrs */
+#include 
+#include 
+#include 
+#include 		/* BIOCIMMEDIATE */
+#include 	/* bus_dmamap_* */
+#include 
 #elif defined(linux)
 #include "bsd_glue.h"
 #elif defined(__APPLE__)
@@ -44,7 +54,7 @@
 
 /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
  * (new API). The new struct is dynamically allocated. */
-struct nmreq_header *
+static struct nmreq_header *
 nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 {
 	struct nmreq_header *hdr = NULL;
@@ -223,7 +233,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
  * It also frees the nmreq_xyz struct, as it was allocated by
  * nmreq_from_legacy(). */
-int
+static int
 nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
 	int ret = 0;
@@ -347,3 +357,72 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	return ret;
 }
 
+int
+netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+			struct thread *td)
+{
+	int error = 0;
+
+	switch (cmd) {
+	case NIOCGINFO:
+	case NIOCREGIF: {
+		/* Request for the legacy control API. Convert it to a
+		 * NIOCCTRL request. */
+		struct nmreq *nmr = (struct nmreq *) data;
+		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
+		if (hdr == NULL) { /* out of memory */
+			return ENOMEM;
+		}
+		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
+		if (error == 0) {
+			nmreq_to_legacy(hdr, nmr);
+		}
+		nm_os_free(hdr);
+		break;
+	}
+#ifdef WITH_VALE
+	case NIOCCONFIG: {
+		struct nm_ifreq *nr = (struct nm_ifreq *)data;
+		error = netmap_bdg_config(nr);
+		break;
+	}
+#endif
+#ifdef __FreeBSD__
+	case FIONBIO:
+	case FIOASYNC:
+		ND("FIONBIO/FIOASYNC are no-ops");
+		break;
+
+	case BIOCIMMEDIATE:
+	case BIOCGHDRCMPLT:
+	case BIOCSHDRCMPLT:
+	case BIOCSSEESENT:
+		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
+		break;
+
+	default:	/* allow device-specific ioctls */
+	    {
+		struct nmreq *nmr = (struct nmreq *)data;
+		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
+		if (ifp == NULL) {
+			error = ENXIO;
+		} else {
+			struct socket so;
+
+			bzero(&so, sizeof(so));
+			so.so_vnet = ifp->if_vnet;
+			// so->so_proto not null.
+			error = ifioctl(&so, cmd, data, td);
+			if_rele(ifp);
+		}
+		break;
+	    }
+
+#else /* linux */
+	default:
+		error = EOPNOTSUPP;
+#endif /* linux */
+	}
+
+	return error;
+}

From b8565325bd87b35809a6be77007d6dbe4ece3163 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 11:39:55 +0100
Subject: [PATCH 0608/2207] linux: ioctl: compute the correct size of NIOCCTRL
 requests

---
 LINUX/netmap_linux.c         | 22 ++++++++++++++++++++--
 sys/dev/netmap/netmap.c      | 32 ++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_kern.h |  1 +
 sys/net/netmap.h             |  7 ++++---
 4 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 564b4a8a5..605e3680a 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1115,7 +1115,6 @@ linux_netmap_set_channels(struct net_device *dev,
 }
 #endif
 
-
 #ifndef NETMAP_LINUX_HAVE_UNLOCKED_IOCTL
 #define LIN_IOCTL_NAME	.ioctl
 static int
@@ -1131,6 +1130,10 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 	union {
 		struct nm_ifreq ifr;
 		struct nmreq nmr;
+		/* It must follow the largest among the nmreq_xyz structs,
+		 * so that there is enough space for any NIOCCTRL request.
+		 * This is asserted by the BUG_ON() below. */
+		struct nmreq_register req;
 	} arg;
 	size_t argsize = 0;
 
@@ -1141,9 +1144,24 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 	case NIOCCONFIG:
 		argsize = sizeof(arg.ifr);
 		break;
-	default:
+	case NIOCREGIF:
+	case NIOCGINFO:
 		argsize = sizeof(arg.nmr);
 		break;
+	case NIOCCTRL: {
+		/* Look at the value of the nr_reqtype field to know
+		 * how much we need to copy from/to userspace. */
+		size_t peeksize = sizeof(arg.req.nr_hdr.nr_version) +
+				sizeof(arg.req.nr_hdr.nr_reqtype);
+		if (copy_from_user(&arg, (void *)data, peeksize) != 0)
+			return -EFAULT;
+		argsize = nmreq_size_by_type(arg.req.nr_hdr.nr_reqtype);
+		BUG_ON(argsize > sizeof(arg));
+		if (argsize == 0) {
+			return -EINVAL;
+		}
+		break;
+	}
 	}
 	if (argsize) {
 		if (!data)
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5021cfcb5..76f84a067 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2644,6 +2644,38 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	return (error);
 }
 
+size_t
+nmreq_size_by_type(uint16_t nr_reqtype)
+{
+	switch (nr_reqtype) {
+	case NETMAP_REQ_REGISTER:
+		return sizeof(struct nmreq_register);
+	case NETMAP_REQ_PORT_INFO_GET:
+		return sizeof(struct nmreq_port_info_get);
+	case NETMAP_REQ_VALE_ATTACH:
+		return sizeof(struct nmreq_vale_attach);
+	case NETMAP_REQ_VALE_DETACH:
+		return sizeof(struct nmreq_vale_detach);
+	case NETMAP_REQ_VALE_LIST:
+		return sizeof(struct nmreq_vale_list);
+	case NETMAP_REQ_PORT_HDR_SET:
+	case NETMAP_REQ_PORT_HDR_GET:
+		return sizeof(struct nmreq_port_hdr);
+	case NETMAP_REQ_VALE_NEWIF:
+		return sizeof(struct nmreq_vale_newif);
+	case NETMAP_REQ_VALE_DELIF:
+		return sizeof(struct nmreq_vale_delif);
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+	case NETMAP_REQ_VALE_POLLING_DISABLE:
+		return sizeof(struct nmreq_vale_polling);
+	case NETMAP_REQ_POOLS_INFO_GET:
+		return sizeof(struct nmreq_pools_info_get);
+	case NETMAP_REQ_VALE_OPS_REGISTER:
+		return sizeof(struct nmreq_vale_ops_register);
+	}
+	return 0;
+}
+
 
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6779b1c58..aa65b90de 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1511,6 +1511,7 @@ void netmap_dtor(void *data);
 int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
 int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			struct thread *td);
+size_t nmreq_size_by_type(uint16_t nr_reqtype);
 
 /* netmap_adapter creation/destruction */
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 7b500b129..857dd23fa 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -396,7 +396,8 @@ struct nmreq_option {
 	uint16_t		nro_reqtype;
 };
 
-/* Header common to all requests. */
+/* Header common to all requests. Do not reorder these fields, as we need
+ * the second one (nr_reqtype) to know how much to copy from/to userspace. */
 struct nmreq_header {
 	uint16_t		nr_version;	/* API version */
 	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
@@ -498,8 +499,8 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * Demultiplexing is done using the nr_hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
- * specifying the largest among the nmreq_xyz structs. */
-#define NIOCCTRL	_IOWR('i', 151, struct nmreq_register)
+ * specifying only nmreq_header, and copyin the remainder. */
+#define NIOCCTRL	_IOWR('i', 151, struct nmreq_header)
 
 /* The ioctl commands to sync TX/RX netmap rings. */
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */

From 28bbd9e1b37ec1d34f0a4ce730205f4d713771b2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:05:01 +0100
Subject: [PATCH 0609/2207] nm_pkt_copy: fix compilation warning

---
 sys/net/netmap_user.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index e12b19de7..ade7eecfd 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -277,7 +277,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024 || l % 64)) {
+	if (unlikely(l >= 1024 || (l % 64))) {
 		memcpy(dst, src, l);
 		return;
 	}

From 198f8ff8d58666a72013403fae2b224b9012988c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:23:21 +0100
Subject: [PATCH 0610/2207] utils: introduce ctrl-api-test

---
 utils/GNUmakefile     |  2 +-
 utils/ctrl-api-test.c | 78 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+), 1 deletion(-)
 create mode 100644 utils/ctrl-api-test.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index b121f1f8d..82639fcfe 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,6 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm functional
+PROGS	= test_select testmmap test_nm functional ctrl-api-test
 X86PROGS = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
new file mode 100644
index 000000000..650ecbe1f
--- /dev/null
+++ b/utils/ctrl-api-test.c
@@ -0,0 +1,78 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+int
+port_info_get(int fd, const char *ifname)
+{
+	struct nmreq_port_info_get req;
+	int ret;
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL)");
+	}
+	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_tx_slots %u\n", req.nr_tx_slots);
+	printf("nr_rx_slots %u\n", req.nr_rx_slots);
+	printf("nr_tx_rings %u\n", req.nr_tx_rings);
+	printf("nr_rx_rings %u\n", req.nr_rx_rings);
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+
+	return ret;
+}
+
+static void
+usage(const char *prog)
+{
+	printf("%s -i IFNAME\n", prog);
+}
+
+int main(int argc, char **argv)
+{
+	const char *ifname = "ens4";
+	int opt;
+
+	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+		switch (opt) {
+		case 'h':
+			usage(argv[0]);
+			return 0;
+
+		case 'i':
+			ifname = optarg;
+			break;
+
+		default:
+			printf("    Unrecognized option %c\n", opt);
+			usage(argv[0]);
+			return -1;
+		}
+	}
+
+	{
+		int fd;
+		int ret;
+		fd = open("/dev/netmap", O_RDWR);
+		if (fd < 0) {
+			perror("open(/dev/netmap)");
+			return fd;
+		}
+		ret = port_info_get(fd, ifname);
+		return ret;
+	}
+
+	return 0;
+}

From 746800d0fdd0645ff92cc556b65a33098ca9efe4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:36:22 +0100
Subject: [PATCH 0611/2207] utils: ctrl-api-test: introduce array of test
 functions

---
 utils/ctrl-api-test.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 650ecbe1f..8118c2ec0 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -9,7 +9,9 @@
 #include 
 #include 
 
-int
+typedef int (*testfunc_t)(int fd, const char *ifname);
+
+static int
 port_info_get(int fd, const char *ifname)
 {
 	struct nmreq_port_info_get req;
@@ -22,6 +24,7 @@ port_info_get(int fd, const char *ifname)
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		return ret;
 	}
 	printf("nr_offset %lu\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
@@ -40,9 +43,13 @@ usage(const char *prog)
 	printf("%s -i IFNAME\n", prog);
 }
 
-int main(int argc, char **argv)
+static testfunc_t tests[] = {port_info_get, NULL};
+
+int
+main(int argc, char **argv)
 {
 	const char *ifname = "ens4";
+	unsigned int i;
 	int opt;
 
 	while ((opt = getopt(argc, argv, "hi:")) != -1) {
@@ -62,7 +69,7 @@ int main(int argc, char **argv)
 		}
 	}
 
-	{
+	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
 		int fd;
 		int ret;
 		fd = open("/dev/netmap", O_RDWR);
@@ -70,7 +77,7 @@ int main(int argc, char **argv)
 			perror("open(/dev/netmap)");
 			return fd;
 		}
-		ret = port_info_get(fd, ifname);
+		ret = tests[i](fd, ifname);
 		return ret;
 	}
 

From d2b6ece5db50836b353681b879c57f21553d608a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 12:55:07 +0100
Subject: [PATCH 0612/2207] utils: ctrl-api-test: add nmreq_register basic test

---
 utils/ctrl-api-test.c | 65 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8118c2ec0..67a606984 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,22 +1,25 @@
-#include 
-#include 
 #include 
-#include 
 #include 
-#include 
-#include 
 #include 
-#include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 typedef int (*testfunc_t)(int fd, const char *ifname);
 
+/* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
 port_info_get(int fd, const char *ifname)
 {
 	struct nmreq_port_info_get req;
 	int ret;
 
+	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ifname);
+
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
@@ -34,7 +37,46 @@ port_info_get(int fd, const char *ifname)
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	return ret;
+	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
+			       req.nr_tx_rings && req.nr_rx_rings &&
+			       req.nr_tx_rings
+		       ? 0
+		       : -1;
+}
+
+/* Single NETMAP_REQ_REGISTER, no use. */
+static int
+port_register(int fd, const char *ifname)
+{
+	struct nmreq_register req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	req.nr_mode	   = NR_REG_NIC_SW;
+	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		return ret;
+	}
+	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_tx_slots %u\n", req.nr_tx_slots);
+	printf("nr_rx_slots %u\n", req.nr_rx_slots);
+	printf("nr_tx_rings %u\n", req.nr_tx_rings);
+	printf("nr_rx_rings %u\n", req.nr_rx_rings);
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+
+	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
+			       req.nr_tx_rings && req.nr_rx_rings &&
+			       req.nr_tx_rings && req.nr_pipes == 0 &&
+			       req.nr_extra_bufs == 0
+		       ? 0
+		       : -1;
 }
 
 static void
@@ -43,7 +85,7 @@ usage(const char *prog)
 	printf("%s -i IFNAME\n", prog);
 }
 
-static testfunc_t tests[] = {port_info_get, NULL};
+static testfunc_t tests[] = {port_info_get, port_register};
 
 int
 main(int argc, char **argv)
@@ -69,7 +111,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
+	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
 		int fd;
 		int ret;
 		fd = open("/dev/netmap", O_RDWR);
@@ -78,7 +120,10 @@ main(int argc, char **argv)
 			return fd;
 		}
 		ret = tests[i](fd, ifname);
-		return ret;
+		if (ret) {
+			printf("Test #%d failed\n", i + 1);
+		}
+		printf("Test #%d successful\n", i + 1);
 	}
 
 	return 0;

From e00b8c81cdd0575906632110fada6873d626c318 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 13:06:18 +0100
Subject: [PATCH 0613/2207] vale: nm_bdg_ctl: support optional host rings

---
 sys/dev/netmap/netmap_kern.h |  2 +-
 sys/dev/netmap/netmap_vale.c | 21 +++++++++++++--------
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index aa65b90de..c18e567d8 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -780,7 +780,7 @@ struct netmap_adapter {
 	 *      Called with NMG_LOCK held.
 	 */
 	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *);
-	int (*nm_bdg_ctl)(struct netmap_adapter *, int);
+	int (*nm_bdg_ctl)(struct nmreq_header *, struct netmap_adapter *);
 
 	/* adapter used to attach this adapter to a VALE switch (if any) */
 	struct netmap_vp_adapter *na_vp;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 8529afb9a..7ff4c4fe3 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -514,13 +514,14 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 
 /* nm_bdg_ctl callback for VALE ports */
 static int
-netmap_vp_bdg_ctl(struct netmap_adapter *na, int attach)
+netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 	struct nm_bridge *b = vpna->na_bdg;
 
-	if (attach)
+	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		return 0; /* nothing to do */
+	}
 	if (b) {
 		netmap_set_all_rings(na, 0 /* disable */);
 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
@@ -898,7 +899,7 @@ nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 		/* nop for VALE ports. The bwrap needs to put the hwna
 		 * in netmap mode (see netmap_bwrap_bdg_ctl)
 		 */
-		error = na->nm_bdg_ctl(na, 1);
+		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
 		if (error)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
@@ -947,7 +948,7 @@ nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
 		 */
-		error = na->nm_bdg_ctl(na, 0);
+		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
 	}
 
 	netmap_adapter_put(na);
@@ -2709,13 +2710,15 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
  * directed to hwna.
  */
 static int
-netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
+netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 {
 	struct netmap_priv_d *npriv;
 	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
 	int error = 0;
 
-	if (attach) {
+	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+		struct nmreq_vale_attach *req =
+			(struct nmreq_vale_attach *)hdr;
 		if (NETMAP_OWNED_BY_ANY(na)) {
 			return EBUSY;
 		}
@@ -2727,7 +2730,9 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, /* TODO no-host-rings*/ NR_REG_NIC_SW, 0, 0);
+		error = netmap_do_regif(npriv, na,
+			(req->nr_flags & NETMAP_BDG_HOST) ? NR_REG_NIC_SW : NR_REG_ALL_NIC,
+			0, 0);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
@@ -2741,8 +2746,8 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, int attach)
 		bna->na_kpriv = NULL;
 		na->na_flags &= ~NAF_BUSY;
 	}
-	return error;
 
+	return error;
 }
 
 /* attach a bridge wrapper to the 'real' device */

From 497c7bbfe65861371673d9aec780dd2908b95e11 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 14:59:19 +0100
Subject: [PATCH 0614/2207] utils: ctrl-api-test: fix compilation issue

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 67a606984..f32cdd847 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,8 +1,8 @@
 #include 
 #include 
+#include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 

From 56a4124a864642519bc826f48607caedeb65802e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 15:15:39 +0100
Subject: [PATCH 0615/2207] utils: ctrl-api-test: introduce TestContext

---
 utils/ctrl-api-test.c | 66 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 50 insertions(+), 16 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index f32cdd847..b2f13a0a1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -9,21 +9,43 @@
 #include 
 #include 
 
-typedef int (*testfunc_t)(int fd, const char *ifname);
+struct TestContext {
+	const char	*ifname;
+	uint32_t	nr_tx_slots;	/* slots in tx rings */
+	uint32_t	nr_rx_slots;	/* slots in rx rings */
+	uint16_t	nr_tx_rings;	/* number of tx rings */
+	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	uint16_t	nr_ringid;	/* ring(s) we care about */
+	uint32_t	nr_mode;	/* specify NR_REG_* modes */
+	uint64_t	nr_flags;	/* additional flags (see below) */
+	uint32_t	nr_pipes;	/* number of pipes to create */
+	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
+};
+
+static void
+ctx_reset(struct TestContext *ctx)
+{
+	const char *tmp = ctx->ifname;
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->ifname = tmp;
+}
+
+typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
-port_info_get(int fd, const char *ifname)
+port_info_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_port_info_get req;
 	int ret;
 
-	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ifname);
+	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL)");
@@ -46,18 +68,18 @@ port_info_get(int fd, const char *ifname)
 
 /* Single NETMAP_REQ_REGISTER, no use. */
 static int
-port_register(int fd, const char *ifname)
+port_register(int fd, struct TestContext *ctx)
 {
 	struct nmreq_register req;
 	int ret;
 
-	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ifname);
+	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 	req.nr_mode	   = NR_REG_NIC_SW;
-	strncpy(req.nr_hdr.nr_name, ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL)");
@@ -71,12 +93,20 @@ port_register(int fd, const char *ifname)
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-			       req.nr_tx_rings && req.nr_rx_rings &&
-			       req.nr_tx_rings && req.nr_pipes == 0 &&
-			       req.nr_extra_bufs == 0
-		       ? 0
-		       : -1;
+	return req.nr_memsize &&
+		((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
+		((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
+		((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
+		((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
+		((!ctx->nr_mem_id && req.nr_mem_id) ||
+			(ctx->nr_mem_id == req.nr_mem_id)) &&
+		(ctx->nr_pipes == req.nr_pipes) &&
+		(ctx->nr_extra_bufs == req.nr_extra_bufs)
+		       ? 0 : -1;
 }
 
 static void
@@ -90,10 +120,13 @@ static testfunc_t tests[] = {port_info_get, port_register};
 int
 main(int argc, char **argv)
 {
-	const char *ifname = "ens4";
+	struct TestContext ctx;
 	unsigned int i;
 	int opt;
 
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.ifname = "ens4";
+
 	while ((opt = getopt(argc, argv, "hi:")) != -1) {
 		switch (opt) {
 		case 'h':
@@ -101,7 +134,7 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'i':
-			ifname = optarg;
+			ctx.ifname = optarg;
 			break;
 
 		default:
@@ -119,7 +152,8 @@ main(int argc, char **argv)
 			perror("open(/dev/netmap)");
 			return fd;
 		}
-		ret = tests[i](fd, ifname);
+		ctx_reset(&ctx);
+		ret = tests[i](fd, &ctx);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 		}

From 481fbb8cf1bec4f2667494377335a2863d082290 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 15:34:28 +0100
Subject: [PATCH 0616/2207] utils: ctrl-api-test: test different values of
 nr_mode

---
 utils/ctrl-api-test.c | 47 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b2f13a0a1..8737f1621 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -73,7 +73,9 @@ port_register(int fd, struct TestContext *ctx)
 	struct nmreq_register req;
 	int ret;
 
-	printf("Testing NETMAP_REQ_REGISTER on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
+		"flags=%lx) on '%s'\n", ctx->nr_mode, ctx->nr_ringid,
+		ctx->nr_flags, ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
@@ -92,8 +94,14 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_mode %u\n", req.nr_mode);
+	printf("nr_ringid %u\n", req.nr_ringid);
+	printf("nr_flags %lx\n", req.nr_flags);
 
 	return req.nr_memsize &&
+		(ctx->nr_mode == req.nr_mode) &&
+		(ctx->nr_ringid == req.nr_ringid) &&
+		(ctx->nr_flags == req.nr_flags) &&
 		((!ctx->nr_tx_slots && req.nr_tx_slots) ||
 			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
 		((!ctx->nr_rx_slots && req.nr_rx_slots) ||
@@ -109,13 +117,47 @@ port_register(int fd, struct TestContext *ctx)
 		       ? 0 : -1;
 }
 
+static int
+port_register_hwall_host(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_NIC_SW;
+	return port_register(fd, ctx);
+}
+
+static int
+port_register_host(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_SW;
+	return port_register(fd, ctx);
+}
+
+static int
+port_register_hwall(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	return port_register(fd, ctx);
+}
+
+static int
+port_register_single_ring_couple(int fd, struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ONE_NIC;
+	ctx->nr_ringid = 0;
+	return port_register(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME\n", prog);
 }
 
-static testfunc_t tests[] = {port_info_get, port_register};
+static testfunc_t tests[] = {
+		port_info_get,
+		port_register_hwall_host,
+		port_register_hwall,
+		port_register_host,
+		port_register_single_ring_couple};
 
 int
 main(int argc, char **argv)
@@ -156,6 +198,7 @@ main(int argc, char **argv)
 		ret = tests[i](fd, &ctx);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
+			return ret;
 		}
 		printf("Test #%d successful\n", i + 1);
 	}

From cfc0b0d98bae7f884e8cdc7de1209c70df78049b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 16:07:39 +0100
Subject: [PATCH 0617/2207] utils: ctrl-api-test: add tests for VALE_ATTACH and
 VALE_DETACH

---
 sys/net/netmap.h      |  2 +-
 utils/ctrl-api-test.c | 85 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 75 insertions(+), 12 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 857dd23fa..1fcd37b96 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -533,7 +533,7 @@ struct nmreq_vale_attach {
 	struct nmreq_header nr_hdr;
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
-#define NETMAP_BDG_HOST		0x1	/* attach the host stack */
+#define NETMAP_BDG_HOST		0x1	/* also  attach the host rings */
 };
 
 /*
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8737f1621..55b96c172 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -11,6 +11,7 @@
 
 struct TestContext {
 	const char	*ifname;
+	const char	*bdgname;
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -26,9 +27,11 @@ struct TestContext {
 static void
 ctx_reset(struct TestContext *ctx)
 {
-	const char *tmp = ctx->ifname;
+	const char *tmp1 = ctx->ifname;
+	const char *tmp2 = ctx->bdgname;
 	memset(ctx, 0, sizeof(*ctx));
-	ctx->ifname = tmp;
+	ctx->ifname = tmp1;
+	ctx->bdgname = tmp2;
 }
 
 typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
@@ -60,10 +63,8 @@ port_info_get(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-			       req.nr_tx_rings && req.nr_rx_rings &&
-			       req.nr_tx_rings
-		       ? 0
-		       : -1;
+		req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings
+		       ? 0 : -1;
 }
 
 /* Single NETMAP_REQ_REGISTER, no use. */
@@ -80,7 +81,16 @@ port_register(int fd, struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	req.nr_mode	   = NR_REG_NIC_SW;
+	req.nr_mem_id	   = ctx->nr_mem_id;
+	req.nr_mode	   = ctx->nr_mode;
+	req.nr_ringid	   = ctx->nr_ringid;
+	req.nr_flags	   = ctx->nr_flags;
+	req.nr_tx_slots	   = ctx->nr_tx_slots;
+	req.nr_rx_slots	   = ctx->nr_rx_slots;
+	req.nr_tx_rings	   = ctx->nr_tx_rings;
+	req.nr_rx_rings	   = ctx->nr_rx_rings;
+	req.nr_pipes	   = ctx->nr_pipes;
+	req.nr_extra_bufs  = ctx->nr_extra_bufs;
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
@@ -94,9 +104,6 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
-	printf("nr_mode %u\n", req.nr_mode);
-	printf("nr_ringid %u\n", req.nr_ringid);
-	printf("nr_flags %lx\n", req.nr_flags);
 
 	return req.nr_memsize &&
 		(ctx->nr_mode == req.nr_mode) &&
@@ -146,6 +153,58 @@ port_register_single_ring_couple(int fd, struct TestContext *ctx)
 	return port_register(fd, ctx);
 }
 
+/* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
+static int
+vale_attach_detach(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_attach req;
+	struct nmreq_vale_detach dreq;
+	char vpname[256];
+	int result = 0;
+	int ret;
+
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
+	req.nr_mem_id = ctx->nr_mem_id;
+	req.nr_flags = ctx->nr_flags;
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
+		return ret;
+	}
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+
+	result = ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
+			(ctx->nr_mem_id == req.nr_mem_id)) &&
+		(ctx->nr_flags == req.nr_flags)
+		       ? 0 : -1;
+
+	memset(&dreq, 0, sizeof(dreq));
+	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
+	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	ret = ioctl(fd, NIOCCTRL, &dreq);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
+		if (result == 0) {
+			result = ret;
+		}
+	}
+
+	return result;
+}
+
+static int
+vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
+{
+	ctx->nr_flags = NETMAP_BDG_HOST;
+	return vale_attach_detach(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -157,7 +216,9 @@ static testfunc_t tests[] = {
 		port_register_hwall_host,
 		port_register_hwall,
 		port_register_host,
-		port_register_single_ring_couple};
+		port_register_single_ring_couple,
+		vale_attach_detach,
+		vale_attach_detach_host_rings};
 
 int
 main(int argc, char **argv)
@@ -168,6 +229,7 @@ main(int argc, char **argv)
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ifname = "ens4";
+	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:")) != -1) {
 		switch (opt) {
@@ -201,6 +263,7 @@ main(int argc, char **argv)
 			return ret;
 		}
 		printf("Test #%d successful\n", i + 1);
+		close(fd);
 	}
 
 	return 0;

From 1522ce3d42001e1b4e78e4d15db4d5a84f0fdc68 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 16:20:50 +0100
Subject: [PATCH 0618/2207] utils: ctrl-api-test: add -j argument

---
 utils/ctrl-api-test.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 55b96c172..33ad1622b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -208,7 +208,7 @@ vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 static void
 usage(const char *prog)
 {
-	printf("%s -i IFNAME\n", prog);
+	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
 static testfunc_t tests[] = {
@@ -225,13 +225,14 @@ main(int argc, char **argv)
 {
 	struct TestContext ctx;
 	unsigned int i;
+	int j = -1;
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ifname = "ens4";
 	ctx.bdgname = "vale1x2";
 
-	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -241,6 +242,10 @@ main(int argc, char **argv)
 			ctx.ifname = optarg;
 			break;
 
+		case 'j':
+			j = atoi(optarg);
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -251,6 +256,9 @@ main(int argc, char **argv)
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
 		int fd;
 		int ret;
+		if (j > 0 && (unsigned)j != i+1) {
+			continue;
+		}
 		fd = open("/dev/netmap", O_RDWR);
 		if (fd < 0) {
 			perror("open(/dev/netmap)");

From b7130d8c4797c6bdbd999e15b83cd197c0f2a6bc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 16:56:23 +0100
Subject: [PATCH 0619/2207] utils: ctrl-api-test: fix register test on nr_pipes

---
 utils/ctrl-api-test.c | 57 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 51 insertions(+), 6 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 33ad1622b..5bb6f2857 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -22,8 +22,10 @@ struct TestContext {
 	uint64_t	nr_flags;	/* additional flags (see below) */
 	uint32_t	nr_pipes;	/* number of pipes to create */
 	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
+	uint32_t	nr_hdr_len;
 };
 
+#if 0
 static void
 ctx_reset(struct TestContext *ctx)
 {
@@ -33,6 +35,7 @@ ctx_reset(struct TestContext *ctx)
 	ctx->ifname = tmp1;
 	ctx->bdgname = tmp2;
 }
+#endif
 
 typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
 
@@ -104,6 +107,8 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_pipes %u\n", req.nr_pipes);
+	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
 	return req.nr_memsize &&
 		(ctx->nr_mode == req.nr_mode) &&
@@ -119,7 +124,7 @@ port_register(int fd, struct TestContext *ctx)
 			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
 		((!ctx->nr_mem_id && req.nr_mem_id) ||
 			(ctx->nr_mem_id == req.nr_mem_id)) &&
-		(ctx->nr_pipes == req.nr_pipes) &&
+		(!ctx->nr_pipes || (ctx->nr_pipes == req.nr_pipes)) &&
 		(ctx->nr_extra_bufs == req.nr_extra_bufs)
 		       ? 0 : -1;
 }
@@ -164,8 +169,8 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
-	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 
+	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
@@ -184,6 +189,7 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 		(ctx->nr_flags == req.nr_flags)
 		       ? 0 : -1;
 
+	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	memset(&dreq, 0, sizeof(dreq));
 	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
 	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
@@ -205,6 +211,43 @@ vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 	return vale_attach_detach(fd, ctx);
 }
 
+/* NETMAP_REQ_PORT_HDR_SET and NETMAP_REQ_PORT_HDR_GET. */
+static int
+port_hdr_set_and_get(int fd, struct TestContext *ctx)
+{
+	struct nmreq_port_hdr req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	req.nr_hdr_len = ctx->nr_hdr_len;
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
+		return ret;
+	}
+	printf("nr_hdr_len %u\n", req.nr_hdr_len);
+
+	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
+}
+
+static int
+vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
+{
+	int ret;
+	ctx->ifname = "vale:eph0";
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	if ((ret = port_register(fd, ctx))) {
+		return ret;
+	}
+	ctx->nr_hdr_len = 12;
+	return port_hdr_set_and_get(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -218,7 +261,8 @@ static testfunc_t tests[] = {
 		port_register_host,
 		port_register_single_ring_couple,
 		vale_attach_detach,
-		vale_attach_detach_host_rings};
+		vale_attach_detach_host_rings,
+		vale_ephemeral_port_hdr_manipulation};
 
 int
 main(int argc, char **argv)
@@ -229,7 +273,7 @@ main(int argc, char **argv)
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname = "ens4";
+	ctx.ifname = "lo";
 	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
@@ -254,6 +298,7 @@ main(int argc, char **argv)
 	}
 
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+		struct TestContext ctxcopy;
 		int fd;
 		int ret;
 		if (j > 0 && (unsigned)j != i+1) {
@@ -264,8 +309,8 @@ main(int argc, char **argv)
 			perror("open(/dev/netmap)");
 			return fd;
 		}
-		ctx_reset(&ctx);
-		ret = tests[i](fd, &ctx);
+		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
+		ret = tests[i](fd, &ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 			return ret;

From 05f4bbc93a680fa88181c46210c7c76ed11161d8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 20:08:44 +0100
Subject: [PATCH 0620/2207] ctrl-api-test: add
 vale_ephemeral_port_hdr_manipulation() test

---
 utils/ctrl-api-test.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5bb6f2857..a37caf1f5 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -211,7 +211,8 @@ vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 	return vale_attach_detach(fd, ctx);
 }
 
-/* NETMAP_REQ_PORT_HDR_SET and NETMAP_REQ_PORT_HDR_GET. */
+/* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
+ * to check that we get the same value. */
 static int
 port_hdr_set_and_get(int fd, struct TestContext *ctx)
 {
@@ -230,6 +231,19 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
 	}
+
+	if (req.nr_hdr_len != ctx->nr_hdr_len) {
+		return -1;
+	}
+
+	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+	req.nr_hdr_len = 0;
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
+		return ret;
+	}
 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
 
 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
@@ -244,8 +258,20 @@ vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 	if ((ret = port_register(fd, ctx))) {
 		return ret;
 	}
+	/* Try to set and get all the acceptable values. */
 	ctx->nr_hdr_len = 12;
-	return port_hdr_set_and_get(fd, ctx);
+	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+		return ret;
+	}
+	ctx->nr_hdr_len = 0;
+	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+		return ret;
+	}
+	ctx->nr_hdr_len = 10;
+	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+		return ret;
+	}
+	return 0;
 }
 
 static void

From 3a4d2b707b35b6243b0f2c2f72ee548c7abb8ea2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Jan 2018 23:34:31 +0100
Subject: [PATCH 0621/2207] ctrl-api-test: add test for persistent vale ports

---
 utils/ctrl-api-test.c | 178 +++++++++++++++++++++++++++---------------
 1 file changed, 113 insertions(+), 65 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a37caf1f5..d370b8e4e 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -10,19 +10,19 @@
 #include 
 
 struct TestContext {
-	const char	*ifname;
-	const char	*bdgname;
-	uint32_t	nr_tx_slots;	/* slots in tx rings */
-	uint32_t	nr_rx_slots;	/* slots in rx rings */
-	uint16_t	nr_tx_rings;	/* number of tx rings */
-	uint16_t	nr_rx_rings;	/* number of rx rings */
-	uint16_t	nr_mem_id;	/* id of the memory allocator */
-	uint16_t	nr_ringid;	/* ring(s) we care about */
-	uint32_t	nr_mode;	/* specify NR_REG_* modes */
-	uint64_t	nr_flags;	/* additional flags (see below) */
-	uint32_t	nr_pipes;	/* number of pipes to create */
-	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
-	uint32_t	nr_hdr_len;
+	const char *ifname;
+	const char *bdgname;
+	uint32_t nr_tx_slots;   /* slots in tx rings */
+	uint32_t nr_rx_slots;   /* slots in rx rings */
+	uint16_t nr_tx_rings;   /* number of tx rings */
+	uint16_t nr_rx_rings;   /* number of rx rings */
+	uint16_t nr_mem_id;     /* id of the memory allocator */
+	uint16_t nr_ringid;     /* ring(s) we care about */
+	uint32_t nr_mode;       /* specify NR_REG_* modes */
+	uint64_t nr_flags;      /* additional flags (see below) */
+	uint32_t nr_pipes;      /* number of pipes to create */
+	uint32_t nr_extra_bufs; /* number of requested extra buffers */
+	uint32_t nr_hdr_len;
 };
 
 #if 0
@@ -66,8 +66,10 @@ port_info_get(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-		req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings
-		       ? 0 : -1;
+			       req.nr_tx_rings && req.nr_rx_rings &&
+			       req.nr_tx_rings
+		       ? 0
+		       : -1;
 }
 
 /* Single NETMAP_REQ_REGISTER, no use. */
@@ -78,22 +80,22 @@ port_register(int fd, struct TestContext *ctx)
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
-		"flags=%lx) on '%s'\n", ctx->nr_mode, ctx->nr_ringid,
-		ctx->nr_flags, ctx->ifname);
+	       "flags=%lx) on '%s'\n",
+	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	req.nr_mem_id	   = ctx->nr_mem_id;
+	req.nr_mem_id	 = ctx->nr_mem_id;
 	req.nr_mode	   = ctx->nr_mode;
-	req.nr_ringid	   = ctx->nr_ringid;
-	req.nr_flags	   = ctx->nr_flags;
-	req.nr_tx_slots	   = ctx->nr_tx_slots;
-	req.nr_rx_slots	   = ctx->nr_rx_slots;
-	req.nr_tx_rings	   = ctx->nr_tx_rings;
-	req.nr_rx_rings	   = ctx->nr_rx_rings;
-	req.nr_pipes	   = ctx->nr_pipes;
-	req.nr_extra_bufs  = ctx->nr_extra_bufs;
+	req.nr_ringid	 = ctx->nr_ringid;
+	req.nr_flags	  = ctx->nr_flags;
+	req.nr_tx_slots       = ctx->nr_tx_slots;
+	req.nr_rx_slots       = ctx->nr_rx_slots;
+	req.nr_tx_rings       = ctx->nr_tx_rings;
+	req.nr_rx_rings       = ctx->nr_rx_rings;
+	req.nr_pipes	  = ctx->nr_pipes;
+	req.nr_extra_bufs     = ctx->nr_extra_bufs;
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
@@ -110,23 +112,24 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_pipes %u\n", req.nr_pipes);
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
-	return req.nr_memsize &&
-		(ctx->nr_mode == req.nr_mode) &&
-		(ctx->nr_ringid == req.nr_ringid) &&
-		(ctx->nr_flags == req.nr_flags) &&
-		((!ctx->nr_tx_slots && req.nr_tx_slots) ||
-			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
-		((!ctx->nr_rx_slots && req.nr_rx_slots) ||
-			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
-		((!ctx->nr_tx_rings && req.nr_tx_rings) ||
-			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
-		((!ctx->nr_rx_rings && req.nr_rx_rings) ||
-			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
-		((!ctx->nr_mem_id && req.nr_mem_id) ||
-			(ctx->nr_mem_id == req.nr_mem_id)) &&
-		(!ctx->nr_pipes || (ctx->nr_pipes == req.nr_pipes)) &&
-		(ctx->nr_extra_bufs == req.nr_extra_bufs)
-		       ? 0 : -1;
+	return req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
+			       (ctx->nr_ringid == req.nr_ringid) &&
+			       (ctx->nr_flags == req.nr_flags) &&
+			       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+				(ctx->nr_tx_slots == req.nr_tx_slots)) &&
+			       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+				(ctx->nr_rx_slots == req.nr_rx_slots)) &&
+			       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+				(ctx->nr_tx_rings == req.nr_tx_rings)) &&
+			       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+				(ctx->nr_rx_rings == req.nr_rx_rings)) &&
+			       ((!ctx->nr_mem_id && req.nr_mem_id) ||
+				(ctx->nr_mem_id == req.nr_mem_id)) &&
+			       (!ctx->nr_pipes ||
+				(ctx->nr_pipes == req.nr_pipes)) &&
+			       (ctx->nr_extra_bufs == req.nr_extra_bufs)
+		       ? 0
+		       : -1;
 }
 
 static int
@@ -153,7 +156,7 @@ port_register_hwall(int fd, struct TestContext *ctx)
 static int
 port_register_single_ring_couple(int fd, struct TestContext *ctx)
 {
-	ctx->nr_mode = NR_REG_ONE_NIC;
+	ctx->nr_mode   = NR_REG_ONE_NIC;
 	ctx->nr_ringid = 0;
 	return port_register(fd, ctx);
 }
@@ -176,8 +179,8 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	req.nr_mem_id = ctx->nr_mem_id;
-	req.nr_flags = ctx->nr_flags;
-	ret = ioctl(fd, NIOCCTRL, &req);
+	req.nr_flags  = ctx->nr_flags;
+	ret	   = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -185,15 +188,16 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	result = ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
-			(ctx->nr_mem_id == req.nr_mem_id)) &&
-		(ctx->nr_flags == req.nr_flags)
-		       ? 0 : -1;
+		  (ctx->nr_mem_id == req.nr_mem_id)) &&
+				 (ctx->nr_flags == req.nr_flags)
+			 ? 0
+			 : -1;
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	memset(&dreq, 0, sizeof(dreq));
 	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
 	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	ret = ioctl(fd, NIOCCTRL, &dreq);
+	ret		       = ioctl(fd, NIOCCTRL, &dreq);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		if (result == 0) {
@@ -226,7 +230,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	req.nr_hdr_len = ctx->nr_hdr_len;
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret	    = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -238,8 +242,8 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-	req.nr_hdr_len = 0;
-	ret = ioctl(fd, NIOCCTRL, &req);
+	req.nr_hdr_len	= 0;
+	ret		      = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -253,7 +257,7 @@ static int
 vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 {
 	int ret;
-	ctx->ifname = "vale:eph0";
+	ctx->ifname  = "vale:eph0";
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	if ((ret = port_register(fd, ctx))) {
 		return ret;
@@ -274,21 +278,65 @@ vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 	return 0;
 }
 
+static int
+vale_persistent_port(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_newif req;
+	struct nmreq_vale_delif dreq;
+	int result;
+	int ret;
+
+	ctx->ifname = "per4";
+
+	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	req.nr_mem_id   = ctx->nr_mem_id;
+	req.nr_tx_slots = ctx->nr_tx_slots;
+	req.nr_rx_slots = ctx->nr_rx_slots;
+	req.nr_tx_rings = ctx->nr_tx_rings;
+	req.nr_rx_rings = ctx->nr_rx_rings;
+	ret		= ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
+		return ret;
+	}
+
+	result = vale_attach_detach(fd, ctx);
+
+	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
+	memset(&dreq, 0, sizeof(dreq));
+	memcpy(&dreq.nr_hdr, &req.nr_hdr, sizeof(dreq.nr_hdr));
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+	ret		      = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
+		if (result == 0) {
+			result = ret;
+		}
+	}
+
+	return result;
+}
+
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
-static testfunc_t tests[] = {
-		port_info_get,
-		port_register_hwall_host,
-		port_register_hwall,
-		port_register_host,
-		port_register_single_ring_couple,
-		vale_attach_detach,
-		vale_attach_detach_host_rings,
-		vale_ephemeral_port_hdr_manipulation};
+static testfunc_t tests[] = {port_info_get,
+			     port_register_hwall_host,
+			     port_register_hwall,
+			     port_register_host,
+			     port_register_single_ring_couple,
+			     vale_attach_detach,
+			     vale_attach_detach_host_rings,
+			     vale_ephemeral_port_hdr_manipulation,
+			     vale_persistent_port};
 
 int
 main(int argc, char **argv)
@@ -299,7 +347,7 @@ main(int argc, char **argv)
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname = "lo";
+	ctx.ifname  = "lo";
 	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
@@ -327,7 +375,7 @@ main(int argc, char **argv)
 		struct TestContext ctxcopy;
 		int fd;
 		int ret;
-		if (j > 0 && (unsigned)j != i+1) {
+		if (j > 0 && (unsigned)j != i + 1) {
 			continue;
 		}
 		fd = open("/dev/netmap", O_RDWR);

From ba76fa8acb337d4b9c184c3b47faa3eac7c30846 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 10:05:08 +0100
Subject: [PATCH 0622/2207] ctrl-api-test: test for pools_info_get

---
 sys/dev/netmap/netmap.c |  4 ++-
 sys/net/netmap.h        |  5 ++--
 utils/ctrl-api-test.c   | 65 +++++++++++++++++++++++++++++++++++++----
 3 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 76f84a067..8ba0572c9 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2544,7 +2544,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info_get *req =
 				(struct nmreq_pools_info_get *)hdr;
-			/* Get information from the memory allocator */
+			/* Get information from the memory allocator. This
+			 * netmap device must already be bound to a port.
+			 * Note that hdr->nr_name is ignored. */
 			NMG_LOCK();
 			if (priv->np_na && priv->np_na->nm_mem) {
 				struct netmap_mem_d *nmd = priv->np_na->nm_mem;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 1fcd37b96..531e168b6 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -601,8 +601,9 @@ struct nmreq_vale_polling {
 
 /*
  * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
- * Get info about the pools of a memory allocator (used i.e. by
- * a ptnetmap-enabled hypervisor).
+ * Get info about the pools of the memory allocator of the port bound
+ * to a given netmap control device (used i.e. by a ptnetmap-enabled
+ * hypervisor). The nr_hdr.nr_name field is ignored.
  */
 struct nmreq_pools_info_get {
 	struct nmreq_header nr_hdr;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d370b8e4e..2ba5d1f4a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -54,10 +54,10 @@ port_info_get(int fd, struct TestContext *ctx)
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
-		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
-	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_offset 0x%lx\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
@@ -80,7 +80,7 @@ port_register(int fd, struct TestContext *ctx)
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
-	       "flags=%lx) on '%s'\n",
+	       "flags=0x%lx) on '%s'\n",
 	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
@@ -99,10 +99,10 @@ port_register(int fd, struct TestContext *ctx)
 	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
-		perror("ioctl(/dev/netmap, NIOCCTRL)");
+		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
 	}
-	printf("nr_offset %lu\n", req.nr_offset);
+	printf("nr_offset 0x%lx\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
@@ -305,6 +305,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 		return ret;
 	}
 
+	/* Attach the persistent VALE port to a switch and then detach. */
 	result = vale_attach_detach(fd, ctx);
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
@@ -322,6 +323,57 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	return result;
 }
 
+/* Single NETMAP_REQ_POOLS_INFO_GET. */
+static int
+pools_info_get(int fd, struct TestContext *ctx)
+{
+	struct nmreq_pools_info_get req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
+		return ret;
+	}
+	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_if_pool_offset 0x%lx\n", req.nr_if_pool_offset);
+	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
+	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
+	printf("nr_ring_pool_offset 0x%lx\n", req.nr_if_pool_offset);
+	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
+	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
+	printf("nr_buf_pool_offset 0x%lx\n", req.nr_buf_pool_offset);
+	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
+	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
+
+	return req.nr_memsize && req.nr_if_pool_objtotal &&
+		req.nr_if_pool_objsize && req.nr_ring_pool_objtotal &&
+		req.nr_ring_pool_objsize && req.nr_buf_pool_objtotal &&
+		req.nr_buf_pool_objsize ? 0: -1;
+}
+
+static int
+register_and_pools_info_get(int fd, struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mode = NR_REG_ONE_NIC;
+	ret = port_register(fd, ctx);
+	if (ret) {
+		return ret;
+	}
+	ctx->nr_mem_id = 1;
+
+	return pools_info_get(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -336,7 +388,8 @@ static testfunc_t tests[] = {port_info_get,
 			     vale_attach_detach,
 			     vale_attach_detach_host_rings,
 			     vale_ephemeral_port_hdr_manipulation,
-			     vale_persistent_port};
+			     vale_persistent_port,
+			     register_and_pools_info_get};
 
 int
 main(int argc, char **argv)

From efd56b0fe20052c6d9f2fcdff98ecb884068e5b0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 11:10:50 +0100
Subject: [PATCH 0623/2207] utils: ctrl-api-test: fix parsing of -j argument

---
 sys/dev/netmap/netmap_vale.c |  2 +-
 utils/ctrl-api-test.c        | 16 +++++++++++++++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 7ff4c4fe3..176b8b54a 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1227,7 +1227,7 @@ nm_bdg_polling(struct nmreq_vale_polling *req)
 
 	NMG_LOCK();
 	error = netmap_get_bdg_na((struct nmreq_header *)req,
-					&na, NULL, 0);
+					&na, NULL, /*create=*/0);
 	if (na && !error) {
 		if (!nm_is_bwrap(na)) {
 			error = EOPNOTSUPP;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 2ba5d1f4a..4ca011bdb 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -364,6 +364,13 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 {
 	int ret;
 
+	ret = pools_info_get(fd, ctx);
+	if (ret == 0) {
+		printf("Failed: POOLS_INFO_GET didn't fail on unbound "
+			"netmap device\n");
+		return -1;
+	}
+
 	ctx->nr_mode = NR_REG_ONE_NIC;
 	ret = port_register(fd, ctx);
 	if (ret) {
@@ -424,11 +431,18 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (j >= 0) {
+		j--; /* one-based --> zero-based */
+		if (j >= (int)(sizeof(tests) / sizeof(tests[0]))) {
+			printf("Error: Test not in range\n");
+			return -1;
+		}
+	}
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
 		struct TestContext ctxcopy;
 		int fd;
 		int ret;
-		if (j > 0 && (unsigned)j != i + 1) {
+		if (j >= 0 && (unsigned)j != i) {
 			continue;
 		}
 		fd = open("/dev/netmap", O_RDWR);

From 764246f7ed9845c4064e163879d3e0f4f7a7c888 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 11:43:51 +0100
Subject: [PATCH 0624/2207] utils: ctrl-api-test: add test for POLLING_ENABLE
 and POLLING_DISABLE

---
 sys/net/netmap.h      |   4 +-
 utils/ctrl-api-test.c | 120 ++++++++++++++++++++++++++++++++++++------
 2 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 531e168b6..439fe3ff5 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -425,9 +425,9 @@ enum {
 	NETMAP_REQ_VALE_NEWIF,
 	/* Delete a persistent VALE port. */
 	NETMAP_REQ_VALE_DELIF,
-	/* Enable polling kthread on a VALE port. */
+	/* Enable polling kernel thread(s) on an attached VALE port. */
 	NETMAP_REQ_VALE_POLLING_ENABLE,
-	/* Disable polling kthread on a VALE port. */
+	/* Disable polling kernel thread(s) on an attached VALE port. */
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 4ca011bdb..e51ab2e82 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -22,7 +22,11 @@ struct TestContext {
 	uint64_t nr_flags;      /* additional flags (see below) */
 	uint32_t nr_pipes;      /* number of pipes to create */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
-	uint32_t nr_hdr_len;
+
+	uint32_t nr_hdr_len;	/* for PORT_HDR_SET and PORT_HDR_GET */
+
+	uint32_t nr_first_cpu_id;	/* vale polling */
+	uint32_t nr_num_polling_cpus;	/* vale polling */
 };
 
 #if 0
@@ -161,14 +165,12 @@ port_register_single_ring_couple(int fd, struct TestContext *ctx)
 	return port_register(fd, ctx);
 }
 
-/* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
+/* NETMAP_REQ_VALE_ATTACH */
 static int
-vale_attach_detach(int fd, struct TestContext *ctx)
+vale_attach(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
-	struct nmreq_vale_detach dreq;
 	char vpname[256];
-	int result = 0;
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
@@ -187,25 +189,47 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 	}
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	result = ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
+	return ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
 		  (ctx->nr_mem_id == req.nr_mem_id)) &&
 				 (ctx->nr_flags == req.nr_flags)
 			 ? 0
 			 : -1;
+}
+
+/* NETMAP_REQ_VALE_DETACH */
+static int
+vale_detach(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_detach req;
+	char vpname[256];
+	int ret;
+
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
-	memset(&dreq, 0, sizeof(dreq));
-	memcpy(&dreq, &req, sizeof(dreq.nr_hdr));
-	dreq.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	ret		       = ioctl(fd, NIOCCTRL, &dreq);
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
+	ret		       = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
-		if (result == 0) {
-			result = ret;
-		}
+		return ret;
 	}
 
-	return result;
+	return 0;
+}
+
+/* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
+static int
+vale_attach_detach(int fd, struct TestContext *ctx)
+{
+	int ret;
+	if ((ret = vale_attach(fd, ctx))) {
+		return ret;
+	}
+
+	return vale_detach(fd, ctx);
 }
 
 static int
@@ -381,6 +405,71 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	return pools_info_get(fd, ctx);
 }
 
+/* NETMAP_REQ_VALE_POLLING_ENABLE */
+static int
+vale_polling_enable(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_polling req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+	req.nr_mode = ctx->nr_mode;
+	req.nr_first_cpu_id = ctx->nr_first_cpu_id;
+	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
+		return ret;
+	}
+
+	return (req.nr_mode == ctx->nr_mode &&
+		req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
+		req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
+			? 0 : -1;
+}
+
+/* NETMAP_REQ_VALE_POLLING_DISABLE */
+static int
+vale_polling_disable(int fd, struct TestContext *ctx)
+{
+	struct nmreq_vale_polling req;
+	int ret;
+
+	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	req.nr_hdr.nr_version = NETMAP_API;
+	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	ret = ioctl(fd, NIOCCTRL, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int
+vale_polling_enable_disable(int fd, struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+	ctx->nr_num_polling_cpus = 1;
+	ctx->nr_first_cpu_id = 0;
+	if ((ret = vale_polling_enable(fd, ctx))) {
+		return ret;
+	}
+
+	return vale_polling_disable(fd, ctx);
+}
+
 static void
 usage(const char *prog)
 {
@@ -396,7 +485,8 @@ static testfunc_t tests[] = {port_info_get,
 			     vale_attach_detach_host_rings,
 			     vale_ephemeral_port_hdr_manipulation,
 			     vale_persistent_port,
-			     register_and_pools_info_get};
+			     register_and_pools_info_get,
+			     vale_polling_enable_disable};
 
 int
 main(int argc, char **argv)

From 6cbcf9d60246dd720fb1bcfc022155a795007153 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 11:48:43 +0100
Subject: [PATCH 0625/2207] ioctl: let polling enable fail on non-vale ports

---
 sys/dev/netmap/netmap_vale.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 176b8b54a..5356a23ed 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1241,6 +1241,9 @@ nm_bdg_polling(struct nmreq_vale_polling *req)
 				netmap_adapter_put(na);
 		}
 		netmap_adapter_put(na);
+	} else if (!na && !error) {
+		/* Not VALE port. */
+		error = EINVAL;
 	}
 	NMG_UNLOCK();
 

From 46965880b7e6911e58601435dd0a1aacaf9abaf3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 12:09:27 +0100
Subject: [PATCH 0626/2207] utils: ctrl-api-test: vale polling on attached vale
 port

---
 utils/ctrl-api-test.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index e51ab2e82..d6f51c07a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -410,9 +410,11 @@ static int
 vale_polling_enable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	char vpname[256];
 	int ret;
 
-	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
@@ -420,7 +422,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 	req.nr_mode = ctx->nr_mode;
 	req.nr_first_cpu_id = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
@@ -438,14 +440,16 @@ static int
 vale_polling_disable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	char vpname[256];
 	int ret;
 
-	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr.nr_version = NETMAP_API;
 	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
+	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	ret = ioctl(fd, NIOCCTRL, &req);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
@@ -458,16 +462,26 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 static int
 vale_polling_enable_disable(int fd, struct TestContext *ctx)
 {
-	int ret;
+	int ret = 0;
+
+	if ((ret = vale_attach(fd, ctx))) {
+		return ret;
+	}
 
 	ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
 	ctx->nr_num_polling_cpus = 1;
 	ctx->nr_first_cpu_id = 0;
 	if ((ret = vale_polling_enable(fd, ctx))) {
+		vale_detach(fd, ctx);
 		return ret;
 	}
 
-	return vale_polling_disable(fd, ctx);
+	if ((ret = vale_polling_disable(fd, ctx))) {
+		vale_detach(fd, ctx);
+		return ret;
+	}
+
+	return vale_detach(fd, ctx);
 }
 
 static void

From 4ecc4bd251b8eca81796a0f9ed83d31bee8d085b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Jan 2018 12:19:33 +0100
Subject: [PATCH 0627/2207] nm_os_kctx_create: remove ptnetmap-specific cfgtype
 parameter

This was causing VALE_POLLING_ENABLE commands to fail.
---
 LINUX/netmap_linux.c            |  8 +-------
 WINDOWS/netmap_windows.c        |  3 +--
 sys/dev/netmap/netmap_freebsd.c |  8 +-------
 sys/dev/netmap/netmap_kern.h    |  1 -
 sys/dev/netmap/netmap_pt.c      | 13 ++++++++++++-
 sys/dev/netmap/netmap_vale.c    |  2 +-
 6 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 605e3680a..5b0a9c392 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1633,17 +1633,11 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 }
 
 struct nm_kctx *
-nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
-		     void *opaque)
+nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	struct nm_kctx *nmk = NULL;
 	int error;
 
-	if (cfgtype != PTNETMAP_CFGTYPE_QEMU) {
-		D("Unsupported cfgtype %u", cfgtype);
-		return NULL;
-	}
-
 	if (!cfg->use_kthread && cfg->notify_fn == NULL) {
 		D("Error: botify function missing with use_htead == 0");
 		return NULL;
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 16523ab5e..5ca26e600 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -1046,8 +1046,7 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 }
 
 struct nm_kctx *
-nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
-		     void *opaque)
+nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	// TODO
 	return NULL;
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 96caf8468..6a1fcacb7 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1145,16 +1145,10 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 }
 
 struct nm_kctx *
-nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
-		     void *opaque)
+nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	struct nm_kctx *nmk = NULL;
 
-	if (cfgtype != PTNETMAP_CFGTYPE_BHYVE) {
-		D("Unsupported cfgtype %u", cfgtype);
-		return NULL;
-	}
-
 	nmk = malloc(sizeof(*nmk),  M_DEVBUF, M_NOWAIT | M_ZERO);
 	if (!nmk)
 		return NULL;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c18e567d8..e7750937b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2097,7 +2097,6 @@ struct nm_kctx_cfg {
 };
 /* kthread configuration */
 struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
-					unsigned int cfgtype,
 					void *opaque);
 int nm_os_kctx_worker_start(struct nm_kctx *);
 void nm_os_kctx_worker_stop(struct nm_kctx *);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index df2553d44..baf1023a7 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -676,8 +676,19 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
 	struct nm_kctx_cfg nmk_cfg;
 	unsigned int num_rings;
 	uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
+	unsigned int expected_cfgtype = 0;
 	int k;
 
+#if defined(__FreeBSD__)
+	expected_cfgtype = PTNETMAP_CFGTYPE_BHYVE;
+#elif defined(linux)
+	expected_cfgtype = PTNETMAP_CFGTYPE_QEMU;
+#endif
+	if (cfg->cfgtype != expected_cfgtype) {
+		D("Unsupported cfgtype %u", cfg->cfgtype);
+		return EINVAL;
+	}
+
 	num_rings = pth_na->up.num_tx_rings +
 		    pth_na->up.num_rx_rings;
 
@@ -695,7 +706,7 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
 		}
 
 		ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
-			cfg->cfgtype, cfg_entries + k * cfg->entry_size);
+				cfg_entries + k * cfg->entry_size);
 		if (ptns->kctxs[k] == NULL) {
 			goto err;
 		}
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 5356a23ed..f013b7c2b 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1027,7 +1027,7 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
 
 		kcfg.type = i;
 		kcfg.worker_private = t;
-		t->nmk = nm_os_kctx_create(&kcfg, 0, NULL);
+		t->nmk = nm_os_kctx_create(&kcfg, NULL);
 		if (t->nmk == NULL) {
 			goto cleanup;
 		}

From 167aa2fec1ba7a4b1dcbc47012720a11c5880139 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Jan 2018 19:54:08 +0100
Subject: [PATCH 0628/2207] newnmreq: separate request header and body to
 support FreeBSD

---
 LINUX/netmap_linux.c            |  20 +---
 WINDOWS/netmap_windows.c        |   2 +-
 sys/dev/netmap/netmap.c         | 150 ++++++++++++++++++-----------
 sys/dev/netmap/netmap_freebsd.c |   2 +-
 sys/dev/netmap/netmap_kern.h    |  45 +++++----
 sys/dev/netmap/netmap_legacy.c  |  95 ++++++++++--------
 sys/dev/netmap/netmap_monitor.c |  13 ++-
 sys/dev/netmap/netmap_pipe.c    |  13 ++-
 sys/dev/netmap/netmap_pt.c      |   7 +-
 sys/dev/netmap/netmap_vale.c    |  80 +++++++++-------
 sys/net/netmap.h                |  39 +-------
 utils/ctrl-api-test.c           | 164 ++++++++++++++++++--------------
 12 files changed, 337 insertions(+), 293 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 5b0a9c392..9deef237a 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1130,10 +1130,7 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 	union {
 		struct nm_ifreq ifr;
 		struct nmreq nmr;
-		/* It must follow the largest among the nmreq_xyz structs,
-		 * so that there is enough space for any NIOCCTRL request.
-		 * This is asserted by the BUG_ON() below. */
-		struct nmreq_register req;
+		struct nmreq_header hdr;
 	} arg;
 	size_t argsize = 0;
 
@@ -1149,17 +1146,7 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 		argsize = sizeof(arg.nmr);
 		break;
 	case NIOCCTRL: {
-		/* Look at the value of the nr_reqtype field to know
-		 * how much we need to copy from/to userspace. */
-		size_t peeksize = sizeof(arg.req.nr_hdr.nr_version) +
-				sizeof(arg.req.nr_hdr.nr_reqtype);
-		if (copy_from_user(&arg, (void *)data, peeksize) != 0)
-			return -EFAULT;
-		argsize = nmreq_size_by_type(arg.req.nr_hdr.nr_reqtype);
-		BUG_ON(argsize > sizeof(arg));
-		if (argsize == 0) {
-			return -EINVAL;
-		}
+		argsize = sizeof(arg.hdr);
 		break;
 	}
 	}
@@ -1170,7 +1157,8 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 		if (copy_from_user(&arg, (void *)data, argsize) != 0)
 			return -EFAULT;
 	}
-	ret = netmap_ioctl(priv, cmd, (caddr_t)&arg, NULL);
+	ret = netmap_ioctl(priv, cmd, (caddr_t)&arg, NULL,
+			   /*nr_body_is_user=*/1);
 	if (data && copy_to_user((void*)data, &arg, argsize) != 0)
 		return -EFAULT;
 	return -ret;
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 5ca26e600..42d66a7d6 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -565,7 +565,7 @@ ioctlDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 		}
 
 		ret = netmap_ioctl(priv, irpSp->Parameters.DeviceIoControl.IoControlCode,
-			(caddr_t)&arg, NULL);
+			(caddr_t)&arg, NULL, 1);
 		if (NT_SUCCESS(ret)) {
 			if (data && !NT_SUCCESS(copy_to_user((void*)data, &arg, argsize, Irp))) {
 				DbgPrint("Netmap.sys: ioctl failure/cannot copy data to user");
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8ba0572c9..7c55e4740 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1455,9 +1455,11 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  * a reference to it and return a valid *ifp.
  */
 int
-netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
-	      struct ifnet **ifp, struct netmap_mem_d *nmd, int create)
+netmap_get_na(struct nmreq_header *hdr,
+	      struct netmap_adapter **na, struct ifnet **ifp,
+	      struct netmap_mem_d *nmd, int create)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	int error = 0;
 	struct netmap_adapter *ret = NULL;
 	int nmd_ref = 0;
@@ -1465,6 +1467,10 @@ netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	*na = NULL;     /* default return value */
 	*ifp = NULL;
 
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
 	NMG_LOCK_ASSERT();
 
 	/* if the request contain a memid, try to find the
@@ -1490,23 +1496,22 @@ netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	 */
 
 	/* try to see if this is a ptnetmap port */
-	error = netmap_get_pt_host_na(req, na, nmd, create);
+	error = netmap_get_pt_host_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a monitor port */
-	error = netmap_get_monitor_na(req, na, nmd, create);
+	error = netmap_get_monitor_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a pipe port */
-	error = netmap_get_pipe_na(req, na, nmd, create);
+	error = netmap_get_pipe_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
 		goto out;
 
 	/* try to see if this is a bridge port */
-	error = netmap_get_bdg_na((struct nmreq_header *)req,
-					na, nmd, create);
+	error = netmap_get_bdg_na(hdr, na, nmd, create);
 	if (error)
 		goto out;
 
@@ -1519,7 +1524,7 @@ netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
 	 * This may still be a tap, a veth/epair, or even a
 	 * persistent VALE port.
 	 */
-	*ifp = ifunit_ref(req->nr_hdr.nr_name);
+	*ifp = ifunit_ref(hdr->nr_name);
 	if (*ifp == NULL) {
 		error = ENXIO;
 		goto out;
@@ -2230,16 +2235,6 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
-static void
-nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
-				 struct nmreq_register *regreq)
-{
-	bzero(regreq, sizeof(*regreq));
-	memcpy(®req->nr_hdr, hdr, sizeof(regreq->nr_hdr));
-	regreq->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	regreq->nr_hdr.nr_options = NULL;
-}
-
 /*
  * ioctl(2) support for the "netmap" device.
  *
@@ -2254,7 +2249,8 @@ nmreq_register_from_nmreq_header(const struct nmreq_header *hdr,
  * Return 0 on success, errno otherwise.
  */
 int
-netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *td)
+netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+		struct thread *td, int nr_body_is_user)
 {
 	struct mbq q;	/* packets from RX hw queues to host stack */
 	struct netmap_adapter *na = NULL;
@@ -2270,6 +2266,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 	switch (cmd) {
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
+		size_t nr_body_size = nmreq_size_by_type(hdr->nr_reqtype);
+		/* Original hdr->nr_body to user-space pointer. */
+		char *usr_nr_body = NULL;
+
 		if (hdr->nr_version != NETMAP_API) {
 			D("API mismatch for reqtype %d: got %d need %d",
 				hdr->nr_version,
@@ -2281,13 +2281,38 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 			return EINVAL;
 		}
 
+		if ((nr_body_size && hdr->nr_body == NULL) ||
+			(!nr_body_size && hdr->nr_body != NULL)) {
+			/* Request body expected, but not found; or
+			 * request body found but unexpected. */
+			return EINVAL;
+		}
+
+		if (nr_body_is_user && nr_body_size) {
+			char *ker_nr_body;
+
+			usr_nr_body = hdr->nr_body;
+			/* Make a kernel-space copy of the user-space nr_body.
+			 * It's handy to temporarily replace hdr->nr_body with
+			 * a pointer to the kernel-space nr_body. */
+			ker_nr_body = nm_os_malloc(nr_body_size);
+			if (!ker_nr_body) {
+				return ENOMEM;
+			}
+			if (copyin(usr_nr_body, ker_nr_body, nr_body_size)) {
+				nm_os_free(ker_nr_body);
+				return EFAULT;
+			}
+			hdr->nr_body = ker_nr_body;
+		}
+
 		/* Sanitize hdr->nr_name. */
 		hdr->nr_name[sizeof(hdr->nr_name) - 1] = '\0';
 
 		switch (hdr->nr_reqtype) {
 		case NETMAP_REQ_REGISTER: {
 			struct nmreq_register *req =
-				(struct nmreq_register *)hdr;
+				(struct nmreq_register *)hdr->nr_body;
 			/* Protect access to priv from concurrent requests. */
 			NMG_LOCK();
 			do {
@@ -2307,7 +2332,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 					}
 				}
 				/* find the interface and a reference */
-				error = netmap_get_na(req, &na, &ifp, nmd,
+				error = netmap_get_na(hdr, &na, &ifp, nmd,
 						      1 /* create */); /* keep reference */
 				if (error)
 					break;
@@ -2376,7 +2401,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 
 		case NETMAP_REQ_PORT_INFO_GET: {
 			struct nmreq_port_info_get *req =
-				(struct nmreq_port_info_get *)hdr;
+				(struct nmreq_port_info_get *)hdr->nr_body;
 
 			NMG_LOCK();
 			do {
@@ -2386,7 +2411,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 					/* Build a nmreq_register out of the nmreq_port_info_get,
 					 * so that we can call netmap_get_na(). */
 					struct nmreq_register regreq;
-					nmreq_register_from_nmreq_header(hdr, ®req);
+					bzero(®req, sizeof(regreq));
 					regreq.nr_tx_slots = req->nr_tx_slots;
 					regreq.nr_rx_slots = req->nr_rx_slots;
 					regreq.nr_tx_rings = req->nr_tx_rings;
@@ -2394,7 +2419,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 					regreq.nr_mem_id = req->nr_mem_id;
 
 					/* get a refcount */
-					error = netmap_get_na(®req, &na, &ifp, NULL, 1 /* create */);
+					hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+					hdr->nr_body = ®req;
+					error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
+					hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; /* reset type */
+					hdr->nr_body = req; /* reset nr_body */
 					if (error) {
 						na = NULL;
 						ifp = NULL;
@@ -2429,33 +2458,27 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		case NETMAP_REQ_VALE_ATTACH: {
-			struct nmreq_vale_attach *req =
-				(struct nmreq_vale_attach *)hdr;
-			error = nm_bdg_ctl_attach(req);
+			error = nm_bdg_ctl_attach(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_DETACH: {
-			struct nmreq_vale_detach *req =
-				(struct nmreq_vale_detach *)hdr;
-			error = nm_bdg_ctl_detach(req);
+			error = nm_bdg_ctl_detach(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_LIST: {
-			struct nmreq_vale_list *req =
-				(struct nmreq_vale_list *)hdr;
-			error = netmap_bdg_list(req);
+			error = netmap_bdg_list(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_PORT_HDR_SET: {
 			struct nmreq_port_hdr *req =
-				(struct nmreq_port_hdr *)hdr;
+				(struct nmreq_port_hdr *)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
-			nmreq_register_from_nmreq_header(hdr, ®req);
+			bzero(®req, sizeof(regreq));
 			/* For now we only support virtio-net headers, and only for
 			 * VALE ports, but this may change in future. Valid lengths
 			 * for the virtio-net header are 0 (no header), 10 and 12. */
@@ -2466,8 +2489,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 				break;
 			}
 			NMG_LOCK();
-			error = netmap_get_bdg_na((struct nmreq_header *)®req,
-							&na, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = ®req;
+			error = netmap_get_bdg_na(hdr, &na, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+			hdr->nr_body = req;
 			if (na && !error) {
 				struct netmap_vp_adapter *vpna =
 					(struct netmap_vp_adapter *)na;
@@ -2487,15 +2513,19 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		case NETMAP_REQ_PORT_HDR_GET: {
 			/* Get vnet-header length for this netmap port */
 			struct nmreq_port_hdr *req =
-				(struct nmreq_port_hdr *)hdr;
+				(struct nmreq_port_hdr *)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
 			struct ifnet *ifp;
-			nmreq_register_from_nmreq_header(hdr, ®req);
 
+			bzero(®req, sizeof(regreq));
 			NMG_LOCK();
-			error = netmap_get_na(®req, &na, &ifp, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = ®req;
+			error = netmap_get_na(hdr, &na, &ifp, NULL, 0);
+			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+			hdr->nr_body = req;
 			if (na && !error) {
 				req->nr_hdr_len = na->virt_hdr_len;
 			}
@@ -2506,17 +2536,21 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 
 		case NETMAP_REQ_VALE_NEWIF: {
 			struct nmreq_vale_newif *req =
-				(struct nmreq_vale_newif *)hdr;
+				(struct nmreq_vale_newif *)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_vale_newif,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
-			nmreq_register_from_nmreq_header(hdr, ®req);
+			bzero(®req, sizeof(regreq));
 			regreq.nr_tx_slots = req->nr_tx_slots;
 			regreq.nr_rx_slots = req->nr_rx_slots;
 			regreq.nr_tx_rings = req->nr_tx_rings;
 			regreq.nr_rx_rings = req->nr_rx_rings;
 			regreq.nr_mem_id = req->nr_mem_id;
-			error = netmap_vi_create(®req, 0 /* no autodelete */);
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = ®req;
+			error = netmap_vi_create(hdr, 0 /* no autodelete */);
+			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			hdr->nr_body = req;
                         /* Write back to the original struct. */
 			req->nr_tx_slots = regreq.nr_tx_slots;
 			req->nr_rx_slots = regreq.nr_rx_slots;
@@ -2527,23 +2561,19 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		case NETMAP_REQ_VALE_DELIF: {
-			struct nmreq_vale_delif *req =
-				(struct nmreq_vale_delif *)hdr;
-			error = nm_vi_destroy(req->nr_hdr.nr_name);
+			error = nm_vi_destroy(hdr->nr_name);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_POLLING_ENABLE:
 		case NETMAP_REQ_VALE_POLLING_DISABLE: {
-			struct nmreq_vale_polling *req =
-				(struct nmreq_vale_polling *)hdr;
-			error = nm_bdg_polling(req);
+			error = nm_bdg_polling(hdr);
 			break;
 		}
 
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info_get *req =
-				(struct nmreq_pools_info_get *)hdr;
+				(struct nmreq_pools_info_get *)hdr->nr_body;
 			/* Get information from the memory allocator. This
 			 * netmap device must already be bound to a port.
 			 * Note that hdr->nr_name is ignored. */
@@ -2559,10 +2589,22 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread
 		}
 
 		default: {
-			return EINVAL;
+			error = EINVAL;
 			break;
 		}
 		}
+		if (nr_body_is_user && nr_body_size) {
+			KASSERT(usr_nr_body && hdr->nr_body,
+				"nr_body pointers must not be NULL");
+			/* Write back request body to userspace and reset the
+			 * user-space pointer. */
+			if (error == 0 && copyout(hdr->nr_body,
+				usr_nr_body, nr_body_size)) {
+				error = EFAULT;
+			}
+			nm_os_free(hdr->nr_body);
+			hdr->nr_body = usr_nr_body;
+		}
 		break;
 	}
 
@@ -2657,7 +2699,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_ATTACH:
 		return sizeof(struct nmreq_vale_attach);
 	case NETMAP_REQ_VALE_DETACH:
-		return sizeof(struct nmreq_vale_detach);
+		return 0;
 	case NETMAP_REQ_VALE_LIST:
 		return sizeof(struct nmreq_vale_list);
 	case NETMAP_REQ_PORT_HDR_SET:
@@ -2666,14 +2708,14 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_NEWIF:
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
-		return sizeof(struct nmreq_vale_delif);
+		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
 		return sizeof(struct nmreq_pools_info_get);
 	case NETMAP_REQ_VALE_OPS_REGISTER:
-		return sizeof(struct nmreq_vale_ops_register);
+		return 0;
 	}
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 6a1fcacb7..ace44d05e 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1417,7 +1417,7 @@ freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
 			error = ENXIO;
 		goto out;
 	}
-	error = netmap_ioctl(priv, cmd, data, td);
+	error = netmap_ioctl(priv, cmd, data, td, /*nr_body_is_user=*/1);
 out:
 	CURVNET_RESTORE();
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e7750937b..0c98546e8 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1005,16 +1005,16 @@ struct netmap_bwrap_adapter {
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
 };
-int nm_bdg_ctl_attach(struct nmreq_vale_attach *req);
-int nm_bdg_ctl_detach(struct nmreq_vale_detach *req);
-int nm_bdg_polling(struct nmreq_vale_polling *req);
+int nm_bdg_ctl_attach(struct nmreq_header *hdr);
+int nm_bdg_ctl_detach(struct nmreq_header *hdr);
+int nm_bdg_polling(struct nmreq_header *hdr);
 int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
-int netmap_vi_create(struct nmreq_register *, int);
+int netmap_vi_create(struct nmreq_header *hdr, int);
 int nm_vi_destroy(const char *name);
-int netmap_bdg_list(struct nmreq_vale_list *req);
+int netmap_bdg_list(struct nmreq_header *hdr);
 
 #else /* !WITH_VALE */
-#define netmap_vi_create(req, a) (EOPNOTSUPP)
+#define netmap_vi_create(hdr, a) (EOPNOTSUPP)
 #endif /* WITH_VALE */
 
 #ifdef WITH_PIPES
@@ -1412,8 +1412,8 @@ int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 void netmap_do_unregif(struct netmap_priv_d *priv);
 
 u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
-int netmap_get_na(struct nmreq_register *req, struct netmap_adapter **na,
-		  struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
+int netmap_get_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
 void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
@@ -1468,26 +1468,25 @@ int netmap_bdg_config(struct nm_ifreq *nifr);
 /* max number of pipes per device */
 #define NM_MAXPIPES	64	/* XXX this should probably be a sysctl */
 void netmap_pipe_dealloc(struct netmap_adapter *);
-int netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create);
+int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+			struct netmap_mem_d *nmd, int create);
 #else /* !WITH_PIPES */
 #define NM_MAXPIPES	0
 #define netmap_pipe_alloc(_1, _2) 	0
 #define netmap_pipe_dealloc(_1)
-#define netmap_get_pipe_na(nmr, _2, _3, _4)	\
-	({ int role__ = (nmr)->nr_flags & NR_REG_MASK; \
+#define netmap_get_pipe_na(hdr, _2, _3, _4)	\
+	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_flags & NR_REG_MASK; \
 	   (role__ == NR_REG_PIPE_MASTER || 	       \
 	    role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
 #endif
 
 #ifdef WITH_MONITOR
-int netmap_get_monitor_na(struct nmreq_register *req,
-		struct netmap_adapter **na, struct netmap_mem_d *nmd,
-		int create);
+int netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create);
 void netmap_monitor_stop(struct netmap_adapter *na);
 #else
-#define netmap_get_monitor_na(nmr, _2, _3, _4) \
-	((nmr)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
+#define netmap_get_monitor_na(hdr, _2, _3, _4) \
+	(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
 #endif
 
 #ifdef CONFIG_NET_NS
@@ -1508,7 +1507,8 @@ void netmap_fini(void);
 int netmap_get_memory(struct netmap_priv_d* p);
 void netmap_dtor(void *data);
 
-int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
+int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
+		struct thread *, int nr_body_is_user);
 int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			struct thread *td);
 size_t nmreq_size_by_type(uint16_t nr_reqtype);
@@ -2124,9 +2124,8 @@ struct netmap_pt_host_adapter {
 };
 
 /* ptnetmap host-side routines */
-int netmap_get_pt_host_na(struct nmreq_register *req,
-		struct netmap_adapter **na, struct netmap_mem_d * nmd,
-		int create);
+int netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+			struct netmap_mem_d * nmd, int create);
 int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
 
 static inline int
@@ -2135,8 +2134,8 @@ nm_ptnetmap_host_on(struct netmap_adapter *na)
 	return na && na->na_flags & NAF_PTNETMAP_HOST;
 }
 #else /* !WITH_PTNETMAP_HOST */
-#define netmap_get_pt_host_na(nmr, _2, _3, _4) \
-	((nmr)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
+#define netmap_get_pt_host_na(hdr, _2, _3, _4) \
+	(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
 #define ptnetmap_ctl(_1, _2, _3)   EINVAL
 #define nm_ptnetmap_host_on(_1)   EINVAL
 #endif /* !WITH_PTNETMAP_HOST */
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 80e580adb..4eacb982d 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -57,13 +57,22 @@
 static struct nmreq_header *
 nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 {
-	struct nmreq_header *hdr = NULL;
+	struct nmreq_header *hdr = nm_os_malloc(sizeof(*hdr));
+
+	if (hdr == NULL) {
+		goto oom;
+	}
 
 	/* Sanitize nmr->nr_name by adding the string terminator. */
 	if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
 	}
 
+	hdr->nr_version = NETMAP_API; /* new API */
+	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
+	hdr->nr_options = NULL;
+	hdr->nr_body = NULL;
+
 	switch (ioctl_cmd) {
 	case NIOCREGIF: {
 		switch (nmr->nr_cmd) {
@@ -71,7 +80,8 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -104,59 +114,53 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			}
 			req->nr_pipes = nmr->nr_arg1;
 			req->nr_extra_bufs = nmr->nr_arg3;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_ATTACH: {
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 			req->nr_mem_id = nmr->nr_arg2;
 			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_DETACH: {
-			struct nmreq_vale_detach *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			hdr = (struct nmreq_header *)req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
 			break;
 		}
 		case NETMAP_BDG_VNET_HDR:
 		case NETMAP_VNET_HDR_GET: {
 			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
+			hdr->nr_body = req;
+			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
 			req->nr_hdr_len = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_NEWIF : {
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
 			req->nr_tx_rings = nmr->nr_tx_rings;
 			req->nr_rx_rings = nmr->nr_rx_rings;
 			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_BDG_DELIF: {
-			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-			hdr = (struct nmreq_header *)req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_DELIF;
 			break;
 		}
 		case NETMAP_BDG_POLLING_ON:
 		case NETMAP_BDG_POLLING_OFF: {
 			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
+			hdr->nr_body = req;
+			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
 			switch (nmr->nr_flags & NR_REG_MASK) {
@@ -172,17 +176,16 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			}
 			req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
 			req->nr_num_polling_cpus = nmr->nr_arg1;
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_POOLS_INFO_GET: {
 			/* We could deny this request similar to ptnetmap requests. */
 			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
 			/* Most of the fields are for output (see
 			 * nmreq_to_legacy). */
-			hdr = (struct nmreq_header *)req;
 			break;
 		}
 		case NETMAP_PT_HOST_CREATE:
@@ -198,15 +201,16 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
 		} else {
 			/* Regular NIOCGINFO. */
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			req->nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			hdr->nr_body = req;
+			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
@@ -214,19 +218,18 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_tx_rings = nmr->nr_tx_rings;
 			req->nr_rx_rings = nmr->nr_rx_rings;
 			req->nr_mem_id = nmr->nr_arg2;
-			hdr = (struct nmreq_header *)req;
 		}
 		break;
 	}
 	}
 
-	KASSERT(hdr != NULL, "Invalid NULL netmap request");
-	hdr->nr_version = NETMAP_API; /* new API */
-	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-
 	return hdr;
 oom:
+	if (hdr) {
+		nm_os_free(hdr);
+	}
 	D("Failed to allocate memory for nmreq_xyz struct");
+
 	return NULL;
 }
 
@@ -244,7 +247,8 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
-		struct nmreq_register *req = (struct nmreq_register *)hdr;
+		struct nmreq_register *req =
+			(struct nmreq_register *)hdr->nr_body;
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -265,7 +269,8 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		break;
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
-		struct nmreq_port_info_get *req = (struct nmreq_port_info_get *)hdr;
+		struct nmreq_port_info_get *req =
+			(struct nmreq_port_info_get *)hdr->nr_body;
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -276,30 +281,32 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		break;
 	}
 	case NETMAP_REQ_VALE_ATTACH: {
-		struct nmreq_vale_attach *req = (struct nmreq_vale_attach *)hdr;
+		struct nmreq_vale_attach *req =
+			(struct nmreq_vale_attach *)hdr->nr_body;
 		nmr->nr_arg2 = req->nr_mem_id;
 		nmr->nr_arg1 = req->nr_flags;
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
-		struct nmreq_vale_detach *req = (struct nmreq_vale_detach *)hdr;
-		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_LIST: {
-		struct nmreq_vale_list *req = (struct nmreq_vale_list *)hdr;
+		struct nmreq_vale_list *req =
+			(struct nmreq_vale_list *)hdr->nr_body;
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
 	}
 	case NETMAP_REQ_PORT_HDR_SET:
 	case NETMAP_REQ_PORT_HDR_GET: {
-		struct nmreq_port_hdr *req = (struct nmreq_port_hdr *)hdr;
+		struct nmreq_port_hdr *req =
+			(struct nmreq_port_hdr *)hdr->nr_body;
 		nmr->nr_arg1 = req->nr_hdr_len;
 		break;
 	}
 	case NETMAP_REQ_VALE_NEWIF: {
-		struct nmreq_vale_newif *req = (struct nmreq_vale_newif *)hdr;
+		struct nmreq_vale_newif *req =
+			(struct nmreq_vale_newif *)hdr->nr_body;
 		nmr->nr_tx_slots = req->nr_tx_slots;
 		nmr->nr_rx_slots = req->nr_rx_slots;
 		nmr->nr_tx_rings = req->nr_tx_rings;
@@ -308,13 +315,12 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		break;
 	}
 	case NETMAP_REQ_VALE_DELIF: {
-		struct nmreq_vale_delif *req = (struct nmreq_vale_delif *)hdr;
-		(void)req;
 		break;
 	}
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
-		struct nmreq_vale_polling *req = (struct nmreq_vale_polling *)hdr;
+		struct nmreq_vale_polling *req =
+			(struct nmreq_vale_polling *)hdr->nr_body;
 		switch (req->nr_mode) {
 		default:
 			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
@@ -334,7 +340,8 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
 		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
 		struct netmap_pools_info pi;
-		struct nmreq_pools_info_get *req = (struct nmreq_pools_info_get *)hdr;
+		struct nmreq_pools_info_get *req =
+			(struct nmreq_pools_info_get *)hdr->nr_body;
 		pi.memsize = req->nr_memsize;
 		pi.memid = req->nr_mem_id;
 		pi.if_pool_offset = req->nr_if_pool_offset;
@@ -373,10 +380,14 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		if (hdr == NULL) { /* out of memory */
 			return ENOMEM;
 		}
-		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td);
+		error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td,
+					/*nr_body_is_user=*/0);
 		if (error == 0) {
 			nmreq_to_legacy(hdr, nmr);
 		}
+		if (hdr->nr_body) {
+			nm_os_free(hdr->nr_body);
+		}
 		nm_os_free(hdr);
 		break;
 	}
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index e6ccfa495..ed25f2f11 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -826,9 +826,10 @@ netmap_monitor_dtor(struct netmap_adapter *na)
 
 /* check if req is a request for a monitor adapter that we can satisfy */
 int
-netmap_get_monitor_na(struct nmreq_register *req, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create)
+netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+			struct netmap_mem_d *nmd, int create)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_monitor_adapter *mna;
@@ -846,16 +847,18 @@ netmap_get_monitor_na(struct nmreq_register *req, struct netmap_adapter **na,
 	}
 	/* this is a request for a monitor adapter */
 
-	ND("flags %x", req->nr_flags);
+	ND("flags %lx", req->nr_flags);
 
-	/* first, try to find the adapter that we want to monitor
+	/* First, try to find the adapter that we want to monitor.
 	 * We use the same req, after we have turned off the monitor flags.
 	 * In this way we can potentially monitor everything netmap understands,
 	 * except other monitors.
 	 */
 	memcpy(&preq, req, sizeof(preq));
 	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
+	hdr->nr_body = &preq;
+	error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
+	hdr->nr_body = req;
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 7c3c624f9..6cd990647 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -527,9 +527,10 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 }
 
 int
-netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
+netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
@@ -547,14 +548,14 @@ netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 
 	/* first, try to find the parent adapter */
 	bzero(&preq, sizeof(preq));
-	memcpy(&preq.nr_hdr.nr_name, req->nr_hdr.nr_name,
-		sizeof(preq.nr_hdr.nr_name));
 	/* pass to parent the requested number of pipes */
 	preq.nr_pipes = req->nr_pipes;
 	for (;;) {
 		int create_error;
 
-		error = netmap_get_na(&preq, &pna, &ifp, nmd, create);
+		hdr->nr_body = &preq;
+		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
+		hdr->nr_body = req;
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -564,7 +565,9 @@ netmap_get_pipe_na(struct nmreq_register *req, struct netmap_adapter **na,
 		ND("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
 		NMG_UNLOCK();
-		create_error = netmap_vi_create(&preq, 1 /* autodelete */);
+		hdr->nr_body = &preq;
+		create_error = netmap_vi_create(hdr, 1 /* autodelete */);
+		hdr->nr_body = req;
 		NMG_LOCK();
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index baf1023a7..5b7f0c7a2 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1159,9 +1159,10 @@ nm_pt_host_dtor(struct netmap_adapter *na)
 
 /* check if nmr is a request for a ptnetmap adapter that we can satisfy */
 int
-netmap_get_pt_host_na(struct nmreq_register *req, struct netmap_adapter **na,
+netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
+    struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
     struct nmreq_register preq;
     struct netmap_adapter *parent; /* target adapter */
     struct netmap_pt_host_adapter *pth_na;
@@ -1187,7 +1188,9 @@ netmap_get_pt_host_na(struct nmreq_register *req, struct netmap_adapter **na,
      */
     memcpy(&preq, req, sizeof(preq));
     preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    error = netmap_get_na(&preq, &parent, &ifp, nmd, create);
+    hdr->nr_body = &preq;
+    error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
+    hdr->nr_body = req;
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index f013b7c2b..d8f450274 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -164,7 +164,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
     "Max batch size to be used in the bridge");
 SYSEND;
 
-static int netmap_vp_create(struct nmreq_register *, struct ifnet *,
+static int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
 static int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 static int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
@@ -623,17 +623,22 @@ nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
  * The interface will be attached to a bridge later.
  */
 int
-netmap_vi_create(struct nmreq_register *req, int autodelete)
+netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct ifnet *ifp;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_mem_d *nmd = NULL;
 	int error;
 
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
 	/* don't include VALE prefix */
-	if (!strncmp(req->nr_hdr.nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
+	if (!strncmp(hdr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
 		return EINVAL;
-	ifp = ifunit_ref(req->nr_hdr.nr_name);
+	ifp = ifunit_ref(hdr->nr_name);
 	if (ifp) { /* already exist, cannot create new one */
 		error = EEXIST;
 		NMG_LOCK();
@@ -646,7 +651,7 @@ netmap_vi_create(struct nmreq_register *req, int autodelete)
 		if_rele(ifp);
 		return error;
 	}
-	error = nm_os_vi_persist(req->nr_hdr.nr_name, &ifp);
+	error = nm_os_vi_persist(hdr->nr_name, &ifp);
 	if (error)
 		return error;
 
@@ -659,7 +664,7 @@ netmap_vi_create(struct nmreq_register *req, int autodelete)
 		}
 	}
 	/* netmap_vp_create creates a struct netmap_vp_adapter */
-	error = netmap_vp_create(req, ifp, nmd, &vpna);
+	error = netmap_vp_create(hdr, ifp, nmd, &vpna);
 	if (error) {
 		D("error %d", error);
 		goto err_1;
@@ -774,8 +779,8 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	ifname = nr_name + b->bdg_namelen + 1;
 	ifp = ifunit_ref(ifname);
 	if (!ifp) {
-		/* Create an ephemeral virtual port
-		 * This block contains all the ephemeral-specific logics
+		/* Create an ephemeral virtual port.
+		 * This block contains all the ephemeral-specific logic.
 		 */
 
 		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
@@ -784,8 +789,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = netmap_vp_create((struct nmreq_register *)hdr,
-					NULL, nmd, &vpna);
+		error = netmap_vp_create(hdr, NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -821,7 +825,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 			/* Check if we need to skip the host rings. */
 			struct nmreq_vale_attach *areq =
-				(struct nmreq_vale_attach *)hdr;
+				(struct nmreq_vale_attach *)hdr->nr_body;
 			if ((areq->nr_flags & NETMAP_BDG_HOST) == 0) {
 				hostna = NULL;
 			}
@@ -858,8 +862,10 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 /* Process NETMAP_REQ_VALE_ATTACH. */
 int
-nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
+nm_bdg_ctl_attach(struct nmreq_header *hdr)
 {
+	struct nmreq_vale_attach *req =
+		(struct nmreq_vale_attach *)hdr->nr_body;
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
 	int error;
@@ -875,12 +881,12 @@ nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 	}
 
 	/* check for existing one */
-	error = netmap_get_bdg_na((struct nmreq_header *)req, &na, nmd, 0);
+	error = netmap_get_bdg_na(hdr, &na, nmd, 0);
 	if (!error) {
 		error = EBUSY;
 		goto unref_exit;
 	}
-	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
+	error = netmap_get_bdg_na(hdr, &na,
 				nmd, 1 /* create if not exists */);
 	if (error) /* no device */
 		goto unlock_exit;
@@ -899,7 +905,7 @@ nm_bdg_ctl_attach(struct nmreq_vale_attach *req)
 		/* nop for VALE ports. The bwrap needs to put the hwna
 		 * in netmap mode (see netmap_bwrap_bdg_ctl)
 		 */
-		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
+		error = na->nm_bdg_ctl(hdr, na);
 		if (error)
 			goto unref_exit;
 		ND("registered %s to netmap-mode", na->name);
@@ -922,14 +928,13 @@ nm_is_bwrap(struct netmap_adapter *na)
 
 /* Process NETMAP_REQ_VALE_DETACH. */
 int
-nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
+nm_bdg_ctl_detach(struct nmreq_header *hdr)
 {
 	struct netmap_adapter *na;
 	int error;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na((struct nmreq_header *)req, &na,
-				NULL, 0 /* don't create */);
+	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
 	}
@@ -948,7 +953,7 @@ nm_bdg_ctl_detach(struct nmreq_vale_detach *req)
 		/* remove the port from bridge. The bwrap
 		 * also needs to put the hwna in normal mode
 		 */
-		error = na->nm_bdg_ctl((struct nmreq_header *)req, na);
+		error = na->nm_bdg_ctl(hdr, na);
 	}
 
 	netmap_adapter_put(na);
@@ -1220,18 +1225,19 @@ nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
 }
 
 int
-nm_bdg_polling(struct nmreq_vale_polling *req)
+nm_bdg_polling(struct nmreq_header *hdr)
 {
+	struct nmreq_vale_polling *req =
+		(struct nmreq_vale_polling *)hdr->nr_body;
 	struct netmap_adapter *na = NULL;
 	int error = 0;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na((struct nmreq_header *)req,
-					&na, NULL, /*create=*/0);
+	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0);
 	if (na && !error) {
 		if (!nm_is_bwrap(na)) {
 			error = EOPNOTSUPP;
-		} else if (req->nr_hdr.nr_reqtype == NETMAP_BDG_POLLING_ON) {
+		} else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) {
 			error = nm_bdg_ctl_polling_start(req, na);
 			if (!error)
 				netmap_adapter_get(na);
@@ -1252,9 +1258,11 @@ nm_bdg_polling(struct nmreq_vale_polling *req)
 
 /* Process NETMAP_REQ_VALE_LIST. */
 int
-netmap_bdg_list(struct nmreq_vale_list *req)
+netmap_bdg_list(struct nmreq_header *hdr)
 {
-	int namelen = strlen(req->nr_hdr.nr_name);
+	struct nmreq_vale_list *req =
+		(struct nmreq_vale_list *)hdr->nr_body;
+	int namelen = strlen(hdr->nr_name);
 	struct nm_bridge *b, *bridges;
 	struct netmap_vp_adapter *vpna;
 	int error = 0, i, j;
@@ -1264,12 +1272,12 @@ netmap_bdg_list(struct nmreq_vale_list *req)
 
 	/* this is used to enumerate bridges and ports */
 	if (namelen) { /* look up indexes of bridge and port */
-		if (strncmp(req->nr_hdr.nr_name, NM_BDG_NAME,
+		if (strncmp(hdr->nr_name, NM_BDG_NAME,
 					strlen(NM_BDG_NAME))) {
 			return EINVAL;
 		}
 		NMG_LOCK();
-		b = nm_find_bridge(req->nr_hdr.nr_name, 0 /* don't create */);
+		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
 		if (!b) {
 			NMG_UNLOCK();
 			return ENOENT;
@@ -1287,7 +1295,7 @@ netmap_bdg_list(struct nmreq_vale_list *req)
 			/* the former and the latter identify a
 			 * virtual port and a NIC, respectively
 			 */
-			if (!strcmp(vpna->up.name, req->nr_hdr.nr_name)) {
+			if (!strcmp(vpna->up.name, hdr->nr_name)) {
 				req->nr_port_idx = i; /* port index */
 				break;
 			}
@@ -1311,7 +1319,7 @@ netmap_bdg_list(struct nmreq_vale_list *req)
 				if (b->bdg_ports[j] == NULL)
 					continue;
 				vpna = b->bdg_ports[j];
-				strncpy(req->nr_hdr.nr_name, vpna->up.name,
+				strncpy(hdr->nr_name, vpna->up.name,
 					(size_t)IFNAMSIZ);
 				error = 0;
 				goto out;
@@ -2200,16 +2208,20 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
  * Only persistent VALE ports have a non-null ifp.
  */
 static int
-netmap_vp_create(struct nmreq_register *req, struct ifnet *ifp,
-		struct netmap_mem_d *nmd,
-		struct netmap_vp_adapter **ret)
+netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
+		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
+	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	int error = 0;
 	u_int npipes = 0;
 	u_int extrabufs = 0;
 
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
 	vpna = nm_os_malloc(sizeof(*vpna));
 	if (vpna == NULL)
 		return ENOMEM;
@@ -2217,7 +2229,7 @@ netmap_vp_create(struct nmreq_register *req, struct ifnet *ifp,
  	na = &vpna->up;
 
 	na->ifp = ifp;
-	strncpy(na->name, req->nr_hdr.nr_name, sizeof(na->name));
+	strncpy(na->name, hdr->nr_name, sizeof(na->name));
 
 	/* bound checking */
 	na->num_tx_rings = req->nr_tx_rings;
@@ -2721,7 +2733,7 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 
 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		struct nmreq_vale_attach *req =
-			(struct nmreq_vale_attach *)hdr;
+			(struct nmreq_vale_attach *)hdr->nr_body;
 		if (NETMAP_OWNED_BY_ANY(na)) {
 			return EBUSY;
 		}
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 439fe3ff5..fb4569b47 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -404,6 +404,7 @@ struct nmreq_header {
 #define NETMAP_REQ_IFNAMSIZ	64
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	struct nmreq_option	*nr_options;	/* command-specific options */
+	void			*nr_body;	/* ptr to nmreq_xyz struct */
 };
 
 enum {
@@ -446,7 +447,6 @@ enum {
  * Bind (register) a netmap port to this control device.
  */
 struct nmreq_register {
-	struct nmreq_header nr_hdr;
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -499,7 +499,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * Demultiplexing is done using the nr_hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
- * specifying only nmreq_header, and copyin the remainder. */
+ * specifying only nmreq_header, and copyin the rest. */
 #define NIOCCTRL	_IOWR('i', 151, struct nmreq_header)
 
 /* The ioctl commands to sync TX/RX netmap rings. */
@@ -512,7 +512,6 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * slots per ring, id of the memory allocator, etc.
  */
 struct nmreq_port_info_get {
-	struct nmreq_header nr_hdr;
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
@@ -530,27 +529,16 @@ struct nmreq_port_info_get {
  * port and the VALE switch are specified through the nr_name argument.
  */
 struct nmreq_vale_attach {
-	struct nmreq_header nr_hdr;
 	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
 	uint16_t	nr_flags;	/* flags (see below) */
 #define NETMAP_BDG_HOST		0x1	/* also  attach the host rings */
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_VALE_DETACH
- * Detach a netmap port from a VALE switch. Both the name of the netmap
- * port and the VALE switch are specified through the nr_name argument.
- */
-struct nmreq_vale_detach {
-	struct nmreq_header nr_hdr;
-};
-
 /*
  * nr_reqtype: NETMAP_REQ_VALE_LIST
  * List the ports of a VALE switch.
  */
 struct nmreq_vale_list {
-	struct nmreq_header nr_hdr;
 	/* Name of the VALE port (valeXXX:YYY) or empty. */
 	uint16_t	nr_bridge_idx;
 	uint16_t	nr_port_idx;
@@ -561,7 +549,6 @@ struct nmreq_vale_list {
  * Set the port header length.
  */
 struct nmreq_port_hdr {
-	struct nmreq_header nr_hdr;
 	uint32_t	nr_hdr_len;
 };
 
@@ -570,7 +557,6 @@ struct nmreq_port_hdr {
  * Create a new persistent VALE port.
  */
 struct nmreq_vale_newif {
-	struct nmreq_header nr_hdr;
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
@@ -578,20 +564,11 @@ struct nmreq_vale_newif {
 	uint16_t	nr_mem_id;	/* id of the memory allocator */
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_VALE_DELIF
- * Delete a persistent VALE port.
- */
-struct nmreq_vale_delif {
-	struct nmreq_header nr_hdr;
-};
-
 /*
  * nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
  * Enable or disable polling kthreads on a VALE port.
  */
 struct nmreq_vale_polling {
-	struct nmreq_header nr_hdr;
 	uint32_t	nr_mode;
 #define NETMAP_POLLING_MODE_SINGLE_CPU 1
 #define NETMAP_POLLING_MODE_MULTI_CPU 2
@@ -606,7 +583,6 @@ struct nmreq_vale_polling {
  * hypervisor). The nr_hdr.nr_name field is ignored.
  */
 struct nmreq_pools_info_get {
-	struct nmreq_header nr_hdr;
 	uint64_t	nr_memsize;
 	uint16_t	nr_mem_id;
 	uint64_t	nr_if_pool_offset;
@@ -620,15 +596,4 @@ struct nmreq_pools_info_get {
 	uint32_t	nr_buf_pool_objsize;
 };
 
-/*
- * nr_reqtype: NETMAP_REQ_VALE_OPS_REGISTER
- * Program a VALE switch by registering custom callbacks (e.g.
- * lookup, config and dtor). This netmap request should not
- * be called from userspace programs, but only by kernel
- * modules.
- */
-struct nmreq_vale_ops_register {
-	struct nmreq_header nr_hdr;
-};
-
 #endif /* _NET_NETMAP_H_ */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d6f51c07a..af43f70b1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -23,10 +23,10 @@ struct TestContext {
 	uint32_t nr_pipes;      /* number of pipes to create */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
 
-	uint32_t nr_hdr_len;	/* for PORT_HDR_SET and PORT_HDR_GET */
+	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
 
-	uint32_t nr_first_cpu_id;	/* vale polling */
-	uint32_t nr_num_polling_cpus;	/* vale polling */
+	uint32_t nr_first_cpu_id;     /* vale polling */
+	uint32_t nr_num_polling_cpus; /* vale polling */
 };
 
 #if 0
@@ -43,20 +43,29 @@ ctx_reset(struct TestContext *ctx)
 
 typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
 
+static void
+nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
+{
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->nr_version = NETMAP_API;
+	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
+}
+
 /* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
 port_info_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_port_info_get req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
@@ -81,27 +90,28 @@ static int
 port_register(int fd, struct TestContext *ctx)
 {
 	struct nmreq_register req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
 	       "flags=0x%lx) on '%s'\n",
 	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	req.nr_mem_id	 = ctx->nr_mem_id;
-	req.nr_mode	   = ctx->nr_mode;
-	req.nr_ringid	 = ctx->nr_ringid;
-	req.nr_flags	  = ctx->nr_flags;
-	req.nr_tx_slots       = ctx->nr_tx_slots;
-	req.nr_rx_slots       = ctx->nr_rx_slots;
-	req.nr_tx_rings       = ctx->nr_tx_rings;
-	req.nr_rx_rings       = ctx->nr_rx_rings;
-	req.nr_pipes	  = ctx->nr_pipes;
-	req.nr_extra_bufs     = ctx->nr_extra_bufs;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	req.nr_mem_id     = ctx->nr_mem_id;
+	req.nr_mode       = ctx->nr_mode;
+	req.nr_ringid     = ctx->nr_ringid;
+	req.nr_flags      = ctx->nr_flags;
+	req.nr_tx_slots   = ctx->nr_tx_slots;
+	req.nr_rx_slots   = ctx->nr_rx_slots;
+	req.nr_tx_rings   = ctx->nr_tx_rings;
+	req.nr_rx_rings   = ctx->nr_rx_rings;
+	req.nr_pipes      = ctx->nr_pipes;
+	req.nr_extra_bufs = ctx->nr_extra_bufs;
+	ret		  = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
@@ -170,19 +180,20 @@ static int
 vale_attach(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
 	req.nr_mem_id = ctx->nr_mem_id;
 	req.nr_flags  = ctx->nr_flags;
-	ret	   = ioctl(fd, NIOCCTRL, &req);
+	ret	   = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -190,28 +201,26 @@ vale_attach(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
-		  (ctx->nr_mem_id == req.nr_mem_id)) &&
-				 (ctx->nr_flags == req.nr_flags)
-			 ? 0
-			 : -1;
+		(ctx->nr_mem_id == req.nr_mem_id)) &&
+			       (ctx->nr_flags == req.nr_flags)
+		       ? 0
+		       : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
 static int
 vale_detach(int fd, struct TestContext *ctx)
 {
-	struct nmreq_vale_detach req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
-	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
-	ret		       = ioctl(fd, NIOCCTRL, &req);
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		return ret;
@@ -245,16 +254,17 @@ static int
 port_hdr_set_and_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_port_hdr req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	req.nr_hdr_len = ctx->nr_hdr_len;
-	ret	    = ioctl(fd, NIOCCTRL, &req);
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -265,9 +275,9 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	}
 
 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-	req.nr_hdr_len	= 0;
-	ret		      = ioctl(fd, NIOCCTRL, &req);
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+	req.nr_hdr_len = 0;
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -281,6 +291,7 @@ static int
 vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
 {
 	int ret;
+
 	ctx->ifname  = "vale:eph0";
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	if ((ret = port_register(fd, ctx))) {
@@ -306,7 +317,7 @@ static int
 vale_persistent_port(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_newif req;
-	struct nmreq_vale_delif dreq;
+	struct nmreq_header hdr;
 	int result;
 	int ret;
 
@@ -314,16 +325,16 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
 	req.nr_mem_id   = ctx->nr_mem_id;
 	req.nr_tx_slots = ctx->nr_tx_slots;
 	req.nr_rx_slots = ctx->nr_rx_slots;
 	req.nr_tx_rings = ctx->nr_tx_rings;
 	req.nr_rx_rings = ctx->nr_rx_rings;
-	ret		= ioctl(fd, NIOCCTRL, &req);
+	ret		= ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		return ret;
@@ -333,10 +344,9 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	result = vale_attach_detach(fd, ctx);
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
-	memset(&dreq, 0, sizeof(dreq));
-	memcpy(&dreq.nr_hdr, &req.nr_hdr, sizeof(dreq.nr_hdr));
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-	ret		      = ioctl(fd, NIOCCTRL, &req);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+	hdr.nr_body    = NULL;
+	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		if (result == 0) {
@@ -352,15 +362,16 @@ static int
 pools_info_get(int fd, struct TestContext *ctx)
 {
 	struct nmreq_pools_info_get req;
+	struct nmreq_header hdr;
 	int ret;
 
 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname);
 
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-	strncpy(req.nr_hdr.nr_name, ctx->ifname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
 		return ret;
@@ -378,9 +389,13 @@ pools_info_get(int fd, struct TestContext *ctx)
 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
 
 	return req.nr_memsize && req.nr_if_pool_objtotal &&
-		req.nr_if_pool_objsize && req.nr_ring_pool_objtotal &&
-		req.nr_ring_pool_objsize && req.nr_buf_pool_objtotal &&
-		req.nr_buf_pool_objsize ? 0: -1;
+			       req.nr_if_pool_objsize &&
+			       req.nr_ring_pool_objtotal &&
+			       req.nr_ring_pool_objsize &&
+			       req.nr_buf_pool_objtotal &&
+			       req.nr_buf_pool_objsize
+		       ? 0
+		       : -1;
 }
 
 static int
@@ -391,12 +406,12 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	ret = pools_info_get(fd, ctx);
 	if (ret == 0) {
 		printf("Failed: POOLS_INFO_GET didn't fail on unbound "
-			"netmap device\n");
+		       "netmap device\n");
 		return -1;
 	}
 
 	ctx->nr_mode = NR_REG_ONE_NIC;
-	ret = port_register(fd, ctx);
+	ret	  = port_register(fd, ctx);
 	if (ret) {
 		return ret;
 	}
@@ -410,20 +425,21 @@ static int
 vale_polling_enable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-	req.nr_mode = ctx->nr_mode;
-	req.nr_first_cpu_id = ctx->nr_first_cpu_id;
+	req.nr_mode		= ctx->nr_mode;
+	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret			= ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
 		return ret;
@@ -432,7 +448,8 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 	return (req.nr_mode == ctx->nr_mode &&
 		req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
 		req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
-			? 0 : -1;
+		       ? 0
+		       : -1;
 }
 
 /* NETMAP_REQ_VALE_POLLING_DISABLE */
@@ -440,17 +457,18 @@ static int
 vale_polling_disable(int fd, struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
+	struct nmreq_header hdr;
 	char vpname[256];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
+	nmreq_hdr_init(&hdr, vpname);
+	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_hdr.nr_version = NETMAP_API;
-	req.nr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	strncpy(req.nr_hdr.nr_name, vpname, sizeof(req.nr_hdr.nr_name));
-	ret = ioctl(fd, NIOCCTRL, &req);
+	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
 		return ret;
@@ -468,9 +486,9 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 		return ret;
 	}
 
-	ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
+	ctx->nr_mode		 = NETMAP_POLLING_MODE_SINGLE_CPU;
 	ctx->nr_num_polling_cpus = 1;
-	ctx->nr_first_cpu_id = 0;
+	ctx->nr_first_cpu_id     = 0;
 	if ((ret = vale_polling_enable(fd, ctx))) {
 		vale_detach(fd, ctx);
 		return ret;

From 07872b33dfe1685f0277ef520e9b896c0c9f404a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 12:00:52 +0100
Subject: [PATCH 0629/2207] pipes: take role from req->nr_mode (was
 req->nr_flags)

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 sys/dev/netmap/netmap_pipe.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0c98546e8..20045156f 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1475,7 +1475,7 @@ int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 #define netmap_pipe_alloc(_1, _2) 	0
 #define netmap_pipe_dealloc(_1)
 #define netmap_get_pipe_na(hdr, _2, _3, _4)	\
-	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_flags & NR_REG_MASK; \
+	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_mode; \
 	   (role__ == NR_REG_PIPE_MASTER || 	       \
 	    role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
 #endif
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 6cd990647..75d181e29 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -536,10 +536,10 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
 	u_int pipe_id;
-	int role = req->nr_flags;
+	int role = req->nr_mode;
 	int error, retries = 0;
 
-	ND("flags %x", req->nr_flags);
+	ND("flags %x", req->nr_mode);
 
 	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
 		ND("not a pipe");

From 6e3bfed067f5e49be5c5d2f3629200bce13270ea Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 15:47:33 +0100
Subject: [PATCH 0630/2207] freebsd: netmap_legacy: add missing include
 directive

---
 sys/dev/netmap/netmap_legacy.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 4eacb982d..75f3e19a8 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -30,6 +30,7 @@
 #include 	/* defines used in kernel.h */
 #include 	/* FIONBIO */
 #include 
+#include 	/* struct socket */
 #include  /* sockaddrs */
 #include 
 #include 

From e48e0f651d8a407bbd646de31deb6e34387df4e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 16:23:02 +0100
Subject: [PATCH 0631/2207] netmap_ioctl: add missing WITH_VALE guards for
 VALE-related operations

---
 sys/dev/netmap/netmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7c55e4740..ec2bceee2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2456,7 +2456,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_UNLOCK();
 			break;
 		}
-
+#ifdef WITH_VALE
 		case NETMAP_REQ_VALE_ATTACH: {
 			error = nm_bdg_ctl_attach(hdr);
 			break;
@@ -2570,7 +2570,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			error = nm_bdg_polling(hdr);
 			break;
 		}
-
+#endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info_get *req =
 				(struct nmreq_pools_info_get *)hdr->nr_body;

From 367d16567ccc660ee58bf048a18fb9570e97b0a8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 16:30:03 +0100
Subject: [PATCH 0632/2207] netmap.h: remove REGOPS, as it should not be
 available from userspace

---
 sys/dev/netmap/netmap.c | 2 --
 sys/net/netmap.h        | 2 --
 2 files changed, 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ec2bceee2..7ae9cbb50 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2714,8 +2714,6 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
 		return sizeof(struct nmreq_pools_info_get);
-	case NETMAP_REQ_VALE_OPS_REGISTER:
-		return 0;
 	}
 	return 0;
 }
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index fb4569b47..dca2950fd 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -432,8 +432,6 @@ enum {
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
-	/* Program a VALE switch by registering custom callbacks. */
-	NETMAP_REQ_VALE_OPS_REGISTER,
 };
 
 enum {

From 8c3fddce3ab07a2882f3f35f6db0ff2dda5fc384 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 21:20:41 +0100
Subject: [PATCH 0633/2207] nmreq_register: remove nr_pipes argument

---
 sys/dev/netmap/netmap_legacy.c | 3 +--
 sys/dev/netmap/netmap_pipe.c   | 6 ++----
 sys/dev/netmap/netmap_vale.c   | 2 --
 sys/net/netmap.h               | 1 -
 utils/ctrl-api-test.c          | 5 -----
 5 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 75f3e19a8..98e0f1046 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -113,7 +113,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
 				req->nr_flags |= NR_DO_RX_POLL;
 			}
-			req->nr_pipes = nmr->nr_arg1;
+			/* nmr->nr_arg1 (nr_pipes) ignored */
 			req->nr_extra_bufs = nmr->nr_arg3;
 			break;
 		}
@@ -265,7 +265,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
 		}
 		nmr->nr_flags = req->nr_mode | req->nr_flags;
-		nmr->nr_arg1 = req->nr_pipes;
 		nmr->nr_arg3 = req->nr_extra_bufs;
 		break;
 	}
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 75d181e29..3d14991aa 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -531,7 +531,6 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
 	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
-	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
@@ -547,12 +546,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	}
 
 	/* first, try to find the parent adapter */
-	bzero(&preq, sizeof(preq));
-	/* pass to parent the requested number of pipes */
-	preq.nr_pipes = req->nr_pipes;
 	for (;;) {
+		struct nmreq_register preq;
 		int create_error;
 
+		bzero(&preq, sizeof(preq)); /* basic register operation */
 		hdr->nr_body = &preq;
 		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
 		hdr->nr_body = req;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index d8f450274..1b819e682 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2247,9 +2247,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	 * but probably can do with some more.
 	 * So let's use 2 as default (when 0 is supplied)
 	 */
-	npipes = req->nr_pipes;
 	nm_bound_var(&npipes, 2, 1, NM_MAXPIPES, NULL);
-	req->nr_pipes = npipes;	/* write back */
 	/* validate extra bufs */
 	nm_bound_var(&extrabufs, 0, 0,
 			128*NM_BDG_MAXSLOTS, NULL);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index dca2950fd..87e98da19 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -479,7 +479,6 @@ struct nmreq_register {
 #define NR_DO_RX_POLL		0x10000
 #define NR_NO_TX_POLL		0x20000
 
-	uint32_t	nr_pipes;	/* number of pipes to create */
 	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
 };
 
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index af43f70b1..94958c2ab 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -20,7 +20,6 @@ struct TestContext {
 	uint16_t nr_ringid;     /* ring(s) we care about */
 	uint32_t nr_mode;       /* specify NR_REG_* modes */
 	uint64_t nr_flags;      /* additional flags (see below) */
-	uint32_t nr_pipes;      /* number of pipes to create */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
 
 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
@@ -109,7 +108,6 @@ port_register(int fd, struct TestContext *ctx)
 	req.nr_rx_slots   = ctx->nr_rx_slots;
 	req.nr_tx_rings   = ctx->nr_tx_rings;
 	req.nr_rx_rings   = ctx->nr_rx_rings;
-	req.nr_pipes      = ctx->nr_pipes;
 	req.nr_extra_bufs = ctx->nr_extra_bufs;
 	ret		  = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -123,7 +121,6 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
-	printf("nr_pipes %u\n", req.nr_pipes);
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
 	return req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
@@ -139,8 +136,6 @@ port_register(int fd, struct TestContext *ctx)
 				(ctx->nr_rx_rings == req.nr_rx_rings)) &&
 			       ((!ctx->nr_mem_id && req.nr_mem_id) ||
 				(ctx->nr_mem_id == req.nr_mem_id)) &&
-			       (!ctx->nr_pipes ||
-				(ctx->nr_pipes == req.nr_pipes)) &&
 			       (ctx->nr_extra_bufs == req.nr_extra_bufs)
 		       ? 0
 		       : -1;

From 83a10caf88f6e2a69603b830c38066481169a870 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Jan 2018 22:23:16 +0100
Subject: [PATCH 0634/2207] vale_attach: use nmreq_register to specify port and
 mode

---
 sys/dev/netmap/netmap_legacy.c | 125 +++++++++++++++++++--------------
 sys/dev/netmap/netmap_vale.c   |  18 +++--
 sys/net/netmap.h               |   6 +-
 sys/net/netmap_legacy.h        |   1 +
 utils/ctrl-api-test.c          |  21 +++---
 5 files changed, 101 insertions(+), 70 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 98e0f1046..f8005c820 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -53,6 +53,43 @@
 #include 
 #include 
 
+static void
+nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
+{
+	req->nr_offset = nmr->nr_offset;
+	req->nr_memsize = nmr->nr_memsize;
+	req->nr_tx_slots = nmr->nr_tx_slots;
+	req->nr_rx_slots = nmr->nr_rx_slots;
+	req->nr_tx_rings = nmr->nr_tx_rings;
+	req->nr_rx_rings = nmr->nr_rx_rings;
+	req->nr_mem_id = nmr->nr_arg2;
+	req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
+	if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
+		/* Convert the older nmr->nr_ringid (original
+		 * netmap control API) to nmr->nr_flags. */
+		u_int regmode = NR_REG_DEFAULT;
+		if (req->nr_ringid & NETMAP_SW_RING) {
+			regmode = NR_REG_SW;
+		} else if (req->nr_ringid & NETMAP_HW_RING) {
+			regmode = NR_REG_ONE_NIC;
+		} else {
+			regmode = NR_REG_ALL_NIC;
+		}
+		nmr->nr_flags = regmode |
+			(nmr->nr_flags & (~NR_REG_MASK));
+	}
+	req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+	req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
+	if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
+		req->nr_flags |= NR_NO_TX_POLL;
+	}
+	if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
+		req->nr_flags |= NR_DO_RX_POLL;
+	}
+	/* nmr->nr_arg1 (nr_pipes) ignored */
+	req->nr_extra_bufs = nmr->nr_arg3;
+}
+
 /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
  * (new API). The new struct is dynamically allocated. */
 static struct nmreq_header *
@@ -83,38 +120,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			req->nr_offset = nmr->nr_offset;
-			req->nr_memsize = nmr->nr_memsize;
-			req->nr_tx_slots = nmr->nr_tx_slots;
-			req->nr_rx_slots = nmr->nr_rx_slots;
-			req->nr_tx_rings = nmr->nr_tx_rings;
-			req->nr_rx_rings = nmr->nr_rx_rings;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
-			if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
-				/* Convert the older nmr->nr_ringid (original
-				 * netmap control API) to nmr->nr_flags. */
-				u_int regmode = NR_REG_DEFAULT;
-				if (req->nr_ringid & NETMAP_SW_RING) {
-					regmode = NR_REG_SW;
-				} else if (req->nr_ringid & NETMAP_HW_RING) {
-					regmode = NR_REG_ONE_NIC;
-				} else {
-					regmode = NR_REG_ALL_NIC;
-				}
-				nmr->nr_flags = regmode |
-					(nmr->nr_flags & (~NR_REG_MASK));
-			}
-			req->nr_mode = nmr->nr_flags & NR_REG_MASK;
-			req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
-			if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
-				req->nr_flags |= NR_NO_TX_POLL;
-			}
-			if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
-				req->nr_flags |= NR_DO_RX_POLL;
-			}
-			/* nmr->nr_arg1 (nr_pipes) ignored */
-			req->nr_extra_bufs = nmr->nr_arg3;
+			nmreq_register_from_legacy(nmr, req);
 			break;
 		}
 		case NETMAP_BDG_ATTACH: {
@@ -122,8 +128,13 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			req->nr_mem_id = nmr->nr_arg2;
-			req->nr_flags = nmr->nr_arg1 & NETMAP_BDG_HOST;
+			nmreq_register_from_legacy(nmr, &req->reg);
+			/* Fix nr_mode, starting from nr_arg1. */
+			if (nmr->nr_arg1 & NETMAP_BDG_HOST) {
+				req->reg.nr_mode = NR_REG_NIC_SW;
+			} else {
+				req->reg.nr_mode = NR_REG_ALL_NIC;
+			}
 			break;
 		}
 		case NETMAP_BDG_DETACH: {
@@ -234,6 +245,27 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	return NULL;
 }
 
+static void
+nmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr)
+{
+	nmr->nr_offset = req->nr_offset;
+	nmr->nr_memsize = req->nr_memsize;
+	nmr->nr_tx_slots = req->nr_tx_slots;
+	nmr->nr_rx_slots = req->nr_rx_slots;
+	nmr->nr_tx_rings = req->nr_tx_rings;
+	nmr->nr_rx_rings = req->nr_rx_rings;
+	nmr->nr_arg2 = req->nr_mem_id;
+	nmr->nr_ringid = req->nr_ringid;
+	if (req->nr_flags & NR_NO_TX_POLL) {
+		nmr->nr_ringid |= NETMAP_NO_TX_POLL;
+	}
+	if (req->nr_flags & NR_DO_RX_POLL) {
+		nmr->nr_ringid |= NETMAP_DO_RX_POLL;
+	}
+	nmr->nr_flags = req->nr_mode | req->nr_flags;
+	nmr->nr_arg3 = req->nr_extra_bufs;
+}
+
 /* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
  * It also frees the nmreq_xyz struct, as it was allocated by
  * nmreq_from_legacy(). */
@@ -250,22 +282,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req =
 			(struct nmreq_register *)hdr->nr_body;
-		nmr->nr_offset = req->nr_offset;
-		nmr->nr_memsize = req->nr_memsize;
-		nmr->nr_tx_slots = req->nr_tx_slots;
-		nmr->nr_rx_slots = req->nr_rx_slots;
-		nmr->nr_tx_rings = req->nr_tx_rings;
-		nmr->nr_rx_rings = req->nr_rx_rings;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_ringid = req->nr_ringid;
-		if (req->nr_flags & NR_NO_TX_POLL) {
-			nmr->nr_ringid |= NETMAP_NO_TX_POLL;
-		}
-		if (req->nr_flags & NR_DO_RX_POLL) {
-			nmr->nr_ringid |= NETMAP_DO_RX_POLL;
-		}
-		nmr->nr_flags = req->nr_mode | req->nr_flags;
-		nmr->nr_arg3 = req->nr_extra_bufs;
+		nmreq_register_to_legacy(req, nmr);
 		break;
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
@@ -283,8 +300,12 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_VALE_ATTACH: {
 		struct nmreq_vale_attach *req =
 			(struct nmreq_vale_attach *)hdr->nr_body;
-		nmr->nr_arg2 = req->nr_mem_id;
-		nmr->nr_arg1 = req->nr_flags;
+		nmreq_register_to_legacy(&req->reg, nmr);
+		if (req->reg.nr_mode == NR_REG_NIC_SW) {
+			nmr->nr_arg1 = NETMAP_BDG_HOST;
+		} else {
+			nmr->nr_arg1 = 0;
+		}
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 1b819e682..51339d411 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -826,7 +826,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			/* Check if we need to skip the host rings. */
 			struct nmreq_vale_attach *areq =
 				(struct nmreq_vale_attach *)hdr->nr_body;
-			if ((areq->nr_flags & NETMAP_BDG_HOST) == 0) {
+			if (areq->reg.nr_mode != NR_REG_NIC_SW) {
 				hostna = NULL;
 			}
 		}
@@ -872,8 +872,8 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr)
 
 	NMG_LOCK();
 
-	if (req->nr_mem_id) {
-		nmd = netmap_mem_find(req->nr_mem_id);
+	if (req->reg.nr_mem_id) {
+		nmd = netmap_mem_find(req->reg.nr_mem_id);
 		if (nmd == NULL) {
 			error = EINVAL;
 			goto unlock_exit;
@@ -2732,6 +2732,13 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		struct nmreq_vale_attach *req =
 			(struct nmreq_vale_attach *)hdr->nr_body;
+		if (req->reg.nr_ringid != 0 ||
+			(req->reg.nr_mode != NR_REG_ALL_NIC &&
+				req->reg.nr_mode != NR_REG_NIC_SW)) {
+			/* We only support attaching all the NIC rings
+			 * and/or the host stack. */
+			return EINVAL;
+		}
 		if (NETMAP_OWNED_BY_ANY(na)) {
 			return EBUSY;
 		}
@@ -2743,9 +2750,8 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na,
-			(req->nr_flags & NETMAP_BDG_HOST) ? NR_REG_NIC_SW : NR_REG_ALL_NIC,
-			0, 0);
+		error = netmap_do_regif(npriv, na, req->reg.nr_mode,
+					req->reg.nr_ringid, req->reg.nr_flags);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 87e98da19..0d9ff99b0 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -524,11 +524,11 @@ struct nmreq_port_info_get {
  * nr_reqtype: NETMAP_REQ_VALE_ATTACH
  * Attach a netmap port to a VALE switch. Both the name of the netmap
  * port and the VALE switch are specified through the nr_name argument.
+ * The attach operation could need to register a port, so at least
+ * the same arguments are available.
  */
 struct nmreq_vale_attach {
-	uint16_t	nr_mem_id;	/* id of the memory allocator to use */
-	uint16_t	nr_flags;	/* flags (see below) */
-#define NETMAP_BDG_HOST		0x1	/* also  attach the host rings */
+	struct nmreq_register reg;
 };
 
 /*
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 9b961a05a..617666026 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -186,6 +186,7 @@ struct nmreq {
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
 #define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
+#define NETMAP_BDG_HOST		1	/* nr_arg1 value for NETMAP_BDG_ATTACH */
 
 	uint16_t	nr_arg2;	/* id of the memory allocator */
 	uint32_t	nr_arg3;	/* req. extra buffers in NIOCREGIF */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 94958c2ab..162caab44 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -186,20 +186,22 @@ vale_attach(int fd, struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 	hdr.nr_body    = &req;
 	memset(&req, 0, sizeof(req));
-	req.nr_mem_id = ctx->nr_mem_id;
-	req.nr_flags  = ctx->nr_flags;
+	req.reg.nr_mem_id = ctx->nr_mem_id;
+	if (ctx->nr_mode == 0) {
+		ctx->nr_mode = NR_REG_ALL_NIC; /* default */;
+	}
+	req.reg.nr_mode = ctx->nr_mode;
 	ret	   = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
 	}
-	printf("nr_mem_id %u\n", req.nr_mem_id);
+	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
 
-	return ((!ctx->nr_mem_id && req.nr_mem_id > 1) ||
-		(ctx->nr_mem_id == req.nr_mem_id)) &&
-			       (ctx->nr_flags == req.nr_flags)
-		       ? 0
-		       : -1;
+	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
+		(ctx->nr_mem_id == req.reg.nr_mem_id)) &&
+			       (ctx->nr_flags == req.reg.nr_flags)
+		       ? 0 : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
@@ -229,6 +231,7 @@ static int
 vale_attach_detach(int fd, struct TestContext *ctx)
 {
 	int ret;
+
 	if ((ret = vale_attach(fd, ctx))) {
 		return ret;
 	}
@@ -239,7 +242,7 @@ vale_attach_detach(int fd, struct TestContext *ctx)
 static int
 vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
 {
-	ctx->nr_flags = NETMAP_BDG_HOST;
+	ctx->nr_mode = NR_REG_NIC_SW;
 	return vale_attach_detach(fd, ctx);
 }
 

From 3971cc4dd7ad1edd39fdbfa58c3c69303e3e6b41 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 10:35:45 +0100
Subject: [PATCH 0635/2207] pipes: allow for pipe syntax in
 nmreq_header.nr_name

---
 sys/dev/netmap/netmap.c        |  7 +++
 sys/dev/netmap/netmap_kern.h   | 12 ++---
 sys/dev/netmap/netmap_legacy.c | 41 ++++++++++++++---
 sys/dev/netmap/netmap_pipe.c   | 81 ++++++++++++++++++++++------------
 sys/net/netmap.h               |  4 +-
 5 files changed, 102 insertions(+), 43 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7ae9cbb50..e454f6aaf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1471,6 +1471,13 @@ netmap_get_na(struct nmreq_header *hdr,
 		return EINVAL;
 	}
 
+	if (req->nr_mode == NR_REG_PIPE_MASTER ||
+			req->nr_mode == NR_REG_PIPE_SLAVE) {
+		/* Do not accept deprecated pipe modes. */
+		D("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
+		return EINVAL;
+	}
+
 	NMG_LOCK_ASSERT();
 
 	/* if the request contain a memid, try to find the
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 20045156f..3474c5934 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -816,7 +816,7 @@ struct netmap_adapter {
 	/* Offset of ethernet header for each packet. */
 	u_int virt_hdr_len;
 
-	char name[64];
+	char name[NETMAP_REQ_IFNAMSIZ]; /* used at least by pipes */
 };
 
 static __inline u_int
@@ -1022,10 +1022,12 @@ int netmap_bdg_list(struct nmreq_header *hdr);
 #define NM_MAXPIPES 	64	/* max number of pipes per adapter */
 
 struct netmap_pipe_adapter {
+	/* pipe identifier is up.name */
 	struct netmap_adapter up;
 
-	u_int id; 	/* pipe identifier */
-	int role;	/* either NR_REG_PIPE_MASTER or NR_REG_PIPE_SLAVE */
+#define NM_PIPE_ROLE_MASTER	0x1
+#define NM_PIPE_ROLE_SLAVE	0x2
+	int role;	/* either NM_PIPE_ROLE_MASTER or NM_PIPE_ROLE_SLAVE */
 
 	struct netmap_adapter *parent; /* adapter that owns the memory */
 	struct netmap_pipe_adapter *peer; /* the other end of the pipe */
@@ -1475,9 +1477,7 @@ int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 #define netmap_pipe_alloc(_1, _2) 	0
 #define netmap_pipe_dealloc(_1)
 #define netmap_get_pipe_na(hdr, _2, _3, _4)	\
-	({ int role__ = ((struct nmreq_register *)hdr->nr_body)->nr_mode; \
-	   (role__ == NR_REG_PIPE_MASTER || 	       \
-	    role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
+	((strchr(hdr->nr_name, '{') != NULL || strchr(hdr->nr_name, '}') != NULL) ? EOPNOTSUPP : 0)
 #endif
 
 #ifdef WITH_MONITOR
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index f8005c820..543da2c8f 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -53,8 +53,9 @@
 #include 
 #include 
 
-static void
-nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
+static int
+nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
+				struct nmreq_register *req)
 {
 	req->nr_offset = nmr->nr_offset;
 	req->nr_memsize = nmr->nr_memsize;
@@ -79,6 +80,22 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
 			(nmr->nr_flags & (~NR_REG_MASK));
 	}
 	req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+	/* Fix nr_name, nr_mode and nr_ringid to handle pipe requests. */
+	if (req->nr_mode == NR_REG_PIPE_MASTER ||
+			req->nr_mode == NR_REG_PIPE_SLAVE) {
+		char suffix[10];
+		snprintf(suffix, sizeof(suffix), "%c%d",
+			(req->nr_mode == NR_REG_PIPE_MASTER ? '{' : '}'),
+			req->nr_ringid);
+		if (strlen(hdr->nr_name) + strlen(suffix)
+					>= sizeof(hdr->nr_name)) {
+			/* No space for the pipe suffix. */
+			return ENOBUFS;
+		}
+		strncat(hdr->nr_name, suffix, strlen(suffix));
+		req->nr_mode = NR_REG_ALL_NIC;
+		req->nr_ringid = 0;
+	}
 	req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
 	if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
 		req->nr_flags |= NR_NO_TX_POLL;
@@ -88,6 +105,8 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_register *req)
 	}
 	/* nmr->nr_arg1 (nr_pipes) ignored */
 	req->nr_extra_bufs = nmr->nr_arg3;
+
+	return 0;
 }
 
 /* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
@@ -106,6 +125,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
 	}
 
+	/* First prepare the request header. */
 	hdr->nr_version = NETMAP_API; /* new API */
 	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
 	hdr->nr_options = NULL;
@@ -120,7 +140,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			nmreq_register_from_legacy(nmr, req);
+			if (nmreq_register_from_legacy(nmr, hdr, req)) {
+				goto oom;
+			}
 			break;
 		}
 		case NETMAP_BDG_ATTACH: {
@@ -128,7 +150,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-			nmreq_register_from_legacy(nmr, &req->reg);
+			if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
+				goto oom;
+			}
 			/* Fix nr_mode, starting from nr_arg1. */
 			if (nmr->nr_arg1 & NETMAP_BDG_HOST) {
 				req->reg.nr_mode = NR_REG_NIC_SW;
@@ -238,6 +262,9 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	return hdr;
 oom:
 	if (hdr) {
+		if (hdr->nr_body) {
+			nm_os_free(hdr->nr_body);
+		}
 		nm_os_free(hdr);
 	}
 	D("Failed to allocate memory for nmreq_xyz struct");
@@ -274,9 +301,9 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
 	int ret = 0;
 	/* Don't bzero 'nmr', we may need the pointers stored into
-	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET). */
-
-	strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET).
+	 * Actually, we may get rid of all the write-backs that are
+	 * not needed. */
 
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 3d14991aa..f18fa4b80 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -127,14 +127,19 @@ netmap_pipe_dealloc(struct netmap_adapter *na)
 
 /* find a pipe endpoint with the given id among the parent's pipes */
 static struct netmap_pipe_adapter *
-netmap_pipe_find(struct netmap_adapter *parent, u_int pipe_id)
+netmap_pipe_find(struct netmap_adapter *parent, const char *pipe_id)
 {
 	int i;
 	struct netmap_pipe_adapter *na;
 
 	for (i = 0; i < parent->na_next_pipe; i++) {
+		const char *na_pipe_id;
 		na = parent->na_pipes[i];
-		if (na->id == pipe_id) {
+		na_pipe_id = strrchr(na->up.name,
+			na->role == NM_PIPE_ROLE_MASTER ? '{' : '}');
+		KASSERT(na_pipe_id != NULL, "Invalid pipe name");
+		++na_pipe_id;
+		if (!strcmp(na_pipe_id, pipe_id)) {
 			return na;
 		}
 	}
@@ -518,7 +523,7 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 		pna->peer_ref = 0;
 		netmap_adapter_put(&pna->peer->up);
 	}
-	if (pna->role == NR_REG_PIPE_MASTER)
+	if (pna->role == NM_PIPE_ROLE_MASTER)
 		netmap_pipe_remove(pna->parent, pna);
 	if (pna->parent_ifp)
 		if_rele(pna->parent_ifp);
@@ -534,26 +539,48 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
-	u_int pipe_id;
-	int role = req->nr_mode;
+	const char *pipe_id = NULL;
+	int role = 0;
 	int error, retries = 0;
+	char *cbra;
 
-	ND("flags %x", req->nr_mode);
-
-	if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
-		ND("not a pipe");
-		return 0;
+	/* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */
+	cbra = strrchr(hdr->nr_name, '{');
+	if (cbra != NULL) {
+		role = NM_PIPE_ROLE_MASTER;
+	} else {
+		cbra = strrchr(hdr->nr_name, '}');
+		if (cbra != NULL) {
+			role = NM_PIPE_ROLE_SLAVE;
+		} else {
+			ND("not a pipe");
+			return 0;
+		}
+	}
+	pipe_id = cbra + 1;
+	if (*pipe_id == '\0' || cbra == hdr->nr_name) {
+		/* Bracket is the last character, so pipe name is missing;
+		 * or bracket is the first character, so base port name
+		 * is missing. */
+		return EINVAL;
+	}
+	if (req->nr_mode != NR_REG_ALL_NIC || req->nr_ringid != 0) {
+		/* Currently we only support opening all the hw rings of
+		 * a pipe. */
+		return EINVAL;
 	}
 
 	/* first, try to find the parent adapter */
 	for (;;) {
-		struct nmreq_register preq;
+		char nr_name_orig[NETMAP_REQ_IFNAMSIZ];
 		int create_error;
 
-		bzero(&preq, sizeof(preq)); /* basic register operation */
-		hdr->nr_body = &preq;
+		/* Temporarily remove the pipe suffix. */
+		strncpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
+		*cbra = '\0';
 		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
-		hdr->nr_body = req;
+		/* Restore the pipe suffix. */
+		strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -562,11 +589,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 		ND("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
+		*cbra = '\0';
 		NMG_UNLOCK();
-		hdr->nr_body = &preq;
 		create_error = netmap_vi_create(hdr, 1 /* autodelete */);
-		hdr->nr_body = req;
 		NMG_LOCK();
+		strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
 				D("failed to create a persistent vale port: %d", create_error);
@@ -583,14 +610,13 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	/* next, lookup the pipe id in the parent list */
 	reqna = NULL;
-	pipe_id = req->nr_ringid;
 	mna = netmap_pipe_find(pna, pipe_id);
 	if (mna) {
 		if (mna->role == role) {
-			ND("found %d directly at %d", pipe_id, mna->parent_slot);
+			ND("found %s directly at %d", pipe_id, mna->parent_slot);
 			reqna = mna;
 		} else {
-			ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
+			ND("found %s indirectly at %d", pipe_id, mna->parent_slot);
 			reqna = mna->peer;
 		}
 		/* the pipe we have found already holds a ref to the parent,
@@ -599,7 +625,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		netmap_unget_na(pna, ifp);
 		goto found;
 	}
-	ND("pipe %d not found, create %d", pipe_id, create);
+	ND("pipe %s not found, create %d", pipe_id, create);
 	if (!create) {
 		error = ENODEV;
 		goto put_out;
@@ -613,10 +639,9 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		error = ENOMEM;
 		goto put_out;
 	}
-	snprintf(mna->up.name, sizeof(mna->up.name), "%s{%d", pna->name, pipe_id);
+	snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id);
 
-	mna->id = pipe_id;
-	mna->role = NR_REG_PIPE_MASTER;
+	mna->role = NM_PIPE_ROLE_MASTER;
 	mna->parent = pna;
 	mna->parent_ifp = ifp;
 
@@ -655,8 +680,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* most fields are the same, copy from master and then fix */
 	*sna = *mna;
 	sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
-	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%d", pna->name, pipe_id);
-	sna->role = NR_REG_PIPE_SLAVE;
+	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
+	sna->role = NM_PIPE_ROLE_SLAVE;
 	error = netmap_attach_common(&sna->up);
 	if (error)
 		goto free_sna;
@@ -673,7 +698,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	if (ifp)
 		if_ref(ifp);
 
-	if (role == NR_REG_PIPE_MASTER) {
+	if (role == NM_PIPE_ROLE_MASTER) {
 		reqna = mna;
 		mna->peer_ref = 1;
 		netmap_adapter_get(&sna->up);
@@ -685,8 +710,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	ND("created master %p and slave %p", mna, sna);
 found:
 
-	ND("pipe %d %s at %p", pipe_id,
-		(reqna->role == NR_REG_PIPE_MASTER ? "master" : "slave"), reqna);
+	ND("pipe %s %s at %p", pipe_id,
+		(reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna);
 	*na = &reqna->up;
 	netmap_adapter_get(*na);
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 0d9ff99b0..d9ee26428 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -488,8 +488,8 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 	NR_REG_SW	= 2,
 	NR_REG_NIC_SW	= 3,
 	NR_REG_ONE_NIC	= 4,
-	NR_REG_PIPE_MASTER = 5,
-	NR_REG_PIPE_SLAVE = 6,
+	NR_REG_PIPE_MASTER = 5, /* deprecated, use "x{y" port name syntax */
+	NR_REG_PIPE_SLAVE = 6,  /* deprecated, use "x}y" port name syntax */
 };
 
 /* A single ioctl number is shared by all the new API command.

From fdcb770126e4622ba3ef58e5e2d462ac4352b34a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 11:08:06 +0100
Subject: [PATCH 0636/2207] remove obsolete usage of NR_REG_PIPE_{MASTER,SLAVE}

---
 sys/dev/netmap/netmap.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e454f6aaf..71e314cd4 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1784,8 +1784,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 	enum txrx t;
 	u_int j;
 
-	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC &&
-                    nr_mode != NR_REG_PIPE_MASTER && nr_mode != NR_REG_PIPE_SLAVE) ||
+	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC) ||
 			nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
 		D("Error: only NR_REG_ALL_NIC supported with netmap passthrough");
 		return EINVAL;
@@ -1798,8 +1797,6 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 		}
 		switch (nr_mode) {
 		case NR_REG_ALL_NIC:
-		case NR_REG_PIPE_MASTER:
-		case NR_REG_PIPE_SLAVE:
 			priv->np_qfirst[t] = 0;
 			priv->np_qlast[t] = nma_get_nrings(na, t);
 			ND("ALL/PIPE: %s %d %d", nm_txrx2str(t),

From f16de13ae9e4f3d2835f16e0d621b79bf13f8ed5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:05:09 +0100
Subject: [PATCH 0637/2207] utils: ctrl-api-test: test pipe syntax

---
 utils/ctrl-api-test.c | 39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 162caab44..21a1f8d4a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -188,10 +188,10 @@ vale_attach(int fd, struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.reg.nr_mem_id = ctx->nr_mem_id;
 	if (ctx->nr_mode == 0) {
-		ctx->nr_mode = NR_REG_ALL_NIC; /* default */;
+		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
 	}
 	req.reg.nr_mode = ctx->nr_mode;
-	ret	   = ioctl(fd, NIOCCTRL, &hdr);
+	ret		= ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -201,7 +201,8 @@ vale_attach(int fd, struct TestContext *ctx)
 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
 		(ctx->nr_mem_id == req.reg.nr_mem_id)) &&
 			       (ctx->nr_flags == req.reg.nr_flags)
-		       ? 0 : -1;
+		       ? 0
+		       : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
@@ -418,6 +419,36 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	return pools_info_get(fd, ctx);
 }
 
+static int
+pipe_master(int fd, struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeid1");
+	ctx->ifname  = pipe_name;
+	ctx->nr_mode = NR_REG_ONE_NIC;
+
+	if (port_register(fd, ctx) == 0) {
+		printf("pipes should not accept NR_REG_ONE_NIC");
+		return -1;
+	}
+	ctx->nr_mode = NR_REG_ALL_NIC;
+
+	return port_register(fd, ctx);
+}
+
+static int
+pipe_slave(int fd, struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s}%s", ctx->ifname, "pipeid2");
+	ctx->ifname  = pipe_name;
+	ctx->nr_mode = NR_REG_ALL_NIC;
+
+	return port_register(fd, ctx);
+}
+
 /* NETMAP_REQ_VALE_POLLING_ENABLE */
 static int
 vale_polling_enable(int fd, struct TestContext *ctx)
@@ -516,6 +547,8 @@ static testfunc_t tests[] = {port_info_get,
 			     vale_ephemeral_port_hdr_manipulation,
 			     vale_persistent_port,
 			     register_and_pools_info_get,
+			     pipe_master,
+			     pipe_slave,
 			     vale_polling_enable_disable};
 
 int

From 56c22adb6dbcbcefe2ff8bd5209ccc7a54fa625a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:10:06 +0100
Subject: [PATCH 0638/2207] remove deprecated (and unused)
 NETMAP_POOLS_INFO_GET

---
 sys/dev/netmap/netmap_legacy.c | 33 ---------------------------------
 sys/net/netmap_legacy.h        | 20 --------------------
 sys/net/netmap_virt.h          |  2 +-
 utils/testmmap.c               | 28 ----------------------------
 4 files changed, 1 insertion(+), 82 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 543da2c8f..3ae856602 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -214,16 +214,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_num_polling_cpus = nmr->nr_arg1;
 			break;
 		}
-		case NETMAP_POOLS_INFO_GET: {
-			/* We could deny this request similar to ptnetmap requests. */
-			struct nmreq_pools_info_get *req = nm_os_malloc(sizeof(*req));
-			if (!req) { goto oom; }
-			hdr->nr_body = req;
-			hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-			/* Most of the fields are for output (see
-			 * nmreq_to_legacy). */
-			break;
-		}
 		case NETMAP_PT_HOST_CREATE:
 		case NETMAP_PT_HOST_DELETE: {
 			D("Netmap passthrough not supported yet");
@@ -384,29 +374,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		nmr->nr_arg1 = req->nr_num_polling_cpus;
 		break;
 	}
-	case NETMAP_REQ_POOLS_INFO_GET: {
-		uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-		struct netmap_pools_info *upi = (struct netmap_pools_info *)(*pp);
-		struct netmap_pools_info pi;
-		struct nmreq_pools_info_get *req =
-			(struct nmreq_pools_info_get *)hdr->nr_body;
-		pi.memsize = req->nr_memsize;
-		pi.memid = req->nr_mem_id;
-		pi.if_pool_offset = req->nr_if_pool_offset;
-		pi.if_pool_objtotal = req->nr_if_pool_objtotal;
-		pi.if_pool_objsize = req->nr_if_pool_objsize;
-		pi.ring_pool_offset = req->nr_ring_pool_offset;
-		pi.ring_pool_objtotal = req->nr_ring_pool_objtotal;
-		pi.ring_pool_objsize = req->nr_ring_pool_objsize;
-		pi.buf_pool_offset = req->nr_buf_pool_offset;
-		pi.buf_pool_objtotal = req->nr_buf_pool_objtotal;
-		pi.buf_pool_objsize = req->nr_buf_pool_objsize;
-		ret = copyout(&pi, upi, sizeof(pi));
-		if (ret) {
-			D("copyout() failed");
-		}
-		break;
-	}
 	}
 
 	return ret;
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 617666026..c3289093b 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -184,7 +184,6 @@ struct nmreq {
 #define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
 #define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
-#define NETMAP_POOLS_INFO_GET	13	/* get memory allocator pools info */
 	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
 #define NETMAP_BDG_HOST		1	/* nr_arg1 value for NETMAP_BDG_ATTACH */
 
@@ -196,25 +195,6 @@ struct nmreq {
 	uint32_t	spare2[1];
 };
 
-/*
- * Structure filled-in by the kernel when asked for allocator info
- * through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
- * ptnetmap. XXX deprecated, 'struct nmreq_pools_info_get' should be used.
- */
-struct netmap_pools_info {
-	uint64_t memsize;	/* same as nmr->nr_memsize */
-	uint32_t memid;		/* same as nmr->nr_arg2 */
-	uint32_t if_pool_offset;
-	uint32_t if_pool_objtotal;
-	uint32_t if_pool_objsize;
-	uint32_t ring_pool_offset;
-	uint32_t ring_pool_objtotal;
-	uint32_t ring_pool_objsize;
-	uint32_t buf_pool_offset;
-	uint32_t buf_pool_objtotal;
-	uint32_t buf_pool_objsize;
-};
-
 #ifdef _WIN32
 /*
  * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 41098a2cb..76f5cbb28 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -111,7 +111,7 @@ struct ptnetmap_cfgentry_bhyve {
 
 /*
  * Pass a pointer to a userspace buffer to be passed to kernelspace for write
- * or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.
+ * or read. Used by NETMAP_PT_HOST_CREATE.
  * XXX deprecated
  */
 static inline void
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 481e41bb1..5da4cea89 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -147,7 +147,6 @@ void do_close()
 #include 
 
 struct nmreq curr_nmr = { .nr_version = NETMAP_API, .nr_flags = NR_REG_ALL_NIC, };
-struct netmap_pools_info curr_pools_info;
 char nmr_name[64];
 
 void parse_nmr_config(char* w, struct nmreq *nmr)
@@ -798,26 +797,6 @@ nmr_arg_error()
 	nmr_arg_unexpected(3);
 }
 
-void
-nmr_pools_info_get()
-{
-	void **pp = (void **)&curr_nmr.nr_arg1;
-	struct netmap_pools_info *upi = *pp;
-
-	printf("arg1+2+3:  %p\n", *pp);
-	printf("    memsize:    %"PRIu64"\n", upi->memsize);
-	printf("    memid:      %"PRIu32"\n", upi->memid);
-	printf("    if off:     %"PRIu32"\n", upi->if_pool_offset);
-	printf("    if tot:     %"PRIu32"\n", upi->if_pool_objtotal);
-	printf("    if siz:     %"PRIu32"\n", upi->if_pool_objsize);
-	printf("    ring off:   %"PRIu32"\n", upi->ring_pool_offset);
-	printf("    ring tot:   %"PRIu32"\n", upi->ring_pool_objtotal);
-	printf("    ring siz:   %"PRIu32"\n", upi->ring_pool_objsize);
-	printf("    buf off:    %"PRIu32"\n", upi->buf_pool_offset);
-	printf("    buf tot:    %"PRIu32"\n", upi->buf_pool_objtotal);
-	printf("    buf siz:    %"PRIu32"\n", upi->buf_pool_objsize);
-}
-
 void
 nmr_arg_extra()
 {
@@ -916,10 +895,6 @@ do_nmr_dump()
 			printf("BDG_POLLING_OFF");
 			arg_interp = nmr_arg_error;
 			break;
-		case NETMAP_POOLS_INFO_GET:
-			printf("POOLS_INFO_GET");
-			arg_interp = nmr_pools_info_get;
-			break;
 		default:
 			printf("???");
 			arg_interp = nmr_arg_error;
@@ -1051,9 +1026,6 @@ do_nmr_cmd()
 		curr_nmr.nr_cmd = NETMAP_PT_HOST_CREATE;
 	} else if (strcmp(arg, "pt-host-delete") == 0) {
 		curr_nmr.nr_cmd = NETMAP_PT_HOST_DELETE;
-	} else if (strcmp(arg, "pools-info-get") == 0) {
-		curr_nmr.nr_cmd = NETMAP_POOLS_INFO_GET;
-		nmreq_pointer_put(&curr_nmr, &curr_pools_info);
 	}
 out:
 	output("cmd=%x", curr_nmr.nr_cmd);

From d3a70d508f699f894259620f71ba6a2c5dbd7f62 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:19:48 +0100
Subject: [PATCH 0639/2207] nmreq_to_legacy: remove useless write-backs

---
 sys/dev/netmap/netmap_legacy.c | 38 +++-------------------------------
 1 file changed, 3 insertions(+), 35 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 3ae856602..a8f510f0e 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -272,14 +272,6 @@ nmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr)
 	nmr->nr_tx_rings = req->nr_tx_rings;
 	nmr->nr_rx_rings = req->nr_rx_rings;
 	nmr->nr_arg2 = req->nr_mem_id;
-	nmr->nr_ringid = req->nr_ringid;
-	if (req->nr_flags & NR_NO_TX_POLL) {
-		nmr->nr_ringid |= NETMAP_NO_TX_POLL;
-	}
-	if (req->nr_flags & NR_DO_RX_POLL) {
-		nmr->nr_ringid |= NETMAP_DO_RX_POLL;
-	}
-	nmr->nr_flags = req->nr_mode | req->nr_flags;
 	nmr->nr_arg3 = req->nr_extra_bufs;
 }
 
@@ -290,11 +282,9 @@ static int
 nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 {
 	int ret = 0;
-	/* Don't bzero 'nmr', we may need the pointers stored into
-	 * nr_arg1, nr_arg2 and nr_arg3 (see NETMAP_REQ_POOLS_INFO_GET).
-	 * Actually, we may get rid of all the write-backs that are
-	 * not needed. */
 
+	/* We only write-back the fields that the user expects to be
+	 * written back. */
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req =
@@ -318,11 +308,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		struct nmreq_vale_attach *req =
 			(struct nmreq_vale_attach *)hdr->nr_body;
 		nmreq_register_to_legacy(&req->reg, nmr);
-		if (req->reg.nr_mode == NR_REG_NIC_SW) {
-			nmr->nr_arg1 = NETMAP_BDG_HOST;
-		} else {
-			nmr->nr_arg1 = 0;
-		}
 		break;
 	}
 	case NETMAP_REQ_VALE_DETACH: {
@@ -352,26 +337,9 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 		nmr->nr_arg2 = req->nr_mem_id;
 		break;
 	}
-	case NETMAP_REQ_VALE_DELIF: {
-		break;
-	}
+	case NETMAP_REQ_VALE_DELIF:
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE: {
-		struct nmreq_vale_polling *req =
-			(struct nmreq_vale_polling *)hdr->nr_body;
-		switch (req->nr_mode) {
-		default:
-			nmr->nr_flags = NR_REG_DEFAULT; /* invalid */
-			break;
-		case NETMAP_POLLING_MODE_MULTI_CPU:
-			nmr->nr_flags = NR_REG_ONE_NIC;
-			break;
-		case NETMAP_POLLING_MODE_SINGLE_CPU:
-			nmr->nr_flags = NR_REG_ALL_NIC;
-			break;
-		}
-		nmr->nr_ringid = req->nr_first_cpu_id;
-		nmr->nr_arg1 = req->nr_num_polling_cpus;
 		break;
 	}
 	}

From c5f45473a13843e557a3465216d589bb21c0afce Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Jan 2018 12:43:37 +0100
Subject: [PATCH 0640/2207] netmap.h: add some comments about the new API

---
 sys/net/netmap.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d9ee26428..2936f8e43 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -386,6 +386,79 @@ struct netmap_if {
 /*
  * New API to control netmap control devices. New applications should only use
  * nmreq_xyz structs with the NIOCCTRL ioctl() command.
+ *
+ * NIOCCTRL takes a nmreq_header struct, which contains the required
+ * API version, the name of a netmap port, a command type, and pointers
+ * to request body and options.
+ *
+ *	nr_name	(in)
+ *		The name of the port (em0, valeXXX:YYY, eth0{pn1 etc.)
+ *
+ *	nr_version (in/out)
+ *		Must match NETMAP_API as used in the kernel, error otherwise.
+ *		Always returns the desired value on output.
+ *
+ *	nr_reqtype (in)
+ *		One of the NETMAP_REQ_* command types below
+ *
+ *	nr_body (in)
+ *		Pointer to a command-specific struct, described by one
+ *		of the struct nmreq_xyz below.
+ *
+ *	nr_options (in)
+ *		Command specific options, if any.
+ *
+ * A NETMAP_REQ_REGISTER command activates netmap mode on the netmap
+ * port (e.g. physical interface) specified by nmreq_header.nr_name.
+ * The request body (struct nmreq_register) has several arguments to
+ * specify how the port is to be registered.
+ *
+ *	nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
+ *		On input, non-zero values may be used to reconfigure the port
+ *		according to the requested values, but this is not guaranteed.
+ *		On output the actual values in use are reported.
+ *
+ *	nr_mode (in)
+ *		Indicate what set of rings must be bound to the netmap
+ *		device (e.g. all NIC rings, host rings only, NIC and
+ *		host rings, ...). Values are in NR_REG_*.
+ *
+ *	nr_ringid (in)
+ *		If nr_mode == NR_REG_ONE_NIC (only a single couple of TX/RX
+ *		rings), indicate which NIC TX and/or RX ring is to be bound
+ *		(0..nr_*x_rings-1).
+ *
+ *	nr_flags (in)
+ *		Indicate special options for how to open the port.
+ *
+ *		NR_NO_TX_POLL can be OR-ed to make select()/poll() push
+ *			packets on tx rings only if POLLOUT is set.
+ *			The default is to push any pending packet.
+ *
+ *		NR_DO_RX_POLL can be OR-ed to make select()/poll() release
+ *			packets on rx rings also when POLLIN is NOT set.
+ *			The default is to touch the rx ring only with POLLIN.
+ *			Note that this is the opposite of TX because it
+ *			reflects the common usage.
+ *
+ *		Other options are NR_MONITOR_TX, NR_MONITOR_RX, NR_ZCOPY_MON,
+ *		NR_EXCLUSIVE, NR_RX_RINGS_ONLY, NR_TX_RINGS_ONLY and
+ *		NR_ACCEPT_VNET_HDR.
+ *
+ *	nr_mem_id (in/out)
+ *		The identity of the memory region used.
+ *		On input, 0 means the system decides autonomously,
+ *		other values may try to select a specific region.
+ *		On return the actual value is reported.
+ *		Region '1' is the global allocator, normally shared
+ *		by all interfaces. Other values are private regions.
+ *		If two ports the same region zero-copy is possible.
+ *
+ *	nr_extra_bufs (in/out)
+ *		Number of extra buffers to be allocated.
+ *
+ * The other NETMAP_REQ_* commands are described below.
+ *
  */
 
 /* Header common to all request options. */
@@ -496,10 +569,13 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * Demultiplexing is done using the nr_hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
- * specifying only nmreq_header, and copyin the rest. */
+ * specifying only nmreq_header, and copyin/copyout the rest. */
 #define NIOCCTRL	_IOWR('i', 151, struct nmreq_header)
 
-/* The ioctl commands to sync TX/RX netmap rings. */
+/* The ioctl commands to sync TX/RX netmap rings.
+ * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
+ *	whose identity is set in NIOCREGIF through nr_ringid.
+ *	These are non blocking and take no argument. */
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
 #define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */
 

From 8d9204b4c97c7a000ff1274eca95f7e12046601b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 29 Jan 2018 19:49:01 +0100
Subject: [PATCH 0641/2207] newnmreq: copy options from/to userspace

---
 sys/dev/netmap/netmap.c | 170 +++++++++++++++++++++++++++++++++++++---
 sys/net/netmap.h        |   3 +
 2 files changed, 161 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 71e314cd4..216884fda 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2239,6 +2239,9 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
+static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
+static int nmreq_copyout(struct nmreq_header *, void *, size_t);
+
 /*
  * ioctl(2) support for the "netmap" device.
  *
@@ -2295,18 +2298,14 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		if (nr_body_is_user && nr_body_size) {
 			char *ker_nr_body;
 
-			usr_nr_body = hdr->nr_body;
 			/* Make a kernel-space copy of the user-space nr_body.
 			 * It's handy to temporarily replace hdr->nr_body with
 			 * a pointer to the kernel-space nr_body. */
-			ker_nr_body = nm_os_malloc(nr_body_size);
+			ker_nr_body = nmreq_copyin(hdr, nr_body_size, &error);
 			if (!ker_nr_body) {
-				return ENOMEM;
-			}
-			if (copyin(usr_nr_body, ker_nr_body, nr_body_size)) {
-				nm_os_free(ker_nr_body);
-				return EFAULT;
+				return error;
 			}
+			usr_nr_body = hdr->nr_body;
 			hdr->nr_body = ker_nr_body;
 		}
 
@@ -2598,16 +2597,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 		}
 		if (nr_body_is_user && nr_body_size) {
+			char *ker_nr_body;
 			KASSERT(usr_nr_body && hdr->nr_body,
 				"nr_body pointers must not be NULL");
 			/* Write back request body to userspace and reset the
 			 * user-space pointer. */
-			if (error == 0 && copyout(hdr->nr_body,
-				usr_nr_body, nr_body_size)) {
-				error = EFAULT;
-			}
-			nm_os_free(hdr->nr_body);
+			ker_nr_body = hdr->nr_body;
 			hdr->nr_body = usr_nr_body;
+			if (error == 0) {
+				error = nmreq_copyout(hdr, ker_nr_body, nr_body_size);
+			}
 		}
 		break;
 	}
@@ -2722,6 +2721,153 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	return 0;
 }
 
+size_t
+nmreq_opt_size_by_type(uint16_t nro_reqtype)
+{
+	return 0;
+}
+
+static void *
+nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
+{
+	size_t bufsz, rqsz;
+	int error;
+	char *ker = NULL, *p;
+	struct nmreq_option **next, *src;
+	struct nmreq_option buf;
+	void **ptrs;
+
+	/* compute the total size of the buffer */
+	rqsz = nmreq_size_by_type(hdr->nr_reqtype);
+	if (rqsz > NETMAP_REQ_MAXSIZE) {
+		error = EMSGSIZE;
+		goto out_err;
+	}
+	bodysz = 2 * sizeof(void *) + rqsz;
+	for (src = hdr->nr_options; src; src = src->nro_next) {
+		size_t optsz;
+		error = copyin(src, &buf, sizeof(*src));
+		if (error)
+			goto out_err;
+		optsz = sizeof(*src);
+		optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
+		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
+			error = EMSGSIZE;
+			goto out_err;
+		}
+		rqsz += optsz;
+		bufsz += optsz + sizeof(void *);
+	}
+
+	bufsz = max(1024UL, roundup_pow_of_two(bodysz));
+	ker = nm_os_malloc(bufsz);
+	if (ker == NULL) {
+		error = ENOMEM;
+		goto out_err;
+	}
+	p = ker;
+
+	/* make a copy of the user pointers */
+	ptrs = (void **)p;
+	*ptrs++ = hdr->nr_body;
+	*ptrs++ = hdr->nr_options;
+	p = (char *)ptrs;
+
+	/* copy the body */
+	error = copyin(hdr->nr_body, p, rqsz);
+	if (error)
+		goto out_err;
+	p += rqsz;
+
+	/* copy the options */
+	next = &hdr->nr_options;
+	src = *next;
+	while (src) {
+		size_t optsz;
+		struct nmreq_option *opt;
+
+		/* copy the option header */
+		ptrs = (void **)p;
+		opt = (struct nmreq_option *)(ptrs + 1);
+		error = copyin(src, opt, sizeof(*src));
+		if (error)
+			goto out_err;
+		/* make a copy of the user next pointer */
+		*ptrs = opt->nro_next;
+		/* overwrite the user pointer with the in-kernel one */
+		*next = opt;
+
+		p = (char *)(opt + 1);
+
+		/* copy the option body */
+		optsz = nmreq_opt_size_by_type(opt->nro_reqtype);
+		if (optsz) {
+			/* the option body follows the option header */
+			error = copyin(src + 1, p, optsz);
+			if (error)
+				goto out_err;
+			p += optsz;
+		}
+
+		/* move to next option */
+		next = &opt->nro_next;
+		src = *next;
+	}
+	/* skip the option list head */
+	return ker + 2 * sizeof(void *);
+
+out_err:
+	if (ker)
+		nm_os_free(ker);
+	if (perror)
+		*perror = error;
+	return NULL;
+}
+
+static int
+nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz)
+{
+	int error = 0;
+	struct nmreq_option *src, *dst;
+	void **ptrs = ker;
+
+	/* copy the body */
+	error = copyout(ker, *(ptrs - 2), bodysz);
+	if (error)
+		goto out;
+
+	/* copy the options */
+	dst = *(ptrs - 1);
+	src = hdr->nr_options;
+	while (src) {
+		size_t optsz;
+		struct nmreq_option *next;
+
+		/* restore the user pointer */
+		next = src->nro_next;
+		ptrs = (void **)src - 1;
+		src->nro_next = *ptrs;
+
+		/* copy the option header */
+		error = copyout(src, dst, sizeof(src));
+		if (error)
+			goto out;
+		       
+		/* copy the option body */
+		optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+		if (optsz) {
+			error = copyout(dst + 1, src + 1, optsz);
+			if (error)
+				goto out;
+		}
+		src = next;
+		dst = *ptrs;
+	}
+
+out:
+	nm_os_free(ker);
+	return error;
+}
 
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 2936f8e43..e90f91afb 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -461,6 +461,9 @@ struct netmap_if {
  *
  */
 
+/* maximum size of a request, including all options */
+#define NETMAP_REQ_MAXSIZE	4096
+
 /* Header common to all request options. */
 struct nmreq_option {
 	/* Pointer ot the next option. */

From 3a8682980903fe6d35b29e0ec9ba7c9daa492857 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 11:57:48 +0100
Subject: [PATCH 0642/2207] nmreq_copyout: release memory also in case of error

---
 sys/dev/netmap/netmap.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 216884fda..dfa28ab03 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2240,7 +2240,7 @@ ring_timestamp_set(struct netmap_ring *ring)
 }
 
 static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
-static int nmreq_copyout(struct nmreq_header *, void *, size_t);
+static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
 
 /*
  * ioctl(2) support for the "netmap" device.
@@ -2604,9 +2604,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			 * user-space pointer. */
 			ker_nr_body = hdr->nr_body;
 			hdr->nr_body = usr_nr_body;
-			if (error == 0) {
-				error = nmreq_copyout(hdr, ker_nr_body, nr_body_size);
-			}
+			error = nmreq_copyout(hdr, ker_nr_body, nr_body_size, error);
 		}
 		break;
 	}
@@ -2825,12 +2823,14 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 }
 
 static int
-nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz)
+nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
 {
-	int error = 0;
 	struct nmreq_option *src, *dst;
 	void **ptrs = ker;
 
+	if (error)
+		goto out;
+
 	/* copy the body */
 	error = copyout(ker, *(ptrs - 2), bodysz);
 	if (error)

From 2e457d6e3b9aa08d3344b433687c7075d87210ca Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 16:34:00 +0100
Subject: [PATCH 0643/2207] added nmreq_findoption

---
 sys/dev/netmap/netmap.c      | 14 ++++++++++++++
 sys/dev/netmap/netmap_kern.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index dfa28ab03..141c40ca0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2241,6 +2241,7 @@ ring_timestamp_set(struct netmap_ring *ring)
 
 static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
 static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
+struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
 
 /*
  * ioctl(2) support for the "netmap" device.
@@ -2295,6 +2296,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			return EINVAL;
 		}
 
+		BUG_ON(!nr_body_is_user && hdr->nr_options);
+
 		if (nr_body_is_user && nr_body_size) {
 			char *ker_nr_body;
 
@@ -2869,6 +2872,17 @@ nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
 	return error;
 }
 
+struct nmreq_option *
+nmreq_findoption(struct nmreq_header *hdr, uint16_t reqtype)
+{
+	struct nmreq_option *opt;
+
+	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+		if (opt->nro_reqtype == reqtype)
+			return opt;
+	return NULL;
+}
+
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
  *
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 3474c5934..5610a9a8c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2179,4 +2179,6 @@ void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
 #endif /* WITH_PTNETMAP_GUEST */
 
+struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+
 #endif /* _NET_NETMAP_KERN_H_ */

From 6f834b12f21c0bc6a9378e6e365e43ca5e097d3d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 16:49:26 +0100
Subject: [PATCH 0644/2207] fail when an option is not recognized

---
 sys/dev/netmap/netmap.c | 27 +++++++++++++++++++++++++++
 sys/net/netmap.h        |  7 ++++++-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 141c40ca0..384ce020a 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2242,6 +2242,7 @@ ring_timestamp_set(struct netmap_ring *ring)
 static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
 static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
 struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+static int nmreq_checkoptions(struct nmreq_header *);
 
 /*
  * ioctl(2) support for the "netmap" device.
@@ -2390,6 +2391,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
 
+				error = nmreq_checkoptions(hdr);
+				if (error) {
+					netmap_do_unregif(priv);
+					break;
+				}
+
 				/* store ifp reference so that priv destructor may release it */
 				priv->np_ifp = ifp;
 			} while (0);
@@ -2798,6 +2805,11 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 		/* overwrite the user pointer with the in-kernel one */
 		*next = opt;
 
+		/* initialize the option as not supported.
+		 * Recognized options will update this field.
+		 */
+		opt->nro_status = EOPNOTSUPP;
+
 		p = (char *)(opt + 1);
 
 		/* copy the option body */
@@ -2883,6 +2895,21 @@ nmreq_findoption(struct nmreq_header *hdr, uint16_t reqtype)
 	return NULL;
 }
 
+static int
+nmreq_checkoptions(struct nmreq_header *hdr)
+{
+	struct nmreq_option *opt;
+	/* return error if there is still any option
+	 * marked as not supported
+	 */
+
+	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+		if (opt->nro_status == EOPNOTSUPP)
+			return EOPNOTSUPP;
+
+	return 0;
+}
+
 /*
  * select(2) and poll(2) handlers for the "netmap" device.
  *
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e90f91afb..eb6e29be1 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -469,7 +469,12 @@ struct nmreq_option {
 	/* Pointer ot the next option. */
 	struct nmreq_option	*nro_next;
 	/* Option type. */
-	uint16_t		nro_reqtype;
+	uint32_t		nro_reqtype;
+	/* (out) status of the option:
+	 * 0: recognized and processed
+	 * !=0: errno value
+	 */
+	uint32_t		nro_status;
 };
 
 /* Header common to all requests. Do not reorder these fields, as we need

From efe51f4ce325abfd0452b04ce5f90781260b343c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 19:42:29 +0100
Subject: [PATCH 0645/2207] nmreq: hide the pointer swapping details

---
 sys/dev/netmap/netmap.c | 105 +++++++++++++++++++++-------------------
 sys/net/netmap.h        |   1 +
 2 files changed, 56 insertions(+), 50 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 384ce020a..5ea937385 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2239,9 +2239,8 @@ ring_timestamp_set(struct netmap_ring *ring)
 	}
 }
 
-static void *nmreq_copyin(struct nmreq_header *, size_t, int *);
-static int nmreq_copyout(struct nmreq_header *, void *, size_t, int);
-struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+static int nmreq_copyin(struct nmreq_header *, int);
+static int nmreq_copyout(struct nmreq_header *, int);
 static int nmreq_checkoptions(struct nmreq_header *);
 
 /*
@@ -2275,9 +2274,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	switch (cmd) {
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
-		size_t nr_body_size = nmreq_size_by_type(hdr->nr_reqtype);
-		/* Original hdr->nr_body to user-space pointer. */
-		char *usr_nr_body = NULL;
 
 		if (hdr->nr_version != NETMAP_API) {
 			D("API mismatch for reqtype %d: got %d need %d",
@@ -2290,27 +2286,15 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			return EINVAL;
 		}
 
-		if ((nr_body_size && hdr->nr_body == NULL) ||
-			(!nr_body_size && hdr->nr_body != NULL)) {
-			/* Request body expected, but not found; or
-			 * request body found but unexpected. */
-			return EINVAL;
-		}
-
-		BUG_ON(!nr_body_is_user && hdr->nr_options);
-
-		if (nr_body_is_user && nr_body_size) {
-			char *ker_nr_body;
-
-			/* Make a kernel-space copy of the user-space nr_body.
-			 * It's handy to temporarily replace hdr->nr_body with
-			 * a pointer to the kernel-space nr_body. */
-			ker_nr_body = nmreq_copyin(hdr, nr_body_size, &error);
-			if (!ker_nr_body) {
-				return error;
-			}
-			usr_nr_body = hdr->nr_body;
-			hdr->nr_body = ker_nr_body;
+		/* Make a kernel-space copy of the user-space nr_body.
+		 * For convenince, the nr_body pointer and the pointers
+		 * in the options list will be replaced with their
+		 * kernel-space counterparts. The original pointers are
+                * saved internally and later restored by nmreq_copyout
+                */
+		error = nmreq_copyin(hdr, nr_body_is_user);
+		if (error) {
+			return error;
 		}
 
 		/* Sanitize hdr->nr_name. */
@@ -2606,16 +2590,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 		}
-		if (nr_body_is_user && nr_body_size) {
-			char *ker_nr_body;
-			KASSERT(usr_nr_body && hdr->nr_body,
-				"nr_body pointers must not be NULL");
-			/* Write back request body to userspace and reset the
-			 * user-space pointer. */
-			ker_nr_body = hdr->nr_body;
-			hdr->nr_body = usr_nr_body;
-			error = nmreq_copyout(hdr, ker_nr_body, nr_body_size, error);
-		}
+		/* Write back request body to userspace and reset the
+		 * user-space pointer. */
+		error = nmreq_copyout(hdr, error);
 		break;
 	}
 
@@ -2735,22 +2712,38 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 	return 0;
 }
 
-static void *
-nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
+int
+nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
-	size_t bufsz, rqsz;
+	size_t bufsz, rqsz, bodysz;
 	int error;
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src;
 	struct nmreq_option buf;
 	void **ptrs;
 
+	if (hdr->nr_reserved)
+		return EINVAL;
+
+	hdr->nr_reserved = nr_body_is_user;
+
+	if (!nr_body_is_user)
+		return 0;
+
 	/* compute the total size of the buffer */
 	rqsz = nmreq_size_by_type(hdr->nr_reqtype);
 	if (rqsz > NETMAP_REQ_MAXSIZE) {
 		error = EMSGSIZE;
 		goto out_err;
 	}
+	if ((rqsz && hdr->nr_body == NULL) ||
+		(!rqsz && hdr->nr_body != NULL)) {
+		/* Request body expected, but not found; or
+		 * request body found but unexpected. */
+		error = EINVAL;
+		goto out_err;
+	}
+
 	bodysz = 2 * sizeof(void *) + rqsz;
 	for (src = hdr->nr_options; src; src = src->nro_next) {
 		size_t optsz;
@@ -2785,6 +2778,8 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 	error = copyin(hdr->nr_body, p, rqsz);
 	if (error)
 		goto out_err;
+	/* overwrite the user pointer with the in-kernel one */
+	hdr->nr_body = p;
 	p += rqsz;
 
 	/* copy the options */
@@ -2826,34 +2821,42 @@ nmreq_copyin(struct nmreq_header *hdr, size_t bodysz, int *perror)
 		next = &opt->nro_next;
 		src = *next;
 	}
-	/* skip the option list head */
-	return ker + 2 * sizeof(void *);
+	return 0;
 
 out_err:
 	if (ker)
 		nm_os_free(ker);
-	if (perror)
-		*perror = error;
-	return NULL;
+	return error;
 }
 
 static int
-nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
+nmreq_copyout(struct nmreq_header *hdr, int error)
 {
 	struct nmreq_option *src, *dst;
-	void **ptrs = ker;
+	void *ker = hdr->nr_body;
+	void **ptrs;
+	size_t bodysz;
+
+	if (!hdr->nr_reserved)
+		return error;
 
 	if (error)
 		goto out;
 
+	/* restore the user pointers in the header */
+	ptrs = (void **)ker;
+	hdr->nr_body = *(ptrs - 2);
+	src = hdr->nr_options;
+	hdr->nr_options = *(ptrs - 1);
+
 	/* copy the body */
-	error = copyout(ker, *(ptrs - 2), bodysz);
+	bodysz = nmreq_size_by_type(hdr->nr_reqtype);
+	error = copyout(ker, hdr->nr_body, bodysz);
 	if (error)
 		goto out;
 
 	/* copy the options */
-	dst = *(ptrs - 1);
-	src = hdr->nr_options;
+	dst = hdr->nr_options;
 	while (src) {
 		size_t optsz;
 		struct nmreq_option *next;
@@ -2879,6 +2882,8 @@ nmreq_copyout(struct nmreq_header *hdr, void *ker, size_t bodysz, int error)
 		dst = *ptrs;
 	}
 
+	hdr->nr_reserved = 0;
+
 out:
 	nm_os_free(ker);
 	return error;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index eb6e29be1..136264228 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -482,6 +482,7 @@ struct nmreq_option {
 struct nmreq_header {
 	uint16_t		nr_version;	/* API version */
 	uint16_t		nr_reqtype;	/* nmreq type (NETMAP_REQ_*) */
+	uint32_t		nr_reserved;	/* must be zero */
 #define NETMAP_REQ_IFNAMSIZ	64
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	struct nmreq_option	*nr_options;	/* command-specific options */

From 4bec549d6205631d9d503cf4bb0c1ae55d8c49a1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 30 Jan 2018 17:03:39 +0100
Subject: [PATCH 0646/2207] testmmap: initial support for new API

---
 utils/testmmap.c | 333 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 302 insertions(+), 31 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 5da4cea89..d9a8ff732 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -146,8 +146,9 @@ void do_close()
 #include 
 #include 
 
-struct nmreq curr_nmr = { .nr_version = NETMAP_API, .nr_flags = NR_REG_ALL_NIC, };
-char nmr_name[64];
+/* legacy */
+struct nmreq curr_nmr = { .nr_version = 11, .nr_flags = NR_REG_ALL_NIC, };
+char nmr_name[256];
 
 void parse_nmr_config(char* w, struct nmreq *nmr)
 {
@@ -179,7 +180,7 @@ void parse_nmr_config(char* w, struct nmreq *nmr)
 	}
 }
 
-void do_getinfo()
+void do_getinfo_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -213,7 +214,7 @@ void do_getinfo()
 }
 
 
-void do_regif()
+void do_regif_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -810,7 +811,7 @@ nmr_arg_extra()
 }
 
 void
-do_nmr_dump()
+do_nmr_legacy_dump()
 {
 	u_int ringid = curr_nmr.nr_ringid & NETMAP_RING_MASK;
 	nmr_arg_interp_fun arg_interp;
@@ -953,7 +954,7 @@ do_nmr_dump()
 }
 
 void
-do_nmr_reset()
+do_nmr_legacy_reset()
 {
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
@@ -961,7 +962,7 @@ do_nmr_reset()
 }
 
 void
-do_nmr_name()
+do_nmr_legacy_name()
 {
 	char *name = nextarg();
 	if (name) {
@@ -973,7 +974,7 @@ do_nmr_name()
 }
 
 void
-do_nmr_ringid()
+do_nmr_legacy_ringid()
 {
 	char *arg;
 	uint16_t ringid = curr_nmr.nr_ringid;
@@ -998,7 +999,7 @@ do_nmr_ringid()
 }
 
 void
-do_nmr_cmd()
+do_nmr_legacy_cmd()
 {
 	char *arg = nextarg();
 	if (arg == NULL)
@@ -1032,7 +1033,7 @@ do_nmr_cmd()
 }
 
 void
-do_nmr_flags()
+do_nmr_legacy_flags()
 {
 	char *arg;
 	uint32_t flags = curr_nmr.nr_flags;
@@ -1075,54 +1076,56 @@ do_nmr_flags()
 	output("flags=%x", curr_nmr.nr_flags);
 }
 
-struct cmd_def nmr_commands[] = {
-	{ "dump",	do_nmr_dump },
-	{ "reset",	do_nmr_reset },
-	{ "name",	do_nmr_name },
-	{ "ringid",	do_nmr_ringid },
-	{ "cmd",	do_nmr_cmd },
-	{ "flags",	do_nmr_flags },
+struct cmd_def nmr_legacy_commands[] = {
+	{ "dump",	do_nmr_legacy_dump },
+	{ "reset",	do_nmr_legacy_reset },
+	{ "name",	do_nmr_legacy_name },
+	{ "ringid",	do_nmr_legacy_ringid },
+	{ "cmd",	do_nmr_legacy_cmd },
+	{ "flags",	do_nmr_legacy_flags },
 };
 
-const int N_NMR_CMDS = sizeof(nmr_commands) / sizeof(struct cmd_def);
+const int N_NMR_LEGACY_CMDS = sizeof(nmr_legacy_commands) / sizeof(struct cmd_def);
 
 int
-find_nmr_command(const char *cmd)
+find_nmr_legacy_command(const char *cmd)
 {
-	return _find_command(nmr_commands, N_NMR_CMDS, cmd);
+	return _find_command(nmr_legacy_commands, N_NMR_LEGACY_CMDS, cmd);
 }
 
-#define nmr_arg_update(f) 				\
+#define __nmr_arg_update(nmr, f) 			\
 	({						\
 		int __ret = 0;				\
 		if (strcmp(cmd, #f) == 0) {		\
 			char *arg = nextarg();		\
 			if (arg) {			\
-				curr_nmr.nr_##f = strtol(arg, NULL, 0); \
+				curr_##nmr.nr_##f = strtol(arg, NULL, 0); \
 			}				\
-			output(#f "=%d", curr_nmr.nr_##f);	\
+			output(#f "=%d", curr_##nmr.nr_##f);	\
 			__ret = 1;			\
 		} 					\
 		__ret;					\
 	})
 
+#define nmr_arg_update(f)	__nmr_arg_update(nmr, f)
+
 /* prepare the curr_nmr */
 void
-do_nmr()
+do_nmr_legacy()
 {
 	char *cmd = nextarg();
 	int i;
 
 	if (cmd == NULL) {
-		do_nmr_dump();
+		do_nmr_legacy_dump();
 		return;
 	}
 	if (cmd[0] == '.') {
 		cmd++;
 	} else {
-		i = find_nmr_command(cmd);
-		if (i < N_NMR_CMDS) {
-			nmr_commands[i].f();
+		i = find_nmr_legacy_command(cmd);
+		if (i < N_NMR_LEGACY_CMDS) {
+			nmr_legacy_commands[i].f();
 			return;
 		}
 	}
@@ -1143,14 +1146,280 @@ do_nmr()
 	output("unknown field: %s", cmd);
 }
 
+/****************************************************************
+ * new API							*
+ ****************************************************************/
+
+static struct nmreq_header curr_hdr = { .nr_version = NETMAP_API };
+static struct nmreq_register curr_register;
+static struct nmreq_port_info_get curr_port_info_get;
+static struct nmreq_vale_attach curr_vale_attach;
+static struct nmreq_vale_list curr_vale_list;
+static struct nmreq_port_hdr curr_port_hdr;
+static struct nmreq_vale_newif curr_vale_newif;
+static struct nmreq_vale_polling curr_vale_polling;
+static struct nmreq_pools_info_get curr_pools_info_get;
+
+typedef void (*nmr_body_dump_fun)(void *);
+
+static void
+nmr_body_dump_register(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_port_info_get(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_attach(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_list(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_port_hdr(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_newif(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_vale_polling(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_body_dump_pools_info_get(void *b)
+{
+	(void)b;
+}
+
+static void
+nmr_option_dump(struct nmreq_option *opt)
+{
+	(void)opt;
+}
+
+static void
+do_hdr_dump()
+{
+	struct nmreq_option *opt;
+	nmr_body_dump_fun body_dump = NULL;
+
+	snprintf(nmr_name, NETMAP_REQ_IFNAMSIZ + 1, "%s", curr_hdr.nr_name);
+	nmr_name[NETMAP_REQ_IFNAMSIZ] = '\0';
+	printf("version:   %d\n", curr_hdr.nr_version);
+	printf("reqtype:   %d [", curr_hdr.nr_reqtype);
+	switch (curr_hdr.nr_reqtype) {
+	case NETMAP_REQ_REGISTER:
+		printf("register");
+		body_dump = nmr_body_dump_register;
+		break;
+	case NETMAP_REQ_PORT_INFO_GET:
+		printf("info-get");
+		body_dump = nmr_body_dump_port_info_get;
+		break;
+	case NETMAP_REQ_VALE_ATTACH:
+		printf("vale-attach");
+		body_dump = nmr_body_dump_vale_attach;
+		break;
+	case NETMAP_REQ_VALE_DETACH:
+		printf("vale-detach");
+		break;
+	case NETMAP_REQ_VALE_LIST:
+		printf("vale-list");
+		body_dump = nmr_body_dump_vale_list;
+		break;
+	case NETMAP_REQ_PORT_HDR_SET:
+		printf("port-hdr-set");
+		body_dump = nmr_body_dump_port_hdr;
+		break;
+	case NETMAP_REQ_PORT_HDR_GET:
+		printf("port-hdr-get");
+		body_dump = nmr_body_dump_port_hdr;
+		break;
+	case NETMAP_REQ_VALE_NEWIF:
+		printf("vale-newif");
+		body_dump = nmr_body_dump_vale_newif;
+		break;
+	case NETMAP_REQ_VALE_DELIF:
+		printf("vale-delif");
+		break;
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+		printf("vale-polliing-enable");
+		body_dump = nmr_body_dump_vale_polling;
+		break;
+	case NETMAP_REQ_VALE_POLLING_DISABLE:
+		printf("vale-polling-disable");
+		body_dump = nmr_body_dump_vale_polling;
+		break;
+	case NETMAP_REQ_POOLS_INFO_GET:
+		printf("pools-info-get");
+		body_dump = nmr_body_dump_pools_info_get;
+		break;
+	default:
+		printf("???");
+		break;
+	}
+	printf("]\n");
+	printf("name: %s\n", nmr_name);
+	opt = curr_hdr.nr_options;
+	printf("options:   %p\n", opt);
+	while (opt) {
+		nmr_option_dump(opt);
+		opt = opt->nro_next;
+	}
+	printf("body:	   %p\n", curr_hdr.nr_body);
+	if (body_dump)
+		body_dump(curr_hdr.nr_body);
+}
+
+static void
+do_hdr_reset()
+{
+	memset(&curr_hdr, 0, sizeof(curr_hdr));
+	curr_hdr.nr_version = NETMAP_API;
+}
+
+void
+do_hdr_name()
+{
+	char *name = nextarg();
+	if (name) {
+		strncpy(curr_hdr.nr_name, name, NETMAP_REQ_IFNAMSIZ);
+	}
+	strncpy(nmr_name, curr_hdr.nr_name, NETMAP_REQ_IFNAMSIZ);
+	nmr_name[NETMAP_REQ_IFNAMSIZ] = '\0';
+	output("name=%s", nmr_name);
+}
+
+
+static void
+do_hdr_type()
+{
+	char *type = nextarg();
+
+	if (strcmp(type, "register") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+		curr_hdr.nr_body = &curr_register;
+	} else if (strcmp(type, "info-get") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+		curr_hdr.nr_body = &curr_port_info_get;
+	} else if (strcmp(type, "vale-attach") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+		curr_hdr.nr_body = &curr_vale_attach;
+	} else if (strcmp(type, "vale-detach") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+	} else if (strcmp(type, "vale-list") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
+		curr_hdr.nr_body = &curr_vale_list;
+	} else if (strcmp(type, "port-hdr-set") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+		curr_hdr.nr_body = &curr_port_hdr;
+	} else if (strcmp(type, "port-hdr-get") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+		curr_hdr.nr_body = &curr_port_hdr;
+	} else if (strcmp(type, "vale-newif") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+		curr_hdr.nr_body = &curr_vale_newif;
+	} else if (strcmp(type, "vale-delif") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+	} else if (strcmp(type, "vale-polliing-enable") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+		curr_hdr.nr_body = &curr_vale_polling;
+	} else if (strcmp(type, "vale-polling-disable") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+		curr_hdr.nr_body = &curr_vale_polling;
+	} else if (strcmp(type, "pools-info-get") == 0) {
+		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
+		curr_hdr.nr_body = &curr_pools_info_get;
+	} else {
+		output("unknown type: %s", type);
+	}
+}
+
+static void
+do_hdr_option()
+{
+}
+
+struct cmd_def hdr_commands[] = {
+	{ "dump",	do_hdr_dump },
+	{ "reset",	do_hdr_reset },
+	{ "name",	do_hdr_name },
+	{ "type",	do_hdr_type },
+	{ "option",	do_hdr_option },
+};
+
+const int N_HDR_CMDS = sizeof(hdr_commands) / sizeof(struct cmd_def);
+
+int
+find_hdr_command(const char *cmd)
+{
+	return _find_command(hdr_commands, N_HDR_CMDS, cmd);
+}
+
+
+
+static void
+do_hdr()
+{
+	char *cmd = nextarg();
+	int i;
+
+	if (cmd == NULL) {
+		do_hdr_dump();
+		return;
+	}
+	i = find_hdr_command(cmd);
+	if (i < N_HDR_CMDS) {
+		hdr_commands[i].f();
+		return;
+	}
+	output("unknown command: %s", cmd);
+}
+
+static void
+do_ctrl()
+{
+	char *arg;
+	int fd, ret;
+
+	arg = nextarg();
+	if (!arg) {
+		fd = last_fd;
+		goto doit;
+	}
+	fd = atoi(arg);
+doit:
+	ret = ioctl(fd, NIOCCTRL, &curr_hdr);
+	output_err(ret, "ioctl(%d, NIOCCTL, %p)=%d", fd, &curr_hdr, ret);
+
+}
 
 
 struct cmd_def commands[] = {
 	{ "open",	do_open,	},
 	{ "close", 	do_close,	},
 #ifdef TEST_NETMAP
-	{ "getinfo",	do_getinfo,	},
-	{ "regif",	do_regif,	},
+	{ "getinfo-legacy",	do_getinfo_legacy,	},
+	{ "regif-legacy",	do_regif_legacy,	},
 	{ "txsync",	do_txsync,	},
 	{ "rxsync",	do_rxsync,	},
 #endif /* TEST_NETMAP */
@@ -1166,7 +1435,9 @@ struct cmd_def commands[] = {
 	{ "ring",       do_ring,        },
 	{ "slot",       do_slot,        },
 	{ "buf",        do_buf,         },
-	{ "nmr",	do_nmr,		}
+	{ "nmr-legacy",	do_nmr_legacy,	},
+	{ "hdr",	do_hdr,		},
+	{ "ctrl",	do_ctrl		}
 };
 
 const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);

From 19edba72496254496e3ca61b516af3988a144a8f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 30 Jan 2018 17:55:09 +0100
Subject: [PATCH 0647/2207] testmmap: initial support for request options

---
 utils/testmmap.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d9a8ff732..1cca4bb8f 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1213,7 +1213,23 @@ nmr_body_dump_pools_info_get(void *b)
 static void
 nmr_option_dump(struct nmreq_option *opt)
 {
-	(void)opt;
+	printf("type: %u [", opt->nro_reqtype);
+	switch (opt->nro_reqtype) {
+	case NETMAP_REQ_OPT_EXTMEM:
+		printf("extmem");
+		break;
+	default:
+#ifdef NETMAP_OPT_DEBUG
+		if (opt->nro_reqtype & NETMAP_REQ_OPT_DEBUG) {
+			printf("debug: %u",
+				(opt->nro_reqtype & ~NETMAP_REQ_OPT_DEBUG));
+			break;
+		}
+#endif /* NETMAP_OPT_DEBUG */
+		printf("???");
+	}
+	printf("]\n");
+	printf("next: %p\n", opt->nro_next);
 }
 
 static void
@@ -1293,8 +1309,15 @@ do_hdr_dump()
 static void
 do_hdr_reset()
 {
+	struct nmreq_option *opt = curr_hdr.nr_options;
+	while (opt) {
+		struct nmreq_option *next = opt->nro_next;
+		free(opt);
+		opt = next;
+	}
 	memset(&curr_hdr, 0, sizeof(curr_hdr));
 	curr_hdr.nr_version = NETMAP_API;
+
 }
 
 void
@@ -1357,6 +1380,29 @@ do_hdr_type()
 static void
 do_hdr_option()
 {
+	char *type;
+	struct nmreq_option **ptr = &curr_hdr.nr_options,
+			    *old = *ptr;
+	size_t sz = sizeof(struct nmreq_option);
+
+	while ( (type = nextarg()) ) {
+		uint16_t reqtype;
+
+		if (strcmp(type, "extmem") == 0) {
+			reqtype = NETMAP_REQ_OPT_EXTMEM;
+#ifdef NETMAP_OPT_DEBUG
+		} else {
+			reqtype = atoi(type) | NETMAP_REQ_OPT_DEBUG;
+#endif /* NETMAP_OPT_DEBUG */
+		}
+		*ptr = malloc(sz);	
+		if (*ptr == NULL) {
+			output_err(-1, "malloc");
+		}
+		(*ptr)->nro_reqtype = reqtype;
+		ptr = &(*ptr)->nro_next;
+	}
+	*ptr = old;
 }
 
 struct cmd_def hdr_commands[] = {

From c81fdad2a3555fb2d76e084cd238069279f23b86 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 13:55:04 +0100
Subject: [PATCH 0648/2207] testmmap: register command

---
 utils/testmmap.c | 219 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 204 insertions(+), 15 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 1cca4bb8f..526ea5465 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1093,18 +1093,19 @@ find_nmr_legacy_command(const char *cmd)
 	return _find_command(nmr_legacy_commands, N_NMR_LEGACY_CMDS, cmd);
 }
 
-#define __nmr_arg_update(nmr, f) 			\
-	({						\
-		int __ret = 0;				\
-		if (strcmp(cmd, #f) == 0) {		\
-			char *arg = nextarg();		\
-			if (arg) {			\
-				curr_##nmr.nr_##f = strtol(arg, NULL, 0); \
-			}				\
-			output(#f "=%d", curr_##nmr.nr_##f);	\
-			__ret = 1;			\
-		} 					\
-		__ret;					\
+#define __nmr_arg_update(nmr, f) 					\
+	({								\
+		int __ret = 0;						\
+		if (strcmp(cmd, #f) == 0) {				\
+			char *arg = nextarg();				\
+			if (arg) {					\
+				curr_##nmr.nr_##f = strtol(arg, NULL, 0);\
+			}						\
+			output(#f "=%llu",				\
+				(unsigned long long)curr_##nmr.nr_##f);	\
+			__ret = 1;					\
+		} 							\
+		__ret;							\
 	})
 
 #define nmr_arg_update(f)	__nmr_arg_update(nmr, f)
@@ -1165,7 +1166,194 @@ typedef void (*nmr_body_dump_fun)(void *);
 static void
 nmr_body_dump_register(void *b)
 {
-	(void)b;
+	struct nmreq_register *r = b;
+	int flags = 0;
+	printf("offset:    %"PRIu64"\n", r->nr_offset);
+	printf("memsize:   %"PRIu64" [", r->nr_memsize);
+	if (r->nr_memsize < (1<<20)) {
+		printf("%"PRIu64" KiB", r->nr_memsize >> 10);
+	} else {
+		printf("%"PRIu64" MiB", r->nr_memsize >> 20);
+	}
+	printf("]\n");
+	printf("tx_slots:  %"PRIu16"\n", r->nr_tx_slots);
+	printf("rx_slots:  %"PRIu16"\n", r->nr_rx_slots);
+	printf("tx_rings:  %"PRIu16"\n", r->nr_tx_rings);
+	printf("rx_rings:  %"PRIu16"\n", r->nr_rx_rings);
+	printf("mem_id:    %"PRIu16" [%s memory region]\n", r->nr_mem_id,
+		(r->nr_mem_id == 0 ? "default" :
+		 r->nr_mem_id == 1 ? "global"  : "private"));
+	printf("ringid     %"PRIu16"\n", r->nr_ringid);
+	printf("mode       %"PRIu32" [", r->nr_mode);
+	switch (r->nr_mode) {
+	case NR_REG_DEFAULT:
+		printf("*DEFAULT");
+		break;
+	case NR_REG_ALL_NIC:
+		printf("ALL_NIC");
+		break;
+	case NR_REG_SW:
+		printf("SW");
+		break;
+	case NR_REG_NIC_SW:
+		printf("NIC_SW");
+		break;
+	case NR_REG_ONE_NIC:
+		printf("ONE_NIC(%"PRIu16")", r->nr_ringid);
+		break;
+	case NR_REG_PIPE_MASTER:
+		printf("*PIPE_MASTER(%d)", r->nr_ringid);
+		break;
+	case NR_REG_PIPE_SLAVE:
+		printf("*PIPE_SLAVE(%d)", r->nr_ringid);
+		break;
+	default:
+		printf("???");
+		break;
+	}
+	printf("]\n");
+	printf("flags:     %lx [", r->nr_flags);
+#define pflag(f) if (r->nr_flags & NR_##f) { printf("%s" #f, flags++ ? ", " : ""); }
+	pflag(MONITOR_TX);
+	pflag(MONITOR_RX);
+	pflag(ZCOPY_MON);
+	pflag(EXCLUSIVE);
+	pflag(PTNETMAP_HOST);
+	pflag(RX_RINGS_ONLY);
+	pflag(TX_RINGS_ONLY);
+	pflag(ACCEPT_VNET_HDR);
+	pflag(DO_RX_POLL);
+	pflag(NO_TX_POLL);
+#undef pflag
+	printf("]\n");
+	printf("extra_bufs %"PRIu32"\n", r->nr_extra_bufs);
+}
+
+static void
+do_register_dump()
+{
+	nmr_body_dump_register(&curr_register);
+}
+
+static void
+do_register_reset()
+{
+	memset(&curr_register, 0, sizeof(curr_register));
+}
+
+static void
+do_register_mode()
+{
+	char *mode = nextarg();
+
+	if (mode == NULL)
+		goto out;
+
+	if (strcmp(mode, "default") == 0) {
+		curr_register.nr_mode = NR_REG_DEFAULT;
+	} else if (strcmp(mode, "all-nic") == 0) {
+		curr_register.nr_mode = NR_REG_ALL_NIC;
+	} else if (strcmp(mode, "sw") == 0) {
+		curr_register.nr_mode = NR_REG_SW;
+	} else if (strcmp(mode, "nic-sw") == 0) {
+		curr_register.nr_mode = NR_REG_NIC_SW;
+	} else if (strcmp(mode, "one-nic") == 0) {
+		curr_register.nr_mode = NR_REG_ONE_NIC;
+	} else if (strcmp(mode, "pipe-master") == 0) {
+		curr_register.nr_mode = NR_REG_PIPE_MASTER;
+	} else if (strcmp(mode, "pipe-slave") == 0) {
+		curr_register.nr_mode = NR_REG_PIPE_SLAVE;
+	}
+
+out:
+	output("mode=%"PRIu32, curr_register.nr_mode);
+}
+
+void
+do_register_flags()
+{
+	char *arg;
+	uint64_t flags = curr_register.nr_flags;
+	int n;
+	for (n = 0, arg = nextarg(); arg; arg = nextarg(), n++) {
+		if (strcmp(arg, "monitor-tx") == 0) {
+			flags |= NR_MONITOR_TX;
+		} else if (strcmp(arg, "monitor-rx") == 0) {
+			flags |= NR_MONITOR_RX;
+		} else if (strcmp(arg, "zcopy-mon") == 0) {
+			flags |= NR_ZCOPY_MON;
+		} else if (strcmp(arg, "exclusive") == 0) {
+			flags |= NR_EXCLUSIVE;
+		} else if (strcmp(arg, "ptnetmap-host") == 0) {
+			flags |= NR_PTNETMAP_HOST;
+		} else if (strcmp(arg, "rx-rings-only") == 0) {
+			flags |= NR_RX_RINGS_ONLY;
+		} else if (strcmp(arg, "tx-rings-only") == 0) {
+			flags |= NR_TX_RINGS_ONLY;
+		} else if (strcmp(arg, "accept-vnet-hdr") == 0) {
+			flags |= NR_ACCEPT_VNET_HDR;
+		} else if (strcmp(arg, "do-rx-poll") == 0) {
+			flags |= NR_DO_RX_POLL;
+		} else if (strcmp(arg, "no-tx-poll") == 0) {
+			flags |= NR_NO_TX_POLL;
+		} else if (strcmp(arg, "reset") == 0) {
+			flags = 0;
+		}
+	}
+	if (n)
+		curr_register.nr_flags = flags;
+	output("flags=%lx", curr_register.nr_flags);
+}
+
+struct cmd_def register_commands[] = {
+	{ "dump",	do_register_dump },
+	{ "reset",	do_register_reset },
+	{ "mode",	do_register_mode },
+	{ "flags",	do_register_flags },
+};
+
+const int N_REGISTER_CMDS = sizeof(register_commands) / sizeof(struct cmd_def);
+
+int
+find_register_command(const char *cmd)
+{
+	return _find_command(register_commands, N_REGISTER_CMDS, cmd);
+}
+
+#define register_update(f) __nmr_arg_update(register, f)
+
+void
+do_register()
+{
+	char *cmd = nextarg();
+	int i;
+
+	if (cmd == NULL) {
+		do_register_dump();
+		return;
+	}
+	if (cmd[0] == '.') {
+		cmd++;
+	} else {
+		i = find_register_command(cmd);
+		if (i < N_REGISTER_CMDS) {
+			register_commands[i].f();
+			return;
+		}
+	}
+	if (register_update(offset) 
+	||  register_update(memsize) 
+	||  register_update(tx_slots) 
+	||  register_update(rx_slots) 
+	||  register_update(tx_rings) 
+	||  register_update(rx_rings) 
+	||  register_update(mem_id) 
+	||  register_update(ringid) 
+	||  register_update(mode) 
+	||  register_update(flags)
+	||  register_update(extra_bufs))
+		return;
+	output("unknown field: %s", cmd);
 }
 
 static void
@@ -1392,7 +1580,7 @@ do_hdr_option()
 			reqtype = NETMAP_REQ_OPT_EXTMEM;
 #ifdef NETMAP_OPT_DEBUG
 		} else {
-			reqtype = atoi(type) | NETMAP_REQ_OPT_DEBUG;
+			reqtype = strtol(type, NULL, 0) | NETMAP_REQ_OPT_DEBUG;
 #endif /* NETMAP_OPT_DEBUG */
 		}
 		*ptr = malloc(sz);	
@@ -1483,7 +1671,8 @@ struct cmd_def commands[] = {
 	{ "buf",        do_buf,         },
 	{ "nmr-legacy",	do_nmr_legacy,	},
 	{ "hdr",	do_hdr,		},
-	{ "ctrl",	do_ctrl		}
+	{ "ctrl",	do_ctrl		},
+	{ "register",	do_register	}
 };
 
 const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);

From ff7626764adc6885d76097a862b0ae70f3131612 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 14:05:47 +0100
Subject: [PATCH 0649/2207] testmmap: print hdr type after update

---
 utils/testmmap.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 526ea5465..a4aba5f24 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1563,6 +1563,7 @@ do_hdr_type()
 	} else {
 		output("unknown type: %s", type);
 	}
+	output("type=%u", curr_hdr.nr_reqtype);
 }
 
 static void

From a81fb5b9e0d161d0a820501be432ba04cd4d6699 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Mar 2017 11:26:36 +0100
Subject: [PATCH 0650/2207] extmem: user-supplied netmap memory region

With this feature a user application may allocate its own memory
(e.g., via mmap()) and pass it to netmap while registering (NIOCREGIF)
an interface.  If the interface was not already registered, it will pin
the underlying pages in memory and use them for its own netmap_if's,
netmap_ring's and buffers.

Example usage:

  void *mem = mmap(...);
  /* the user must fill a netmap_pools_info header before passing
   * the region to netmap;
   * the header is used to split the region into netmap_if's,
   * netmap_ring's and buffers
   */
  struct netmap_pools_info *pi = mem;
  pi->ring_pool_objtotal = 100;   /* how many rings */
  pi->buf_pool_objtotal = 100000; /* how many buffers */
  /* etc. */
  struct nmreq req;
  /* other nmreq initializations... */
  nmreq_pointer_put(&req, mem);
  req.nr_cmd = NETMAP_POOLS_CREATE;
  fd = open("/dev/netmap");
  ioctl(fd, NIOCREGIF, &req);
  /* pi is now filled with the actual values used */

Possible uses:
- support of hugepages
- persistent memory (e.g., PASTE)

Bugs:
- while a port is registered in this way, no other application can
  open it, not even on non intersecting sets of rings (this may actually
  be a feature);
- each netmap_if, netmap_ring and buffer needs to be contiguous in
  physical memory; netmap_ring's, in particular, are usually bigger
  than 4KiB and netmap may fail to allocate them if the user pages
  are scattered around; note, however, that this is not a problem
  for the above suggested use-cases;
- nmreq_pointer_put() overwrites nr_arg1, nr_arg2 and nr_arg3; this means
  that extra buffers cannot be asked for in the same NIOCREGIF (one may
  ask for extra buffers in another NIOCREGIF, possibily on a dummy port)
- Linux only (for now)
---
 LINUX/bsd_glue.h             |   5 +
 LINUX/configure              |  49 +++++-
 LINUX/netmap_linux.c         |   2 +
 sys/dev/netmap/netmap.c      |   1 +
 sys/dev/netmap/netmap_kern.h |   3 +
 sys/dev/netmap/netmap_mem2.c | 287 +++++++++++++++++++++++++++++++++--
 sys/dev/netmap/netmap_mem2.h |   8 +
 utils/testmmap.c             |  33 ++++
 8 files changed, 377 insertions(+), 11 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index d20eb6ec4..571618211 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -57,6 +57,7 @@
 
 #include 	// virt_to_phys
 #include 
+#include  // kmap
 
 #define KASSERT(a, b)		BUG_ON(!(a))
 
@@ -181,6 +182,10 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb) {
 #define NM_UNREG_NETDEV_NOTIF(nb)	unregister_netdevice_notifier(nb)
 #endif /* NETMAP_LINUX_HAVE_REG_NOTIF_RH */
 
+#ifndef NETMAP_LINUX_HAVE_PAGE_TO_VIRT
+#define page_to_virt(p) 		phys_to_virt(page_to_phys(p))
+#endif /* NETMAP_LINUX_HAVE_PAGE_TO_VIRT */
+
 /*----------- end of LINUX_VERSION_CODE dependencies ----------*/
 
 /* Type redefinitions. XXX check them */
diff --git a/LINUX/configure b/LINUX/configure
index e26db83cc..511682217 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -91,7 +91,8 @@ setop()
 }
 
 # available subsystems
-subsystem_avail="vale pipe monitor generic ptnetmap-guest ptnetmap-host sink"
+subsystem_avail="vale pipe monitor generic ptnetmap-guest ptnetmap-host sink \
+	extmem"
 #enabled subsystems (bitfield)
 subsystem=0
 
@@ -305,9 +306,10 @@ Available options:
   --disable-ptnetmap           disable ptnetmap (both guest and host)
   --enable-sink   	       enable the netmap sink device
   --disable-sink   	       disable the netmap sink device
+  --enable-extmem   	       enable the external memory allocators
+  --disable-extmem   	       disable the external memory allocators
   --force-debug	       	       build the modules w/ debug symbols (default)
   --no-force-debug	       build the modules w/ or w/o debug symbols,
-  			       according to the kernel configuration
   --cache=		       dir for reusing/caching of netmap_linux_config.h
 
   --cc=                        C compiler to be used for the apps [$cc]
@@ -1488,6 +1490,49 @@ EOF
 	}
 EOF
 
+# check for get_user_pages_unlocked number of args
+  add_test 'have GUP_4ARGS' <
+
+	long
+	dummy(unsigned long start, unsigned long nr_pages,
+		struct page **pages, unsigned int gup_flags) {
+		return get_user_pages_unlocked(start, nr_pages, pages, gup_flags);
+	}
+EOF
+
+  add_test 'have GUP_5ARGS' <
+
+	long
+	dummy(unsigned long start, unsigned long nr_pages,
+		int write, int force, struct page **pages) {
+		return get_user_pages_unlocked(start, nr_pages, write, force, pages);
+	}
+EOF
+
+  add_test 'have GUP_7ARGS' <
+
+	long
+	dummy(struct task_struct *tsk, struct mm_struct *mm,
+		unsigned long start, unsigned long nr_pages,
+		int write, int force, struct page **pages) {
+		return get_user_pages_unlocked(tsk, mm, start, nr_pages,
+			write, force, pages);
+	}
+EOF
+
+# check for page_to_virt
+  add_test 'have PAGE_TO_VIRT' <
+
+	void *
+	dummy(struct page *page) {
+		return page_to_virt(page);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 9deef237a..9f2fc38ac 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1058,6 +1058,8 @@ linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
 			(vma->vm_end - vma->vm_start), memsize);
 	if (off + (vma->vm_end - vma->vm_start) > memsize)
 		return -EINVAL;
+	if (memflags & NETMAP_MEM_EXT)
+		return -ENODEV;
 	if (memflags & NETMAP_MEM_IO) {
 		vm_ooffset_t pa;
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5ea937385..546a84f2f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3258,6 +3258,7 @@ netmap_attach_common(struct netmap_adapter *na)
 	if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
 		na->if_input = na->ifp->if_input; /* for netmap_send_up */
 	}
+	pa->pdev = na; /* make sure netmap_mem_map() is called */
 #endif /* __FreeBSD__ */
 	if (na->nm_krings_create == NULL) {
 		/* we assume that we have been called by a driver,
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 5610a9a8c..dee654caf 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -37,6 +37,9 @@
 
 #if defined(linux)
 
+#if defined(CONFIG_NETMAP_EXTMEM)
+#define WITH_EXTMEM
+#endif
 #if  defined(CONFIG_NETMAP_VALE)
 #define WITH_VALE
 #endif
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f05bfb96c..344d507cc 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -333,6 +333,7 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 		}
 	}
 
+	ND("%s free %u", p->name, p->objfree);
 	if (p->objfree == 0)
 		return ENOMEM;
 
@@ -664,7 +665,7 @@ nm_free_lut(struct lut_entry *lut, u_int objtotal)
 #endif
 }
 
-#ifdef linux
+#if defined(linux) || defined(_WIN32)
 static struct plut_entry *
 nm_alloc_plut(u_int nobj)
 {
@@ -679,7 +680,7 @@ nm_free_plut(struct plut_entry * lut)
 {
 	vfree(lut);
 }
-#endif
+#endif /* linux or _WIN32 */
 
 
 /*
@@ -999,7 +1000,7 @@ netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr)
 		ssize_t relofs = (ssize_t) vaddr - (ssize_t) base;
 
 		/* Given address, is out of the scope of the current cluster.*/
-		if (vaddr < base || relofs >= p->_clustsize)
+		if (base == NULL || vaddr < base || relofs >= p->_clustsize)
 			continue;
 
 		j = j + relofs / p->_objsize;
@@ -1294,6 +1295,11 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 	int i; /* must be signed */
 	size_t n;
 
+	if (p->lut) {
+		/* already finalized, nothing to do */
+		return 0;
+	}
+
 	/* optimistically assume we have enough memory */
 	p->numclusters = p->_numclusters;
 	p->objtotal = p->_objtotal;
@@ -1478,6 +1484,9 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	for (i = 0; i < lim; i += p->_clustentries) {
 		int j;
 
+		if (p->lut[i].vaddr == NULL)
+			continue;
+
 		error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr,
 				p->lut[i].vaddr, p->_clustsize);
 		if (error) {
@@ -1537,19 +1546,21 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
 /*
  * allocator for private memory
  */
-static struct netmap_mem_d *
-_netmap_mem_private_new(struct netmap_obj_params *p, int *perr)
+static void *
+_netmap_mem_private_new(size_t size, struct netmap_obj_params *p, 
+		struct netmap_mem_ops *ops, int *perr)
 {
 	struct netmap_mem_d *d = NULL;
 	int i, err = 0;
 
-	d = nm_os_malloc(sizeof(struct netmap_mem_d));
+	d = nm_os_malloc(size);
 	if (d == NULL) {
 		err = ENOMEM;
 		goto error;
 	}
 
 	*d = nm_blueprint;
+	d->ops = ops;
 
 	err = nm_mem_assign_id(d);
 	if (err)
@@ -1638,7 +1649,7 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 			p[NETMAP_BUF_POOL].num,
 			p[NETMAP_BUF_POOL].size);
 
-	d = _netmap_mem_private_new(p, perr);
+	d = _netmap_mem_private_new(sizeof(*d), p, &netmap_mem_global_ops, perr);
 
 	return d;
 }
@@ -1685,14 +1696,14 @@ netmap_mem2_finalize(struct netmap_mem_d *nmd)
 	int err;
 
 	/* update configuration if changed */
-	if (netmap_mem2_config(nmd))
+	if (netmap_mem_config(nmd))
 		goto out1;
 
 	nmd->active++;
 
 	if (nmd->flags & NETMAP_MEM_FINALIZED) {
 		/* may happen if config is not changed */
-		ND("nothing to do");
+		D("nothing to do");
 		goto out;
 	}
 
@@ -2011,6 +2022,264 @@ netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
 	return 0;
 }
 
+#ifdef WITH_EXTMEM
+struct netmap_mem_ext {
+	struct netmap_mem_d up;
+
+	struct page **pages;
+	int nr_pages;
+};
+
+static void
+netmap_mem_ext_delete(struct netmap_mem_d *d)
+{
+	int i;
+	struct netmap_mem_ext *e =
+		(struct netmap_mem_ext *)d;
+
+	for (i = 0; i < NETMAP_POOLS_NR; i++) {
+		struct netmap_obj_pool *p = &d->pools[i];
+		
+		if (p->lut) {
+			nm_free_lut(p->lut, p->objtotal);
+			p->lut = NULL;
+		}
+	}
+	if (e->pages) {
+		for (i = 0; i < e->nr_pages; i++) {
+			kunmap(e->pages[i]);
+			put_page(e->pages[i]);
+		}
+		nm_os_free(e->pages);
+		e->pages = NULL;
+		e->nr_pages = 0;
+	}
+	netmap_mem2_delete(d);
+}
+
+static int
+netmap_mem_ext_config(struct netmap_mem_d *nmd)
+{
+	return 0;
+}
+
+struct netmap_mem_ops netmap_mem_ext_ops = {
+	.nmd_get_lut = netmap_mem2_get_lut,
+	.nmd_get_info = netmap_mem2_get_info,
+	.nmd_ofstophys = netmap_mem2_ofstophys,
+	.nmd_config = netmap_mem_ext_config,
+	.nmd_finalize = netmap_mem2_finalize,
+	.nmd_deref = netmap_mem2_deref,
+	.nmd_delete = netmap_mem_ext_delete,
+	.nmd_if_offset = netmap_mem2_if_offset,
+	.nmd_if_new = netmap_mem2_if_new,
+	.nmd_if_delete = netmap_mem2_if_delete,
+	.nmd_rings_create = netmap_mem2_rings_create,
+	.nmd_rings_delete = netmap_mem2_rings_delete
+};
+
+struct netmap_mem_d *
+netmap_mem_ext_create(struct nmreq *nmr, int *perror)
+{
+	uintptr_t p = *(uintptr_t *)&nmr->nr_arg1;
+	struct netmap_pools_info pi;
+	int error = 0;
+	unsigned long end, start;
+	int nr_pages, res, i, j;
+	struct page **pages = NULL;
+	struct netmap_mem_ext *nme;
+	char *clust;
+	size_t off;
+
+	error = copyin((void *)p, &pi, sizeof(pi));
+	if (error)
+		goto out;
+
+	// XXX sanity checks
+	if (pi.if_pool_objtotal == 0)
+		pi.if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num;
+	if (pi.if_pool_objsize == 0)
+		pi.if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size;
+	if (pi.ring_pool_objtotal == 0)
+		pi.ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num;
+	if (pi.ring_pool_objsize == 0)
+		pi.ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size;
+	if (pi.buf_pool_objtotal == 0)
+		pi.buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
+	if (pi.buf_pool_objsize == 0)
+		pi.buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
+	D("if %d %d ring %d %d buf %d %d",
+			pi.if_pool_objtotal, pi.if_pool_objsize,
+			pi.ring_pool_objtotal, pi.ring_pool_objsize,
+			pi.buf_pool_objtotal, pi.buf_pool_objsize);
+		
+	end = (p + pi.memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	start = p >> PAGE_SHIFT;
+	nr_pages = end - start;
+
+	pages = nm_os_malloc(nr_pages * sizeof(*pages));
+	if (pages == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			pages,
+			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
+#elif defined(NETMAP_LINUX_HAVE_GUP_5ARGS)
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
+	res = get_user_pages_unlocked(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#else
+	down_read(¤t->mm->mmap_sem);
+	res = get_user_pages(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages,
+			NULL);
+	up_read(¤t->mm->mmap_sem);
+#endif	/* NETMAP_LINUX_GUP */
+
+	if (res < nr_pages) {
+		error = EFAULT;
+		goto out_unmap;
+	}
+
+	nme = nm_os_malloc(sizeof(*nme));
+	if (nme == NULL) {
+		error = ENOMEM;
+		goto out_unmap;
+	}
+
+	nme = _netmap_mem_private_new(sizeof(*nme),
+			(struct netmap_obj_params[]){
+				{ pi.if_pool_objsize, pi.if_pool_objtotal },
+				{ pi.ring_pool_objsize, pi.ring_pool_objtotal },
+				{ pi.buf_pool_objsize, pi.buf_pool_objtotal }},
+			&netmap_mem_ext_ops,
+			&error);
+	if (nme == NULL)
+		goto out_unmap;
+					
+	/* from now on pages will be released by nme destructor;
+	 * we let res = 0 to prevent release in out_unmap below
+	 */
+	res = 0;
+	nme->pages = pages;
+	nme->nr_pages = nr_pages;
+	nme->up.flags |= NETMAP_MEM_EXT;
+
+	clust = kmap(*pages);
+	off = 0;
+	for (i = 0; i < NETMAP_POOLS_NR; i++) {
+		struct netmap_obj_pool *p = &nme->up.pools[i];
+		struct netmap_obj_params *o = &nme->up.params[i];
+
+		p->_objsize = o->size;
+		p->_clustsize = o->size;
+		p->_clustentries = 1;
+
+		p->lut = nm_alloc_lut(o->num);
+		if (p->lut == NULL) {
+			error = ENOMEM;
+			goto out_delete;
+		}
+
+		if (nr_pages == 0) {
+			p->objtotal = 0;
+			p->memtotal = 0;
+			p->objfree = 0;
+			continue;
+		}
+
+		for (j = 0; j < o->num && nr_pages > 0; j++) {
+			size_t noff;
+			size_t skip;
+
+			p->lut[j].vaddr = clust + off;
+			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
+			noff = off + p->_objsize;
+			if (noff < PAGE_SIZE) {
+				off = noff;
+				continue;
+			}
+			ND("too big, recomputing offset...");
+			skip = PAGE_SIZE - (off & PAGE_MASK);
+			while (noff >= PAGE_SIZE) {
+				noff -= skip;
+				pages++;
+				nr_pages--;
+				ND("noff %zu page %p nr_pages %d", noff,
+						page_to_virt(*pages), nr_pages);
+				if (noff > 0 && p->lut[j].vaddr &&
+					(nr_pages == 0 || *pages != *(pages - 1) + 1))
+				{
+					/* out of space or non contiguous,
+					 * drop this object
+					 * */
+					p->lut[j].vaddr = NULL;
+					ND("non contiguous at off %zu, drop", noff);
+				}
+				if (nr_pages == 0)
+					break;
+				skip = PAGE_SIZE;
+			}
+			off = noff;
+			clust = page_to_virt(*pages);
+		}
+		p->objtotal = j;
+		p->numclusters = p->objtotal;
+		p->memtotal = j * p->_objsize;
+		ND("%d memtotal %u", j, p->memtotal);
+	}
+
+	/* skip the first netmap_if, where the pools info reside */
+	{
+		struct netmap_obj_pool *p = &nme->up.pools[NETMAP_IF_POOL];
+		p->lut[0].vaddr = NULL;
+	}
+
+	error = netmap_mem_init_bitmaps(&nme->up);
+	if (error)
+		goto out_delete;
+
+	return &nme->up;
+
+out_delete:
+	netmap_mem_put(&nme->up);
+out_unmap:
+	for (i = 0; i < res; i++)
+		put_page(pages[i]);
+	if (res)
+		nm_os_free(pages);
+out:
+	if (perror)
+		*perror = error;
+	return NULL;
+
+}
+#endif /* WITH_EXTMEM */
+
+
 #ifdef WITH_PTNETMAP_GUEST
 struct mem_pt_if {
 	struct mem_pt_if *next;
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 1467a60e7..a57784764 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -150,6 +150,13 @@ void __netmap_mem_put(struct netmap_mem_d *, const char *, int);
 struct netmap_mem_d* netmap_mem_find(nm_memid_t);
 unsigned netmap_mem_bufsize(struct netmap_mem_d *nmd);
 
+#ifdef WITH_EXTMEM
+struct netmap_mem_d* netmap_mem_ext_create(struct nmreq *, int *);
+#else /* !WITH_EXTMEM */
+#define netmap_mem_ext_create(nmr, _perr) \
+	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
+#endif /* WITH_EXTMEM */
+
 #ifdef WITH_PTNETMAP_GUEST
 struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,
 					     unsigned int nifp_offset,
@@ -164,6 +171,7 @@ int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
 #define NETMAP_MEM_IO		0x4	/* the underlying memory is mmapped I/O */
+#define NETMAP_MEM_EXT		0x10	/* external memory (not remappable) */
 
 uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 
diff --git a/utils/testmmap.c b/utils/testmmap.c
index a4aba5f24..4cb541b05 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -335,6 +335,38 @@ void do_mmap()
 
 }
 
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000
+#endif
+
+void do_anon_mmap()
+{
+	size_t memsize;
+	char *arg;
+	int flags = 0;
+
+	arg = nextarg();
+	if (!arg) {
+		memsize = last_memsize;
+		goto doit;
+	}
+	memsize = atoi(arg);
+	arg = nextarg();
+	if (!arg)
+		goto doit;
+	flags |= MAP_HUGETLB;
+doit:
+	last_mmap_addr = mmap(0, memsize,
+			PROT_WRITE | PROT_READ,
+			MAP_PRIVATE | MAP_ANONYMOUS | flags, -1, 0);
+	if (last_access_addr == NULL)
+		last_access_addr = last_mmap_addr;
+	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
+		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS%s, -1, 0)=%p",
+		memsize, (flags ? "MAP_HUGETLB" : ""), last_mmap_addr);
+
+}
+
 void do_munmap()
 {
 	void *mmap_addr;
@@ -1660,6 +1692,7 @@ struct cmd_def commands[] = {
 #endif /* TEST_NETMAP */
 	{ "dup",	do_dup,		},
 	{ "mmap",	do_mmap,	},
+	{ "anon-mmap",	do_anon_mmap,	},
 	{ "access",	do_access,	},
 	{ "munmap",	do_munmap,	},
 	{ "poll",	do_poll,	},

From c1c3631b9aa1717d0392c496f75b9b7254ab4662 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Dec 2017 11:20:25 +0100
Subject: [PATCH 0651/2207] extmem: userspace support in nm_open()

---
 sys/net/netmap_user.h | 71 +++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 22 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index ade7eecfd..ea386907a 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -98,6 +98,7 @@
 #endif /* likely and unlikely */
 
 #include 
+#include  /* nmreq_pointer_get() */
 
 /* helper macro */
 #define _NETMAP_OFFSET(type, ptr, offset) \
@@ -609,6 +610,23 @@ nm_is_identifier(const char *s, const char *e)
 	return 1;
 }
 
+static void
+nm_init_offsets(struct nm_desc *d)
+{
+	struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
+	struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
+	if ((void *)r == (void *)nifp) {
+		/* the descriptor is open for TX only */
+		r = NETMAP_TXRING(nifp, d->first_tx_ring);
+	}
+
+	*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
+	*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
+	*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
+	*(void **)(uintptr_t)&d->buf_end =
+		(char *)d->mem + d->memsize;
+}
+
 #define MAXERRMSG 80
 static int
 nm_parse(const char *ifname, struct nm_desc *d, char *err)
@@ -816,6 +834,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	const struct nm_desc *parent = arg;
 	char errmsg[MAXERRMSG] = "";
 	uint32_t nr_reg;
+	struct netmap_pools_info *pi = NULL;
 
 	if (strncmp(ifname, "netmap:", 7) &&
 			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@@ -836,8 +855,23 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
-	if (req)
+	if (req) {
 		d->req = *req;
+		if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
+			if (IS_NETMAP_DESC(parent) &&
+					(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
+				snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
+				errno = EINVAL;
+				goto fail;
+			}
+		        pi = nmreq_pointer_get(&d->req);
+			if (pi == NULL) {
+				snprintf(errmsg, MAXERRMSG, "missing netmap_pools_info pointer");
+				errno = EINVAL;
+				goto fail;
+			}
+		}
+	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
 		if (nm_parse(ifname, d, errmsg) < 0)
@@ -886,6 +920,19 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
+	if (pi != NULL) {
+		d->mem = pi;
+		d->memsize = pi->memsize;
+		nm_init_offsets(d);
+	} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
+		/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
+	        errno = nm_mmap(d, parent);
+		if (errno) {
+			snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
+			goto fail;
+		}
+	}
+
 	nr_reg = d->req.nr_flags & NR_REG_MASK;
 
 	if (nr_reg == NR_REG_SW) { /* host stack */
@@ -910,13 +957,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->first_rx_ring = d->last_rx_ring = 0;
 	}
 
-        /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
-	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
-	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
-		goto fail;
-	}
-
-
 #ifdef DEBUG_NETMAP_USER
     { /* debugging code */
 	int i;
@@ -994,21 +1034,8 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 		}
 		d->done_mmap = 1;
 	}
-	{
-		struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
-		struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
-		if ((void *)r == (void *)nifp) {
-			/* the descriptor is open for TX only */
-			r = NETMAP_TXRING(nifp, d->first_tx_ring);
-		}
-
-		*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
-		*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
-		*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
-		*(void **)(uintptr_t)&d->buf_end =
-			(char *)d->mem + d->memsize;
-	}
 
+	nm_init_offsets(d);
 	return 0;
 
 fail:

From e1c7699617803e94b1ecfb64c435b3abed5b0e37 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 3 Apr 2017 11:50:42 +0200
Subject: [PATCH 0652/2207] testmmap: pools-info command

---
 sys/net/netmap_virt.h |  7 ++++
 utils/testmmap.c      | 79 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 76f5cbb28..3007bbf82 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -121,6 +121,13 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 	*pp = (uintptr_t)userptr;
 }
 
+static inline void *
+nmreq_pointer_get(struct nmreq *nmr)
+{
+	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+	return (void *)*pp;
+}
+
 /* ptnetmap features */
 #define PTNETMAP_F_VNET_HDR        1
 
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 4cb541b05..7d46fb529 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -2,6 +2,7 @@
 
 #include 
 #include 	/* ULONG_MAX */
+#include 
 #include 
 #include 
 #include 
@@ -747,6 +748,84 @@ int _find_command(const struct cmd_def *cmds, int ncmds, const char* cmd)
 	return i;
 }
 
+struct pools_info_field {
+	char *name;
+	size_t off;
+	size_t size;
+};
+#define PIFD(n, f)	{ n, offsetof(struct netmap_pools_info, f), \
+	sizeof(((struct netmap_pools_info *)0)->f) }
+struct pools_info_field pools_info_fields[] = {
+	PIFD("memsize", memsize),
+	PIFD("memid", memid),
+	PIFD("if-off", if_pool_offset),
+	PIFD("if-tot", if_pool_objtotal),
+	PIFD("if-siz", if_pool_objsize),
+	PIFD("ring-off", ring_pool_offset),
+	PIFD("ring-tot", ring_pool_objtotal),
+	PIFD("ring-siz", ring_pool_objsize),
+	PIFD("buf-off", buf_pool_offset),
+	PIFD("buf-tot", buf_pool_objtotal),
+	PIFD("buf-siz", buf_pool_objsize),
+	{ NULL, 0, 0 }
+};
+#define PIF(t, p, o)	(*(t*)((void *)((char *)(p)+(o))))
+void
+pools_info_dump(int tab, struct netmap_pools_info *upi)
+{
+	static const char space[] = "        ";
+	struct pools_info_field *f;
+	for (f = pools_info_fields; f->name; f++) {
+		printf("%.*s%-12s", tab, space, f->name);
+		switch (f->size) {
+		case 8:
+			printf("%"PRIu64"\n", PIF(uint64_t, upi, f->off));
+			break;
+		case 4:
+			printf("%"PRIu32"\n", PIF(uint32_t, upi, f->off));
+			break;
+		case 2:
+			printf("%"PRIu16"\n", PIF(uint16_t, upi, f->off));
+			break;
+		}
+	}
+}
+
+/* prepare the curr_pools_info */
+void
+do_pools_info()
+{
+	char *cmd = nextarg();
+	unsigned long long v;
+
+	if (cmd == NULL) {
+		pools_info_dump(0, &curr_pools_info);
+		return;
+	}
+	struct pools_info_field *f = NULL;
+	for (f = pools_info_fields; f->name; f++) {
+		if (strcmp(f->name, cmd) == 0)
+			break;
+	}
+	if (f == NULL)
+		return;
+	cmd = nextarg();
+	if (cmd == NULL)
+		return;
+	v = strtoll(cmd, NULL, 0);
+	switch (f->size) {
+	case 8:
+		PIF(uint64_t, &curr_pools_info, f->off) = v;
+		break;
+	case 4:
+		PIF(uint32_t, &curr_pools_info, f->off) = v;
+		break;
+	case 2:
+		PIF(uint16_t, &curr_pools_info, f->off) = v;
+		break;
+	}
+}
+
 typedef void (*nmr_arg_interp_fun)();
 
 #define nmr_arg_unexpected(n) \

From 95dce0200fa073cc55ee880d0d7657be8699f5f5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Dec 2017 16:20:15 +0100
Subject: [PATCH 0653/2207] testmmap: read and write memory commands

---
 utils/testmmap.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 7d46fb529..d2cd6ec32 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -268,8 +268,7 @@ do_rxsync()
 #endif /* TEST_NETMAP */
 
 
-volatile char tmp1;
-void do_access()
+void do_rd()
 {
 	char *arg = nextarg();
 	char *p;
@@ -283,7 +282,31 @@ void do_access()
 		p = (char *)strtoul((void *)arg, NULL, 0);
 	}
 	last_access_addr = p + 4096;
-	tmp1 = *p;
+	output("%2x", *p);
+}
+
+char *last_wr_byte = "x";
+void do_wr()
+{
+	char *arg = nextarg();
+	char *p;
+	if (!arg) {
+		if (!last_access_addr) {
+			output("missing address");
+			return;
+		}
+		p = last_access_addr;
+		last_access_addr += 4096;
+	} else {
+		p = (char *)strtoul((void *)arg, NULL, 0);
+	}
+	arg = nextarg();
+	if (!arg) {
+		arg = last_wr_byte;
+	}
+	for ( ; arg; arg = nextarg()) {
+		*p++ = strtoul((void *)arg, NULL, 0);
+	}
 }
 
 void do_dup()
@@ -1772,7 +1795,8 @@ struct cmd_def commands[] = {
 	{ "dup",	do_dup,		},
 	{ "mmap",	do_mmap,	},
 	{ "anon-mmap",	do_anon_mmap,	},
-	{ "access",	do_access,	},
+	{ "rd",		do_rd,		},
+	{ "wr",		do_wr,		},
 	{ "munmap",	do_munmap,	},
 	{ "poll",	do_poll,	},
 	{ "expr",	do_expr,	},

From 8952a9f6c79c37a8a0d7aff3277e40ac9f10147a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Dec 2017 16:22:07 +0100
Subject: [PATCH 0654/2207] testmmap: simplify access to buffers

---
 utils/testmmap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d2cd6ec32..5fcb8fde8 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -753,6 +753,8 @@ do_buf()
 doit:
 	ring = get_ring();
 	buf = NETMAP_BUF(ring, buf_idx);
+	output("buf=%p", buf);
+	last_access_addr = buf;
 	dump_payload(buf, len);
 }
 

From 9b5cbdba99c8699638c49b9e0693990c77e44eac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 3 Jan 2018 23:01:50 +0100
Subject: [PATCH 0655/2207] testmmap: ring and slot field modification

---
 utils/testmmap.c | 97 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 79 insertions(+), 18 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 5fcb8fde8..d88292116 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -556,7 +556,7 @@ get_if()
 
 	/* first arg: if offset */
 	arg = nextarg();
-	if (!arg) {
+	if (!arg || (strcmp(arg, "-") == 0)) {
 		goto doit;
 	}
 	off = strtoul(arg, NULL, 0);
@@ -618,14 +618,9 @@ get_ring()
 	return NETMAP_TXRING(nifp, ringid);
 }
 
-
 void
-do_ring()
+dump_ring(struct netmap_ring *ring)
 {
-	struct netmap_ring *ring;
-
-	ring = get_ring();
-
 	printf("buf_ofs     %"PRId64"\n", ring->buf_ofs);
 	printf("num_slots   %u\n", ring->num_slots);
 	printf("nr_buf_size %u\n", ring->nr_buf_size);
@@ -663,23 +658,46 @@ do_ring()
 }
 
 void
-do_slot()
+do_ring()
 {
 	struct netmap_ring *ring;
-	struct netmap_slot *slot;
-	long int index;
 	char *arg;
+	int upd = -1;
+	unsigned int v;
 
-	/* defaults */
-	index = 0;
+	ring = get_ring();
 
 	arg = nextarg();
-	if (!arg)
-		goto doit;
-	index = strtoll(arg, NULL, 0);
-doit:
-	ring = get_ring();
-	slot = ring->slot + index;
+	if (!arg) {
+		dump_ring(ring);
+		return;
+	}
+	if (strcmp(arg, "head") == 0) {
+		upd = 1;
+	} else if (strcmp(arg, "cur") == 0) {
+		upd = 2;
+	} else if (strcmp(arg, "both") == 0) {
+		upd = 3;
+	} else {
+		return;
+	}
+	arg = nextarg();
+	if (!arg) {
+		v = ring->cur + 1;
+		if (ring->cur >= ring->num_slots)
+			ring->cur = 0;
+	} else {
+		v = strtoul((void *)arg, NULL, 0);
+	}
+	if (upd & 1)
+		ring->head = v;
+	if (upd & 2)
+		ring->cur = v;
+}
+
+void
+dump_slot(struct netmap_slot *slot)
+{
 	printf("buf_idx       %u\n", slot->buf_idx);
 	printf("len           %u\n", slot->len);
 	printf("flags         %x", slot->flags);
@@ -703,12 +721,55 @@ do_slot()
 		if (slot->flags & NS_MOREFRAG) {
 			printf(" MOREFRAG");
 		}
+		if (NS_RFRAGS(slot)) {
+			printf(" fragments=%u", NS_RFRAGS(slot));
+		}
 		printf(" ]");
 	}
 	printf("\n");
 	printf("ptr           %lx\n", (long)slot->ptr);
 }
 
+void
+do_slot()
+{
+	struct netmap_ring *ring;
+	struct netmap_slot *slot;
+	long int index;
+	char *arg;
+
+	/* defaults */
+	index = 0;
+
+	arg = nextarg();
+	if (!arg)
+		goto doit;
+	index = strtoll(arg, NULL, 0);
+doit:
+	ring = get_ring();
+	slot = ring->slot + index;
+	arg = nextarg();
+	if (!arg) {
+		dump_slot(slot);
+		return;
+	}
+	if (strcmp(arg, "buf_idx") == 0) {
+		arg = nextarg();
+		if (!arg) {
+			output("buf_idx=%u", slot->buf_idx);
+			return;
+		}
+		slot->buf_idx = strtoul((void *)arg, NULL, 0);
+	} else if (strcmp(arg, "len") == 0) {
+		arg = nextarg();
+		if (!arg) {
+			output("len=%u", slot->len);
+			return;
+		}
+		slot->len = strtoul((void *)arg, NULL, 0);
+	}
+}
+
 static void
 dump_payload(char *p, int len)
 {

From 2b00144b90de86e55750d6625233f2493586d007 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:15:33 +0100
Subject: [PATCH 0656/2207] extmem: fix access out of bounds

---
 sys/dev/netmap/netmap_mem2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 344d507cc..18c23a1c9 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2244,7 +2244,8 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				skip = PAGE_SIZE;
 			}
 			off = noff;
-			clust = page_to_virt(*pages);
+			if (nr_pages > 0)
+				clust = page_to_virt(*pages);
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;

From fa31a1d64c016e188f65cfa5fda419bec9890653 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:15:52 +0100
Subject: [PATCH 0657/2207] extmem: always use kmap

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 18c23a1c9..bc4072ee4 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2245,7 +2245,7 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			}
 			off = noff;
 			if (nr_pages > 0)
-				clust = page_to_virt(*pages);
+				clust = kmap(*pages);
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;

From 1074cb09ee31bf9de2687e704d09064dfee25c21 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:16:31 +0100
Subject: [PATCH 0658/2207] testmmap: fix input of forked processes

---
 utils/testmmap.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index d88292116..1ba907ca2 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1980,13 +1980,8 @@ cmd_loop(FILE *input)
 				output_err(-1, "fork");
 				goto clean1;
 			case 0:
-				fclose(stdin);
-				if (dup(p1[0]) < 0) {
-					output_err(-1, "dup");
-					exit(1);
-				}
 				close(p1[1]);
-				stdin = fdopen(0, "r");
+				input = fdopen(p1[0], "r");
 				chan_clear_all(channels, MAX_CHAN);
 				goto out;
 			default:

From 1158b0f7fe142047c605f8bffaea8a886c4f63fc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 00:16:57 +0100
Subject: [PATCH 0659/2207] testmmap: use MAP_SHARED in anon-mmap

---
 utils/testmmap.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 1ba907ca2..aabb2a81a 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -382,12 +382,12 @@ void do_anon_mmap()
 doit:
 	last_mmap_addr = mmap(0, memsize,
 			PROT_WRITE | PROT_READ,
-			MAP_PRIVATE | MAP_ANONYMOUS | flags, -1, 0);
+			MAP_SHARED | MAP_ANONYMOUS | flags, -1, 0);
 	if (last_access_addr == NULL)
 		last_access_addr = last_mmap_addr;
 	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
-		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS%s, -1, 0)=%p",
-		memsize, (flags ? "MAP_HUGETLB" : ""), last_mmap_addr);
+		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS%s, -1, 0)=%p",
+		memsize, (flags ? "|MAP_HUGETLB" : ""), last_mmap_addr);
 
 }
 

From 6ae8b1663c6e876b105335f15fd3dd1991192a47 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 18:34:30 +0100
Subject: [PATCH 0660/2207] extmem: use a bitmap to record skipped objects

Pre-allocated objects that cross non-contiguous pages cannot be used.
The previous code skipped these objects may setting their vaddr to NULL
in the lut, but this created bugs in the mmap code.
---
 sys/dev/netmap/netmap_mem2.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index bc4072ee4..4aeabcdab 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -106,6 +106,7 @@ struct netmap_obj_pool {
 
 	struct lut_entry *lut;  /* virt,phys addresses, objtotal entries */
 	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
+	uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */
 	uint32_t bitmap_slots;	/* number of uint32 entries in bitmap */
 	/* ---------------------------------------------------*/
 
@@ -300,6 +301,12 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	return nmd->lasterr;
 }
 
+static int
+nm_isset(uint32_t *bitmap, u_int i)
+{
+	return bitmap[ (i>>5) ] & ( 1U << (i & 31U) );
+}
+
 
 static int
 netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
@@ -327,10 +334,12 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 	 * free.
 	 */
 	for (j = 0; j < p->objtotal; j++) {
-		if (p->lut[j].vaddr != NULL) {
-			p->bitmap[ (j>>5) ] |=  ( 1U << (j & 31U) );
-			p->objfree++;
+		if (p->invalid_bitmap && nm_isset(p->invalid_bitmap, j)) {
+			D("skipping %s %d", p->name, j);
+			continue;
 		}
+		p->bitmap[ (j>>5) ] |=  ( 1U << (j & 31U) );
+		p->objfree++;
 	}
 
 	ND("%s free %u", p->name, p->objfree);
@@ -1165,6 +1174,9 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 	if (p->bitmap)
 		nm_os_free(p->bitmap);
 	p->bitmap = NULL;
+	if (p->invalid_bitmap)
+		nm_os_free(p->invalid_bitmap);
+	p->invalid_bitmap = NULL;
 	if (p->lut) {
 		u_int i;
 
@@ -1175,8 +1187,7 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 		 * in the lut.
 		 */
 		for (i = 0; i < p->objtotal; i += p->_clustentries) {
-			if (p->lut[i].vaddr)
-				contigfree(p->lut[i].vaddr, p->_clustsize, M_NETMAP);
+			contigfree(p->lut[i].vaddr, p->_clustsize, M_NETMAP);
 		}
 		nm_free_lut(p->lut, p->objtotal);
 	}
@@ -2203,6 +2214,13 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			error = ENOMEM;
 			goto out_delete;
 		}
+		
+		p->bitmap_slots = (o->num + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+		p->invalid_bitmap = nm_os_malloc(sizeof(uint32_t) * p->bitmap_slots);
+		if (p->invalid_bitmap == NULL) {
+			error = ENOMEM;
+			goto out_delete;
+		}
 
 		if (nr_pages == 0) {
 			p->objtotal = 0;
@@ -2230,13 +2248,13 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				nr_pages--;
 				ND("noff %zu page %p nr_pages %d", noff,
 						page_to_virt(*pages), nr_pages);
-				if (noff > 0 && p->lut[j].vaddr &&
+				if (noff > 0 && !nm_isset(p->invalid_bitmap, j) &&
 					(nr_pages == 0 || *pages != *(pages - 1) + 1))
 				{
 					/* out of space or non contiguous,
 					 * drop this object
 					 * */
-					p->lut[j].vaddr = NULL;
+					p->invalid_bitmap[ (j>>5) ] |= 1U << (j & 31U);
 					ND("non contiguous at off %zu, drop", noff);
 				}
 				if (nr_pages == 0)
@@ -2256,7 +2274,7 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	/* skip the first netmap_if, where the pools info reside */
 	{
 		struct netmap_obj_pool *p = &nme->up.pools[NETMAP_IF_POOL];
-		p->lut[0].vaddr = NULL;
+		p->invalid_bitmap[0] |= 1U;
 	}
 
 	error = netmap_mem_init_bitmaps(&nme->up);

From 3da833f4c89e6ea590fa5de08ac29bec50c2eadf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 4 Jan 2018 20:18:17 +0100
Subject: [PATCH 0661/2207] nm_open: do not overwrite arg1-3 if not requested

---
 sys/net/netmap_user.h | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index ea386907a..2ccc69f93 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -871,6 +871,10 @@ nm_open(const char *ifname, const struct nmreq *req,
 				goto fail;
 			}
 		}
+	} else {
+		d->req.nr_arg1 = 4;
+		d->req.nr_arg2 = 0;
+		d->req.nr_arg3 = 0;
 	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
@@ -883,18 +887,18 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
-		if (new_flags & NM_OPEN_ARG1)
+		if (new_flags & NM_OPEN_ARG1) {
 			D("overriding ARG1 %d", parent->req.nr_arg1);
-		d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
-			parent->req.nr_arg1 : 4;
+			d->req.nr_arg1 = parent->req.nr_arg1;
+		}
 		if (new_flags & NM_OPEN_ARG2) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
-			d->req.nr_arg2 =  parent->req.nr_arg2;
+			d->req.nr_arg2 = parent->req.nr_arg2;
 		}
-		if (new_flags & NM_OPEN_ARG3)
+		if (new_flags & NM_OPEN_ARG3) {
 			D("overriding ARG3 %d", parent->req.nr_arg3);
-		d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
-			parent->req.nr_arg3 : 0;
+			d->req.nr_arg3 = parent->req.nr_arg3;
+		}
 		if (new_flags & NM_OPEN_RING_CFG) {
 			D("overriding RING_CFG");
 			d->req.nr_tx_slots = parent->req.nr_tx_slots;

From a9a8f2c3ee58e8f23a73e94b3c6d2af9e36d3ac1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 10:37:19 +0100
Subject: [PATCH 0662/2207] extmem: removed useless allocation

---
 sys/dev/netmap/netmap_mem2.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 4aeabcdab..1792c5cc3 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2175,12 +2175,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 		goto out_unmap;
 	}
 
-	nme = nm_os_malloc(sizeof(*nme));
-	if (nme == NULL) {
-		error = ENOMEM;
-		goto out_unmap;
-	}
-
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){
 				{ pi.if_pool_objsize, pi.if_pool_objtotal },

From 294b6cd361555f8709cabc26f38494a321c4cf7d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 11:55:30 +0100
Subject: [PATCH 0663/2207] extmem: allow sharing of allocator

---
 sys/dev/netmap/netmap_mem2.c | 97 ++++++++++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1792c5cc3..b55a46d57 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1747,12 +1747,21 @@ netmap_mem2_delete(struct netmap_mem_d *nmd)
 		nm_os_free(nmd);
 }
 
+#ifdef WITH_EXTMEM
+/* doubly linekd list of all existing external allocators */
+static struct netmap_mem_ext *netmap_mem_ext_list = NULL;
+NM_MTX_T nm_mem_ext_list_lock;
+#endif /* WITH_EXTMEM */
+
 int
 netmap_mem_init(void)
 {
 	NM_MTX_INIT(nm_mem_list_lock);
 	NMA_LOCK_INIT(&nm_mem);
 	netmap_mem_get(&nm_mem);
+#ifdef WITH_EXTMEM
+	NM_MTX_INIT(nm_mem_ext_list_lock);
+#endif /* WITH_EXTMEM */
 	return (0);
 }
 
@@ -2039,8 +2048,79 @@ struct netmap_mem_ext {
 
 	struct page **pages;
 	int nr_pages;
+	struct netmap_mem_ext *next, *prev;
 };
 
+/* call with nm_mem_list_lock held */
+static void
+netmap_mem_ext_register(struct netmap_mem_ext *e)
+{
+	NM_MTX_LOCK(nm_mem_ext_list_lock);
+	if (netmap_mem_ext_list)
+		netmap_mem_ext_list->prev = e;
+	e->next = netmap_mem_ext_list;
+	netmap_mem_ext_list = e;
+	e->prev = NULL;
+	NM_MTX_UNLOCK(nm_mem_ext_list_lock);
+}
+
+/* call with nm_mem_list_lock held */
+static void
+netmap_mem_ext_unregister(struct netmap_mem_ext *e)
+{
+	if (e->prev)
+		e->prev->next = e->next;
+	else
+		netmap_mem_ext_list = e->next;
+	if (e->next)
+		e->next->prev = e->prev;
+	e->prev = e->next = NULL;
+}
+
+static int
+netmap_mem_ext_same_pages(struct netmap_mem_ext *e, struct page **pages, int nr_pages)
+{
+	int i;
+
+	if (e->nr_pages != nr_pages)
+		return 0;
+
+	for (i = 0; i < nr_pages; i++)
+		if (pages[i] != e->pages[i])
+			return 0;
+
+	return 1;
+}
+
+static struct netmap_mem_ext *
+netmap_mem_ext_search(struct page **pages, int nr_pages)
+{
+	struct netmap_mem_ext *e;
+
+	NM_MTX_LOCK(nm_mem_ext_list_lock);
+	for (e = netmap_mem_ext_list; e; e = e->next) {
+		if (netmap_mem_ext_same_pages(e, pages, nr_pages)) {
+			netmap_mem_get(&e->up);
+			break;
+		}
+	}
+	NM_MTX_UNLOCK(nm_mem_ext_list_lock);
+	return e;
+}
+
+
+static void
+netmap_mem_ext_free_pages(struct page **pages, int nr_pages)
+{
+	int i;
+
+	for (i = 0; i < nr_pages; i++) {
+		kunmap(pages[i]);
+		put_page(pages[i]);
+	}
+	nm_os_free(pages);
+}
+
 static void
 netmap_mem_ext_delete(struct netmap_mem_d *d)
 {
@@ -2048,6 +2128,8 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 	struct netmap_mem_ext *e =
 		(struct netmap_mem_ext *)d;
 
+	netmap_mem_ext_unregister(e);
+
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &d->pools[i];
 		
@@ -2057,11 +2139,7 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 		}
 	}
 	if (e->pages) {
-		for (i = 0; i < e->nr_pages; i++) {
-			kunmap(e->pages[i]);
-			put_page(e->pages[i]);
-		}
-		nm_os_free(e->pages);
+		netmap_mem_ext_free_pages(e->pages, e->nr_pages);
 		e->pages = NULL;
 		e->nr_pages = 0;
 	}
@@ -2175,6 +2253,13 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 		goto out_unmap;
 	}
 
+	nme = netmap_mem_ext_search(pages, nr_pages);
+	if (nme) {
+		netmap_mem_ext_free_pages(pages, nr_pages);
+		return &nme->up;
+	}
+	D("not found, creating new");
+
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){
 				{ pi.if_pool_objsize, pi.if_pool_objtotal },
@@ -2275,6 +2360,8 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	if (error)
 		goto out_delete;
 
+	netmap_mem_ext_register(nme);
+
 	return &nme->up;
 
 out_delete:

From c491ebcfcf31ef71d08d1667de3d63c87e268e29 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 19:11:33 +0100
Subject: [PATCH 0664/2207] extmem: added support in nm_open/nm_parse

---
 sys/net/netmap_user.h | 159 +++++++++++++++++++++++++++++++++++++-----
 sys/net/netmap_virt.h |   2 +-
 2 files changed, 143 insertions(+), 18 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 2ccc69f93..f93466729 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -349,6 +349,7 @@ enum {
 	NM_OPEN_ARG2 =		0x200000,
 	NM_OPEN_ARG3 =		0x400000,
 	NM_OPEN_RING_CFG =	0x800000, /* tx|rx rings|slots */
+	NM_OPEN_EXTMEM =       0x1000000,
 };
 
 
@@ -628,8 +629,10 @@ nm_init_offsets(struct nm_desc *d)
 }
 
 #define MAXERRMSG 80
+#define NM_PARSE_OK	  	0
+#define NM_PARSE_MEMID 		1
 static int
-nm_parse(const char *ifname, struct nm_desc *d, char *err)
+nm_parse_one(const char *ifname, struct nmreq *d, char **out)
 {
 	int is_vale;
 	const char *port = NULL;
@@ -643,6 +646,13 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 
 	errno = 0;
 
+	if (strncmp(ifname, "netmap:", 7) &&
+			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
+		snprintf(errmsg, MAXERRMSG, "invalid port name: %s", ifname);
+		errno = EINVAL;
+		goto fail;
+	}
+
 	is_vale = (ifname[0] == 'v');
 	if (is_vale) {
 		port = index(ifname, ':');
@@ -673,12 +683,13 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 	}
 
 	namelen = port - ifname;
-	if (namelen >= sizeof(d->req.nr_name)) {
+	if (namelen >= sizeof(d->nr_name)) {
 		snprintf(errmsg, MAXERRMSG, "name too long");
 		goto fail;
 	}
-	memcpy(d->req.nr_name, ifname, namelen);
-	d->req.nr_name[namelen] = '\0';
+	memcpy(d->nr_name, ifname, namelen);
+	d->nr_name[namelen] = '\0';
+	D("name %s", d->nr_name);
 
 	p_state = P_START;
 	nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
@@ -782,15 +793,21 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 			}
 			num = strtol(port, (char **)&port, 10);
 			if (num <= 0) {
-				snprintf(errmsg, MAXERRMSG, "invalid memid %ld, must be >0", num);
-				goto fail;
+				ND("non-numeric memid %s (out = %p)", port, out);
+				if (out == NULL)
+					goto fail;
+				*out = (char *)port;
+				while (*port)
+					port++;
+			} else {
+				nr_arg2 = num;
+				p_state = P_RNGSFXOK;
 			}
-			nr_arg2 = num;
-			p_state = P_RNGSFXOK;
 			break;
 		}
 	}
-	if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) {
+	if (p_state != P_START && p_state != P_RNGSFXOK &&
+	    p_state != P_FLAGSOK && p_state != P_MEMID) {
 		snprintf(errmsg, MAXERRMSG, "unexpected end of port name");
 		goto fail;
 	}
@@ -800,21 +817,106 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
 			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
 
-	d->req.nr_flags |= nr_flags;
-	d->req.nr_ringid |= nr_ringid;
-	d->req.nr_arg2 = nr_arg2;
-
-	d->self = d;
+	d->nr_flags |= nr_flags;
+	d->nr_ringid |= nr_ringid;
+	d->nr_arg2 = nr_arg2;
 
-	return 0;
+	return (p_state == P_MEMID) ? NM_PARSE_MEMID : NM_PARSE_OK;
 fail:
 	if (!errno)
 		errno = EINVAL;
-	if (err)
-		strncpy(err, errmsg, MAXERRMSG);
+	if (out)
+		*out = strdup(errmsg);
 	return -1;
 }
 
+static int
+nm_interp_memid(const char *memid, struct nmreq *req, char **err)
+{
+	int fd = -1;
+	char errmsg[MAXERRMSG] = "";
+	struct nmreq greq;
+	off_t mapsize;
+	struct netmap_pools_info *pi;
+
+	/* first, try to look for a netmap port with this name */
+	fd = open("/dev/netmap", O_RDONLY);
+	if (fd < 0) {
+		snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno));
+		goto fail;
+	}
+	memset(&greq, 0, sizeof(greq));
+	if (nm_parse_one(memid, &greq, err) == NM_PARSE_OK) {
+		greq.nr_version = NETMAP_API;
+		if (ioctl(fd, NIOCGINFO, &greq) < 0) {
+			if (errno == ENOENT || errno == ENXIO)
+				goto try_external;
+			snprintf(errmsg, MAXERRMSG, "cannot getinfo for %s: %s", memid, strerror(errno));
+			goto fail;
+		}
+		req->nr_arg2 = greq.nr_arg2;
+		close(fd);
+		return 0;
+	}
+try_external:
+	D("trying with external memory");
+	close(fd);
+	fd = open(memid, O_RDWR);
+	if (fd < 0) {
+		snprintf(errmsg, MAXERRMSG, "cannot open %s: %s", memid, strerror(errno));
+		goto fail;
+	}
+	mapsize = lseek(fd, 0, SEEK_END);
+	if (mapsize < 0) {
+		snprintf(errmsg, MAXERRMSG, "failed to obtain filesize of %s: %s", memid, strerror(errno));
+		goto fail;
+	}
+	pi = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (pi == MAP_FAILED) {
+		snprintf(errmsg, MAXERRMSG, "cannot map %s: %s", memid, strerror(errno));
+		goto fail;
+	}
+	req->nr_cmd = NETMAP_POOLS_CREATE;
+	pi->memsize = mapsize;
+	nmreq_pointer_put(req, pi);
+	D("mapped %zu bytes at %p from file %s", mapsize, pi, memid);
+	return 0;
+
+fail:
+	D("%s", errmsg);
+	close(fd);
+	if (err && !*err)
+		*err = strdup(errmsg);
+	return errno;
+}
+
+static int
+nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
+{
+	char *err;
+	switch (nm_parse_one(ifname, &d->req, &err)) {
+	case NM_PARSE_OK:
+		D("parse OK");
+		break;
+	case NM_PARSE_MEMID:
+		D("memid: %s", err);
+		errno = nm_interp_memid(err, &d->req, &err);
+		D("errno = %d", errno);
+		if (!errno)
+			break;
+		/* fallthrough */
+	default:
+		D("error");
+		strncpy(errmsg, err, MAXERRMSG);
+		errmsg[MAXERRMSG-1] = '\0';
+		free(err);
+		return -1;
+	}
+	D("parsed name: %s", d->req.nr_name);
+	d->self = d;
+	return 0;
+}
+
 /*
  * Try to open, return descriptor if successful, NULL otherwise.
  * An invalid netmap name will return errno = 0;
@@ -857,6 +959,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (req) {
 		d->req = *req;
+#if 0
 		if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
 			if (IS_NETMAP_DESC(parent) &&
 					(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
@@ -871,6 +974,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 				goto fail;
 			}
 		}
+#endif
 	} else {
 		d->req.nr_arg1 = 4;
 		d->req.nr_arg2 = 0;
@@ -882,11 +986,28 @@ nm_open(const char *ifname, const struct nmreq *req,
 			goto fail;
 	}
 
+	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
+		if (IS_NETMAP_DESC(parent) &&
+				(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
+			snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
+			errno = EINVAL;
+			goto fail;
+		}
+	}
+
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
+		if (new_flags & NM_OPEN_EXTMEM) {
+			if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
+				d->req.nr_cmd = NETMAP_POOLS_CREATE;
+				nmreq_pointer_put(&d->req, nmreq_pointer_get(&parent->req));
+				D("Warning: not overriding arg[1-3] since external memory is being used");
+				new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
+			}
+		}
 		if (new_flags & NM_OPEN_ARG1) {
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 			d->req.nr_arg1 = parent->req.nr_arg1;
@@ -919,6 +1040,10 @@ nm_open(const char *ifname, const struct nmreq *req,
 	/* add the *XPOLL flags */
 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
 
+	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
+		pi = nmreq_pointer_get(&d->req);
+	}
+
 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
 		goto fail;
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 3007bbf82..0c127601f 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -122,7 +122,7 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 }
 
 static inline void *
-nmreq_pointer_get(struct nmreq *nmr)
+nmreq_pointer_get(const struct nmreq *nmr)
 {
 	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
 	return (void *)*pp;

From 4837871c8dcc30dfbe3b5fc2439ca70702857076 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 22:51:57 +0100
Subject: [PATCH 0665/2207] extmem: pass extmem flag in pkt-gen

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f51fe7288..62643116e 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2953,7 +2953,7 @@ main(int arc, char **argv)
 	 * reconfigure. We do the open here to have time to reset.
 	 */
 	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
-		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
+		NM_OPEN_ARG3 | NM_OPEN_EXTMEM | NM_OPEN_RING_CFG;
 	if (g.nthreads > 1) {
 		base_nmd.req.nr_flags &= ~NR_REG_MASK;
 		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;

From 0710dafab8240c94986718af3bdaeb326afa8c7d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2018 22:52:27 +0100
Subject: [PATCH 0666/2207] netmap_mem_map: prefer objtotal over the internal
 _objtotal

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index b55a46d57..de92335c0 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1458,7 +1458,7 @@ static int
 netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 {
 	int error = 0;
-	int i, lim = p->_objtotal;
+	int i, lim = p->objtotal;
 	struct netmap_lut *lut = &na->na_lut;
 
 	if (na->pdev == NULL)

From 7a246291ee55c99e511bef84b594963bec7f0c01 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 10 Jan 2018 14:46:13 +0100
Subject: [PATCH 0667/2207] nm_open: disallow recursive memid specification

---
 sys/net/netmap_user.h | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index f93466729..126a88c33 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -632,7 +632,7 @@ nm_init_offsets(struct nm_desc *d)
 #define NM_PARSE_OK	  	0
 #define NM_PARSE_MEMID 		1
 static int
-nm_parse_one(const char *ifname, struct nmreq *d, char **out)
+nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 {
 	int is_vale;
 	const char *port = NULL;
@@ -787,7 +787,7 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out)
 			p_state = P_FLAGSOK;
 			break;
 		case P_MEMID:
-			if (nr_arg2 != 0) {
+			if (!memid_allowed) {
 				snprintf(errmsg, MAXERRMSG, "double setting of memid");
 				goto fail;
 			}
@@ -801,6 +801,7 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out)
 					port++;
 			} else {
 				nr_arg2 = num;
+				memid_allowed = 0;
 				p_state = P_RNGSFXOK;
 			}
 			break;
@@ -846,7 +847,7 @@ nm_interp_memid(const char *memid, struct nmreq *req, char **err)
 		goto fail;
 	}
 	memset(&greq, 0, sizeof(greq));
-	if (nm_parse_one(memid, &greq, err) == NM_PARSE_OK) {
+	if (nm_parse_one(memid, &greq, err, 0) == NM_PARSE_OK) {
 		greq.nr_version = NETMAP_API;
 		if (ioctl(fd, NIOCGINFO, &greq) < 0) {
 			if (errno == ENOENT || errno == ENXIO)
@@ -894,7 +895,7 @@ static int
 nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
 {
 	char *err;
-	switch (nm_parse_one(ifname, &d->req, &err)) {
+	switch (nm_parse_one(ifname, &d->req, &err, 1)) {
 	case NM_PARSE_OK:
 		D("parse OK");
 		break;

From 7271d2eff2246341253aad4bb78a451b4db178db Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Mon, 25 Dec 2017 00:37:01 +0900
Subject: [PATCH 0668/2207] mem: large memory size support

---
 LINUX/netmap_linux.c         | 14 ++++++++++++++
 apps/pkt-gen/pkt-gen.c       |  2 +-
 sys/dev/netmap/netmap_kern.h |  2 ++
 sys/dev/netmap/netmap_mem2.c |  4 ++--
 sys/net/netmap_user.h        |  4 ++--
 5 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 9f2fc38ac..203599145 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -51,6 +51,15 @@ nm_os_malloc(size_t size)
 	return rv;
 }
 
+void *
+nm_os_vmalloc(size_t size)
+{
+	void *rv = vmalloc(size);
+	if (IS_ERR(rv))
+		return NULL;
+	return rv;
+}
+
 void *
 nm_os_realloc(void *addr, size_t new_size, size_t old_size)
 {
@@ -67,6 +76,11 @@ nm_os_free(void *addr){
 	kfree(addr);
 }
 
+void
+nm_os_vfree(void *addr){
+	vfree(addr);
+}
+
 void
 nm_os_selinfo_init(NM_SELINFO_T *si)
 {
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 62643116e..93db2b565 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2965,7 +2965,7 @@ main(int arc, char **argv)
 		goto out;
 	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %dKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
+	D("mapped %luKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
 
 	if (g.virt_header) {
 		/* Set the virtio-net header length, since the user asked
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index dee654caf..fd8d1719e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -298,8 +298,10 @@ void netmap_undo_zombie(struct ifnet *);
 
 /* os independent alloc/realloc/free */
 void *nm_os_malloc(size_t);
+void *nm_os_vmalloc(size_t);
 void *nm_os_realloc(void *, size_t new_size, size_t old_size);
 void nm_os_free(void *);
+void nm_os_vfree(void *);
 
 /* passes a packet up to the host stack.
  * If the packet is sent (or dropped) immediately it returns NULL,
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index de92335c0..2062de157 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2118,7 +2118,7 @@ netmap_mem_ext_free_pages(struct page **pages, int nr_pages)
 		kunmap(pages[i]);
 		put_page(pages[i]);
 	}
-	nm_os_free(pages);
+	nm_os_vfree(pages);
 }
 
 static void
@@ -2206,7 +2206,7 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	start = p >> PAGE_SHIFT;
 	nr_pages = end - start;
 
-	pages = nm_os_malloc(nr_pages * sizeof(*pages));
+	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
 	if (pages == NULL) {
 		error = ENOMEM;
 		goto out;
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 126a88c33..98f126af3 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -113,7 +113,7 @@
 	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
 
 #define NETMAP_BUF(ring, index)				\
-	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
+	((char *)(ring) + (ring)->buf_ofs + ((long)(index)*(ring)->nr_buf_size))
 
 #define NETMAP_BUF_IDX(ring, buf)			\
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
@@ -223,7 +223,7 @@ struct nm_desc {
 	struct nm_desc *self; /* point to self if netmap. */
 	int fd;
 	void *mem;
-	uint32_t memsize;
+	uint64_t memsize;
 	int done_mmap;	/* set if mem is the result of mmap */
 	struct netmap_if * const nifp;
 	uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;

From 8c120a389cbc1fc11bc82ef126c53d8ecc70268c Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Dec 2017 21:04:03 +0900
Subject: [PATCH 0669/2207] unnecessary debug in the master

---
 LINUX/if_e1000_netmap.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 8159a2d76..f0ceb1a61 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -315,7 +315,6 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]);
 		if (i < 0) // XXX something wrong here, can it really happen ?
 			i += rxr->count;
-		D("i now is %d", i);
 		wmb(); /* Force memory writes to complete */
 		writel(i, hw->hw_addr + rxr->rdt);
 	}

From 1f659e6a737199d6cfd2e34b9ff47529c2933c02 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Dec 2017 21:27:48 +0900
Subject: [PATCH 0670/2207] silence compiler

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 93db2b565..d434a8db1 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1623,7 +1623,7 @@ sender_body(void *data)
 			}
 			m = send_packets(txring, pkt, frame, size, targ->g,
 					 limit, options, frags);
-			ND("limit %d tail %d frags %d m %d",
+			ND("limit %lu tail %d frags %d m %d",
 				limit, txring->tail, frags, m);
 			sent += m;
 			if (m > 0) //XXX-ste: can m be 0?

From 1e68abf1f71145a9d9e91d08909abb2e94cf6072 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Jan 2018 12:33:41 +0100
Subject: [PATCH 0671/2207] extmem: don't init bitmaps during creation

Bitmap initialization is already done during netmap_mem_finalize(),
so the action was duplicated.
---
 sys/dev/netmap/netmap_mem2.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 2062de157..686157791 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2356,10 +2356,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 		p->invalid_bitmap[0] |= 1U;
 	}
 
-	error = netmap_mem_init_bitmaps(&nme->up);
-	if (error)
-		goto out_delete;
-
 	netmap_mem_ext_register(nme);
 
 	return &nme->up;

From 4c526beb34ca8ae82a0821d2dfbe5c380a0ee89a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Jan 2018 18:19:07 +0100
Subject: [PATCH 0672/2207] nm_open: remove stale code

---
 sys/net/netmap_user.h | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 98f126af3..08f8636af 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -960,22 +960,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (req) {
 		d->req = *req;
-#if 0
-		if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-			if (IS_NETMAP_DESC(parent) &&
-					(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
-				snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
-				errno = EINVAL;
-				goto fail;
-			}
-		        pi = nmreq_pointer_get(&d->req);
-			if (pi == NULL) {
-				snprintf(errmsg, MAXERRMSG, "missing netmap_pools_info pointer");
-				errno = EINVAL;
-				goto fail;
-			}
-		}
-#endif
 	} else {
 		d->req.nr_arg1 = 4;
 		d->req.nr_arg2 = 0;

From 700b8f1bf43a4586cd51590aade986a0fa6c7801 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Jan 2018 18:22:24 +0100
Subject: [PATCH 0673/2207] nm_open: more sensible handling of NM_OPEN_NO_MMAP

---
 sys/net/netmap_user.h | 57 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 48 insertions(+), 9 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 08f8636af..61da64827 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -923,8 +923,12 @@ nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
  * An invalid netmap name will return errno = 0;
  * You can pass a pointer to a pre-filled nm_desc to add special
  * parameters. Flags is used as follows
- * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
+ * NM_OPEN_NO_MMAP	use the memory from arg, only
  *			if the nr_arg2 (memory block) matches.
+ *			Special case: if arg is NULL, skip the
+ *			mmap entirely (maybe because you are going
+ *			to do it by yourself, or you plan to call
+ *			nm_mmap() only later)
  * NM_OPEN_ARG1		use req.nr_arg1 from arg
  * NM_OPEN_ARG2		use req.nr_arg2 from arg
  * NM_OPEN_RING_CFG	user ring config from arg
@@ -967,16 +971,50 @@ nm_open(const char *ifname, const struct nmreq *req,
 	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
-		if (nm_parse(ifname, d, errmsg) < 0)
+		char *err;
+		switch (nm_parse_one(ifname, &d->req, &err, 1)) {
+		case NM_PARSE_OK:
+			break;
+		case NM_PARSE_MEMID:
+			if ((new_flags & NM_OPEN_NO_MMAP) &&
+					IS_NETMAP_DESC(parent)) {
+				/* ignore the memid setting, since we are
+				 * going to use the parent's one
+				 */
+				break;
+			}
+			errno = nm_interp_memid(err, &d->req, &err);
+			if (!errno)
+				break;
+			/* fallthrough */
+		default:
+			strncpy(errmsg, err, MAXERRMSG);
+			errmsg[MAXERRMSG-1] = '\0';
+			free(err);
 			goto fail;
+		}
+		d->self = d;
 	}
 
+	/* compatibility checks for POOL_SCREATE and NM_OPEN flags
+	 * the first check may be dropped once we have a larger nreq
+	 */
 	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-		if (IS_NETMAP_DESC(parent) &&
-				(new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3))) {
-			snprintf(errmsg, MAXERRMSG, "POOLS_CREATE is incompatibile with NM_OPEN_ARG? flags");
-			errno = EINVAL;
-			goto fail;
+		if (IS_NETMAP_DESC(parent)) {
+		       	if (new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3)) {
+				snprintf(errmsg, MAXERRMSG,
+						"POOLS_CREATE is incompatibile "
+						"with NM_OPEN_ARG? flags");
+				errno = EINVAL;
+				goto fail;
+			}
+			if (new_flags & NM_OPEN_NO_MMAP) {
+				snprintf(errmsg, MAXERRMSG,
+						"POOLS_CREATE is incompatible "
+						"with NM_OPEN_NO_MMAP flag");
+				errno = EINVAL;
+				goto fail;
+			}
 		}
 	}
 
@@ -997,7 +1035,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 			d->req.nr_arg1 = parent->req.nr_arg1;
 		}
-		if (new_flags & NM_OPEN_ARG2) {
+		if (new_flags & (NM_OPEN_ARG2 | NM_OPEN_NO_MMAP)) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
 			d->req.nr_arg2 = parent->req.nr_arg2;
 		}
@@ -1111,7 +1149,8 @@ nm_close(struct nm_desc *d)
 	 */
 	static void *__xxzt[] __attribute__ ((unused))  =
 		{ (void *)nm_open, (void *)nm_inject,
-		  (void *)nm_dispatch, (void *)nm_nextpkt } ;
+		  (void *)nm_dispatch, (void *)nm_nextpkt,
+	          (void *)nm_parse } ;
 
 	if (d == NULL || d->self != d)
 		return EINVAL;

From 4bd573f44af4c454076712acbf0b16d95cfffcd6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Jan 2018 10:25:09 +0000
Subject: [PATCH 0674/2207] FreeBSD: fix compilation

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 546a84f2f..4f0523c40 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3258,7 +3258,7 @@ netmap_attach_common(struct netmap_adapter *na)
 	if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
 		na->if_input = na->ifp->if_input; /* for netmap_send_up */
 	}
-	pa->pdev = na; /* make sure netmap_mem_map() is called */
+	na->pdev = na; /* make sure netmap_mem_map() is called */
 #endif /* __FreeBSD__ */
 	if (na->nm_krings_create == NULL) {
 		/* we assume that we have been called by a driver,

From 7b623f113c651b7eba0885d7f3f1675e8e5eb2eb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Jan 2018 10:25:37 +0000
Subject: [PATCH 0675/2207] fix const-related warning

---
 sys/net/netmap_virt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 0c127601f..1b8b26cc9 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -124,7 +124,7 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
 static inline void *
 nmreq_pointer_get(const struct nmreq *nmr)
 {
-	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
+	const uintptr_t *pp = (const uintptr_t *)&nmr->nr_arg1;
 	return (void *)*pp;
 }
 

From 78eb98123da0ec0fdb2e8f945955582c64ab786e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Jan 2018 19:26:48 +0100
Subject: [PATCH 0676/2207] extmem: factorize out os-dependend code

---
 LINUX/netmap_linux.c         | 137 +++++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_mem2.c | 126 +++++++-------------------------
 sys/dev/netmap/netmap_mem2.h |  10 +++
 3 files changed, 172 insertions(+), 101 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 203599145..7703b5b0f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -168,12 +168,149 @@ nm_os_ifnet_fini(void)
 	}
 }
 
+
 unsigned
 nm_os_ifnet_mtu(struct ifnet *ifp)
 {
 	return ifp->mtu;
 }
 
+#ifdef WITH_EXTMEM
+struct nm_os_extmem {
+	struct page **pages;
+	int nr_pages;
+	int mapped;
+};
+
+void
+nm_os_extmem_delete(struct nm_os_extmem *e)
+{
+	int i;
+	for (i = 0; i < e->nr_pages; i++) {
+		if (i < e->mapped)
+			kunmap(e->pages[i]);
+		put_page(e->pages[i]);
+	}
+	if (e->pages)
+		nm_os_vfree(e->pages);
+	nm_os_free(e);
+}
+
+char *
+nm_os_extmem_nextpage(struct nm_os_extmem *e)
+{
+	if (e->mapped >= e->nr_pages)
+		return NULL;
+	D("mapping %d/%d", e->mapped, e->nr_pages);
+	return kmap(e->pages[e->mapped++]);
+}
+
+int
+nm_os_extmem_isequal(struct nm_os_extmem *e1, struct nm_os_extmem *e2)
+{
+	int i;
+
+	if (e1->nr_pages != e2->nr_pages)
+		return 0;
+
+	for (i = 0; i < e1->nr_pages; i++)
+		if (e1->pages[i] != e2->pages[i])
+			return 0;
+
+	return 1;
+}
+
+int
+nm_os_extmem_nr_pages(struct nm_os_extmem *e)
+{
+	return e->nr_pages;
+}
+
+
+struct nm_os_extmem *
+nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+{
+	unsigned long end, start;
+	int nr_pages, res;
+	struct nm_os_extmem *e = NULL;
+	int err;
+	struct page **pages;
+
+	end = (p + pi->memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	start = p >> PAGE_SHIFT;
+	nr_pages = end - start;
+
+	e = nm_os_malloc(sizeof(*e));
+	if (e == NULL) {
+		D("failed to allocate os_extmem");
+		err = ENOMEM;
+		goto out;
+	}
+
+	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
+	if (pages == NULL) {
+		D("failed to allocate pages array (nr_pages %d)", nr_pages);
+		err = ENOMEM;
+		goto out;
+	}
+
+	e->pages = pages;
+
+#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			pages,
+			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
+#elif defined(NETMAP_LINUX_HAVE_GUP_5ARGS)
+	res = get_user_pages_unlocked(
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
+	res = get_user_pages_unlocked(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages);
+#else
+	down_read(¤t->mm->mmap_sem);
+	res = get_user_pages(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			1, /* write */
+			0, /* don't force */
+			pages,
+			NULL);
+	up_read(¤t->mm->mmap_sem);
+#endif	/* NETMAP_LINUX_GUP */
+
+	e->nr_pages = res;
+
+	if (res < nr_pages) {
+		D("failed to get user pages: res %d nr_pages %d", res, nr_pages);
+		err = EFAULT;
+		goto out;
+	}
+
+	return e;
+
+out:
+	if (e)
+		nm_os_extmem_delete(e);
+	if (perror)
+		*perror = err;
+	return NULL;
+}
+#endif /* WITH_EXTMEM */
+
 #ifdef NETMAP_LINUX_HAVE_IOMMU
 #include 
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 686157791..1698c7b0c 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2046,8 +2046,7 @@ netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
 struct netmap_mem_ext {
 	struct netmap_mem_d up;
 
-	struct page **pages;
-	int nr_pages;
+	struct nm_os_extmem *os;
 	struct netmap_mem_ext *next, *prev;
 };
 
@@ -2077,29 +2076,14 @@ netmap_mem_ext_unregister(struct netmap_mem_ext *e)
 	e->prev = e->next = NULL;
 }
 
-static int
-netmap_mem_ext_same_pages(struct netmap_mem_ext *e, struct page **pages, int nr_pages)
-{
-	int i;
-
-	if (e->nr_pages != nr_pages)
-		return 0;
-
-	for (i = 0; i < nr_pages; i++)
-		if (pages[i] != e->pages[i])
-			return 0;
-
-	return 1;
-}
-
 static struct netmap_mem_ext *
-netmap_mem_ext_search(struct page **pages, int nr_pages)
+netmap_mem_ext_search(struct nm_os_extmem *os)
 {
 	struct netmap_mem_ext *e;
 
 	NM_MTX_LOCK(nm_mem_ext_list_lock);
 	for (e = netmap_mem_ext_list; e; e = e->next) {
-		if (netmap_mem_ext_same_pages(e, pages, nr_pages)) {
+		if (nm_os_extmem_isequal(e->os, os)) {
 			netmap_mem_get(&e->up);
 			break;
 		}
@@ -2109,18 +2093,6 @@ netmap_mem_ext_search(struct page **pages, int nr_pages)
 }
 
 
-static void
-netmap_mem_ext_free_pages(struct page **pages, int nr_pages)
-{
-	int i;
-
-	for (i = 0; i < nr_pages; i++) {
-		kunmap(pages[i]);
-		put_page(pages[i]);
-	}
-	nm_os_vfree(pages);
-}
-
 static void
 netmap_mem_ext_delete(struct netmap_mem_d *d)
 {
@@ -2138,11 +2110,8 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 			p->lut = NULL;
 		}
 	}
-	if (e->pages) {
-		netmap_mem_ext_free_pages(e->pages, e->nr_pages);
-		e->pages = NULL;
-		e->nr_pages = 0;
-	}
+	if (e->os)
+		nm_os_extmem_delete(e->os);
 	netmap_mem2_delete(d);
 }
 
@@ -2173,12 +2142,12 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	uintptr_t p = *(uintptr_t *)&nmr->nr_arg1;
 	struct netmap_pools_info pi;
 	int error = 0;
-	unsigned long end, start;
-	int nr_pages, res, i, j;
-	struct page **pages = NULL;
+	int i, j;
 	struct netmap_mem_ext *nme;
 	char *clust;
 	size_t off;
+	struct nm_os_extmem *os = NULL;
+	int nr_pages;
 
 	error = copyin((void *)p, &pi, sizeof(pi));
 	if (error)
@@ -2202,60 +2171,15 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			pi.ring_pool_objtotal, pi.ring_pool_objsize,
 			pi.buf_pool_objtotal, pi.buf_pool_objsize);
 		
-	end = (p + pi.memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	start = p >> PAGE_SHIFT;
-	nr_pages = end - start;
-
-	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
-	if (pages == NULL) {
-		error = ENOMEM;
+	os = nm_os_extmem_create(p, &pi, &error);
+	if (os == NULL) {
+		D("os extmem creation failed");
 		goto out;
 	}
 
-#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
-	res = get_user_pages_unlocked(
-			p,
-			nr_pages,
-			pages,
-			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
-#elif defined(NETMAP_LINUX_HAVE_GUP_5ARGS)
-	res = get_user_pages_unlocked(
-			p,
-			nr_pages,
-			1, /* write */
-			0, /* don't force */
-			pages);
-#elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
-	res = get_user_pages_unlocked(
-			current,
-			current->mm,
-			p,
-			nr_pages,
-			1, /* write */
-			0, /* don't force */
-			pages);
-#else
-	down_read(¤t->mm->mmap_sem);
-	res = get_user_pages(
-			current,
-			current->mm,
-			p,
-			nr_pages,
-			1, /* write */
-			0, /* don't force */
-			pages,
-			NULL);
-	up_read(¤t->mm->mmap_sem);
-#endif	/* NETMAP_LINUX_GUP */
-
-	if (res < nr_pages) {
-		error = EFAULT;
-		goto out_unmap;
-	}
-
-	nme = netmap_mem_ext_search(pages, nr_pages);
+	nme = netmap_mem_ext_search(os);
 	if (nme) {
-		netmap_mem_ext_free_pages(pages, nr_pages);
+		nm_os_extmem_delete(os);
 		return &nme->up;
 	}
 	D("not found, creating new");
@@ -2270,15 +2194,17 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	if (nme == NULL)
 		goto out_unmap;
 					
+	nr_pages = nm_os_extmem_nr_pages(os);
+
 	/* from now on pages will be released by nme destructor;
 	 * we let res = 0 to prevent release in out_unmap below
 	 */
-	res = 0;
-	nme->pages = pages;
-	nme->nr_pages = nr_pages;
+	nme->os = os;
+	os = NULL; /* pass ownership */
 	nme->up.flags |= NETMAP_MEM_EXT;
 
-	clust = kmap(*pages);
+
+	clust = nm_os_extmem_nextpage(nme->os);
 	off = 0;
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &nme->up.pools[i];
@@ -2322,13 +2248,15 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			ND("too big, recomputing offset...");
 			skip = PAGE_SIZE - (off & PAGE_MASK);
 			while (noff >= PAGE_SIZE) {
+				char *old_clust = clust;
 				noff -= skip;
-				pages++;
+				clust = nm_os_extmem_nextpage(nme->os);
 				nr_pages--;
 				ND("noff %zu page %p nr_pages %d", noff,
 						page_to_virt(*pages), nr_pages);
 				if (noff > 0 && !nm_isset(p->invalid_bitmap, j) &&
-					(nr_pages == 0 || *pages != *(pages - 1) + 1))
+					(nr_pages == 0 ||
+					 old_clust + PAGE_SIZE != clust))
 				{
 					/* out of space or non contiguous,
 					 * drop this object
@@ -2341,8 +2269,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				skip = PAGE_SIZE;
 			}
 			off = noff;
-			if (nr_pages > 0)
-				clust = kmap(*pages);
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;
@@ -2363,10 +2289,8 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 out_delete:
 	netmap_mem_put(&nme->up);
 out_unmap:
-	for (i = 0; i < res; i++)
-		put_page(pages[i]);
-	if (res)
-		nm_os_free(pages);
+	if (os)
+		nm_os_extmem_delete(os);
 out:
 	if (perror)
 		*perror = error;
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index a57784764..58d1afb32 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -175,4 +175,14 @@ int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
 
 uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 
+#ifdef WITH_EXTMEM
+#include 
+struct nm_os_extmem; /* opaque */
+struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct netmap_pools_info *, int *perror);
+char *nm_os_extmem_nextpage(struct nm_os_extmem *);
+int nm_os_extmem_nr_pages(struct nm_os_extmem *);
+int nm_os_extmem_isequal(struct nm_os_extmem *, struct nm_os_extmem *);
+void nm_os_extmem_delete(struct nm_os_extmem *);
+#endif /* WITH_EXTMEM */
+
 #endif

From a9890ef4030ab81a2a1e869dc429a7cecbd585de Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 26 Jan 2018 18:29:16 +0000
Subject: [PATCH 0677/2207] extmem: fix offset computation

---
 sys/dev/netmap/netmap_mem2.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1698c7b0c..2a80b7190 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2236,7 +2236,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 
 		for (j = 0; j < o->num && nr_pages > 0; j++) {
 			size_t noff;
-			size_t skip;
 
 			p->lut[j].vaddr = clust + off;
 			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
@@ -2246,10 +2245,9 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				continue;
 			}
 			ND("too big, recomputing offset...");
-			skip = PAGE_SIZE - (off & PAGE_MASK);
 			while (noff >= PAGE_SIZE) {
 				char *old_clust = clust;
-				noff -= skip;
+				noff -= PAGE_SIZE;
 				clust = nm_os_extmem_nextpage(nme->os);
 				nr_pages--;
 				ND("noff %zu page %p nr_pages %d", noff,
@@ -2266,7 +2264,6 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 				}
 				if (nr_pages == 0)
 					break;
-				skip = PAGE_SIZE;
 			}
 			off = noff;
 		}

From b793d525a770edfdd77a13073371ae4201e707c3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 26 Jan 2018 18:43:51 +0000
Subject: [PATCH 0678/2207] extmem: FreeBSD support

---
 sys/dev/netmap/netmap_freebsd.c | 110 ++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_kern.h    |   2 +-
 sys/dev/netmap/netmap_mem2.c    |   3 +
 3 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index ace44d05e..8b8644d46 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -613,6 +613,116 @@ nm_os_vi_detach(struct ifnet *ifp)
 	if_free(ifp);
 }
 
+#ifdef WITH_EXTMEM
+#include 
+#include 
+struct nm_os_extmem {
+	vm_object_t obj;
+	vm_offset_t kva;
+        vm_offset_t size;
+	vm_pindex_t scan;
+};
+
+void
+nm_os_extmem_delete(struct nm_os_extmem *e)
+{
+	D("freeing %lx bytes", e->size);
+	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
+	nm_os_free(e);
+}
+
+char *
+nm_os_extmem_nextpage(struct nm_os_extmem *e)
+{
+	char *rv = NULL;
+	if (e->scan < e->kva + e->size) {
+		rv = (char *)e->scan;
+		e->scan += PAGE_SIZE;
+	}
+	return rv;
+}
+
+int
+nm_os_extmem_isequal(struct nm_os_extmem *e1, struct nm_os_extmem *e2)
+{
+	return (e1->obj == e1->obj);
+}
+
+int
+nm_os_extmem_nr_pages(struct nm_os_extmem *e)
+{
+	return e->size >> PAGE_SHIFT;
+}
+
+struct nm_os_extmem *
+nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+{
+	vm_map_t map;
+	vm_map_entry_t entry;
+	vm_object_t obj;
+	vm_prot_t prot;
+	vm_pindex_t index;
+	boolean_t wired;
+	struct nm_os_extmem *e = NULL;
+	int rv, error = 0;
+
+	e = nm_os_malloc(sizeof(*e));
+	if (e == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	map = &curthread->td_proc->p_vmspace->vm_map;
+	rv = vm_map_lookup(&map, p, VM_PROT_RW, &entry,
+			&obj, &index, &prot, &wired);
+	if (rv != KERN_SUCCESS) {
+		D("address %lx not found", p);
+		goto out_free;
+	}
+	/* check that we are given the whole vm_object ? */
+	vm_map_lookup_done(map, entry);
+
+	// XXX can we really use obj after releasing the map lock?
+	e->obj = obj;
+	vm_object_reference(obj);
+	/* wire the memory and add the vm_object to the kernel map,
+	 * to make sure that it is not fred even if the processes that
+	 * are mmap()ing it all exit
+	 */
+	e->kva = vm_map_min(kernel_map);
+	e->size = obj->size << PAGE_SHIFT;
+	rv = vm_map_find(kernel_map, obj, 0, &e->kva, e->size, 0,
+			VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
+			VM_PROT_READ | VM_PROT_WRITE, 0);
+	if (rv != KERN_SUCCESS) {
+		D("vm_map_find(%lx) failed", e->size);
+		goto out_rel;
+	}
+	rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,
+			VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
+	if (rv != KERN_SUCCESS) {
+		D("vm_map_wire failed");
+		goto out_rem;
+	}
+
+	e->scan = e->kva;
+
+	return e;
+
+out_rem:
+	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
+	e->obj = NULL;
+out_rel:
+	vm_object_deallocate(e->obj);
+out_free:
+	nm_os_free(e);
+out:
+	if (perror)
+		*perror = error;
+	return NULL;
+}
+#endif /* WITH_EXTMEM */
+
 /* ======================== PTNETMAP SUPPORT ========================== */
 
 #ifdef WITH_PTNETMAP_GUEST
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index fd8d1719e..61e32a761 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -75,7 +75,7 @@
 #define WITH_GENERIC
 #define WITH_PTNETMAP_HOST	/* ptnetmap host support */
 #define WITH_PTNETMAP_GUEST	/* ptnetmap guest support */
-
+#define WITH_EXTMEM
 #endif
 
 #if defined(__FreeBSD__)
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 2a80b7190..145c50e51 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2238,6 +2238,9 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 			size_t noff;
 
 			p->lut[j].vaddr = clust + off;
+#if !defined(linux) && !defined(_WIN32)
+			p->lut[j].paddr = vtophys(p->lut[j].vaddr);
+#endif
 			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
 			noff = off + p->_objsize;
 			if (noff < PAGE_SIZE) {

From 445fa9926e601fc12dae40afebb00ce9dc47c71e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jan 2018 16:34:46 +0100
Subject: [PATCH 0679/2207] extmem: parse the option in the new API

---
 LINUX/netmap_linux.c         |  4 +--
 apps/pkt-gen/pkt-gen.c       |  2 +-
 sys/dev/netmap/netmap.c      | 36 +++++++++++++++++++++++----
 sys/dev/netmap/netmap_mem2.c | 48 ++++++++++++++++--------------------
 sys/dev/netmap/netmap_mem2.h |  6 ++---
 sys/net/netmap.h             | 12 ++++++++-
 sys/net/netmap_user.h        | 17 +++++++++++--
 7 files changed, 84 insertions(+), 41 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 7703b5b0f..1c52e0e96 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -228,7 +228,7 @@ nm_os_extmem_nr_pages(struct nm_os_extmem *e)
 
 
 struct nm_os_extmem *
-nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 {
 	unsigned long end, start;
 	int nr_pages, res;
@@ -236,7 +236,7 @@ nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
 	int err;
 	struct page **pages;
 
-	end = (p + pi->memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	end = (p + pi->nr_memsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	start = p >> PAGE_SHIFT;
 	nr_pages = end - start;
 
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d434a8db1..d07f6daa2 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2965,7 +2965,7 @@ main(int arc, char **argv)
 		goto out;
 	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %luKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
+	D("mapped %"PRIu32"KB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
 
 	if (g.virt_header) {
 		/* Set the virtio-net header length, since the user asked
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4f0523c40..145b3b333 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2308,13 +2308,26 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_LOCK();
 			do {
 				u_int memflags;
+				struct nmreq_option *opt;
 
 				if (priv->np_nifp != NULL) {	/* thread already registered */
 					error = EBUSY;
 					break;
 				}
 
-				if (req->nr_mem_id) {
+#ifdef WITH_EXTMEM
+				opt = nmreq_findoption(hdr, NETMAP_REQ_OPT_EXTMEM);
+				if (opt != NULL) {
+					struct nmreq_opt_extmem *e =
+						(struct nmreq_opt_extmem *)opt;
+					nmd = netmap_mem_ext_create(e->nro_usrptr,
+							&e->nro_info, &error);
+					if (nmd == NULL)
+						break;
+				}
+#endif /* WITH_EXTMEM */
+
+				if (nmd == NULL && req->nr_mem_id) {
 					/* find the allocator and get a reference */
 					nmd = netmap_mem_find(req->nr_mem_id);
 					if (nmd == NULL) {
@@ -2569,8 +2582,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 #endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
-			struct nmreq_pools_info_get *req =
-				(struct nmreq_pools_info_get *)hdr->nr_body;
+			struct nmreq_pools_info *req =
+				(struct nmreq_pools_info *)hdr->nr_body;
 			/* Get information from the memory allocator. This
 			 * netmap device must already be bound to a port.
 			 * Note that hdr->nr_name is ignored. */
@@ -2701,7 +2714,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
-		return sizeof(struct nmreq_pools_info_get);
+		return sizeof(struct nmreq_pools_info);
 	}
 	return 0;
 }
@@ -2709,7 +2722,20 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 size_t
 nmreq_opt_size_by_type(uint16_t nro_reqtype)
 {
-	return 0;
+	size_t rv = sizeof(struct nmreq_option);
+#ifdef NETMAP_REQ_OPT_DEBUG
+	if (nro_reqtype & NETMAP_REQ_OPT_DEBUG)
+		return (nro_reqtype & ~NETMAP_REQ_OPT_DEBUG);
+#endif /* NETMAP_REQ_OPT_DEBUG */
+	switch (nro_reqtype) {
+#ifdef WITH_EXTMEM
+	case NETMAP_REQ_OPT_EXTMEM:
+		rv = sizeof(struct nmreq_opt_extmem);
+		break;
+	}
+#endif /* WITH_EXTMEM */
+	/* subtract the common header */
+	return rv - sizeof(struct nmreq_option);
 }
 
 int
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 145c50e51..dd7198483 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2013,7 +2013,7 @@ struct netmap_mem_ops netmap_mem_global_ops = {
 };
 
 int
-netmap_mem_pools_info_get(struct nmreq_pools_info_get *req,
+netmap_mem_pools_info_get(struct nmreq_pools_info *req,
 				struct netmap_mem_d *nmd)
 {
 	int ret;
@@ -2137,10 +2137,8 @@ struct netmap_mem_ops netmap_mem_ext_ops = {
 };
 
 struct netmap_mem_d *
-netmap_mem_ext_create(struct nmreq *nmr, int *perror)
+netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 {
-	uintptr_t p = *(uintptr_t *)&nmr->nr_arg1;
-	struct netmap_pools_info pi;
 	int error = 0;
 	int i, j;
 	struct netmap_mem_ext *nme;
@@ -2149,29 +2147,25 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 	struct nm_os_extmem *os = NULL;
 	int nr_pages;
 
-	error = copyin((void *)p, &pi, sizeof(pi));
-	if (error)
-		goto out;
-
 	// XXX sanity checks
-	if (pi.if_pool_objtotal == 0)
-		pi.if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num;
-	if (pi.if_pool_objsize == 0)
-		pi.if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size;
-	if (pi.ring_pool_objtotal == 0)
-		pi.ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num;
-	if (pi.ring_pool_objsize == 0)
-		pi.ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size;
-	if (pi.buf_pool_objtotal == 0)
-		pi.buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
-	if (pi.buf_pool_objsize == 0)
-		pi.buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
+	if (pi->nr_if_pool_objtotal == 0)
+		pi->nr_if_pool_objtotal = netmap_min_priv_params[NETMAP_IF_POOL].num;
+	if (pi->nr_if_pool_objsize == 0)
+		pi->nr_if_pool_objsize = netmap_min_priv_params[NETMAP_IF_POOL].size;
+	if (pi->nr_ring_pool_objtotal == 0)
+		pi->nr_ring_pool_objtotal = netmap_min_priv_params[NETMAP_RING_POOL].num;
+	if (pi->nr_ring_pool_objsize == 0)
+		pi->nr_ring_pool_objsize = netmap_min_priv_params[NETMAP_RING_POOL].size;
+	if (pi->nr_buf_pool_objtotal == 0)
+		pi->nr_buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
+	if (pi->nr_buf_pool_objsize == 0)
+		pi->nr_buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
 	D("if %d %d ring %d %d buf %d %d",
-			pi.if_pool_objtotal, pi.if_pool_objsize,
-			pi.ring_pool_objtotal, pi.ring_pool_objsize,
-			pi.buf_pool_objtotal, pi.buf_pool_objsize);
+			pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize,
+			pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize,
+			pi->nr_buf_pool_objtotal, pi->nr_buf_pool_objsize);
 		
-	os = nm_os_extmem_create(p, &pi, &error);
+	os = nm_os_extmem_create(usrptr, pi, &error);
 	if (os == NULL) {
 		D("os extmem creation failed");
 		goto out;
@@ -2186,9 +2180,9 @@ netmap_mem_ext_create(struct nmreq *nmr, int *perror)
 
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){
-				{ pi.if_pool_objsize, pi.if_pool_objtotal },
-				{ pi.ring_pool_objsize, pi.ring_pool_objtotal },
-				{ pi.buf_pool_objsize, pi.buf_pool_objtotal }},
+				{ pi->nr_if_pool_objsize, pi->nr_if_pool_objtotal },
+				{ pi->nr_ring_pool_objsize, pi->nr_ring_pool_objtotal },
+				{ pi->nr_buf_pool_objsize, pi->nr_buf_pool_objtotal }},
 			&netmap_mem_ext_ops,
 			&error);
 	if (nme == NULL)
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 58d1afb32..66bed977c 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -151,7 +151,7 @@ struct netmap_mem_d* netmap_mem_find(nm_memid_t);
 unsigned netmap_mem_bufsize(struct netmap_mem_d *nmd);
 
 #ifdef WITH_EXTMEM
-struct netmap_mem_d* netmap_mem_ext_create(struct nmreq *, int *);
+struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *, int *);
 #else /* !WITH_EXTMEM */
 #define netmap_mem_ext_create(nmr, _perr) \
 	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
@@ -166,7 +166,7 @@ struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16
 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
 #endif /* WITH_PTNETMAP_GUEST */
 
-int netmap_mem_pools_info_get(struct nmreq_pools_info_get *,
+int netmap_mem_pools_info_get(struct nmreq_pools_info *,
 				struct netmap_mem_d *);
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
@@ -178,7 +178,7 @@ uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 #ifdef WITH_EXTMEM
 #include 
 struct nm_os_extmem; /* opaque */
-struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct netmap_pools_info *, int *perror);
+struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct nmreq_pools_info *, int *perror);
 char *nm_os_extmem_nextpage(struct nm_os_extmem *);
 int nm_os_extmem_nr_pages(struct nm_os_extmem *);
 int nm_os_extmem_isequal(struct nm_os_extmem *, struct nm_os_extmem *);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 136264228..a1bcc06a9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -664,7 +664,7 @@ struct nmreq_vale_polling {
  * to a given netmap control device (used i.e. by a ptnetmap-enabled
  * hypervisor). The nr_hdr.nr_name field is ignored.
  */
-struct nmreq_pools_info_get {
+struct nmreq_pools_info {
 	uint64_t	nr_memsize;
 	uint16_t	nr_mem_id;
 	uint64_t	nr_if_pool_offset;
@@ -678,4 +678,14 @@ struct nmreq_pools_info_get {
 	uint32_t	nr_buf_pool_objsize;
 };
 
+/*
+ * data for NETMAP_REQ_OPT_* options
+ */
+
+struct nmreq_opt_extmem {
+	struct nmreq_option	nro_opt;	/* common header */
+	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */
+	struct nmreq_pools_info	nro_info;	/* (in/out) */
+};
+
 #endif /* _NET_NETMAP_H_ */
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 61da64827..775019598 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -834,6 +834,7 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 static int
 nm_interp_memid(const char *memid, struct nmreq *req, char **err)
 {
+#if 0
 	int fd = -1;
 	char errmsg[MAXERRMSG] = "";
 	struct nmreq greq;
@@ -889,6 +890,12 @@ nm_interp_memid(const char *memid, struct nmreq *req, char **err)
 	if (err && !*err)
 		*err = strdup(errmsg);
 	return errno;
+#else
+	(void)memid;
+	(void)req;
+	(void)err;
+	return EOPNOTSUPP;
+#endif
 }
 
 static int
@@ -941,7 +948,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	const struct nm_desc *parent = arg;
 	char errmsg[MAXERRMSG] = "";
 	uint32_t nr_reg;
-	struct netmap_pools_info *pi = NULL;
+	struct nmreq_pools_info *pi = NULL;
 
 	if (strncmp(ifname, "netmap:", 7) &&
 			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@@ -996,6 +1003,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->self = d;
 	}
 
+#if 0
 	/* compatibility checks for POOL_SCREATE and NM_OPEN flags
 	 * the first check may be dropped once we have a larger nreq
 	 */
@@ -1017,12 +1025,14 @@ nm_open(const char *ifname, const struct nmreq *req,
 			}
 		}
 	}
+#endif
 
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
+#if 0
 		if (new_flags & NM_OPEN_EXTMEM) {
 			if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
 				d->req.nr_cmd = NETMAP_POOLS_CREATE;
@@ -1031,6 +1041,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 				new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
 			}
 		}
+#endif
 		if (new_flags & NM_OPEN_ARG1) {
 			D("overriding ARG1 %d", parent->req.nr_arg1);
 			d->req.nr_arg1 = parent->req.nr_arg1;
@@ -1063,9 +1074,11 @@ nm_open(const char *ifname, const struct nmreq *req,
 	/* add the *XPOLL flags */
 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
 
+#if 0
 	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
 		pi = nmreq_pointer_get(&d->req);
 	}
+#endif
 
 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
@@ -1074,7 +1087,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 
 	if (pi != NULL) {
 		d->mem = pi;
-		d->memsize = pi->memsize;
+		d->memsize = pi->nr_memsize;
 		nm_init_offsets(d);
 	} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
 		/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */

From e4ce22691c0000b8be21eef95f37942c1957f9ed Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 09:29:44 +0100
Subject: [PATCH 0680/2207] testmmap: fix compilation

---
 sys/net/netmap_user.h |  2 +-
 utils/ctrl-api-test.c |  2 +-
 utils/testmmap.c      | 14 ++++++++------
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 775019598..bb250d06b 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -978,7 +978,7 @@ nm_open(const char *ifname, const struct nmreq *req,
 	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
-		char *err;
+		char *err = NULL;
 		switch (nm_parse_one(ifname, &d->req, &err, 1)) {
 		case NM_PARSE_OK:
 			break;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 21a1f8d4a..8d9b9cb42 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -360,7 +360,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 static int
 pools_info_get(int fd, struct TestContext *ctx)
 {
-	struct nmreq_pools_info_get req;
+	struct nmreq_pools_info req;
 	struct nmreq_header hdr;
 	int ret;
 
diff --git a/utils/testmmap.c b/utils/testmmap.c
index aabb2a81a..3f8548773 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -839,11 +839,11 @@ struct pools_info_field {
 	size_t off;
 	size_t size;
 };
-#define PIFD(n, f)	{ n, offsetof(struct netmap_pools_info, f), \
-	sizeof(((struct netmap_pools_info *)0)->f) }
+#define PIFD(n, f)	{ n, offsetof(struct nmreq_pools_info, nr_##f), \
+	sizeof(((struct nmreq_pools_info *)0)->nr_##f) }
 struct pools_info_field pools_info_fields[] = {
 	PIFD("memsize", memsize),
-	PIFD("memid", memid),
+	PIFD("mem_id", mem_id),
 	PIFD("if-off", if_pool_offset),
 	PIFD("if-tot", if_pool_objtotal),
 	PIFD("if-siz", if_pool_objsize),
@@ -857,7 +857,7 @@ struct pools_info_field pools_info_fields[] = {
 };
 #define PIF(t, p, o)	(*(t*)((void *)((char *)(p)+(o))))
 void
-pools_info_dump(int tab, struct netmap_pools_info *upi)
+pools_info_dump(int tab, struct nmreq_pools_info *upi)
 {
 	static const char space[] = "        ";
 	struct pools_info_field *f;
@@ -877,6 +877,9 @@ pools_info_dump(int tab, struct netmap_pools_info *upi)
 	}
 }
 
+
+static struct nmreq_pools_info curr_pools_info;
+
 /* prepare the curr_pools_info */
 void
 do_pools_info()
@@ -1356,7 +1359,6 @@ static struct nmreq_vale_list curr_vale_list;
 static struct nmreq_port_hdr curr_port_hdr;
 static struct nmreq_vale_newif curr_vale_newif;
 static struct nmreq_vale_polling curr_vale_polling;
-static struct nmreq_pools_info_get curr_pools_info_get;
 
 typedef void (*nmr_body_dump_fun)(void *);
 
@@ -1756,7 +1758,7 @@ do_hdr_type()
 		curr_hdr.nr_body = &curr_vale_polling;
 	} else if (strcmp(type, "pools-info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-		curr_hdr.nr_body = &curr_pools_info_get;
+		curr_hdr.nr_body = &curr_pools_info;
 	} else {
 		output("unknown type: %s", type);
 	}

From 97e8fe59fbcfb6eb9e35e67cac0141be30bffcea Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 17:29:33 +0100
Subject: [PATCH 0681/2207] testmmap: nmreq options support

---
 sys/dev/netmap/netmap.c |  1 +
 utils/testmmap.c        | 41 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 145b3b333..3bf82ed16 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2322,6 +2322,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						(struct nmreq_opt_extmem *)opt;
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
+					opt->nro_status = error;
 					if (nmd == NULL)
 						break;
 				}
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 3f8548773..adf4a4ae9 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1597,13 +1597,30 @@ nmr_body_dump_pools_info_get(void *b)
 	(void)b;
 }
 
+typedef void (*nmr_option_dump_fun)(struct nmreq_option *);
+
+static void
+nmr_option_dump_extmem(struct nmreq_option *opt)
+{
+	struct nmreq_opt_extmem *e =
+		(struct nmreq_opt_extmem *)opt;
+
+	printf("usrptr: %p\n", (void *)e->nro_usrptr);
+	printf("info:\n");
+	pools_info_dump(4, &e->nro_info);
+}
+
 static void
 nmr_option_dump(struct nmreq_option *opt)
 {
-	printf("type: %u [", opt->nro_reqtype);
+	nmr_option_dump_fun d = NULL;
+
+	printf("next: %p\n", opt->nro_next);
+	printf("type: %"PRIu32" [", opt->nro_reqtype);
 	switch (opt->nro_reqtype) {
 	case NETMAP_REQ_OPT_EXTMEM:
 		printf("extmem");
+		d = nmr_option_dump_extmem;
 		break;
 	default:
 #ifdef NETMAP_OPT_DEBUG
@@ -1616,7 +1633,10 @@ nmr_option_dump(struct nmreq_option *opt)
 		printf("???");
 	}
 	printf("]\n");
-	printf("next: %p\n", opt->nro_next);
+	printf("status: %"PRIu32" [%s]\n", 
+			opt->nro_status, strerror(opt->nro_status));
+	if (d)
+		d(opt);
 }
 
 static void
@@ -1765,6 +1785,17 @@ do_hdr_type()
 	output("type=%u", curr_hdr.nr_reqtype);
 }
 
+typedef void (*nmreq_opt_init)(struct nmreq_option *);
+
+static void
+nmreq_opt_extmem_init(struct nmreq_option *opt)
+{
+	struct nmreq_opt_extmem *e =
+		(struct nmreq_opt_extmem *)opt;
+	e->nro_usrptr = (uint64_t)last_mmap_addr;
+	e->nro_info.nr_memsize = last_memsize;
+}
+
 static void
 do_hdr_option()
 {
@@ -1772,12 +1803,15 @@ do_hdr_option()
 	struct nmreq_option **ptr = &curr_hdr.nr_options,
 			    *old = *ptr;
 	size_t sz = sizeof(struct nmreq_option);
+	nmreq_opt_init init = NULL;
 
 	while ( (type = nextarg()) ) {
 		uint16_t reqtype;
 
 		if (strcmp(type, "extmem") == 0) {
 			reqtype = NETMAP_REQ_OPT_EXTMEM;
+			sz = sizeof(struct nmreq_opt_extmem);
+			init = nmreq_opt_extmem_init;
 #ifdef NETMAP_OPT_DEBUG
 		} else {
 			reqtype = strtol(type, NULL, 0) | NETMAP_REQ_OPT_DEBUG;
@@ -1787,7 +1821,10 @@ do_hdr_option()
 		if (*ptr == NULL) {
 			output_err(-1, "malloc");
 		}
+		memset(*ptr, 0, sz);
 		(*ptr)->nro_reqtype = reqtype;
+		if (init)
+			init(*ptr);
 		ptr = &(*ptr)->nro_next;
 	}
 	*ptr = old;

From 968ab2504455fe237211d6667b8b4c24cb73d8e1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 19:05:33 +0100
Subject: [PATCH 0682/2207] nmreq_copyin: do not access userspace memory

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3bf82ed16..d1bc1cf64 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2772,7 +2772,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	}
 
 	bodysz = 2 * sizeof(void *) + rqsz;
-	for (src = hdr->nr_options; src; src = src->nro_next) {
+	for (src = hdr->nr_options; src; src = buf.nro_next) {
 		size_t optsz;
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)

From 51024b7dbb315cf70b606418b3cbac3e06a9892c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Feb 2018 19:05:54 +0100
Subject: [PATCH 0683/2207] nmreq_copyout: always restore the header

---
 sys/dev/netmap/netmap.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d1bc1cf64..78c06e49e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2860,21 +2860,22 @@ static int
 nmreq_copyout(struct nmreq_header *hdr, int error)
 {
 	struct nmreq_option *src, *dst;
-	void *ker = hdr->nr_body;
+	void *ker = hdr->nr_body, *bufstart;
 	void **ptrs;
 	size_t bodysz;
 
 	if (!hdr->nr_reserved)
 		return error;
 
-	if (error)
-		goto out;
-
 	/* restore the user pointers in the header */
-	ptrs = (void **)ker;
-	hdr->nr_body = *(ptrs - 2);
+	ptrs = (void **)ker - 2;
+	bufstart = ptrs;
+	hdr->nr_body = *ptrs++;
 	src = hdr->nr_options;
-	hdr->nr_options = *(ptrs - 1);
+	hdr->nr_options = *ptrs;
+
+	if (error)
+		goto out;
 
 	/* copy the body */
 	bodysz = nmreq_size_by_type(hdr->nr_reqtype);
@@ -2909,10 +2910,10 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 		dst = *ptrs;
 	}
 
-	hdr->nr_reserved = 0;
 
 out:
-	nm_os_free(ker);
+	hdr->nr_reserved = 0;
+	nm_os_free(bufstart);
 	return error;
 }
 

From adf2f450a50a66565e358dfcc17fda8cf6c01209 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:00:06 +0100
Subject: [PATCH 0684/2207] nmreq_copyin: fix size computations

---
 sys/dev/netmap/netmap.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 78c06e49e..cf51bc6bf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2742,7 +2742,7 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 int
 nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
-	size_t bufsz, rqsz, bodysz;
+	size_t rqsz, optsz, bufsz;
 	int error;
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src;
@@ -2771,23 +2771,21 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		goto out_err;
 	}
 
-	bodysz = 2 * sizeof(void *) + rqsz;
+	bufsz = 2 * sizeof(void *) + rqsz;
+	optsz = 0;
 	for (src = hdr->nr_options; src; src = buf.nro_next) {
-		size_t optsz;
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)
 			goto out_err;
-		optsz = sizeof(*src);
+		optsz += sizeof(*src);
 		optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
 		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
 			error = EMSGSIZE;
 			goto out_err;
 		}
-		rqsz += optsz;
 		bufsz += optsz + sizeof(void *);
 	}
 
-	bufsz = max(1024UL, roundup_pow_of_two(bodysz));
 	ker = nm_os_malloc(bufsz);
 	if (ker == NULL) {
 		error = ENOMEM;
@@ -2813,7 +2811,6 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	next = &hdr->nr_options;
 	src = *next;
 	while (src) {
-		size_t optsz;
 		struct nmreq_option *opt;
 
 		/* copy the option header */

From 683cd19b1719af930ccf26d5ad1e24911ec99649 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:00:56 +0100
Subject: [PATCH 0685/2207] nmreq_copyin: restore the user header in case of
 error

---
 sys/dev/netmap/netmap.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index cf51bc6bf..ad019f3a1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2752,11 +2752,11 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	if (hdr->nr_reserved)
 		return EINVAL;
 
-	hdr->nr_reserved = nr_body_is_user;
-
 	if (!nr_body_is_user)
 		return 0;
 
+	hdr->nr_reserved = nr_body_is_user;
+
 	/* compute the total size of the buffer */
 	rqsz = nmreq_size_by_type(hdr->nr_reqtype);
 	if (rqsz > NETMAP_REQ_MAXSIZE) {
@@ -2802,7 +2802,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	/* copy the body */
 	error = copyin(hdr->nr_body, p, rqsz);
 	if (error)
-		goto out_err;
+		goto out_restore;
 	/* overwrite the user pointer with the in-kernel one */
 	hdr->nr_body = p;
 	p += rqsz;
@@ -2818,7 +2818,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		opt = (struct nmreq_option *)(ptrs + 1);
 		error = copyin(src, opt, sizeof(*src));
 		if (error)
-			goto out_err;
+			goto out_restore;
 		/* make a copy of the user next pointer */
 		*ptrs = opt->nro_next;
 		/* overwrite the user pointer with the in-kernel one */
@@ -2837,7 +2837,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 			/* the option body follows the option header */
 			error = copyin(src + 1, p, optsz);
 			if (error)
-				goto out_err;
+				goto out_restore;
 			p += optsz;
 		}
 
@@ -2847,9 +2847,13 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	}
 	return 0;
 
+out_restore:
+	ptrs = (void **)ker;
+	hdr->nr_body = *ptrs++;
+	hdr->nr_options = *ptrs++;
+	hdr->nr_reserved = 0;
+	nm_os_free(ker);
 out_err:
-	if (ker)
-		nm_os_free(ker);
 	return error;
 }
 

From 59170b06a7f3177ae9100233b3012da6543628c5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:03:05 +0100
Subject: [PATCH 0686/2207] nmreq_copyout: always copy the option headers

---
 sys/dev/netmap/netmap.c | 46 ++++++++++++++++++++++++-----------------
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ad019f3a1..1fd710b54 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2858,15 +2858,16 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 }
 
 static int
-nmreq_copyout(struct nmreq_header *hdr, int error)
+nmreq_copyout(struct nmreq_header *hdr, int rerror)
 {
 	struct nmreq_option *src, *dst;
 	void *ker = hdr->nr_body, *bufstart;
 	void **ptrs;
 	size_t bodysz;
+	int error;
 
 	if (!hdr->nr_reserved)
-		return error;
+		return rerror;
 
 	/* restore the user pointers in the header */
 	ptrs = (void **)ker - 2;
@@ -2875,14 +2876,15 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 	src = hdr->nr_options;
 	hdr->nr_options = *ptrs;
 
-	if (error)
-		goto out;
-
-	/* copy the body */
-	bodysz = nmreq_size_by_type(hdr->nr_reqtype);
-	error = copyout(ker, hdr->nr_body, bodysz);
-	if (error)
-		goto out;
+	if (!rerror) {
+		/* copy the body */
+		bodysz = nmreq_size_by_type(hdr->nr_reqtype);
+		error = copyout(ker, hdr->nr_body, bodysz);
+		if (error) {
+			rerror = error;
+			goto out;
+		}
+	}
 
 	/* copy the options */
 	dst = hdr->nr_options;
@@ -2895,17 +2897,23 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 		ptrs = (void **)src - 1;
 		src->nro_next = *ptrs;
 
-		/* copy the option header */
+		/* always copy the option header */
 		error = copyout(src, dst, sizeof(src));
-		if (error)
+		if (error) {
+			rerror = error;
 			goto out;
+		}
 		       
-		/* copy the option body */
-		optsz = nmreq_opt_size_by_type(src->nro_reqtype);
-		if (optsz) {
-			error = copyout(dst + 1, src + 1, optsz);
-			if (error)
-				goto out;
+		/* copy the option body only if there was no error */
+		if (!rerror && !src->nro_status) {
+			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+			if (optsz) {
+				error = copyout(dst + 1, src + 1, optsz);
+				if (error) {
+					rerror = error;
+					goto out;
+				}
+			}
 		}
 		src = next;
 		dst = *ptrs;
@@ -2915,7 +2923,7 @@ nmreq_copyout(struct nmreq_header *hdr, int error)
 out:
 	hdr->nr_reserved = 0;
 	nm_os_free(bufstart);
-	return error;
+	return rerror;
 }
 
 struct nmreq_option *

From aef2997f955fa1e8478ab5c5776627e78bc89637 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 15:13:59 +0100
Subject: [PATCH 0687/2207] options: check for duplicates

---
 sys/dev/netmap/netmap.c      | 27 ++++++++++++++++++++++-----
 sys/dev/netmap/netmap_kern.h |  3 ++-
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1fd710b54..72968e609 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2316,10 +2316,14 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 #ifdef WITH_EXTMEM
-				opt = nmreq_findoption(hdr, NETMAP_REQ_OPT_EXTMEM);
+				opt = nmreq_findoption(hdr->nr_options, NETMAP_REQ_OPT_EXTMEM);
 				if (opt != NULL) {
 					struct nmreq_opt_extmem *e =
 						(struct nmreq_opt_extmem *)opt;
+
+					error = nmreq_checkduplicate(opt);
+					if (error)
+						break;
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
 					opt->nro_status = error;
@@ -2927,16 +2931,29 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 }
 
 struct nmreq_option *
-nmreq_findoption(struct nmreq_header *hdr, uint16_t reqtype)
+nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
 {
-	struct nmreq_option *opt;
-
-	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+	for ( ; opt; opt = opt->nro_next)
 		if (opt->nro_reqtype == reqtype)
 			return opt;
 	return NULL;
 }
 
+int
+nmreq_checkduplicate(struct nmreq_option *opt) {
+	struct nmreq_option *scan;
+	uint16_t type = opt->nro_reqtype;
+	int dup = 0;
+
+	for (scan = opt->nro_next; scan;
+		scan = nmreq_findoption(scan, type))
+	{
+		dup++;
+		scan->nro_status = EINVAL;
+	}
+	return (dup ? EINVAL : 0);
+}
+
 static int
 nmreq_checkoptions(struct nmreq_header *hdr)
 {
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 61e32a761..1af68fde6 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2184,6 +2184,7 @@ void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
 #endif /* WITH_PTNETMAP_GUEST */
 
-struct nmreq_option * nmreq_findoption(struct nmreq_header *, uint16_t);
+struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
+int nmreq_checkduplicate(struct nmreq_option *);
 
 #endif /* _NET_NETMAP_KERN_H_ */

From 48e45de1c54853b8abae606a0ea2bbe1f1432295 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 17:54:46 +0100
Subject: [PATCH 0688/2207] wip

---
 utils/ctrl-api-test.c | 68 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 55 insertions(+), 13 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8d9b9cb42..20b06dab1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -26,6 +26,7 @@ struct TestContext {
 
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
+	struct nmreq_option *nr_opt; /* list of options */
 };
 
 #if 0
@@ -99,6 +100,7 @@ port_register(int fd, struct TestContext *ctx)
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 	hdr.nr_body    = &req;
+	hdr.nr_options = ctx->nr_opt;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id     = ctx->nr_mem_id;
 	req.nr_mode       = ctx->nr_mode;
@@ -531,25 +533,65 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 	return vale_detach(fd, ctx);
 }
 
+static void
+push_option(struct nmreq_option *opt, struct TestContext *ctx)
+{
+	opt->nro_next = ctx->nr_opt;
+	ctx->nr_opt = opt;
+}
+
+static void
+clear_options(struct TestContext *ctx)
+{
+	ctx->nr_opt = NULL;
+}
+
+static int
+unsupported_option(int fd, struct TestContext *ctx)
+{
+	struct nmreq_option opt, save;
+
+	printf("Testing unsupported option on %s\n", ctx->ifname);
+
+	opt.nro_reqtype = 1234;
+	push_option(&opt, ctx);
+	save = opt;
+
+	if (!port_register_hwall(fd, ctx))
+		return 1;
+
+	clear_options(ctx);
+
+	return opt.nro_reqtype == save.nro_reqtype   &&
+	       opt.nro_next == save.nro_next &&
+	       opt.nro_status == EOPNOTSUPP;
+}
+
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
-static testfunc_t tests[] = {port_info_get,
-			     port_register_hwall_host,
-			     port_register_hwall,
-			     port_register_host,
-			     port_register_single_ring_couple,
-			     vale_attach_detach,
-			     vale_attach_detach_host_rings,
-			     vale_ephemeral_port_hdr_manipulation,
-			     vale_persistent_port,
-			     register_and_pools_info_get,
-			     pipe_master,
-			     pipe_slave,
-			     vale_polling_enable_disable};
+static testfunc_t tests[] = {
+	port_info_get,
+	port_register_hwall_host,
+	port_register_hwall,
+	port_register_host,
+	port_register_single_ring_couple,
+	vale_attach_detach,
+	vale_attach_detach_host_rings,
+	vale_ephemeral_port_hdr_manipulation,
+	vale_persistent_port,
+	register_and_pools_info_get,
+	pipe_master,
+	pipe_slave,
+	vale_polling_enable_disable,
+	unsupported_option
+//	infinite_options,
+//	extmem_option,
+//	duplicate_extmem_options
+};
 
 int
 main(int argc, char **argv)

From 880ed111c0245189fdc49211224bef1633466a58 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Feb 2018 18:26:43 +0100
Subject: [PATCH 0689/2207] nmreq_copyout: fix size of copyout

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 72968e609..36717328f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2902,7 +2902,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 		src->nro_next = *ptrs;
 
 		/* always copy the option header */
-		error = copyout(src, dst, sizeof(src));
+		error = copyout(src, dst, sizeof(*src));
 		if (error) {
 			rerror = error;
 			goto out;

From a124db58e3a215264091098b449dea4009ea654a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:34:31 +0100
Subject: [PATCH 0690/2207] nmreq_copyout: fix direction of copy

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 36717328f..4be523603 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2912,7 +2912,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 		if (!rerror && !src->nro_status) {
 			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
 			if (optsz) {
-				error = copyout(dst + 1, src + 1, optsz);
+				error = copyout(src + 1, dst + 1, optsz);
 				if (error) {
 					rerror = error;
 					goto out;

From 0638d689e49e04d5193f32a18a3413ad7b5647ad Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:53:18 +0100
Subject: [PATCH 0691/2207] extmem: fix scan of duplicate options

---
 LINUX/netmap_linux.c    | 1 -
 sys/dev/netmap/netmap.c | 6 ++++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1c52e0e96..d5203fa85 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -201,7 +201,6 @@ nm_os_extmem_nextpage(struct nm_os_extmem *e)
 {
 	if (e->mapped >= e->nr_pages)
 		return NULL;
-	D("mapping %d/%d", e->mapped, e->nr_pages);
 	return kmap(e->pages[e->mapped++]);
 }
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4be523603..8f83fd051 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2322,8 +2322,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						(struct nmreq_opt_extmem *)opt;
 
 					error = nmreq_checkduplicate(opt);
-					if (error)
+					if (error) {
+						opt->nro_status = error;
 						break;
+					}
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
 					opt->nro_status = error;
@@ -2946,7 +2948,7 @@ nmreq_checkduplicate(struct nmreq_option *opt) {
 	int dup = 0;
 
 	for (scan = opt->nro_next; scan;
-		scan = nmreq_findoption(scan, type))
+		scan = nmreq_findoption(scan->nro_next, type))
 	{
 		dup++;
 		scan->nro_status = EINVAL;

From f9a9baf7dae49efc88d50e7879a7e397cc6461ed Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:54:15 +0100
Subject: [PATCH 0692/2207] mem: prevent mem2 to free extmem clusters

---
 sys/dev/netmap/netmap_mem2.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index dd7198483..7fd553567 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -108,6 +108,7 @@ struct netmap_obj_pool {
 	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
 	uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */
 	uint32_t bitmap_slots;	/* number of uint32 entries in bitmap */
+	int	alloc_done;	/* we have allocated the memory */
 	/* ---------------------------------------------------*/
 
 	/* limits */
@@ -1177,6 +1178,12 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 	if (p->invalid_bitmap)
 		nm_os_free(p->invalid_bitmap);
 	p->invalid_bitmap = NULL;
+	if (!p->alloc_done) {
+		/* allocation was done by somebody else.
+		 * Let them clean up after themselves.
+		 */
+		return;
+	}
 	if (p->lut) {
 		u_int i;
 
@@ -1196,6 +1203,7 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p)
 	p->memtotal = 0;
 	p->numclusters = 0;
 	p->objfree = 0;
+	p->alloc_done = 0;
 }
 
 /*
@@ -1307,13 +1315,20 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 	size_t n;
 
 	if (p->lut) {
-		/* already finalized, nothing to do */
+		/* if the lut is already there we assume that also all the
+		 * clusters have already been allocated, possibily by somebody
+		 * else (e.g., extmem). In the latter case, the alloc_done flag
+		 * will remain at zero, so that we will not attempt to
+		 * deallocate the clusters by ourselves in
+		 * netmap_reset_obj_allocator.
+		 */
 		return 0;
 	}
 
 	/* optimistically assume we have enough memory */
 	p->numclusters = p->_numclusters;
 	p->objtotal = p->_objtotal;
+	p->alloc_done = 1;
 
 	p->lut = nm_alloc_lut(p->objtotal);
 	if (p->lut == NULL) {

From 124dfc0f60ebd2ce1ffa8ba960f942dc51ebc8d5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:54:41 +0100
Subject: [PATCH 0693/2207] extmem: deleted leftovers from old API

---
 sys/dev/netmap/netmap_mem2.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 7fd553567..ed5b0c5db 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2210,8 +2210,6 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 	 */
 	nme->os = os;
 	os = NULL; /* pass ownership */
-	nme->up.flags |= NETMAP_MEM_EXT;
-
 
 	clust = nm_os_extmem_nextpage(nme->os);
 	off = 0;
@@ -2285,12 +2283,6 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		ND("%d memtotal %u", j, p->memtotal);
 	}
 
-	/* skip the first netmap_if, where the pools info reside */
-	{
-		struct netmap_obj_pool *p = &nme->up.pools[NETMAP_IF_POOL];
-		p->invalid_bitmap[0] |= 1U;
-	}
-
 	netmap_mem_ext_register(nme);
 
 	return &nme->up;

From e551179432520a68ab5ee87bc78f0380960d8e37 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Feb 2018 17:58:18 +0100
Subject: [PATCH 0694/2207] tests for options and extmem

---
 utils/ctrl-api-test.c | 240 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 230 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 20b06dab1..b65a35a6f 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -7,7 +7,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 
 struct TestContext {
 	const char *ifname;
@@ -546,6 +548,30 @@ clear_options(struct TestContext *ctx)
 	ctx->nr_opt = NULL;
 }
 
+static int
+checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
+{
+	if (opt->nro_next != exp->nro_next) {
+		printf("nro_next %p expected %p\n",
+				opt->nro_next,
+				exp->nro_next);
+		return -1;
+	}
+	if (opt->nro_reqtype != exp->nro_reqtype) {
+		printf("nro_reqtype %u expected %u\n",
+				opt->nro_reqtype,
+				exp->nro_reqtype);
+		return -1;
+	}
+	if (opt->nro_status != exp->nro_status) {
+		printf("nro_status %u expected %u\n",
+				opt->nro_status,
+				exp->nro_status);
+		return -1;
+	}
+	return 0;
+}
+
 static int
 unsupported_option(int fd, struct TestContext *ctx)
 {
@@ -553,19 +579,210 @@ unsupported_option(int fd, struct TestContext *ctx)
 
 	printf("Testing unsupported option on %s\n", ctx->ifname);
 
+	memset(&opt, 0, sizeof(opt));
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
 	save = opt;
 
-	if (!port_register_hwall(fd, ctx))
-		return 1;
+	if (port_register_hwall(fd, ctx) >= 0)
+		return -1;
 
 	clear_options(ctx);
+	save.nro_status = EOPNOTSUPP;
+	return checkoption(&opt, &save);
+}
+
+static int
+infinite_options(int fd, struct TestContext *ctx)
+{
+	struct nmreq_option opt, save;
+
+	printf("Testing infinite list of options on %s\n", ctx->ifname);
+
+	opt.nro_reqtype = 1234;
+	push_option(&opt, ctx);
+	opt.nro_next = &opt;
+	save = opt;
+	if (port_register_hwall(fd, ctx) >= 0)
+		return -1;
+
+	clear_options(ctx);
+	save.nro_status = EOPNOTSUPP;
+	return checkoption(&opt, &save);
+}
+
+#ifdef WITH_EXTMEM
+static int
+change_param(const char *pname, unsigned long newv, unsigned long *poldv)
+{
+#ifdef linux
+	char param[256] = "/sys/module/netmap/parameters/";
+	unsigned long oldv;
+	FILE *f;
 
-	return opt.nro_reqtype == save.nro_reqtype   &&
-	       opt.nro_next == save.nro_next &&
-	       opt.nro_status == EOPNOTSUPP;
+	strncat(param, pname, 256);
+
+	f = fopen(param, "r+");
+	if (f == NULL) {
+		perror(param);
+		return -1;
+	}
+	if (fscanf(f, "%ld", &oldv) != 1) {
+		perror(param);
+		fclose(f);
+		return -1;
+	}
+	if (poldv)
+		*poldv = oldv;
+	rewind(f);
+	if (fprintf(f, "%ld\n", newv) < 0) {
+		perror(param);
+		fclose(f);
+		return -1;
+	}
+	fclose(f);
+	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
+#endif /* linux */
+	return 0;
+}
+
+
+static int
+push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
+{
+	void *addr;
+
+	addr = mmap(NULL, (1U << 22), PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	if (addr == MAP_FAILED) {
+		perror("mmap");
+		return -1;
+	}
+
+	memset(e, 0, sizeof(*e));
+	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
+	e->nro_usrptr = (uint64_t)addr;
+	e->nro_info.nr_memsize = (1U << 22);
+
+	push_option(&e->nro_opt, ctx);
+
+	return 0;
+}
+
+static int
+pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
+{
+	struct nmreq_opt_extmem *e;
+	int ret;
+
+	e = (struct nmreq_opt_extmem *)ctx->nr_opt;
+	ctx->nr_opt = ctx->nr_opt->nro_next;
+
+	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
+		return ret;
+	}
+
+	if (e->nro_usrptr != exp->nro_usrptr) {
+		printf("usrptr %"PRIu64" expected %"PRIu64"\n",
+				e->nro_usrptr,
+				exp->nro_usrptr);
+		return -1;
+	}
+	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
+		printf("memsize %"PRIu64" expected %"PRIu64"\n",
+				e->nro_info.nr_memsize,
+				exp->nro_info.nr_memsize);
+		return -1;
+	}
+
+	if ((ret = munmap((void *)e->nro_usrptr, e->nro_info.nr_memsize)))
+		return ret;
+
+	return 0;
+}
+
+static int
+_extmem_option(int fd, struct TestContext *ctx, int new_rsz)
+{
+	struct nmreq_opt_extmem e, save;
+	int ret;
+	unsigned long old_rsz;
+
+	if ((ret = push_extmem_option(ctx, &e)) < 0)
+		return ret;
+
+	save = e;
+
+	ctx->ifname = "vale0:0";
+	ctx->nr_tx_slots = 16;
+	ctx->nr_rx_slots = 16;
+
+	if ((ret = change_param("priv_ring_size", new_rsz, &old_rsz)))
+		return ret;
+
+	if ((ret = port_register_hwall(fd, ctx)))
+		return ret;
+
+	ret = pop_extmem_option(ctx, &save);
+
+	if (change_param("priv_ring_size", old_rsz, NULL) < 0)
+		return -1;
+
+	return ret;
+}
+
+static int
+extmem_option(int fd, struct TestContext *ctx)
+{
+	printf("Testing extmem option on vale0:0\n");
+
+	return _extmem_option(fd, ctx, 512);
+}
+
+static int
+bad_extmem_option(int fd, struct TestContext *ctx)
+{
+	printf("Testing bad extmem option on vale0:0\n");
+
+	return _extmem_option(fd, ctx, (1<<16)) < 0 ? 0 : -1;
+}
+
+static int
+duplicate_extmem_options(int fd, struct TestContext *ctx)
+{
+	struct nmreq_opt_extmem e1, save1, e2, save2;
+	int ret;
+
+	printf("Testing duplicate extmem option on vale0:0\n");
+
+	if ((ret = push_extmem_option(ctx, &e1)) < 0)
+		return ret;
+
+	if ((ret = push_extmem_option(ctx, &e2)) < 0) {
+		clear_options(ctx);
+		return ret;
+	}
+
+	save1 = e1;
+	save2 = e2;
+
+	ret = port_register_hwall(fd, ctx);
+	if (ret >= 0) {
+		printf("duplicate option not detected\n");
+		return -1;
+	}
+
+	save2.nro_opt.nro_status = EINVAL;
+	if ((ret = pop_extmem_option(ctx, &save2)))
+		return ret;
+
+	save1.nro_opt.nro_status = EINVAL;
+	if ((ret = pop_extmem_option(ctx, &save1)))
+		return ret;
+
+	return 0;
 }
+#endif /* WITH_EXTMEM */
 
 static void
 usage(const char *prog)
@@ -587,10 +804,13 @@ static testfunc_t tests[] = {
 	pipe_master,
 	pipe_slave,
 	vale_polling_enable_disable,
-	unsupported_option
-//	infinite_options,
-//	extmem_option,
-//	duplicate_extmem_options
+	unsupported_option,
+	infinite_options,
+#ifdef WITH_EXTMEM
+	extmem_option,
+	bad_extmem_option,
+	duplicate_extmem_options,
+#endif /* WITH_EXTMEM */
 };
 
 int
@@ -633,7 +853,7 @@ main(int argc, char **argv)
 			return -1;
 		}
 	}
-	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+	for (i = 0; i < sizeof(tests) / sizeof(tests[0]) - 1; i++) {
 		struct TestContext ctxcopy;
 		int fd;
 		int ret;

From e015b5612ea66b862b9627e7427e97229d21534b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 6 Feb 2018 09:26:57 +0100
Subject: [PATCH 0695/2207] nmreq options: fix compilation errors
 (!WITH_EXTMEM)

---
 sys/dev/netmap/netmap.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8f83fd051..55f9a7db3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2308,7 +2308,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_LOCK();
 			do {
 				u_int memflags;
+#ifdef WITH_EXTMEM
 				struct nmreq_option *opt;
+#endif /* WITH_EXTMEM */
 
 				if (priv->np_nifp != NULL) {	/* thread already registered */
 					error = EBUSY;
@@ -2739,8 +2741,8 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 	case NETMAP_REQ_OPT_EXTMEM:
 		rv = sizeof(struct nmreq_opt_extmem);
 		break;
-	}
 #endif /* WITH_EXTMEM */
+	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
 }

From 4a60f5a71528971a4d65fd193c2f2eec22711b6c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 6 Feb 2018 09:39:28 +0100
Subject: [PATCH 0696/2207] legacy: add missing write back of nmr->nr_name for
 NETMAP_BDG_LIST

---
 sys/dev/netmap/netmap_legacy.c | 1 +
 sys/dev/netmap/netmap_vale.c   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index a8f510f0e..61e924708 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -316,6 +316,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_VALE_LIST: {
 		struct nmreq_vale_list *req =
 			(struct nmreq_vale_list *)hdr->nr_body;
+		strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 51339d411..0419fecb4 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1319,6 +1319,7 @@ netmap_bdg_list(struct nmreq_header *hdr)
 				if (b->bdg_ports[j] == NULL)
 					continue;
 				vpna = b->bdg_ports[j];
+				/* write back the VALE switch name */
 				strncpy(hdr->nr_name, vpna->up.name,
 					(size_t)IFNAMSIZ);
 				error = 0;

From 0f2c839f0d6f255a496f0854e8bfa40fa48cc236 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 10 Feb 2018 12:27:43 +0100
Subject: [PATCH 0697/2207] linux: ixgbe: use IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT
 macro instead of "2"

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index f42f2da21..fc0788241 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -127,7 +127,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
 		reg_idx &= mask;
 	}
-	srrctl = IXGBE_RX_HDR_SIZE << 2;
+	srrctl = IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT;
 	srrctl |= NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
 	D("bufsz: %d srrctl: %d", NETMAP_BUF_SIZE(na),
 		NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);

From 235ed3d30e68e7af9180a4152497b9d50bf9d1c5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Feb 2018 14:11:46 +0100
Subject: [PATCH 0698/2207] pipe: multiple rings

---
 sys/dev/netmap/netmap_pipe.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index f18fa4b80..1b7c84478 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2016 Giuseppe Lettieri
+ * Copyright (C) 2014-2018 Giuseppe Lettieri
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,7 @@
 #ifdef WITH_PIPES
 
 #define NM_PIPE_MAXSLOTS	4096
+#define NM_PIPE_MAXRINGS	256
 
 static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
 SYSBEGIN(vars_pipes);
@@ -564,11 +565,6 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		 * is missing. */
 		return EINVAL;
 	}
-	if (req->nr_mode != NR_REG_ALL_NIC || req->nr_ringid != 0) {
-		/* Currently we only support opening all the hw rings of
-		 * a pipe. */
-		return EINVAL;
-	}
 
 	/* first, try to find the parent adapter */
 	for (;;) {
@@ -655,8 +651,12 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	mna->up.na_flags |= NAF_MEM_OWNER;
 	mna->up.na_lut = pna->na_lut;
 
-	mna->up.num_tx_rings = 1;
-	mna->up.num_rx_rings = 1;
+	mna->up.num_tx_rings = req->nr_tx_rings;
+	nm_bound_var(&mna->up.num_tx_rings, 1,
+			1, NM_PIPE_MAXRINGS, NULL);
+	mna->up.num_rx_rings = req->nr_rx_rings;
+	nm_bound_var(&mna->up.num_rx_rings, 1,
+			1, NM_PIPE_MAXRINGS, NULL);
 	mna->up.num_tx_desc = req->nr_tx_slots;
 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
 			1, NM_PIPE_MAXSLOTS, NULL);
@@ -680,6 +680,9 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* most fields are the same, copy from master and then fix */
 	*sna = *mna;
 	sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
+	/* swap the number of tx/rx rings */
+	sna->up.num_tx_rings = mna->up.num_rx_rings;
+	sna->up.num_rx_rings = mna->up.num_tx_rings;
 	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
 	sna->role = NM_PIPE_ROLE_SLAVE;
 	error = netmap_attach_common(&sna->up);

From 0647c4dd0b533b439403febe8289cb0436f9e3fa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 13 Feb 2018 18:24:52 +0100
Subject: [PATCH 0699/2207] extmem: remove obsolete userspace support

---
 apps/pkt-gen/pkt-gen.c |   2 +-
 sys/net/netmap_user.h  | 301 ++++++++---------------------------------
 2 files changed, 55 insertions(+), 248 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d07f6daa2..f48a17c96 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2953,7 +2953,7 @@ main(int arc, char **argv)
 	 * reconfigure. We do the open here to have time to reset.
 	 */
 	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
-		NM_OPEN_ARG3 | NM_OPEN_EXTMEM | NM_OPEN_RING_CFG;
+		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
 	if (g.nthreads > 1) {
 		base_nmd.req.nr_flags &= ~NR_REG_MASK;
 		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index bb250d06b..0147c947a 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -98,7 +98,6 @@
 #endif /* likely and unlikely */
 
 #include 
-#include  /* nmreq_pointer_get() */
 
 /* helper macro */
 #define _NETMAP_OFFSET(type, ptr, offset) \
@@ -113,7 +112,7 @@
 	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
 
 #define NETMAP_BUF(ring, index)				\
-	((char *)(ring) + (ring)->buf_ofs + ((long)(index)*(ring)->nr_buf_size))
+	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
 
 #define NETMAP_BUF_IDX(ring, buf)			\
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
@@ -223,7 +222,7 @@ struct nm_desc {
 	struct nm_desc *self; /* point to self if netmap. */
 	int fd;
 	void *mem;
-	uint64_t memsize;
+	uint32_t memsize;
 	int done_mmap;	/* set if mem is the result of mmap */
 	struct netmap_if * const nifp;
 	uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;
@@ -278,7 +277,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024 || (l % 64))) {
+	if (unlikely(l >= 1024)) {
 		memcpy(dst, src, l);
 		return;
 	}
@@ -349,7 +348,6 @@ enum {
 	NM_OPEN_ARG2 =		0x200000,
 	NM_OPEN_ARG3 =		0x400000,
 	NM_OPEN_RING_CFG =	0x800000, /* tx|rx rings|slots */
-	NM_OPEN_EXTMEM =       0x1000000,
 };
 
 
@@ -611,28 +609,9 @@ nm_is_identifier(const char *s, const char *e)
 	return 1;
 }
 
-static void
-nm_init_offsets(struct nm_desc *d)
-{
-	struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
-	struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
-	if ((void *)r == (void *)nifp) {
-		/* the descriptor is open for TX only */
-		r = NETMAP_TXRING(nifp, d->first_tx_ring);
-	}
-
-	*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
-	*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
-	*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
-	*(void **)(uintptr_t)&d->buf_end =
-		(char *)d->mem + d->memsize;
-}
-
 #define MAXERRMSG 80
-#define NM_PARSE_OK	  	0
-#define NM_PARSE_MEMID 		1
 static int
-nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
+nm_parse(const char *ifname, struct nm_desc *d, char *err)
 {
 	int is_vale;
 	const char *port = NULL;
@@ -646,13 +625,6 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 
 	errno = 0;
 
-	if (strncmp(ifname, "netmap:", 7) &&
-			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
-		snprintf(errmsg, MAXERRMSG, "invalid port name: %s", ifname);
-		errno = EINVAL;
-		goto fail;
-	}
-
 	is_vale = (ifname[0] == 'v');
 	if (is_vale) {
 		port = index(ifname, ':');
@@ -683,13 +655,12 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 	}
 
 	namelen = port - ifname;
-	if (namelen >= sizeof(d->nr_name)) {
+	if (namelen >= sizeof(d->req.nr_name)) {
 		snprintf(errmsg, MAXERRMSG, "name too long");
 		goto fail;
 	}
-	memcpy(d->nr_name, ifname, namelen);
-	d->nr_name[namelen] = '\0';
-	D("name %s", d->nr_name);
+	memcpy(d->req.nr_name, ifname, namelen);
+	d->req.nr_name[namelen] = '\0';
 
 	p_state = P_START;
 	nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
@@ -787,28 +758,21 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 			p_state = P_FLAGSOK;
 			break;
 		case P_MEMID:
-			if (!memid_allowed) {
+			if (nr_arg2 != 0) {
 				snprintf(errmsg, MAXERRMSG, "double setting of memid");
 				goto fail;
 			}
 			num = strtol(port, (char **)&port, 10);
 			if (num <= 0) {
-				ND("non-numeric memid %s (out = %p)", port, out);
-				if (out == NULL)
-					goto fail;
-				*out = (char *)port;
-				while (*port)
-					port++;
-			} else {
-				nr_arg2 = num;
-				memid_allowed = 0;
-				p_state = P_RNGSFXOK;
+				snprintf(errmsg, MAXERRMSG, "invalid memid %ld, must be >0", num);
+				goto fail;
 			}
+			nr_arg2 = num;
+			p_state = P_RNGSFXOK;
 			break;
 		}
 	}
-	if (p_state != P_START && p_state != P_RNGSFXOK &&
-	    p_state != P_FLAGSOK && p_state != P_MEMID) {
+	if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) {
 		snprintf(errmsg, MAXERRMSG, "unexpected end of port name");
 		goto fail;
 	}
@@ -818,124 +782,28 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
 			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
 			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
 
-	d->nr_flags |= nr_flags;
-	d->nr_ringid |= nr_ringid;
-	d->nr_arg2 = nr_arg2;
+	d->req.nr_flags |= nr_flags;
+	d->req.nr_ringid |= nr_ringid;
+	d->req.nr_arg2 = nr_arg2;
+
+	d->self = d;
 
-	return (p_state == P_MEMID) ? NM_PARSE_MEMID : NM_PARSE_OK;
+	return 0;
 fail:
 	if (!errno)
 		errno = EINVAL;
-	if (out)
-		*out = strdup(errmsg);
+	if (err)
+		strncpy(err, errmsg, MAXERRMSG);
 	return -1;
 }
 
-static int
-nm_interp_memid(const char *memid, struct nmreq *req, char **err)
-{
-#if 0
-	int fd = -1;
-	char errmsg[MAXERRMSG] = "";
-	struct nmreq greq;
-	off_t mapsize;
-	struct netmap_pools_info *pi;
-
-	/* first, try to look for a netmap port with this name */
-	fd = open("/dev/netmap", O_RDONLY);
-	if (fd < 0) {
-		snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno));
-		goto fail;
-	}
-	memset(&greq, 0, sizeof(greq));
-	if (nm_parse_one(memid, &greq, err, 0) == NM_PARSE_OK) {
-		greq.nr_version = NETMAP_API;
-		if (ioctl(fd, NIOCGINFO, &greq) < 0) {
-			if (errno == ENOENT || errno == ENXIO)
-				goto try_external;
-			snprintf(errmsg, MAXERRMSG, "cannot getinfo for %s: %s", memid, strerror(errno));
-			goto fail;
-		}
-		req->nr_arg2 = greq.nr_arg2;
-		close(fd);
-		return 0;
-	}
-try_external:
-	D("trying with external memory");
-	close(fd);
-	fd = open(memid, O_RDWR);
-	if (fd < 0) {
-		snprintf(errmsg, MAXERRMSG, "cannot open %s: %s", memid, strerror(errno));
-		goto fail;
-	}
-	mapsize = lseek(fd, 0, SEEK_END);
-	if (mapsize < 0) {
-		snprintf(errmsg, MAXERRMSG, "failed to obtain filesize of %s: %s", memid, strerror(errno));
-		goto fail;
-	}
-	pi = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-	if (pi == MAP_FAILED) {
-		snprintf(errmsg, MAXERRMSG, "cannot map %s: %s", memid, strerror(errno));
-		goto fail;
-	}
-	req->nr_cmd = NETMAP_POOLS_CREATE;
-	pi->memsize = mapsize;
-	nmreq_pointer_put(req, pi);
-	D("mapped %zu bytes at %p from file %s", mapsize, pi, memid);
-	return 0;
-
-fail:
-	D("%s", errmsg);
-	close(fd);
-	if (err && !*err)
-		*err = strdup(errmsg);
-	return errno;
-#else
-	(void)memid;
-	(void)req;
-	(void)err;
-	return EOPNOTSUPP;
-#endif
-}
-
-static int
-nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
-{
-	char *err;
-	switch (nm_parse_one(ifname, &d->req, &err, 1)) {
-	case NM_PARSE_OK:
-		D("parse OK");
-		break;
-	case NM_PARSE_MEMID:
-		D("memid: %s", err);
-		errno = nm_interp_memid(err, &d->req, &err);
-		D("errno = %d", errno);
-		if (!errno)
-			break;
-		/* fallthrough */
-	default:
-		D("error");
-		strncpy(errmsg, err, MAXERRMSG);
-		errmsg[MAXERRMSG-1] = '\0';
-		free(err);
-		return -1;
-	}
-	D("parsed name: %s", d->req.nr_name);
-	d->self = d;
-	return 0;
-}
-
 /*
  * Try to open, return descriptor if successful, NULL otherwise.
  * An invalid netmap name will return errno = 0;
  * You can pass a pointer to a pre-filled nm_desc to add special
  * parameters. Flags is used as follows
- * NM_OPEN_NO_MMAP	use the memory from arg, only
+ * NM_OPEN_NO_MMAP	use the memory from arg, only XXX avoid mmap
  *			if the nr_arg2 (memory block) matches.
- *			Special case: if arg is NULL, skip the
- *			mmap entirely (maybe because you are going
- *			to do it by yourself, or you plan to call
- *			nm_mmap() only later)
  * NM_OPEN_ARG1		use req.nr_arg1 from arg
  * NM_OPEN_ARG2		use req.nr_arg2 from arg
  * NM_OPEN_RING_CFG	user ring config from arg
@@ -948,7 +816,6 @@ nm_open(const char *ifname, const struct nmreq *req,
 	const struct nm_desc *parent = arg;
 	char errmsg[MAXERRMSG] = "";
 	uint32_t nr_reg;
-	struct nmreq_pools_info *pi = NULL;
 
 	if (strncmp(ifname, "netmap:", 7) &&
 			strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@@ -969,91 +836,31 @@ nm_open(const char *ifname, const struct nmreq *req,
 		goto fail;
 	}
 
-	if (req) {
+	if (req)
 		d->req = *req;
-	} else {
-		d->req.nr_arg1 = 4;
-		d->req.nr_arg2 = 0;
-		d->req.nr_arg3 = 0;
-	}
 
 	if (!(new_flags & NM_OPEN_IFNAME)) {
-		char *err = NULL;
-		switch (nm_parse_one(ifname, &d->req, &err, 1)) {
-		case NM_PARSE_OK:
-			break;
-		case NM_PARSE_MEMID:
-			if ((new_flags & NM_OPEN_NO_MMAP) &&
-					IS_NETMAP_DESC(parent)) {
-				/* ignore the memid setting, since we are
-				 * going to use the parent's one
-				 */
-				break;
-			}
-			errno = nm_interp_memid(err, &d->req, &err);
-			if (!errno)
-				break;
-			/* fallthrough */
-		default:
-			strncpy(errmsg, err, MAXERRMSG);
-			errmsg[MAXERRMSG-1] = '\0';
-			free(err);
+		if (nm_parse(ifname, d, errmsg) < 0)
 			goto fail;
-		}
-		d->self = d;
 	}
 
-#if 0
-	/* compatibility checks for POOL_SCREATE and NM_OPEN flags
-	 * the first check may be dropped once we have a larger nreq
-	 */
-	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-		if (IS_NETMAP_DESC(parent)) {
-		       	if (new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3)) {
-				snprintf(errmsg, MAXERRMSG,
-						"POOLS_CREATE is incompatibile "
-						"with NM_OPEN_ARG? flags");
-				errno = EINVAL;
-				goto fail;
-			}
-			if (new_flags & NM_OPEN_NO_MMAP) {
-				snprintf(errmsg, MAXERRMSG,
-						"POOLS_CREATE is incompatible "
-						"with NM_OPEN_NO_MMAP flag");
-				errno = EINVAL;
-				goto fail;
-			}
-		}
-	}
-#endif
-
 	d->req.nr_version = NETMAP_API;
 	d->req.nr_ringid &= NETMAP_RING_MASK;
 
 	/* optionally import info from parent */
 	if (IS_NETMAP_DESC(parent) && new_flags) {
-#if 0
-		if (new_flags & NM_OPEN_EXTMEM) {
-			if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
-				d->req.nr_cmd = NETMAP_POOLS_CREATE;
-				nmreq_pointer_put(&d->req, nmreq_pointer_get(&parent->req));
-				D("Warning: not overriding arg[1-3] since external memory is being used");
-				new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
-			}
-		}
-#endif
-		if (new_flags & NM_OPEN_ARG1) {
+		if (new_flags & NM_OPEN_ARG1)
 			D("overriding ARG1 %d", parent->req.nr_arg1);
-			d->req.nr_arg1 = parent->req.nr_arg1;
-		}
-		if (new_flags & (NM_OPEN_ARG2 | NM_OPEN_NO_MMAP)) {
+		d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
+			parent->req.nr_arg1 : 4;
+		if (new_flags & NM_OPEN_ARG2) {
 			D("overriding ARG2 %d", parent->req.nr_arg2);
-			d->req.nr_arg2 = parent->req.nr_arg2;
+			d->req.nr_arg2 =  parent->req.nr_arg2;
 		}
-		if (new_flags & NM_OPEN_ARG3) {
+		if (new_flags & NM_OPEN_ARG3)
 			D("overriding ARG3 %d", parent->req.nr_arg3);
-			d->req.nr_arg3 = parent->req.nr_arg3;
-		}
+		d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
+			parent->req.nr_arg3 : 0;
 		if (new_flags & NM_OPEN_RING_CFG) {
 			D("overriding RING_CFG");
 			d->req.nr_tx_slots = parent->req.nr_tx_slots;
@@ -1074,30 +881,11 @@ nm_open(const char *ifname, const struct nmreq *req,
 	/* add the *XPOLL flags */
 	d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
 
-#if 0
-	if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
-		pi = nmreq_pointer_get(&d->req);
-	}
-#endif
-
 	if (ioctl(d->fd, NIOCREGIF, &d->req)) {
 		snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
 		goto fail;
 	}
 
-	if (pi != NULL) {
-		d->mem = pi;
-		d->memsize = pi->nr_memsize;
-		nm_init_offsets(d);
-	} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
-		/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
-	        errno = nm_mmap(d, parent);
-		if (errno) {
-			snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
-			goto fail;
-		}
-	}
-
 	nr_reg = d->req.nr_flags & NR_REG_MASK;
 
 	if (nr_reg == NR_REG_SW) { /* host stack */
@@ -1122,6 +910,13 @@ nm_open(const char *ifname, const struct nmreq *req,
 		d->first_rx_ring = d->last_rx_ring = 0;
 	}
 
+        /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
+	if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
+	        snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
+		goto fail;
+	}
+
+
 #ifdef DEBUG_NETMAP_USER
     { /* debugging code */
 	int i;
@@ -1162,8 +957,7 @@ nm_close(struct nm_desc *d)
 	 */
 	static void *__xxzt[] __attribute__ ((unused))  =
 		{ (void *)nm_open, (void *)nm_inject,
-		  (void *)nm_dispatch, (void *)nm_nextpkt,
-	          (void *)nm_parse } ;
+		  (void *)nm_dispatch, (void *)nm_nextpkt } ;
 
 	if (d == NULL || d->self != d)
 		return EINVAL;
@@ -1200,8 +994,21 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 		}
 		d->done_mmap = 1;
 	}
+	{
+		struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
+		struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
+		if ((void *)r == (void *)nifp) {
+			/* the descriptor is open for TX only */
+			r = NETMAP_TXRING(nifp, d->first_tx_ring);
+		}
+
+		*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
+		*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
+		*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
+		*(void **)(uintptr_t)&d->buf_end =
+			(char *)d->mem + d->memsize;
+	}
 
-	nm_init_offsets(d);
 	return 0;
 
 fail:

From 06b36c880767fc0a60521f2837d7f3f2b807b4e8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 14 Feb 2018 15:47:47 +0100
Subject: [PATCH 0700/2207] pkt-gen: better output on poll errors

---
 apps/pkt-gen/pkt-gen.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f48a17c96..03f36ed21 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1564,6 +1564,7 @@ sender_body(void *data)
 
 	nifp = targ->nmd->nifp;
 	while (!targ->cancel && (n == 0 || sent < n)) {
+		int rv;
 
 		if (rate_limit && tosend <= 0) {
 			tosend = targ->g->burst;
@@ -1575,17 +1576,18 @@ sender_body(void *data)
 		 * wait for available room in the send queue(s)
 		 */
 #ifdef BUSYWAIT
+		(void)rv;
 		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
 			D("ioctl error on queue %d: %s", targ->me,
 					strerror(errno));
 			goto quit;
 		}
 #else /* !BUSYWAIT */
-		if (poll(&pfd, 1, 2000) <= 0) {
+		if ( (rv = poll(&pfd, 1, 2000)) <= 0) {
 			if (targ->cancel)
 				break;
-			D("poll error/timeout on queue %d: %s", targ->me,
-				strerror(errno));
+			D("poll error on queue %d: %s", targ->me,
+				rv ? strerror(errno) : "timeout");
 			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {
@@ -1884,6 +1886,7 @@ txseq_body(void *data)
 		unsigned int head;
 		int fcnt;
 		uint16_t sum = 0;
+		int rv;
 
 		if (!rate_limit) {
 			budget = targ->g->burst;
@@ -1896,17 +1899,18 @@ txseq_body(void *data)
 
 		/* wait for available room in the send queue */
 #ifdef BUSYWAIT
+		(void)rv;
 		if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) {
 			D("ioctl error on queue %d: %s", targ->me,
 					strerror(errno));
 			goto quit;
 		}
 #else /* !BUSYWAIT */
-		if (poll(&pfd, 1, 2000) <= 0) {
+		if ( (rv = poll(&pfd, 1, 2000)) <= 0) {
 			if (targ->cancel)
 				break;
-			D("poll error/timeout on queue %d: %s", targ->me,
-				strerror(errno));
+			D("poll error on queue %d: %s", targ->me,
+				rv ? strerror(errno) : "timeout");
 			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {

From f8d2f2eb66218f1d51808e6230c160cd5b98b22d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 16 Feb 2018 14:21:36 +0100
Subject: [PATCH 0701/2207] newnmreq: only use arch-independent types in the
 ABI

---
 sys/dev/netmap/netmap.c        | 70 ++++++++++++++++++----------------
 sys/dev/netmap/netmap_legacy.c | 22 +++++------
 sys/net/netmap.h               |  6 +--
 3 files changed, 51 insertions(+), 47 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 55f9a7db3..4ba746638 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2439,10 +2439,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 					/* get a refcount */
 					hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-					hdr->nr_body = ®req;
+					hdr->nr_body = (uint64_t)®req;
 					error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
 					hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; /* reset type */
-					hdr->nr_body = req; /* reset nr_body */
+					hdr->nr_body = (uint64_t)req; /* reset nr_body */
 					if (error) {
 						na = NULL;
 						ifp = NULL;
@@ -2509,10 +2509,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			}
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
+			hdr->nr_body = (uint64_t)®req;
 			error = netmap_get_bdg_na(hdr, &na, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			if (na && !error) {
 				struct netmap_vp_adapter *vpna =
 					(struct netmap_vp_adapter *)na;
@@ -2541,10 +2541,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			bzero(®req, sizeof(regreq));
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
+			hdr->nr_body = (uint64_t)®req;
 			error = netmap_get_na(hdr, &na, &ifp, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			if (na && !error) {
 				req->nr_hdr_len = na->virt_hdr_len;
 			}
@@ -2566,10 +2566,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			regreq.nr_rx_rings = req->nr_rx_rings;
 			regreq.nr_mem_id = req->nr_mem_id;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = ®req;
+			hdr->nr_body = (uint64_t)®req;
 			error = netmap_vi_create(hdr, 0 /* no autodelete */);
 			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
                         /* Write back to the original struct. */
 			req->nr_tx_slots = regreq.nr_tx_slots;
 			req->nr_rx_slots = regreq.nr_rx_slots;
@@ -2755,7 +2755,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src;
 	struct nmreq_option buf;
-	void **ptrs;
+	uint64_t *ptrs;
 
 	if (hdr->nr_reserved)
 		return EINVAL;
@@ -2771,8 +2771,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		error = EMSGSIZE;
 		goto out_err;
 	}
-	if ((rqsz && hdr->nr_body == NULL) ||
-		(!rqsz && hdr->nr_body != NULL)) {
+	if ((rqsz && hdr->nr_body == (uint64_t)NULL) ||
+		(!rqsz && hdr->nr_body != (uint64_t)NULL)) {
 		/* Request body expected, but not found; or
 		 * request body found but unexpected. */
 		error = EINVAL;
@@ -2781,7 +2781,9 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 
 	bufsz = 2 * sizeof(void *) + rqsz;
 	optsz = 0;
-	for (src = hdr->nr_options; src; src = buf.nro_next) {
+	for (src = (struct nmreq_option *)hdr->nr_options; src;
+	     src = (struct nmreq_option *)buf.nro_next)
+	{
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)
 			goto out_err;
@@ -2802,27 +2804,27 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	p = ker;
 
 	/* make a copy of the user pointers */
-	ptrs = (void **)p;
+	ptrs = (uint64_t*)p;
 	*ptrs++ = hdr->nr_body;
 	*ptrs++ = hdr->nr_options;
 	p = (char *)ptrs;
 
 	/* copy the body */
-	error = copyin(hdr->nr_body, p, rqsz);
+	error = copyin((void *)hdr->nr_body, p, rqsz);
 	if (error)
 		goto out_restore;
 	/* overwrite the user pointer with the in-kernel one */
-	hdr->nr_body = p;
+	hdr->nr_body = (uint64_t)p;
 	p += rqsz;
 
 	/* copy the options */
-	next = &hdr->nr_options;
+	next = (struct nmreq_option **)&hdr->nr_options;
 	src = *next;
 	while (src) {
 		struct nmreq_option *opt;
 
 		/* copy the option header */
-		ptrs = (void **)p;
+		ptrs = (uint64_t *)p;
 		opt = (struct nmreq_option *)(ptrs + 1);
 		error = copyin(src, opt, sizeof(*src));
 		if (error)
@@ -2850,13 +2852,13 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		}
 
 		/* move to next option */
-		next = &opt->nro_next;
+		next = (struct nmreq_option **)&opt->nro_next;
 		src = *next;
 	}
 	return 0;
 
 out_restore:
-	ptrs = (void **)ker;
+	ptrs = (uint64_t *)ker;
 	hdr->nr_body = *ptrs++;
 	hdr->nr_options = *ptrs++;
 	hdr->nr_reserved = 0;
@@ -2869,8 +2871,8 @@ static int
 nmreq_copyout(struct nmreq_header *hdr, int rerror)
 {
 	struct nmreq_option *src, *dst;
-	void *ker = hdr->nr_body, *bufstart;
-	void **ptrs;
+	void *ker = (void *)hdr->nr_body, *bufstart;
+	uint64_t *ptrs;
 	size_t bodysz;
 	int error;
 
@@ -2878,16 +2880,16 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 		return rerror;
 
 	/* restore the user pointers in the header */
-	ptrs = (void **)ker - 2;
+	ptrs = (uint64_t *)ker - 2;
 	bufstart = ptrs;
 	hdr->nr_body = *ptrs++;
-	src = hdr->nr_options;
+	src = (struct nmreq_option *)hdr->nr_options;
 	hdr->nr_options = *ptrs;
 
 	if (!rerror) {
 		/* copy the body */
 		bodysz = nmreq_size_by_type(hdr->nr_reqtype);
-		error = copyout(ker, hdr->nr_body, bodysz);
+		error = copyout(ker, (void *)hdr->nr_body, bodysz);
 		if (error) {
 			rerror = error;
 			goto out;
@@ -2895,14 +2897,14 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 	}
 
 	/* copy the options */
-	dst = hdr->nr_options;
+	dst = (struct nmreq_option *)hdr->nr_options;
 	while (src) {
 		size_t optsz;
-		struct nmreq_option *next;
+		uint64_t next;
 
 		/* restore the user pointer */
 		next = src->nro_next;
-		ptrs = (void **)src - 1;
+		ptrs = (uint64_t *)src - 1;
 		src->nro_next = *ptrs;
 
 		/* always copy the option header */
@@ -2923,8 +2925,8 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 				}
 			}
 		}
-		src = next;
-		dst = *ptrs;
+		src = (struct nmreq_option *)next;
+		dst = (struct nmreq_option *)*ptrs;
 	}
 
 
@@ -2937,7 +2939,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 struct nmreq_option *
 nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
 {
-	for ( ; opt; opt = opt->nro_next)
+	for ( ; opt; opt = (struct nmreq_option *)opt->nro_next)
 		if (opt->nro_reqtype == reqtype)
 			return opt;
 	return NULL;
@@ -2949,8 +2951,9 @@ nmreq_checkduplicate(struct nmreq_option *opt) {
 	uint16_t type = opt->nro_reqtype;
 	int dup = 0;
 
-	for (scan = opt->nro_next; scan;
-		scan = nmreq_findoption(scan->nro_next, type))
+	for (scan = (struct nmreq_option *)opt->nro_next; scan;
+		scan = nmreq_findoption((struct nmreq_option *)scan->nro_next,
+			type))
 	{
 		dup++;
 		scan->nro_status = EINVAL;
@@ -2966,7 +2969,8 @@ nmreq_checkoptions(struct nmreq_header *hdr)
 	 * marked as not supported
 	 */
 
-	for (opt = hdr->nr_options; opt; opt = opt->nro_next)
+	for (opt = (struct nmreq_option *)hdr->nr_options; opt;
+	     opt = (struct nmreq_option *)opt->nro_next)
 		if (opt->nro_status == EOPNOTSUPP)
 			return EOPNOTSUPP;
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 61e924708..65deeaf72 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -128,8 +128,8 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	/* First prepare the request header. */
 	hdr->nr_version = NETMAP_API; /* new API */
 	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-	hdr->nr_options = NULL;
-	hdr->nr_body = NULL;
+	hdr->nr_options = (uint64_t)NULL;
+	hdr->nr_body = (uint64_t)NULL;
 
 	switch (ioctl_cmd) {
 	case NIOCREGIF: {
@@ -138,7 +138,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			if (nmreq_register_from_legacy(nmr, hdr, req)) {
 				goto oom;
@@ -148,7 +148,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_ATTACH: {
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 			if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
 				goto oom;
@@ -169,7 +169,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_VNET_HDR_GET: {
 			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
 			req->nr_hdr_len = nmr->nr_arg1;
@@ -178,7 +178,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_NEWIF : {
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
@@ -195,7 +195,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_POLLING_OFF: {
 			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
@@ -227,7 +227,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
@@ -235,7 +235,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCGINFO. */
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = req;
+			hdr->nr_body = (uint64_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
@@ -253,7 +253,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 oom:
 	if (hdr) {
 		if (hdr->nr_body) {
-			nm_os_free(hdr->nr_body);
+			nm_os_free((void *)hdr->nr_body);
 		}
 		nm_os_free(hdr);
 	}
@@ -370,7 +370,7 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			nmreq_to_legacy(hdr, nmr);
 		}
 		if (hdr->nr_body) {
-			nm_os_free(hdr->nr_body);
+			nm_os_free((void *)hdr->nr_body);
 		}
 		nm_os_free(hdr);
 		break;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a1bcc06a9..06a3b56d3 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -467,7 +467,7 @@ struct netmap_if {
 /* Header common to all request options. */
 struct nmreq_option {
 	/* Pointer ot the next option. */
-	struct nmreq_option	*nro_next;
+	uint64_t		nro_next;
 	/* Option type. */
 	uint32_t		nro_reqtype;
 	/* (out) status of the option:
@@ -485,8 +485,8 @@ struct nmreq_header {
 	uint32_t		nr_reserved;	/* must be zero */
 #define NETMAP_REQ_IFNAMSIZ	64
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
-	struct nmreq_option	*nr_options;	/* command-specific options */
-	void			*nr_body;	/* ptr to nmreq_xyz struct */
+	uint64_t		nr_options;	/* command-specific options */
+	uint64_t		nr_body;	/* ptr to nmreq_xyz struct */
 };
 
 enum {

From 9c5e2acc6a668694693070878bb1fd023fed069d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 16 Feb 2018 14:40:21 +0100
Subject: [PATCH 0702/2207] monitor: fix compilation

---
 sys/dev/netmap/netmap_monitor.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index ed25f2f11..ed8218bd2 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -856,9 +856,9 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	 */
 	memcpy(&preq, req, sizeof(preq));
 	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	hdr->nr_body = &preq;
+	hdr->nr_body = (uint64_t)&preq;
 	error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
-	hdr->nr_body = req;
+	hdr->nr_body = (uint64_t)req;
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;

From 92f86e97607c68f0ba9073fd88f96273e791630a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 16 Feb 2018 14:42:51 +0100
Subject: [PATCH 0703/2207] ptnetmap: fix warning

---
 sys/dev/netmap/netmap_pt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 5b7f0c7a2..c90fec7ee 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1188,9 +1188,9 @@ netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
      */
     memcpy(&preq, req, sizeof(preq));
     preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    hdr->nr_body = &preq;
+    hdr->nr_body = (uint64_t)&preq;
     error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
-    hdr->nr_body = req;
+    hdr->nr_body = (uint64_t)req;
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;

From 76af763e228139182ffa1c3c86ea1d6f457252c9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:19:00 +0100
Subject: [PATCH 0704/2207] utils: fix various compilation issues

---
 sys/net/netmap_user.h |   2 +-
 utils/ctrl-api-test.c |  72 +++--
 utils/testmmap.c      | 654 +++++++++++++++++++++++-------------------
 3 files changed, 393 insertions(+), 335 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 0147c947a..e12b19de7 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -277,7 +277,7 @@ nm_pkt_copy(const void *_src, void *_dst, int l)
 	const uint64_t *src = (const uint64_t *)_src;
 	uint64_t *dst = (uint64_t *)_dst;
 
-	if (unlikely(l >= 1024)) {
+	if (unlikely(l >= 1024 || l % 64)) {
 		memcpy(dst, src, l);
 		return;
 	}
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b65a35a6f..d58f81dac 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,15 +1,15 @@
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
 
 struct TestContext {
 	const char *ifname;
@@ -28,7 +28,7 @@ struct TestContext {
 
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
-	struct nmreq_option *nr_opt; /* list of options */
+	struct nmreq_option *nr_opt;  /* list of options */
 };
 
 #if 0
@@ -65,7 +65,7 @@ port_info_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -101,8 +101,8 @@ port_register(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	hdr.nr_body    = &req;
-	hdr.nr_options = ctx->nr_opt;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_options = (uint64_t)(uintptr_t)ctx->nr_opt;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id     = ctx->nr_mem_id;
 	req.nr_mode       = ctx->nr_mode;
@@ -188,7 +188,7 @@ vale_attach(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.reg.nr_mem_id = ctx->nr_mem_id;
 	if (ctx->nr_mode == 0) {
@@ -264,7 +264,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr_len = ctx->nr_hdr_len;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
@@ -330,7 +330,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id   = ctx->nr_mem_id;
 	req.nr_tx_slots = ctx->nr_tx_slots;
@@ -348,7 +348,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-	hdr.nr_body    = NULL;
+	hdr.nr_body    = (uint64_t)(uintptr_t)NULL;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
@@ -372,7 +372,7 @@ pools_info_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -433,7 +433,7 @@ pipe_master(int fd, struct TestContext *ctx)
 	ctx->nr_mode = NR_REG_ONE_NIC;
 
 	if (port_register(fd, ctx) == 0) {
-		printf("pipes should not accept NR_REG_ONE_NIC");
+		printf("pipes should not accept NR_REG_ONE_NIC\n");
 		return -1;
 	}
 	ctx->nr_mode = NR_REG_ALL_NIC;
@@ -467,7 +467,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mode		= ctx->nr_mode;
 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
@@ -499,7 +499,7 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	hdr.nr_body    = &req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -538,8 +538,8 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 static void
 push_option(struct nmreq_option *opt, struct TestContext *ctx)
 {
-	opt->nro_next = ctx->nr_opt;
-	ctx->nr_opt = opt;
+	opt->nro_next = (uint64_t)(uintptr_t)ctx->nr_opt;
+	ctx->nr_opt   = opt;
 }
 
 static void
@@ -552,21 +552,18 @@ static int
 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
 {
 	if (opt->nro_next != exp->nro_next) {
-		printf("nro_next %p expected %p\n",
-				opt->nro_next,
-				exp->nro_next);
+		printf("nro_next %p expected %p\n", (void *)opt->nro_next,
+		       (void *)exp->nro_next);
 		return -1;
 	}
 	if (opt->nro_reqtype != exp->nro_reqtype) {
-		printf("nro_reqtype %u expected %u\n",
-				opt->nro_reqtype,
-				exp->nro_reqtype);
+		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
+		       exp->nro_reqtype);
 		return -1;
 	}
 	if (opt->nro_status != exp->nro_status) {
-		printf("nro_status %u expected %u\n",
-				opt->nro_status,
-				exp->nro_status);
+		printf("nro_status %u expected %u\n", opt->nro_status,
+		       exp->nro_status);
 		return -1;
 	}
 	return 0;
@@ -601,8 +598,8 @@ infinite_options(int fd, struct TestContext *ctx)
 
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
-	opt.nro_next = &opt;
-	save = opt;
+	opt.nro_next = (uint64_t)(uintptr_t)&opt;
+	save	 = opt;
 	if (port_register_hwall(fd, ctx) >= 0)
 		return -1;
 
@@ -646,14 +643,13 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 	return 0;
 }
 
-
 static int
 push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 {
 	void *addr;
 
 	addr = mmap(NULL, (1U << 22), PROT_READ | PROT_WRITE,
-			MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+		    MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 	if (addr == MAP_FAILED) {
 		perror("mmap");
 		return -1;
@@ -661,7 +657,7 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 
 	memset(e, 0, sizeof(*e));
 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
-	e->nro_usrptr = (uint64_t)addr;
+	e->nro_usrptr	  = (uint64_t)addr;
 	e->nro_info.nr_memsize = (1U << 22);
 
 	push_option(&e->nro_opt, ctx);
@@ -675,7 +671,7 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	struct nmreq_opt_extmem *e;
 	int ret;
 
-	e = (struct nmreq_opt_extmem *)ctx->nr_opt;
+	e	   = (struct nmreq_opt_extmem *)ctx->nr_opt;
 	ctx->nr_opt = ctx->nr_opt->nro_next;
 
 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
@@ -683,15 +679,13 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	}
 
 	if (e->nro_usrptr != exp->nro_usrptr) {
-		printf("usrptr %"PRIu64" expected %"PRIu64"\n",
-				e->nro_usrptr,
-				exp->nro_usrptr);
+		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
+		       e->nro_usrptr, exp->nro_usrptr);
 		return -1;
 	}
 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
-		printf("memsize %"PRIu64" expected %"PRIu64"\n",
-				e->nro_info.nr_memsize,
-				exp->nro_info.nr_memsize);
+		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
+		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
 		return -1;
 	}
 
@@ -713,7 +707,7 @@ _extmem_option(int fd, struct TestContext *ctx, int new_rsz)
 
 	save = e;
 
-	ctx->ifname = "vale0:0";
+	ctx->ifname      = "vale0:0";
 	ctx->nr_tx_slots = 16;
 	ctx->nr_rx_slots = 16;
 
@@ -744,7 +738,7 @@ bad_extmem_option(int fd, struct TestContext *ctx)
 {
 	printf("Testing bad extmem option on vale0:0\n");
 
-	return _extmem_option(fd, ctx, (1<<16)) < 0 ? 0 : -1;
+	return _extmem_option(fd, ctx, (1 << 16)) < 0 ? 0 : -1;
 }
 
 static int
diff --git a/utils/testmmap.c b/utils/testmmap.c
index adf4a4ae9..ef38bf284 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1,30 +1,30 @@
 #define TEST_NETMAP
 
+#include 
+#include 
+#include  /* O_RDWR */
 #include 
-#include 	/* ULONG_MAX */
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
-#include 
-#include 
+#include   /* PROT_* */
+#include  /* ULONG_MAX */
 #include 
 #include 
-#include 	/* PROT_* */
-#include 	/* O_RDWR */
-#include 
-#include 
-#include 
-
+#include 
 
 #define MAX_VARS 100
 
 char *variables[MAX_VARS];
 int curr_var;
 
-#define VAR_FAILED ((void*)1)
+#define VAR_FAILED ((void *)1)
 
-char *firstarg(char *buf)
+char *
+firstarg(char *buf)
 {
 	int v;
 	char *arg = strtok(buf, " \t\n");
@@ -33,7 +33,7 @@ char *firstarg(char *buf)
 		return NULL;
 	if (arg[0] != '$' && arg[0] != '?')
 		return arg;
-	v = atoi(arg+1);
+	v = atoi(arg + 1);
 	if (v < 0 || v >= MAX_VARS)
 		return "";
 	ret = variables[v];
@@ -49,45 +49,49 @@ char *firstarg(char *buf)
 	return ret;
 }
 
-char *nextarg()
+char *
+nextarg()
 {
 	return firstarg(NULL);
 }
 
-char *restofline()
+char *
+restofline()
 {
 	return strtok(NULL, "\n");
 }
 
-void resetvar(int v, char *b)
+void
+resetvar(int v, char *b)
 {
 	if (variables[v] != VAR_FAILED)
 		free(variables[v]);
 	variables[v] = b;
 }
 
-#define outecho(format, args...) \
-	do {\
-		printf("%u:%lu: " format "\n", getpid(), (unsigned long) pthread_self(), ##args);\
-		fflush(stdout);\
+#define outecho(format, args...)                                               \
+	do {                                                                   \
+		printf("%u:%lu: " format "\n", getpid(),                       \
+		       (unsigned long)pthread_self(), ##args);                 \
+		fflush(stdout);                                                \
 	} while (0)
 
-#define output(format, args...) \
-	do {\
-		resetvar(curr_var, (char*)malloc(1024));\
-		snprintf(variables[curr_var], 1024, format, ##args);\
-		outecho(format, ##args);\
+#define output(format, args...)                                                \
+	do {                                                                   \
+		resetvar(curr_var, (char *)malloc(1024));                      \
+		snprintf(variables[curr_var], 1024, format, ##args);           \
+		outecho(format, ##args);                                       \
 	} while (0)
 
-#define output_err(ret, format, args...)\
-	do {\
-		if ((ret) < 0) {\
-			resetvar(curr_var, VAR_FAILED);\
-			outecho(format, ##args);\
-			outecho("error: %s", strerror(errno));\
-		} else {\
-			output(format, ##args);\
-		}\
+#define output_err(ret, format, args...)                                       \
+	do {                                                                   \
+		if ((ret) < 0) {                                               \
+			resetvar(curr_var, VAR_FAILED);                        \
+			outecho(format, ##args);                               \
+			outecho("error: %s", strerror(errno));                 \
+		} else {                                                       \
+			output(format, ##args);                                \
+		}                                                              \
 	} while (0)
 
 struct chan {
@@ -96,7 +100,8 @@ struct chan {
 	pthread_t tid;
 };
 
-int chan_search_free(struct chan* c[], int max)
+int
+chan_search_free(struct chan *c[], int max)
 {
 	int i;
 
@@ -106,7 +111,8 @@ int chan_search_free(struct chan* c[], int max)
 	return i;
 }
 
-void chan_clear_all(struct chan *c[], int max)
+void
+chan_clear_all(struct chan *c[], int max)
 {
 	int i;
 
@@ -119,46 +125,51 @@ void chan_clear_all(struct chan *c[], int max)
 	}
 }
 
-int last_fd = -1;
-size_t last_memsize = 0;
-void* last_mmap_addr = NULL;
-char* last_access_addr = NULL;
-
+int last_fd	    = -1;
+size_t last_memsize    = 0;
+void *last_mmap_addr   = NULL;
+char *last_access_addr = NULL;
 
-void do_open()
+void
+do_open()
 {
 	last_fd = open("/dev/netmap", O_RDWR);
 	output_err(last_fd, "open(\"/dev/netmap\", O_RDWR)=%d", last_fd);
 }
 
-void do_close()
+void
+do_close()
 {
 	int ret, fd;
 	char *arg = nextarg();
-	fd = arg ? atoi(arg) : last_fd;
-	ret = close(fd);
+	fd	= arg ? atoi(arg) : last_fd;
+	ret       = close(fd);
 	output_err(ret, "close(%d)=%d", fd, ret);
 }
 
 #ifdef TEST_NETMAP
-#include 
-#include 
 #include 
 #include 
 #include 
+#include 
+#include 
 
 /* legacy */
-struct nmreq curr_nmr = { .nr_version = 11, .nr_flags = NR_REG_ALL_NIC, };
+struct nmreq curr_nmr = {
+	.nr_version = 11,
+	.nr_flags   = NR_REG_ALL_NIC,
+};
 char nmr_name[256];
 
-void parse_nmr_config(char* w, struct nmreq *nmr)
+void
+parse_nmr_config(char *w, struct nmreq *nmr)
 {
 	char *tok;
 	int i, v;
 
 	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
 	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
-	if (w == NULL || ! *w)
+	if (w == NULL || !*w)
 		return;
 	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
 		v = atoi(tok);
@@ -181,7 +192,8 @@ void parse_nmr_config(char* w, struct nmreq *nmr)
 	}
 }
 
-void do_getinfo_legacy()
+void
+do_getinfo_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -208,14 +220,14 @@ void do_getinfo_legacy()
 	parse_nmr_config(arg, &curr_nmr);
 
 doit:
-	ret = ioctl(fd, NIOCGINFO, &curr_nmr);
+	ret	  = ioctl(fd, NIOCGINFO, &curr_nmr);
 	last_memsize = curr_nmr.nr_memsize;
 	output_err(ret, "ioctl(%d, NIOCGINFO) for %s: region %d memsize=%zu",
-		fd, name, curr_nmr.nr_arg2, last_memsize);
+		   fd, name, curr_nmr.nr_arg2, last_memsize);
 }
 
-
-void do_regif_legacy()
+void
+do_regif_legacy()
 {
 	int ret;
 	char *arg, *name;
@@ -229,7 +241,7 @@ void do_regif_legacy()
 
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
-	curr_nmr.nr_flags = NR_REG_ALL_NIC;
+	curr_nmr.nr_flags   = NR_REG_ALL_NIC;
 	strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name));
 
 	arg = nextarg();
@@ -242,18 +254,18 @@ void do_regif_legacy()
 	parse_nmr_config(arg, &curr_nmr);
 
 doit:
-	ret = ioctl(fd, NIOCREGIF, &curr_nmr);
+	ret	  = ioctl(fd, NIOCREGIF, &curr_nmr);
 	last_memsize = curr_nmr.nr_memsize;
 	output_err(ret, "ioctl(%d, NIOCREGIF) for %s: region %d memsize=%zu",
-		fd, name, curr_nmr.nr_arg2, last_memsize);
+		   fd, name, curr_nmr.nr_arg2, last_memsize);
 }
 
 void
 do_txsync()
 {
 	char *arg = nextarg();
-	int fd = arg ? atoi(arg) : last_fd;
-	int ret = ioctl(fd, NIOCTXSYNC, NULL);
+	int fd    = arg ? atoi(arg) : last_fd;
+	int ret   = ioctl(fd, NIOCTXSYNC, NULL);
 	output_err(ret, "ioctl(%d, NIOCTXSYNC)=%d", fd, ret);
 }
 
@@ -261,14 +273,14 @@ void
 do_rxsync()
 {
 	char *arg = nextarg();
-	int fd = arg ? atoi(arg) : last_fd;
-	int ret = ioctl(fd, NIOCRXSYNC, NULL);
+	int fd    = arg ? atoi(arg) : last_fd;
+	int ret   = ioctl(fd, NIOCRXSYNC, NULL);
 	output_err(ret, "ioctl(%d, NIOCRXSYNC)=%d", fd, ret);
 }
 #endif /* TEST_NETMAP */
 
-
-void do_rd()
+void
+do_rd()
 {
 	char *arg = nextarg();
 	char *p;
@@ -286,7 +298,8 @@ void do_rd()
 }
 
 char *last_wr_byte = "x";
-void do_wr()
+void
+do_wr()
 {
 	char *arg = nextarg();
 	char *p;
@@ -304,15 +317,16 @@ void do_wr()
 	if (!arg) {
 		arg = last_wr_byte;
 	}
-	for ( ; arg; arg = nextarg()) {
+	for (; arg; arg = nextarg()) {
 		*p++ = strtoul((void *)arg, NULL, 0);
 	}
 }
 
-void do_dup()
+void
+do_dup()
 {
 	char *arg = nextarg();
-	int fd = last_fd;
+	int fd    = last_fd;
 	int ret;
 
 	if (arg) {
@@ -320,10 +334,10 @@ void do_dup()
 	}
 	ret = dup(fd);
 	output_err(ret, "dup(%d)=%d", fd, ret);
-
 }
 
-void do_mmap()
+void
+do_mmap()
 {
 	size_t memsize;
 	off_t off = 0;
@@ -333,37 +347,36 @@ void do_mmap()
 	arg = nextarg();
 	if (!arg) {
 		memsize = last_memsize;
-		fd = last_fd;
+		fd      = last_fd;
 		goto doit;
 	}
 	memsize = atoi(arg);
-	arg = nextarg();
+	arg     = nextarg();
 	if (!arg) {
 		fd = last_fd;
 		goto doit;
 	}
-	fd = atoi(arg);
+	fd  = atoi(arg);
 	arg = nextarg();
 	if (arg) {
 		off = (off_t)atol(arg);
 	}
 doit:
-	last_mmap_addr = mmap(0, memsize,
-			PROT_WRITE | PROT_READ,
-			MAP_SHARED, fd, off);
+	last_mmap_addr =
+		mmap(0, memsize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, off);
 	if (last_access_addr == NULL)
 		last_access_addr = last_mmap_addr;
 	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
-		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED, %d, %jd)=%p",
-		memsize, fd, (intmax_t)off, last_mmap_addr);
-
+		   "mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED, %d, %jd)=%p",
+		   memsize, fd, (intmax_t)off, last_mmap_addr);
 }
 
 #ifndef MAP_HUGETLB
 #define MAP_HUGETLB 0x40000
 #endif
 
-void do_anon_mmap()
+void
+do_anon_mmap()
 {
 	size_t memsize;
 	char *arg;
@@ -375,23 +388,23 @@ void do_anon_mmap()
 		goto doit;
 	}
 	memsize = atoi(arg);
-	arg = nextarg();
+	arg     = nextarg();
 	if (!arg)
 		goto doit;
 	flags |= MAP_HUGETLB;
 doit:
-	last_mmap_addr = mmap(0, memsize,
-			PROT_WRITE | PROT_READ,
-			MAP_SHARED | MAP_ANONYMOUS | flags, -1, 0);
+	last_mmap_addr = mmap(0, memsize, PROT_WRITE | PROT_READ,
+			      MAP_SHARED | MAP_ANONYMOUS | flags, -1, 0);
 	if (last_access_addr == NULL)
 		last_access_addr = last_mmap_addr;
 	output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
-		"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS%s, -1, 0)=%p",
-		memsize, (flags ? "|MAP_HUGETLB" : ""), last_mmap_addr);
-
+		   "mmap(0, %zu, PROT_WRITE|PROT_READ, "
+		   "MAP_SHARED|MAP_ANONYMOUS%s, -1, 0)=%p",
+		   memsize, (flags ? "|MAP_HUGETLB" : ""), last_mmap_addr);
 }
 
-void do_munmap()
+void
+do_munmap()
 {
 	void *mmap_addr;
 	size_t memsize;
@@ -401,11 +414,11 @@ void do_munmap()
 	arg = nextarg();
 	if (!arg) {
 		mmap_addr = last_mmap_addr;
-		memsize = last_memsize;
+		memsize   = last_memsize;
 		goto doit;
 	}
-	mmap_addr = (void*)strtoul(arg, NULL, 0);
-	arg = nextarg();
+	mmap_addr = (void *)strtoul(arg, NULL, 0);
+	arg       = nextarg();
 	if (!arg) {
 		memsize = last_memsize;
 		goto doit;
@@ -416,7 +429,8 @@ void do_munmap()
 	output_err(ret, "munmap(%p, %zu)=%d", mmap_addr, memsize, ret);
 }
 
-void do_poll()
+void
+do_poll()
 {
 	/* timeout fd fd... */
 	nfds_t nfds = 0, allocated_fds = 10, i;
@@ -433,11 +447,12 @@ void do_poll()
 		output_err(-1, "out of memory");
 		return;
 	}
-	while ( (arg = nextarg()) ) {
+	while ((arg = nextarg())) {
 		if (nfds >= allocated_fds) {
 			struct pollfd *new_fds;
 			allocated_fds *= 2;
-			new_fds = realloc(fds, allocated_fds * sizeof(struct pollfd));
+			new_fds = realloc(fds, allocated_fds *
+						       sizeof(struct pollfd));
 			if (new_fds == NULL) {
 				free(fds);
 				output_err(-1, "out of memory");
@@ -445,25 +460,23 @@ void do_poll()
 			}
 			fds = new_fds;
 		}
-		fds[nfds].fd = atoi(arg);
+		fds[nfds].fd     = atoi(arg);
 		fds[nfds].events = POLLIN;
 		nfds++;
 	}
 	ret = poll(fds, nfds, timeout);
 	for (i = 0; i < nfds; i++) {
 		output("poll(%d)=%s%s%s%s%s", fds[i].fd,
-			(fds[i].revents & POLLIN) ? "IN  " : "-   ",
-			(fds[i].revents & POLLOUT)? "OUT " : "-   ",
-			(fds[i].revents & POLLERR)? "ERR " : "-   ",
-			(fds[i].revents & POLLHUP)? "HUP " : "-   ",
-			(fds[i].revents & POLLNVAL)?"NVAL" : "-");
-
+		       (fds[i].revents & POLLIN) ? "IN  " : "-   ",
+		       (fds[i].revents & POLLOUT) ? "OUT " : "-   ",
+		       (fds[i].revents & POLLERR) ? "ERR " : "-   ",
+		       (fds[i].revents & POLLHUP) ? "HUP " : "-   ",
+		       (fds[i].revents & POLLNVAL) ? "NVAL" : "-");
 	}
 	output_err(ret, "poll(...)=%d", ret);
 	free(fds);
 }
 
-
 void
 do_expr()
 {
@@ -473,7 +486,7 @@ do_expr()
 	int err = 0;
 
 	stack[10] = ULONG_MAX;
-	while ( (arg = nextarg()) ) {
+	while ((arg = nextarg())) {
 		errno = 0;
 		char *rest;
 		unsigned long n = strtoul(arg, &rest, 0);
@@ -488,7 +501,7 @@ do_expr()
 		if (top <= 8) {
 			unsigned long n1 = stack[top++];
 			unsigned long n2 = stack[top++];
-			unsigned long r = 0;
+			unsigned long r  = 0;
 			switch (arg[0]) {
 			case '+':
 				r = n1 + n2;
@@ -504,7 +517,7 @@ do_expr()
 					r = n1 / n2;
 				else {
 					errno = EDOM;
-					err = -1;
+					err   = -1;
 				}
 				break;
 			default:
@@ -520,8 +533,6 @@ do_expr()
 	output_err(err, "expr=%lu", stack[top]);
 }
 
-
-
 void
 do_echo()
 {
@@ -539,7 +550,7 @@ do_vars()
 		const char *v = variables[i];
 		if (v == NULL)
 			continue;
-		printf("?%d\t%s\n", i, v == VAR_FAILED ?  "FAILED" : v);
+		printf("?%d\t%s\n", i, v == VAR_FAILED ? "FAILED" : v);
 	}
 }
 
@@ -551,7 +562,7 @@ get_if()
 	char *arg;
 
 	/* defaults */
-	off = curr_nmr.nr_offset;
+	off       = curr_nmr.nr_offset;
 	mmap_addr = last_mmap_addr;
 
 	/* first arg: if offset */
@@ -565,7 +576,7 @@ get_if()
 	if (!arg) {
 		goto doit;
 	}
-	mmap_addr = (void*)strtoul(arg, NULL, 0);
+	mmap_addr = (void *)strtoul(arg, NULL, 0);
 doit:
 	return NETMAP_IF(mmap_addr, off);
 }
@@ -621,7 +632,7 @@ get_ring()
 void
 dump_ring(struct netmap_ring *ring)
 {
-	printf("buf_ofs     %"PRId64"\n", ring->buf_ofs);
+	printf("buf_ofs     %" PRId64 "\n", ring->buf_ofs);
 	printf("num_slots   %u\n", ring->num_slots);
 	printf("nr_buf_size %u\n", ring->nr_buf_size);
 	printf("ringid      %d\n", ring->ringid);
@@ -653,8 +664,8 @@ dump_ring(struct netmap_ring *ring)
 		printf(" ]");
 	}
 	printf("\n");
-	printf("ts          %ld:%ld\n",
-			(long int)ring->ts.tv_sec, (long int)ring->ts.tv_usec);
+	printf("ts          %ld:%ld\n", (long int)ring->ts.tv_sec,
+	       (long int)ring->ts.tv_usec);
 }
 
 void
@@ -748,7 +759,7 @@ do_slot()
 doit:
 	ring = get_ring();
 	slot = ring->slot + index;
-	arg = nextarg();
+	arg  = nextarg();
 	if (!arg) {
 		dump_slot(slot);
 		return;
@@ -777,15 +788,15 @@ dump_payload(char *p, int len)
 	int i, j, i0;
 
 	/* hexdump routine */
-	for (i = 0; i < len; ) {
+	for (i = 0; i < len;) {
 		memset(buf, sizeof(buf), ' ');
 		sprintf(buf, "%5d: ", i);
 		i0 = i;
-		for (j=0; j < 16 && i < len; i++, j++)
-			sprintf(buf+7+j*3, "%02x ", (uint8_t)(p[i]));
+		for (j = 0; j < 16 && i < len; i++, j++)
+			sprintf(buf + 7 + j * 3, "%02x ", (uint8_t)(p[i]));
 		i = i0;
-		for (j=0; j < 16 && i < len; i++, j++)
-			sprintf(buf+7+j + 48, "%c",
+		for (j = 0; j < 16 && i < len; i++, j++)
+			sprintf(buf + 7 + j + 48, "%c",
 				isprint(p[i]) ? p[i] : '.');
 		printf("%s\n", buf);
 	}
@@ -800,7 +811,7 @@ do_buf()
 
 	/* defaults */
 	buf_idx = 2;
-	len = 64;
+	len     = 64;
 
 	arg = nextarg();
 	if (!arg)
@@ -813,7 +824,7 @@ do_buf()
 	len = strtoll(arg, NULL, 0);
 doit:
 	ring = get_ring();
-	buf = NETMAP_BUF(ring, buf_idx);
+	buf  = NETMAP_BUF(ring, buf_idx);
 	output("buf=%p", buf);
 	last_access_addr = buf;
 	dump_payload(buf, len);
@@ -824,7 +835,8 @@ struct cmd_def {
 	void (*f)(void);
 };
 
-int _find_command(const struct cmd_def *cmds, int ncmds, const char* cmd)
+int
+_find_command(const struct cmd_def *cmds, int ncmds, const char *cmd)
 {
 	int i;
 	for (i = 0; i < ncmds; i++) {
@@ -839,8 +851,11 @@ struct pools_info_field {
 	size_t off;
 	size_t size;
 };
-#define PIFD(n, f)	{ n, offsetof(struct nmreq_pools_info, nr_##f), \
-	sizeof(((struct nmreq_pools_info *)0)->nr_##f) }
+#define PIFD(n, f)                                                             \
+	{                                                                      \
+		n, offsetof(struct nmreq_pools_info, nr_##f),                  \
+			sizeof(((struct nmreq_pools_info *)0)->nr_##f)         \
+	}
 struct pools_info_field pools_info_fields[] = {
 	PIFD("memsize", memsize),
 	PIFD("mem_id", mem_id),
@@ -853,9 +868,8 @@ struct pools_info_field pools_info_fields[] = {
 	PIFD("buf-off", buf_pool_offset),
 	PIFD("buf-tot", buf_pool_objtotal),
 	PIFD("buf-siz", buf_pool_objsize),
-	{ NULL, 0, 0 }
-};
-#define PIF(t, p, o)	(*(t*)((void *)((char *)(p)+(o))))
+	{NULL, 0, 0}};
+#define PIF(t, p, o) (*(t *)((void *)((char *)(p) + (o))))
 void
 pools_info_dump(int tab, struct nmreq_pools_info *upi)
 {
@@ -865,19 +879,18 @@ pools_info_dump(int tab, struct nmreq_pools_info *upi)
 		printf("%.*s%-12s", tab, space, f->name);
 		switch (f->size) {
 		case 8:
-			printf("%"PRIu64"\n", PIF(uint64_t, upi, f->off));
+			printf("%" PRIu64 "\n", PIF(uint64_t, upi, f->off));
 			break;
 		case 4:
-			printf("%"PRIu32"\n", PIF(uint32_t, upi, f->off));
+			printf("%" PRIu32 "\n", PIF(uint32_t, upi, f->off));
 			break;
 		case 2:
-			printf("%"PRIu16"\n", PIF(uint16_t, upi, f->off));
+			printf("%" PRIu16 "\n", PIF(uint16_t, upi, f->off));
 			break;
 		}
 	}
 }
 
-
 static struct nmreq_pools_info curr_pools_info;
 
 /* prepare the curr_pools_info */
@@ -917,9 +930,9 @@ do_pools_info()
 
 typedef void (*nmr_arg_interp_fun)();
 
-#define nmr_arg_unexpected(n) \
-	printf("arg%d:      %d%s\n", n, curr_nmr.nr_arg ## n, \
-		(curr_nmr.nr_arg ## n ? "???" : ""))
+#define nmr_arg_unexpected(n)                                                  \
+	printf("arg%d:      %d%s\n", n, curr_nmr.nr_arg##n,                    \
+	       (curr_nmr.nr_arg##n ? "???" : ""))
 
 void
 nmr_arg_bdg_attach()
@@ -1002,12 +1015,13 @@ void
 nmr_arg_extra()
 {
 	printf("arg1:      %d [%sextra rings]\n", curr_nmr.nr_arg1,
-		(curr_nmr.nr_arg1 ? "" : "no "));
+	       (curr_nmr.nr_arg1 ? "" : "no "));
 	printf("arg2:      %d [%s memory allocator]\n", curr_nmr.nr_arg2,
-		(curr_nmr.nr_arg2 == 0 ? "default" :
-		 curr_nmr.nr_arg2 == 1 ? "global"  : "private"));
+	       (curr_nmr.nr_arg2 == 0
+			? "default"
+			: curr_nmr.nr_arg2 == 1 ? "global" : "private"));
 	printf("arg3:      %d [%sextra buffers]\n", curr_nmr.nr_arg3,
-		(curr_nmr.nr_arg3 ? "" : "no "));
+	       (curr_nmr.nr_arg3 ? "" : "no "));
 }
 
 void
@@ -1022,7 +1036,7 @@ do_nmr_legacy_dump()
 	printf("version:   %d\n", curr_nmr.nr_version);
 	printf("offset:    %d\n", curr_nmr.nr_offset);
 	printf("memsize:   %d [", curr_nmr.nr_memsize);
-	if (curr_nmr.nr_memsize < (1<<20)) {
+	if (curr_nmr.nr_memsize < (1 << 20)) {
 		printf("%d KiB", curr_nmr.nr_memsize >> 10);
 	} else {
 		printf("%d MiB", curr_nmr.nr_memsize >> 20);
@@ -1158,7 +1172,7 @@ do_nmr_legacy_reset()
 {
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
-	curr_nmr.nr_flags = NR_REG_ALL_NIC;
+	curr_nmr.nr_flags   = NR_REG_ALL_NIC;
 }
 
 void
@@ -1277,15 +1291,13 @@ do_nmr_legacy_flags()
 }
 
 struct cmd_def nmr_legacy_commands[] = {
-	{ "dump",	do_nmr_legacy_dump },
-	{ "reset",	do_nmr_legacy_reset },
-	{ "name",	do_nmr_legacy_name },
-	{ "ringid",	do_nmr_legacy_ringid },
-	{ "cmd",	do_nmr_legacy_cmd },
-	{ "flags",	do_nmr_legacy_flags },
+	{"dump", do_nmr_legacy_dump}, {"reset", do_nmr_legacy_reset},
+	{"name", do_nmr_legacy_name}, {"ringid", do_nmr_legacy_ringid},
+	{"cmd", do_nmr_legacy_cmd},   {"flags", do_nmr_legacy_flags},
 };
 
-const int N_NMR_LEGACY_CMDS = sizeof(nmr_legacy_commands) / sizeof(struct cmd_def);
+const int N_NMR_LEGACY_CMDS =
+	sizeof(nmr_legacy_commands) / sizeof(struct cmd_def);
 
 int
 find_nmr_legacy_command(const char *cmd)
@@ -1293,22 +1305,22 @@ find_nmr_legacy_command(const char *cmd)
 	return _find_command(nmr_legacy_commands, N_NMR_LEGACY_CMDS, cmd);
 }
 
-#define __nmr_arg_update(nmr, f) 					\
-	({								\
-		int __ret = 0;						\
-		if (strcmp(cmd, #f) == 0) {				\
-			char *arg = nextarg();				\
-			if (arg) {					\
-				curr_##nmr.nr_##f = strtol(arg, NULL, 0);\
-			}						\
-			output(#f "=%llu",				\
-				(unsigned long long)curr_##nmr.nr_##f);	\
-			__ret = 1;					\
-		} 							\
-		__ret;							\
+#define __nmr_arg_update(nmr, f)                                               \
+	({                                                                     \
+		int __ret = 0;                                                 \
+		if (strcmp(cmd, #f) == 0) {                                    \
+			char *arg = nextarg();                                 \
+			if (arg) {                                             \
+				curr_##nmr.nr_##f = strtol(arg, NULL, 0);      \
+			}                                                      \
+			output(#f "=%llu",                                     \
+			       (unsigned long long)curr_##nmr.nr_##f);         \
+			__ret = 1;                                             \
+		}                                                              \
+		__ret;                                                         \
 	})
 
-#define nmr_arg_update(f)	__nmr_arg_update(nmr, f)
+#define nmr_arg_update(f) __nmr_arg_update(nmr, f)
 
 /* prepare the curr_nmr */
 void
@@ -1330,18 +1342,12 @@ do_nmr_legacy()
 			return;
 		}
 	}
-	if (nmr_arg_update(version) ||
-	    nmr_arg_update(offset) ||
-	    nmr_arg_update(memsize) ||
-	    nmr_arg_update(tx_slots) ||
-	    nmr_arg_update(rx_slots) ||
-	    nmr_arg_update(tx_rings) ||
-	    nmr_arg_update(rx_rings) ||
-	    nmr_arg_update(ringid) ||
-	    nmr_arg_update(cmd) ||
-	    nmr_arg_update(arg1) ||
-	    nmr_arg_update(arg2) ||
-	    nmr_arg_update(arg3) ||
+	if (nmr_arg_update(version) || nmr_arg_update(offset) ||
+	    nmr_arg_update(memsize) || nmr_arg_update(tx_slots) ||
+	    nmr_arg_update(rx_slots) || nmr_arg_update(tx_rings) ||
+	    nmr_arg_update(rx_rings) || nmr_arg_update(ringid) ||
+	    nmr_arg_update(cmd) || nmr_arg_update(arg1) ||
+	    nmr_arg_update(arg2) || nmr_arg_update(arg3) ||
 	    nmr_arg_update(flags))
 		return;
 	output("unknown field: %s", cmd);
@@ -1351,7 +1357,7 @@ do_nmr_legacy()
  * new API							*
  ****************************************************************/
 
-static struct nmreq_header curr_hdr = { .nr_version = NETMAP_API };
+static struct nmreq_header curr_hdr = {.nr_version = NETMAP_API};
 static struct nmreq_register curr_register;
 static struct nmreq_port_info_get curr_port_info_get;
 static struct nmreq_vale_attach curr_vale_attach;
@@ -1366,24 +1372,24 @@ static void
 nmr_body_dump_register(void *b)
 {
 	struct nmreq_register *r = b;
-	int flags = 0;
-	printf("offset:    %"PRIu64"\n", r->nr_offset);
-	printf("memsize:   %"PRIu64" [", r->nr_memsize);
-	if (r->nr_memsize < (1<<20)) {
-		printf("%"PRIu64" KiB", r->nr_memsize >> 10);
+	int flags		 = 0;
+	printf("offset:    %" PRIu64 "\n", r->nr_offset);
+	printf("memsize:   %" PRIu64 " [", r->nr_memsize);
+	if (r->nr_memsize < (1 << 20)) {
+		printf("%" PRIu64 " KiB", r->nr_memsize >> 10);
 	} else {
-		printf("%"PRIu64" MiB", r->nr_memsize >> 20);
+		printf("%" PRIu64 " MiB", r->nr_memsize >> 20);
 	}
 	printf("]\n");
-	printf("tx_slots:  %"PRIu16"\n", r->nr_tx_slots);
-	printf("rx_slots:  %"PRIu16"\n", r->nr_rx_slots);
-	printf("tx_rings:  %"PRIu16"\n", r->nr_tx_rings);
-	printf("rx_rings:  %"PRIu16"\n", r->nr_rx_rings);
-	printf("mem_id:    %"PRIu16" [%s memory region]\n", r->nr_mem_id,
-		(r->nr_mem_id == 0 ? "default" :
-		 r->nr_mem_id == 1 ? "global"  : "private"));
-	printf("ringid     %"PRIu16"\n", r->nr_ringid);
-	printf("mode       %"PRIu32" [", r->nr_mode);
+	printf("tx_slots:  %" PRIu16 "\n", r->nr_tx_slots);
+	printf("rx_slots:  %" PRIu16 "\n", r->nr_rx_slots);
+	printf("tx_rings:  %" PRIu16 "\n", r->nr_tx_rings);
+	printf("rx_rings:  %" PRIu16 "\n", r->nr_rx_rings);
+	printf("mem_id:    %" PRIu16 " [%s memory region]\n", r->nr_mem_id,
+	       (r->nr_mem_id == 0 ? "default"
+				  : r->nr_mem_id == 1 ? "global" : "private"));
+	printf("ringid     %" PRIu16 "\n", r->nr_ringid);
+	printf("mode       %" PRIu32 " [", r->nr_mode);
 	switch (r->nr_mode) {
 	case NR_REG_DEFAULT:
 		printf("*DEFAULT");
@@ -1398,7 +1404,7 @@ nmr_body_dump_register(void *b)
 		printf("NIC_SW");
 		break;
 	case NR_REG_ONE_NIC:
-		printf("ONE_NIC(%"PRIu16")", r->nr_ringid);
+		printf("ONE_NIC(%" PRIu16 ")", r->nr_ringid);
 		break;
 	case NR_REG_PIPE_MASTER:
 		printf("*PIPE_MASTER(%d)", r->nr_ringid);
@@ -1412,7 +1418,10 @@ nmr_body_dump_register(void *b)
 	}
 	printf("]\n");
 	printf("flags:     %lx [", r->nr_flags);
-#define pflag(f) if (r->nr_flags & NR_##f) { printf("%s" #f, flags++ ? ", " : ""); }
+#define pflag(f)                                                               \
+	if (r->nr_flags & NR_##f) {                                            \
+		printf("%s" #f, flags++ ? ", " : "");                          \
+	}
 	pflag(MONITOR_TX);
 	pflag(MONITOR_RX);
 	pflag(ZCOPY_MON);
@@ -1425,7 +1434,7 @@ nmr_body_dump_register(void *b)
 	pflag(NO_TX_POLL);
 #undef pflag
 	printf("]\n");
-	printf("extra_bufs %"PRIu32"\n", r->nr_extra_bufs);
+	printf("extra_bufs %" PRIu32 "\n", r->nr_extra_bufs);
 }
 
 static void
@@ -1465,7 +1474,7 @@ do_register_mode()
 	}
 
 out:
-	output("mode=%"PRIu32, curr_register.nr_mode);
+	output("mode=%" PRIu32, curr_register.nr_mode);
 }
 
 void
@@ -1505,10 +1514,10 @@ do_register_flags()
 }
 
 struct cmd_def register_commands[] = {
-	{ "dump",	do_register_dump },
-	{ "reset",	do_register_reset },
-	{ "mode",	do_register_mode },
-	{ "flags",	do_register_flags },
+	{"dump", do_register_dump},
+	{"reset", do_register_reset},
+	{"mode", do_register_mode},
+	{"flags", do_register_flags},
 };
 
 const int N_REGISTER_CMDS = sizeof(register_commands) / sizeof(struct cmd_def);
@@ -1540,17 +1549,12 @@ do_register()
 			return;
 		}
 	}
-	if (register_update(offset) 
-	||  register_update(memsize) 
-	||  register_update(tx_slots) 
-	||  register_update(rx_slots) 
-	||  register_update(tx_rings) 
-	||  register_update(rx_rings) 
-	||  register_update(mem_id) 
-	||  register_update(ringid) 
-	||  register_update(mode) 
-	||  register_update(flags)
-	||  register_update(extra_bufs))
+	if (register_update(offset) || register_update(memsize) ||
+	    register_update(tx_slots) || register_update(rx_slots) ||
+	    register_update(tx_rings) || register_update(rx_rings) ||
+	    register_update(mem_id) || register_update(ringid) ||
+	    register_update(mode) || register_update(flags) ||
+	    register_update(extra_bufs))
 		return;
 	output("unknown field: %s", cmd);
 }
@@ -1602,8 +1606,7 @@ typedef void (*nmr_option_dump_fun)(struct nmreq_option *);
 static void
 nmr_option_dump_extmem(struct nmreq_option *opt)
 {
-	struct nmreq_opt_extmem *e =
-		(struct nmreq_opt_extmem *)opt;
+	struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)opt;
 
 	printf("usrptr: %p\n", (void *)e->nro_usrptr);
 	printf("info:\n");
@@ -1615,8 +1618,8 @@ nmr_option_dump(struct nmreq_option *opt)
 {
 	nmr_option_dump_fun d = NULL;
 
-	printf("next: %p\n", opt->nro_next);
-	printf("type: %"PRIu32" [", opt->nro_reqtype);
+	printf("next: %p\n", (void *)opt->nro_next);
+	printf("type: %" PRIu32 " [", opt->nro_reqtype);
 	switch (opt->nro_reqtype) {
 	case NETMAP_REQ_OPT_EXTMEM:
 		printf("extmem");
@@ -1626,15 +1629,15 @@ nmr_option_dump(struct nmreq_option *opt)
 #ifdef NETMAP_OPT_DEBUG
 		if (opt->nro_reqtype & NETMAP_REQ_OPT_DEBUG) {
 			printf("debug: %u",
-				(opt->nro_reqtype & ~NETMAP_REQ_OPT_DEBUG));
+			       (opt->nro_reqtype & ~NETMAP_REQ_OPT_DEBUG));
 			break;
 		}
 #endif /* NETMAP_OPT_DEBUG */
 		printf("???");
 	}
 	printf("]\n");
-	printf("status: %"PRIu32" [%s]\n", 
-			opt->nro_status, strerror(opt->nro_status));
+	printf("status: %" PRIu32 " [%s]\n", opt->nro_status,
+	       strerror(opt->nro_status));
 	if (d)
 		d(opt);
 }
@@ -1702,29 +1705,29 @@ do_hdr_dump()
 	}
 	printf("]\n");
 	printf("name: %s\n", nmr_name);
-	opt = curr_hdr.nr_options;
+	opt = (struct nmreq_option *)curr_hdr.nr_options;
 	printf("options:   %p\n", opt);
 	while (opt) {
 		nmr_option_dump(opt);
-		opt = opt->nro_next;
+		opt = (struct nmreq_option *)opt->nro_next;
 	}
-	printf("body:	   %p\n", curr_hdr.nr_body);
+	printf("body:	   %p\n", (void *)curr_hdr.nr_body);
 	if (body_dump)
-		body_dump(curr_hdr.nr_body);
+		body_dump((void *)curr_hdr.nr_body);
 }
 
 static void
 do_hdr_reset()
 {
-	struct nmreq_option *opt = curr_hdr.nr_options;
+	struct nmreq_option *opt = (struct nmreq_option *)curr_hdr.nr_options;
 	while (opt) {
-		struct nmreq_option *next = opt->nro_next;
+		struct nmreq_option *next =
+			(struct nmreq_option *)opt->nro_next;
 		free(opt);
 		opt = next;
 	}
 	memset(&curr_hdr, 0, sizeof(curr_hdr));
 	curr_hdr.nr_version = NETMAP_API;
-
 }
 
 void
@@ -1739,7 +1742,6 @@ do_hdr_name()
 	output("name=%s", nmr_name);
 }
 
-
 static void
 do_hdr_type()
 {
@@ -1747,38 +1749,38 @@ do_hdr_type()
 
 	if (strcmp(type, "register") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-		curr_hdr.nr_body = &curr_register;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_register;
 	} else if (strcmp(type, "info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-		curr_hdr.nr_body = &curr_port_info_get;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_info_get;
 	} else if (strcmp(type, "vale-attach") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-		curr_hdr.nr_body = &curr_vale_attach;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_attach;
 	} else if (strcmp(type, "vale-detach") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	} else if (strcmp(type, "vale-list") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-		curr_hdr.nr_body = &curr_vale_list;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_list;
 	} else if (strcmp(type, "port-hdr-set") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-		curr_hdr.nr_body = &curr_port_hdr;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_hdr;
 	} else if (strcmp(type, "port-hdr-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-		curr_hdr.nr_body = &curr_port_hdr;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_hdr;
 	} else if (strcmp(type, "vale-newif") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-		curr_hdr.nr_body = &curr_vale_newif;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_newif;
 	} else if (strcmp(type, "vale-delif") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	} else if (strcmp(type, "vale-polliing-enable") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-		curr_hdr.nr_body = &curr_vale_polling;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_polling;
 	} else if (strcmp(type, "vale-polling-disable") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-		curr_hdr.nr_body = &curr_vale_polling;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_polling;
 	} else if (strcmp(type, "pools-info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-		curr_hdr.nr_body = &curr_pools_info;
+		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_pools_info;
 	} else {
 		output("unknown type: %s", type);
 	}
@@ -1790,34 +1792,34 @@ typedef void (*nmreq_opt_init)(struct nmreq_option *);
 static void
 nmreq_opt_extmem_init(struct nmreq_option *opt)
 {
-	struct nmreq_opt_extmem *e =
-		(struct nmreq_opt_extmem *)opt;
-	e->nro_usrptr = (uint64_t)last_mmap_addr;
-	e->nro_info.nr_memsize = last_memsize;
+	struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)opt;
+	e->nro_usrptr		   = (uint64_t)last_mmap_addr;
+	e->nro_info.nr_memsize     = last_memsize;
 }
 
 static void
 do_hdr_option()
 {
 	char *type;
-	struct nmreq_option **ptr = &curr_hdr.nr_options,
+	struct nmreq_option **ptr = (struct nmreq_option **)&curr_hdr
+					    .nr_options,
 			    *old = *ptr;
-	size_t sz = sizeof(struct nmreq_option);
-	nmreq_opt_init init = NULL;
+	size_t sz		 = sizeof(struct nmreq_option);
+	nmreq_opt_init init      = NULL;
 
-	while ( (type = nextarg()) ) {
+	while ((type = nextarg())) {
 		uint16_t reqtype;
 
 		if (strcmp(type, "extmem") == 0) {
 			reqtype = NETMAP_REQ_OPT_EXTMEM;
-			sz = sizeof(struct nmreq_opt_extmem);
-			init = nmreq_opt_extmem_init;
+			sz      = sizeof(struct nmreq_opt_extmem);
+			init    = nmreq_opt_extmem_init;
 #ifdef NETMAP_OPT_DEBUG
 		} else {
 			reqtype = strtol(type, NULL, 0) | NETMAP_REQ_OPT_DEBUG;
 #endif /* NETMAP_OPT_DEBUG */
 		}
-		*ptr = malloc(sz);	
+		*ptr = malloc(sz);
 		if (*ptr == NULL) {
 			output_err(-1, "malloc");
 		}
@@ -1825,17 +1827,14 @@ do_hdr_option()
 		(*ptr)->nro_reqtype = reqtype;
 		if (init)
 			init(*ptr);
-		ptr = &(*ptr)->nro_next;
+		ptr = (struct nmreq_option **)&(*ptr)->nro_next;
 	}
 	*ptr = old;
 }
 
 struct cmd_def hdr_commands[] = {
-	{ "dump",	do_hdr_dump },
-	{ "reset",	do_hdr_reset },
-	{ "name",	do_hdr_name },
-	{ "type",	do_hdr_type },
-	{ "option",	do_hdr_option },
+	{"dump", do_hdr_dump}, {"reset", do_hdr_reset},   {"name", do_hdr_name},
+	{"type", do_hdr_type}, {"option", do_hdr_option},
 };
 
 const int N_HDR_CMDS = sizeof(hdr_commands) / sizeof(struct cmd_def);
@@ -1846,8 +1845,6 @@ find_hdr_command(const char *cmd)
 	return _find_command(hdr_commands, N_HDR_CMDS, cmd);
 }
 
-
-
 static void
 do_hdr()
 {
@@ -1881,49 +1878,113 @@ do_ctrl()
 doit:
 	ret = ioctl(fd, NIOCCTRL, &curr_hdr);
 	output_err(ret, "ioctl(%d, NIOCCTL, %p)=%d", fd, &curr_hdr, ret);
-
 }
 
-
-struct cmd_def commands[] = {
-	{ "open",	do_open,	},
-	{ "close", 	do_close,	},
+struct cmd_def commands[] = {{
+				     "open",
+				     do_open,
+			     },
+			     {
+				     "close",
+				     do_close,
+			     },
 #ifdef TEST_NETMAP
-	{ "getinfo-legacy",	do_getinfo_legacy,	},
-	{ "regif-legacy",	do_regif_legacy,	},
-	{ "txsync",	do_txsync,	},
-	{ "rxsync",	do_rxsync,	},
+			     {
+				     "getinfo-legacy",
+				     do_getinfo_legacy,
+			     },
+			     {
+				     "regif-legacy",
+				     do_regif_legacy,
+			     },
+			     {
+				     "txsync",
+				     do_txsync,
+			     },
+			     {
+				     "rxsync",
+				     do_rxsync,
+			     },
 #endif /* TEST_NETMAP */
-	{ "dup",	do_dup,		},
-	{ "mmap",	do_mmap,	},
-	{ "anon-mmap",	do_anon_mmap,	},
-	{ "rd",		do_rd,		},
-	{ "wr",		do_wr,		},
-	{ "munmap",	do_munmap,	},
-	{ "poll",	do_poll,	},
-	{ "expr",	do_expr,	},
-	{ "echo",	do_echo,	},
-	{ "vars",	do_vars,	},
-	{ "if",         do_if,          },
-	{ "ring",       do_ring,        },
-	{ "slot",       do_slot,        },
-	{ "buf",        do_buf,         },
-	{ "nmr-legacy",	do_nmr_legacy,	},
-	{ "hdr",	do_hdr,		},
-	{ "ctrl",	do_ctrl		},
-	{ "register",	do_register	}
-};
+			     {
+				     "dup",
+				     do_dup,
+			     },
+			     {
+				     "mmap",
+				     do_mmap,
+			     },
+			     {
+				     "anon-mmap",
+				     do_anon_mmap,
+			     },
+			     {
+				     "rd",
+				     do_rd,
+			     },
+			     {
+				     "wr",
+				     do_wr,
+			     },
+			     {
+				     "munmap",
+				     do_munmap,
+			     },
+			     {
+				     "poll",
+				     do_poll,
+			     },
+			     {
+				     "expr",
+				     do_expr,
+			     },
+			     {
+				     "echo",
+				     do_echo,
+			     },
+			     {
+				     "vars",
+				     do_vars,
+			     },
+			     {
+				     "if",
+				     do_if,
+			     },
+			     {
+				     "ring",
+				     do_ring,
+			     },
+			     {
+				     "slot",
+				     do_slot,
+			     },
+			     {
+				     "buf",
+				     do_buf,
+			     },
+			     {
+				     "nmr-legacy",
+				     do_nmr_legacy,
+			     },
+			     {
+				     "hdr",
+				     do_hdr,
+			     },
+			     {"ctrl", do_ctrl},
+			     {"register", do_register}};
 
 const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);
 
-int find_command(const char* cmd)
+int
+find_command(const char *cmd)
 {
 	return _find_command(commands, N_CMDS, cmd);
 }
 
 #define MAX_CHAN 10
 
-void prompt(FILE *f)
+void
+prompt(FILE *f)
 {
 	if (isatty(fileno(f))) {
 		printf("> ");
@@ -1932,18 +1993,18 @@ void prompt(FILE *f)
 
 struct chan *channels[MAX_CHAN];
 
-void*
+void *
 thread_cmd_loop(void *arg)
 {
 	char buf[1024];
-	FILE *in = (FILE*)arg;
+	FILE *in = (FILE *)arg;
 
 	while (fgets(buf, 1024, in)) {
 		char *cmd;
 		int i;
 
 		cmd = firstarg(buf);
-		i = find_command(cmd);
+		i   = find_command(cmd);
 		if (i < N_CMDS) {
 			commands[i].f();
 			continue;
@@ -1954,7 +2015,8 @@ thread_cmd_loop(void *arg)
 	return NULL;
 }
 
-void do_exit()
+void
+do_exit()
 {
 	output("quit");
 }
@@ -1989,16 +2051,17 @@ cmd_loop(FILE *input)
 		}
 
 		if (strcmp(cmd, "fork") == 0) {
-			int slot = chan_search_free(channels, MAX_CHAN);
+			int slot       = chan_search_free(channels, MAX_CHAN);
 			struct chan *c = NULL;
 			pid_t pid;
-			int p1[2] = { -1, -1};
+			int p1[2] = {-1, -1};
 
 			if (slot == MAX_CHAN) {
 				output("too many channels");
 				continue;
 			}
-			c = channels[slot] = (struct chan*)malloc(sizeof(struct chan));
+			c = channels[slot] =
+				(struct chan *)malloc(sizeof(struct chan));
 			if (c == NULL) {
 				output_err(-1, "malloc");
 				continue;
@@ -2053,7 +2116,7 @@ cmd_loop(FILE *input)
 				output("invalid slot: %s", cmd);
 				continue;
 			}
-			c = channels[slot];
+			c   = channels[slot];
 			ret = kill(c->pid, SIGTERM);
 			output_err(ret, "kill(%d, SIGTERM)=%d", c->pid, ret);
 			if (ret != -1) {
@@ -2065,10 +2128,10 @@ cmd_loop(FILE *input)
 			continue;
 		}
 		if (strcmp(cmd, "thread") == 0) {
-			int slot = chan_search_free(channels, MAX_CHAN);
+			int slot       = chan_search_free(channels, MAX_CHAN);
 			struct chan *c = NULL;
 			pthread_t tid;
-			int p1[2] = { -1, -1};
+			int p1[2] = {-1, -1};
 			int ret;
 			FILE *in = NULL;
 
@@ -2076,7 +2139,8 @@ cmd_loop(FILE *input)
 				output("too many channels");
 				continue;
 			}
-			c = channels[slot] = (struct chan*)malloc(sizeof(struct chan));
+			c = channels[slot] =
+				(struct chan *)malloc(sizeof(struct chan));
 			bzero(c, sizeof(*c));
 			if (pipe(p1) < 0) {
 				output_err(-1, "pipe");
@@ -2094,7 +2158,7 @@ cmd_loop(FILE *input)
 			}
 			ret = pthread_create(&tid, NULL, thread_cmd_loop, in);
 			output_err(ret, "pthread_create() tid=%lu slot=%d",
-				(unsigned long) tid, slot);
+				   (unsigned long)tid, slot);
 			if (ret < 0)
 				goto clean2;
 			c->pid = getpid();
@@ -2125,7 +2189,7 @@ cmd_loop(FILE *input)
 			fclose(c->out);
 			ret = pthread_join(c->tid, NULL);
 			output_err(ret, "pthread_join(%lu)=%d",
-				(unsigned long) c->tid, ret);
+				   (unsigned long)c->tid, ret);
 			if (ret > 0) {
 				free(c);
 				channels[slot] = NULL;
@@ -2163,7 +2227,7 @@ main(int argc, char **argv)
 	if (argc > 1) {
 		for (i = 1; i < argc; i++) {
 			FILE *f;
-		       	if (!strcmp(argv[i], "-")) {
+			if (!strcmp(argv[i], "-")) {
 				f = stdin;
 			} else {
 				f = fopen(argv[i], "r");

From 3b28add60712cf731d69bfa0f7ebd0cbc896ba43 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:30:25 +0100
Subject: [PATCH 0705/2207] pipes: fix integration test #12

---
 sys/dev/netmap/netmap_pipe.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 1b7c84478..a0ad22c28 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -566,6 +566,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		return EINVAL;
 	}
 
+	if (req->nr_mode != NR_REG_ALL_NIC) {
+		/* For pipes we currently accept only NR_REG_ALL_NIC. */
+		return EINVAL;
+	}
+
 	/* first, try to find the parent adapter */
 	for (;;) {
 		char nr_name_orig[NETMAP_REQ_IFNAMSIZ];

From 7e6617e6f90c26b6d7576f68f66fe1ff019dc5dc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:52:06 +0100
Subject: [PATCH 0706/2207] pipes: accept NR_REG_ONE_NIC but don't accept modes
 involving sw rings

---
 sys/dev/netmap/netmap_pipe.c | 4 ++--
 utils/ctrl-api-test.c        | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index a0ad22c28..6270d692b 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -566,8 +566,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		return EINVAL;
 	}
 
-	if (req->nr_mode != NR_REG_ALL_NIC) {
-		/* For pipes we currently accept only NR_REG_ALL_NIC. */
+	if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) {
+		/* We only accept modes involving hardware rings. */
 		return EINVAL;
 	}
 
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d58f81dac..98a513b1e 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -430,10 +430,10 @@ pipe_master(int fd, struct TestContext *ctx)
 
 	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeid1");
 	ctx->ifname  = pipe_name;
-	ctx->nr_mode = NR_REG_ONE_NIC;
+	ctx->nr_mode = NR_REG_NIC_SW;
 
 	if (port_register(fd, ctx) == 0) {
-		printf("pipes should not accept NR_REG_ONE_NIC\n");
+		printf("pipes should not accept NR_REG_NIC_SW\n");
 		return -1;
 	}
 	ctx->nr_mode = NR_REG_ALL_NIC;

From bdc5f6b528c5cc0e01e5ed553160a2271ba5596c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Feb 2018 18:57:37 +0100
Subject: [PATCH 0707/2207] ci: add control api tests

---
 ci/run-integration-tests | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 3d51146fb..6357471e8 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -1,6 +1,16 @@
 #!/bin/bash -eu
 
 sudo modprobe netmap
+
+# Run control API tests
+pushd .
+cd utils
+make
+sudo ./ctrl-api-test
+popd
+
+# Transmit some packets into VALE ports or pipes, using pkt-gen
 sudo pkt-gen -i vale:x -f tx -n 100 -w0
 sudo pkt-gen -i netmap:pipe{3 -f tx -n 65 -w0
+
 sudo rmmod netmap

From 0dfc0156f5164d15c85392786a98f46abdc67ce9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 22 Feb 2018 17:23:08 +0100
Subject: [PATCH 0708/2207] linux/configure: also build utils

---
 LINUX/configure     | 20 ++++++++++++++++----
 LINUX/netmap.mak.in | 23 ++++++++++++++++++++---
 2 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 511682217..eaa710797 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -4,6 +4,7 @@ BUILDDIR=$PWD
 SRCDIR=$(cd $(dirname $0); pwd)
 MODNAME=netmap
 DEBUG=1
+UTILS=
 
 # setelem2n  
 setelem2n()
@@ -262,6 +263,7 @@ replace_vars()
 		-e "s|@PREFIX@|$prefix|g" \
 		-e "s|@DESTDIR@|$DESTDIR|g" \
 		-e "s|@DEBUG@|$DEBUG|g" \
+		-e "s|@UTILS@|$UTILS|g" \
 		$1
 }
 
@@ -289,6 +291,7 @@ Available options:
   --no-apps	               do not compile any app
   --no-apps=                   do not compile the given apps (comma sep.)
   --apps=                      only compile the given apps (comma sep.)
+  --utils		       also compile the utils
   --mod-name=		       netmap module name [$MODNAME]
   --enable-vale      	       enable the VALE switch
   --disable-vale      	       disable the VALE switch
@@ -312,10 +315,10 @@ Available options:
   --no-force-debug	       build the modules w/ or w/o debug symbols,
   --cache=		       dir for reusing/caching of netmap_linux_config.h
 
-  --cc=                        C compiler to be used for the apps [$cc]
-  --ld=                        linker to be used for the apps [$ld]
-  --prefix=                    install path for the apps [$prefix]
-  --destdir=                    destination dir for the apps [$DESTDIR]
+  --cc=                        C compiler to be used for the apps and utils [$cc]
+  --ld=                        linker to be used for the apps and utils [$ld]
+  --prefix=                    install path for the apps and utils [$prefix]
+  --destdir=                   destination dir for the apps and utils [$DESTDIR]
 
   --show-drivers	       print the list of available drivers and exit
   --show-ext-drivers	       print the list of available external drivers and exit
@@ -619,6 +622,9 @@ for opt do
 	--no-force-debug)
 		DEBUG=
 	;;
+	--utils)
+		UTILS=1
+		;;
 	*)
 		echo "Unrecognized option: $opt" | warning
 	;;
@@ -1883,6 +1889,12 @@ for a in $(app print); do
 	ln -s $SRCDIR/../apps/$a/GNUmakefile build-apps/$a/GNUmakefile 2> /dev/null || true
 done
 
+# create the build directory for the utils
+if [ -n "$UTILS" ]; then
+	mkdir -p build-utils
+	ln -s $SRCDIR/../utils/GNUmakefile build-utils/GNUmakefile 2>/dev/null || true
+fi
+
 # config.status can be used to rerun configure with the
 # same arguments
 rm -f config.status
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 4e2a5b30f..5b8921636 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -33,6 +33,7 @@ PATCHES = @PATCHES@
 S_DRIVERS = @S_DRIVERS@
 E_DRIVERS = @E_DRIVERS@
 DRVSUFFIX = @DRVSUFFIX@
+UTILS = @UTILS@
 
 ifeq (,$(DRVSUFFIX))
 else
@@ -71,7 +72,7 @@ endef
 .PHONY: $(foreach d,$(E_DRIVERS),build-$(d) clean-$(1) install-$(1)) netmap.ko
 
 
-all: $(S_DRIVERS:%=get-%) netmap.ko $(E_DRIVERS:%=build-%) apps
+all: $(S_DRIVERS:%=get-%) netmap.ko $(E_DRIVERS:%=build-%) apps utils
 
 netmap.ko:
 	$(MAKE) $(COMMON_OPTS) CONFIG_NETMAP=m $(MOD_LIST) O_DRIVERS="$(patsubst %.c,%.o,$(filter-out $(DRIVERS_EXT),$(DRIVERS)))" NETMAP_DRIVER_SUFFIX=$(DRVSUFFIX)
@@ -85,7 +86,7 @@ $(foreach d,$(S_DRIVERS),$(eval $(call common_driver,$(d))))
 $(foreach d,$(E_DRIVERS),$(eval $(call external_driver,$(d))))
 
 .PHONY: install install-netmap install-apps install-headers install-docs
-install: install-netmap $(E_DRIVERS:%=install-%) install-apps install-headers install-docs
+install: install-netmap $(E_DRIVERS:%=install-%) install-apps install-headers install-docs install-utils
 
 install-netmap:
 	$(MAKE) -C $(KSRC) M=$(BUILDDIR) CONFIG_NETMAP=m $(MOD_LIST) \
@@ -95,7 +96,7 @@ install-netmap:
 		$(if $(MODPATH),INSTALL_MOD_PATH=$(MODPATH)) \
 		modules_install
 
-clean: $(E_DRIVERS:%=clean-%) clean-apps
+clean: $(E_DRIVERS:%=clean-%) clean-apps clean-utils
 	-@ $(MAKE) -C $(KSRC) M=$(BUILDDIR) clean 2> /dev/null
 
 APPS_LIST=@APPS_LIST@
@@ -127,6 +128,21 @@ $(foreach a,$(APPS_LIST),$(eval $(call apps_actions,$(a))))
 +%:
 	@echo $($*)
 
+ifeq (,$(UTILS))
+utils:
+install-utils:
+clean-utils:
+else
+utils:
+	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)"
+
+install-utils:
+	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
+
+clean-utils:
+	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/..
+endif
+
 INCLUDE_PREFIX := $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)
 
 install-headers:
@@ -150,6 +166,7 @@ distclean: clean $(S_DRIVERS:%=distclean-%)
 	if [ -L drv-subdir.mak ]; then rm drv-subdir.mak; fi
 	if [ -L read-vars.mak ]; then rm read-vars.mak; fi
 	rm -rf build-apps
+	rm -rf build-utils
 
 format:
 	clang-format -i -style=file $(shell git ls-files "utils/*.[ch]" "apps/*.[ch]" "extra/*.[ch]" "LINUX/*.[ch]" "WINDOWS/*.[ch]")

From 4b155246f4ad36fa712d7f6f137de754b39b8161 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 27 Feb 2018 18:29:15 +0100
Subject: [PATCH 0709/2207] extmem: fix warning

---
 sys/dev/netmap/netmap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4ba746638..9b28fadcc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2318,7 +2318,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 #ifdef WITH_EXTMEM
-				opt = nmreq_findoption(hdr->nr_options, NETMAP_REQ_OPT_EXTMEM);
+				opt = nmreq_findoption((struct nmreq_option *)hdr->nr_options,
+						NETMAP_REQ_OPT_EXTMEM);
 				if (opt != NULL) {
 					struct nmreq_opt_extmem *e =
 						(struct nmreq_opt_extmem *)opt;

From cf9e6c7f0f7f57ad2872949caf134f84021c30dc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 15 Feb 2018 19:09:57 +0100
Subject: [PATCH 0710/2207] changed kring array to array of pointers to krings

---
 LINUX/if_e1000_netmap.h         |  6 +--
 LINUX/netmap_ptnet.c            | 12 +++---
 sys/dev/netmap/netmap.c         | 68 +++++++++++++++++++--------------
 sys/dev/netmap/netmap_generic.c |  6 +--
 sys/dev/netmap/netmap_kern.h    | 23 +++++++----
 sys/dev/netmap/netmap_mem2.c    | 16 ++++----
 sys/dev/netmap/netmap_monitor.c | 14 +++----
 sys/dev/netmap/netmap_pipe.c    | 10 ++---
 sys/dev/netmap/netmap_vale.c    | 64 +++++++++++++++----------------
 9 files changed, 118 insertions(+), 101 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index f0ceb1a61..fd622653a 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -305,14 +305,14 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		rxr = &adapter->rx_ring[r];
 
 		for (i = 0; i < rxr->count; i++) {
-			si = netmap_idx_n2k(&na->rx_rings[r], i);
+			si = netmap_idx_n2k(na->rx_rings[r], i);
 			PNMB(na, slot + si, &paddr);
 			E1000_RX_DESC(*rxr, i)->buffer_addr = htole64(paddr);
 		}
 
 		rxr->next_to_use = 0;
 		/* preserve buffers already made available to clients */
-		i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]);
+		i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[0]);
 		if (i < 0) // XXX something wrong here, can it really happen ?
 			i += rxr->count;
 		wmb(); /* Force memory writes to complete */
@@ -328,7 +328,7 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		}
 
 		for (i = 0; i < na->num_tx_desc; i++) {
-			si = netmap_idx_n2k(&na->tx_rings[r], i);
+			si = netmap_idx_n2k(na->tx_rings[r], i);
 			PNMB(na, slot + si, &paddr);
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
 		}
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 59b8d928c..9c7eb58f8 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -223,7 +223,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	int f;
 
 	a.na = &pi->ptna->dr.up;
-	kring = &a.na->tx_rings[queue_idx];
+	kring = a.na->tx_rings[queue_idx];
 	a.ring = kring->ring;
 	a.lim = kring->nkr_num_slots - 1;
 
@@ -480,7 +480,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 	struct ptnet_csb_hg *pthg = pq->pthg;
 	struct ptnet_info *pi = pq->pi;
 	struct netmap_adapter *na = &pi->ptna->dr.up;
-	struct netmap_kring *kring = &na->rx_rings[pq->kring_id];
+	struct netmap_kring *kring = na->rx_rings[pq->kring_id];
 	struct netmap_ring *ring = kring->ring;
 	unsigned int const lim = kring->nkr_num_slots - 1;
 	bool have_vnet_hdr = pi->vnet_hdr_len;
@@ -1056,9 +1056,9 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
-			kring = na->tx_rings + i;
+			kring = na->tx_rings[i];
 		} else {
-			kring = na->rx_rings + i - na->num_tx_rings;
+			kring = na->rx_rings[i - na->num_tx_rings];
 		}
 		kring->rhead = kring->ring->head = ptgh->head;
 		kring->rcur = kring->ring->cur = ptgh->cur;
@@ -1163,7 +1163,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		if (native) {
 			for_rx_tx(t) {
 				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = &NMR(na, t)[i];
+					struct netmap_kring *kring = NMR(na, t)[i];
 
 					if (nm_kring_pending_on(kring)) {
 						kring->nr_mode = NKR_NETMAP_ON;
@@ -1178,7 +1178,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			nm_clear_native_flags(na);
 			for_rx_tx(t) {
 				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = &NMR(na, t)[i];
+					struct netmap_kring *kring = NMR(na, t)[i];
 
 					if (nm_kring_pending_off(kring)) {
 						kring->nr_mode = NKR_NETMAP_OFF;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9b28fadcc..faa4fb737 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -589,9 +589,9 @@ void
 netmap_set_ring(struct netmap_adapter *na, u_int ring_id, enum txrx t, int stopped)
 {
 	if (stopped)
-		netmap_disable_ring(NMR(na, t) + ring_id, stopped);
+		netmap_disable_ring(NMR(na, t)[ring_id], stopped);
 	else
-		NMR(na, t)[ring_id].nkr_stopped = 0;
+		NMR(na, t)[ring_id]->nkr_stopped = 0;
 }
 
 
@@ -825,7 +825,9 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	n[NR_TX] = na->num_tx_rings + 1;
 	n[NR_RX] = na->num_rx_rings + 1;
 
-	len = (n[NR_TX] + n[NR_RX]) * sizeof(struct netmap_kring) + tailroom;
+	len = (n[NR_TX] + n[NR_RX]) * 
+		(sizeof(struct netmap_kring) + sizeof(struct netmap_kring *))
+		+ tailroom;
 
 	na->tx_rings = nm_os_malloc((size_t)len);
 	if (na->tx_rings == NULL) {
@@ -833,6 +835,14 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 		return ENOMEM;
 	}
 	na->rx_rings = na->tx_rings + n[NR_TX];
+	na->tailroom = na->rx_rings + n[NR_RX];
+ 
+	/* link the krings in the krings array */
+	kring = (struct netmap_kring *)((char *)na->tailroom + tailroom);
+	for (i = 0; i < n[NR_TX] + n[NR_RX]; i++) {
+		na->tx_rings[i] = kring;
+		kring++;
+	}
 
 	/*
 	 * All fields in krings are 0 except the one initialized below.
@@ -841,9 +851,10 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	for_rx_tx(t) {
 		ndesc = nma_get_ndesc(na, t);
 		for (i = 0; i < n[t]; i++) {
-			kring = &NMR(na, t)[i];
+			kring = NMR(na, t)[i];
 			bzero(kring, sizeof(*kring));
 			kring->na = na;
+			kring->notify_na = na;
 			kring->ring_id = i;
 			kring->tx = t;
 			kring->nkr_num_slots = ndesc;
@@ -872,7 +883,6 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 		nm_os_selinfo_init(&na->si[t]);
 	}
 
-	na->tailroom = na->rx_rings + n[NR_RX];
 
 	return 0;
 }
@@ -883,7 +893,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 void
 netmap_krings_delete(struct netmap_adapter *na)
 {
-	struct netmap_kring *kring = na->tx_rings;
+	struct netmap_kring **kring = na->tx_rings;
 	enum txrx t;
 
 	if (na->tx_rings == NULL) {
@@ -896,8 +906,8 @@ netmap_krings_delete(struct netmap_adapter *na)
 
 	/* we rely on the krings layout described above */
 	for ( ; kring != na->tailroom; kring++) {
-		mtx_destroy(&kring->q_lock);
-		nm_os_selinfo_uninit(&kring->si);
+		mtx_destroy((*kring)->q_lock);
+		nm_os_selinfo_uninit(&(*kring)->si);
 	}
 	nm_os_free(na->tx_rings);
 	na->tx_rings = na->rx_rings = na->tailroom = NULL;
@@ -913,7 +923,7 @@ netmap_krings_delete(struct netmap_adapter *na)
 void
 netmap_hw_krings_delete(struct netmap_adapter *na)
 {
-	struct mbq *q = &na->rx_rings[na->num_rx_rings].rx_queue;
+	struct mbq *q = &na->rx_rings[na->num_rx_rings]->rx_queue;
 
 	ND("destroy sw mbq with len %d", mbq_len(q));
 	mbq_purge(q);
@@ -1194,7 +1204,7 @@ nm_may_forward_down(struct netmap_kring *kring, int sync_flags)
 static u_int
 netmap_sw_to_nic(struct netmap_adapter *na)
 {
-	struct netmap_kring *kring = &na->rx_rings[na->num_rx_rings];
+	struct netmap_kring *kring = na->rx_rings[na->num_rx_rings];
 	struct netmap_slot *rxslot = kring->ring->slot;
 	u_int i, rxcur = kring->nr_hwcur;
 	u_int const head = kring->rhead;
@@ -1203,7 +1213,7 @@ netmap_sw_to_nic(struct netmap_adapter *na)
 
 	/* scan rings to find space, then fill as much as possible */
 	for (i = 0; i < na->num_tx_rings; i++) {
-		struct netmap_kring *kdst = &na->tx_rings[i];
+		struct netmap_kring *kdst = na->tx_rings[i];
 		struct netmap_ring *rdst = kdst->ring;
 		u_int const dst_lim = kdst->nkr_num_slots - 1;
 
@@ -1931,7 +1941,7 @@ netmap_krings_get(struct netmap_priv_d *priv)
 	 */
 	for_rx_tx(t) {
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = &NMR(na, t)[i];
+			kring = NMR(na, t)[i];
 			if ((kring->nr_kflags & NKR_EXCLUSIVE) ||
 			    (kring->users && excl))
 			{
@@ -1946,7 +1956,7 @@ netmap_krings_get(struct netmap_priv_d *priv)
 	 */
 	for_rx_tx(t) {
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = &NMR(na, t)[i];
+			kring = NMR(na, t)[i];
 			kring->users++;
 			if (excl)
 				kring->nr_kflags |= NKR_EXCLUSIVE;
@@ -1979,7 +1989,7 @@ netmap_krings_put(struct netmap_priv_d *priv)
 
 	for_rx_tx(t) {
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = &NMR(na, t)[i];
+			kring = NMR(na, t)[i];
 			if (excl)
 				kring->nr_kflags &= ~NKR_EXCLUSIVE;
 			kring->users--;
@@ -2267,7 +2277,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	int error = 0;
 	u_int i, qfirst, qlast;
 	struct netmap_if *nifp;
-	struct netmap_kring *krings;
+	struct netmap_kring **krings;
 	int sync_flags;
 	enum txrx t;
 
@@ -2384,7 +2394,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 				for_rx_tx(t) {
 					priv->np_si[t] = nm_si_user(priv, t) ?
-						&na->si[t] : &NMR(na, t)[priv->np_qfirst[t]].si;
+						&na->si[t] : &NMR(na, t)[priv->np_qfirst[t]]->si;
 				}
 
 				if (req->nr_extra_bufs) {
@@ -2645,7 +2655,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		sync_flags = priv->np_sync_flags;
 
 		for (i = qfirst; i < qlast; i++) {
-			struct netmap_kring *kring = krings + i;
+			struct netmap_kring *kring = krings[i];
 			struct netmap_ring *ring = kring->ring;
 
 			if (unlikely(nm_kr_tryget(kring, 1, &error))) {
@@ -3089,9 +3099,9 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 #ifdef linux
 	/* The selrecord must be unconditional on linux. */
 	nm_os_selrecord(sr, check_all_tx ?
-	    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]].si);
+	    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]]->si);
 	nm_os_selrecord(sr, check_all_rx ?
-		&na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]].si);
+		&na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]]->si);
 #endif /* linux */
 
 	/*
@@ -3111,7 +3121,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
 			int found = 0;
 
-			kring = &na->tx_rings[i];
+			kring = na->tx_rings[i];
 			ring = kring->ring;
 
 			/*
@@ -3174,7 +3184,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		for (i = priv->np_qfirst[NR_RX]; i < priv->np_qlast[NR_RX]; i++) {
 			int found = 0;
 
-			kring = &na->rx_rings[i];
+			kring = na->rx_rings[i];
 			ring = kring->ring;
 
 			if (unlikely(nm_kr_tryget(kring, 1, &revents)))
@@ -3254,7 +3264,7 @@ nma_intr_enable(struct netmap_adapter *na, int onoff)
 
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t); i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 			int on = !(kring->nr_kflags & NKR_NOINTR);
 
 			if (!!onoff != !!on) {
@@ -3290,7 +3300,7 @@ nma_intr_enable(struct netmap_adapter *na, int onoff)
 static int
 netmap_notify(struct netmap_kring *kring, int flags)
 {
-	struct netmap_adapter *na = kring->na;
+	struct netmap_adapter *na = kring->notify_na;
 	enum txrx t = kring->tx;
 
 	nm_os_selwakeup(&kring->si);
@@ -3532,7 +3542,7 @@ netmap_hw_krings_create(struct netmap_adapter *na)
 	int ret = netmap_krings_create(na, 0);
 	if (ret == 0) {
 		/* initialize the mbq for the sw rx ring */
-		mbq_safe_init(&na->rx_rings[na->num_rx_rings].rx_queue);
+		mbq_safe_init(&na->rx_rings[na->num_rx_rings]->rx_queue);
 		ND("initialized sw rx queue %d", na->num_rx_rings);
 	}
 	return ret;
@@ -3596,7 +3606,7 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	struct mbq *q;
 	int busy;
 
-	kring = &na->rx_rings[na->num_rx_rings];
+	kring = na->rx_rings[na->num_rx_rings];
 	// XXX [Linux] we do not need this lock
 	// if we follow the down/configure/up protocol -gl
 	// mtx_lock(&na->core_lock);
@@ -3611,7 +3621,7 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	if (txr >= na->num_tx_rings) {
 		txr %= na->num_tx_rings;
 	}
-	tx_kring = &NMR(na, NR_TX)[txr];
+	tx_kring = NMR(na, NR_TX)[txr];
 
 	if (tx_kring->nr_mode == NKR_NETMAP_OFF) {
 		return MBUF_TRANSMIT(na, ifp, m);
@@ -3699,7 +3709,7 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 		if (n >= na->num_tx_rings)
 			return NULL;
 
-		kring = na->tx_rings + n;
+		kring = na->tx_rings[n];
 
 		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
 			kring->nr_mode = NKR_NETMAP_OFF;
@@ -3711,7 +3721,7 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 	} else {
 		if (n >= na->num_rx_rings)
 			return NULL;
-		kring = na->rx_rings + n;
+		kring = na->rx_rings[n];
 
 		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
 			kring->nr_mode = NKR_NETMAP_OFF;
@@ -3779,7 +3789,7 @@ netmap_common_irq(struct netmap_adapter *na, u_int q, u_int *work_done)
 	if (q >= nma_get_nrings(na, t))
 		return NM_IRQ_PASS; // not a physical queue
 
-	kring = NMR(na, t) + q;
+	kring = NMR(na, t)[q];
 
 	if (kring->nr_mode == NKR_NETMAP_OFF) {
 		return NM_IRQ_PASS;
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 95f4e993f..aab0bf013 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -230,7 +230,7 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 
 
 #define for_each_kring_n(_i, _k, _karr, _n) \
-	for (_k=_karr, _i = 0; _i < _n; (_k)++, (_i)++)
+	for ((_k)=*(_karr), (_i) = 0; (_i) < (_n); (_i)++, (_k) = (_karr)[(_i)])
 
 #define for_each_tx_kring(_i, _k, _na) \
             for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings)
@@ -587,7 +587,7 @@ generic_mbuf_destructor(struct mbuf *m)
         for (;;) {
 		bool match = false;
 
-		kring = &na->tx_rings[r];
+		kring = na->tx_rings[r];
 		mtx_lock_spin(&kring->tx_event_lock);
 		if (kring->tx_event == m) {
 			kring->tx_event = NULL;
@@ -951,7 +951,7 @@ generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
 		r = r % na->num_rx_rings;
 	}
 
-	kring = &na->rx_rings[r];
+	kring = na->rx_rings[r];
 
 	if (kring->nr_mode == NKR_NETMAP_OFF) {
 		/* We must not intercept this mbuf. */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 1af68fde6..56009eee0 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -448,7 +448,14 @@ struct netmap_kring {
 	NM_LOCK_T	q_lock;		/* protects kring and ring. */
 	NM_ATOMIC_T	nr_busy;	/* prevent concurrent syscalls */
 
+	/* the adapter the owns this kring */
 	struct netmap_adapter *na;
+	
+	/* the adapter that wants to be notified when this kring has
+	 * new slots avaialable. This is usually the same as the above,
+	 * but wrappers may let it point to themselves
+	 */
+	struct netmap_adapter *notify_na;
 
 	/* The following fields are for VALE switch support */
 	struct nm_bdg_fwd *nkr_ft;
@@ -688,8 +695,8 @@ struct netmap_adapter {
 	 * as a contiguous chunk of memory. Each array has
 	 * N+1 entries, for the adapter queues and for the host queue.
 	 */
-	struct netmap_kring *tx_rings; /* array of TX rings. */
-	struct netmap_kring *rx_rings; /* array of RX rings. */
+	struct netmap_kring **tx_rings; /* array of TX rings. */
+	struct netmap_kring **rx_rings; /* array of RX rings. */
 
 	void *tailroom;		       /* space below the rings array */
 				       /* (used for leases) */
@@ -854,7 +861,7 @@ nma_set_nrings(struct netmap_adapter *na, enum txrx t, u_int v)
 		na->num_rx_rings = v;
 }
 
-static __inline struct netmap_kring*
+static __inline struct netmap_kring**
 NMR(struct netmap_adapter *na, enum txrx t)
 {
 	return (t == NR_TX ? na->tx_rings : na->rx_rings);
@@ -1260,10 +1267,10 @@ static inline void
 nm_update_hostrings_mode(struct netmap_adapter *na)
 {
 	/* Process nr_mode and nr_pending_mode for host rings. */
-	na->tx_rings[na->num_tx_rings].nr_mode =
-		na->tx_rings[na->num_tx_rings].nr_pending_mode;
-	na->rx_rings[na->num_rx_rings].nr_mode =
-		na->rx_rings[na->num_rx_rings].nr_pending_mode;
+	na->tx_rings[na->num_tx_rings]->nr_mode =
+		na->tx_rings[na->num_tx_rings]->nr_pending_mode;
+	na->rx_rings[na->num_rx_rings]->nr_mode =
+		na->rx_rings[na->num_rx_rings]->nr_pending_mode;
 }
 
 /* set/clear native flags and if_transmit/netdev_ops */
@@ -1879,7 +1886,7 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
 
 	for_rx_tx(t) {
 		for (i = np->np_qfirst[t]; i < np->np_qlast[t]; i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 			if (kring->nr_mode != kring->nr_pending_mode) {
 				return 1;
 			}
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index ed5b0c5db..94ac65338 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1794,7 +1794,7 @@ netmap_free_rings(struct netmap_adapter *na)
 	for_rx_tx(t) {
 		u_int i;
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_ring *ring = kring->ring;
 
 			if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) {
@@ -1831,7 +1831,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 		u_int i;
 
 		for (i = 0; i <= nma_get_nrings(na, t); i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_ring *ring = kring->ring;
 			u_int len, ndesc;
 
@@ -1961,10 +1961,10 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 		 * ring, like we do for buffers? */
 		ssize_t ofs = 0;
 
-		if (na->tx_rings[i].ring != NULL && i >= priv->np_qfirst[NR_TX]
+		if (na->tx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_TX]
 				&& i < priv->np_qlast[NR_TX]) {
 			ofs = netmap_ring_offset(na->nm_mem,
-						 na->tx_rings[i].ring) - base;
+						 na->tx_rings[i]->ring) - base;
 		}
 		*(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = ofs;
 	}
@@ -1973,10 +1973,10 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 		 * ring, like we do for buffers? */
 		ssize_t ofs = 0;
 
-		if (na->rx_rings[i].ring != NULL && i >= priv->np_qfirst[NR_RX]
+		if (na->rx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_RX]
 				&& i < priv->np_qlast[NR_RX]) {
 			ofs = netmap_ring_offset(na->nm_mem,
-						 na->rx_rings[i].ring) - base;
+						 na->rx_rings[i]->ring) - base;
 		}
 		*(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = ofs;
 	}
@@ -2621,14 +2621,14 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 	/* point each kring to the corresponding backend ring */
 	nifp = (struct netmap_if *)((char *)ptnmd->nm_addr + ptif->nifp_offset);
 	for (i = 0; i <= na->num_tx_rings; i++) {
-		struct netmap_kring *kring = na->tx_rings + i;
+		struct netmap_kring *kring = na->tx_rings[i];
 		if (kring->ring)
 			continue;
 		kring->ring = (struct netmap_ring *)
 			((char *)nifp + nifp->ring_ofs[i]);
 	}
 	for (i = 0; i <= na->num_rx_rings; i++) {
-		struct netmap_kring *kring = na->rx_rings + i;
+		struct netmap_kring *kring = na->rx_rings[i];
 		if (kring->ring)
 			continue;
 		kring->ring = (struct netmap_ring *)
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index ed8218bd2..9e96e25e6 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -167,8 +167,8 @@ netmap_monitor_krings_create(struct netmap_adapter *na)
 	if (error)
 		return error;
 	/* override the host rings callbacks */
-	na->tx_rings[na->num_tx_rings].nm_sync = netmap_monitor_txsync;
-	na->rx_rings[na->num_rx_rings].nm_sync = netmap_monitor_rxsync;
+	na->tx_rings[na->num_tx_rings]->nm_sync = netmap_monitor_txsync;
+	na->rx_rings[na->num_rx_rings]->nm_sync = netmap_monitor_rxsync;
 	return 0;
 }
 
@@ -390,7 +390,7 @@ netmap_monitor_stop(struct netmap_adapter *na)
 		u_int i;
 
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_kring *zkring;
 			u_int j;
 
@@ -456,7 +456,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 		}
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				mkring = &NMR(na, t)[i];
+				mkring = NMR(na, t)[i];
 				if (!nm_kring_pending_on(mkring))
 					continue;
 				mkring->nr_mode = NKR_NETMAP_ON;
@@ -466,7 +466,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 					if (i > nma_get_nrings(pna, s))
 						continue;
 					if (mna->flags & nm_txrx2flag(s)) {
-						kring = &NMR(pna, s)[i];
+						kring = NMR(pna, s)[i];
 						netmap_monitor_add(mkring, kring, zmon);
 					}
 				}
@@ -478,7 +478,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				mkring = &NMR(na, t)[i];
+				mkring = NMR(na, t)[i];
 				if (!nm_kring_pending_off(mkring))
 					continue;
 				mkring->nr_mode = NKR_NETMAP_OFF;
@@ -494,7 +494,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 					if (i > nma_get_nrings(pna, s))
 						continue;
 					if (mna->flags & nm_txrx2flag(s)) {
-						kring = &NMR(pna, s)[i];
+						kring = NMR(pna, s)[i];
 						netmap_monitor_del(mkring, kring);
 					}
 				}
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 6270d692b..29bd5f4f1 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -339,8 +339,8 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
 		for_rx_tx(t) {
 			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				NMR(na, t)[i].pipe = NMR(ona, r) + i;
-				NMR(ona, r)[i].pipe = NMR(na, t) + i;
+				NMR(na, t)[i]->pipe = NMR(ona, r)[i];
+				NMR(ona, r)[i]->pipe = NMR(na, t)[i];
 			}
 		}
 
@@ -399,7 +399,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 	if (onoff) {
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring)) {
 					/* mark the peer ring as needed */
@@ -416,7 +416,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 		/* In case of no error we put our rings in netmap mode */
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring)) {
 					kring->nr_mode = NKR_NETMAP_ON;
@@ -430,7 +430,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring)) {
 					kring->nr_mode = NKR_NETMAP_OFF;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 0419fecb4..c63fa22fc 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -392,15 +392,15 @@ static void
 nm_free_bdgfwd(struct netmap_adapter *na)
 {
 	int nrings, i;
-	struct netmap_kring *kring;
+	struct netmap_kring **kring;
 
 	NMG_LOCK_ASSERT();
 	nrings = na->num_tx_rings;
 	kring = na->tx_rings;
 	for (i = 0; i < nrings; i++) {
-		if (kring[i].nkr_ft) {
-			nm_os_free(kring[i].nkr_ft);
-			kring[i].nkr_ft = NULL; /* protect from freeing twice */
+		if (kring[i]->nkr_ft) {
+			nm_os_free(kring[i]->nkr_ft);
+			kring[i]->nkr_ft = NULL; /* protect from freeing twice */
 		}
 	}
 }
@@ -413,7 +413,7 @@ static int
 nm_alloc_bdgfwd(struct netmap_adapter *na)
 {
 	int nrings, l, i, num_dstq;
-	struct netmap_kring *kring;
+	struct netmap_kring **kring;
 
 	NMG_LOCK_ASSERT();
 	/* all port:rings + broadcast */
@@ -439,7 +439,7 @@ nm_alloc_bdgfwd(struct netmap_adapter *na)
 			dstq[j].bq_head = dstq[j].bq_tail = NM_FT_NULL;
 			dstq[j].bq_len = 0;
 		}
-		kring[i].nkr_ft = ft;
+		kring[i]->nkr_ft = ft;
 	}
 	return 0;
 }
@@ -990,7 +990,7 @@ netmap_bwrap_polling(void *data, int is_kthread)
 	struct nm_bdg_kthread *nbk = data;
 	struct netmap_bwrap_adapter *bna;
 	u_int qfirst, qlast, i;
-	struct netmap_kring *kring0, *kring;
+	struct netmap_kring **kring0, *kring;
 
 	if (!nbk)
 		return;
@@ -1000,7 +1000,7 @@ netmap_bwrap_polling(void *data, int is_kthread)
 	kring0 = NMR(bna->hwna, NR_RX);
 
 	for (i = qfirst; i < qlast; i++) {
-		kring = kring0 + i;
+		kring = kring0[i];
 		kring->nm_notify(kring, 0);
 	}
 }
@@ -1409,7 +1409,7 @@ netmap_vp_krings_create(struct netmap_adapter *na)
 	leases = na->tailroom;
 
 	for (i = 0; i < nrx; i++) { /* Receive rings */
-		na->rx_rings[i].nkr_leases = leases;
+		na->rx_rings[i]->nkr_leases = leases;
 		leases += na->num_rx_desc;
 	}
 
@@ -1579,7 +1579,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 	if (onoff) {
 		for_rx_tx(t) {
 			for (i = 0; i < netmap_real_rings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring))
 					kring->nr_mode = NKR_NETMAP_ON;
@@ -1595,7 +1595,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {
 			for (i = 0; i < netmap_real_rings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring))
 					kring->nr_mode = NKR_NETMAP_OFF;
@@ -1913,7 +1913,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		nrings = dst_na->up.num_rx_rings;
 		if (dst_nr >= nrings)
 			dst_nr = dst_nr % nrings;
-		kring = &dst_na->up.rx_rings[dst_nr];
+		kring = dst_na->up.rx_rings[dst_nr];
 		ring = kring->ring;
 		/* the destination ring may have not been opened for RX */
 		if (unlikely(ring == NULL || kring->nr_mode != NKR_NETMAP_ON))
@@ -2391,7 +2391,7 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 	if (netmap_verbose)
 	    D("%s %s 0x%x", na->name, kring->name, flags);
 
-	bkring = &vpna->up.tx_rings[ring_nr];
+	bkring = vpna->up.tx_rings[ring_nr];
 
 	/* make sure the ring is not disabled */
 	if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) {
@@ -2474,8 +2474,8 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 	/* pass down the pending ring state information */
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++)
-			NMR(hwna, t)[i].nr_pending_mode =
-				NMR(na, t)[i].nr_pending_mode;
+			NMR(hwna, t)[i]->nr_pending_mode =
+				NMR(na, t)[i]->nr_pending_mode;
 	}
 
 	/* forward the request to the hwna */
@@ -2486,8 +2486,8 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 	/* copy up the current ring state information */
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = &NMR(hwna, t)[i];
-			NMR(na, t)[i].nr_mode = kring->nr_mode;
+			struct netmap_kring *kring = NMR(hwna, t)[i];
+			NMR(na, t)[i]->nr_mode = kring->nr_mode;
 		}
 	}
 
@@ -2500,15 +2500,15 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		u_int i;
 		/* intercept the hwna nm_nofify callback on the hw rings */
 		for (i = 0; i < hwna->num_rx_rings; i++) {
-			hwna->rx_rings[i].save_notify = hwna->rx_rings[i].nm_notify;
-			hwna->rx_rings[i].nm_notify = netmap_bwrap_intr_notify;
+			hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
+			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
 		}
 		i = hwna->num_rx_rings; /* for safety */
 		/* save the host ring notify unconditionally */
-		hwna->rx_rings[i].save_notify = hwna->rx_rings[i].nm_notify;
+		hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
 		if (hostna->na_bdg) {
 			/* also intercept the host ring notify */
-			hwna->rx_rings[i].nm_notify = netmap_bwrap_intr_notify;
+			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
 		}
 		if (na->active_fds == 0)
 			na->na_flags |= NAF_NETMAP_ON;
@@ -2520,8 +2520,8 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 
 		/* reset all notify callbacks (including host ring) */
 		for (i = 0; i <= hwna->num_rx_rings; i++) {
-			hwna->rx_rings[i].nm_notify = hwna->rx_rings[i].save_notify;
-			hwna->rx_rings[i].save_notify = NULL;
+			hwna->rx_rings[i]->nm_notify = hwna->rx_rings[i]->save_notify;
+			hwna->rx_rings[i]->save_notify = NULL;
 		}
 		hwna->na_lut.lut = NULL;
 		hwna->na_lut.plut = NULL;
@@ -2531,7 +2531,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		/* pass ownership of the netmap rings to the hwna */
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				NMR(na, t)[i].ring = NULL;
+				NMR(na, t)[i]->ring = NULL;
 			}
 		}
 
@@ -2588,7 +2588,7 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	/* increment the usage counter for all the hwna krings */
         for_rx_tx(t) {
                 for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
-			NMR(hwna, t)[i].users++;
+			NMR(hwna, t)[i]->users++;
 		}
         }
 
@@ -2605,8 +2605,8 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
         for_rx_tx(t) {
                 enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
                 for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
-                        NMR(na, t)[i].nkr_num_slots = NMR(hwna, r)[i].nkr_num_slots;
-                        NMR(na, t)[i].ring = NMR(hwna, r)[i].ring;
+                        NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
+                        NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
                 }
         }
 
@@ -2616,16 +2616,16 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 		 * hostna
 		 */
 		hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
-		hostna->tx_rings[0].na = hostna;
+		hostna->tx_rings[0]->na = hostna;
 		hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
-		hostna->rx_rings[0].na = hostna;
+		hostna->rx_rings[0]->na = hostna;
 	}
 
 	return 0;
 
 err_dec_users:
         for_rx_tx(t) {
-		NMR(hwna, t)[i].users--;
+		NMR(hwna, t)[i]->users--;
         }
 	hwna->nm_krings_delete(hwna);
 err_del_vp_rings:
@@ -2649,7 +2649,7 @@ netmap_bwrap_krings_delete(struct netmap_adapter *na)
 	/* decrement the usage counter for all the hwna krings */
         for_rx_tx(t) {
                 for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
-			NMR(hwna, t)[i].users--;
+			NMR(hwna, t)[i]->users--;
 		}
         }
 
@@ -2676,7 +2676,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 			(kring ? kring->name : "NULL!"),
 			(na ? na->name : "NULL!"),
 			(hwna ? hwna->name : "NULL!"));
-	hw_kring = &hwna->tx_rings[ring_n];
+	hw_kring = hwna->tx_rings[ring_n];
 
 	if (nm_kr_tryget(hw_kring, 0, NULL)) {
 		return ENXIO;

From ba05b8a17668f075b17915cd6d6d989faf45bf33 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Mar 2018 13:39:35 +0100
Subject: [PATCH 0711/2207] utils: fix compilation of functional

---
 utils/functional.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/functional.c b/utils/functional.c
index e87b9d0d5..577c55347 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -27,7 +27,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -37,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 #define NETMAP_WITH_LIBS
 #include 
 

From 288ea650ddcf53978c637eae17f46b8c77424e27 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Mar 2018 13:42:50 +0100
Subject: [PATCH 0712/2207] utils: fix compilation of ctrl-api-test

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 98a513b1e..fdc4a3b54 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -672,7 +672,7 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	int ret;
 
 	e	   = (struct nmreq_opt_extmem *)ctx->nr_opt;
-	ctx->nr_opt = ctx->nr_opt->nro_next;
+	ctx->nr_opt = (struct nmreq_option *)ctx->nr_opt->nro_next;
 
 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
 		return ret;

From 955bd42fad7b025c447d25afffb02d78af010fd2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Mar 2018 15:54:49 +0100
Subject: [PATCH 0713/2207] ctrl-test-api: improve output

---
 utils/ctrl-api-test.c | 50 +++++++++++++++++++++++++------------------
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fdc4a3b54..86fe88a48 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -784,26 +784,33 @@ usage(const char *prog)
 	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
 }
 
-static testfunc_t tests[] = {
-	port_info_get,
-	port_register_hwall_host,
-	port_register_hwall,
-	port_register_host,
-	port_register_single_ring_couple,
-	vale_attach_detach,
-	vale_attach_detach_host_rings,
-	vale_ephemeral_port_hdr_manipulation,
-	vale_persistent_port,
-	register_and_pools_info_get,
-	pipe_master,
-	pipe_slave,
-	vale_polling_enable_disable,
-	unsupported_option,
-	infinite_options,
+struct mytest {
+	testfunc_t test;
+	const char *name;
+};
+
+#define decltest(f) 	{ .test = f, .name = #f }
+
+static struct mytest tests[] = {
+	decltest(port_info_get),
+	decltest(port_register_hwall_host),
+	decltest(port_register_hwall),
+	decltest(port_register_host),
+	decltest(port_register_single_ring_couple),
+	decltest(vale_attach_detach),
+	decltest(vale_attach_detach_host_rings),
+	decltest(vale_ephemeral_port_hdr_manipulation),
+	decltest(vale_persistent_port),
+	decltest(register_and_pools_info_get),
+	decltest(pipe_master),
+	decltest(pipe_slave),
+	decltest(vale_polling_enable_disable),
+	decltest(unsupported_option),
+	decltest(infinite_options),
 #ifdef WITH_EXTMEM
-	extmem_option,
-	bad_extmem_option,
-	duplicate_extmem_options,
+	decltest(extmem_option),
+	decltest(bad_extmem_option),
+	decltest(duplicate_extmem_options),
 #endif /* WITH_EXTMEM */
 };
 
@@ -854,18 +861,19 @@ main(int argc, char **argv)
 		if (j >= 0 && (unsigned)j != i) {
 			continue;
 		}
+		printf("==> Start of Test #%d -- %s\n", i + 1, tests[i].name);
 		fd = open("/dev/netmap", O_RDWR);
 		if (fd < 0) {
 			perror("open(/dev/netmap)");
 			return fd;
 		}
 		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
-		ret = tests[i](fd, &ctxcopy);
+		ret = tests[i].test(fd, &ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 			return ret;
 		}
-		printf("Test #%d successful\n", i + 1);
+		printf("==> Test #%d successful\n", i + 1);
 		close(fd);
 	}
 

From 8b812403a9fcd443abec65bcb519d2480711a666 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 1 Mar 2018 17:30:21 +0100
Subject: [PATCH 0714/2207] linux/configure: pass enabled subsystems to
 build-utils

---
 LINUX/netmap.mak.in   | 6 ++++--
 utils/GNUmakefile     | 1 +
 utils/ctrl-api-test.c | 8 ++++----
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 5b8921636..7e195525f 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -14,11 +14,13 @@ DEBUG:=@DEBUG@
 # The following commands are needed to build the modules as out-of-tree,
 # in fact the kernel sources path must be specified.
 
+# subsystem flags
+SUBSYS_FLAGS = $(foreach s,$(SUBSYS),-DCONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_))
 # Additional compile flags (e.g. header location)
 EXTRA_CFLAGS := -I$(BUILDDIR) -I$(SRCDIR) -I$(SRCDIR)/../sys -I$(SRCDIR)/../sys/dev -DCONFIG_NETMAP
 EXTRA_CFLAGS += -Wno-unused-but-set-variable
-EXTRA_CFLAGS += $(foreach s,$(SUBSYS),-DCONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_))
 EXTRA_CFLAGS += $(if $(DEBUG),-g)
+EXTRA_CFLAGS += $(SUBSYS_FLAGS)
 
 
 # We use KSRC for the kernel configuration and sources.
@@ -134,7 +136,7 @@ install-utils:
 clean-utils:
 else
 utils:
-	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)"
+	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)" SUBSYS_FLAGS="$(SUBSYS_FLAGS)"
 
 install-utils:
 	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 82639fcfe..6169c3488 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -14,6 +14,7 @@ CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys # -I/home/luigi/FreeBSD/head/sys -I../sys
 CFLAGS += -Wextra
+CFLAGS += $(SUBSYS_FLAGS)
 ifdef WITH_PCAP
 # do not use pcap by default, as it is not always available on linux
 LDLIBS += -lpcap
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 86fe88a48..4646d03e5 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -608,7 +608,7 @@ infinite_options(int fd, struct TestContext *ctx)
 	return checkoption(&opt, &save);
 }
 
-#ifdef WITH_EXTMEM
+#ifdef CONFIG_NETMAP_EXTMEM
 static int
 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 {
@@ -776,7 +776,7 @@ duplicate_extmem_options(int fd, struct TestContext *ctx)
 
 	return 0;
 }
-#endif /* WITH_EXTMEM */
+#endif /* CONFIG_NETMAP_EXTMEM */
 
 static void
 usage(const char *prog)
@@ -807,11 +807,11 @@ static struct mytest tests[] = {
 	decltest(vale_polling_enable_disable),
 	decltest(unsupported_option),
 	decltest(infinite_options),
-#ifdef WITH_EXTMEM
+#ifdef CONFIG_NETMAP_EXTMEM
 	decltest(extmem_option),
 	decltest(bad_extmem_option),
 	decltest(duplicate_extmem_options),
-#endif /* WITH_EXTMEM */
+#endif /* CONFIG_NETMAP_EXTMEM */
 };
 
 int

From 4912901966a0f5afd0b74b21fed2c5fd60474789 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 1 Mar 2018 19:27:19 +0100
Subject: [PATCH 0715/2207] continuous integration: build drivers using various
 combinations

Intel drivers can be built either using vanilla sources or
external sources.
---
 ci/build-linux | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index c1f505d1c..71d0b8d5d 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -42,6 +42,19 @@ make -j $PROC_COUNT ARCH=${ARCH} defconfig
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
-# Build and install
-./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --enable-ptnetmap
+# First build in-tree-only drivers
+echo "Building vanilla-only drivers"
+./configure --no-ext-drivers --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=r8169.c,virtio_net.c,forcedeth.c,veth.c,e1000,vmxnet3 --enable-ptnetmap
+make -j $PROC_COUNT
+
+# Then build external intel drivers
+make distclean
+echo "Building external intel drivers"
+./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=e1000e,igb,ixgbe,i40e
+make -j $PROC_COUNT
+
+# Then build vanilla intel drivers
+make distclean
+echo "Building vanilla intel drivers"
+./configure --no-ext-drivers --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=e1000e,igb,ixgbe,i40e
 make -j $PROC_COUNT

From 94cd31e246b3cf1ff39ffa80cbb864afd20b3233 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 2 Mar 2018 11:24:31 +0100
Subject: [PATCH 0716/2207] fix for VALE persistent ports attached to 2 bridges

---
 sys/dev/netmap/netmap_kern.h |  3 +++
 sys/dev/netmap/netmap_vale.c | 29 ++++++++++++++++++++++++++---
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index cdd5f5264..1df5d7fe4 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -678,6 +678,9 @@ struct netmap_adapter {
 #define NAF_HOST_RINGS  64	/* the adapter supports the host rings */
 #define NAF_FORCE_NATIVE 128	/* the adapter is always NATIVE */
 #define NAF_PTNETMAP_HOST 256	/* the adapter supports ptnetmap in the host */
+#define NAF_VP_DOUBLE_ATTACH 512 /* the adapter is a VALE persistent port which
+				  * has been attached to 2 bridges
+				  */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
 				  * cannot be registered from userspace
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 2332b8597..b6128cc57 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1109,6 +1109,13 @@ nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
 	}
 
 	vpna = (struct netmap_vp_adapter *)na;
+	if (na->na_vp != vpna) {
+		/* trying to detach first attach of VALE persistent port attached
+		 * to 2 bridges
+		 */
+		error = EBUSY;
+		goto unlock_exit;
+	}
 	nmreq_det->port_index = vpna->bdg_port;
 
 	if (na->nm_bdg_ctl) {
@@ -2409,8 +2416,18 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 
-	if (vpna->na_bdg)
-		return netmap_bwrap_attach(name, na);
+	if (vpna->na_bdg) {
+		int error = netmap_bwrap_attach(name, na);
+		if (error == 0) {
+			/* flags the netmap_adapter of the bwrap as a second attach
+			 * of a VALE persistent port, so we can restore the na_vp
+			 * pointer of the netmap_adapter (of the first attach)
+			 * during the detach of the second
+			 */
+			na->na_vp->up.na_flags |= NAF_VP_DOUBLE_ATTACH;
+		}
+		return error;
+	}
 	na->na_vp = vpna;
 	strncpy(na->name, name, sizeof(na->name));
 	na->na_hostvp = NULL;
@@ -2562,8 +2579,14 @@ netmap_bwrap_dtor(struct netmap_adapter *na)
 	ND("na %p", na);
 	na->ifp = NULL;
 	bna->host.up.ifp = NULL;
+	if (na->na_flags & NAF_VP_DOUBLE_ATTACH) {
+		na->na_flags &= ~NAF_VP_DOUBLE_ATTACH;
+		hwna->na_vp = (struct netmap_vp_adapter *)hwna;
+	} else {
+		hwna->na_vp = NULL;
+	}
+	hwna->na_hostvp = NULL;
 	hwna->na_private = NULL;
-	hwna->na_vp = hwna->na_hostvp = NULL;
 	hwna->na_flags &= ~NAF_BUSY;
 	netmap_adapter_put(hwna);
 

From 5a6c0eb96664b19174def0eb0e4efaf5549d89fd Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 2 Mar 2018 11:38:17 +0100
Subject: [PATCH 0717/2207] added a length check inside netmap_vi_create()

---
 sys/dev/netmap/netmap_vale.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index b6128cc57..061ccd8ac 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -772,6 +772,9 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 	/* don't include VALE prefix */
 	if (!strncmp(hdr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
 		return EINVAL;
+	if (strlen(hdr->nr_name) >= IFNAMSIZ) {
+		return EINVAL;
+	}
 	ifp = ifunit_ref(hdr->nr_name);
 	if (ifp) { /* already exist, cannot create new one */
 		error = EEXIST;

From ae24a45979e31fff85abd762e26c768b9a00a75d Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 2 Mar 2018 14:19:16 +0100
Subject: [PATCH 0718/2207] changed how private data is modified

---
 sys/dev/netmap/netmap_kern.h |  6 +++---
 sys/dev/netmap/netmap_vale.c | 13 ++++++++-----
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 1df5d7fe4..ed7bcf909 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1451,7 +1451,7 @@ typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
 		struct netmap_vp_adapter *, void *private_data);
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
-typedef int (*bdg_update_private_data_fn_t)(void **private_data, void *callback_data);
+typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
 struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
@@ -1475,8 +1475,8 @@ int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
 #define NM_BDG_EXCLUSIVE	2
 int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
-int nm_bdg_update_private_data(const char *name, void *auth_token,
-	bdg_update_private_data_fn_t callback, void *callback_data);
+int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
+	void *callback_data, void *auth_token);
 int netmap_bdg_config(struct nm_ifreq *nifr);
 void *netmap_bdg_create(const char *bdg_name, int *return_status);
 int netmap_bdg_destroy(const char *bdg_name, void *auth_token);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 061ccd8ac..4aac6ffbd 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -544,8 +544,9 @@ nm_bdg_valid_auth_token(struct nm_bridge *b, void *auth_token)
 }
 
 /* Allows external modules to create bridges in exclusive mode,
- * returns the authentication token that the external module will need
- * to provide during nm_bdg_ctl_{attach, detach}() operations.
+ * returns an authentication token that the external module will need
+ * to provide during nm_bdg_ctl_{attach, detach}(), netmap_bdg_regops(),
+ * and nm_bdg_update_private_data() operations.
  * Successfully executed if ret != NULL and *return_status == 0.
  */
 void *
@@ -1558,9 +1559,10 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *privat
  * Called without NMG_LOCK.
  */
 int
-nm_bdg_update_private_data(const char *name, void *auth_token,
-	bdg_update_private_data_fn_t callback, void *callback_data)
+nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
+	void *callback_data, void *auth_token)
 {
+	void *private_data = NULL;
 	struct nm_bridge *b;
 	int error = 0;
 
@@ -1575,7 +1577,8 @@ nm_bdg_update_private_data(const char *name, void *auth_token,
 		goto unlock_update_priv;
 	}
 	BDG_WLOCK(b);
-	error = callback((&b->private_data), callback_data);
+	private_data = callback(b->private_data, callback_data, &error);
+	b->private_data = private_data;
 	BDG_WUNLOCK(b);
 
 unlock_update_priv:

From d1df22947c509a7d2981e5bb346716c118c07cc4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Mar 2018 18:21:44 +0100
Subject: [PATCH 0719/2207] lb: fix name of pipes when input port is VALE

---
 apps/lb/lb.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 64c9bce04..541d02c2c 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -779,7 +779,9 @@ int main(int argc, char **argv)
 		int k;
 		for (k = 0; k < g->nports; ++k) {
 			struct port_des *p = &g->ports[k];
-			snprintf(p->interface, MAX_PORTNAMELEN, "netmap:%s{%d/xT@%d", g->pipename, g->first_id + k,
+			snprintf(p->interface, MAX_PORTNAMELEN, "%s%s{%d/xT@%d",
+					(strncmp(g->pipename, "vale", 4) ? "netmap:" : ""),
+					g->pipename, g->first_id + k,
 					rxport->nmd->req.nr_arg2);
 			D("opening pipe named %s", p->interface);
 

From ddbb5a06adb1ffc35c303a3add85ac7b0770b49c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Mar 2018 18:52:59 +0100
Subject: [PATCH 0720/2207] nmreplay: fix packet duplication in cons()

Whenever cons() reached the burst limit it would send all
pending packets without advancing head. This caused the
last injected packet to be sent again in the next round.

See also 46020cd4.
---
 apps/nmreplay/nmreplay.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index 01d74566c..f04389783 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -894,9 +894,7 @@ cons(void *_pa)
 	    continue;
 	}
 	/* XXX copy is inefficient but simple */
-	pending++;
-	if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0 ||
-		pending > q->burst) {
+	if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
 	    RD(1, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
 		(int)p->pktlen, (u_long)q->cons_now, (u_long)p->pt_tx,
 		(u_long)q->_head, (u_long)q->_tail, (u_long)p->next);
@@ -904,6 +902,12 @@ cons(void *_pa)
 	    pending = 0;
 	    continue;
 	}
+	pending++;
+	if (pending > q->burst) {
+	    ioctl(pa->pb->fd, NIOCTXSYNC, 0);
+	    pending = 0;
+	}
+
 	q->cons_head = p->next;
 	/* drain packets from the queue */
 	q->rx++;

From 88241cd4e1a2b17aec9d70e07f5eac6038f61d8b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Mar 2018 19:23:01 +0100
Subject: [PATCH 0721/2207] nmreplay: fix full-speed transmissions after first
 loop

---
 apps/nmreplay/nmreplay.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index f04389783..4760d1894 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -879,6 +879,7 @@ cons(void *_pa)
 	     * add to q->t0 the time for the last packet
 	     */
 	    q->t0 += last_ts;
+	    set_tns_now(&q->cons_now, q->t0);
 	    q->cons_head = 0;	//restart from beginning of the queue
 	    continue;
 	}

From 00deffe1329e019a4c9de24cd330eea3c8561fd8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 3 Mar 2018 10:45:46 +0100
Subject: [PATCH 0722/2207] linux/configure: fail and give instructions when
 leftovers are found

---
 LINUX/configure | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index e26db83cc..fb3f51c8e 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -893,6 +893,16 @@ update_drivers
 # create the config.h file
 #################################################
 
+rm -f netmap_linux_config.h
+if [ -e "$SRCDIR/netmap_linux_config.h" ]; then
+	error <
Date: Sat, 3 Mar 2018 10:46:37 +0100
Subject: [PATCH 0723/2207] ignore vmxnet3 build files

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 9a82bc100..0edc4e34a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ r8169.c
 get-drivers
 igb*/
 ixgbe*/
+vmxnet*/
 log/
 scripts/conf
 virtio_net.c

From 5763c7c409ff0f00aa08f4e837cf27089b7bc9ec Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 5 Mar 2018 16:57:33 +0100
Subject: [PATCH 0724/2207] pkt-gen: fix regression on UDP-checksum in txseq

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f51fe7288..8ce8ded73 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1952,6 +1952,7 @@ txseq_body(void *data)
 			PKT(pkt, body, targ->g->af)[2] = (sequence >> 8) & 0xff;
 			PKT(pkt, body, targ->g->af)[3] = sequence & 0xff;
 			sum = ~cksum_add(~sum, cksum_add(~t, *w));
+			memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum));
 			nm_pkt_copy(frame, p, size);
 			if (fcnt == frags) {
 				update_addresses(pkt, targ->g);
@@ -1981,7 +1982,6 @@ txseq_body(void *data)
 				budget--;
 			}
 		}
-		memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum));
 
 		ring->cur = ring->head = head;
 

From cb5274c4a24fe79df0a8b21dcc902f50dbc5e0a4 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 5 Mar 2018 17:04:51 +0100
Subject: [PATCH 0725/2207] fixed a merge error?

---
 sys/dev/netmap/netmap_mem2.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 599d41b7e..66bed977c 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -157,13 +157,6 @@ struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *,
 	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
 #endif /* WITH_EXTMEM */
 
-#ifdef WITH_EXTMEM
-struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *, int *);
-#else /* !WITH_EXTMEM */
-#define netmap_mem_ext_create(nmr, _perr) \
-	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
-#endif /* WITH_EXTMEM */
-
 #ifdef WITH_PTNETMAP_GUEST
 struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,
 					     unsigned int nifp_offset,

From 5c337b2535b6d52c02ae13e9574019dee6000a04 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 6 Mar 2018 12:46:22 +0100
Subject: [PATCH 0726/2207] mem: inizialize slot ptr on alloc

---
 sys/dev/netmap/netmap_mem2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1d8aa65f2..f865be38a 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1102,6 +1102,7 @@ netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n)
 		slot[i].buf_idx = index;
 		slot[i].len = p->_objsize;
 		slot[i].flags = 0;
+		slot[i].ptr = 0;
 	}
 
 	ND("allocated %d buffers, %d available, first at %d", n, p->objfree, pos);

From dc3eea8eda665d7b0ac411266090bfdcc11b4bcd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 6 Mar 2018 13:48:54 +0100
Subject: [PATCH 0727/2207] pipe: sligthly faster swap loop

---
 sys/dev/netmap/netmap_pipe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 3b936d96f..46c043810 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -216,10 +216,10 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 
                 /* swap the slots and report the buffer change */
                 tmp = *rs;
+		tmp.flags |= NS_BUF_CHANGED;
                 *rs = *ts;
 		rs->flags |= NS_BUF_CHANGED;
                 *ts = tmp;
-		ts->flags |= NS_BUF_CHANGED;
 
                 j = nm_next(j, lim_rx);
                 k = nm_next(k, lim_tx);

From cd48e5070d59c80c1c58a44d07055bb95a6a390d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 6 Mar 2018 14:27:37 +0100
Subject: [PATCH 0728/2207] pkt-gen: improve poll error/timeout message

---
 apps/pkt-gen/pkt-gen.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 8ce8ded73..540cf3f9c 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1584,8 +1584,8 @@ sender_body(void *data)
 		if (poll(&pfd, 1, 2000) <= 0) {
 			if (targ->cancel)
 				break;
-			D("poll error/timeout on queue %d: %s", targ->me,
-				strerror(errno));
+			D("poll error on queue %d: %s", targ->me,
+				errno ? strerror(errno) : "timeout");
 			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {
@@ -1905,8 +1905,8 @@ txseq_body(void *data)
 		if (poll(&pfd, 1, 2000) <= 0) {
 			if (targ->cancel)
 				break;
-			D("poll error/timeout on queue %d: %s", targ->me,
-				strerror(errno));
+			D("poll error on queue %d: %s", targ->me,
+				errno ? strerror(errno) : "timeout");
 			// goto quit;
 		}
 		if (pfd.revents & POLLERR) {

From 3f05ad3f543ab2086aa05225356fda202c474e39 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 6 Mar 2018 15:28:19 +0100
Subject: [PATCH 0729/2207] fixed nmreq_checkduplicate()

---
 sys/dev/netmap/netmap.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0266dbea8..ae505c5a0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2937,16 +2937,13 @@ nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
 
 int
 nmreq_checkduplicate(struct nmreq_option *opt) {
-	struct nmreq_option *scan;
 	uint16_t type = opt->nro_reqtype;
 	int dup = 0;
 
-	for (scan = (struct nmreq_option *)opt->nro_next; scan;
-		scan = nmreq_findoption((struct nmreq_option *)scan->nro_next,
-			type))
-	{
+	while ((opt = nmreq_findoption((struct nmreq_option *)opt->nro_next,
+			type))) {
 		dup++;
-		scan->nro_status = EINVAL;
+		opt->nro_status = EINVAL;
 	}
 	return (dup ? EINVAL : 0);
 }

From b4056af338d148ac7a4a222190cf963dc2ccd1a8 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 6 Mar 2018 15:42:02 +0100
Subject: [PATCH 0730/2207] Incapsulated bridge free logic inside
 netmap_bdg_free(). netmap_bdg_detach_commom() uses tmp_bdg_array_index inside
 nm_bridge instead of a temporary array allocated on the stack

---
 sys/dev/netmap/netmap_vale.c | 41 ++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3fb23cc7c..fc9feaaba 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -214,6 +214,8 @@ struct nm_bridge {
 	 * and all other remaining ports.
 	 */
 	uint32_t	bdg_port_index[NM_BDG_MAXPORTS];
+	/* used by netmap_bdg_detach_common() */
+	uint32_t	tmp_bdg_port_index[NM_BDG_MAXPORTS];
 
 	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
 
@@ -460,6 +462,21 @@ nm_alloc_bdgfwd(struct netmap_adapter *na)
 	return 0;
 }
 
+static int
+netmap_bdg_free(struct nm_bridge *b)
+{
+	if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) {
+		return EBUSY;
+	}
+
+	ND("marking bridge %s as free", b->bdg_basename);
+	nm_os_free(b->ht);
+	b->bdg_ops = NULL;
+	b->bdg_flags = 0;
+	NM_BNS_PUT(b);
+	return 0;
+}
+
 
 /* remove from bridge b the ports in slots hw and sw
  * (sw can be -1 if not needed)
@@ -469,7 +486,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 {
 	int s_hw = hw, s_sw = sw;
 	int i, lim =b->bdg_active_ports;
-	uint32_t tmp[NM_BDG_MAXPORTS];
+	uint32_t *tmp = b->tmp_bdg_port_index;
 
 	/*
 	New algorithm:
@@ -486,7 +503,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	/* make a copy of the list of active ports, update it,
 	 * and then copy back within BDG_WLOCK().
 	 */
-	memcpy(tmp, b->bdg_port_index, sizeof(tmp));
+	memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index));
 	for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) {
 		if (hw >= 0 && tmp[i] == hw) {
 			ND("detach hw %d at %d", hw, i);
@@ -515,18 +532,12 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	if (s_sw >= 0) {
 		b->bdg_ports[s_sw] = NULL;
 	}
-	memcpy(b->bdg_port_index, tmp, sizeof(tmp));
+	memcpy(b->bdg_port_index, b->tmp_bdg_port_index, sizeof(b->tmp_bdg_port_index));
 	b->bdg_active_ports = lim;
 	BDG_WUNLOCK(b);
 
 	ND("now %d active ports", lim);
-	if ((b->bdg_flags & NM_BDG_ACTIVE) + lim == 0) {
-		ND("marking bridge %s as free", b->bdg_basename);
-		nm_os_free(b->ht);
-		b->bdg_ops = NULL;
-		b->bdg_flags = 0; /* marks bridge as free */
-		NM_BNS_PUT(b);
-	}
+	netmap_bdg_free(b);
 }
 
 static inline void * 
@@ -594,7 +605,6 @@ netmap_bdg_destroy(const char *bdg_name, void *auth_token)
 		goto unlock_bdg_free;
 	}
 
-
 	if (!nm_bdg_valid_auth_token(b, auth_token)) {
 		ret = EACCES;
 		goto unlock_bdg_free;
@@ -603,13 +613,12 @@ netmap_bdg_destroy(const char *bdg_name, void *auth_token)
 		ret = EINVAL;
 		goto unlock_bdg_free;
 	}
-	if (b->bdg_active_ports != 0) {
-		ret = EINVAL;
-		goto unlock_bdg_free;
-	}
 
 	b->bdg_flags &= ~(NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE);
-	netmap_bdg_detach_common(b, -1, -1);
+	ret = netmap_bdg_free(b);
+	if (ret) {
+		b->bdg_flags |= NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE;
+	}
 
 unlock_bdg_free:
 	NMG_UNLOCK();

From a5f949b73a90a0173aacf194ff9f8775d65cb824 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 13:34:04 +0100
Subject: [PATCH 0731/2207] ptnetmap: fix compilation after indir-kring change

---
 sys/dev/netmap/netmap_mem2.h |  2 +-
 sys/dev/netmap/netmap_pt.c   | 30 +++++++++++++++---------------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 66bed977c..9ddaad58e 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -137,7 +137,7 @@ void	   netmap_mem_rings_delete(struct netmap_adapter *);
 int 	   netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *);
 int	   netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
 int	   netmap_mem_get_info(struct netmap_mem_d *, uint64_t *size,
-				u_int *memflags, uint16_t *id);
+				u_int *memflags, nm_memid_t *id);
 ssize_t    netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr);
 struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_int rxd,
 		u_int extra_bufs, u_int npipes, int* error);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index c90fec7ee..5365b123b 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -639,9 +639,9 @@ static struct netmap_kring *
 ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
 {
 	if (k < pth_na->up.num_tx_rings) {
-		return pth_na->up.tx_rings + k;
+		return pth_na->up.tx_rings[k];
 	}
-	return pth_na->up.rx_rings + k - pth_na->up.num_tx_rings;
+	return pth_na->up.rx_rings[k - pth_na->up.num_tx_rings];
 }
 
 static int
@@ -847,14 +847,14 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
     }
 
     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i].save_notify =
-        	pth_na->up.rx_rings[i].nm_notify;
-        pth_na->up.rx_rings[i].nm_notify = nm_pt_host_notify;
+        pth_na->up.rx_rings[i]->save_notify =
+        	pth_na->up.rx_rings[i]->nm_notify;
+        pth_na->up.rx_rings[i]->nm_notify = nm_pt_host_notify;
     }
     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i].save_notify =
-        	pth_na->up.tx_rings[i].nm_notify;
-        pth_na->up.tx_rings[i].nm_notify = nm_pt_host_notify;
+        pth_na->up.tx_rings[i]->save_notify =
+        	pth_na->up.tx_rings[i]->nm_notify;
+        pth_na->up.tx_rings[i]->nm_notify = nm_pt_host_notify;
     }
 
 #ifdef RATE
@@ -895,14 +895,14 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
     pth_na->parent->na_flags = pth_na->parent_na_flags;
 
     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i].nm_notify =
-        	pth_na->up.rx_rings[i].save_notify;
-        pth_na->up.rx_rings[i].save_notify = NULL;
+        pth_na->up.rx_rings[i]->nm_notify =
+        	pth_na->up.rx_rings[i]->save_notify;
+        pth_na->up.rx_rings[i]->save_notify = NULL;
     }
     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i].nm_notify =
-        	pth_na->up.tx_rings[i].save_notify;
-        pth_na->up.tx_rings[i].save_notify = NULL;
+        pth_na->up.tx_rings[i]->nm_notify =
+        	pth_na->up.tx_rings[i]->save_notify;
+        pth_na->up.tx_rings[i]->save_notify = NULL;
     }
 
     /* Destroy kernel contexts. */
@@ -1079,7 +1079,7 @@ nm_pt_host_krings_create(struct netmap_adapter *na)
 	 * host rings independently on what the regif asked for:
 	 * these rings are needed by the guest ptnetmap adapter
 	 * anyway. */
-	kring = &NMR(na, t)[nma_get_nrings(na, t)];
+	kring = NMR(na, t)[nma_get_nrings(na, t)];
 	kring->nr_kflags |= NKR_NEEDRING;
     }
 

From aa2ceb42821a06dd18582e06ac29bf371025d73b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 10:39:18 +0100
Subject: [PATCH 0732/2207] mem: remove annoying callback macros

---
 sys/dev/netmap/netmap_mem2.c | 88 ++++++++++++++++++++----------------
 1 file changed, 49 insertions(+), 39 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 94ac65338..86b96398b 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -178,56 +178,66 @@ struct netmap_mem_d {
 	char name[NM_MEM_NAMESZ];
 };
 
-/*
- * XXX need to fix the case of t0 == void
- */
-#define NMD_DEFCB(t0, name) \
-t0 \
-netmap_mem_##name(struct netmap_mem_d *nmd) \
-{ \
-	return nmd->ops->nmd_##name(nmd); \
+int
+netmap_mem_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut)
+{
+	return nmd->ops->nmd_get_lut(nmd, lut);
 }
 
-#define NMD_DEFCB1(t0, name, t1) \
-t0 \
-netmap_mem_##name(struct netmap_mem_d *nmd, t1 a1) \
-{ \
-	return nmd->ops->nmd_##name(nmd, a1); \
+int
+netmap_mem_get_info(struct netmap_mem_d *nmd, uint64_t *size,
+		u_int *memflags, nm_memid_t *memid)
+{
+	return nmd->ops->nmd_get_info(nmd, size, memflags, memid);
 }
 
-#define NMD_DEFCB3(t0, name, t1, t2, t3) \
-t0 \
-netmap_mem_##name(struct netmap_mem_d *nmd, t1 a1, t2 a2, t3 a3) \
-{ \
-	return nmd->ops->nmd_##name(nmd, a1, a2, a3); \
+vm_paddr_t
+netmap_mem_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off)
+{
+	return nmd->ops->nmd_ofstophys(nmd, off);
 }
 
-#define NMD_DEFNACB(t0, name) \
-t0 \
-netmap_mem_##name(struct netmap_adapter *na) \
-{ \
-	return na->nm_mem->ops->nmd_##name(na); \
+static int
+netmap_mem_config(struct netmap_mem_d *nmd)
+{
+	return nmd->ops->nmd_config(nmd);
 }
 
-#define NMD_DEFNACB1(t0, name, t1) \
-t0 \
-netmap_mem_##name(struct netmap_adapter *na, t1 a1) \
-{ \
-	return na->nm_mem->ops->nmd_##name(na, a1); \
+ssize_t
+netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *off)
+{
+	return nmd->ops->nmd_if_offset(nmd, off);
 }
 
-NMD_DEFCB1(int, get_lut, struct netmap_lut *);
-NMD_DEFCB3(int, get_info, uint64_t *, u_int *, uint16_t *);
-NMD_DEFCB1(vm_paddr_t, ofstophys, vm_ooffset_t);
-static int netmap_mem_config(struct netmap_mem_d *);
-NMD_DEFCB(int, config);
-NMD_DEFCB1(ssize_t, if_offset, const void *);
-NMD_DEFCB(void, delete);
+void
+netmap_mem_delete(struct netmap_mem_d *nmd)
+{
+	nmd->ops->nmd_delete(nmd);
+}
 
-NMD_DEFNACB1(struct netmap_if *, if_new, struct netmap_priv_d *);
-NMD_DEFNACB1(void, if_delete, struct netmap_if *);
-NMD_DEFNACB(int, rings_create);
-NMD_DEFNACB(void, rings_delete);
+struct netmap_if *
+netmap_mem_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
+{
+	return na->nm_mem->ops->nmd_if_new(na, priv);
+}
+
+void
+netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nif)
+{
+	na->nm_mem->ops->nmd_if_delete(na, nif);
+}
+
+int
+netmap_mem_rings_create(struct netmap_adapter *na)
+{
+	return na->nm_mem->ops->nmd_rings_create(na);
+}
+
+void
+netmap_mem_rings_delete(struct netmap_adapter *na)
+{
+	na->nm_mem->ops->nmd_rings_delete(na);
+}
 
 static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *);
 static int netmap_mem_unmap(struct netmap_obj_pool *, struct netmap_adapter *);

From 7b2e5109644cc0c5db5bcd6a2747d3337de17962 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 12:01:53 +0100
Subject: [PATCH 0733/2207] mem: unexpose internal function

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 sys/dev/netmap/netmap_mem2.h | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 86b96398b..827e2f848 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -209,7 +209,7 @@ netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *off)
 	return nmd->ops->nmd_if_offset(nmd, off);
 }
 
-void
+static void
 netmap_mem_delete(struct netmap_mem_d *nmd)
 {
 	nmd->ops->nmd_delete(nmd);
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 9ddaad58e..3fc48784d 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -141,7 +141,6 @@ int	   netmap_mem_get_info(struct netmap_mem_d *, uint64_t *size,
 ssize_t    netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr);
 struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_int rxd,
 		u_int extra_bufs, u_int npipes, int* error);
-void	   netmap_mem_delete(struct netmap_mem_d *);
 
 #define netmap_mem_get(d) __netmap_mem_get(d, __FUNCTION__, __LINE__)
 #define netmap_mem_put(d) __netmap_mem_put(d, __FUNCTION__, __LINE__)

From 75a2557028f0e5ac60bed1eb5b095353311011ec Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 12:14:43 +0100
Subject: [PATCH 0734/2207] mem: factorize locking of public callbacks

---
 sys/dev/netmap/netmap_mem2.c | 128 ++++++++++++++++++-----------------
 1 file changed, 67 insertions(+), 61 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 827e2f848..c5e48f1a8 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -130,7 +130,11 @@ struct netmap_obj_pool {
 };
 
 #define NMA_LOCK_T		NM_MTX_T
-
+#define NMA_LOCK_INIT(n)	NM_MTX_INIT((n)->nm_mtx)
+#define NMA_LOCK_DESTROY(n)	NM_MTX_DESTROY((n)->nm_mtx)
+#define NMA_LOCK(n)		NM_MTX_LOCK((n)->nm_mtx)
+#define NMA_SPINLOCK(n)         NM_MTX_SPINLOCK((n)->nm_mtx)
+#define NMA_UNLOCK(n)		NM_MTX_UNLOCK((n)->nm_mtx)
 
 struct netmap_mem_ops {
 	int (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*);
@@ -181,20 +185,45 @@ struct netmap_mem_d {
 int
 netmap_mem_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut)
 {
-	return nmd->ops->nmd_get_lut(nmd, lut);
+	int rv;
+
+	NMA_LOCK(nmd);
+	rv = nmd->ops->nmd_get_lut(nmd, lut);
+	NMA_UNLOCK(nmd);
+
+	return rv;
 }
 
 int
 netmap_mem_get_info(struct netmap_mem_d *nmd, uint64_t *size,
 		u_int *memflags, nm_memid_t *memid)
 {
-	return nmd->ops->nmd_get_info(nmd, size, memflags, memid);
+	int rv;
+
+	NMA_LOCK(nmd);
+	rv = nmd->ops->nmd_get_info(nmd, size, memflags, memid);
+	NMA_UNLOCK(nmd);
+
+	return rv;
 }
 
 vm_paddr_t
 netmap_mem_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off)
 {
-	return nmd->ops->nmd_ofstophys(nmd, off);
+	vm_paddr_t pa;
+
+#if defined(__FreeBSD__)
+	/* This function is called by netmap_dev_pager_fault(), which holds a
+	 * non-sleepable lock since FreeBSD 12. Since we cannot sleep, we
+	 * spin on the trylock. */
+	NMA_SPINLOCK(nmd);
+#else
+	NMA_LOCK(nmd);
+#endif
+	pa = nmd->ops->nmd_ofstophys(nmd, off);
+	NMA_UNLOCK(nmd);
+
+	return pa;
 }
 
 static int
@@ -206,7 +235,13 @@ netmap_mem_config(struct netmap_mem_d *nmd)
 ssize_t
 netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *off)
 {
-	return nmd->ops->nmd_if_offset(nmd, off);
+	ssize_t rv;
+
+	NMA_LOCK(nmd);
+	rv = nmd->ops->nmd_if_offset(nmd, off);
+	NMA_UNLOCK(nmd);
+
+	return rv;
 }
 
 static void
@@ -218,25 +253,47 @@ netmap_mem_delete(struct netmap_mem_d *nmd)
 struct netmap_if *
 netmap_mem_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 {
-	return na->nm_mem->ops->nmd_if_new(na, priv);
+	struct netmap_if *nifp;
+	struct netmap_mem_d *nmd = na->nm_mem;
+
+	NMA_LOCK(nmd);
+	nifp = nmd->ops->nmd_if_new(na, priv);
+	NMA_UNLOCK(nmd);
+
+	return nifp;
 }
 
 void
 netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nif)
 {
-	na->nm_mem->ops->nmd_if_delete(na, nif);
+	struct netmap_mem_d *nmd = na->nm_mem;
+
+	NMA_LOCK(nmd);
+	nmd->ops->nmd_if_delete(na, nif);
+	NMA_UNLOCK(nmd);
 }
 
 int
 netmap_mem_rings_create(struct netmap_adapter *na)
 {
-	return na->nm_mem->ops->nmd_rings_create(na);
+	int rv;
+	struct netmap_mem_d *nmd = na->nm_mem;
+
+	NMA_LOCK(nmd);
+	rv = nmd->ops->nmd_rings_create(na);
+	NMA_UNLOCK(nmd);
+
+	return rv;
 }
 
 void
 netmap_mem_rings_delete(struct netmap_adapter *na)
 {
-	na->nm_mem->ops->nmd_rings_delete(na);
+	struct netmap_mem_d *nmd = na->nm_mem;
+
+	NMA_LOCK(nmd);
+	nmd->ops->nmd_rings_delete(na);
+	NMA_UNLOCK(nmd);
 }
 
 static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *);
@@ -250,12 +307,6 @@ netmap_mem_get_id(struct netmap_mem_d *nmd)
 	return nmd->nm_id;
 }
 
-#define NMA_LOCK_INIT(n)	NM_MTX_INIT((n)->nm_mtx)
-#define NMA_LOCK_DESTROY(n)	NM_MTX_DESTROY((n)->nm_mtx)
-#define NMA_LOCK(n)		NM_MTX_LOCK((n)->nm_mtx)
-#define NMA_SPINLOCK(n)         NM_MTX_SPINLOCK((n)->nm_mtx)
-#define NMA_UNLOCK(n)		NM_MTX_UNLOCK((n)->nm_mtx)
-
 #ifdef NM_DEBUG_MEM_PUTGET
 #define NM_DBG_REFC(nmd, func, line)	\
 	nm_prinf("%s:%d mem[%d] -> %d\n", func, line, (nmd)->nm_id, (nmd)->refcount);
@@ -715,14 +766,6 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 	vm_paddr_t pa;
 	struct netmap_obj_pool *p;
 
-#if defined(__FreeBSD__)
-	/* This function is called by netmap_dev_pager_fault(), which holds a
-	 * non-sleepable lock since FreeBSD 12. Since we cannot sleep, we
-	 * spin on the trylock. */
-	NMA_SPINLOCK(nmd);
-#else
-	NMA_LOCK(nmd);
-#endif
 	p = nmd->pools;
 
 	for (i = 0; i < NETMAP_POOLS_NR; offset -= p[i].memtotal, i++) {
@@ -736,7 +779,6 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 		pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr);
 		pa.QuadPart += offset % p[i]._objsize;
 #endif
-		NMA_UNLOCK(nmd);
 		return pa;
 	}
 	/* this is only in case of errors */
@@ -747,7 +789,6 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 		p[NETMAP_IF_POOL].memtotal
 			+ p[NETMAP_RING_POOL].memtotal
 			+ p[NETMAP_BUF_POOL].memtotal);
-	NMA_UNLOCK(nmd);
 #ifndef _WIN32
 	return 0; /* bad address */
 #else
@@ -860,7 +901,6 @@ netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size,
 			u_int *memflags, nm_memid_t *id)
 {
 	int error = 0;
-	NMA_LOCK(nmd);
 	error = netmap_mem_config(nmd);
 	if (error)
 		goto out;
@@ -881,7 +921,6 @@ netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size,
 	if (id)
 		*id = nmd->nm_id;
 out:
-	NMA_UNLOCK(nmd);
 	return error;
 }
 
@@ -925,11 +964,7 @@ netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr)
 static ssize_t
 netmap_mem2_if_offset(struct netmap_mem_d *nmd, const void *addr)
 {
-	ssize_t v;
-	NMA_LOCK(nmd);
-	v = netmap_if_offset(nmd, addr);
-	NMA_UNLOCK(nmd);
-	return v;
+	return netmap_if_offset(nmd, addr);
 }
 
 /*
@@ -1835,8 +1870,6 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 {
 	enum txrx t;
 
-	NMA_LOCK(na->nm_mem);
-
 	for_rx_tx(t) {
 		u_int i;
 
@@ -1895,15 +1928,11 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 		}
 	}
 
-	NMA_UNLOCK(na->nm_mem);
-
 	return 0;
 
 cleanup:
 	netmap_free_rings(na);
 
-	NMA_UNLOCK(na->nm_mem);
-
 	return ENOMEM;
 }
 
@@ -1911,11 +1940,7 @@ static void
 netmap_mem2_rings_delete(struct netmap_adapter *na)
 {
 	/* last instance, release bufs and rings */
-	NMA_LOCK(na->nm_mem);
-
 	netmap_free_rings(na);
-
-	NMA_UNLOCK(na->nm_mem);
 }
 
 
@@ -1946,8 +1971,6 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	 * to the tx and rx rings in the shared memory region.
 	 */
 
-	NMA_LOCK(na->nm_mem);
-
 	len = sizeof(struct netmap_if) + (ntot * sizeof(ssize_t));
 	nifp = netmap_if_malloc(na->nm_mem, len);
 	if (nifp == NULL) {
@@ -1991,8 +2014,6 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 		*(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = ofs;
 	}
 
-	NMA_UNLOCK(na->nm_mem);
-
 	return (nifp);
 }
 
@@ -2002,12 +2023,9 @@ netmap_mem2_if_delete(struct netmap_adapter *na, struct netmap_if *nifp)
 	if (nifp == NULL)
 		/* nothing to do */
 		return;
-	NMA_LOCK(na->nm_mem);
 	if (nifp->ni_bufs_head)
 		netmap_extra_free(na, nifp->ni_bufs_head);
 	netmap_if_free(na->nm_mem, nifp);
-
-	NMA_UNLOCK(na->nm_mem);
 }
 
 static void
@@ -2426,8 +2444,6 @@ netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, uint64_t *size,
 {
 	int error = 0;
 
-	NMA_LOCK(nmd);
-
 	error = nmd->ops->nmd_config(nmd);
 	if (error)
 		goto out;
@@ -2440,7 +2456,6 @@ netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, uint64_t *size,
 		*id = nmd->nm_id;
 
 out:
-	NMA_UNLOCK(nmd);
 
 	return error;
 }
@@ -2583,8 +2598,6 @@ netmap_mem_pt_guest_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv
 	struct mem_pt_if *ptif;
 	struct netmap_if *nifp = NULL;
 
-	NMA_LOCK(na->nm_mem);
-
 	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
 	if (ptif == NULL) {
 		D("Error: interface %p is not in passthrough", na->ifp);
@@ -2593,7 +2606,6 @@ netmap_mem_pt_guest_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv
 
 	nifp = (struct netmap_if *)((char *)(ptnmd->nm_addr) +
 				    ptif->nifp_offset);
-	NMA_UNLOCK(na->nm_mem);
 out:
 	return nifp;
 }
@@ -2603,12 +2615,10 @@ netmap_mem_pt_guest_if_delete(struct netmap_adapter *na, struct netmap_if *nifp)
 {
 	struct mem_pt_if *ptif;
 
-	NMA_LOCK(na->nm_mem);
 	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
 	if (ptif == NULL) {
 		D("Error: interface %p is not in passthrough", na->ifp);
 	}
-	NMA_UNLOCK(na->nm_mem);
 }
 
 static int
@@ -2619,8 +2629,6 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 	struct netmap_if *nifp;
 	int i, error = -1;
 
-	NMA_LOCK(na->nm_mem);
-
 	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
 	if (ptif == NULL) {
 		D("Error: interface %p is not in passthrough", na->ifp);
@@ -2648,8 +2656,6 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 
 	error = 0;
 out:
-	NMA_UNLOCK(na->nm_mem);
-
 	return error;
 }
 

From 0f561c3da25d0b60db2dbe87b93a6adad1f75bc4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 13:53:42 +0100
Subject: [PATCH 0735/2207] mem: fix locking of netmap_mem_finalize

---
 sys/dev/netmap/netmap_mem2.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c5e48f1a8..afb81b160 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -345,22 +345,24 @@ __netmap_mem_put(struct netmap_mem_d *nmd, const char *func, int line)
 int
 netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
+	int lasterr = 0;
 	if (nm_mem_assign_group(nmd, na->pdev) < 0) {
 		return ENOMEM;
-	} else {
-		NMA_LOCK(nmd);
-		nmd->lasterr = nmd->ops->nmd_finalize(nmd);
-		NMA_UNLOCK(nmd);
 	}
 
+	NMA_LOCK(nmd);
+	nmd->lasterr = nmd->ops->nmd_finalize(nmd);
+
 	if (!nmd->lasterr && na->pdev) {
 		nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
-		if (nmd->lasterr) {
-			netmap_mem_deref(nmd, na);
-		}
 	}
+	lasterr = nmd->lasterr;
+	NMA_UNLOCK(nmd);
 
-	return nmd->lasterr;
+	if (lasterr)
+		netmap_mem_deref(nmd, na);
+
+	return lasterr;
 }
 
 static int

From 3857078fbddfc4c170aaf0fa88c04fc85e2564c1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 14:31:42 +0100
Subject: [PATCH 0736/2207] mem: factorize active counter management

---
 sys/dev/netmap/netmap_mem2.c | 59 +++++++++++++++---------------------
 1 file changed, 24 insertions(+), 35 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index afb81b160..f0bdb1e52 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -229,6 +229,13 @@ netmap_mem_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off)
 static int
 netmap_mem_config(struct netmap_mem_d *nmd)
 {
+	if (nmd->active) {
+		/* already in use. Not fatal, but we
+		 * cannot change the configuration
+		 */
+		return 0;
+	}
+
 	return nmd->ops->nmd_config(nmd);
 }
 
@@ -351,11 +358,19 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	}
 
 	NMA_LOCK(nmd);
+
+	if (netmap_mem_config(nmd))
+		goto out;
+
+	nmd->active++;
+
 	nmd->lasterr = nmd->ops->nmd_finalize(nmd);
 
 	if (!nmd->lasterr && na->pdev) {
 		nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
 	}
+
+out:
 	lasterr = nmd->lasterr;
 	NMA_UNLOCK(nmd);
 
@@ -462,6 +477,10 @@ netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	}
 	nmd->ops->nmd_deref(nmd);
 
+	nmd->active--;
+	if (!nmd->active)
+		nmd->nm_grp = -1;
+
 	NMA_UNLOCK(nmd);
 	return last_user;
 }
@@ -1734,10 +1753,6 @@ netmap_mem2_config(struct netmap_mem_d *nmd)
 {
 	int i;
 
-	if (nmd->active)
-		/* already in use, we cannot change the configuration */
-		goto out;
-
 	if (!netmap_mem_params_changed(nmd->params))
 		goto out;
 
@@ -1766,19 +1781,8 @@ netmap_mem2_config(struct netmap_mem_d *nmd)
 static int
 netmap_mem2_finalize(struct netmap_mem_d *nmd)
 {
-	int err;
-
-	/* update configuration if changed */
-	if (netmap_mem_config(nmd))
-		goto out1;
-
-	nmd->active++;
-
-	if (nmd->flags & NETMAP_MEM_FINALIZED) {
-		/* may happen if config is not changed */
-		D("nothing to do");
+	if (nmd->flags & NETMAP_MEM_FINALIZED)
 		goto out;
-	}
 
 	if (netmap_mem_finalize_all(nmd))
 		goto out;
@@ -1786,13 +1790,7 @@ netmap_mem2_finalize(struct netmap_mem_d *nmd)
 	nmd->lasterr = 0;
 
 out:
-	if (nmd->lasterr)
-		nmd->active--;
-out1:
-	err = nmd->lasterr;
-
-	return err;
-
+	return nmd->lasterr;
 }
 
 static void
@@ -2034,9 +2032,6 @@ static void
 netmap_mem2_deref(struct netmap_mem_d *nmd)
 {
 
-	nmd->active--;
-	if (!nmd->active)
-		nmd->nm_grp = -1;
 	if (netmap_verbose)
 		D("active = %d", nmd->active);
 
@@ -2495,21 +2490,19 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 	int i;
 	int error = 0;
 
-	nmd->active++;
-
 	if (nmd->flags & NETMAP_MEM_FINALIZED)
 		goto out;
 
 	if (ptnmd->ptn_dev == NULL) {
 		D("ptnetmap memdev not attached");
 		error = ENOMEM;
-		goto err;
+		goto out;
 	}
 	/* Map memory through ptnetmap-memdev BAR. */
 	error = nm_os_pt_memdev_iomap(ptnmd->ptn_dev, &ptnmd->nm_paddr,
 				      &ptnmd->nm_addr, &mem_size);
 	if (error)
-		goto err;
+		goto out;
 
         /* Initialize the lut using the information contained in the
 	 * ptnetmap memory device. */
@@ -2546,9 +2539,6 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 
 	nmd->flags |= NETMAP_MEM_FINALIZED;
 out:
-	return 0;
-err:
-	nmd->active--;
 	return error;
 }
 
@@ -2557,8 +2547,7 @@ netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd)
 {
 	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 
-	nmd->active--;
-	if (nmd->active <= 0 &&
+	if (nmd->active == 1 &&
 		(nmd->flags & NETMAP_MEM_FINALIZED)) {
 	    nmd->flags  &= ~NETMAP_MEM_FINALIZED;
 	    /* unmap ptnetmap-memdev memory */

From 7870c0516fdb0f62288005292cdc2765c9817dc9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 15:28:11 +0100
Subject: [PATCH 0737/2207] mem: introduce NKR_FAKERING flag

---
 sys/dev/netmap/netmap.c      |  2 ++
 sys/dev/netmap/netmap_kern.h |  1 +
 sys/dev/netmap/netmap_mem2.c | 10 ++++++++--
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index faa4fb737..33e2cff5f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -863,6 +863,8 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 			if (i < nma_get_nrings(na, t)) {
 				kring->nm_sync = (t == NR_TX ? na->nm_txsync : na->nm_rxsync);
 			} else {
+				if (!(na->na_flags & NAF_HOST_RINGS))
+					kring->nr_kflags |= NKR_FAKERING;
 				kring->nm_sync = (t == NR_TX ?
 						netmap_txsync_to_host:
 						netmap_rxsync_from_host);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 56009eee0..9b58b48c0 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -422,6 +422,7 @@ struct netmap_kring {
 					 *  by ptnetmap host ports)
 					 */
 #define NKR_NOINTR      0x10            /* don't use interrupts on this ring */
+#define NKR_FAKERING	0x20		/* don't allocate/free buffers */
 
 	uint32_t	nr_mode;
 	uint32_t	nr_pending_mode;
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f0bdb1e52..7bb696dcf 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1850,8 +1850,12 @@ netmap_free_rings(struct netmap_adapter *na)
 			}
 			if (netmap_verbose)
 				D("deleting ring %s", kring->name);
-			if (i != nma_get_nrings(na, t) || na->na_flags & NAF_HOST_RINGS)
+			if (!(kring->nr_kflags & NKR_FAKERING)) {
+				ND("freeing bufs for %s", kring->name);
 				netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots);
+			} else {
+				ND("NOT freeing bufs for %s", kring->name);
+			}
 			netmap_ring_free(na->nm_mem, ring);
 			kring->ring = NULL;
 		}
@@ -1912,14 +1916,16 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 			ND("%s h %d c %d t %d", kring->name,
 				ring->head, ring->cur, ring->tail);
 			ND("initializing slots for %s_ring", nm_txrx2str(txrx));
-			if (i != nma_get_nrings(na, t) || (na->na_flags & NAF_HOST_RINGS)) {
+			if (!(kring->nr_kflags & NKR_FAKERING)) {
 				/* this is a real ring */
+				ND("allocating buffers for %s", kring->name);
 				if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) {
 					D("Cannot allocate buffers for %s_ring", nm_txrx2str(t));
 					goto cleanup;
 				}
 			} else {
 				/* this is a fake ring, set all indices to 0 */
+				ND("NOT allocating buffers for %s", kring->name);
 				netmap_mem_set_ring(na->nm_mem, ring->slot, ndesc, 0);
 			}
 		        /* ring info */

From 8dfa567fa33d50b12a99dd9381e45b288fcf0b39 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 17:04:01 +0100
Subject: [PATCH 0738/2207] pipe: non-swapping transfer

This netmap pipes implementation shares the netmap buffers between
the two rings of the same transfer direction, instead of swapping
slots.

This has two benefits:

- it is faster, since there is less work to do in the fast path and,
  more importantly, because always reusing the same buffers is more
  cache/TLB friendly

- if the receiving end does not swap slots with other ports
  (e.g., it is read-only), the behaviour is now the same for pipes,
  VALE and hardware ports: when tail moves, the user can recover
  from the ring the packets she had sent.
---
 sys/dev/netmap/netmap_pipe.c | 160 ++++++++++++++++++++++-------------
 1 file changed, 102 insertions(+), 58 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 29bd5f4f1..de149db51 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -183,63 +183,46 @@ int
 netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 {
         struct netmap_kring *rxkring = txkring->pipe;
-        u_int limit; /* slots to transfer */
-        u_int j, k, lim_tx = txkring->nkr_num_slots - 1,
-                lim_rx = rxkring->nkr_num_slots - 1;
-        int m, busy;
+        u_int k, lim = txkring->nkr_num_slots - 1;
+        int m; /* slots to transfer */
 	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
         ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
-        ND(2, "before: hwcur %d hwtail %d cur %d head %d tail %d", txkring->nr_hwcur, txkring->nr_hwtail,
+        ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
+		txkring->nr_hwcur, txkring->nr_hwtail,
                 txkring->rcur, txkring->rhead, txkring->rtail);
 
-        j = rxkring->nr_hwtail; /* RX */
-        k = txkring->nr_hwcur;  /* TX */
         m = txkring->rhead - txkring->nr_hwcur; /* new slots */
         if (m < 0)
                 m += txkring->nkr_num_slots;
-        limit = m;
-        m = lim_rx; /* max avail space on destination */
-        busy = j - rxkring->nr_hwcur; /* busy slots */
-	if (busy < 0)
-		busy += rxkring->nkr_num_slots;
-	m -= busy; /* subtract busy slots */
-        ND(2, "m %d limit %d", m, limit);
-        if (m < limit)
-                limit = m;
-
-	if (limit == 0) {
-		/* either the rxring is full, or nothing to send */
+
+	if (m == 0) {
+		/* nothing to send */
 		return 0;
 	}
 
-        while (limit-- > 0) {
-                struct netmap_slot *rs = &rxring->slot[j];
+        for (k = txkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
+                struct netmap_slot *rs = &rxring->slot[k];
                 struct netmap_slot *ts = &txring->slot[k];
-                struct netmap_slot tmp;
-
-		__builtin_prefetch(ts + 1);
 
-                /* swap the slots and report the buffer change */
-                tmp = *rs;
-                *rs = *ts;
-		rs->flags |= NS_BUF_CHANGED;
-                *ts = tmp;
-		ts->flags |= NS_BUF_CHANGED;
+		rs->len = ts->len;
+		rs->ptr = ts->ptr;
 
-                j = nm_next(j, lim_rx);
-                k = nm_next(k, lim_tx);
+		if (ts->flags & NS_BUF_CHANGED) {
+			rs->buf_idx = ts->buf_idx;
+			rs->flags |= NS_BUF_CHANGED;
+			ts->flags &= ~NS_BUF_CHANGED;
+		}
         }
 
         mb(); /* make sure the slots are updated before publishing them */
-        rxkring->nr_hwtail = j;
+        rxkring->nr_hwtail = k;
         txkring->nr_hwcur = k;
-        txkring->nr_hwtail = nm_prev(k, lim_tx);
 
-        ND(2, "after: hwcur %d hwtail %d cur %d head %d tail %d j %d", txkring->nr_hwcur, txkring->nr_hwtail,
-                txkring->rcur, txkring->rhead, txkring->rtail, j);
+        ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
+		txkring->nr_hwcur, txkring->nr_hwtail,
+                txkring->rcur, txkring->rhead, txkring->rtail, k);
 
-        mb(); /* make sure rxkring->nr_hwtail is updated before notifying */
         rxkring->nm_notify(rxkring, 0);
 
 	return 0;
@@ -249,20 +232,46 @@ int
 netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 {
         struct netmap_kring *txkring = rxkring->pipe;
-	uint32_t oldhwcur = rxkring->nr_hwcur;
+        u_int k, lim = rxkring->nkr_num_slots - 1;
+        int m; /* slots to release */
+	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
-        ND("%s %x <- %s", rxkring->name, flags, txkring->name);
-        rxkring->nr_hwcur = rxkring->rhead; /* recover user-relased slots */
-        ND(5, "hwcur %d hwtail %d cur %d head %d tail %d", rxkring->nr_hwcur, rxkring->nr_hwtail,
+        ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
+        ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
+		rxkring->nr_hwcur, rxkring->nr_hwtail,
                 rxkring->rcur, rxkring->rhead, rxkring->rtail);
-        mb(); /* paired with the first mb() in txsync */
 
-	if (oldhwcur != rxkring->nr_hwcur) {
-		/* we have released some slots, notify the other end */
-		mb(); /* make sure nr_hwcur is updated before notifying */
-		txkring->nm_notify(txkring, 0);
+        m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */
+        if (m < 0)
+                m += rxkring->nkr_num_slots;
+
+	if (m == 0) {
+		/* nothing to release */
+		return 0;
 	}
-        return 0;
+
+        for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
+                struct netmap_slot *rs = &rxring->slot[k];
+                struct netmap_slot *ts = &txring->slot[k];
+
+		if (rs->flags & NS_BUF_CHANGED) {
+			/* copy the slot and report the buffer change */
+			*ts = *rs;
+			rs->flags &= ~NS_BUF_CHANGED;
+		}
+        }
+
+        mb(); /* make sure the slots are updated before publishing them */
+        txkring->nr_hwtail = nm_prev(k, lim);
+        rxkring->nr_hwcur = k;
+
+        ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
+		rxkring->nr_hwcur, rxkring->nr_hwtail,
+                rxkring->rcur, rxkring->rhead, rxkring->rtail, k);
+
+        txkring->nm_notify(txkring, 0);
+
+	return 0;
 }
 
 /* Pipe endpoints are created and destroyed together, so that endopoints do not
@@ -341,6 +350,8 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				NMR(na, t)[i]->pipe = NMR(ona, r)[i];
 				NMR(ona, r)[i]->pipe = NMR(na, t)[i];
+				/* mark all peer-adapter rings as fake */
+				NMR(ona, r)[i]->nr_kflags |= NKR_FAKERING;
 			}
 		}
 
@@ -408,7 +419,10 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		/* create all missing needed rings on the other end */
+		/* create all missing needed rings on the other end.
+		 * They have all been marked as fake in the krings_create
+		 * above, so the will not be filled with buffers
+		 */
 		error = netmap_mem_rings_create(ona);
 		if (error)
 			return error;
@@ -417,8 +431,18 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
-
 				if (nm_kring_pending_on(kring)) {
+					struct netmap_ring *sring = kring->ring,
+							   *dring = kring->pipe->ring;
+
+					/* copy our buffers info into the peer ring */
+					memcpy(dring->slot, sring->slot,
+							sizeof(struct netmap_slot) *
+							sring->num_slots);
+					/* mark also our ring as fake, so that buffers
+					 * will not be automatically deleted
+					 */
+					kring->nr_kflags |= NKR_FAKERING;
 					kring->nr_mode = NKR_NETMAP_ON;
 				}
 			}
@@ -434,17 +458,9 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 
 				if (nm_kring_pending_off(kring)) {
 					kring->nr_mode = NKR_NETMAP_OFF;
-					/* mark the peer ring as no longer needed by us
-					 * (it may still be kept if sombody else is using it)
-					 */
-					if (kring->pipe) {
-						kring->pipe->nr_kflags &= ~NKR_NEEDRING;
-					}
 				}
 			}
 		}
-		/* delete all the peer rings that are no longer needed */
-		netmap_mem_rings_delete(ona);
 	}
 
 	if (na->active_fds) {
@@ -495,20 +511,48 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 	struct netmap_pipe_adapter *pna =
 		(struct netmap_pipe_adapter *)na;
 	struct netmap_adapter *ona; /* na of the other end */
+	enum txrx t;
+	int i, j;
 
 	if (!pna->peer_ref) {
 		ND("%p: case 2, kept alive by peer",  na);
 		return;
 	}
+	ona = &pna->peer->up;
 	/* case 1) above */
 	ND("%p: case 1, deleting everything", na);
+	/* zero-out one index of all shared buffers */
+	if (ona->tx_rings) {
+		for_rx_tx(t) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+				struct netmap_ring *sring = kring->ring,
+						   *dring = kring->pipe->ring;
+
+				if (sring == NULL)
+					continue;
+
+				for (j = 0; j < sring->num_slots; j++) {
+					if (sring->slot[j].buf_idx ==
+					    dring->slot[j].buf_idx)
+						dring->slot[j].buf_idx = 0;
+				}
+				kring->nr_kflags &= ~NKR_FAKERING;
+				kring->pipe->nr_kflags &= ~NKR_FAKERING;
+			}
+
+		}
+	}
+
+	netmap_mem_rings_delete(na);
 	netmap_krings_delete(na); /* also zeroes tx_rings etc. */
-	ona = &pna->peer->up;
+	
 	if (ona->tx_rings == NULL) {
 		/* already deleted, we must be on an
                  * cleanup-after-error path */
 		return;
 	}
+	netmap_mem_rings_delete(ona);
 	netmap_krings_delete(ona);
 }
 

From 89a1b6533ff75a95df792c19b43140fc480b404d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 8 Mar 2018 07:23:00 +0100
Subject: [PATCH 0739/2207] do_regif: use if_xname rather than "name"

---
 sys/dev/netmap/netmap.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ecc3aa2ba..7673198df 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2113,13 +2113,13 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 					nm_prerr("error: large MTU (%d) needed "
 						"but %s does not support "
 						"NS_MOREFRAG", mtu,
-						na->ifp->name);
+						na->ifp->if_xname);
 					error = EINVAL;
 					goto err_drop_mem;
 				} else if (nbs < hw_max_slot_len) {
 					nm_prerr("error: using NS_MOREFRAG on "
 						"%s requires netmap buf size "
-						">= %u", na->ifp->name,
+						">= %u", na->ifp->if_xname,
 						hw_max_slot_len);
 					error = EINVAL;
 					goto err_drop_mem;
@@ -2128,7 +2128,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 						"%s needs to support "
 						"NS_MOREFRAG "
 						"(MTU=%u,netmap_buf_size=%u)",
-						na->ifp->name, mtu, nbs);
+						na->ifp->if_xname, mtu, nbs);
 				}
 			}
 		}

From d6a80060797b52286605ba17d8325aff8ec669c6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 8 Mar 2018 07:42:44 +0100
Subject: [PATCH 0740/2207] freebsd: fix compilation error in nm_os_ifnet_mtu:
 for FreeBSD >= 11.0

---
 sys/dev/netmap/netmap_freebsd.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 96caf8468..3ad4f408d 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -174,7 +174,11 @@ nm_os_ifnet_fini(void)
 unsigned
 nm_os_ifnet_mtu(struct ifnet *ifp)
 {
+#if __FreeBSD_version < 1100030
        return ifp->if_data.ifi_mtu;
+#else /* __FreeBSD_version >= 1100030 */
+       return ifp->ifi_mtu;
+#endif
 }
 
 rawsum_t

From 48ff5b951e51ef65317e680a220b526003eab2a9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 8 Mar 2018 07:45:08 +0100
Subject: [PATCH 0741/2207] freebsd: nm_os_ifnet_mtu: fix typo

---
 sys/dev/netmap/netmap_freebsd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 3ad4f408d..598424b10 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -177,7 +177,7 @@ nm_os_ifnet_mtu(struct ifnet *ifp)
 #if __FreeBSD_version < 1100030
        return ifp->if_data.ifi_mtu;
 #else /* __FreeBSD_version >= 1100030 */
-       return ifp->ifi_mtu;
+       return ifp->if_mtu;
 #endif
 }
 

From 653c34c6da8338e71dad7eee24f26757ed183508 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 8 Mar 2018 10:30:50 +0100
Subject: [PATCH 0742/2207] linux/i40e: patch for Intel 2.4.6 version

---
 LINUX/final-patches/intel--i40e--2.4.6 | 154 +++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.4.6

diff --git a/LINUX/final-patches/intel--i40e--2.4.6 b/LINUX/final-patches/intel--i40e--2.4.6
new file mode 100644
index 000000000..1927e489c
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.4.6
@@ -0,0 +1,154 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index d33d3a8..e5f49a0 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -30,9 +30,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -46,13 +46,13 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index ae669c3..42e541d 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3280,6 +3285,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3361,6 +3370,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -10914,6 +10928,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -11282,6 +11301,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index eea26ba..de76992 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -26,6 +26,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -788,6 +792,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2386,6 +2395,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ 	bool failure = false;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 45d778f096e64344d97e36a808e2edf1386f7c51 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Mar 2018 20:25:34 +0100
Subject: [PATCH 0743/2207] pipe: fix deletion of rings

---
 sys/dev/netmap/netmap_mem2.c |   6 ++-
 sys/dev/netmap/netmap_pipe.c | 101 ++++++++++++++++++++++-------------
 2 files changed, 69 insertions(+), 38 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 7bb696dcf..b19131bce 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1182,7 +1182,7 @@ netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n)
 		slot[i].flags = 0;
 	}
 
-	ND("allocated %d buffers, %d available, first at %d", n, p->objfree, pos);
+	ND("%s: allocated %d buffers, %d available, first at %d", p->name, n, p->objfree, pos);
 	return (0);
 
 cleanup:
@@ -1227,9 +1227,11 @@ netmap_free_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n)
 	u_int i;
 
 	for (i = 0; i < n; i++) {
-		if (slot[i].buf_idx > 2)
+		if (slot[i].buf_idx > 1)
 			netmap_free_buf(nmd, slot[i].buf_idx);
 	}
+	ND("%s: released some buffers, available: %u",
+			p->name, p->objfree);
 }
 
 static void
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index de149db51..a5d79b7e6 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -395,7 +395,7 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
  *         usr1 --> e1     e2 <-- usr2
  *
  *       and we are either e1 or e2. Add a ref from the
- *       other end and hide our rings.
+ *       other end.
  */
 static int
 netmap_pipe_reg(struct netmap_adapter *na, int onoff)
@@ -420,8 +420,8 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 		}
 
 		/* create all missing needed rings on the other end.
-		 * They have all been marked as fake in the krings_create
-		 * above, so the will not be filled with buffers
+		 * Either our end, or the other, has been marked as
+		 * fake, so the allocation will not be done twice.
 		 */
 		error = netmap_mem_rings_create(ona);
 		if (error)
@@ -432,17 +432,30 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 				if (nm_kring_pending_on(kring)) {
-					struct netmap_ring *sring = kring->ring,
-							   *dring = kring->pipe->ring;
-
-					/* copy our buffers info into the peer ring */
-					memcpy(dring->slot, sring->slot,
-							sizeof(struct netmap_slot) *
-							sring->num_slots);
-					/* mark also our ring as fake, so that buffers
-					 * will not be automatically deleted
+					struct netmap_kring *sring, *dring;
+
+					/* copy the buffers from the non-fake ring */
+					if (kring->nr_kflags & NKR_FAKERING) {
+						sring = kring->pipe;
+						dring = kring;
+					} else {
+						sring = kring;
+						dring = kring->pipe;
+					}
+					memcpy(dring->ring->slot,
+					       sring->ring->slot,
+					       sizeof(struct netmap_slot) *
+							sring->nkr_num_slots);
+					/* mark both rings as fake and needed,
+					 * so that buffers will not be
+					 * deleted by the standard machinery
+					 * (we will delete them by ourselves in
+					 * netmap_pipe_krings_delete)
 					 */
-					kring->nr_kflags |= NKR_FAKERING;
+					sring->nr_kflags |=
+						(NKR_FAKERING | NKR_NEEDRING);
+					dring->nr_kflags |=
+						(NKR_FAKERING | NKR_NEEDRING);
 					kring->nr_mode = NKR_NETMAP_ON;
 				}
 			}
@@ -502,17 +515,16 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
  *    and we are either e1 or e2.
  *
  * In the former case we have to also delete the krings of e2;
- * in the latter case we do nothing (note that our krings
- * have already been hidden in the unregister callback).
+ * in the latter case we do nothing.
  */
 static void
 netmap_pipe_krings_delete(struct netmap_adapter *na)
 {
 	struct netmap_pipe_adapter *pna =
 		(struct netmap_pipe_adapter *)na;
-	struct netmap_adapter *ona; /* na of the other end */
+	struct netmap_adapter *sna, *ona; /* na of the other end */
 	enum txrx t;
-	int i, j;
+	int i;
 
 	if (!pna->peer_ref) {
 		ND("%p: case 2, kept alive by peer",  na);
@@ -521,27 +533,44 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 	ona = &pna->peer->up;
 	/* case 1) above */
 	ND("%p: case 1, deleting everything", na);
-	/* zero-out one index of all shared buffers */
-	if (ona->tx_rings) {
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-				struct netmap_ring *sring = kring->ring,
-						   *dring = kring->pipe->ring;
-
-				if (sring == NULL)
-					continue;
-
-				for (j = 0; j < sring->num_slots; j++) {
-					if (sring->slot[j].buf_idx ==
-					    dring->slot[j].buf_idx)
-						dring->slot[j].buf_idx = 0;
-				}
-				kring->nr_kflags &= ~NKR_FAKERING;
-				kring->pipe->nr_kflags &= ~NKR_FAKERING;
+	/* To avoid double-frees we zero-out all the buffers in the kernel part
+	 * of each ring. The reason is this: If the user is behaving correctly,
+	 * all buffers are found in exactly one slot in the userspace part of
+	 * some ring.  If the user is not behaving correctly, we cannot release
+	 * buffers cleanly anyway. In the latter case, the allocator will
+	 * return to a clean state only when all its users will close.
+	 */
+	sna = na;
+cleanup:
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(sna, t) + 1; i++) {
+			struct netmap_kring *kring = NMR(sna, t)[i];
+			struct netmap_ring *ring = kring->ring;
+			uint32_t j, lim = kring->nkr_num_slots - 1;
+
+			D("%s ring %p hwtail %u hwcur %u",
+				kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
+
+			if (ring == NULL)
+				continue;
+
+			if (kring->nr_hwtail == kring->nr_hwcur)
+				ring->slot[kring->nr_hwtail].buf_idx = 0;
+
+			for (j = nm_next(kring->nr_hwtail, lim);
+			     j != kring->nr_hwcur;
+			     j = nm_next(j, lim))
+			{
+				ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
+				ring->slot[j].buf_idx = 0;
 			}
-
+			kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING);
 		}
+
+	}
+	if (sna != ona && ona->tx_rings) {
+		sna = ona;
+		goto cleanup;
 	}
 
 	netmap_mem_rings_delete(na);

From 47cd73f1263c08e1351512dabd6d36a91c83db53 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 8 Mar 2018 16:43:33 +0100
Subject: [PATCH 0744/2207] lb: use new pipe behaviour to implement pipe-groups

---
 apps/lb/lb.c | 83 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 51 insertions(+), 32 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 64c9bce04..957e95e44 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -171,6 +171,7 @@ struct port_des {
 	char interface[MAX_PORTNAMELEN];
 	struct my_ctrs ctr;
 	unsigned int last_sync;
+	uint32_t last_tail;
 	struct overflow_queue *oq;
 	struct nm_desc *nmd;
 	struct netmap_ring *ring;
@@ -496,32 +497,19 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs)
 	 * packet still in the overflow queue (since those must
 	 * take precedence over the new one)
 	*/
-	if (nm_ring_space(ring) && (q == NULL || oq_empty(q))) {
-		struct netmap_slot *ts = &ring->slot[ring->cur];
+	if (ring->head != ring->tail && (q == NULL || oq_empty(q))) {
+		struct netmap_slot *ts = &ring->slot[ring->head];
 		struct netmap_slot old_slot = *ts;
-		uint32_t free_buf;
 
 		ts->buf_idx = rs->buf_idx;
 		ts->len = rs->len;
 		ts->flags |= NS_BUF_CHANGED;
 		ts->ptr = rs->ptr;
-		ring->head = ring->cur = nm_ring_next(ring, ring->cur);
+		ring->head = nm_ring_next(ring, ring->head);
 		port->ctr.bytes += rs->len;
 		port->ctr.pkts++;
 		forwarded++;
-		if (old_slot.ptr && !g->last) {
-			/* old slot not empty and we are not the last group:
-			 * push it further down the chain
-			 */
-			free_buf = forward_packet(g + 1, &old_slot);
-		} else {
-			/* just return the old slot buffer: it is
-			 * either empty or already seen by everybody
-			 */
-			free_buf = old_slot.buf_idx;
-		}
-
-		return free_buf;
+		return old_slot.buf_idx;
 	}
 
 	/* use the overflow queue, if available */
@@ -798,6 +786,7 @@ int main(int argc, char **argv)
 				D("successfully opened pipe #%d %s (tx slots: %d)",
 				  k + 1, p->interface, p->nmd->req.nr_tx_slots);
 				p->ring = NETMAP_TXRING(p->nmd->nifp, 0);
+				p->last_tail = nm_ring_next(p->ring, p->ring->tail);
 			}
 			D("zerocopy %s",
 			  (rxport->nmd->mem == p->nmd->mem) ? "enabled" : "disabled");
@@ -856,7 +845,14 @@ int main(int argc, char **argv)
 
 		for (i = 0; i < npipes; ++i) {
 			struct netmap_ring *ring = ports[i].ring;
-			if (!glob_arg.busy_wait && !nm_tx_pending(ring)) {
+			int pending = nm_tx_pending(ring);
+
+			/* if there are packets pending, we want to be notified when
+			 * tail moves, so we let cur=tail
+			 */
+			ring->cur = pending ? ring->tail : ring->head;
+
+			if (!glob_arg.busy_wait && !pending) {
 				/* no need to poll, there are no packets pending */
 				continue;
 			}
@@ -879,6 +875,39 @@ int main(int argc, char **argv)
 			goto send_stats;
 		}
 
+		/* if there are several groups, try pushing released packets from
+		 * upstream groups to the downstream ones.
+		 *
+		 * It is important to do this before returned slots are reused
+		 * for new transmissions. For the same reason, this must be
+		 * done starting from the last group going backwards.
+		 */
+		for (i = glob_arg.num_groups - 1U; i > 0; i--) {
+			struct group_des *g = &groups[i - 1];
+			int j;
+			
+			for (j = 0; j < g->nports; j++) {
+				struct port_des *p = &g->ports[j];
+				struct netmap_ring *ring = p->ring;
+				uint32_t last = p->last_tail,
+					 stop = nm_ring_next(ring, ring->tail);
+
+				/* slight abuse of the API here: we touch the slot
+				 * pointed to by tail
+				 */
+				for ( ; last != stop; last = nm_ring_next(ring, last)) {
+					struct netmap_slot *rs = &ring->slot[last];
+					// XXX less aggressive?
+					rs->buf_idx = forward_packet(g + 1, rs);
+					rs->flags |= NS_BUF_CHANGED;
+					rs->ptr = 0;
+				}
+				p->last_tail = last;
+			}
+		}
+
+
+
 		if (oq) {
 			/* try to push packets from the overflow queues
 			 * to the corresponding pipes
@@ -886,7 +915,6 @@ int main(int argc, char **argv)
 			for (i = 0; i < npipes; i++) {
 				struct port_des *p = &ports[i];
 				struct overflow_queue *q = p->oq;
-				struct group_des *g = p->group;
 				uint32_t j, lim;
 				struct netmap_ring *ring;
 				struct netmap_slot *slot;
@@ -902,26 +930,17 @@ int main(int argc, char **argv)
 				for (j = 0; j < lim; j++) {
 					struct netmap_slot s = oq_deq(q), tmp;
 					tmp.ptr = 0;
-					slot = &ring->slot[ring->cur];
-					if (slot->ptr && !g->last) {
-						tmp.buf_idx = forward_packet(g + 1, slot);
-						/* the forwarding may have removed packets
-						 * from the current queue
-						 */
-						if (q->n < lim)
-							lim = q->n;
-					} else {
-						tmp.buf_idx = slot->buf_idx;
-					}
+					slot = &ring->slot[ring->head];
+					tmp.buf_idx = slot->buf_idx;
 					oq_enq(freeq, &tmp);
 					*slot = s;
 					slot->flags |= NS_BUF_CHANGED;
-					ring->cur = nm_ring_next(ring, ring->cur);
+					ring->head = nm_ring_next(ring, ring->head);
 				}
-				ring->head = ring->cur;
 			}
 		}
 
+		/* push any new packets from the input port to the first group */
 		int batch = 0;
 		for (i = rxport->nmd->first_rx_ring; i <= rxport->nmd->last_rx_ring; i++) {
 			struct netmap_ring *rxring = NETMAP_RXRING(rxport->nmd->nifp, i);

From 4f8bbc7562da1ba97e05b89e66735f3b65c5450c Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 9 Mar 2018 10:51:39 +0100
Subject: [PATCH 0745/2207] netmap_bwrap_attach() saves the na_vp of the hwna,
 then netmap_bwrap_dtor() restores it, NAF_VP_DOUBLE_ATTACH_FLAG no longer
 needed.

---
 sys/dev/netmap/netmap_kern.h |  7 ++++---
 sys/dev/netmap/netmap_vale.c | 19 +++----------------
 2 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 1c79eac52..2fdff6ddb 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -677,9 +677,6 @@ struct netmap_adapter {
 #define NAF_FORCE_NATIVE 128	/* the adapter is always NATIVE */
 #define NAF_PTNETMAP_HOST 256	/* the adapter supports ptnetmap in the host */
 #define NAF_MOREFRAG	512	/* the adapter supports NS_MOREFRAG */
-#define NAF_VP_DOUBLE_ATTACH 1024 /* the adapter is a VALE persistent port which
-				   * has been attached to 2 bridges
-				   */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
 				  * cannot be registered from userspace
@@ -1019,6 +1016,10 @@ struct netmap_bwrap_adapter {
 	 */
 	struct netmap_priv_d *na_kpriv;
 	struct nm_bdg_polling_state *na_polling_state;
+	/* we overwrite the hwna->na_vp pointer, so we save
+	 * here its original value, to be restored at detach
+	 */
+	struct netmap_vp_adapter *saved_na_vp;
 };
 int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index fc9feaaba..e6ac1dedb 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2431,16 +2431,7 @@ netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 
 	if (vpna->na_bdg) {
-		int error = netmap_bwrap_attach(name, na);
-		if (error == 0) {
-			/* flags the netmap_adapter of the bwrap as a second attach
-			 * of a VALE persistent port, so we can restore the na_vp
-			 * pointer of the netmap_adapter (of the first attach)
-			 * during the detach of the second
-			 */
-			na->na_vp->up.na_flags |= NAF_VP_DOUBLE_ATTACH;
-		}
-		return error;
+		return netmap_bwrap_attach(name, na);
 	}
 	na->na_vp = vpna;
 	strncpy(na->name, name, sizeof(na->name));
@@ -2593,12 +2584,7 @@ netmap_bwrap_dtor(struct netmap_adapter *na)
 	ND("na %p", na);
 	na->ifp = NULL;
 	bna->host.up.ifp = NULL;
-	if (na->na_flags & NAF_VP_DOUBLE_ATTACH) {
-		na->na_flags &= ~NAF_VP_DOUBLE_ATTACH;
-		hwna->na_vp = (struct netmap_vp_adapter *)hwna;
-	} else {
-		hwna->na_vp = NULL;
-	}
+	hwna->na_vp = bna->saved_na_vp;
 	hwna->na_hostvp = NULL;
 	hwna->na_private = NULL;
 	hwna->na_flags &= ~NAF_BUSY;
@@ -3074,6 +3060,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	bna->hwna = hwna;
 	netmap_adapter_get(hwna);
 	hwna->na_private = bna; /* weak reference */
+	bna->saved_na_vp = hwna->na_vp;
 	hwna->na_vp = &bna->up;
 	bna->up.up.na_vp = &(bna->up);
 

From 4a2121200fd72db747ba36f91acf7c65c1740366 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 9 Mar 2018 11:59:19 +0100
Subject: [PATCH 0746/2207] mute some debugging messages

---
 sys/dev/netmap/netmap_pipe.c | 2 +-
 sys/dev/netmap/netmap_vale.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index a5d79b7e6..9eca8dba9 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -548,7 +548,7 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 			struct netmap_ring *ring = kring->ring;
 			uint32_t j, lim = kring->nkr_num_slots - 1;
 
-			D("%s ring %p hwtail %u hwcur %u",
+			ND("%s ring %p hwtail %u hwcur %u",
 				kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
 
 			if (ring == NULL)
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index c63fa22fc..df80d1708 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -682,11 +682,11 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 	if (error) {
 		goto err_2;
 	}
-	D("returning nr_mem_id %d", req->nr_mem_id);
+	ND("returning nr_mem_id %d", req->nr_mem_id);
 	if (nmd)
 		netmap_mem_put(nmd);
 	NMG_UNLOCK();
-	D("created %s", ifp->if_xname);
+	ND("created %s", ifp->if_xname);
 	return 0;
 
 err_2:
@@ -2276,7 +2276,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	na->nm_krings_create = netmap_vp_krings_create;
 	na->nm_krings_delete = netmap_vp_krings_delete;
 	na->nm_dtor = netmap_vp_dtor;
-	D("nr_mem_id %d", req->nr_mem_id);
+	ND("nr_mem_id %d", req->nr_mem_id);
 	na->nm_mem = nmd ?
 		netmap_mem_get(nmd):
 		netmap_mem_private_new(

From bc798c9b8b08bbaffff8e2bd37c92cf2441666c2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 9 Mar 2018 12:34:49 +0100
Subject: [PATCH 0747/2207] lb: removed useless computed-hash flag

---
 apps/lb/lb.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 957e95e44..a149deebd 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -956,11 +956,10 @@ int main(int argc, char **argv)
 				received_bytes += rs->len;
 
 				// CHOOSE THE CORRECT OUTPUT PIPE
-				uint32_t hash = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B');
-				if (hash == 0) {
+				rs->ptr = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B');
+				if (rs->ptr == 0) {
 					non_ip++; // XXX ??
 				}
-				rs->ptr = hash | (1ULL << 32);
 				// prefetch the buffer for the next round
 				next_cur = nm_ring_next(rxring, next_cur);
 				next_slot = &rxring->slot[next_cur];

From 3cb2605650ad3b430f5e94696a1f9255a9e902a3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 10 Mar 2018 02:26:18 +0100
Subject: [PATCH 0748/2207] ptnetmap allocator: fix regression introduced by
 MTU check in do_regif

---
 sys/dev/netmap/netmap_mem2.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index f865be38a..4736b0c18 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2237,6 +2237,14 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 	ptnmd->buf_lut.objsize = bufsize;
 	nmd->nm_totalsize = (unsigned int)mem_size;
 
+	/* Initialize these fields as are needed by
+	 * netmap_mem_bufsize().
+	 * XXX please improve this, why do we need this
+	 * replication? maybe we nmd->pools[] should no be
+	 * there for the guest allocator? */
+	nmd->pools[NETMAP_BUF_POOL]._objsize = bufsize;
+	nmd->pools[NETMAP_BUF_POOL]._objtotal = nbuffers;
+
 	nmd->flags |= NETMAP_MEM_FINALIZED;
 out:
 	return 0;

From 45e7a6c9523b5fb2a45756cda89bb8a1e8ab8037 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 16 Mar 2018 16:49:18 +0100
Subject: [PATCH 0749/2207] ptnetmap: fix compilation error

---
 sys/dev/netmap/netmap_pt.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index c90fec7ee..5365b123b 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -639,9 +639,9 @@ static struct netmap_kring *
 ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
 {
 	if (k < pth_na->up.num_tx_rings) {
-		return pth_na->up.tx_rings + k;
+		return pth_na->up.tx_rings[k];
 	}
-	return pth_na->up.rx_rings + k - pth_na->up.num_tx_rings;
+	return pth_na->up.rx_rings[k - pth_na->up.num_tx_rings];
 }
 
 static int
@@ -847,14 +847,14 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
     }
 
     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i].save_notify =
-        	pth_na->up.rx_rings[i].nm_notify;
-        pth_na->up.rx_rings[i].nm_notify = nm_pt_host_notify;
+        pth_na->up.rx_rings[i]->save_notify =
+        	pth_na->up.rx_rings[i]->nm_notify;
+        pth_na->up.rx_rings[i]->nm_notify = nm_pt_host_notify;
     }
     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i].save_notify =
-        	pth_na->up.tx_rings[i].nm_notify;
-        pth_na->up.tx_rings[i].nm_notify = nm_pt_host_notify;
+        pth_na->up.tx_rings[i]->save_notify =
+        	pth_na->up.tx_rings[i]->nm_notify;
+        pth_na->up.tx_rings[i]->nm_notify = nm_pt_host_notify;
     }
 
 #ifdef RATE
@@ -895,14 +895,14 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
     pth_na->parent->na_flags = pth_na->parent_na_flags;
 
     for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i].nm_notify =
-        	pth_na->up.rx_rings[i].save_notify;
-        pth_na->up.rx_rings[i].save_notify = NULL;
+        pth_na->up.rx_rings[i]->nm_notify =
+        	pth_na->up.rx_rings[i]->save_notify;
+        pth_na->up.rx_rings[i]->save_notify = NULL;
     }
     for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i].nm_notify =
-        	pth_na->up.tx_rings[i].save_notify;
-        pth_na->up.tx_rings[i].save_notify = NULL;
+        pth_na->up.tx_rings[i]->nm_notify =
+        	pth_na->up.tx_rings[i]->save_notify;
+        pth_na->up.tx_rings[i]->save_notify = NULL;
     }
 
     /* Destroy kernel contexts. */
@@ -1079,7 +1079,7 @@ nm_pt_host_krings_create(struct netmap_adapter *na)
 	 * host rings independently on what the regif asked for:
 	 * these rings are needed by the guest ptnetmap adapter
 	 * anyway. */
-	kring = &NMR(na, t)[nma_get_nrings(na, t)];
+	kring = NMR(na, t)[nma_get_nrings(na, t)];
 	kring->nr_kflags |= NKR_NEEDRING;
     }
 

From 4efec97a69438b63b1d38a7d4b95afa58e330daf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 16 Mar 2018 20:01:51 +0100
Subject: [PATCH 0750/2207] fix various compilation errors introduced by
 cf9e6c7f0f7f57ad

---
 LINUX/forcedeth_netmap.h   |  6 +++---
 LINUX/i40e_netmap_linux.h  |  2 +-
 LINUX/if_e1000e_netmap.h   |  6 +++---
 LINUX/if_igb_netmap.h      |  6 +++---
 LINUX/ixgbe_netmap_linux.h |  8 ++++----
 LINUX/veth_netmap.h        | 12 ++++++------
 LINUX/virtio_netmap.h      |  8 ++++----
 7 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/LINUX/forcedeth_netmap.h b/LINUX/forcedeth_netmap.h
index 8ffa1a65c..f271bfd23 100644
--- a/LINUX/forcedeth_netmap.h
+++ b/LINUX/forcedeth_netmap.h
@@ -334,7 +334,7 @@ forcedeth_netmap_tx_init(struct SOFTC_T *np)
 
 	/* l points in the netmap ring, i points in the NIC ring */
 	for (i = 0; i < n; i++) {
-		int l = netmap_idx_n2k(&na->tx_rings[0], i);
+		int l = netmap_idx_n2k(na->tx_rings[0], i);
 		uint64_t paddr;
 		PNMB(na, slot + l, &paddr);
 		desc[i].flaglen = 0;
@@ -360,11 +360,11 @@ forcedeth_netmap_rx_init(struct SOFTC_T *np)
 	 * Do not release the slots owned by userspace,
 	 * and also keep one empty.
 	 */
-	lim = np->rx_ring_size - 1 - nm_kr_rxspace(&na->rx_rings[0]);
+	lim = np->rx_ring_size - 1 - nm_kr_rxspace(na->rx_rings[0]);
 	for (i = 0; i < np->rx_ring_size; i++) {
 		void *addr;
 		uint64_t paddr;
-		int l = netmap_idx_n2k(&na->rx_rings[0], i);
+		int l = netmap_idx_n2k(na->rx_rings[0], i);
 
 		addr = PNMB(na, slot + l, &paddr);
 		//netmap_reload_map(np->rl_ldata.rl_rx_mtag,
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 226d6902d..fdceafdb2 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -171,7 +171,7 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 
 	na = NA(ring->netdev);
 	ring_nr = ring->queue_index;
-	kring = &na->rx_rings[ring_nr];
+	kring = na->rx_rings[ring_nr];
 
 	slot = netmap_reset(na, NR_RX, ring_nr, 0);
 	if (!slot)
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 5ae381bb8..a4f407def 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -338,7 +338,7 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc;
 		for (i = 0; i < rxr->count; i++) {
 			struct e1000_buffer *bi = &rxr->buffer_info[i];
-			si = netmap_idx_n2k(&na->rx_rings[0], i);
+			si = netmap_idx_n2k(na->rx_rings[0], i);
 			PNMB(na, slot + si, &paddr);
 			if (bi->skb)
 				D("Warning: rx skb still set on slot #%d", i);
@@ -346,7 +346,7 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		}
 		rxr->next_to_use = 0;
 		/* preserve buffers already made available to clients */
-		i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[0]);
+		i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[0]);
 		wmb();	/* Force memory writes to complete */
 		NM_WR_RX_TAIL(i);
 	}
@@ -355,7 +355,7 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 	if (slot) {
 		/* initialize the tx ring for netmap mode */
 		for (i = 0; i < na->num_tx_desc; i++) {
-			si = netmap_idx_n2k(&na->tx_rings[0], i);
+			si = netmap_idx_n2k(na->tx_rings[0], i);
 			PNMB(na, slot + si, &paddr);
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
 		}
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 000ff9a96..6d883c57f 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -315,7 +315,7 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 		return 0;  // not in netmap native mode
 	for (i = 0; i < na->num_tx_desc; i++) {
 		union e1000_adv_tx_desc *tx_desc;
-		si = netmap_idx_n2k(&na->tx_rings[ring_nr], i);
+		si = netmap_idx_n2k(na->tx_rings[ring_nr], i);
 		addr = PNMB(na, slot + si, &paddr);
 		tx_desc = E1000_TX_DESC_ADV(*txr, i);
 		tx_desc->read.buffer_addr = htole64(paddr);
@@ -351,7 +351,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	for (i = 0; i < rxr->count; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;
-		int si = netmap_idx_n2k(&na->rx_rings[reg_idx], i);
+		int si = netmap_idx_n2k(na->rx_rings[reg_idx], i);
 
 #if 0
 		// XXX the skb check can go away
@@ -367,7 +367,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 		rx_desc->read.pkt_addr = htole64(paddr);
 	}
 	/* preserve buffers already made available to clients */
-	i = rxr->count - 1 - nm_kr_rxspace(&na->rx_rings[reg_idx]);
+	i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[reg_idx]);
 
 	wmb();	/* Force memory writes to complete */
 	ND("%s rxr%d.tail %d", na->name, reg_idx, i);
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index fc0788241..f7da72e64 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -603,7 +603,7 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	 * loading the map.
 	 */
 	for (j = 0; j < na->num_tx_desc; j++) {
-		int sj = netmap_idx_n2k(&na->tx_rings[ring_nr], j);
+		int sj = netmap_idx_n2k(na->tx_rings[ring_nr], j);
 		uint64_t paddr;
 		void *addr = PNMB(na, slot + sj, &paddr);
 	}
@@ -644,7 +644,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	// XXX can we move it later ?
 	ixgbe_netmap_configure_srrctl(adapter, ring);
 
-	lim = na->num_rx_desc - 1 - nm_kr_rxspace(&na->rx_rings[ring_nr]);
+	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 
 	for (i = 0; i < na->num_rx_desc; i++) {
 		/*
@@ -652,7 +652,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 		 * considering the offset between the netmap and NIC rings
 		 * (see comment in ixgbe_setup_transmit_ring() ).
 		 */
-		int si = netmap_idx_n2k(&na->rx_rings[ring_nr], i);
+		int si = netmap_idx_n2k(na->rx_rings[ring_nr], i);
 		union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(ring, i);
 		uint64_t paddr;
 		PNMB(na, slot + si, &paddr);
@@ -719,7 +719,7 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 			goto err;
 		}
 		*h->phead = 0;
-		D("%s: phead %p *phead %x", na->tx_rings[i].name, h->phead, *h->phead);
+		D("%s: phead %p *phead %x", na->tx_rings[i]->name, h->phead, *h->phead);
 	}
 	return 0;
 
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 10e10bbf0..1cc4a7213 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -90,7 +90,7 @@ krings_needed(struct netmap_adapter *na)
 
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 
 			if (kring->nr_kflags & NKR_NEEDRING) {
 				return true;
@@ -147,7 +147,7 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 	if (onoff) {
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring)) {
 					/* mark the peer ring as needed */
@@ -165,7 +165,7 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		/* In case of no error we put our rings in netmap mode */
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring)) {
 					kring->nr_mode = NKR_NETMAP_ON;
@@ -181,7 +181,7 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring)) {
 					kring->nr_mode = NKR_NETMAP_OFF;
@@ -262,8 +262,8 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 		int i;
 
 		for (i = 0; i < nma_get_nrings(na, t); i++) {
-			NMR(na, t)[i].pipe = NMR(peer_na, r) + i;
-			NMR(peer_na, r)[i].pipe = NMR(na, t) + i;
+			NMR(na, t)[i]->pipe = NMR(peer_na, r)[i];
+			NMR(peer_na, r)[i]->pipe = NMR(na, t)[i];
 		}
 	}
 
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index c68355690..f18551bf6 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -274,7 +274,7 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 	hwrings = nma_get_nrings(na, NR_TX) + nma_get_nrings(na, NR_RX);
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t); i++) {
-			struct netmap_kring *kring = &NMR(na, t)[i];
+			struct netmap_kring *kring = NMR(na, t)[i];
 
 			if ((onoff && nm_kring_pending_on(kring)) ||
 				(!onoff && nm_kring_pending_off(kring))) {
@@ -341,7 +341,7 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 		/* enable netmap mode */
 		for_rx_tx(t) {
 			for (i = 0; i <= nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring)) {
 					kring->nr_mode = NKR_NETMAP_ON;
@@ -353,7 +353,7 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 		nm_clear_native_flags(na);
 		for_rx_tx(t) {
 			for (i = 0; i <= nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = &NMR(na, t)[i];
+				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring)) {
 					kring->nr_mode = NKR_NETMAP_OFF;
@@ -626,7 +626,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi)
 
 	for (r = 0; r < na->num_rx_rings; r++) {
 		COMPAT_DECL_SG
-		struct netmap_ring *ring = na->rx_rings[r].ring;
+		struct netmap_ring *ring = na->rx_rings[r]->ring;
 		struct virtqueue *vq = GET_RX_VQ(vi, r);
 		struct scatterlist *sg = GET_RX_SG(vi, r);
 		struct netmap_slot* slot;

From 492e1cf17e8173887b8cde4aff2cc6b697c76c8c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 16 Mar 2018 20:16:27 +0100
Subject: [PATCH 0751/2207] linux: ixgbe: don't use macro not defined in header

The corresponding literal is used directly to avoid
compilation issues.
---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index f7da72e64..83781154b 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -127,7 +127,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
 		reg_idx &= mask;
 	}
-	srrctl = IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT;
+	srrctl = IXGBE_RX_HDR_SIZE << 2; /*IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT */
 	srrctl |= NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
 	D("bufsz: %d srrctl: %d", NETMAP_BUF_SIZE(na),
 		NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);

From d8725b19286dd23f593c3fac4771f8339c4ac6c0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 11:19:34 +0100
Subject: [PATCH 0752/2207] utils: ctrl-api-test: fix MTU to run test on
 loopback

---
 utils/ctrl-api-test.c | 35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index caf93a77b..801b1925d 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -223,7 +223,7 @@ vale_detach(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	hdr.nr_body = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
@@ -791,7 +791,10 @@ struct mytest {
 	const char *name;
 };
 
-#define decltest(f) 	{ .test = f, .name = #f }
+#define decltest(f)                                                            \
+	{                                                                      \
+		.test = f, .name = #f                                          \
+	}
 
 static struct mytest tests[] = {
 	decltest(port_info_get),
@@ -821,7 +824,9 @@ main(int argc, char **argv)
 {
 	struct TestContext ctx;
 	unsigned int i;
-	int j = -1;
+	int loopback_if;
+	int ret = 0;
+	int j   = -1;
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
@@ -849,17 +854,26 @@ main(int argc, char **argv)
 		}
 	}
 
+	loopback_if = !strcmp(ctx.ifname, "lo");
+	if (loopback_if) {
+		/* For the tests, we need the MTU to be smaller than
+		 * the NIC RX buffer size, otherwise we will fail on
+		 * registering the interface. To stay safe, let's
+		 * just use a standard MTU. */
+		system("ip link set dev lo mtu 1514");
+	}
+
 	if (j >= 0) {
 		j--; /* one-based --> zero-based */
 		if (j >= (int)(sizeof(tests) / sizeof(tests[0]))) {
 			printf("Error: Test not in range\n");
-			return -1;
+			ret = -1;
+			goto out;
 		}
 	}
 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]) - 1; i++) {
 		struct TestContext ctxcopy;
 		int fd;
-		int ret;
 		if (j >= 0 && (unsigned)j != i) {
 			continue;
 		}
@@ -867,17 +881,22 @@ main(int argc, char **argv)
 		fd = open("/dev/netmap", O_RDWR);
 		if (fd < 0) {
 			perror("open(/dev/netmap)");
-			return fd;
+			ret = fd;
+			goto out;
 		}
 		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
 		ret = tests[i].test(fd, &ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
-			return ret;
+			goto out;
 		}
 		printf("==> Test #%d successful\n", i + 1);
 		close(fd);
 	}
+out:
+	if (loopback_if) {
+		system("ip link set dev lo mtu 65536");
+	}
 
-	return 0;
+	return ret;
 }

From 630f4c4c4a10ab47216fa47ece5dacc2e3ee96e5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 11:48:15 +0100
Subject: [PATCH 0753/2207] utils: ctrl-api-test: fix unused result compilation
 issue

---
 utils/ctrl-api-test.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 801b1925d..51a50a540 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -860,7 +860,10 @@ main(int argc, char **argv)
 		 * the NIC RX buffer size, otherwise we will fail on
 		 * registering the interface. To stay safe, let's
 		 * just use a standard MTU. */
-		system("ip link set dev lo mtu 1514");
+		if (system("ip link set dev lo mtu 1514")) {
+			perror("system(mtu=1514)");
+			return -1;
+		}
 	}
 
 	if (j >= 0) {
@@ -895,7 +898,10 @@ main(int argc, char **argv)
 	}
 out:
 	if (loopback_if) {
-		system("ip link set dev lo mtu 65536");
+		if (system("ip link set dev lo mtu 65536")) {
+			perror("system(mtu=1514)");
+			return -1;
+		}
 	}
 
 	return ret;

From 7b2e1545689a0f590a44932ebcca2b2010b63d27 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 17 Mar 2018 12:28:14 +0100
Subject: [PATCH 0754/2207] linux/configure: fix missing utils build when
 building from root dir

---
 LINUX/netmap.mak.in | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 7e195525f..08a10a6ff 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -135,6 +135,7 @@ utils:
 install-utils:
 clean-utils:
 else
+.PHONY: utils
 utils:
 	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)" SUBSYS_FLAGS="$(SUBSYS_FLAGS)"
 

From 22a5df4204855ef7f754198163f2dc7b84964c1c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 16:03:56 +0100
Subject: [PATCH 0755/2207] integration tests: remove flaky pkt-gen tests

---
 ci/run-integration-tests | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 6357471e8..4f1ab722e 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -9,8 +9,4 @@ make
 sudo ./ctrl-api-test
 popd
 
-# Transmit some packets into VALE ports or pipes, using pkt-gen
-sudo pkt-gen -i vale:x -f tx -n 100 -w0
-sudo pkt-gen -i netmap:pipe{3 -f tx -n 65 -w0
-
 sudo rmmod netmap

From 2ad207eff79b058c135afbc158894b8cae93033d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 17:30:26 +0100
Subject: [PATCH 0756/2207] travis: als build 4.15 kernels

---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index d48092739..7a9cfb3e9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,6 +38,7 @@ env:
   - KERNEL_VERSION=4.12  ARCH=x86_64
   - KERNEL_VERSION=4.13  ARCH=x86_64
   - KERNEL_VERSION=4.14  ARCH=x86_64
+  - KERNEL_VERSION=4.15  ARCH=x86_64
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"

From 16852ffb5751c7f8881b002b19f6a6a0a1fcb7ce Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 17 Mar 2018 22:59:24 +0100
Subject: [PATCH 0757/2207] ignore test utils

---
 .gitignore | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitignore b/.gitignore
index 94a8676a1..646430f4d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,8 @@ utils/testmmap
 utils/vale-ctl
 utils/test_nm
 utils/cygwin1.dll
+utils/ctrl-api-test
+utils/functional
 examples/pkt-gen.exe
 examples/pkt-gen.exe.stackdump
 examples/pkt-gen-b.exe

From 2f982ff1b539241044da392d7273f01e1c3c4771 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 18 Mar 2018 16:22:02 +0100
Subject: [PATCH 0758/2207] remove stale comment

---
 sys/dev/netmap/netmap_kern.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 93e1e396c..4c0d2f3f7 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -365,9 +365,6 @@ struct netmap_zmon_list {
  * 	the next empty buffer as known by the hardware (next_to_check or so).
  * TX rings: hwcur + hwofs coincides with next_to_send
  *
- * For received packets, slot->flags is set to nkr_slot_flags
- * so we can provide a proper initial value.
- *
  * The following fields are used to implement lock-free copy of packets
  * from input to output ports in VALE switch:
  *	nkr_hwlease	buffer after the last one being copied.

From 69373ac3690de122e0816dd4f09cdbf49e6882d8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 09:52:05 +0100
Subject: [PATCH 0759/2207] travis: install the missing libelf-dev

---
 ci/build-linux | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 71d0b8d5d..2f6a2be4a 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -8,8 +8,9 @@ readonly GCC_MAJOR_VERSION=$(echo '#include 
 void main() { printf("%u\n", __GNUC__); }' | gcc -x c - -o /tmp/getgccversion  && /tmp/getgccversion)
 readonly PROC_COUNT=$(grep -c '^processor' /proc/cpuinfo)
 
+sudo apt-get -qq update
+sudo apt-get install libelf-dev
 if [ ${KERNEL_VERSION} == "local" ]; then
-    sudo apt-get -qq update
     sudo apt-get install -y linux-headers-$(uname -r)
     ./configure --no-drivers
     make -j $PROC_COUNT

From 94d98d613caec799319fd75a6722b57c55f2c193 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 11:09:46 +0100
Subject: [PATCH 0760/2207] nm_config: change signature to use an extensible
 struct nm_config_info

---
 LINUX/bsd_glue.h                 |  3 ---
 LINUX/ixgbe_netmap_linux.h       | 11 +++++------
 LINUX/netmap_linux.c             |  9 +++++----
 LINUX/netmap_ptnet.c             | 15 ++++++++-------
 LINUX/virtio_netmap.h            | 14 +++++++-------
 sys/dev/netmap/if_ptnet.c        | 14 +++++++-------
 sys/dev/netmap/if_vtnet_netmap.h | 15 ++++++---------
 sys/dev/netmap/netmap.c          | 31 +++++++++++++++++--------------
 sys/dev/netmap/netmap_kern.h     | 16 ++++++++++++++--
 sys/dev/netmap/netmap_pt.c       | 13 +++++--------
 sys/dev/netmap/netmap_vale.c     | 11 +++++------
 11 files changed, 79 insertions(+), 73 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 571618211..03b59fcd6 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -482,9 +482,6 @@ int sysctl_handle_long(SYSCTL_HANDLER_ARGS);
 #define MALLOC_DECLARE(a)
 #define MALLOC_DEFINE(a, b, c)
 
-struct netmap_adapter;
-int netmap_linux_config(struct netmap_adapter *na,
-		u_int *txr, u_int *rxr, u_int *txd, u_int *rxd);
 /* ---- namespaces ------ */
 #ifdef CONFIG_NET_NS
 int netmap_bns_register(void);
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 83781154b..7dfeaa9a5 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -730,15 +730,14 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 }
 
 static int
-ixgbe_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
-		    u_int *rxr, u_int *rxd)
+ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(na->ifp);
 
-	*txr = adapter->num_tx_queues;
-	*rxr = adapter->num_rx_queues;
-	*txd = NM_IXGBE_TX_RING(adapter, 0)->count;
-	*rxd = NM_IXGBE_RX_RING(adapter, 0)->count;
+	info->num_tx_rings = adapter->num_tx_queues;
+	info->num_rx_rings = adapter->num_rx_queues;
+	info->num_tx_descs = NM_IXGBE_TX_RING(adapter, 0)->count;
+	info->num_rx_descs = NM_IXGBE_RX_RING(adapter, 0)->count;
 
 	return 0;
 }
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 23c838142..ca7fede8d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1063,8 +1063,7 @@ nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
 }
 
 int
-netmap_linux_config(struct netmap_adapter *na,
-		u_int *txr, u_int *txd, u_int *rxr, u_int *rxd)
+netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct ifnet *ifp = na->ifp;
 	int error = 0;
@@ -1076,10 +1075,12 @@ netmap_linux_config(struct netmap_adapter *na,
 		error = ENXIO;
 		goto out;
 	}
-	error = nm_os_generic_find_num_desc(ifp, txd, rxd);
+	error = nm_os_generic_find_num_desc(ifp, &info->num_tx_descs,
+						&info->num_rx_descs);
 	if (error)
 		goto out;
-	nm_os_generic_find_num_queues(ifp, txr, rxr);
+	nm_os_generic_find_num_queues(ifp, &info->num_tx_rings,
+					&info->num_rx_rings);
 
 out:
 	rtnl_unlock();
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 9c7eb58f8..37317b64e 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1206,18 +1206,19 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 }
 
 static int
-ptnet_nm_config(struct netmap_adapter *na, unsigned *txr, unsigned *txd,
-		unsigned *rxr, unsigned *rxd)
+ptnet_nm_config(struct netmap_adapter *na,
+		struct nm_config_info *info)
 {
 	struct ptnet_info *pi = netdev_priv(na->ifp);
 
-	*txr = ioread32(pi->ioaddr + PTNET_IO_NUM_TX_RINGS);
-	*rxr = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_RINGS);
-	*txd = ioread32(pi->ioaddr + PTNET_IO_NUM_TX_SLOTS);
-	*rxd = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_SLOTS);
+	info->num_tx_rings = ioread32(pi->ioaddr + PTNET_IO_NUM_TX_RINGS);
+	info->num_rx_rings = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_RINGS);
+	info->num_tx_descs = ioread32(pi->ioaddr + PTNET_IO_NUM_TX_SLOTS);
+	info->num_rx_descs = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_SLOTS);
 
 	pr_info("%s: txr %u, rxr %u, txd %u, rxd %u\n", __func__,
-		*txr, *rxr, *txd, *rxd);
+		info->num_tx_rings, info->num_rx_rings, info->num_tx_descs,
+		info->num_rx_descs);
 
 	return 0;
 }
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index f18551bf6..5651e3ea2 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -701,18 +701,18 @@ virtio_netmap_intr(struct netmap_adapter *na, int onoff)
  * the multiqueue mode.
  */
 static int
-virtio_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
-		     u_int *rxr, u_int *rxd)
+virtio_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct ifnet *ifp = na->ifp;
 	struct virtnet_info *vi = netdev_priv(ifp);
 
-	*txr = ifp->real_num_tx_queues;
-	*txd = virtqueue_get_vring_size(GET_TX_VQ(vi, 0));
-	*rxr = 1;
-	*rxd = virtqueue_get_vring_size(GET_RX_VQ(vi, 0));
+	info->num_tx_rings = ifp->real_num_tx_queues;
+	info->num_tx_descs = virtqueue_get_vring_size(GET_TX_VQ(vi, 0));
+	info->num_rx_rings = 1;
+	info->num_rx_descs = virtqueue_get_vring_size(GET_RX_VQ(vi, 0));
 	D("virtio config txq=%d, txd=%d rxq=%d, rxd=%d",
-			*txr, *txd, *rxr, *rxd);
+		info->num_tx_rings, info->num_tx_descs, info->num_rx_rings,
+		info->num_rx_descs);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 1805a7f31..d69651a33 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1104,18 +1104,18 @@ ptnet_nm_ptctl(if_t ifp, uint32_t cmd)
 }
 
 static int
-ptnet_nm_config(struct netmap_adapter *na, unsigned *txr, unsigned *txd,
-		unsigned *rxr, unsigned *rxd)
+ptnet_nm_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct ptnet_softc *sc = if_getsoftc(na->ifp);
 
-	*txr = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
-	*rxr = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
-	*txd = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS);
-	*rxd = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS);
+	info->num_tx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
+	info->num_rx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
+	info->num_tx_descs = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS);
+	info->num_rx_descs = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS);
 
 	device_printf(sc->dev, "txr %u, rxr %u, txd %u, rxd %u\n",
-		      *txr, *rxr, *txd, *rxd);
+			info->num_tx_rings, info->num_rx_rings,
+			info->num_tx_descs, info->num_rx_descs);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 292e0c94b..427c6d558 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -408,24 +408,21 @@ vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc)
 }
 
 /* Update the virtio-net device configurations. Number of queues can
- * change dinamically, by 'ethtool --set-channels $IFNAME combined $N'.
- * This is actually the only way virtio-net can currently enable
- * the multiqueue mode.
+ * change dinamically.
  * XXX note that we seem to lose packets if the netmap ring has more
  * slots than the queue
  */
 static int
-vtnet_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
-						u_int *rxr, u_int *rxd)
+vtnet_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct ifnet *ifp = na->ifp;
 	struct SOFTC_T *sc = ifp->if_softc;
 
-	*txr = *rxr = sc->vtnet_max_vq_pairs;
-	*rxd = 512; // sc->vtnet_rx_nmbufs;
-	*txd = *rxd; // XXX
+	info->num_tx_rings = info->num_rx_rings = sc->vtnet_max_vq_pairs;
+	info->num_tx_descs = info->num_rx_descs = 512; // sc->vtnet_rx_nmbufs;
         D("vtnet config txq=%d, txd=%d rxq=%d, rxd=%d",
-					*txr, *txd, *rxr, *rxd);
+		info->num_tx_rings, info->num_tx_descs,
+		info->num_rx_rings, info->num_rx_descs);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a863e9032..9296d469a 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -743,21 +743,23 @@ nm_dump_buf(char *p, int len, int lim, char *dst)
 int
 netmap_update_config(struct netmap_adapter *na)
 {
-	u_int txr, txd, rxr, rxd;
+	struct nm_config_info info;
 
-	txr = txd = rxr = rxd = 0;
+	bzero(&info, sizeof(info));
 	if (na->nm_config == NULL ||
-	    na->nm_config(na, &txr, &txd, &rxr, &rxd))
+	    na->nm_config(na, &info))
 	{
 		/* take whatever we had at init time */
-		txr = na->num_tx_rings;
-		txd = na->num_tx_desc;
-		rxr = na->num_rx_rings;
-		rxd = na->num_rx_desc;
+		info.num_tx_rings = na->num_tx_rings;
+		info.num_tx_descs = na->num_tx_desc;
+		info.num_rx_rings = na->num_rx_rings;
+		info.num_rx_descs = na->num_rx_desc;
 	}
 
-	if (na->num_tx_rings == txr && na->num_tx_desc == txd &&
-	    na->num_rx_rings == rxr && na->num_rx_desc == rxd)
+	if (na->num_tx_rings == info.num_tx_rings &&
+	    na->num_tx_desc == info.num_tx_descs &&
+	    na->num_rx_rings == info.num_rx_rings &&
+	    na->num_rx_desc == info.num_rx_descs)
 		return 0; /* nothing changed */
 	if (netmap_verbose || na->active_fds > 0) {
 		D("stored config %s: txring %d x %d, rxring %d x %d",
@@ -765,14 +767,15 @@ netmap_update_config(struct netmap_adapter *na)
 			na->num_tx_rings, na->num_tx_desc,
 			na->num_rx_rings, na->num_rx_desc);
 		D("new config %s: txring %d x %d, rxring %d x %d",
-			na->name, txr, txd, rxr, rxd);
+			na->name, info.num_tx_rings, info.num_tx_descs,
+			info.num_rx_rings, info.num_rx_descs);
 	}
 	if (na->active_fds == 0) {
 		D("configuration changed (but fine)");
-		na->num_tx_rings = txr;
-		na->num_tx_desc = txd;
-		na->num_rx_rings = rxr;
-		na->num_rx_desc = rxd;
+		na->num_tx_rings = info.num_tx_rings;
+		na->num_tx_desc = info.num_tx_descs;
+		na->num_rx_rings = info.num_rx_rings;
+		na->num_rx_desc = info.num_rx_descs;
 		return 0;
 	}
 	D("configuration changed while active, this is bad...");
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4c0d2f3f7..293da82c1 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -633,6 +633,14 @@ struct netmap_lut {
 
 struct netmap_vp_adapter; // forward
 
+/* Struct to be filled by nm_config callbacks. */
+struct nm_config_info {
+	unsigned num_tx_rings;
+	unsigned num_rx_rings;
+	unsigned num_tx_descs;
+	unsigned num_rx_descs;
+};
+
 /*
  * The "struct netmap_adapter" extends the "struct adapter"
  * (or equivalent) device descriptor.
@@ -769,8 +777,7 @@ struct netmap_adapter {
 #define NAF_FORCE_RECLAIM   2
 #define NAF_CAN_FORWARD_DOWN 4
 	/* return configuration information */
-	int (*nm_config)(struct netmap_adapter *,
-		u_int *txr, u_int *txd, u_int *rxr, u_int *rxd);
+	int (*nm_config)(struct netmap_adapter *, struct nm_config_info *info);
 	int (*nm_krings_create)(struct netmap_adapter *);
 	void (*nm_krings_delete)(struct netmap_adapter *);
 #ifdef WITH_VALE
@@ -1333,6 +1340,11 @@ nm_clear_native_flags(struct netmap_adapter *na)
 #endif
 }
 
+#ifdef linux
+int netmap_linux_config(struct netmap_adapter *na,
+			struct nm_config_info *info);
+#endif /* linux */
+
 /*
  * nm_*sync_prologue() functions are used in ioctl/poll and ptnetmap
  * kthreads.
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 5365b123b..bd3af87d0 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1020,8 +1020,7 @@ nm_unused_notify(struct netmap_kring *kring, int flags)
 
 /* nm_config callback for bwrap */
 static int
-nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
-        u_int *rxr, u_int *rxd)
+nm_pt_host_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
     struct netmap_pt_host_adapter *pth_na =
         (struct netmap_pt_host_adapter *)na;
@@ -1033,12 +1032,10 @@ nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
     /* forward the request */
     error = netmap_update_config(parent);
 
-    *rxr = na->num_rx_rings = parent->num_rx_rings;
-    *txr = na->num_tx_rings = parent->num_tx_rings;
-    *txd = na->num_tx_desc = parent->num_tx_desc;
-    *rxd = na->num_rx_desc = parent->num_rx_desc;
-
-    DBG(D("rxr: %d txr: %d txd: %d rxd: %d", *rxr, *txr, *txd, *rxd));
+    info->num_rx_rings = na->num_rx_rings = parent->num_rx_rings;
+    info->num_tx_rings = na->num_tx_rings = parent->num_tx_rings;
+    info->num_tx_descs = na->num_tx_desc = parent->num_tx_desc;
+    info->num_rx_descs = na->num_rx_desc = parent->num_rx_desc;
 
     return error;
 }
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index ee858ac08..38aa641d2 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2777,8 +2777,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 
 /* nm_config callback for bwrap */
 static int
-netmap_bwrap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
-				    u_int *rxr, u_int *rxd)
+netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct netmap_bwrap_adapter *bna =
 		(struct netmap_bwrap_adapter *)na;
@@ -2787,10 +2786,10 @@ netmap_bwrap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
 	/* forward the request */
 	netmap_update_config(hwna);
 	/* swap the results */
-	*txr = hwna->num_rx_rings;
-	*txd = hwna->num_rx_desc;
-	*rxr = hwna->num_tx_rings;
-	*rxd = hwna->num_rx_desc;
+	info->num_tx_rings = hwna->num_rx_rings;
+	info->num_tx_descs = hwna->num_rx_desc;
+	info->num_rx_rings = hwna->num_tx_rings;
+	info->num_rx_descs = hwna->num_tx_desc;
 
 	return 0;
 }

From e1c5ef94bd58d3f37154766fabdfd9e6bbec5138 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 15:05:32 +0100
Subject: [PATCH 0761/2207] netmap adapter: add rx_buffer_size

---
 sys/dev/netmap/netmap.c      | 14 ++++++++------
 sys/dev/netmap/netmap_kern.h |  7 +++++++
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9296d469a..8f24f1b6e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2102,11 +2102,8 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 			/* This netmap adapter is attached to an ifnet. */
 			unsigned nbs = netmap_mem_bufsize(na->nm_mem);
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
-			/* The maximum amount of bytes that a single
-			 * receive or transmit NIC descriptor can hold. */
-			unsigned hw_max_slot_len = 4096;
 
-			if (mtu <= hw_max_slot_len) {
+			if (mtu <= na->rx_buffer_size) {
 				/* The MTU fits a single NIC slot. We only
 				 * Need to check that netmap buffers are
 				 * large enough to hold an MTU. NS_MOREFRAG
@@ -2130,11 +2127,11 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 						na->ifp->if_xname);
 					error = EINVAL;
 					goto err_drop_mem;
-				} else if (nbs < hw_max_slot_len) {
+				} else if (nbs < na->rx_buffer_size) {
 					nm_prerr("error: using NS_MOREFRAG on "
 						"%s requires netmap buf size "
 						">= %u", na->ifp->if_xname,
-						hw_max_slot_len);
+						na->rx_buffer_size);
 					error = EINVAL;
 					goto err_drop_mem;
 				} else {
@@ -3308,6 +3305,11 @@ netmap_attach_common(struct netmap_adapter *na)
 		return EINVAL;
 	}
 
+	if (!na->rx_buffer_size) {
+		/* Set a conservative default (larger is safer). */
+		na->rx_buffer_size = PAGE_SIZE;
+	}
+
 #ifdef __FreeBSD__
 	if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
 		na->if_input = na->ifp->if_input; /* for netmap_send_up */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 293da82c1..532a4805a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -639,6 +639,7 @@ struct nm_config_info {
 	unsigned num_rx_rings;
 	unsigned num_tx_descs;
 	unsigned num_rx_descs;
+	unsigned rx_buffer_size;
 };
 
 /*
@@ -833,6 +834,12 @@ struct netmap_adapter {
 	/* Offset of ethernet header for each packet. */
 	u_int virt_hdr_len;
 
+	/* Max number of bytes that the NIC can store in the buffer
+	 * referenced by each RX descriptor. This translates to the maximum
+	 * bytes that a single netmap slot can reference. Larger packets
+	 * require NS_MOREFRAG support. */
+	unsigned rx_buffer_size;
+
 	char name[NETMAP_REQ_IFNAMSIZ]; /* used at least by pipes */
 };
 

From 45667e7ef20c0a4f787362f7adcab38c2756d8f2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 16:58:06 +0100
Subject: [PATCH 0762/2207] virtio: remove redundant nm_config callbacks

---
 LINUX/virtio_netmap.h            | 23 -----------------------
 sys/dev/netmap/if_vtnet_netmap.h | 21 ---------------------
 2 files changed, 44 deletions(-)

diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 5651e3ea2..65ba54252 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -695,28 +695,6 @@ virtio_netmap_intr(struct netmap_adapter *na, int onoff)
 	}
 }
 
-/* Update the virtio-net device configurations. Number of queues can
- * change dinamically, by 'ethtool --set-channels $IFNAME combined $N'.
- * This is actually the only way virtio-net can currently enable
- * the multiqueue mode.
- */
-static int
-virtio_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-	struct ifnet *ifp = na->ifp;
-	struct virtnet_info *vi = netdev_priv(ifp);
-
-	info->num_tx_rings = ifp->real_num_tx_queues;
-	info->num_tx_descs = virtqueue_get_vring_size(GET_TX_VQ(vi, 0));
-	info->num_rx_rings = 1;
-	info->num_rx_descs = virtqueue_get_vring_size(GET_RX_VQ(vi, 0));
-	D("virtio config txq=%d, txd=%d rxq=%d, rxd=%d",
-		info->num_tx_rings, info->num_tx_descs, info->num_rx_rings,
-		info->num_rx_descs);
-
-	return 0;
-}
-
 static void
 virtio_netmap_attach(struct virtnet_info *vi)
 {
@@ -732,7 +710,6 @@ virtio_netmap_attach(struct virtnet_info *vi)
 	na.nm_register = virtio_netmap_reg;
 	na.nm_txsync = virtio_netmap_txsync;
 	na.nm_rxsync = virtio_netmap_rxsync;
-	na.nm_config = virtio_netmap_config;
 	na.nm_intr = virtio_netmap_intr;
 
 	ret = netmap_attach_ext(&na, sizeof(struct netmap_virtio_adapter), 1);
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 427c6d558..7dc7716fc 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -407,26 +407,6 @@ vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc)
 	return 1;
 }
 
-/* Update the virtio-net device configurations. Number of queues can
- * change dinamically.
- * XXX note that we seem to lose packets if the netmap ring has more
- * slots than the queue
- */
-static int
-vtnet_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-	struct ifnet *ifp = na->ifp;
-	struct SOFTC_T *sc = ifp->if_softc;
-
-	info->num_tx_rings = info->num_rx_rings = sc->vtnet_max_vq_pairs;
-	info->num_tx_descs = info->num_rx_descs = 512; // sc->vtnet_rx_nmbufs;
-        D("vtnet config txq=%d, txd=%d rxq=%d, rxd=%d",
-		info->num_tx_rings, info->num_tx_descs,
-		info->num_rx_rings, info->num_rx_descs);
-
-	return 0;
-}
-
 static void
 vtnet_netmap_attach(struct SOFTC_T *sc)
 {
@@ -440,7 +420,6 @@ vtnet_netmap_attach(struct SOFTC_T *sc)
 	na.nm_register = vtnet_netmap_reg;
 	na.nm_txsync = vtnet_netmap_txsync;
 	na.nm_rxsync = vtnet_netmap_rxsync;
-	na.nm_config = vtnet_netmap_config;
 	na.nm_intr = vtnet_netmap_intr;
 	na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs;
 	D("max rings %d", sc->vtnet_max_vq_pairs);

From c4dd24c412f4bec5bea264c8a66d6b3a87a06a13 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 16:59:22 +0100
Subject: [PATCH 0763/2207] ixgbe: remove redundant nm_config callback

---
 LINUX/ixgbe_netmap_linux.h | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 7dfeaa9a5..5bac2c634 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -729,19 +729,6 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 	return ret;
 }
 
-static int
-ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(na->ifp);
-
-	info->num_tx_rings = adapter->num_tx_queues;
-	info->num_rx_rings = adapter->num_rx_queues;
-	info->num_tx_descs = NM_IXGBE_TX_RING(adapter, 0)->count;
-	info->num_rx_descs = NM_IXGBE_RX_RING(adapter, 0)->count;
-
-	return 0;
-}
-
 static void ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter);
 /*
  * The attach routine, called near the end of ixgbe_attach(),
@@ -780,7 +767,6 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.nm_register = ixgbe_netmap_reg;
 	na.nm_krings_create = ixgbe_netmap_krings_create;
 	na.nm_krings_delete = ixgbe_netmap_krings_delete;
-	na.nm_config = ixgbe_netmap_config;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
 	na.nm_intr = ixgbe_netmap_intr;

From c66e256150469b2cae27a9b3e2081daad90528d1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:14:41 +0100
Subject: [PATCH 0764/2207] linux: introduce netmap_rings_config_get() for
 linux drivers

---
 LINUX/netmap_linux.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index ca7fede8d..c09b45e66 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1063,7 +1063,7 @@ nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
 }
 
 int
-netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
+netmap_rings_config_get(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	struct ifnet *ifp = na->ifp;
 	int error = 0;
@@ -1087,7 +1087,23 @@ netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
 
 	return error;
 }
+EXPORT_SYMBOL(netmap_rings_config_get);
+
+/* Default nm_config implementation for netmap_hw_adapter on Linux. */
+int
+netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
 
+	/* Take what we had at init time. */
+	info->rx_buffer_size = na->rx_buffer_size;
+
+	return 0;
+}
 
 /* ######################## FILE OPERATIONS ####################### */
 

From 036024ea70cd44cc39f80b1cbdc9775af4582b93 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:25:39 +0100
Subject: [PATCH 0765/2207] linux: i40e: add nm_config support (including
 rx_buffer_size)

---
 LINUX/i40e_netmap_linux.h    | 19 ++++++++++++++++++-
 sys/dev/netmap/netmap_kern.h |  1 +
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index fdceafdb2..b182f5dd6 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -230,6 +230,21 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 	return 0;
 }
 
+static int
+i40e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	struct i40e_netdev_priv *np = netdev_priv(na->ifp);
+	struct i40e_vsi  *vsi = np->vsi;
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buffer_size = vsi->rx_buf_len;
+
+	return 0;
+}
 
 /*
  * The attach routine, called near the end of i40e_attach(),
@@ -250,10 +265,12 @@ i40e_netmap_attach(struct i40e_vsi *vsi)
 	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = NM_I40E_TX_RING(vsi, 0)->count;
 	na.num_rx_desc = NM_I40E_RX_RING(vsi, 0)->count;
+	na.num_tx_rings = na.num_rx_rings = vsi->num_queue_pairs;
+	na.rx_buffer_size = vsi->rx_buf_len;
 	na.nm_txsync = i40e_netmap_txsync;
 	na.nm_rxsync = i40e_netmap_rxsync;
 	na.nm_register = i40e_netmap_reg;
-	na.num_tx_rings = na.num_rx_rings = vsi->num_queue_pairs;
+	na.nm_config = i40e_netmap_config;
 	netmap_attach(&na);
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 532a4805a..53e05a07a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1224,6 +1224,7 @@ int netmap_transmit(struct ifnet *, struct mbuf *);
 struct netmap_slot *netmap_reset(struct netmap_adapter *na,
 	enum txrx tx, u_int n, u_int new_cur);
 int netmap_ring_reinit(struct netmap_kring *);
+int netmap_rings_config_get(struct netmap_adapter *, struct nm_config_info *);
 
 /* Return codes for netmap_*x_irq. */
 enum {

From 45d08f500e1f3eb026f4320ec0013e583665a9ba Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:29:44 +0100
Subject: [PATCH 0766/2207] linux: e1000: add nm_config support (including
 rx_buffer_size)

---
 LINUX/if_e1000_netmap.h | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index fd622653a..300cf90bd 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -337,6 +337,21 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 	return 1;
 }
 
+static int
+e1000_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	struct SOFTC_T *adapter = netdev_priv(na->ifp);
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buffer_size = adapter->rx_buffer_len;
+
+	return 0;
+}
+
 static void
 e1000_netmap_attach(struct SOFTC_T *adapter)
 {
@@ -349,11 +364,13 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = adapter->tx_ring[0].count;
 	na.num_rx_desc = adapter->rx_ring[0].count;
+	na.num_tx_rings = na.num_rx_rings = 1;
+	na.rx_buffer_size = adapter->rx_buffer_len;
 	na.nm_register = e1000_netmap_reg;
 	na.nm_txsync = e1000_netmap_txsync;
 	na.nm_rxsync = e1000_netmap_rxsync;
-	na.num_tx_rings = na.num_rx_rings = 1;
 	na.nm_intr = e1000_netmap_intr;
+	na.nm_config = e1000_netmap_config;
 
 	netmap_attach(&na);
 }

From e06036f47fd08468259b2592f8ca544811235af3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:31:24 +0100
Subject: [PATCH 0767/2207] linux: e1000e: add nm_config support (including
 rx_buffer_size)

---
 LINUX/if_e1000e_netmap.h | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index a4f407def..ce00be76f 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -363,6 +363,21 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 	return 1;
 }
 
+static int
+e1000e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	struct SOFTC_T *adapter = netdev_priv(na->ifp);
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buffer_size = adapter->rx_buffer_len;
+
+	return 0;
+}
+
 
 static void
 e1000_netmap_attach(struct SOFTC_T *adapter)
@@ -376,10 +391,12 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = adapter->tx_ring->count;
 	na.num_rx_desc = adapter->rx_ring->count;
+	na.num_tx_rings = na.num_rx_rings = 1;
+	na.rx_buffer_size = adapter->rx_buffer_len;
 	na.nm_register = e1000_netmap_reg;
 	na.nm_txsync = e1000_netmap_txsync;
 	na.nm_rxsync = e1000_netmap_rxsync;
-	na.num_tx_rings = na.num_rx_rings = 1;
+	na.nm_config = e1000e_netmap_config;
 	netmap_attach(&na);
 }
 

From fdaa28752efc0f3915aedc31d90e38653fe4a681 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:39:26 +0100
Subject: [PATCH 0768/2207] linux: ixgbe: add nm_config support (including
 rx_buffer_size)

---
 LINUX/configure            | 10 ++++++++++
 LINUX/ixgbe_netmap_linux.h | 35 +++++++++++++++++++++++++++++++++--
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 95924948e..3c195c590 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1663,6 +1663,16 @@ EOF
 		return ring->next_to_alloc;
 	}
 EOF
+
+    add_test 'have IXGBE_RX_BUFSZ' <ifp);
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buffer_size = nm_ixgbe_rx_buffer_size(adapter);
+
+	return 0;
+}
+
+
 static void ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter);
 /*
  * The attach routine, called near the end of ixgbe_attach(),
@@ -762,14 +790,17 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = NM_IXGBE_TX_RING(adapter, 0)->count;
 	na.num_rx_desc = NM_IXGBE_RX_RING(adapter, 0)->count;
+	na.num_tx_rings = adapter->num_tx_queues;
+	na.num_rx_rings = adapter->num_rx_queues;
+	na.rx_buffer_size = nm_ixgbe_rx_buffer_size(adapter);
 	na.nm_txsync = ixgbe_netmap_txsync;
 	na.nm_rxsync = ixgbe_netmap_rxsync;
 	na.nm_register = ixgbe_netmap_reg;
 	na.nm_krings_create = ixgbe_netmap_krings_create;
 	na.nm_krings_delete = ixgbe_netmap_krings_delete;
-	na.num_tx_rings = adapter->num_tx_queues;
-	na.num_rx_rings = adapter->num_rx_queues;
 	na.nm_intr = ixgbe_netmap_intr;
+	na.nm_config = ixgbe_netmap_config;
+
 	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter), 1)) {
 		pr_err("netmap: failed to attach netmap adapter");
 #ifndef NM_IXGBE_USE_TDH

From 1f1918d94372001cd45da4e78ea0ebd09ce62b1e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:46:12 +0100
Subject: [PATCH 0769/2207] linux: igb: add nm_config support (including
 rx_buffer_size)

---
 LINUX/configure       |  9 +++++++++
 LINUX/if_igb_netmap.h | 31 +++++++++++++++++++++++++++++--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 3c195c590..2d414dc7a 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1834,6 +1834,15 @@ EOF
 		return igb_rd32(hw, reg);
 	}
 EOF
+
+    add_test 'have IGB_RX_BUFSZ' <rx_ring[0]);
+#else  /* !NETMAP_LINUX_HAVE_IGB_RX_BUFSZ */
+	return 3072; /* stay on the safe side */
+#endif /* !NETMAP_LINUX_HAVE_IGB_RX_BUFSZ */
+}
+
+static int
+igb_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	struct SOFTC_T *adapter = netdev_priv(na->ifp);
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buffer_size = nm_igb_rx_buffer_size(adapter);
+
+	return 0;
+}
+
 
 static void
 igb_netmap_attach(struct SOFTC_T *adapter)
@@ -388,11 +413,13 @@ igb_netmap_attach(struct SOFTC_T *adapter)
 	na.na_flags = NAF_MOREFRAG;
 	na.num_tx_desc = adapter->tx_ring_count;
 	na.num_rx_desc = adapter->rx_ring_count;
+	na.num_tx_rings = adapter->num_tx_queues;
+	na.num_rx_rings = adapter->num_rx_queues;
+	na.rx_buffer_size = nm_igb_rx_buffer_size(adapter);
 	na.nm_register = igb_netmap_reg;
 	na.nm_txsync = igb_netmap_txsync;
 	na.nm_rxsync = igb_netmap_rxsync;
-	na.num_tx_rings = adapter->num_tx_queues;
-	na.num_rx_rings = adapter->num_rx_queues;
+	na.nm_config = igb_netmap_config;
 	netmap_attach(&na);
 }
 

From c6754007f989008fb0ff8cdfec2bab29260a510b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Mar 2018 17:10:39 +0100
Subject: [PATCH 0770/2207] linux: ixgbe: don't touch SRRCTL when entering
 netmap mode

SRRCTL is setup by the ixgbe driver accordingly to the interface
MTU.
---
 LINUX/ixgbe_netmap_linux.h | 40 --------------------------------------
 1 file changed, 40 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index d3f3725ab..4bbdc4505 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -111,37 +111,6 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 }
 #endif /* NETMAP_LINUX_IXGBE_HAVE_DISABLE */
 
-/*
- * In netmap mode, overwrite the srrctl register with netmap_buf_size
- * to properly configure the Receive Buffer Size
- */
-static void
-ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_RING *rx_ring)
-{
-	struct netmap_adapter *na = NA(adapter->netdev);
-	struct ixgbe_hw *hw = &adapter->hw;
-	u32 srrctl;
-	u8 reg_idx = rx_ring->reg_idx;
-
-	if (hw->mac.type == ixgbe_mac_82598EB) {
-		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
-		reg_idx &= mask;
-	}
-	srrctl = IXGBE_RX_HDR_SIZE << 2; /*IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT */
-	srrctl |= NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-	D("bufsz: %d srrctl: %d", NETMAP_BUF_SIZE(na),
-		NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);
-	/*
-	 * XXX
-	 * With Advanced RX descriptor, the address needs to be rewritten,
-	 * but with Legacy RX descriptor, it simply has to zero the status
-	 * byte in the descriptor to make it ready for reuse by hardware.
-	 * (ixgbe datasheet - Section 7.1.9)
-	 */
-	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
-	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
-}
-
 #ifdef NETMAP_LINUX_IXGBE_HAVE_NTA
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBE_HAVE_NTA */
@@ -186,13 +155,6 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 	RD(5, "per-queue irq disable not supported");
 }
 
-static void
-ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_RING *rx_ring)
-{
-	// TODO
-	D("not supported");
-}
-
 #ifdef NETMAP_LINUX_IXGBEVF_HAVE_NTA
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBEVF_HAVE_NTA */
@@ -641,8 +603,6 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
         /* same as in ixgbe_setup_transmit_ring() */
 	if (!slot)
 		return 0;	// not in native netmap mode
-	// XXX can we move it later ?
-	ixgbe_netmap_configure_srrctl(adapter, ring);
 
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 

From a09b2697ca6c6eedfa0bcc7308c166c29371f727 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:56:11 +0100
Subject: [PATCH 0771/2207] netmap_update_config: handle rx_buffer_size

---
 sys/dev/netmap/netmap.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8f24f1b6e..e20b924c0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -747,38 +747,38 @@ netmap_update_config(struct netmap_adapter *na)
 
 	bzero(&info, sizeof(info));
 	if (na->nm_config == NULL ||
-	    na->nm_config(na, &info))
-	{
+	    na->nm_config(na, &info)) {
 		/* take whatever we had at init time */
 		info.num_tx_rings = na->num_tx_rings;
 		info.num_tx_descs = na->num_tx_desc;
 		info.num_rx_rings = na->num_rx_rings;
 		info.num_rx_descs = na->num_rx_desc;
+		info.rx_buffer_size = na->rx_buffer_size;
 	}
 
 	if (na->num_tx_rings == info.num_tx_rings &&
 	    na->num_tx_desc == info.num_tx_descs &&
 	    na->num_rx_rings == info.num_rx_rings &&
-	    na->num_rx_desc == info.num_rx_descs)
+	    na->num_rx_desc == info.num_rx_descs &&
+	    na->rx_buffer_size == info.rx_buffer_size)
 		return 0; /* nothing changed */
-	if (netmap_verbose || na->active_fds > 0) {
-		D("stored config %s: txring %d x %d, rxring %d x %d",
-			na->name,
-			na->num_tx_rings, na->num_tx_desc,
-			na->num_rx_rings, na->num_rx_desc);
-		D("new config %s: txring %d x %d, rxring %d x %d",
-			na->name, info.num_tx_rings, info.num_tx_descs,
-			info.num_rx_rings, info.num_rx_descs);
-	}
 	if (na->active_fds == 0) {
-		D("configuration changed (but fine)");
+		D("configuration changed for %s: txring %d x %d, "
+			"rxring %d x %d, rxbufsz %d",
+			na->name, na->num_tx_rings, na->num_tx_desc,
+			na->num_rx_rings, na->num_rx_desc, na->rx_buffer_size);
 		na->num_tx_rings = info.num_tx_rings;
 		na->num_tx_desc = info.num_tx_descs;
 		na->num_rx_rings = info.num_rx_rings;
 		na->num_rx_desc = info.num_rx_descs;
+		na->rx_buffer_size = info.rx_buffer_size;
 		return 0;
 	}
-	D("configuration changed while active, this is bad...");
+	D("WARNING: configuration changed for %s while active: "
+		"txring %d x %d, rxring %d x %d, rxbufsz %d",
+		na->name, info.num_tx_rings, info.num_tx_descs,
+		info.num_rx_rings, info.num_rx_descs,
+		info.rx_buffer_size);
 	return 1;
 }
 

From 72df7b4cd5a053be0465b813117469363bd0d321 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 17:58:39 +0100
Subject: [PATCH 0772/2207] rename rx_buffer_size into rx_buf_maxsize

    The second name is more meaningful, as the value of this variable
    is in general an upper bound for the actual NIC RX buf size.
---
 LINUX/i40e_netmap_linux.h    |  4 ++--
 LINUX/if_e1000_netmap.h      |  4 ++--
 LINUX/if_e1000e_netmap.h     |  4 ++--
 LINUX/if_igb_netmap.h        |  6 +++---
 LINUX/ixgbe_netmap_linux.h   |  6 +++---
 LINUX/netmap_linux.c         |  2 +-
 sys/dev/netmap/netmap.c      | 20 ++++++++++----------
 sys/dev/netmap/netmap_kern.h |  4 ++--
 8 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index b182f5dd6..bad62871a 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -241,7 +241,7 @@ i40e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	info->rx_buffer_size = vsi->rx_buf_len;
+	info->rx_buf_maxsize = vsi->rx_buf_len;
 
 	return 0;
 }
@@ -266,7 +266,7 @@ i40e_netmap_attach(struct i40e_vsi *vsi)
 	na.num_tx_desc = NM_I40E_TX_RING(vsi, 0)->count;
 	na.num_rx_desc = NM_I40E_RX_RING(vsi, 0)->count;
 	na.num_tx_rings = na.num_rx_rings = vsi->num_queue_pairs;
-	na.rx_buffer_size = vsi->rx_buf_len;
+	na.rx_buf_maxsize = vsi->rx_buf_len;
 	na.nm_txsync = i40e_netmap_txsync;
 	na.nm_rxsync = i40e_netmap_rxsync;
 	na.nm_register = i40e_netmap_reg;
diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 300cf90bd..a013aab40 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -347,7 +347,7 @@ e1000_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	info->rx_buffer_size = adapter->rx_buffer_len;
+	info->rx_buf_maxsize = adapter->rx_buffer_len;
 
 	return 0;
 }
@@ -365,7 +365,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 	na.num_tx_desc = adapter->tx_ring[0].count;
 	na.num_rx_desc = adapter->rx_ring[0].count;
 	na.num_tx_rings = na.num_rx_rings = 1;
-	na.rx_buffer_size = adapter->rx_buffer_len;
+	na.rx_buf_maxsize = adapter->rx_buffer_len;
 	na.nm_register = e1000_netmap_reg;
 	na.nm_txsync = e1000_netmap_txsync;
 	na.nm_rxsync = e1000_netmap_rxsync;
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index ce00be76f..75c91e3ad 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -373,7 +373,7 @@ e1000e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	info->rx_buffer_size = adapter->rx_buffer_len;
+	info->rx_buf_maxsize = adapter->rx_buffer_len;
 
 	return 0;
 }
@@ -392,7 +392,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 	na.num_tx_desc = adapter->tx_ring->count;
 	na.num_rx_desc = adapter->rx_ring->count;
 	na.num_tx_rings = na.num_rx_rings = 1;
-	na.rx_buffer_size = adapter->rx_buffer_len;
+	na.rx_buf_maxsize = adapter->rx_buffer_len;
 	na.nm_register = e1000_netmap_reg;
 	na.nm_txsync = e1000_netmap_txsync;
 	na.nm_rxsync = e1000_netmap_rxsync;
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index f46b452af..26eabe4ff 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -376,7 +376,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 }
 
 static unsigned
-nm_igb_rx_buffer_size(struct SOFTC_T *adapter)
+nm_igb_rx_buf_maxsize(struct SOFTC_T *adapter)
 {
 #if defined(NETMAP_LINUX_HAVE_IGB_RX_BUFSZ)
 	return igb_rx_bufsz(adapter->rx_ring[0]);
@@ -395,7 +395,7 @@ igb_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	info->rx_buffer_size = nm_igb_rx_buffer_size(adapter);
+	info->rx_buf_maxsize = nm_igb_rx_buf_maxsize(adapter);
 
 	return 0;
 }
@@ -415,7 +415,7 @@ igb_netmap_attach(struct SOFTC_T *adapter)
 	na.num_rx_desc = adapter->rx_ring_count;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
-	na.rx_buffer_size = nm_igb_rx_buffer_size(adapter);
+	na.rx_buf_maxsize = nm_igb_rx_buf_maxsize(adapter);
 	na.nm_register = igb_netmap_reg;
 	na.nm_txsync = igb_netmap_txsync;
 	na.nm_rxsync = igb_netmap_rxsync;
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 4bbdc4505..e28eb0a72 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -690,7 +690,7 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 }
 
 static unsigned
-nm_ixgbe_rx_buffer_size(struct NM_IXGBE_ADAPTER *adapter)
+nm_ixgbe_rx_buf_maxsize(struct NM_IXGBE_ADAPTER *adapter)
 {
 #if defined(NM_IXGBEVF)
        return IXGBEVF_RXBUFFER_2048;
@@ -711,7 +711,7 @@ ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	info->rx_buffer_size = nm_ixgbe_rx_buffer_size(adapter);
+	info->rx_buf_maxsize = nm_ixgbe_rx_buf_maxsize(adapter);
 
 	return 0;
 }
@@ -752,7 +752,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.num_rx_desc = NM_IXGBE_RX_RING(adapter, 0)->count;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
-	na.rx_buffer_size = nm_ixgbe_rx_buffer_size(adapter);
+	na.rx_buf_maxsize = nm_ixgbe_rx_buf_maxsize(adapter);
 	na.nm_txsync = ixgbe_netmap_txsync;
 	na.nm_rxsync = ixgbe_netmap_rxsync;
 	na.nm_register = ixgbe_netmap_reg;
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index c09b45e66..45ac3b589 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1100,7 +1100,7 @@ netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
 	}
 
 	/* Take what we had at init time. */
-	info->rx_buffer_size = na->rx_buffer_size;
+	info->rx_buf_maxsize = na->rx_buf_maxsize;
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e20b924c0..9e8f076fb 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -753,32 +753,32 @@ netmap_update_config(struct netmap_adapter *na)
 		info.num_tx_descs = na->num_tx_desc;
 		info.num_rx_rings = na->num_rx_rings;
 		info.num_rx_descs = na->num_rx_desc;
-		info.rx_buffer_size = na->rx_buffer_size;
+		info.rx_buf_maxsize = na->rx_buf_maxsize;
 	}
 
 	if (na->num_tx_rings == info.num_tx_rings &&
 	    na->num_tx_desc == info.num_tx_descs &&
 	    na->num_rx_rings == info.num_rx_rings &&
 	    na->num_rx_desc == info.num_rx_descs &&
-	    na->rx_buffer_size == info.rx_buffer_size)
+	    na->rx_buf_maxsize == info.rx_buf_maxsize)
 		return 0; /* nothing changed */
 	if (na->active_fds == 0) {
 		D("configuration changed for %s: txring %d x %d, "
 			"rxring %d x %d, rxbufsz %d",
 			na->name, na->num_tx_rings, na->num_tx_desc,
-			na->num_rx_rings, na->num_rx_desc, na->rx_buffer_size);
+			na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
 		na->num_tx_rings = info.num_tx_rings;
 		na->num_tx_desc = info.num_tx_descs;
 		na->num_rx_rings = info.num_rx_rings;
 		na->num_rx_desc = info.num_rx_descs;
-		na->rx_buffer_size = info.rx_buffer_size;
+		na->rx_buf_maxsize = info.rx_buf_maxsize;
 		return 0;
 	}
 	D("WARNING: configuration changed for %s while active: "
 		"txring %d x %d, rxring %d x %d, rxbufsz %d",
 		na->name, info.num_tx_rings, info.num_tx_descs,
 		info.num_rx_rings, info.num_rx_descs,
-		info.rx_buffer_size);
+		info.rx_buf_maxsize);
 	return 1;
 }
 
@@ -2103,7 +2103,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 			unsigned nbs = netmap_mem_bufsize(na->nm_mem);
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
 
-			if (mtu <= na->rx_buffer_size) {
+			if (mtu <= na->rx_buf_maxsize) {
 				/* The MTU fits a single NIC slot. We only
 				 * Need to check that netmap buffers are
 				 * large enough to hold an MTU. NS_MOREFRAG
@@ -2127,11 +2127,11 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 						na->ifp->if_xname);
 					error = EINVAL;
 					goto err_drop_mem;
-				} else if (nbs < na->rx_buffer_size) {
+				} else if (nbs < na->rx_buf_maxsize) {
 					nm_prerr("error: using NS_MOREFRAG on "
 						"%s requires netmap buf size "
 						">= %u", na->ifp->if_xname,
-						na->rx_buffer_size);
+						na->rx_buf_maxsize);
 					error = EINVAL;
 					goto err_drop_mem;
 				} else {
@@ -3305,9 +3305,9 @@ netmap_attach_common(struct netmap_adapter *na)
 		return EINVAL;
 	}
 
-	if (!na->rx_buffer_size) {
+	if (!na->rx_buf_maxsize) {
 		/* Set a conservative default (larger is safer). */
-		na->rx_buffer_size = PAGE_SIZE;
+		na->rx_buf_maxsize = PAGE_SIZE;
 	}
 
 #ifdef __FreeBSD__
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 53e05a07a..d290fcc8b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -639,7 +639,7 @@ struct nm_config_info {
 	unsigned num_rx_rings;
 	unsigned num_tx_descs;
 	unsigned num_rx_descs;
-	unsigned rx_buffer_size;
+	unsigned rx_buf_maxsize;
 };
 
 /*
@@ -838,7 +838,7 @@ struct netmap_adapter {
 	 * referenced by each RX descriptor. This translates to the maximum
 	 * bytes that a single netmap slot can reference. Larger packets
 	 * require NS_MOREFRAG support. */
-	unsigned rx_buffer_size;
+	unsigned rx_buf_maxsize;
 
 	char name[NETMAP_REQ_IFNAMSIZ]; /* used at least by pipes */
 };

From c00dd4097c0b449dd34b5ba5565005efd273a141 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 18:04:00 +0100
Subject: [PATCH 0773/2207] ptnet: update nm_config callback to handle
 rx_buf_maxsize

---
 LINUX/netmap_ptnet.c      | 5 +++--
 sys/dev/netmap/if_ptnet.c | 6 ++++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 37317b64e..0d65e5e9f 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1215,10 +1215,11 @@ ptnet_nm_config(struct netmap_adapter *na,
 	info->num_rx_rings = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_RINGS);
 	info->num_tx_descs = ioread32(pi->ioaddr + PTNET_IO_NUM_TX_SLOTS);
 	info->num_rx_descs = ioread32(pi->ioaddr + PTNET_IO_NUM_RX_SLOTS);
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
-	pr_info("%s: txr %u, rxr %u, txd %u, rxd %u\n", __func__,
+	pr_info("%s: txr %u, rxr %u, txd %u, rxd %u, rxbufsz %u\n", __func__,
 		info->num_tx_rings, info->num_rx_rings, info->num_tx_descs,
-		info->num_rx_descs);
+		info->num_rx_descs, info->rx_buf_maxsize);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index d69651a33..d3f7e734a 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1112,10 +1112,12 @@ ptnet_nm_config(struct netmap_adapter *na, struct nm_config_info *info)
 	info->num_rx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
 	info->num_tx_descs = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS);
 	info->num_rx_descs = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS);
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
-	device_printf(sc->dev, "txr %u, rxr %u, txd %u, rxd %u\n",
+	device_printf(sc->dev, "txr %u, rxr %u, txd %u, rxd %u, rxbufsz %u\n",
 			info->num_tx_rings, info->num_rx_rings,
-			info->num_tx_descs, info->num_rx_descs);
+			info->num_tx_descs, info->num_rx_descs,
+			info->rx_buf_maxsize);
 
 	return 0;
 }

From 40a58d5155b436723380e3366c0fb9de9d5cd773 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 18 Mar 2018 18:05:57 +0100
Subject: [PATCH 0774/2207] ptnetmap, bwrap: handle rx_buf_maxsize variable in
 nm_config()

---
 LINUX/netmap_linux.c         | 2 +-
 sys/dev/netmap/netmap_pt.c   | 1 +
 sys/dev/netmap/netmap_vale.c | 3 ++-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 45ac3b589..352b4e5fd 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1099,7 +1099,7 @@ netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	/* Take what we had at init time. */
+	/* Take whatever we had at init time. */
 	info->rx_buf_maxsize = na->rx_buf_maxsize;
 
 	return 0;
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index bd3af87d0..cfa32b0bc 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1036,6 +1036,7 @@ nm_pt_host_config(struct netmap_adapter *na, struct nm_config_info *info)
     info->num_tx_rings = na->num_tx_rings = parent->num_tx_rings;
     info->num_tx_descs = na->num_tx_desc = parent->num_tx_desc;
     info->num_rx_descs = na->num_rx_desc = parent->num_rx_desc;
+    info->rx_buf_maxsize = na->rx_buf_maxsize = parent->rx_buf_maxsize;
 
     return error;
 }
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 38aa641d2..8fd0c6ca4 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2785,11 +2785,12 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 
 	/* forward the request */
 	netmap_update_config(hwna);
-	/* swap the results */
+	/* swap the results and propagate */
 	info->num_tx_rings = hwna->num_rx_rings;
 	info->num_tx_descs = hwna->num_rx_desc;
 	info->num_rx_rings = hwna->num_tx_rings;
 	info->num_rx_descs = hwna->num_tx_desc;
+	info->rx_buf_maxsize = hwna->rx_buf_maxsize;
 
 	return 0;
 }

From a219abd395caebd1d68153628e9de1a76f28377c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 19 Mar 2018 17:49:59 +0100
Subject: [PATCH 0775/2207] linux/configure: optionally fail on first driver
 error

---
 LINUX/configure | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 2d414dc7a..ba9609d0f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -5,6 +5,7 @@ SRCDIR=$(cd $(dirname $0); pwd)
 MODNAME=netmap
 DEBUG=1
 UTILS=
+DRVERRFAIL=
 
 # setelem2n  
 setelem2n()
@@ -239,6 +240,15 @@ warning()
 	message WARNING
 }
 
+drverror() {
+	message WARNING
+	if [ -n "$DRVERRFAIL" ]; then
+		error <&1 || { warning <&1 || { drverror <
Date: Tue, 20 Mar 2018 11:34:37 +0100
Subject: [PATCH 0776/2207] linux/igb: test for next_to_alloc definition

---
 LINUX/configure       | 8 ++++++++
 LINUX/if_igb_netmap.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index ba9609d0f..945c432b5 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1857,6 +1857,14 @@ EOF
        dummy(struct igb_ring *ring) {
                return igb_rx_bufsz(ring);
        }
+EOF
+    add_test 'have IGB_NTA' <next_to_alloc;
+       }
 EOF
   fi # igb
   
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 26eabe4ff..8ec587d72 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -252,7 +252,9 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
+#ifdef NETMAP_LINUX_HAVE_IGB_NTA
 			rxr->next_to_alloc = nic_i;
+#endif /* NETMAP_LINUX_HAVE_IGB_NTA */
 			kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;

From 478379f414075bdd02d70686f2aba2a381dc78dc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 20 Mar 2018 11:37:40 +0100
Subject: [PATCH 0777/2207] linux/ixgbe,ixgbevf: fix typo in next_to_alloc
 checks

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index e28eb0a72..db16c9f7d 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -473,7 +473,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
 			rxr->next_to_use = rxr->next_to_clean;
-#ifdef NETMAP_LINUX_IXGBE_HAVE_NTA
+#ifdef NETMAP_LINUX_HAVE_NTA
 			rxr->next_to_alloc = rxr->next_to_clean;
 #endif /* NETMAP_LINUX_HAVE_NTA */
 			kring->nr_hwtail = nm_i;

From 030089b70bf51fe86af1020a51882c49ac0525b3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 20 Mar 2018 11:40:55 +0100
Subject: [PATCH 0778/2207] linux/ixgbevf: don't assume that _RXBUFFER_2048 is
 defined

---
 LINUX/ixgbe_netmap_linux.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index db16c9f7d..4dfa5d5f4 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -693,7 +693,11 @@ static unsigned
 nm_ixgbe_rx_buf_maxsize(struct NM_IXGBE_ADAPTER *adapter)
 {
 #if defined(NM_IXGBEVF)
+#ifdef IXGBEVF_RXBUFFER_2048
        return IXGBEVF_RXBUFFER_2048;
+#else
+       return 2048;
+#endif /* IXGBEVF_RXBUFFER_2048 */
 #elif defined(NETMAP_LINUX_HAVE_IXGBE_RX_BUFSZ)
        return ixgbe_rx_bufsz(NM_IXGBE_RX_RING(adapter, 0));
 #else  /* !NETMAP_LINUX_HAVE_IXGBE_RX_BUFSZ */

From 6e6c98120573ff90c9d57b2455e634d8e53e4e5d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 22 Mar 2018 11:56:19 +0100
Subject: [PATCH 0779/2207] LINUX: README: remove obsolete warning

---
 LINUX/README | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/LINUX/README b/LINUX/README
index 8ad4ab474..535b7871b 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -288,16 +288,6 @@ COMMON PROBLEMS
   In emulated netmap mode (i.e. with unpatched drivers) VLAN tags are never
   visible by the netmap application.
 
-* if you are using e1000 with netmap, you should verify the result of the patch
-  from final-patches/vanilla--e1000--20620--31200 that was applied on
-  e1000/e1000_main.c. It was observed that when using non-vanilla kernel version
-  netmap hook that needs to be applied on e1000_clean_rx_irq is actually 
-  applied on e1000_clean_jumbo_rx_irq. As a result it will end up in packets
-  going directly from NIC Rx Rings to Host stack.
-      
-      You should fix this issue by manually patching e1000/e1000_main.c to add
-  the correct netmap hook in e1000_clean_rx_irq
-
 REVISION HISTORY
 -----------------
 

From 93a86ef080d647903ab94045bdc035ee5876d7d9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 22 Mar 2018 12:19:53 +0100
Subject: [PATCH 0780/2207] netmap_do_regif: add missing newline character in
 log statements

---
 sys/dev/netmap/netmap.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9e8f076fb..850071179 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2110,7 +2110,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 				 * cannot be used in this case. */
 				if (nbs < mtu) {
 					nm_prerr("error: netmap buf size (%u) "
-						"< device MTU (%u)", nbs, mtu);
+						"< device MTU (%u)\n", nbs, mtu);
 					error = EINVAL;
 					goto err_drop_mem;
 				}
@@ -2123,14 +2123,14 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 				if (!(na->na_flags & NAF_MOREFRAG)) {
 					nm_prerr("error: large MTU (%d) needed "
 						"but %s does not support "
-						"NS_MOREFRAG", mtu,
+						"NS_MOREFRAG\n", mtu,
 						na->ifp->if_xname);
 					error = EINVAL;
 					goto err_drop_mem;
 				} else if (nbs < na->rx_buf_maxsize) {
 					nm_prerr("error: using NS_MOREFRAG on "
 						"%s requires netmap buf size "
-						">= %u", na->ifp->if_xname,
+						">= %u\n", na->ifp->if_xname,
 						na->rx_buf_maxsize);
 					error = EINVAL;
 					goto err_drop_mem;
@@ -2138,7 +2138,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 					nm_prinf("info: netmap application on "
 						"%s needs to support "
 						"NS_MOREFRAG "
-						"(MTU=%u,netmap_buf_size=%u)",
+						"(MTU=%u,netmap_buf_size=%u)\n",
 						na->ifp->if_xname, mtu, nbs);
 				}
 			}

From 132b2feb9ed19852fb1c77a2f6441bd6e029a041 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 25 Mar 2018 11:34:05 +0200
Subject: [PATCH 0781/2207] linux/ixgbe: fix dma_pool cleanup

The previous code assumed that ixgbe_netmap_detach() would always be
called after ixgbe_netmap_krings_delete(), but the former is called
on ixgbe-netmap module removal, and this may happen while ixgbe ports
are still open in netmap mode. Hot module removal, therefore, first
caused a warning about the destruction of a busy dma_pool, and then
a null pointer dereference when the dma regions where returned to the
no-longer-existing pool.
---
 LINUX/ixgbe_netmap_linux.h | 114 +++++++++++++++++++------------------
 1 file changed, 59 insertions(+), 55 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 4dfa5d5f4..35d4c3bb3 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -626,14 +626,52 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	return 1;
 }
 
+#ifndef NM_IXGBE_USE_TDH
+static void ixgbe_netmap_destroy_heads(struct netmap_adapter *);
+static int
+ixgbe_netmap_create_heads(struct netmap_adapter *na)
+{
+	struct netmap_ixgbe_adapter *ina =
+		(struct netmap_ixgbe_adapter *)na;
+	int i;
+
+	// allocate head-writeback region
+	ina->pool = dma_pool_create("head-wb",
+			na->pdev, sizeof(u32),
+			L1_CACHE_BYTES, 0);
+	if (ina->pool == NULL) {
+		pr_err("netmap: failed to allocated head-wb pool");
+		goto err;
+	}
+
+	ina->heads = kmalloc(sizeof(struct netmap_ixgbe_head) * na->num_tx_rings,
+			GFP_KERNEL | __GFP_ZERO);
+	if (ina->heads == NULL)
+		goto err;
+	for (i = 0; i < na->num_tx_rings; i++) {
+		struct netmap_ixgbe_head *h = &ina->heads[i];
+
+		h->phead = dma_pool_alloc(ina->pool, GFP_KERNEL, &h->map);
+		if (h->phead == NULL) {
+			pr_err("netmap: failed to allocated head %d", i);
+			goto err;
+		}
+		*h->phead = 0;
+		ND("%s: phead %p *phead %x", na->tx_rings[i].name, h->phead, *h->phead);
+	}
+	return 0;
+
+err:
+	ixgbe_netmap_destroy_heads(na);
+	return ENOMEM;
+}
+
 static void
-ixgbe_netmap_krings_delete(struct netmap_adapter *na)
+ixgbe_netmap_destroy_heads(struct netmap_adapter *na)
 {
-#ifndef NM_IXGBE_USE_TDH
 	struct netmap_ixgbe_adapter *ina =
 		(struct netmap_ixgbe_adapter *)na;
 
-	ina = (struct netmap_ixgbe_adapter *)na;
 	if (ina->heads != NULL) {
 		int i;
 
@@ -646,6 +684,18 @@ ixgbe_netmap_krings_delete(struct netmap_adapter *na)
 		kfree(ina->heads);
 		ina->heads = NULL;
 	}
+	if (ina->pool != NULL) {
+		dma_pool_destroy(ina->pool);
+		ina->pool = NULL;
+	}
+}
+#endif /* !NM_IXGBE_USE_TDH */
+
+static void
+ixgbe_netmap_krings_delete(struct netmap_adapter *na)
+{
+#ifndef NM_IXGBE_USE_TDH
+	ixgbe_netmap_destroy_heads(na);
 #endif /*! NM_IXGBE_USE_TDH */
 	netmap_hw_krings_delete(na);
 }
@@ -653,11 +703,6 @@ ixgbe_netmap_krings_delete(struct netmap_adapter *na)
 static int
 ixgbe_netmap_krings_create(struct netmap_adapter *na)
 {
-#ifndef NM_IXGBE_USE_TDH
-	struct netmap_ixgbe_adapter *ina =
-		(struct netmap_ixgbe_adapter *)na;
-	int i;
-#endif /* !NM_IXGBE_USE_TDH */
         int ret;
        
 	ret = netmap_hw_krings_create(na);
@@ -665,28 +710,13 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 		return ret;
 
 #ifndef NM_IXGBE_USE_TDH
-	ret = ENOMEM;
-	ina->heads = kmalloc(sizeof(struct netmap_ixgbe_head) * na->num_tx_rings,
-			GFP_KERNEL | __GFP_ZERO);
-	if (ina->heads == NULL)
-		goto err;
-	for (i = 0; i < na->num_tx_rings; i++) {
-		struct netmap_ixgbe_head *h = &ina->heads[i];
-
-		h->phead = dma_pool_alloc(ina->pool, GFP_KERNEL, &h->map);
-		if (h->phead == NULL) {
-			pr_err("netmap: failed to allocated head %d", i);
-			goto err;
-		}
-		*h->phead = 0;
-		D("%s: phead %p *phead %x", na->tx_rings[i]->name, h->phead, *h->phead);
+	ret = ixgbe_netmap_create_heads(na);
+	if (ret) {
+		netmap_hw_krings_delete(na);
+		return ret;
 	}
-	return 0;
-
-err:
-	ixgbe_netmap_krings_delete(na);
 #endif /*! NM_IXGBE_USE_TDH */
-	return ret;
+	return 0;
 }
 
 static unsigned
@@ -733,19 +763,6 @@ static void
 ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 {
 	struct netmap_adapter na;
-#ifndef NM_IXGBE_USE_TDH
-	struct netmap_ixgbe_adapter *ina;
-	struct dma_pool *pool;
-
-	// allocate head-writeback region
-	pool = dma_pool_create("head-wb",
-			&adapter->pdev->dev, sizeof(u32),
-			L1_CACHE_BYTES, 0);
-	if (pool == NULL) {
-		pr_err("netmap: failed to allocated head-wb pool");
-		return;
-	}
-#endif /*! NM_IXGBE_USE_TDH */
 
 	bzero(&na, sizeof(na));
 
@@ -767,31 +784,18 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 
 	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter), 1)) {
 		pr_err("netmap: failed to attach netmap adapter");
-#ifndef NM_IXGBE_USE_TDH
-		dma_pool_destroy(pool);
-#endif /*! NM_IXGBE_USE_TDH */
 		return;
 	}
-#ifndef NM_IXGBE_USE_TDH
-	ina = (struct netmap_ixgbe_adapter *)NA(adapter->netdev);
-	ina->pool = pool;
-#endif /*! NM_IXGBE_USE_TDH */
 }
 
 static void
 ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter)
 {
 #ifndef NM_IXGBE_USE_TDH
-	struct netmap_ixgbe_adapter *ina;
-
 	if (!NM_NA_VALID(adapter->netdev))
 		return;
 
-	ina = (struct netmap_ixgbe_adapter *)NA(adapter->netdev);
-	if (ina->pool != NULL) {
-		dma_pool_destroy(ina->pool);
-		ina->pool = NULL;
-	}
+	ixgbe_netmap_destroy_heads(NA(adapter->netdev));
 #endif /*! NM_IXGBE_USE_TDH */
 
 	netmap_detach(adapter->netdev);

From fe13476b106ed1f4b517b1590e1dfb3f268b6e78 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 23 Mar 2018 12:49:33 +0100
Subject: [PATCH 0782/2207] ixgbe/ixgbevf: fix NS_MOREFRAG handling in the TX
 path

---
 LINUX/ixgbe_netmap_linux.h | 78 +++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 13 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 35d4c3bb3..4b7a486e3 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -237,7 +237,6 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int ring_nr = kring->ring_id;
 	u_int nm_i;	/* index into the netmap ring */
 	u_int nic_i;	/* index into the NIC ring */
-	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	/*
@@ -249,7 +248,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	/* device-specific */
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
 	struct NM_IXGBE_RING *txr = NM_IXGBE_TX_RING(adapter, ring_nr);
-	int reclaim_tx;
+	int reclaim_tx, report;
 
 	/*
 	 * First part: process new packets to send.
@@ -289,7 +288,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	nm_i = kring->nr_hwcur;
 	if (nm_i != head) {	/* we have new packets to send */
 		nic_i = netmap_idx_k2n(kring, nm_i);
-		for (n = 0; nm_i != head; n++) {
+		while (nm_i != head) {
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			uint64_t paddr;
@@ -297,22 +296,76 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			union ixgbe_adv_tx_desc *curr = NM_IXGBE_TX_DESC(txr, nic_i);
-			int hw_flags = (slot->flags & NS_REPORT ||
-				nic_i == 0 || nic_i == report_frequency
-				) ? IXGBE_TXD_CMD_RS : 0;
+			unsigned int hw_flags =	IXGBE_ADVTXD_DTYP_DATA | IXGBE_ADVTXD_DCMD_DEXT |
+				IXGBE_ADVTXD_DCMD_IFCS;
+			u_int totlen = len;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
-			if (!(slot->flags & NS_MOREFRAG))
-				hw_flags |= IXGBE_TXD_CMD_EOP;
+			report = slot->flags & NS_REPORT ||
+				nic_i == 0 ||
+				nic_i == report_frequency;
+			if (slot->flags & NS_MOREFRAG) {
+				/* There is some duplicated code here, but
+				 * mixing everything up in the outer loop makes
+				 * things less transparent, and it also adds
+				 * unnecessary instructions in the fast path
+				 */
+				union ixgbe_adv_tx_desc *first = curr;
+
+				first->read.buffer_addr = htole64(paddr);
+				first->read.cmd_type_len = htole32(len | hw_flags);
+				netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
+						&paddr, len, NR_TX);
+				/* avoid setting the FCS flag in the
+				 * descriptors after the first, for safety
+				 */
+				hw_flags &= ~IXGBE_ADVTXD_DCMD_IFCS;
+				for (;;) {
+					nm_i = nm_next(nm_i, lim);
+					nic_i = nm_next(nic_i, lim);
+					/* remember that we have to ask for a
+					 * report each time we move past half a
+					 * ring
+					 */
+					report |= nic_i == 0 ||
+						nic_i == report_frequency;
+					if (nm_i == head) {
+						// XXX should we accept incomplete packets?
+						return EINVAL;
+					}
+					slot = &ring->slot[nm_i];
+					len = slot->len;
+					addr = PNMB(na, slot, &paddr);
+					NM_CHECK_ADDR_LEN(na, addr, len);
+					curr = NM_IXGBE_TX_DESC(txr, nic_i);
+					totlen += len;
+					if (!(slot->flags & NS_MOREFRAG))
+						break;
+					curr->read.buffer_addr = htole64(paddr);
+					curr->read.olinfo_status = 0;
+					curr->read.cmd_type_len = htole32(len | hw_flags);
+
+					netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
+							&paddr, len, NR_TX);
+				}
+				first->read.olinfo_status =
+					htole32(totlen << IXGBE_ADVTXD_PAYLEN_SHIFT);
+				totlen = 0;
+			}
+
+			/* curr now always points to the last descriptor of a packet
+			 * (which is also the first for single-slot packets)
+			 *
+			 * EOP and RS must be set only in this descriptor.
+			 */
+			hw_flags |= IXGBE_TXD_CMD_EOP | (report ? IXGBE_TXD_CMD_RS : 0);
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
 			/* Fill the slot in the NIC ring. */
 			curr->read.buffer_addr = htole64(paddr);
-			curr->read.olinfo_status = htole32(len << IXGBE_ADVTXD_PAYLEN_SHIFT);
-			curr->read.cmd_type_len = htole32(len | hw_flags |
-				IXGBE_ADVTXD_DTYP_DATA | IXGBE_ADVTXD_DCMD_DEXT |
-				IXGBE_ADVTXD_DCMD_IFCS);
+			curr->read.olinfo_status = htole32(totlen << IXGBE_ADVTXD_PAYLEN_SHIFT);
+			curr->read.cmd_type_len = htole32(len | hw_flags);
 			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -329,7 +382,6 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	 */
 #ifndef NM_IXGBE_USE_TDH
 	(void)reclaim_tx;
-	(void)report_frequency;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
 		u32 h = NM_ACCESS_ONCE(*ina->heads[ring_nr].phead);
 		ND(5, "%s: h %d", kring->name, h);

From 904407292be462fdfa8826b4439b462f688778fc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Mar 2018 11:26:12 +0200
Subject: [PATCH 0783/2207] linux: veth: import updates from netmap_pipe.c

---
 LINUX/veth_netmap.h | 100 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 81 insertions(+), 19 deletions(-)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 1cc4a7213..5a0cea152 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -113,7 +113,7 @@ veth_netmap_dtor(struct netmap_adapter *na)
 }
 
 /*
- * Register/unregister. We are already under netmap lock.
+ * Register/unregister. We are already under RCU lock.
  * This register function is similar to the one used by
  * pipes; in addition to the regular tasks (commit the rings
  * in/out netmap node and call nm_(set|clear)_native_flags),
@@ -156,7 +156,11 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		/* create all missing needed rings on the other end */
+		/* create all missing needed rings on the other end.
+		 * They have all been marked as fake in the krings_create
+		 * above, so the will not be filled with buffers
+		 */
+
 		error = netmap_mem_rings_create(peer_na);
 		if (error) {
 			return error;
@@ -168,6 +172,30 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_on(kring)) {
+					struct netmap_kring *sring, *dring;
+
+					/* copy the buffers from the non-fake ring */
+					if (kring->nr_kflags & NKR_FAKERING) {
+						sring = kring->pipe;
+						dring = kring;
+					} else {
+						sring = kring;
+						dring = kring->pipe;
+					}
+					memcpy(dring->ring->slot,
+					       sring->ring->slot,
+					       sizeof(struct netmap_slot) *
+							sring->nkr_num_slots);
+					/* mark both rings as fake and needed,
+					 * so that buffers will not be
+					 * deleted by the standard machinery
+					 * (we will delete them by ourselves in
+					 * veth_netmap_krings_delete)
+					 */
+					sring->nr_kflags |=
+						(NKR_FAKERING | NKR_NEEDRING);
+					dring->nr_kflags |=
+						(NKR_FAKERING | NKR_NEEDRING);
 					kring->nr_mode = NKR_NETMAP_ON;
 				}
 			}
@@ -185,20 +213,9 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 
 				if (nm_kring_pending_off(kring)) {
 					kring->nr_mode = NKR_NETMAP_OFF;
-					/* If hw kring, mark the peer kring
-					 * as no longer needed by us (it may
-					 * still be kept if sombody else is
-					 * using it).
-					 */
-					if (kring->pipe) {
-						kring->pipe->nr_kflags &=
-								~NKR_NEEDRING;
-					}
 				}
 			}
 		}
-		/* delete all the peer rings that are no longer needed */
-		netmap_mem_rings_delete(peer_na);
 		if (netmap_verbose) {
 			D("unregistered veth %s", na->name);
 		}
@@ -221,6 +238,7 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 	return 0;
 }
 
+/* See netmap_pipe_krings_create(). */
 static int
 veth_netmap_krings_create(struct netmap_adapter *na)
 {
@@ -264,6 +282,8 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 		for (i = 0; i < nma_get_nrings(na, t); i++) {
 			NMR(na, t)[i]->pipe = NMR(peer_na, r)[i];
 			NMR(peer_na, r)[i]->pipe = NMR(na, t)[i];
+			/* mark all peer-adapter rings as fake */
+			NMR(peer_na, r)[i]->nr_kflags |= NKR_FAKERING;
 		}
 	}
 
@@ -282,10 +302,13 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 	return error;
 }
 
+/* See netmap_pipe_krings_delete(). */
 static void
 veth_netmap_krings_delete(struct netmap_adapter *na)
 {
-	struct netmap_adapter *peer_na;
+	struct netmap_adapter *peer_na, *sna;
+	enum txrx t;
+	int i;
 
 	if (krings_needed(na)) {
 		/* Our krings are needed by the other peer, so we
@@ -293,7 +316,7 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 		 * our krings when it needs to destroy its krings. */
 		if (netmap_verbose) {
 			D("krings for %s are still needed by its peer",
-			  na->name);
+					na->name);
 		}
 		return;
 	}
@@ -302,10 +325,6 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 		D("Delete krings for %s and its peer", na->name);
 	}
 
-	/* Destroy my krings. */
-	netmap_krings_delete(na);
-
-	/* Destroy the krings of our peer. */
 	rcu_read_lock();
 	peer_na = veth_get_peer_na(na);
 	if (!peer_na) {
@@ -314,6 +333,49 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 		return;
 	}
 
+	sna = na;
+cleanup:
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(sna, t) + 1; i++) {
+			struct netmap_kring *kring = NMR(sna, t)[i];
+			struct netmap_ring *ring = kring->ring;
+			uint32_t j, lim = kring->nkr_num_slots - 1;
+
+			ND("%s ring %p hwtail %u hwcur %u",
+				kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
+
+			if (ring == NULL)
+				continue;
+
+			if (kring->nr_hwtail == kring->nr_hwcur)
+				ring->slot[kring->nr_hwtail].buf_idx = 0;
+
+			for (j = nm_next(kring->nr_hwtail, lim);
+			     j != kring->nr_hwcur;
+			     j = nm_next(j, lim))
+			{
+				ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
+				ring->slot[j].buf_idx = 0;
+			}
+			kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING);
+		}
+
+	}
+	if (sna != peer_na && peer_na->tx_rings) {
+		sna = peer_na;
+		goto cleanup;
+	}
+
+	netmap_mem_rings_delete(na);
+	netmap_krings_delete(na); /* also zeroes tx_rings etc. */
+
+	if (peer_na->tx_rings == NULL) {
+		/* already deleted, we must be on an
+                 * cleanup-after-error path */
+		rcu_read_unlock();
+		return;
+	}
+	netmap_mem_rings_delete(peer_na);
 	netmap_krings_delete(peer_na);
 	rcu_read_unlock();
 }

From 23d882bfb47d2397d93b84c123928958c7b78db7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Mar 2018 18:12:14 +0200
Subject: [PATCH 0784/2207] Revert "linux: ixgbe: don't touch SRRCTL when
 entering netmap mode"

This reverts commit c6754007f989008fb0ff8cdfec2bab29260a510b.
---
 LINUX/ixgbe_netmap_linux.h | 40 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 4b7a486e3..06e5bb84a 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -111,6 +111,37 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 }
 #endif /* NETMAP_LINUX_IXGBE_HAVE_DISABLE */
 
+/*
+ * In netmap mode, overwrite the srrctl register with netmap_buf_size
+ * to properly configure the Receive Buffer Size
+ */
+static void
+ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_RING *rx_ring)
+{
+	struct netmap_adapter *na = NA(adapter->netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 srrctl;
+	u8 reg_idx = rx_ring->reg_idx;
+
+	if (hw->mac.type == ixgbe_mac_82598EB) {
+		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
+		reg_idx &= mask;
+	}
+	srrctl = IXGBE_RX_HDR_SIZE << 2; /*IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT */
+	srrctl |= NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+	D("bufsz: %d srrctl: %d", NETMAP_BUF_SIZE(na),
+		NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);
+	/*
+	 * XXX
+	 * With Advanced RX descriptor, the address needs to be rewritten,
+	 * but with Legacy RX descriptor, it simply has to zero the status
+	 * byte in the descriptor to make it ready for reuse by hardware.
+	 * (ixgbe datasheet - Section 7.1.9)
+	 */
+	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
+}
+
 #ifdef NETMAP_LINUX_IXGBE_HAVE_NTA
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBE_HAVE_NTA */
@@ -155,6 +186,13 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 	RD(5, "per-queue irq disable not supported");
 }
 
+static void
+ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_RING *rx_ring)
+{
+	// TODO
+	D("not supported");
+}
+
 #ifdef NETMAP_LINUX_IXGBEVF_HAVE_NTA
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBEVF_HAVE_NTA */
@@ -655,6 +693,8 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
         /* same as in ixgbe_setup_transmit_ring() */
 	if (!slot)
 		return 0;	// not in native netmap mode
+	// XXX can we move it later ?
+	ixgbe_netmap_configure_srrctl(adapter, ring);
 
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 

From 11e8dcce9d0f7a4951e6705d258547ce4d9066fe Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Mar 2018 18:20:34 +0200
Subject: [PATCH 0785/2207] linux: ixgbe::nm_config: use netmap buffer size as
 rx_buf_maxsize

---
 LINUX/ixgbe_netmap_linux.h | 20 ++------------------
 1 file changed, 2 insertions(+), 18 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 06e5bb84a..0b6b80c9e 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -811,22 +811,6 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 	return 0;
 }
 
-static unsigned
-nm_ixgbe_rx_buf_maxsize(struct NM_IXGBE_ADAPTER *adapter)
-{
-#if defined(NM_IXGBEVF)
-#ifdef IXGBEVF_RXBUFFER_2048
-       return IXGBEVF_RXBUFFER_2048;
-#else
-       return 2048;
-#endif /* IXGBEVF_RXBUFFER_2048 */
-#elif defined(NETMAP_LINUX_HAVE_IXGBE_RX_BUFSZ)
-       return ixgbe_rx_bufsz(NM_IXGBE_RX_RING(adapter, 0));
-#else  /* !NETMAP_LINUX_HAVE_IXGBE_RX_BUFSZ */
-       return 4096; /* stay on the safe side */
-#endif /* !NETMAP_LINUX_HAVE_IXGBE_RX_BUFSZ */
-}
-
 static int
 ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
@@ -837,7 +821,7 @@ ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 		return ret;
 	}
 
-	info->rx_buf_maxsize = nm_ixgbe_rx_buf_maxsize(adapter);
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
 	return 0;
 }
@@ -865,7 +849,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.num_rx_desc = NM_IXGBE_RX_RING(adapter, 0)->count;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
-	na.rx_buf_maxsize = nm_ixgbe_rx_buf_maxsize(adapter);
+	na.rx_buf_maxsize = 1500; /* will be overwritten by nm_config */
 	na.nm_txsync = ixgbe_netmap_txsync;
 	na.nm_rxsync = ixgbe_netmap_rxsync;
 	na.nm_register = ixgbe_netmap_reg;

From 90ebfb8b520da85a34da01c17937f1a3eda6294b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 28 Mar 2018 11:02:22 +0200
Subject: [PATCH 0786/2207] linux: veth: use peer_ref to handle creation and
 destruction of na

---
 LINUX/veth_netmap.h | 130 +++++++++++++++-----------------------------
 1 file changed, 45 insertions(+), 85 deletions(-)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 5a0cea152..be0843d97 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -42,7 +42,8 @@ struct netmap_veth_adapter {
 	int peer_ref;
 };
 
-/* To be called under RCU read lock */
+/* To be called under RCU read lock. This also sets peer_ref in the
+ * same way netmap_get_pipe_na() does. */
 static struct netmap_adapter *
 veth_get_peer_na(struct netmap_adapter *na)
 {
@@ -53,54 +54,26 @@ veth_get_peer_na(struct netmap_adapter *na)
 		(struct netmap_veth_adapter *)na;
 
 	if (vna->peer == NULL) {
-		rcu_read_lock();
+		/* Only one of the two endpoint enters here,
+		 * and only once. */
 		peer_ifp = rcu_dereference(priv->peer);
 		if (!peer_ifp) {
-			rcu_read_unlock();
 			return NULL;
 		}
-		/* cache the na pointer so that we can retrieve it
-		 * and do our clean-up even when the peer_ifp is
-		 * detached from us
-		 */
+		/* Cross link the peer netmap adapters. Note that we
+		 * can retrieve the peer to do our clean-up even if
+		 * the peer_ifp is detached from us. */
 		vna->peer = (struct netmap_veth_adapter *)NA(peer_ifp);
+		vna->peer->peer = vna;
+
+		/* Get a reference to the other endpoint. */
 		netmap_adapter_get(&vna->peer->up.up);
 		vna->peer_ref = 1;
-		/* also set the cross reference from the peer_na to us */
-		vna->peer->peer = vna;
-		rcu_read_unlock();
 	}
 
 	return &vna->peer->up.up;
 }
 
-/*
- * Returns true if our krings needed by the other peer, false
- * if they are not, or they do not exist.
- */
-static bool
-krings_needed(struct netmap_adapter *na)
-{
-	enum txrx t;
-	int i;
-
-	if (na->tx_rings == NULL) {
-		return false;
-	}
-
-	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = NMR(na, t)[i];
-
-			if (kring->nr_kflags & NKR_NEEDRING) {
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
 static void
 veth_netmap_dtor(struct netmap_adapter *na)
 {
@@ -225,8 +198,9 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		veth_open(ifp);
 	}
 
-	if (vna->peer_ref)
+	if (vna->peer_ref) {
 		return 0;
+	}
 	if (onoff) {
 		vna->peer->peer_ref = 0;
 		netmap_adapter_put(na);
@@ -242,63 +216,57 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 static int
 veth_netmap_krings_create(struct netmap_adapter *na)
 {
+	struct netmap_veth_adapter *vna = (struct netmap_veth_adapter *)na;
 	struct netmap_adapter *peer_na;
 	int error = 0;
 	enum txrx t;
 
-	if (krings_needed(na)) {
-		/* Our krings are already needed by our peer, which
-		 * means they were already created. */
-		if (netmap_verbose) {
-			D("krings already created for %s, nothing to do",
-			  na->name);
-		}
-		return 0;
-	}
-
+	/* The nm_krings_create callback is called first in netmap_do_regif(),
+	 * so the the cross linking happens now (if this is the first endpoint
+	 * to register). */
 	rcu_read_lock();
 	peer_na = veth_get_peer_na(na);
+	rcu_read_unlock();
 	if (!peer_na) {
-		rcu_read_unlock();
 		D("veth peer not found");
 		return ENXIO;
 	}
 
-	/* create my krings */
-	error = netmap_krings_create(na, 0);
-	if (error)
-		goto err;
+	if (vna->peer_ref) {
 
-	/* create the krings of the other end */
-	error = netmap_krings_create(peer_na, 0);
-	if (error)
-		goto del_krings1;
+		/* create my krings */
+		error = netmap_krings_create(na, 0);
+		if (error)
+			return error;
 
-	/* cross link the krings (only the hw ones, not the host krings) */
-	for_rx_tx(t) {
-		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-		int i;
-
-		for (i = 0; i < nma_get_nrings(na, t); i++) {
-			NMR(na, t)[i]->pipe = NMR(peer_na, r)[i];
-			NMR(peer_na, r)[i]->pipe = NMR(na, t)[i];
-			/* mark all peer-adapter rings as fake */
-			NMR(peer_na, r)[i]->nr_kflags |= NKR_FAKERING;
-		}
-	}
+		/* create the krings of the other end */
+		error = netmap_krings_create(peer_na, 0);
+		if (error)
+			goto del_krings1;
 
-	rcu_read_unlock();
+		/* cross link the krings (only the hw ones, not
+		 * the host krings) */
+		for_rx_tx(t) {
+			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
+			int i;
 
-	if (netmap_verbose) {
-		D("created krings for %s and its peer", na->name);
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
+				NMR(na, t)[i]->pipe = NMR(peer_na, r)[i];
+				NMR(peer_na, r)[i]->pipe = NMR(na, t)[i];
+				/* mark all peer-adapter rings as fake */
+				NMR(peer_na, r)[i]->nr_kflags |= NKR_FAKERING;
+			}
+		}
+
+		if (netmap_verbose) {
+			D("created krings for %s and its peer", na->name);
+		}
 	}
 
 	return 0;
 
 del_krings1:
 	netmap_krings_delete(na);
-err:
-	rcu_read_unlock();
 	return error;
 }
 
@@ -306,18 +274,12 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 static void
 veth_netmap_krings_delete(struct netmap_adapter *na)
 {
+	struct netmap_veth_adapter *vna = (struct netmap_veth_adapter *)na;
 	struct netmap_adapter *peer_na, *sna;
 	enum txrx t;
 	int i;
 
-	if (krings_needed(na)) {
-		/* Our krings are needed by the other peer, so we
-		 * do nothing here, and let the peer destroy also
-		 * our krings when it needs to destroy its krings. */
-		if (netmap_verbose) {
-			D("krings for %s are still needed by its peer",
-					na->name);
-		}
+	if (!vna->peer_ref) {
 		return;
 	}
 
@@ -327,8 +289,8 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 
 	rcu_read_lock();
 	peer_na = veth_get_peer_na(na);
+	rcu_read_unlock();
 	if (!peer_na) {
-		rcu_read_unlock();
 		D("veth peer not found");
 		return;
 	}
@@ -372,12 +334,10 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 	if (peer_na->tx_rings == NULL) {
 		/* already deleted, we must be on an
                  * cleanup-after-error path */
-		rcu_read_unlock();
 		return;
 	}
 	netmap_mem_rings_delete(peer_na);
 	netmap_krings_delete(peer_na);
-	rcu_read_unlock();
 }
 
 static void

From a1a457730c6a30affcd5ee349292540941b64ec9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Mar 2018 11:25:59 +0200
Subject: [PATCH 0787/2207] linux/ixgbe: fix srrctl setting

There is no need to set the header size, since we are not using
packet-split.

More importantly, the netmap buffer size must be rounded to next KiB.
---
 LINUX/ixgbe_netmap_linux.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 0b6b80c9e..00068510f 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -127,10 +127,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
 		reg_idx &= mask;
 	}
-	srrctl = IXGBE_RX_HDR_SIZE << 2; /*IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT */
-	srrctl |= NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-	D("bufsz: %d srrctl: %d", NETMAP_BUF_SIZE(na),
-		NETMAP_BUF_SIZE(na) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);
+	srrctl = ((NETMAP_BUF_SIZE(na) + 1023) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);
 	/*
 	 * XXX
 	 * With Advanced RX descriptor, the address needs to be rewritten,
@@ -139,6 +136,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	 * (ixgbe datasheet - Section 7.1.9)
 	 */
 	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+	ND("bufsz: %d srrctl: %x", NETMAP_BUF_SIZE(na), srrctl);
 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
 }
 

From d356b719a88e7400edf2c54b195bc84996a52186 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Mar 2018 12:13:48 +0200
Subject: [PATCH 0788/2207] Anticipate the lut caching during regif

The ixgbe nm_config() callback, and possibily others, needs the netmap
buffer size, but this is only computed when the allocator has been
configured and the lut info has been cached in the netmap adapter.
---
 sys/dev/netmap/netmap.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 850071179..48cb9d190 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2082,8 +2082,6 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	int error;
 
 	NMG_LOCK_ASSERT();
-	/* ring configuration may have changed, fetch from the card */
-	netmap_update_config(na);
 	priv->np_na = na;     /* store the reference */
 	error = netmap_set_ringid(priv, nr_mode, nr_ringid, nr_flags);
 	if (error)
@@ -2093,6 +2091,17 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		goto err;
 
 	if (na->active_fds == 0) {
+
+		/* cache the allocator info in the na */
+		error = netmap_mem_get_lut(na->nm_mem, &na->na_lut);
+		if (error)
+			goto err_drop_mem;
+		ND("lut %p bufs %u size %u", na->na_lut.lut, na->na_lut.objtotal,
+					    na->na_lut.objsize);
+
+		/* ring configuration may have changed, fetch from the card */
+		netmap_update_config(na);
+
 		/*
 		 * If this is the first registration of the adapter,
 		 * perform sanity checks and create the in-kernel view
@@ -2150,7 +2159,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 */
 		error = na->nm_krings_create(na);
 		if (error)
-			goto err_drop_mem;
+			goto err_put_lut;
 
 	}
 
@@ -2174,21 +2183,12 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		goto err_del_rings;
 	}
 
-	if (na->active_fds == 0) {
-		/* cache the allocator info in the na */
-		error = netmap_mem_get_lut(na->nm_mem, &na->na_lut);
-		if (error)
-			goto err_del_if;
-		ND("lut %p bufs %u size %u", na->na_lut.lut, na->na_lut.objtotal,
-					    na->na_lut.objsize);
-	}
-
 	if (nm_kring_pending(priv)) {
 		/* Some kring is switching mode, tell the adapter to
 		 * react on this. */
 		error = na->nm_register(na, 1);
 		if (error)
-			goto err_put_lut;
+			goto err_del_if;
 	}
 
 	/* Commit the reference. */
@@ -2204,9 +2204,6 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 
 	return 0;
 
-err_put_lut:
-	if (na->active_fds == 0)
-		memset(&na->na_lut, 0, sizeof(na->na_lut));
 err_del_if:
 	netmap_mem_if_delete(na, nifp);
 err_del_rings:
@@ -2216,6 +2213,9 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 err_del_krings:
 	if (na->active_fds == 0)
 		na->nm_krings_delete(na);
+err_put_lut:
+	if (na->active_fds == 0)
+		memset(&na->na_lut, 0, sizeof(na->na_lut));
 err_drop_mem:
 	netmap_mem_drop(na);
 err:

From 1a06731c248c3bb5b6f7842c656ce3b89489cc96 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Mar 2018 13:00:41 +0200
Subject: [PATCH 0789/2207] linux/ixgbe: fix warning

---
 LINUX/ixgbe_netmap_linux.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 00068510f..9386bb537 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -812,7 +812,6 @@ ixgbe_netmap_krings_create(struct netmap_adapter *na)
 static int
 ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
-	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(na->ifp);
 	int ret = netmap_rings_config_get(na, info);
 
 	if (ret) {

From 8ed83a1837d4fff490017408a1358f96257cbaea Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Mar 2018 13:01:10 +0200
Subject: [PATCH 0790/2207] log NS_MOREFRAG warning only when opening for RX

---
 sys/dev/netmap/netmap.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 48cb9d190..fe9f68a35 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2004,6 +2004,12 @@ netmap_krings_put(struct netmap_priv_d *priv)
 	}
 }
 
+static int
+nm_priv_rx_enabled(struct netmap_priv_d *priv)
+{
+	return (priv->np_qfirst[NR_RX] != priv->np_qlast[NR_RX]);
+}
+
 /*
  * possibly move the interface to netmap-mode.
  * If success it returns a pointer to netmap_if, otherwise NULL.
@@ -2107,11 +2113,14 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 * perform sanity checks and create the in-kernel view
 		 * of the netmap rings (the netmap krings).
 		 */
-		if (na->ifp) {
+		if (na->ifp && nm_priv_rx_enabled(priv)) {
 			/* This netmap adapter is attached to an ifnet. */
 			unsigned nbs = netmap_mem_bufsize(na->nm_mem);
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
 
+			ND("mtu %d rx_buf_maxsize %d netmap_buf_size %d",
+					mtu, na->rx_buf_maxsize, nbs);
+
 			if (mtu <= na->rx_buf_maxsize) {
 				/* The MTU fits a single NIC slot. We only
 				 * Need to check that netmap buffers are

From ddc49d4be75c08991e0b1cc77833f66930efb562 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Mar 2018 14:07:46 +0200
Subject: [PATCH 0791/2207] mem: use actual number of objects when unmapping

Before this patch, netmap_mem_unmap() was relying on the _objtotal field
for the number of clusters to unmap.  However, the actual number of
objects is stored in the objtotal field, which be less than _objtotal if
allocation failed midway. The lut entries beyond objtotal are garbage,
and therefore netmap_mem_unmap() was sometimes causing panics.
---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c014a930d..c732e9712 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1507,7 +1507,7 @@ netmap_mem_reset_all(struct netmap_mem_d *nmd)
 static int
 netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 {
-	int i, lim = p->_objtotal;
+	int i, lim = p->objtotal;
 	struct netmap_lut *lut = &na->na_lut;
 
 	if (na == NULL || na->pdev == NULL)

From 601c55312b78ab470838cc42ee5687614f0d9cd9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 2 Apr 2018 10:40:05 +0200
Subject: [PATCH 0792/2207] linux: fix warning

---
 LINUX/netmap_linux.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 352b4e5fd..a7df75d25 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2335,7 +2335,9 @@ static int linux_netmap_init(void)
 #endif /* WITH_GENERIC */
 	return 0;
 
+#ifdef WITH_GENERIC
 sink_fini:
+#endif /* WITH_GENERIC */
 #ifdef WITH_SINK
 	netmap_sink_fini();
 ptnetmap_fini:

From 9e055ffa01c74366b1ddb4bcaa4f668479e07075 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 2 Apr 2018 10:42:12 +0200
Subject: [PATCH 0793/2207] linux/e1000e: silence debug message

---
 LINUX/if_e1000e_netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 75c91e3ad..914997f93 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -48,13 +48,13 @@ char netmap_e1000e_driver_name[] = "e1000e" NETMAP_LINUX_DRIVER_SUFFIX;
  * Adaptation to different versions of the driver.
  */
 #ifdef NETMAP_LINUX_HAVE_E1000E_EXT_RXDESC
-#warning this driver uses extended descriptors
+//#warning this driver uses extended descriptors
 #define NM_E1K_RX_DESC_T	union e1000_rx_desc_extended
 #define	NM_E1R_RX_STATUS	wb.upper.status_error
 #define	NM_E1R_RX_LENGTH	wb.upper.length
 #define	NM_E1R_RX_BUFADDR	read.buffer_addr
 #else
-#warning this driver uses regular descriptors
+//#warning this driver uses regular descriptors
 #define E1000_RX_DESC_EXT	E1000_RX_DESC	// XXX workaround
 #define NM_E1K_RX_DESC_T	struct e1000_rx_desc
 #define	NM_E1R_RX_STATUS	status

From e24eb26d55f4164beea3376e9958e5772b481e54 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 2 Apr 2018 11:16:08 +0200
Subject: [PATCH 0794/2207] linux/generic: check for extack in Qdisc init

---
 LINUX/configure      | 10 ++++++++++
 LINUX/netmap_linux.c | 10 +++++++---
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 945c432b5..f62037fa7 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1564,6 +1564,16 @@ EOF
 	}
 EOF
 
+# check for extack in Qdisc_ops init callback
+  add_test 'have QDISC_EXTACK' <
+
+	int
+	dummy(struct Qdisc_ops *ops, struct netlink_ext_ack *extack) {
+		return ops->init(NULL, NULL, extack);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a7df75d25..3e656e883 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -635,7 +635,11 @@ struct nm_generic_qdisc {
 };
 
 static int
-generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt)
+generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt
+#ifdef NETMAP_LINUX_HAVE_QDISC_EXTACK
+		, struct netlink_ext_ack *extack
+#endif /* NETMAP_LINUX_HAVE_QDISC_EXTACK */
+	)
 {
 	struct nm_generic_qdisc *priv = NULL;
 
@@ -649,8 +653,8 @@ generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt)
 		uint32_t *limit = nla_data(opt);
 
 		if (nla_len(opt) < sizeof(*limit) || *limit <= 0) {
-			D("Invalid netlink attribute");
-			return EINVAL;
+			NL_SET_ERR_MSG(extack, "Invalid netlink attribute");
+			return -EINVAL;
 		}
 		priv->limit = *limit;
 	}

From c8a8b374ba8dba6c644d74a42c96f3b99b286e02 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 2 Apr 2018 11:49:54 +0200
Subject: [PATCH 0795/2207] linux/generic: use extack only when defined

---
 LINUX/netmap_linux.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 3e656e883..1d5e6594c 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -653,7 +653,11 @@ generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt
 		uint32_t *limit = nla_data(opt);
 
 		if (nla_len(opt) < sizeof(*limit) || *limit <= 0) {
+#ifdef NETMAP_LINUX_HAVE_QDISC_EXTACK
 			NL_SET_ERR_MSG(extack, "Invalid netlink attribute");
+#else
+			D("Invalid netlink attribute");
+#endif /* NETMAP_LINUX_HAVE_QDISC_EXTACK */
 			return -EINVAL;
 		}
 		priv->limit = *limit;

From 27eb85d88d588cad1ad3ca8669213abad85ea0a2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 26 Mar 2018 16:01:38 +0200
Subject: [PATCH 0796/2207] linux/i40e: set the RS flag only on the last TX
 slot

---
 LINUX/i40e_netmap_linux.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index bad62871a..a07e0713a 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -382,9 +382,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 
 			/* device-specific */
 			struct i40e_tx_desc *curr = I40E_TX_DESC(txr, nic_i);
-			u64 hw_flags = (slot->flags & NS_REPORT ||
-				nic_i == 0 || nic_i == report_frequency) ?
-				((u64)I40E_TX_DESC_CMD_RS << I40E_TXD_QW1_CMD_SHIFT) : 0;
+			u64 hw_flags = 0;
 
 			/* prefetch for next round */
 			__builtin_prefetch(&ring->slot[nm_i + 1]);
@@ -393,7 +391,13 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
-				hw_flags |= ((u64)(I40E_TX_DESC_CMD_EOP) << I40E_TXD_QW1_CMD_SHIFT);
+				hw_flags |= ((u64)(I40E_TX_DESC_CMD_EOP) <<
+						I40E_TXD_QW1_CMD_SHIFT);
+				if (slot->flags & NS_REPORT || nic_i == 0 ||
+						nic_i == report_frequency) {
+					hwflags |= ((u64)I40E_TX_DESC_CMD_RS <<
+							I40E_TXD_QW1_CMD_SHIFT);
+				}
 			}
 			if (slot->flags & NS_BUF_CHANGED) {
 				/* buffer has changed, reload map */

From 0e15788252170728e83ae964afc7ae869d00dbed Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 4 Apr 2018 13:10:41 +0200
Subject: [PATCH 0797/2207] linux: patches for vanilla 4.17 drivers

---
 .../vanilla--forcedeth.c--20626--99999        |   2 +-
 .../final-patches/vanilla--igb--20621--20623  |   2 +-
 .../final-patches/vanilla--igb--20623--30200  |   2 +-
 .../final-patches/vanilla--igb--30200--30800  |   2 +-
 .../final-patches/vanilla--igb--30800--30f00  |   2 +-
 .../final-patches/vanilla--igb--30f00--40100  |   2 +-
 .../final-patches/vanilla--igb--40100--40400  |   2 +-
 .../final-patches/vanilla--igb--40400--99999  |   2 +-
 .../vanilla--ixgbe--20620--20622              |   2 +-
 .../vanilla--ixgbe--20622--20623              |   2 +-
 .../vanilla--ixgbe--20623--20625              |   2 +-
 .../vanilla--ixgbe--20625--20626              |   2 +-
 .../vanilla--ixgbe--20626--30100              |   2 +-
 .../vanilla--ixgbe--30100--30200              |   2 +-
 .../vanilla--ixgbe--30200--30400              |   2 +-
 .../vanilla--ixgbe--30400--30500              |   2 +-
 .../vanilla--ixgbe--30500--30700              |   2 +-
 .../vanilla--ixgbe--30700--30a00              |   2 +-
 .../vanilla--ixgbe--30a00--30d00              |   2 +-
 .../vanilla--ixgbe--30d00--30f00              |   2 +-
 .../vanilla--ixgbe--30f00--31300              |   2 +-
 .../vanilla--ixgbe--31300--40900              |   2 +-
 ...00--99999 => vanilla--ixgbe--40900--41000} |   2 +-
 .../vanilla--ixgbe--41000--99999              | 126 ++++++++++++++++++
 .../vanilla--ixgbevf--20622--30500            |   2 +-
 .../vanilla--ixgbevf--30500--30600            |   2 +-
 .../vanilla--ixgbevf--30600--30700            |   2 +-
 .../vanilla--ixgbevf--30700--30d00            |   2 +-
 .../vanilla--ixgbevf--30d00--30e00            |   2 +-
 .../vanilla--ixgbevf--30e00--30f00            |   2 +-
 .../vanilla--ixgbevf--30f00--31200            |   2 +-
 .../vanilla--ixgbevf--31200--31300            |   2 +-
 .../vanilla--ixgbevf--31300--40000            |   2 +-
 .../vanilla--ixgbevf--40000--40700            |   2 +-
 .../vanilla--ixgbevf--40700--40800            |   2 +-
 .../vanilla--ixgbevf--40800--40900            |   2 +-
 .../vanilla--ixgbevf--40900--99999            |   2 +-
 .../vanilla--r8169.c--20620--20625            |   2 +-
 .../vanilla--r8169.c--20625--20626            |   2 +-
 .../vanilla--r8169.c--20626--30400            |   2 +-
 .../vanilla--veth.c--20620--30900             |   2 +-
 .../vanilla--veth.c--30900--30f00             |   2 +-
 .../vanilla--veth.c--30f00--99999             |   2 +-
 .../vanilla--virtio_net.c--20622--20625       |   2 +-
 .../vanilla--virtio_net.c--20625--20626       |   2 +-
 .../vanilla--virtio_net.c--20626--30300       |   2 +-
 .../vanilla--virtio_net.c--30300--30500       |   2 +-
 .../vanilla--virtio_net.c--30500--30800       |   2 +-
 .../vanilla--virtio_net.c--30800--30b00       |   2 +-
 .../vanilla--virtio_net.c--30b00--31100       |   2 +-
 .../vanilla--virtio_net.c--31100--31300       |   2 +-
 .../vanilla--virtio_net.c--31300--40100       |   2 +-
 .../vanilla--virtio_net.c--40100--40900       |   2 +-
 .../vanilla--virtio_net.c--40900--40c00       |   2 +-
 .../vanilla--virtio_net.c--40c00--40f00       |   2 +-
 ...99 => vanilla--virtio_net.c--40f00--41000} |   2 +-
 .../vanilla--virtio_net.c--41000--99999       |  99 ++++++++++++++
 .../vanilla--vmxnet3--31000--99999            |   2 +-
 58 files changed, 281 insertions(+), 56 deletions(-)
 rename LINUX/final-patches/{vanilla--ixgbe--40900--99999 => vanilla--ixgbe--40900--41000} (99%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--41000--99999
 rename LINUX/final-patches/{vanilla--virtio_net.c--40f00--99999 => vanilla--virtio_net.c--40f00--41000} (98%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--41000--99999

diff --git a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 b/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
index e9723a2aa..4eb888276 100644
--- a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
+++ b/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
@@ -1,5 +1,5 @@
 diff --git a/forcedeth.c b/forcedeth.c
-index 9c0b1ba..b081d6b 100644
+index 9c0b1bac6af6..b081d6ba11a2 100644
 --- a/forcedeth.c
 +++ b/forcedeth.c
 @@ -1865,12 +1865,25 @@ static void nv_init_tx(struct net_device *dev)
diff --git a/LINUX/final-patches/vanilla--igb--20621--20623 b/LINUX/final-patches/vanilla--igb--20621--20623
index 470149b91..22476d6f2 100644
--- a/LINUX/final-patches/vanilla--igb--20621--20623
+++ b/LINUX/final-patches/vanilla--igb--20621--20623
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index c881347..a2af379 100644
+index c881347cb26d..a2af3799f5a8 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -226,6 +226,10 @@ char *igb_get_hw_dev_name(struct e1000_hw *hw)
diff --git a/LINUX/final-patches/vanilla--igb--20623--30200 b/LINUX/final-patches/vanilla--igb--20623--30200
index 7708b0fff..a258b2391 100644
--- a/LINUX/final-patches/vanilla--igb--20623--30200
+++ b/LINUX/final-patches/vanilla--igb--20623--30200
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index cea37e0..81fd28b 100644
+index cea37e0837ff..81fd28b8cb4e 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -201,6 +201,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
diff --git a/LINUX/final-patches/vanilla--igb--30200--30800 b/LINUX/final-patches/vanilla--igb--30200--30800
index 4043728f5..9ae06fa01 100644
--- a/LINUX/final-patches/vanilla--igb--30200--30800
+++ b/LINUX/final-patches/vanilla--igb--30200--30800
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index ced5444..43c2419 100644
+index ced544499f1b..43c2419cd340 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -225,6 +225,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
diff --git a/LINUX/final-patches/vanilla--igb--30800--30f00 b/LINUX/final-patches/vanilla--igb--30800--30f00
index 1e3643441..1eaa64b3c 100644
--- a/LINUX/final-patches/vanilla--igb--30800--30f00
+++ b/LINUX/final-patches/vanilla--igb--30800--30f00
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 31cfe2e..2776ed4 100644
+index 31cfe2ec75df..2776ed444bf4 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -247,6 +247,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--igb--30f00--40100 b/LINUX/final-patches/vanilla--igb--30f00--40100
index 8f7a2004a..81138684a 100644
--- a/LINUX/final-patches/vanilla--igb--30f00--40100
+++ b/LINUX/final-patches/vanilla--igb--30f00--40100
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 16430a8..c2c4622 100644
+index 16430a8440fa..c2c462218ec3 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -257,6 +257,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--igb--40100--40400 b/LINUX/final-patches/vanilla--igb--40100--40400
index dfee4bdf4..00a867770 100644
--- a/LINUX/final-patches/vanilla--igb--40100--40400
+++ b/LINUX/final-patches/vanilla--igb--40100--40400
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index a0a9b1f..85be1eb 100644
+index a0a9b1fcb5e8..85be1ebd02ab 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -251,6 +251,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--igb--40400--99999 b/LINUX/final-patches/vanilla--igb--40400--99999
index f73685ad5..5d5ea3430 100644
--- a/LINUX/final-patches/vanilla--igb--40400--99999
+++ b/LINUX/final-patches/vanilla--igb--40400--99999
@@ -1,5 +1,5 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index ea7b098..ddb376e 100644
+index ea7b09887245..ddb376efc198 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
 @@ -253,6 +253,10 @@ static int debug = -1;
diff --git a/LINUX/final-patches/vanilla--ixgbe--20620--20622 b/LINUX/final-patches/vanilla--ixgbe--20620--20622
index ee0c0bd8a..d803909ec 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20620--20622
+++ b/LINUX/final-patches/vanilla--ixgbe--20620--20622
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index a456578..12c3857 100644
+index a456578b8578..12c38576bdac 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -337,6 +337,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
diff --git a/LINUX/final-patches/vanilla--ixgbe--20622--20623 b/LINUX/final-patches/vanilla--ixgbe--20622--20623
index 91a2af59b..721b9d6e0 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20622--20623
+++ b/LINUX/final-patches/vanilla--ixgbe--20622--20623
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 6c00ee4..36f9ef2 100644
+index 6c00ee493a3b..36f9ef2f366f 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -400,6 +400,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
diff --git a/LINUX/final-patches/vanilla--ixgbe--20623--20625 b/LINUX/final-patches/vanilla--ixgbe--20623--20625
index a9aed3202..1e0b7de53 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20623--20625
+++ b/LINUX/final-patches/vanilla--ixgbe--20623--20625
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 74d9b6d..803bc4b 100644
+index 74d9b6df3029..803bc4befaa2 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--20625--20626 b/LINUX/final-patches/vanilla--ixgbe--20625--20626
index 32abae28e..a1a53d5c5 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20625--20626
+++ b/LINUX/final-patches/vanilla--ixgbe--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index eee0b29..b7722c9 100644
+index eee0b298bd36..b7722c97827f 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--20626--30100 b/LINUX/final-patches/vanilla--ixgbe--20626--30100
index c95807eec..f6004d9fa 100644
--- a/LINUX/final-patches/vanilla--ixgbe--20626--30100
+++ b/LINUX/final-patches/vanilla--ixgbe--20626--30100
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 30f9ccf..4f5a19e 100644
+index 30f9ccfb4f87..4f5a19efbc65 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -221,6 +221,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30100--30200 b/LINUX/final-patches/vanilla--ixgbe--30100--30200
index e53050a31..2ab977802 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30100--30200
+++ b/LINUX/final-patches/vanilla--ixgbe--30100--30200
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e1fcc95..8753411 100644
+index e1fcc9589278..8753411450c4 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -249,6 +249,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30200--30400 b/LINUX/final-patches/vanilla--ixgbe--30200--30400
index e76337ec8..c470e60ef 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30200--30400
+++ b/LINUX/final-patches/vanilla--ixgbe--30200--30400
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 8ef92d1..6574699 100644
+index 8ef92d1a6aa1..65746992e80f 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -188,6 +188,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30400--30500 b/LINUX/final-patches/vanilla--ixgbe--30400--30500
index 383d8cf47..78fa4923f 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30400--30500
+++ b/LINUX/final-patches/vanilla--ixgbe--30400--30500
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 467948e9..568104f 100644
+index 467948e9ecd9..568104f44cae 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30500--30700 b/LINUX/final-patches/vanilla--ixgbe--30500--30700
index 60497e568..eb8e67881 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30500--30700
+++ b/LINUX/final-patches/vanilla--ixgbe--30500--30700
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e242104..6320fd1 100644
+index e242104ab471..6320fd181a90 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30700--30a00 b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
index 752c6d4b9..e4adf9a7d 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30700--30a00
+++ b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fa3d552..f0f4735 100644
+index fa3d552e1f4a..f0f47356e3f7 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -205,6 +205,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
index 54e0531d9..f5db6e7d4 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
+++ b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d30fbdd..a6bcb88 100644
+index d30fbdd81fca..a6bcb88e6004 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -248,6 +248,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
index 7c54c73ea..febd3bc92 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 5bcc870..eef4667 100644
+index 5bcc870f8367..eef466715f03 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--30f00--31300 b/LINUX/final-patches/vanilla--ixgbe--30f00--31300
index 9c7d4028e..c6584010a 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30f00--31300
+++ b/LINUX/final-patches/vanilla--ixgbe--30f00--31300
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d62e7a2..1c0b31a 100644
+index d62e7a25cf97..1c0b31aa4880 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -417,6 +417,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--31300--40900 b/LINUX/final-patches/vanilla--ixgbe--31300--40900
index 0cdf92094..97909dd2e 100644
--- a/LINUX/final-patches/vanilla--ixgbe--31300--40900
+++ b/LINUX/final-patches/vanilla--ixgbe--31300--40900
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 67b02bd..ba3e46d 100644
+index 67b02bde179e..ba3e46d70c49 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--40900--99999 b/LINUX/final-patches/vanilla--ixgbe--40900--41000
similarity index 99%
rename from LINUX/final-patches/vanilla--ixgbe--40900--99999
rename to LINUX/final-patches/vanilla--ixgbe--40900--41000
index 29b1e9bba..b3ca99fc5 100644
--- a/LINUX/final-patches/vanilla--ixgbe--40900--99999
+++ b/LINUX/final-patches/vanilla--ixgbe--40900--41000
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fee1f2918..7b86ce4 100644
+index fee1f2918ead..7b86ce44333a 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -497,6 +497,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
diff --git a/LINUX/final-patches/vanilla--ixgbe--41000--99999 b/LINUX/final-patches/vanilla--ixgbe--41000--99999
new file mode 100644
index 000000000..55599b36e
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--41000--99999
@@ -0,0 +1,126 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 9fc063af233c..85ceb30fd6c7 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -516,6 +516,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1178,6 +1194,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2341,6 +2368,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	while (likely(total_rx_packets < budget)) {
+@@ -3582,6 +3619,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3596,7 +3637,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+ 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
+@@ -4170,6 +4211,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -5667,6 +5712,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -10665,6 +10713,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
+ 			true);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -10710,6 +10762,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
+ 	set_bit(__IXGBE_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--20622--30500 b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
index 705ca371e..9304d203b 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--20622--30500
+++ b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 0cd6202..57e93f4 100644
+index 0cd6202dfacc..57e93f43df51 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -209,6 +209,24 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
index e8b4ea1f9..deb5d9bb6 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30500--30600
+++ b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 41e3225..5a9610e 100644
+index 41e32257a4e8..5a9610ec6b8b 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -186,6 +186,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
index 5458d64d8..0fb79f717 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30600--30700
+++ b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 60ef645..b0c3eb1 100644
+index 60ef64587412..b0c3eb141ec0 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
index da9db16b3..2fab97397 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index de1ad50..154571d 100644
+index de1ad506665d..154571deebe0 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
index 341ae4859..0dc67d0a7 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 92ef4cb..3c5d85c 100644
+index 92ef4cb5a8e8..3c5d85cec0a7 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
index 1c5314c2a..b1a3980ee 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 9df2898..05d9620 100644
+index 9df28985eba7..05d9620c5c3f 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -175,6 +175,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
index cda03e2be..3b72e5c37 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
+++ b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index d0799e8..3105f9c 100644
+index d0799e8e31e4..3105f9c82ac3 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
index 76369471f..cffd903e3 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--31200--31300
+++ b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 030a219..07adcf8 100644
+index 030a219c85e3..07adcf8211df 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
index abd865e5b..1a74b70dc 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--31300--40000
+++ b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 38c7a0b..ce0c373 100644
+index 38c7a0be8197..ce0c37370f07 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -208,6 +208,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40000--40700 b/LINUX/final-patches/vanilla--ixgbevf--40000--40700
index 93b9a8ab3..13df445f2 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40000--40700
+++ b/LINUX/final-patches/vanilla--ixgbevf--40000--40700
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 4186981..f37d7cc 100644
+index 4186981e562d..f37d7cc10e24 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -283,6 +283,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40700--40800 b/LINUX/final-patches/vanilla--ixgbevf--40700--40800
index 7a5378a78..ef0acae1c 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40700--40800
+++ b/LINUX/final-patches/vanilla--ixgbevf--40700--40800
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index acc2401..3d0b47e 100644
+index acc24010cfe0..3d0b47eb123b 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -292,6 +292,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40800--40900 b/LINUX/final-patches/vanilla--ixgbevf--40800--40900
index 39cd13e9e..35cdd90a7 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40800--40900
+++ b/LINUX/final-patches/vanilla--ixgbevf--40800--40900
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index d9d6616..501804f 100644
+index d9d6616f02a4..501804fe4ae7 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--99999 b/LINUX/final-patches/vanilla--ixgbevf--40900--99999
index 0c9776c1f..5d1f05e9a 100644
--- a/LINUX/final-patches/vanilla--ixgbevf--40900--99999
+++ b/LINUX/final-patches/vanilla--ixgbevf--40900--99999
@@ -1,5 +1,5 @@
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index cbf70fe..724ea09 100644
+index cbf70fe4028a..724ea090a557 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -294,6 +294,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
diff --git a/LINUX/final-patches/vanilla--r8169.c--20620--20625 b/LINUX/final-patches/vanilla--r8169.c--20620--20625
index d4a8f3781..20b7a6018 100644
--- a/LINUX/final-patches/vanilla--r8169.c--20620--20625
+++ b/LINUX/final-patches/vanilla--r8169.c--20620--20625
@@ -1,5 +1,5 @@
 diff --git a/r8169.c b/r8169.c
-index 0fe2fc9..5d363e5 100644
+index 0fe2fc90f207..5d363e589803 100644
 --- a/r8169.c
 +++ b/r8169.c
 @@ -537,6 +537,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
diff --git a/LINUX/final-patches/vanilla--r8169.c--20625--20626 b/LINUX/final-patches/vanilla--r8169.c--20625--20626
index fe419354f..e5cf077e7 100644
--- a/LINUX/final-patches/vanilla--r8169.c--20625--20626
+++ b/LINUX/final-patches/vanilla--r8169.c--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/r8169.c b/r8169.c
-index 53b13de..ced4849 100644
+index 53b13deade95..ced4849577f0 100644
 --- a/r8169.c
 +++ b/r8169.c
 @@ -535,6 +535,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
diff --git a/LINUX/final-patches/vanilla--r8169.c--20626--30400 b/LINUX/final-patches/vanilla--r8169.c--20626--30400
index 5e6d6473a..a1b9eb6f6 100644
--- a/LINUX/final-patches/vanilla--r8169.c--20626--30400
+++ b/LINUX/final-patches/vanilla--r8169.c--20626--30400
@@ -1,5 +1,5 @@
 diff --git a/r8169.c b/r8169.c
-index 7ffdb80..fc92723 100644
+index 7ffdb80adf40..fc9272305d02 100644
 --- a/r8169.c
 +++ b/r8169.c
 @@ -590,6 +590,10 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
diff --git a/LINUX/final-patches/vanilla--veth.c--20620--30900 b/LINUX/final-patches/vanilla--veth.c--20620--30900
index fffae7d65..c63d70bf1 100644
--- a/LINUX/final-patches/vanilla--veth.c--20620--30900
+++ b/LINUX/final-patches/vanilla--veth.c--20620--30900
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index 52af501..a416e43 100644
+index 52af5017c46b..a416e437bebf 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -38,6 +38,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--veth.c--30900--30f00 b/LINUX/final-patches/vanilla--veth.c--30900--30f00
index e2ca5b885..04f5b4e43 100644
--- a/LINUX/final-patches/vanilla--veth.c--30900--30f00
+++ b/LINUX/final-patches/vanilla--veth.c--30900--30f00
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index 07a4af0..672375e 100644
+index 07a4af0aa3dc..672375e5c5c8 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -36,6 +36,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--veth.c--30f00--99999 b/LINUX/final-patches/vanilla--veth.c--30f00--99999
index 0e17d9ca0..9d0b49ad7 100644
--- a/LINUX/final-patches/vanilla--veth.c--30f00--99999
+++ b/LINUX/final-patches/vanilla--veth.c--30f00--99999
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index b4a10bc..52b7c37 100644
+index b4a10bcb66a0..52b7c371f06b 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -37,6 +37,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
index 775493f38..342b63b0b 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
+++ b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index b0577dd..0c873c4 100644
+index b0577dd1a42d..0c873c4ae173 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -64,6 +64,10 @@ struct virtnet_info
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
index 2e013c912..8edbcc909 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
+++ b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index b6d4028..60bb2b2 100644
+index b6d402806ae6..60bb2b2cc257 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -67,6 +67,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
index 03ad70378..d6a60b6db 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
+++ b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 82dba5a..06324f8 100644
+index 82dba5aaf423..06324f8b2593 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -67,6 +67,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
index deba61c7e..7f5e9463b 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 4880aa8..64e3625 100644
+index 4880aa8b4c28..64e3625b1750 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -80,6 +80,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
index 91c23fba3..51dbf469e 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index f18149a..cc935cf 100644
+index f18149ae2588..cc935cfce8b2 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -90,6 +90,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 b/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
index 4bec12874..b75bfeb91 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 35c00c5..bfbb178 100644
+index 35c00c5ea02a..bfbb1787ec55 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -132,6 +132,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
index 06d6ee96a..29a0d5966 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 3d2a90a..2365434 100644
+index 3d2a90a62649..23654348b613 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -131,6 +131,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
index 9f1b59fc6..09db3f340 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 59caa06..b64cb15 100644
+index 59caa06f34a6..b64cb151db9f 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -145,6 +145,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
index a703e7170..bc49240cf 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 059fdf1..d79cd6a 100644
+index 059fdf1bf5ee..d79cd6a386e0 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
index e83d330fa..3e453fd44 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 63c7810..f5fc43c 100644
+index 63c7810e1545..f5fc43c34afa 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
index 437566ac0..e852dffa3 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index cbf1c61..be4daab 100644
+index cbf1c613c67a..be4daabbc51b 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -155,6 +155,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00 b/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
index 8ebf13e41..b254abd9b 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 143d8a9..27de2c2 100644
+index 143d8a95a60d..27de2c282e08 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -170,6 +170,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40f00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--40f00--41000
similarity index 98%
rename from LINUX/final-patches/vanilla--virtio_net.c--40f00--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--40f00--41000
index 63ce0bbf1..992fa8cac 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40f00--99999
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40f00--41000
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 559b215..00aad16 100644
+index 559b215c0169..00aad16f3aa2 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -181,6 +181,10 @@ struct virtnet_info {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--41000--99999 b/LINUX/final-patches/vanilla--virtio_net.c--41000--99999
new file mode 100644
index 000000000..9b71a0a9c
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--41000--99999
@@ -0,0 +1,99 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 23374603e4d9..fc0d8be71d4e 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -208,6 +208,10 @@ struct virtnet_info {
+ 	unsigned long guest_offloads;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_mrg_rxbuf hdr;
+ 	/*
+@@ -304,6 +308,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -1272,6 +1281,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int received;
+ 	bool xdp_xmit = false;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	struct virtnet_info *vi = rq->vq->vdev->priv;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -1290,6 +1312,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
+ 		if (i < vi->curr_queue_pairs)
+@@ -2855,6 +2886,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	virtnet_set_queues(vi, vi->curr_queue_pairs);
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+@@ -2905,7 +2940,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -2972,6 +3014,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {
diff --git a/LINUX/final-patches/vanilla--vmxnet3--31000--99999 b/LINUX/final-patches/vanilla--vmxnet3--31000--99999
index 3909077a5..a4a3d2345 100644
--- a/LINUX/final-patches/vanilla--vmxnet3--31000--99999
+++ b/LINUX/final-patches/vanilla--vmxnet3--31000--99999
@@ -1,7 +1,7 @@
 diff --git a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
 old mode 100644
 new mode 100755
-index b76f7dc..f87199a
+index b76f7dcde0db..f87199abe09e
 --- a/vmxnet3/vmxnet3_drv.c
 +++ b/vmxnet3/vmxnet3_drv.c
 @@ -308,6 +308,11 @@ static u32 get_bitfield32(const __le32 *bitfield, u32 pos, u32 size)

From 76792f7c50ef21529403aa8c8e67fa954e3d4dd3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 5 Apr 2018 09:05:09 +0200
Subject: [PATCH 0798/2207] pkt-gen: don't wait link with VALE ports by default

---
 apps/pkt-gen/pkt-gen.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index b10bb21ad..b572cc5e5 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2646,6 +2646,7 @@ main(int arc, char **argv)
 
 	int ch;
 	int devqueues = 1;	/* how many device queues */
+	int wait_link_arg = 0;
 
 	int pkt_size_done = 0;
 
@@ -2673,7 +2674,7 @@ main(int arc, char **argv)
 	g.frags = 1;
 	g.nmr_config = "";
 	g.virt_header = 0;
-	g.wait_link = 2;
+	g.wait_link = 2;	/* wait 2 seconds for physical ports */
 
 	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
 	    "T:w:WvR:XC:H:e:E:m:rP:zZAh")) != -1) {
@@ -2790,6 +2791,7 @@ main(int arc, char **argv)
 
 		case 'w':
 			g.wait_link = atoi(optarg);
+			wait_link_arg = 1;
 			break;
 
 		case 'W':
@@ -2874,6 +2876,10 @@ main(int arc, char **argv)
 	if (g.cpus == 0)
 		g.cpus = i;
 
+	if (!wait_link_arg && !strncmp(g.ifname, "vale", 4)) {
+		g.wait_link = 0;
+	}
+
 	if (g.pkt_size < 16 || g.pkt_size > MAX_PKTSIZE) {
 		D("bad pktsize %d [16..%d]\n", g.pkt_size, MAX_PKTSIZE);
 		usage(-1);

From 3e7a06aa356b1b8b7e91849d29a0e089a9df0f2a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 5 Apr 2018 16:43:56 +0200
Subject: [PATCH 0799/2207] linux: i40e: fix typo

---
 LINUX/i40e_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index a07e0713a..f828abf13 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -395,7 +395,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 						I40E_TXD_QW1_CMD_SHIFT);
 				if (slot->flags & NS_REPORT || nic_i == 0 ||
 						nic_i == report_frequency) {
-					hwflags |= ((u64)I40E_TX_DESC_CMD_RS <<
+					hw_flags |= ((u64)I40E_TX_DESC_CMD_RS <<
 							I40E_TXD_QW1_CMD_SHIFT);
 				}
 			}

From 459f261841f43898a1bfc8d7b461083374658d67 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 5 Apr 2018 18:11:54 +0200
Subject: [PATCH 0800/2207] netmap_poll: use ring->head instead of ring->cur to
 check if txsync is needed

---
 sys/dev/netmap/netmap.c      | 4 ++--
 sys/dev/netmap/netmap_kern.h | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index fe9f68a35..130f90144 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3115,9 +3115,9 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 			 * Don't try to txsync this TX ring if we already found some
 			 * space in some of the TX rings (want_tx == 0) and there are no
 			 * TX slots in this ring that need to be flushed to the NIC
-			 * (cur == hwcur).
+			 * (head == hwcur).
 			 */
-			if (!send_down && !want_tx && ring->cur == kring->nr_hwcur)
+			if (!send_down && !want_tx && ring->head == kring->nr_hwcur)
 				continue;
 
 			if (nm_kr_tryget(kring, 1, &revents))
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d290fcc8b..033de060a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -396,7 +396,7 @@ struct netmap_zmon_list {
 struct netmap_kring {
 	struct netmap_ring	*ring;
 
-	uint32_t	nr_hwcur;
+	uint32_t	nr_hwcur;  /* should be nr_hwhead */
 	uint32_t	nr_hwtail;
 
 	/*

From 62a25bd5ca2798ffca667578f06b083c8e394234 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 7 Apr 2018 10:05:16 +0200
Subject: [PATCH 0801/2207] linux: README: document limitations of veths in
 netmap mode

Mentioned in #465.
---
 LINUX/README | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/LINUX/README b/LINUX/README
index 535b7871b..8225f1a6d 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -288,6 +288,14 @@ COMMON PROBLEMS
   In emulated netmap mode (i.e. with unpatched drivers) VLAN tags are never
   visible by the netmap application.
 
+* When opening a veth interface in native netmap mode, the peer veth interface
+  must also be opened in native netmap mode, otherwise the traffic won't flow.
+  In other words, one cannot use native netmap mode on a veth endpoint and
+  use the kernel network stack on the other endpoint. This is not a missing
+  feature, as the native veth datapath is implemented using netmap pipes, and
+  it does not make sense (in terms of performance) for pipes to support
+  conversion betweeen netmap buffers and skbuffs.
+
 REVISION HISTORY
 -----------------
 

From 5a5dc2eb630c5991c37a208f9402766a4038096d Mon Sep 17 00:00:00 2001
From: Stuart Grace 
Date: Mon, 9 Apr 2018 14:32:10 +0100
Subject: [PATCH 0802/2207] mlx5: add header file for mellanox ethernet driver
 support

---
 LINUX/mlx5_netmap_linux.h | 739 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 739 insertions(+)
 create mode 100644 LINUX/mlx5_netmap_linux.h

diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
new file mode 100644
index 000000000..42c4ccfe4
--- /dev/null
+++ b/LINUX/mlx5_netmap_linux.h
@@ -0,0 +1,739 @@
+/*
+ * netmap support for Mellanox mlx5 Ethernet driver on Linux
+ *
+ * Copyright (C) 2015-2018 British Broadcasting Corporation. All rights reserved.
+ *
+ * Author: Stuart Grace, BBC Research & Development
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *   SUCH DAMAGE.
+ *
+ * Some portions are:
+ *
+ *   Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *   SUCH DAMAGE.
+ *
+ * Some portions are:
+ *
+ *   Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ *       Redistribution and use in source and binary forms, with or
+ *       without modification, are permitted provided that the following
+ *       conditions are met:
+ *
+ *        - Redistributions of source code must retain the above
+ *          copyright notice, this list of conditions and the following
+ *          disclaimer.
+ *
+ *        - Redistributions in binary form must reproduce the above
+ *          copyright notice, this list of conditions and the following
+ *          disclaimer in the documentation and/or other materials
+ *          provided with the distribution.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ *   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ *   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *   SOFTWARE.
+ */
+
+#ifndef __MLX5_NETMAP_LINUX_H__
+#define __MLX5_NETMAP_LINUX_H__
+
+#include 
+#include 
+#include 
+
+#ifdef NETMAP_MLX5_MAIN
+
+#include "en.h"
+
+#define NM_MLX5E_ADAPTER mlx5e_priv
+
+/* These functions are in en_rx.c but needed here to
+ * deal with compressed CQEs
+ */
+inline void mlx5e_read_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data);
+inline void mlx5e_write_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data);
+inline void mlx5e_decompress_cqe(struct mlx5e_cq *cq, struct mlx5_cqe64 *title,
+                                 struct mlx5_mini_cqe8 *mini, u16 wqe_counter,
+                                 int i);
+void mlx5e_decompress_cqes(struct mlx5e_cq *cq);
+
+/*
+ * Register/unregister. We are already under netmap lock.
+ * Only called on the first register or the last unregister.
+ */
+int mlx5e_netmap_reg(struct netmap_adapter *na, int onoff) {
+  struct ifnet *ifp = na->ifp;
+  struct NM_MLX5E_ADAPTER *adapter = netdev_priv(ifp);
+  int err = 0;
+  int was_opened;
+
+  D("mlx5e switching %s native netmap mode", onoff ? "into" : "out of");
+
+  /* Should we check and wait for any reset in progress to complete? */
+  mutex_lock(&adapter->state_lock);
+  was_opened = test_bit(MLX5E_STATE_OPENED, &adapter->state);
+
+  if (was_opened) {
+    mlx5e_close_locked(adapter->netdev);
+  }
+
+  /* enable or disable flags and callbacks in na and ifp */
+  if (onoff) {
+    nm_set_native_flags(na);
+  } else {
+    nm_clear_native_flags(na);
+  }
+
+  if (was_opened)
+    err = mlx5e_open_locked(adapter->netdev);
+
+  if (err)
+    netdev_err(adapter->netdev,
+               "mlx5e_netmap_reg: mlx5e_open_locked returned err code %d\n",
+               err);
+
+  mutex_unlock(&adapter->state_lock);
+
+  return err;
+}
+
+/*
+ * Reconcile kernel and user view of the transmit ring.
+ *
+ * Userspace wants to send packets up to the one before ring->head,
+ * kernel knows kring->nr_hwcur is the first unsent packet.
+ *
+ * Here we push packets out (as many as possible), and possibly
+ * reclaim buffers from previously completed transmission.
+ *
+ * ring->tail is updated on return.
+ * ring->head is never used here.
+ *
+ * The caller (netmap) guarantees that there is only one instance
+ * running at any time. Any interference with other driver
+ * methods should be handled by the individual drivers.
+ */
+int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
+  struct netmap_adapter *na = kring->na;
+  struct ifnet *ifp = na->ifp;
+  struct netmap_ring *ring = kring->ring;
+  u32 ring_nr = kring->ring_id;
+  u32 nm_i; /* index into the netmap ring */
+  u32 n;
+  u32 const lim = kring->nkr_num_slots - 1;
+  u32 const head = kring->rhead;
+
+  /* device-specific */
+  struct NM_MLX5E_ADAPTER *priv = netdev_priv(ifp);
+
+  struct mlx5e_sq *sq = priv->txq_to_sq_map[ring_nr];
+  struct mlx5e_cq *cq = &(sq->cq);
+  struct mlx5e_tx_wqe *wqe = NULL;
+  struct mlx5_cqe64 *cqe = NULL;
+  struct mlx5_wqe_ctrl_seg *cseg;
+  struct mlx5_wqe_eth_seg *eseg;
+  struct mlx5_wqe_data_seg *dseg;
+  u16 sqcc;
+  int cqe_found = 0;
+
+  /*
+   * If we have packets to send (kring->nr_hwcur != ring->cur)
+   * iterate over the netmap ring, fetch buffer address and length
+   * and create a suitable WQE for each packet to send.
+   *
+   * Only the last WQE requests a CQE is created to report
+   * completion.
+   */
+
+  if (!netif_carrier_ok(ifp)) {
+    goto out;
+  }
+
+  nm_i = kring->nr_hwcur;
+
+  if (nm_i != head) { /* we have new packets to send */
+
+    /* D("TX ring %u sending slots %u to %u",
+     *            ring_nr, nm_i, nm_prev(head, lim));
+     */
+
+    for (n = 0; nm_i != head; n++) {
+
+      struct netmap_slot *slot = &ring->slot[nm_i];
+      u_int len = slot->len;
+      uint64_t paddr; /* physical address for DMA */
+      void *addr = PNMB(na, slot, &paddr);
+
+      /* Code below based on mlx5e_sq_xmit() in en_tx.c */
+
+      struct mlx5_wq_cyc *wq = &sq->wq;
+      u16 pi = sq->pc & wq->sz_m1; /* producer index */
+
+      u8 opcode = MLX5_OPCODE_SEND;
+      u16 ds_cnt;
+      u16 ihs; /* inline hdr size */
+      u8 num_wqebbs = 0;
+
+      wqe = mlx5_wq_cyc_get_wqe(wq, pi);
+      cseg = &wqe->ctrl; /* ctrl seg */
+      eseg = &wqe->eth;  /* ethernet seg */
+      ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS;
+
+      NM_CHECK_ADDR_LEN(na, addr, len); /* limit len to buf size */
+
+      slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+
+      memset(wqe, 0, sizeof(*wqe));
+
+      /* request checksum generation in hw */
+      eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
+
+      /* Use minimum inline header to minimise data copying */
+      ihs = ETH_HLEN + 2; /* MAC + MAC + VLAN + Ethertype = 16 bytes */
+
+      if (unlikely(ihs > len))
+        ihs = len; /* whole packet fits inline */
+
+      memcpy(eseg->inline_hdr_start, addr, ihs);
+      eseg->inline_hdr_sz = cpu_to_be16(ihs);
+
+      ds_cnt +=
+          DIV_ROUND_UP(ihs - sizeof(eseg->inline_hdr_start), MLX5_SEND_WQE_DS);
+
+      dseg = (struct mlx5_wqe_data_seg *)cseg + ds_cnt;
+
+      /* Put all rest of packet into a single data segment */
+      /* excluding bytes in the inline header */
+      if (likely(len > ihs)) {
+
+        dseg->addr = cpu_to_be64(paddr + ihs); /* phys addr */
+        dseg->lkey = sq->mkey_be;
+        dseg->byte_count = cpu_to_be32(len - ihs);
+        ds_cnt++;
+      }
+
+      cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode);
+      cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt);
+
+      num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
+      sq->pc += num_wqebbs;
+
+      /* Instead of storing pointer to a skb in sq->skb[pi], we use
+       * it to store info we will need at completion:
+       *   - number of wqebbs in this wqe (shifted up by 24 bits)
+       *   - slot number in the netmap kring that this wqe is sending
+       *           (in bottom 24 bits)
+       */
+      sq->skb[pi] = (void *)(uintptr_t)(nm_i & 0x00FFFFFF) +
+                    ((uintptr_t)num_wqebbs << 24);
+
+      /* fill sq edge with nops to avoid wqe wrap around */
+      while ((sq->pc & wq->sz_m1) > sq->edge)
+        mlx5e_send_nop(sq, false);
+
+      sq->stats.packets++;
+
+      /* next netmap slot */
+      nm_i = nm_next(nm_i, lim);
+    } /* next packet */
+
+    /* Wake up the hardware if any packets enqueued */
+    if (wqe) {
+      /* Request a CQE when the final WQE has completed */
+      cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
+
+      mlx5e_tx_notify_hw(sq, wqe, 0);
+    }
+
+    kring->nr_hwcur = head;
+  }
+
+  /*
+   * Second part: reclaim buffers from completed transmissions.
+   * We find these by looking for CQEs in the CQ.
+   *
+   * Code below based on mlx5e_poll_tx_cq() in en_tx.c
+   */
+
+  /* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
+   * otherwise a cq overrun may occur */
+  sqcc = sq->cc;
+
+  cqe = mlx5e_get_cqe(cq);
+
+  while (cqe) {
+    u16 wqe_counter;
+    bool last_wqe;
+
+    cqe_found = 1;
+    mlx5_cqwq_pop(&cq->wq);
+    mlx5e_prefetch_cqe(cq);
+
+    /* this cqe could relate to many wqes */
+    wqe_counter = be16_to_cpu(cqe->wqe_counter);
+
+    do {
+      u16 ci = sqcc & sq->wq.sz_m1;
+      void *skb = sq->skb[ci];
+      u8 num_wqebbs;
+      u32 nm_i_done;
+
+      last_wqe = (sqcc == wqe_counter);
+
+      if (unlikely(!skb)) { /* nop */
+        sq->stats.nop++;
+        sqcc++;
+        continue;
+      }
+
+      /* unpack num_wqebbs and slot number from skb pointer */
+      num_wqebbs = (u8)((uintptr_t)skb >> 24);
+      nm_i_done = (u32)((uintptr_t)skb & 0x00FFFFFF);
+
+      sqcc += num_wqebbs;
+      kring->nr_hwtail = nm_prev(nm_i_done, lim);
+
+    } while (!last_wqe);
+
+    cqe = mlx5e_get_cqe(cq);
+  }
+
+  if (cqe_found) {
+
+    mlx5_cqwq_update_db_record(&cq->wq);
+
+    /* ensure cq space is freed before enabling more cqes */
+    wmb();
+    sq->cc = sqcc;
+  }
+
+  mlx5e_cq_arm(cq); /* allow interrupts from this CQ */
+
+out:
+  return 0;
+}
+
+/*
+ * Reconcile kernel and user view of the receive ring.
+ * Same as for the txsync, this routine must be efficient.
+ * The caller guarantees a single invocations, but races against
+ * the rest of the driver should be handled here.
+ *
+ * When called, userspace has released buffers up to ring->head
+ * (last one excluded).
+ *
+ * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
+ * of whether or not we received an interrupt.
+ */
+int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
+  struct netmap_adapter *na = kring->na;
+  struct ifnet *ifp = na->ifp;
+  struct netmap_ring *ring = kring->ring;
+  u_int ring_nr = kring->ring_id;
+  u_int nm_i = 0; /* index into the netmap ring */
+  u_int const lim = kring->nkr_num_slots - 1;
+  u_int const head = kring->rhead;
+  uint16_t slot_flags = 0;
+
+  /* device-specific */
+  struct NM_MLX5E_ADAPTER *priv = netdev_priv(ifp);
+  struct mlx5e_rq *rq = &(priv->channel[ring_nr]->rq);
+  struct mlx5e_cq *cq = &(rq->cq);
+  struct mlx5_cqe64 *cqe = NULL;
+  int cqe_found = 0;
+
+  if (unlikely(rq->rq_type == RQ_TYPE_STRIDE)) {
+    netdev_err(ifp,
+               "RQ type is STRIDING - this is not supported in netmap mode\n");
+    return 0;
+  }
+
+  if (!netif_carrier_ok(ifp))
+    return 0;
+
+  if (unlikely(head > lim)) {
+    return netmap_ring_reinit(kring);
+  }
+
+  rmb();
+
+  /*
+   * first part: reclaim buffers that userspace has released:
+   *  (from kring->nr_hwcur to slot before ring->head)
+   * and make the buffers available for reception.
+   * As usual nm_i is the index in the netmap ring.
+   */
+  nm_i = kring->nr_hwcur;
+
+  if (nm_i != head) {
+
+    struct mlx5_wq_ll *wq = &rq->wq;
+    struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
+    struct netmap_slot *slot;
+    uint64_t paddr;
+    void *addr;
+
+    while (nm_i != head && !mlx5_wq_ll_is_full(wq)) {
+
+      slot = &ring->slot[nm_i];
+      addr = PNMB(na, slot, &paddr); /* find phys address */
+
+      if (unlikely(addr == NETMAP_BUF_BASE(na))) { /* bad buf */
+        netdev_warn(ifp, "Resetting RX ring %u in mlx5e_netmap_rxsync\n",
+                    ring_nr);
+        goto ring_reset;
+      }
+
+      if (slot->flags & NS_BUF_CHANGED) {
+        slot->flags &= ~NS_BUF_CHANGED;
+      }
+
+      wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
+      wqe->data.addr = cpu_to_be64(paddr);
+
+      mlx5_wq_ll_push(wq, be16_to_cpu(wqe->next.next_wqe_index));
+
+      nm_i = nm_next(nm_i, lim);
+    }
+
+    kring->nr_hwcur = nm_i;
+
+    /* ensure wqes are visible to device before updating doorbell record */
+    wmb();
+    mlx5_wq_ll_update_db_record(wq);
+  }
+
+  /*
+   * Second part: import newly received packets.
+   * We are told about received packets by CQEs in the CQ.
+   *
+   * nm_i is the index of the next free slot in the netmap ring:
+   */
+  nm_i = kring->nr_hwtail;
+
+  cqe = mlx5e_get_cqe(cq);
+
+  while (cqe) {
+    struct mlx5e_rx_wqe *wqe;
+    u16 bytes_recv = 0;
+    __be16 wqe_id_be;
+    u16 wqe_counter;
+
+    cqe_found = 1;
+
+    if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED)
+      mlx5e_decompress_cqes(&rq->cq);
+
+    mlx5_cqwq_pop(&cq->wq);
+    mlx5e_prefetch_cqe(cq);
+
+    wqe_id_be = cqe->wqe_counter;
+    wqe_counter = be16_to_cpu(wqe_id_be);
+    wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
+    bytes_recv = be32_to_cpu(cqe->byte_cnt);
+
+    if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) {
+      rq->stats.wqe_err++;
+      netdev_warn(ifp, "Bad response found in CQE for RQ %u\n", ring_nr);
+      goto wq_ll_pop;
+    }
+
+    rq->stats.packets++;
+    if (cqe->hds_ip_ext & CQE_L4_OK)
+      rq->stats.csum_good++;
+
+    /* could analyse checksums more thoroughly using flags in
+     * l4_hdr_type_etc that us which checksums are applicable
+     */
+    /* Following is useful during debugging:
+     *   printk(KERN_ERR "** Received %u bytes for ring %u slot %u with
+     *                    L2CSUM %s, L3CSUM %s, L4CSUM %s\n",
+     *   be32_to_cpu(cqe->byte_cnt), ring_nr, nm_i,
+     *   (cqe->hds_ip_ext & CQE_L2_OK)? "good" : "*BAD*",
+     *   (cqe->hds_ip_ext & CQE_L3_OK)? "good" : "bad or not IP",
+     *   (cqe->hds_ip_ext & CQE_L4_OK)? "good" : "bad or not TCP/UDP");
+     */
+
+    ring->slot[nm_i].len = bytes_recv;
+    ring->slot[nm_i].flags = slot_flags;
+    nm_i = nm_next(nm_i, lim);
+
+  wq_ll_pop:
+    cqe = mlx5e_get_cqe(cq);
+    mlx5_wq_ll_pop(&rq->wq, wqe_id_be, &wqe->next.next_wqe_index);
+  }
+
+  if (cqe_found) {
+    kring->nr_hwtail = nm_i;
+    mlx5_cqwq_update_db_record(&cq->wq);
+
+    /* ensure cq space is freed before enabling more cqes */
+    wmb();
+
+    /* update the kring state */
+    kring->nr_kflags &= ~NKR_PENDINTR;
+  }
+
+  mlx5e_cq_arm(cq); /* allow interrupts from this CQ */
+
+  return 0;
+
+ring_reset:
+  return netmap_ring_reinit(kring);
+}
+
+/*
+ * Acknowledge and clear all CQEs when TX queue is closing down
+ */
+int mlx5e_netmap_tx_flush(struct mlx5e_sq *sq) {
+  struct mlx5e_cq *cq = &(sq->cq);
+  struct mlx5_cqe64 *cqe;
+  u16 sqcc;
+
+  rmb();
+
+  /* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
+   * otherwise a cq overrun may occur */
+  sqcc = sq->cc;
+
+  /* Any completed jobs in the CQ? */
+  cqe = mlx5e_get_cqe(cq);
+
+  while (cqe) {
+    u16 wqe_counter;
+    bool last_wqe;
+
+    mlx5_cqwq_pop(&cq->wq);
+    mlx5e_prefetch_cqe(cq);
+
+    /* this cqe could relate to many wqes */
+    wqe_counter = be16_to_cpu(cqe->wqe_counter);
+
+    do {
+      u16 ci = sqcc & sq->wq.sz_m1;
+      void *skb = sq->skb[ci];
+
+      last_wqe = (sqcc == wqe_counter);
+
+      if (unlikely(!skb)) { /* nop */
+        sq->stats.nop++;
+        sqcc++;
+        continue;
+      }
+
+      /* extract num_wqebbs from skb pointer */
+      sqcc += (u8)((uintptr_t)skb >> 24);
+
+    } while (!last_wqe);
+
+    cqe = mlx5e_get_cqe(cq);
+  }
+
+  mlx5_cqwq_update_db_record(&cq->wq);
+
+  /* ensure cq space is freed before enabling more cqes */
+  wmb();
+  sq->cc = sqcc;
+
+  return 0;
+}
+
+/*
+ * Acknowledge and clear all CQEs when RX queue is closing down
+ */
+int mlx5e_netmap_rx_flush(struct mlx5e_rq *rq) {
+  struct mlx5e_cq *cq = &(rq->cq);
+  struct mlx5_cqe64 *cqe;
+
+  rmb();
+
+  cqe = mlx5e_get_cqe(cq);
+
+  while (cqe) {
+    struct mlx5e_rx_wqe *wqe;
+    __be16 wqe_id_be;
+    u16 wqe_counter;
+
+    if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED)
+      mlx5e_decompress_cqes(&rq->cq);
+
+    mlx5_cqwq_pop(&cq->wq);
+    mlx5e_prefetch_cqe(cq);
+
+    wqe_id_be = cqe->wqe_counter;
+    wqe_counter = be16_to_cpu(wqe_id_be);
+    wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
+
+    cqe = mlx5e_get_cqe(cq);
+    mlx5_wq_ll_pop(&rq->wq, wqe_id_be, &wqe->next.next_wqe_index);
+  }
+
+  mlx5_cqwq_update_db_record(&cq->wq);
+
+  /* ensure cq space is freed before enabling more cqes */
+  wmb();
+
+  mlx5e_cq_arm(cq); /* allow interrupts from this CQ */
+
+  return 0;
+}
+
+/*
+ * if in netmap mode, attach the netmap buffers to the ring and return true.
+ * Otherwise return false.
+ */
+int mlx5e_netmap_configure_tx_ring(struct NM_MLX5E_ADAPTER *adapter,
+                                   int ring_nr) {
+  struct netmap_adapter *na = NA(adapter->netdev);
+  struct netmap_slot *slot;
+
+  slot = netmap_reset(na, NR_TX, ring_nr, 0);
+  if (!slot)
+    return 0; /* not in native netmap mode */
+
+  /*
+   * On some cards we would set up the slot addresses now.
+   * But on mlx5e, the address will be written to the WQ when
+   * each packet arrives in mlx5e_netmap_txsync
+   */
+
+  return 1;
+}
+
+int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
+  /*
+   * In netmap mode, we must preserve the buffers made
+   * available to userspace before the if_init()
+   * (this is true by default on the TX side, because
+   * init makes all buffers available to userspace).
+   */
+  struct netmap_adapter *na = NA(rq->netdev);
+  struct netmap_slot *slot;
+  int lim; /* number of WQEs to prepare */
+  int count = 0;
+
+  struct mlx5_wq_ll *wq = &rq->wq;
+
+  slot = netmap_reset(na, NR_RX, ring_nr, 0);
+  if (!slot)
+    return 0; /* not in native netmap mode */
+
+  lim = na->num_rx_desc - 1 - nm_kr_rxspace(&na->rx_rings[ring_nr]);
+
+  while (!mlx5_wq_ll_is_full(wq) && (count < lim)) {
+
+    struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
+
+    uint64_t paddr;
+    PNMB(na, slot + count, &paddr);
+
+    wqe->data.addr = cpu_to_be64(paddr);
+
+    mlx5_wq_ll_push(wq, be16_to_cpu(wqe->next.next_wqe_index));
+    count++;
+  }
+
+  D("populated %d WQEs in ring %d", count, ring_nr);
+
+  /* tell netmap how many buffers we have prepared */
+  (na->rx_rings[ring_nr]).nr_hwcur = count;
+
+  /* ensure wqes are visible to device before updating doorbell record */
+  wmb();
+  mlx5_wq_ll_update_db_record(wq);
+
+  return 1;
+}
+
+int mlx5e_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
+                        u_int *rxr, u_int *rxd) {
+  struct ifnet *ifp = na->ifp;
+  struct NM_MLX5E_ADAPTER *adapter = netdev_priv(ifp);
+
+  /* each channel has 1 rx ring and a tx for each tc */
+  *txr = adapter->params.num_channels * adapter->params.num_tc;
+  *rxr = adapter->params.num_channels;
+  *txd = (1 << adapter->params.log_sq_size);
+  *rxd = (1 << adapter->params.log_rq_size);
+
+  D("TX: %d rings with %d slots;  RX: %d rings with %d slots", *txr, *txd, *rxr,
+    *rxd);
+
+  return 0;
+}
+
+/*
+ * The attach routine, called at the end of mlx5e_create_netdev(),
+ * fills the parameters for netmap_attach() and calls it.
+ * It cannot fail, in the worst case (such as no memory)
+ * netmap mode will be disabled and the driver will only
+ * operate in standard mode.
+ */
+void mlx5e_netmap_attach(struct NM_MLX5E_ADAPTER *adapter) {
+  struct netmap_adapter na;
+  bzero(&na, sizeof(na));
+
+  na.ifp = adapter->netdev;
+  na.pdev = &adapter->mdev->pdev->dev;
+  na.num_tx_desc = (1 << adapter->params.log_sq_size);
+  na.num_rx_desc = (1 << adapter->params.log_rq_size);
+  na.nm_txsync = mlx5e_netmap_txsync;
+  na.nm_rxsync = mlx5e_netmap_rxsync;
+  na.nm_register = mlx5e_netmap_reg;
+  na.nm_config = mlx5e_netmap_config;
+
+  /* each channel has 1 rx ring and a tx for each tc */
+  na.num_tx_rings = adapter->params.num_channels * adapter->params.num_tc;
+  na.num_rx_rings = adapter->params.num_channels;
+  netmap_attach(&na);
+}
+
+#endif /* NETMAP_MLX5_MAIN */
+
+#endif /* __MLX5_NETMAP_LINUX_H__ */
+
+/* end of file */

From 8789b4cb4ab4f9e596ccc8f49296de4a8fcb4063 Mon Sep 17 00:00:00 2001
From: Stuart Grace 
Date: Mon, 9 Apr 2018 14:36:52 +0100
Subject: [PATCH 0803/2207] mlx5: add patch file for mellanox ethernet v3.3
 driver

---
 LINUX/final-patches/mellanox--mlx5--3.3 | 379 ++++++++++++++++++++++++
 1 file changed, 379 insertions(+)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--3.3

diff --git a/LINUX/final-patches/mellanox--mlx5--3.3 b/LINUX/final-patches/mellanox--mlx5--3.3
new file mode 100644
index 000000000..0e9d270e6
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--3.3
@@ -0,0 +1,379 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index b8ce0b5..574d21a 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -1,12 +1,13 @@
+ ccflags-y += $(MLNX_CFLAGS)
+ 
+-obj-$(CONFIG_MLX5_CORE)		+= mlx5_core.o
++obj-$(CONFIG_MLX5_CORE)		+= mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o   \
+ 		mad.o wq.o vport.o transobj.o en_main.o \
+ 		en_ethtool.o en_tx.o en_rx.o en_txrx.o \
+ 		sriov.o params.o en_debugfs.o en_selftest.o en_sysfs.o en_ecn.o \
+ 		en_dcb_nl.o fs_cmd.o fs_core.o fs_debugfs.o en_fs.o \
+ 		eswitch.o vxlan.o en_clock.o en_sniffer.o rl.o
+-mlx5_core-$(CONFIG_RFS_ACCEL) +=  en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) +=  en_arfs.o
++
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+index 847d804..342c754 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+@@ -32,6 +32,12 @@
+ 
+ #include "en.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_GET_RQ_TYPE(mdev)  RQ_TYPE_NONE  /* ensure RQ_TYPE_STRIDE not used with netmap */
++#else
++#define NETMAP_GET_RQ_TYPE(mdev)  MLX5_CAP_GEN(mdev, striding_rq)
++#endif
++
+ static const char mlx5e_test_names[][ETH_GSTRING_LEN] = {
+ 	"Speed Test",
+ 	"Link Test",
+@@ -468,8 +474,7 @@ static void mlx5e_get_ringparam(struct net_device *dev,
+ 				struct ethtool_ringparam *param)
+ {
+ 	struct mlx5e_priv *priv = netdev_priv(dev);
+-	int rq_wq_type = MLX5_CAP_GEN(priv->mdev, striding_rq);
+-
++	int rq_wq_type = NETMAP_GET_RQ_TYPE(priv->mdev);  /* Add netmap support */
+ 	param->rx_max_pending =
+ 		mlx5e_rx_wqes_to_packets(rq_wq_type,
+ 					   1 << mlx5_max_log_rq_size(rq_wq_type));
+@@ -485,7 +490,7 @@ static int mlx5e_set_ringparam(struct net_device *dev,
+ {
+ 	struct mlx5e_priv *priv = netdev_priv(dev);
+ 	struct mlx5e_params new_params;
+-	int rq_wq_type = MLX5_CAP_GEN(priv->mdev, striding_rq);
++	int rq_wq_type = NETMAP_GET_RQ_TYPE(priv->mdev);  /* Add netmap support */
+ 	u16 min_rx_wqes;
+ 	u8 log_rq_size;
+ 	u8 log_sq_size;
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 70fd71a..48644dc 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -61,6 +61,19 @@ struct mlx5e_channel_param {
+ 	struct mlx5e_cq_param      tx_cq;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#include "mlx5_netmap_linux.h"
++
++#define NETMAP_GET_RQ_TYPE(mdev)  RQ_TYPE_NONE  /* ensure RQ_TYPE_STRIDE not used with netmap */
++#else
++#define NETMAP_GET_RQ_TYPE(mdev)  MLX5_CAP_GEN(mdev, striding_rq)
++#endif
++
+ static void mlx5e_update_carrier(struct mlx5e_priv *priv)
+ {
+ 	struct mlx5_core_dev *mdev = priv->mdev;
+@@ -351,8 +364,7 @@ static int mlx5e_create_rq(struct mlx5e_channel *c,
+ 
+ 	param->wq.db_numa_node = cpu_to_node(c->cpu);
+ 
+-	rq->rq_type =  MLX5_CAP_GEN(mdev, striding_rq);
+-
++	rq->rq_type =  NETMAP_GET_RQ_TYPE(mdev);  /* Add netmap support */
+ 	err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq,
+ 				&rq->wq_ctrl);
+ 	if (err)
+@@ -415,6 +427,10 @@ static int mlx5e_create_rq(struct mlx5e_channel *c,
+ 	rq->channel = c;
+ 	rq->ix      = c->ix;
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_rq_wq_destroy:
+@@ -551,6 +567,11 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq)
+ 	struct mlx5_wq_ll *wq = &rq->wq;
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(c->netdev)))
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	for (i = 0; i < MLX5_EN_MAX_ITER; i++) {
+ 		if (wq->cur_sz >= priv->params.min_rx_wqes)
+ 			return 0;
+@@ -636,7 +657,12 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
+ 	if (err)
+ 		goto err_disable_rq;
+ 
+-	set_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(c->netdev)))
++#endif
++	{
++		set_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
++	}
+ 	mlx5e_send_nop(&c->sq[0], true); /* trigger mlx5e_post_rx_wqes() */
+ 
+ 	return 0;
+@@ -660,9 +686,15 @@ static void mlx5e_close_rq(struct mlx5e_rq *rq)
+ 
+ 	mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR);
+ 	if (!priv->internal_error) {
+-		for (i = 0; i < MLX5_EN_MAX_ITER && !mlx5_wq_ll_is_empty(&rq->wq); i++)
++		for (i = 0; i < MLX5_EN_MAX_ITER && !mlx5_wq_ll_is_empty(&rq->wq); i++) {
+ 			msleep(MLX5_EN_MSLEEP_QUANT);
+ 
++#ifdef DEV_NETMAP
++			if (nm_netmap_on(NA(c->netdev)))
++				mlx5e_netmap_rx_flush(rq); /* handle the CQEs */
++#endif
++		}
++
+ 		if (i == MLX5_EN_MAX_ITER)
+ 			pr_warn("%s: aborted\n", __func__);
+ 	}
+@@ -751,6 +783,11 @@ static int mlx5e_create_sq(struct mlx5e_channel *c,
+ 	sq->bf_budget = MLX5E_SQ_BF_BUDGET;
+ 	sq->edge      = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -913,9 +950,14 @@ static void mlx5e_close_sq(struct mlx5e_priv *priv, struct mlx5e_sq *sq)
+ 	napi_synchronize(&sq->channel->napi); /* prevent netif_tx_wake_queue */
+ 	netif_tx_disable_queue(sq->txq);
+ 
+-	/* ensure hw is notified of all pending wqes */
+-	if (mlx5e_sq_has_room_for(sq, 1))
+-		mlx5e_send_nop(sq, true);
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(priv->netdev)))
++#endif
++	{
++		/* ensure hw is notified of all pending wqes */
++		if (mlx5e_sq_has_room_for(sq, 1))
++			mlx5e_send_nop(sq, true);
++	}
+ 
+ 	err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR, false, 0);
+ 	if (!priv->internal_error && !err) {
+@@ -924,6 +966,11 @@ static void mlx5e_close_sq(struct mlx5e_priv *priv, struct mlx5e_sq *sq)
+ 			    test_bit(MLX5E_SQ_TX_TIMEOUT, &sq->state))
+ 				break;
+ 			msleep(MLX5_EN_MSLEEP_QUANT);
++
++#ifdef DEV_NETMAP
++			if (nm_netmap_on(NA(priv->netdev)))
++				mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 		}
+ 
+ 		if (i == MLX5_EN_MAX_ITER)
+@@ -1400,7 +1447,7 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
+ 	MLX5_SET(wq, wq, pd,               priv->pdn);
+ 	MLX5_SET(rqc,  rqc, counter_set_id, priv->counter_set_id);
+ 
+-	if (MLX5_CAP_GEN(priv->mdev, striding_rq) == RQ_TYPE_STRIDE) {
++	if (NETMAP_GET_RQ_TYPE(priv->mdev) == RQ_TYPE_STRIDE) {
+ 		MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_STRQ);
+ 		MLX5_SET(wq, wq, log_wqe_num_of_strides,
+ 			 MLX5E_PARAMS_DEFAULT_LOG_WQE_NUM_STRIDES);
+@@ -1451,7 +1498,7 @@ static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
+ 		MLX5_SET(cqc, cqc, cqe_comp_en, 1);
+ 	}
+ 
+-	if (MLX5_CAP_GEN(priv->mdev, striding_rq) == RQ_TYPE_STRIDE) {
++	if (NETMAP_GET_RQ_TYPE(priv->mdev) == RQ_TYPE_STRIDE) {
+ 		MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_rq_size +
+ 			 ilog2(MLX5E_PARAMS_HW_NUM_STRIDES_BASIC_VAL) +  MLX5E_PARAMS_DEFAULT_LOG_WQE_NUM_STRIDES);
+ 		/* Currently disable compressed with striding */
+@@ -2185,6 +2232,10 @@ int mlx5e_open_locked(struct net_device *netdev)
+ #endif
+ 	mlx5e_set_rx_mode_core(priv);
+ 
++#ifdef DEV_NETMAP
++	netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
+ 	queue_delayed_work(priv->wq, &priv->service_task, 0);
+ 
+@@ -2246,6 +2297,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 	}
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++	netmap_disable_all_rings(netdev);
++#endif
++
+ 	mlx5e_set_rx_mode_core(priv);
+ #if defined(HAVE_VXLAN_ENABLED) && defined(HAVE_VXLAN_DYNAMIC_PORT)
+ 	mlx5e_vxlan_cleanup(priv);
+@@ -3077,16 +3132,16 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
+ 	netdev_rss_key_fill(priv->params.toeplitz_hash_key,
+ 			    sizeof(priv->params.toeplitz_hash_key));
+ 
+-	if (MLX5_CAP_GEN(mdev, striding_rq)) {
++	if (NETMAP_GET_RQ_TYPE(mdev)) {  /* Add netmap support */
+ 		/* TODO ethtoo for these params */
+ 		priv->params.log_rq_size = MLX5E_PARAMS_DEFAULT_LOG_STRIDING_RQ_SIZE;
+ 	}
+ 	priv->params.min_rx_wqes =
+-		mlx5_min_rx_wqes(MLX5_CAP_GEN(mdev, striding_rq),
++		mlx5_min_rx_wqes(NETMAP_GET_RQ_TYPE(mdev),
+ 				 BIT(priv->params.log_rq_size));
+ 	/* TODO: add user ability to configure lro wqe size */
+ 	/* Enable LRO by default in case of strided RQ is supported */
+-	if (MLX5_CAP_GEN(mdev, striding_rq) && MLX5_CAP_ETH(mdev, lro_cap)) {
++	if (NETMAP_GET_RQ_TYPE(mdev) && MLX5_CAP_ETH(mdev, lro_cap)) {
+ 		priv->params.lro_en = true;
+ #ifdef CONFIG_COMPAT_LRO_ENABLED_IPOIB
+ 		priv->pflags |= MLX5E_PRIV_FLAG_HWLRO;
+@@ -3353,6 +3408,10 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
+ 	if (err)
+ 		goto err_unregister_netdev;
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return priv;
+ 
+ err_unregister_netdev:
+@@ -3387,6 +3446,10 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
+ 	struct mlx5e_priv *priv = vpriv;
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_sysfs_remove(netdev);
+ 
+ 	if (test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state))
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index f8bc512..d09a7e2 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -40,19 +40,23 @@
+ 	(priv->tstamp.hwtstamp_config.rx_filter ==	\
+ 		     HWTSTAMP_FILTER_ALL)
+ 
+-static inline void mlx5e_read_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
++/* Removed "static" from next four functions so they can
++ * be used from mlx5_netmap_linux.c for handling compressed
++ * CQEs in mlx5e_netmap_rxsync()
++ */
++inline void mlx5e_read_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
+ {
+ 	memcpy(data, mlx5_cqwq_get_wqe(&cq->wq, (cc & cq->wq.sz_m1)),
+ 	       sizeof(struct mlx5_cqe64));
+ }
+ 
+-static inline void mlx5e_write_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
++inline void mlx5e_write_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data)
+ {
+ 	memcpy(mlx5_cqwq_get_wqe(&cq->wq, cc & cq->wq.sz_m1),
+ 	       data, sizeof(struct mlx5_cqe64));
+ }
+ 
+-static inline void mlx5e_decompress_cqe(struct mlx5e_cq *cq,
++inline void mlx5e_decompress_cqe(struct mlx5e_cq *cq,
+ 					struct mlx5_cqe64 *title,
+ 					struct mlx5_mini_cqe8 *mini,
+ 					u16 wqe_counter, int i)
+@@ -65,7 +69,7 @@ static inline void mlx5e_decompress_cqe(struct mlx5e_cq *cq,
+ }
+ 
+ #define MLX5E_MINI_ARRAY_SZ 8
+-static void mlx5e_decompress_cqes(struct mlx5e_cq *cq)
++void mlx5e_decompress_cqes(struct mlx5e_cq *cq)
+ {
+ 	struct mlx5_mini_cqe8 mini_array[8];
+ 	struct mlx5_cqe64 title;
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+index 721fabc..2526e79 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+@@ -34,6 +34,14 @@
+ #include 
+ #include 
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ void mlx5e_prefetch_cqe(struct mlx5e_cq *cq)
+ {
+ 	struct mlx5_cqwq *wq = &cq->wq;
+@@ -92,6 +100,50 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
+ 
+ 	clear_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags);
+ 
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(c->netdev))) {
++		/*
++		 * In netmap mode, all the work is done in the context
++		 * of the client thread. Interrupt handlers only wake up
++		 * clients, which may be sleeping on individual rings
++		 * or on a global resource for all rings.
++		 */
++		struct mlx5e_rq *rq = &c->rq;
++		int dummy;
++
++		/* Wake netmap rx client. This results in a call to
++		 * mlx5e_netmap_rxsync() which will check for any
++		 * received packets and process them
++		 */
++		netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++
++		for (i = 0; i < c->num_tc; i++) {
++
++			struct mlx5e_cq *scq = &c->sq[i].cq;
++
++			/* Wake netmap tx client. This results in a call to
++			 * mlx5e_netmap_txsync()  which will check if a batch
++			 * of packets has finished sending and recycle the
++			 * buffers
++			 */
++			netmap_tx_irq(scq->channel->netdev, scq->channel->ix);
++		}
++
++		/* cq interrupts are not re-armed until the end of the
++		 * mlx5e_netmap_*sync() functions so we don't get more
++		 * interrupts if a call to those is already pending or in progress.
++		 */
++		napi_complete(napi);
++
++		/* avoid losing completion event during/after polling cqs */
++		if (test_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags)) {
++			napi_schedule(napi); /* request another call to this func */
++		}
++
++		return 0;
++	}
++#endif
++
+ 	busy |= mlx5e_poll_rx_cq(&c->rq.cq, budget);
+ 
+ 	busy |= mlx5e_post_rx_wqes(&c->rq);

From 003b0cf49024f13a0ded69ffc219f7daacbcefd8 Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Mon, 9 Apr 2018 14:40:05 +0100
Subject: [PATCH 0804/2207] mlx5: add mellanox driver to configure script

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index f62037fa7..9f7666fa6 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -110,7 +110,7 @@ subsys enable generic
 
 # available drivers
 driver_avail="r8169.c virtio_net.c forcedeth.c veth.c \
-	e1000 e1000e igb ixgbe ixgbevf i40e vmxnet3"
+	e1000 e1000e igb ixgbe ixgbevf i40e vmxnet3 mlx5"
 # enabled drivers (bitfield)
 driver=
 drv()

From e8fe24c8fdf8d772cd09758d8ec98ccfabf432ae Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 15:50:34 +0200
Subject: [PATCH 0805/2207] vale: netmap_get_bdg_na: remove misleading error
 message

No VALE switch is found when creating a new bridge, but this is
not an error.

Mentioned in #474.
---
 sys/dev/netmap/netmap_vale.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 8fd0c6ca4..dd2ffd045 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -881,7 +881,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	b = nm_find_bridge(nr_name, create);
 	if (b == NULL) {
-		D("no bridges available for '%s'", nr_name);
+		ND("no bridges available for '%s'", nr_name);
 		return (create ? ENOMEM : ENXIO);
 	}
 	if (strlen(nr_name) < b->bdg_namelen) /* impossible */

From fb3a0af053eae159efb7895a6501c3d8faa43648 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 17:24:03 +0200
Subject: [PATCH 0806/2207] freebsd: if_ptnet: fix compilation issues

---
 sys/dev/netmap/if_ptnet.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index d3f7e734a..0afbd936b 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -210,8 +210,8 @@ static int	ptnet_irqs_init(struct ptnet_softc *sc);
 static void	ptnet_irqs_fini(struct ptnet_softc *sc);
 
 static uint32_t ptnet_nm_ptctl(if_t ifp, uint32_t cmd);
-static int	ptnet_nm_config(struct netmap_adapter *na, unsigned *txr,
-				unsigned *txd, unsigned *rxr, unsigned *rxd);
+static int      ptnet_nm_config(struct netmap_adapter *na,
+				struct nm_config_info *info);
 static void	ptnet_update_vnet_hdr(struct ptnet_softc *sc);
 static int	ptnet_nm_register(struct netmap_adapter *na, int onoff);
 static int	ptnet_nm_txsync(struct netmap_kring *kring, int flags);
@@ -1135,9 +1135,9 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
-			kring = na->tx_rings + i;
+			kring = na->tx_rings[i];
 		} else {
-			kring = na->rx_rings + i - na->num_tx_rings;
+			kring = na->rx_rings[i - na->num_tx_rings];
 		}
 		kring->rhead = kring->ring->head = ptgh->head;
 		kring->rcur = kring->ring->cur = ptgh->cur;
@@ -1230,7 +1230,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		if (native) {
 			for_rx_tx(t) {
 				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = &NMR(na, t)[i];
+					struct netmap_kring *kring = NMR(na, t)[i];
 
 					if (nm_kring_pending_on(kring)) {
 						kring->nr_mode = NKR_NETMAP_ON;
@@ -1245,7 +1245,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			nm_clear_native_flags(na);
 			for_rx_tx(t) {
 				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = &NMR(na, t)[i];
+					struct netmap_kring *kring = NMR(na, t)[i];
 
 					if (nm_kring_pending_off(kring)) {
 						kring->nr_mode = NKR_NETMAP_OFF;
@@ -1760,7 +1760,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 
 	ptgh = pq->ptgh;
 	pthg = pq->pthg;
-	kring = na->tx_rings + pq->kring_id;
+	kring = na->tx_rings[pq->kring_id];
 	ring = kring->ring;
 	lim = kring->nkr_num_slots - 1;
 	head = ring->head;
@@ -2023,7 +2023,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 	struct ptnet_csb_gh *ptgh = pq->ptgh;
 	struct ptnet_csb_hg *pthg = pq->pthg;
 	struct netmap_adapter *na = &sc->ptna->dr.up;
-	struct netmap_kring *kring = na->rx_rings + pq->kring_id;
+	struct netmap_kring *kring = na->rx_rings[pq->kring_id];
 	struct netmap_ring *ring = kring->ring;
 	unsigned int const lim = kring->nkr_num_slots - 1;
 	unsigned int batch_count = 0;

From 31337e2a80dfcf2c433faa5bc6c89dc56c30a8cc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 17:29:23 +0200
Subject: [PATCH 0807/2207] freebsd: fix compilation issues introduced by kring
 indirection

---
 sys/dev/netmap/netmap.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 130f90144..9ddd808bf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3060,7 +3060,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	if (want_tx) {
 		enum txrx t = NR_TX;
 		for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) {
-			kring = &NMR(na, t)[i];
+			kring = NMR(na, t)[i];
 			/* XXX compare ring->cur and kring->tail */
 			if (!nm_ring_empty(kring->ring)) {
 				revents |= want[t];
@@ -3072,7 +3072,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		enum txrx t = NR_RX;
 		want_rx = 0; /* look for a reason to run the handlers */
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = &NMR(na, t)[i];
+			kring = NMR(na, t)[i];
 			if (kring->ring->cur == kring->ring->tail /* try fetch new buffers */
 			    || kring->rhead != kring->ring->head /* release buffers */) {
 				want_rx = 1;
@@ -3154,7 +3154,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		if (want_tx && retry_tx && sr) {
 #ifndef linux
 			nm_os_selrecord(sr, check_all_tx ?
-			    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]].si);
+			    &na->si[NR_TX] : na->tx_rings[priv->np_qfirst[NR_TX]].si);
 #endif /* !linux */
 			retry_tx = 0;
 			goto flush_tx;
@@ -3215,7 +3215,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 #ifndef linux
 		if (retry_rx && sr) {
 			nm_os_selrecord(sr, check_all_rx ?
-			    &na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]].si);
+			    &na->si[NR_RX] : na->rx_rings[priv->np_qfirst[NR_RX]].si);
 		}
 #endif /* !linux */
 		if (send_down || retry_rx) {

From b2142d462eb176839dc403ad078a4568a12df338 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 17:34:17 +0200
Subject: [PATCH 0808/2207] freebsd: fix signature of nm_os_extmem_create()

---
 sys/dev/netmap/netmap_freebsd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 463dbf2f5..2e0801f2d 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -659,7 +659,7 @@ nm_os_extmem_nr_pages(struct nm_os_extmem *e)
 }
 
 struct nm_os_extmem *
-nm_os_extmem_create(unsigned long p, struct netmap_pools_info *pi, int *perror)
+nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 {
 	vm_map_t map;
 	vm_map_entry_t entry;

From 61affc0685b12eaf4f78ba48af3619e98383e3f6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 17:54:04 +0200
Subject: [PATCH 0809/2207] freebsd: fix more compilation issues

---
 sys/dev/netmap/netmap.c      | 6 +++---
 sys/dev/netmap/netmap_pipe.c | 2 +-
 sys/dev/netmap/netmap_vale.c | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9ddd808bf..90e162a18 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -911,7 +911,7 @@ netmap_krings_delete(struct netmap_adapter *na)
 
 	/* we rely on the krings layout described above */
 	for ( ; kring != na->tailroom; kring++) {
-		mtx_destroy((*kring)->q_lock);
+		mtx_destroy(&(*kring)->q_lock);
 		nm_os_selinfo_uninit(&(*kring)->si);
 	}
 	nm_os_free(na->tx_rings);
@@ -3154,7 +3154,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		if (want_tx && retry_tx && sr) {
 #ifndef linux
 			nm_os_selrecord(sr, check_all_tx ?
-			    &na->si[NR_TX] : na->tx_rings[priv->np_qfirst[NR_TX]].si);
+			    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]]->si);
 #endif /* !linux */
 			retry_tx = 0;
 			goto flush_tx;
@@ -3215,7 +3215,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 #ifndef linux
 		if (retry_rx && sr) {
 			nm_os_selrecord(sr, check_all_rx ?
-			    &na->si[NR_RX] : na->rx_rings[priv->np_qfirst[NR_RX]].si);
+			    &na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]]->si);
 		}
 #endif /* !linux */
 		if (send_down || retry_rx) {
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 9eca8dba9..89ae0cf5d 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -138,7 +138,7 @@ netmap_pipe_find(struct netmap_adapter *parent, const char *pipe_id)
 		na = parent->na_pipes[i];
 		na_pipe_id = strrchr(na->up.name,
 			na->role == NM_PIPE_ROLE_MASTER ? '{' : '}');
-		KASSERT(na_pipe_id != NULL, "Invalid pipe name");
+		KASSERT(na_pipe_id != NULL, ("Invalid pipe name"));
 		++na_pipe_id;
 		if (!strcmp(na_pipe_id, pipe_id)) {
 			return na;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index dd2ffd045..5d69f98d3 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1852,7 +1852,7 @@ uint32_t
 netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *na, void *private_data)
 {
-	uint8_t *buf = ft->ft_buf + ft->ft_offset;
+	uint8_t *buf = ((uint8_t *)ft->ft_buf) + ft->ft_offset;
 	u_int buf_len = ft->ft_len - ft->ft_offset;
 	struct nm_hash_ent *ht = private_data;
 	uint32_t sh, dh;

From 3fb0013037181463838bb60d3a838d5b3a7d0ee5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 17:55:35 +0200
Subject: [PATCH 0810/2207] make nmreq_opt_size_by_type() static

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 90e162a18..31791fc98 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2729,7 +2729,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	return 0;
 }
 
-size_t
+static size_t
 nmreq_opt_size_by_type(uint16_t nro_reqtype)
 {
 	size_t rv = sizeof(struct nmreq_option);

From a5ed798c4ffcc65eeeb7059b493aedcda052e805 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 18:54:48 +0200
Subject: [PATCH 0811/2207] mem2: remove freebsd logs for preallocated
 mapping/unmapping

---
 sys/dev/netmap/netmap_mem2.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index c732e9712..dec807999 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1514,10 +1514,11 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 		return 0;
 
 #if defined(__FreeBSD__)
+	/* On FreeBSD mapping and unmapping is performed by the txsync
+	 * and rxsync routine, packet by packet. */
 	(void)i;
 	(void)lim;
 	(void)lut;
-	D("unsupported on FreeBSD");
 #elif defined(_WIN32)
 	(void)i;
 	(void)lim;
@@ -1549,10 +1550,11 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 		return 0;
 
 #if defined(__FreeBSD__)
+	/* On FreeBSD mapping and unmapping is performed by the txsync
+	 * and rxsync routine, packet by packet. */
 	(void)i;
 	(void)lim;
 	(void)lut;
-	D("unsupported on FreeBSD");
 #elif defined(_WIN32)
 	(void)i;
 	(void)lim;

From 9008b3d98e6a7d82e0eb5036942bd28ae9ecc558 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 19:00:45 +0200
Subject: [PATCH 0812/2207] pkt-gen: fix compilation issue on FreeBSD

---
 apps/pkt-gen/pkt-gen.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index b572cc5e5..7a7b9f342 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2975,7 +2975,8 @@ main(int arc, char **argv)
 		goto out;
 	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %"PRIu32"KB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem);
+	D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
+				g.nmd->mem);
 
 	if (g.virt_header) {
 		/* Set the virtio-net header length, since the user asked

From 5da523d020f01b6e3c1dfe75388f05d31f574c5e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 19:01:28 +0200
Subject: [PATCH 0813/2207] utils: testmmap: fix compilation issue on FreeBSD

---
 utils/testmmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index ef38bf284..0ad3058aa 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1808,7 +1808,7 @@ do_hdr_option()
 	nmreq_opt_init init      = NULL;
 
 	while ((type = nextarg())) {
-		uint16_t reqtype;
+		uint16_t reqtype = 0;
 
 		if (strcmp(type, "extmem") == 0) {
 			reqtype = NETMAP_REQ_OPT_EXTMEM;

From d5d02ad95d9f0eb738f2a5f9cb0b2562ea10c8b1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 11 Apr 2018 19:06:50 +0200
Subject: [PATCH 0814/2207] functional: rearrange headers to fix compilation

---
 utils/functional.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 577c55347..c8ecd3992 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -25,20 +25,20 @@
  * SUCH DAMAGE.
  */
 #include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #define NETMAP_WITH_LIBS
 #include 
+#include 
+#include 
+#include 
+#include 
 
 #define ETH_ADDR_LEN 6
 

From ddedc20dbd83aada6bb1aa8fb442dd6b17e061de Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 10:27:19 +0200
Subject: [PATCH 0815/2207] netmap_do_regif: log na->name with MTU,
 rx_buf_maxsize and netmap buf size

---
 sys/dev/netmap/netmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 31791fc98..fa7ad0d23 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2118,8 +2118,8 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 			unsigned nbs = netmap_mem_bufsize(na->nm_mem);
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
 
-			ND("mtu %d rx_buf_maxsize %d netmap_buf_size %d",
-					mtu, na->rx_buf_maxsize, nbs);
+			ND("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",
+					na->name, mtu, na->rx_buf_maxsize, nbs);
 
 			if (mtu <= na->rx_buf_maxsize) {
 				/* The MTU fits a single NIC slot. We only

From 8e54dd0f4afc9801fc48977d5bcaa977061eaffa Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 10:41:13 +0200
Subject: [PATCH 0816/2207] vale: netmap_brap_attach: initialize rx_buf_maxsize

---
 sys/dev/netmap/netmap_vale.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 5d69f98d3..3a0a94a09 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -3053,6 +3053,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	na->pdev = hwna->pdev;
 	na->nm_mem = netmap_mem_get(hwna->nm_mem);
 	na->virt_hdr_len = hwna->virt_hdr_len;
+	na->rx_buf_maxsize = hwna->rx_buf_maxsize;
 	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
 	/* Set the mfs, needed on the VALE mismatch datapath. */
 	bna->up.mfs = NM_BDG_MFS_DEFAULT;
@@ -3085,6 +3086,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		na->na_hostvp = hwna->na_hostvp =
 			hostna->na_hostvp = &bna->host;
 		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
+		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
 		bna->host.mfs = NM_BDG_MFS_DEFAULT;
 	}
 

From e1d504021eb51c1d24c8d79f6b0816c6ec9d6090 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 17:48:48 +0200
Subject: [PATCH 0817/2207] netmap_update_config: log updated configuration

---
 sys/dev/netmap/netmap.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index fa7ad0d23..f4bc817ec 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -763,15 +763,15 @@ netmap_update_config(struct netmap_adapter *na)
 	    na->rx_buf_maxsize == info.rx_buf_maxsize)
 		return 0; /* nothing changed */
 	if (na->active_fds == 0) {
-		D("configuration changed for %s: txring %d x %d, "
-			"rxring %d x %d, rxbufsz %d",
-			na->name, na->num_tx_rings, na->num_tx_desc,
-			na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
 		na->num_tx_rings = info.num_tx_rings;
 		na->num_tx_desc = info.num_tx_descs;
 		na->num_rx_rings = info.num_rx_rings;
 		na->num_rx_desc = info.num_rx_descs;
 		na->rx_buf_maxsize = info.rx_buf_maxsize;
+		D("configuration changed for %s: txring %d x %d, "
+			"rxring %d x %d, rxbufsz %d",
+			na->name, na->num_tx_rings, na->num_tx_desc,
+			na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
 		return 0;
 	}
 	D("WARNING: configuration changed for %s while active: "

From 42c0d15db4cc3694cf72ef45e2786204a8e1b3b5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 18:04:58 +0200
Subject: [PATCH 0818/2207] netmap_do_regif: check for rx_buf_maxsize being
 zero

---
 sys/dev/netmap/netmap.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f4bc817ec..6c06c9664 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2121,6 +2121,12 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 			ND("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",
 					na->name, mtu, na->rx_buf_maxsize, nbs);
 
+			if (na->rx_buf_maxsize == 0) {
+				D("%s: error: rx_buf_maxsize == 0", na->name);
+				error = EIO;
+				goto err_drop_mem;
+			}
+
 			if (mtu <= na->rx_buf_maxsize) {
 				/* The MTU fits a single NIC slot. We only
 				 * Need to check that netmap buffers are

From 7192442c35a1a3c0fe97099badc6fe699aab5a5a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 18:08:37 +0200
Subject: [PATCH 0819/2207] netmap_do_regif: use NETMAP_BUF_SIZE to get buffer
 size

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6c06c9664..1c51cf342 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2115,7 +2115,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 */
 		if (na->ifp && nm_priv_rx_enabled(priv)) {
 			/* This netmap adapter is attached to an ifnet. */
-			unsigned nbs = netmap_mem_bufsize(na->nm_mem);
+			unsigned nbs = NETMAP_BUF_SIZE(na);
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
 
 			ND("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",

From d464441d270603103cd39a281ecb07816ae5377d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 18:20:40 +0200
Subject: [PATCH 0820/2207] netmap_bwrap_config: call netmap_mem_get_lut() on
 the hwna

Mentioned in #474.
---
 sys/dev/netmap/netmap_vale.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3a0a94a09..9d2cb9234 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2782,8 +2782,14 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 	struct netmap_bwrap_adapter *bna =
 		(struct netmap_bwrap_adapter *)na;
 	struct netmap_adapter *hwna = bna->hwna;
+	int error;
 
-	/* forward the request */
+	/* Forward the request to the hwna. It may happen that nobody
+	 * registered hwna yet, so netmap_mem_get_lut() may have not
+	 * been called yet. */
+	error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut);
+	if (error)
+		return error;
 	netmap_update_config(hwna);
 	/* swap the results and propagate */
 	info->num_tx_rings = hwna->num_rx_rings;

From fbae1940a2daf06fb4a1050ff87c9222c1ece345 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 18:52:18 +0200
Subject: [PATCH 0821/2207] utils: use uintptr_t casts to fill uint64_t pointer
 fields

This avoids sign extension that results from directly converting
a pointer to an uint64_t.
---
 utils/ctrl-api-test.c | 39 ++++++++++++++++++++-------------------
 utils/testmmap.c      | 38 +++++++++++++++++++-------------------
 2 files changed, 39 insertions(+), 38 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 51a50a540..51da3f73e 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -65,7 +65,7 @@ port_info_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -101,8 +101,8 @@ port_register(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
-	hdr.nr_options = (uint64_t)(uintptr_t)ctx->nr_opt;
+	hdr.nr_body    = (uintptr_t)&req;
+	hdr.nr_options = (uintptr_t)ctx->nr_opt;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id     = ctx->nr_mem_id;
 	req.nr_mode       = ctx->nr_mode;
@@ -188,7 +188,7 @@ vale_attach(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.reg.nr_mem_id = ctx->nr_mem_id;
 	if (ctx->nr_mode == 0) {
@@ -223,7 +223,7 @@ vale_detach(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
@@ -266,7 +266,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr_len = ctx->nr_hdr_len;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
@@ -332,7 +332,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id   = ctx->nr_mem_id;
 	req.nr_tx_slots = ctx->nr_tx_slots;
@@ -350,7 +350,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
-	hdr.nr_body    = (uint64_t)(uintptr_t)NULL;
+	hdr.nr_body    = (uintptr_t)NULL;
 	ret	    = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
@@ -374,7 +374,7 @@ pools_info_get(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -469,7 +469,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mode		= ctx->nr_mode;
 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
@@ -501,7 +501,7 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-	hdr.nr_body    = (uint64_t)(uintptr_t)&req;
+	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
@@ -540,7 +540,7 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 static void
 push_option(struct nmreq_option *opt, struct TestContext *ctx)
 {
-	opt->nro_next = (uint64_t)(uintptr_t)ctx->nr_opt;
+	opt->nro_next = (uintptr_t)ctx->nr_opt;
 	ctx->nr_opt   = opt;
 }
 
@@ -554,8 +554,9 @@ static int
 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
 {
 	if (opt->nro_next != exp->nro_next) {
-		printf("nro_next %p expected %p\n", (void *)opt->nro_next,
-		       (void *)exp->nro_next);
+		printf("nro_next %p expected %p\n",
+			(void *)(uintptr_t)opt->nro_next,
+			(void *)(uintptr_t)exp->nro_next);
 		return -1;
 	}
 	if (opt->nro_reqtype != exp->nro_reqtype) {
@@ -600,7 +601,7 @@ infinite_options(int fd, struct TestContext *ctx)
 
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
-	opt.nro_next = (uint64_t)(uintptr_t)&opt;
+	opt.nro_next = (uintptr_t)&opt;
 	save	 = opt;
 	if (port_register_hwall(fd, ctx) >= 0)
 		return -1;
@@ -659,7 +660,7 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 
 	memset(e, 0, sizeof(*e));
 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
-	e->nro_usrptr	  = (uint64_t)addr;
+	e->nro_usrptr	  = (uintptr_t)addr;
 	e->nro_info.nr_memsize = (1U << 22);
 
 	push_option(&e->nro_opt, ctx);
@@ -673,8 +674,8 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	struct nmreq_opt_extmem *e;
 	int ret;
 
-	e	   = (struct nmreq_opt_extmem *)ctx->nr_opt;
-	ctx->nr_opt = (struct nmreq_option *)ctx->nr_opt->nro_next;
+	e	   = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
+	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
 
 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
 		return ret;
@@ -691,7 +692,7 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 		return -1;
 	}
 
-	if ((ret = munmap((void *)e->nro_usrptr, e->nro_info.nr_memsize)))
+	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr, e->nro_info.nr_memsize)))
 		return ret;
 
 	return 0;
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 0ad3058aa..19d0208fb 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1608,7 +1608,7 @@ nmr_option_dump_extmem(struct nmreq_option *opt)
 {
 	struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)opt;
 
-	printf("usrptr: %p\n", (void *)e->nro_usrptr);
+	printf("usrptr: %p\n", (void *)(uintptr_t)e->nro_usrptr);
 	printf("info:\n");
 	pools_info_dump(4, &e->nro_info);
 }
@@ -1618,7 +1618,7 @@ nmr_option_dump(struct nmreq_option *opt)
 {
 	nmr_option_dump_fun d = NULL;
 
-	printf("next: %p\n", (void *)opt->nro_next);
+	printf("next: %p\n", (void *)(uintptr_t)opt->nro_next);
 	printf("type: %" PRIu32 " [", opt->nro_reqtype);
 	switch (opt->nro_reqtype) {
 	case NETMAP_REQ_OPT_EXTMEM:
@@ -1705,24 +1705,24 @@ do_hdr_dump()
 	}
 	printf("]\n");
 	printf("name: %s\n", nmr_name);
-	opt = (struct nmreq_option *)curr_hdr.nr_options;
+	opt = (struct nmreq_option *)(uintptr_t)curr_hdr.nr_options;
 	printf("options:   %p\n", opt);
 	while (opt) {
 		nmr_option_dump(opt);
-		opt = (struct nmreq_option *)opt->nro_next;
+		opt = (struct nmreq_option *)(uintptr_t)opt->nro_next;
 	}
-	printf("body:	   %p\n", (void *)curr_hdr.nr_body);
+	printf("body:	   %p\n", (void *)(uintptr_t)curr_hdr.nr_body);
 	if (body_dump)
-		body_dump((void *)curr_hdr.nr_body);
+		body_dump((void *)(uintptr_t)curr_hdr.nr_body);
 }
 
 static void
 do_hdr_reset()
 {
-	struct nmreq_option *opt = (struct nmreq_option *)curr_hdr.nr_options;
+	struct nmreq_option *opt = (struct nmreq_option *)(uintptr_t)curr_hdr.nr_options;
 	while (opt) {
 		struct nmreq_option *next =
-			(struct nmreq_option *)opt->nro_next;
+			(struct nmreq_option *)(uintptr_t)opt->nro_next;
 		free(opt);
 		opt = next;
 	}
@@ -1749,38 +1749,38 @@ do_hdr_type()
 
 	if (strcmp(type, "register") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_REGISTER;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_register;
+		curr_hdr.nr_body    = (uintptr_t)&curr_register;
 	} else if (strcmp(type, "info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_info_get;
+		curr_hdr.nr_body    = (uintptr_t)&curr_port_info_get;
 	} else if (strcmp(type, "vale-attach") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_attach;
+		curr_hdr.nr_body    = (uintptr_t)&curr_vale_attach;
 	} else if (strcmp(type, "vale-detach") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	} else if (strcmp(type, "vale-list") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_LIST;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_list;
+		curr_hdr.nr_body    = (uintptr_t)&curr_vale_list;
 	} else if (strcmp(type, "port-hdr-set") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_hdr;
+		curr_hdr.nr_body    = (uintptr_t)&curr_port_hdr;
 	} else if (strcmp(type, "port-hdr-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_port_hdr;
+		curr_hdr.nr_body    = (uintptr_t)&curr_port_hdr;
 	} else if (strcmp(type, "vale-newif") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_newif;
+		curr_hdr.nr_body    = (uintptr_t)&curr_vale_newif;
 	} else if (strcmp(type, "vale-delif") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	} else if (strcmp(type, "vale-polliing-enable") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_polling;
+		curr_hdr.nr_body    = (uintptr_t)&curr_vale_polling;
 	} else if (strcmp(type, "vale-polling-disable") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_vale_polling;
+		curr_hdr.nr_body    = (uintptr_t)&curr_vale_polling;
 	} else if (strcmp(type, "pools-info-get") == 0) {
 		curr_hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
-		curr_hdr.nr_body    = (uint64_t)(uintptr_t)&curr_pools_info;
+		curr_hdr.nr_body    = (uintptr_t)&curr_pools_info;
 	} else {
 		output("unknown type: %s", type);
 	}
@@ -1793,7 +1793,7 @@ static void
 nmreq_opt_extmem_init(struct nmreq_option *opt)
 {
 	struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)opt;
-	e->nro_usrptr		   = (uint64_t)last_mmap_addr;
+	e->nro_usrptr		   = (uintptr_t)last_mmap_addr;
 	e->nro_info.nr_memsize     = last_memsize;
 }
 

From ac6ce654a763a40ad46546ab65c8e5de3af84cb4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 12 Apr 2018 19:38:02 +0200
Subject: [PATCH 0822/2207] use uintptr_t as an intermediate type between void*
 and uint64_t

This avoids sign-extension problems that may arise when running
32 bit binaries.
---
 sys/dev/netmap/netmap.c         | 58 ++++++++++++++++-----------------
 sys/dev/netmap/netmap_kern.h    |  4 +--
 sys/dev/netmap/netmap_legacy.c  | 36 ++++++++++----------
 sys/dev/netmap/netmap_monitor.c |  6 ++--
 sys/dev/netmap/netmap_pipe.c    |  2 +-
 sys/dev/netmap/netmap_pt.c      |  6 ++--
 sys/dev/netmap/netmap_vale.c    | 22 ++++++-------
 7 files changed, 67 insertions(+), 67 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1c51cf342..95d1caeca 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1474,7 +1474,7 @@ netmap_get_na(struct nmreq_header *hdr,
 	      struct netmap_adapter **na, struct ifnet **ifp,
 	      struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
 	int error = 0;
 	struct netmap_adapter *ret = NULL;
 	int nmd_ref = 0;
@@ -2330,7 +2330,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		switch (hdr->nr_reqtype) {
 		case NETMAP_REQ_REGISTER: {
 			struct nmreq_register *req =
-				(struct nmreq_register *)hdr->nr_body;
+				(struct nmreq_register *)(uintptr_t)hdr->nr_body;
 			/* Protect access to priv from concurrent requests. */
 			NMG_LOCK();
 			do {
@@ -2345,7 +2345,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 #ifdef WITH_EXTMEM
-				opt = nmreq_findoption((struct nmreq_option *)hdr->nr_options,
+				opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 						NETMAP_REQ_OPT_EXTMEM);
 				if (opt != NULL) {
 					struct nmreq_opt_extmem *e =
@@ -2448,7 +2448,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 		case NETMAP_REQ_PORT_INFO_GET: {
 			struct nmreq_port_info_get *req =
-				(struct nmreq_port_info_get *)hdr->nr_body;
+				(struct nmreq_port_info_get *)(uintptr_t)hdr->nr_body;
 
 			NMG_LOCK();
 			do {
@@ -2467,10 +2467,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 					/* get a refcount */
 					hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-					hdr->nr_body = (uint64_t)®req;
+					hdr->nr_body = (uintptr_t)®req;
 					error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
 					hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; /* reset type */
-					hdr->nr_body = (uint64_t)req; /* reset nr_body */
+					hdr->nr_body = (uintptr_t)req; /* reset nr_body */
 					if (error) {
 						na = NULL;
 						ifp = NULL;
@@ -2521,7 +2521,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 		case NETMAP_REQ_PORT_HDR_SET: {
 			struct nmreq_port_hdr *req =
-				(struct nmreq_port_hdr *)hdr->nr_body;
+				(struct nmreq_port_hdr *)(uintptr_t)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
@@ -2537,10 +2537,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			}
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = (uint64_t)®req;
+			hdr->nr_body = (uintptr_t)®req;
 			error = netmap_get_bdg_na(hdr, &na, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			if (na && !error) {
 				struct netmap_vp_adapter *vpna =
 					(struct netmap_vp_adapter *)na;
@@ -2560,7 +2560,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		case NETMAP_REQ_PORT_HDR_GET: {
 			/* Get vnet-header length for this netmap port */
 			struct nmreq_port_hdr *req =
-				(struct nmreq_port_hdr *)hdr->nr_body;
+				(struct nmreq_port_hdr *)(uintptr_t)hdr->nr_body;
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
@@ -2569,10 +2569,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			bzero(®req, sizeof(regreq));
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-			hdr->nr_body = (uint64_t)®req;
+			hdr->nr_body = (uintptr_t)®req;
 			error = netmap_get_na(hdr, &na, &ifp, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			if (na && !error) {
 				req->nr_hdr_len = na->virt_hdr_len;
 			}
@@ -2599,7 +2599,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 #endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			struct nmreq_pools_info *req =
-				(struct nmreq_pools_info *)hdr->nr_body;
+				(struct nmreq_pools_info *)(uintptr_t)hdr->nr_body;
 			/* Get information from the memory allocator. This
 			 * netmap device must already be bound to a port.
 			 * Note that hdr->nr_name is ignored. */
@@ -2778,8 +2778,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		error = EMSGSIZE;
 		goto out_err;
 	}
-	if ((rqsz && hdr->nr_body == (uint64_t)NULL) ||
-		(!rqsz && hdr->nr_body != (uint64_t)NULL)) {
+	if ((rqsz && hdr->nr_body == (uintptr_t)NULL) ||
+		(!rqsz && hdr->nr_body != (uintptr_t)NULL)) {
 		/* Request body expected, but not found; or
 		 * request body found but unexpected. */
 		error = EINVAL;
@@ -2788,8 +2788,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 
 	bufsz = 2 * sizeof(void *) + rqsz;
 	optsz = 0;
-	for (src = (struct nmreq_option *)hdr->nr_options; src;
-	     src = (struct nmreq_option *)buf.nro_next)
+	for (src = (struct nmreq_option *)(uintptr_t)hdr->nr_options; src;
+	     src = (struct nmreq_option *)(uintptr_t)buf.nro_next)
 	{
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)
@@ -2817,11 +2817,11 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	p = (char *)ptrs;
 
 	/* copy the body */
-	error = copyin((void *)hdr->nr_body, p, rqsz);
+	error = copyin((void *)(uintptr_t)hdr->nr_body, p, rqsz);
 	if (error)
 		goto out_restore;
 	/* overwrite the user pointer with the in-kernel one */
-	hdr->nr_body = (uint64_t)p;
+	hdr->nr_body = (uintptr_t)p;
 	p += rqsz;
 
 	/* copy the options */
@@ -2878,7 +2878,7 @@ static int
 nmreq_copyout(struct nmreq_header *hdr, int rerror)
 {
 	struct nmreq_option *src, *dst;
-	void *ker = (void *)hdr->nr_body, *bufstart;
+	void *ker = (void *)(uintptr_t)hdr->nr_body, *bufstart;
 	uint64_t *ptrs;
 	size_t bodysz;
 	int error;
@@ -2890,13 +2890,13 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 	ptrs = (uint64_t *)ker - 2;
 	bufstart = ptrs;
 	hdr->nr_body = *ptrs++;
-	src = (struct nmreq_option *)hdr->nr_options;
+	src = (struct nmreq_option *)(uintptr_t)hdr->nr_options;
 	hdr->nr_options = *ptrs;
 
 	if (!rerror) {
 		/* copy the body */
 		bodysz = nmreq_size_by_type(hdr->nr_reqtype);
-		error = copyout(ker, (void *)hdr->nr_body, bodysz);
+		error = copyout(ker, (void *)(uintptr_t)hdr->nr_body, bodysz);
 		if (error) {
 			rerror = error;
 			goto out;
@@ -2904,7 +2904,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 	}
 
 	/* copy the options */
-	dst = (struct nmreq_option *)hdr->nr_options;
+	dst = (struct nmreq_option *)(uintptr_t)hdr->nr_options;
 	while (src) {
 		size_t optsz;
 		uint64_t next;
@@ -2932,8 +2932,8 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 				}
 			}
 		}
-		src = (struct nmreq_option *)next;
-		dst = (struct nmreq_option *)*ptrs;
+		src = (struct nmreq_option *)(uintptr_t)next;
+		dst = (struct nmreq_option *)(uintptr_t)*ptrs;
 	}
 
 
@@ -2946,7 +2946,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 struct nmreq_option *
 nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
 {
-	for ( ; opt; opt = (struct nmreq_option *)opt->nro_next)
+	for ( ; opt; opt = (struct nmreq_option *)(uintptr_t)opt->nro_next)
 		if (opt->nro_reqtype == reqtype)
 			return opt;
 	return NULL;
@@ -2957,7 +2957,7 @@ nmreq_checkduplicate(struct nmreq_option *opt) {
 	uint16_t type = opt->nro_reqtype;
 	int dup = 0;
 
-	while ((opt = nmreq_findoption((struct nmreq_option *)opt->nro_next,
+	while ((opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)opt->nro_next,
 			type))) {
 		dup++;
 		opt->nro_status = EINVAL;
@@ -2973,8 +2973,8 @@ nmreq_checkoptions(struct nmreq_header *hdr)
 	 * marked as not supported
 	 */
 
-	for (opt = (struct nmreq_option *)hdr->nr_options; opt;
-	     opt = (struct nmreq_option *)opt->nro_next)
+	for (opt = (struct nmreq_option *)(uintptr_t)hdr->nr_options; opt;
+	     opt = (struct nmreq_option *)(uintptr_t)opt->nro_next)
 		if (opt->nro_status == EOPNOTSUPP)
 			return EOPNOTSUPP;
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 033de060a..e2cc49611 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1526,7 +1526,7 @@ int netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 void netmap_monitor_stop(struct netmap_adapter *na);
 #else
 #define netmap_get_monitor_na(hdr, _2, _3, _4) \
-	(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
+	(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
 #endif
 
 #ifdef CONFIG_NET_NS
@@ -2175,7 +2175,7 @@ nm_ptnetmap_host_on(struct netmap_adapter *na)
 }
 #else /* !WITH_PTNETMAP_HOST */
 #define netmap_get_pt_host_na(hdr, _2, _3, _4) \
-	(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
+	(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
 #define ptnetmap_ctl(_1, _2, _3)   EINVAL
 #define nm_ptnetmap_host_on(_1)   EINVAL
 #endif /* !WITH_PTNETMAP_HOST */
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index aeb1802b4..762810a61 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -128,8 +128,8 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 	/* First prepare the request header. */
 	hdr->nr_version = NETMAP_API; /* new API */
 	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
-	hdr->nr_options = (uint64_t)NULL;
-	hdr->nr_body = (uint64_t)NULL;
+	hdr->nr_options = (uintptr_t)NULL;
+	hdr->nr_body = (uintptr_t)NULL;
 
 	switch (ioctl_cmd) {
 	case NIOCREGIF: {
@@ -138,7 +138,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCREGIF operation. */
 			struct nmreq_register *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			if (nmreq_register_from_legacy(nmr, hdr, req)) {
 				goto oom;
@@ -148,7 +148,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_ATTACH: {
 			struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 			if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
 				goto oom;
@@ -163,14 +163,14 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		}
 		case NETMAP_BDG_DETACH: {
 			hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
-			hdr->nr_body = (uint64_t)nm_os_malloc(sizeof(struct nmreq_vale_detach));
+			hdr->nr_body = (uintptr_t)nm_os_malloc(sizeof(struct nmreq_vale_detach));
 			break;
 		}
 		case NETMAP_BDG_VNET_HDR:
 		case NETMAP_VNET_HDR_GET: {
 			struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
 				NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
 			req->nr_hdr_len = nmr->nr_arg1;
@@ -179,7 +179,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_NEWIF : {
 			struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
@@ -196,7 +196,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		case NETMAP_BDG_POLLING_OFF: {
 			struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
 				NETMAP_REQ_VALE_POLLING_ENABLE :
 				NETMAP_REQ_VALE_POLLING_DISABLE;
@@ -228,7 +228,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		if (nmr->nr_cmd == NETMAP_BDG_LIST) {
 			struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
 			req->nr_bridge_idx = nmr->nr_arg1;
 			req->nr_port_idx = nmr->nr_arg2;
@@ -236,7 +236,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			/* Regular NIOCGINFO. */
 			struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
 			if (!req) { goto oom; }
-			hdr->nr_body = (uint64_t)req;
+			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
@@ -254,7 +254,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 oom:
 	if (hdr) {
 		if (hdr->nr_body) {
-			nm_os_free((void *)hdr->nr_body);
+			nm_os_free((void *)(uintptr_t)hdr->nr_body);
 		}
 		nm_os_free(hdr);
 	}
@@ -289,13 +289,13 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	switch (hdr->nr_reqtype) {
 	case NETMAP_REQ_REGISTER: {
 		struct nmreq_register *req =
-			(struct nmreq_register *)hdr->nr_body;
+			(struct nmreq_register *)(uintptr_t)hdr->nr_body;
 		nmreq_register_to_legacy(req, nmr);
 		break;
 	}
 	case NETMAP_REQ_PORT_INFO_GET: {
 		struct nmreq_port_info_get *req =
-			(struct nmreq_port_info_get *)hdr->nr_body;
+			(struct nmreq_port_info_get *)(uintptr_t)hdr->nr_body;
 		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
@@ -307,7 +307,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_VALE_ATTACH: {
 		struct nmreq_vale_attach *req =
-			(struct nmreq_vale_attach *)hdr->nr_body;
+			(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
 		nmreq_register_to_legacy(&req->reg, nmr);
 		break;
 	}
@@ -316,7 +316,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	}
 	case NETMAP_REQ_VALE_LIST: {
 		struct nmreq_vale_list *req =
-			(struct nmreq_vale_list *)hdr->nr_body;
+			(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
 		strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
@@ -325,13 +325,13 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_PORT_HDR_SET:
 	case NETMAP_REQ_PORT_HDR_GET: {
 		struct nmreq_port_hdr *req =
-			(struct nmreq_port_hdr *)hdr->nr_body;
+			(struct nmreq_port_hdr *)(uintptr_t)hdr->nr_body;
 		nmr->nr_arg1 = req->nr_hdr_len;
 		break;
 	}
 	case NETMAP_REQ_VALE_NEWIF: {
 		struct nmreq_vale_newif *req =
-			(struct nmreq_vale_newif *)hdr->nr_body;
+			(struct nmreq_vale_newif *)(uintptr_t)hdr->nr_body;
 		nmr->nr_tx_slots = req->nr_tx_slots;
 		nmr->nr_rx_slots = req->nr_rx_slots;
 		nmr->nr_tx_rings = req->nr_tx_rings;
@@ -371,7 +371,7 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			nmreq_to_legacy(hdr, nmr);
 		}
 		if (hdr->nr_body) {
-			nm_os_free((void *)hdr->nr_body);
+			nm_os_free((void *)(uintptr_t)hdr->nr_body);
 		}
 		nm_os_free(hdr);
 		break;
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 9e96e25e6..ebb96a5f9 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -829,7 +829,7 @@ int
 netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
 	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_monitor_adapter *mna;
@@ -856,9 +856,9 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	 */
 	memcpy(&preq, req, sizeof(preq));
 	preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
-	hdr->nr_body = (uint64_t)&preq;
+	hdr->nr_body = (uintptr_t)&preq;
 	error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
-	hdr->nr_body = (uint64_t)req;
+	hdr->nr_body = (uintptr_t)req;
 	if (error) {
 		D("parent lookup failed: %d", error);
 		return error;
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 89ae0cf5d..1b3bfcef9 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -609,7 +609,7 @@ int
 netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
 	struct ifnet *ifp = NULL;
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index cfa32b0bc..bf7872ff2 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1160,7 +1160,7 @@ int
 netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-    struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
+    struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
     struct nmreq_register preq;
     struct netmap_adapter *parent; /* target adapter */
     struct netmap_pt_host_adapter *pth_na;
@@ -1186,9 +1186,9 @@ netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
      */
     memcpy(&preq, req, sizeof(preq));
     preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    hdr->nr_body = (uint64_t)&preq;
+    hdr->nr_body = (uintptr_t)&preq;
     error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
-    hdr->nr_body = (uint64_t)req;
+    hdr->nr_body = (uintptr_t)req;
     if (error) {
         D("parent lookup failed: %d", error);
         goto put_out_noputparent;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 9d2cb9234..6ffa29d85 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -677,7 +677,7 @@ int
 nm_vi_create(struct nmreq_header *hdr)
 {
 	struct nmreq_vale_newif *req =
-		(struct nmreq_vale_newif *)hdr->nr_body;
+		(struct nmreq_vale_newif *)(uintptr_t)hdr->nr_body;
 	int error = 0;
 	/* Build a nmreq_register out of the nmreq_vale_newif,
 	 * so that we can call netmap_get_bdg_na(). */
@@ -689,10 +689,10 @@ nm_vi_create(struct nmreq_header *hdr)
 	regreq.nr_rx_rings = req->nr_rx_rings;
 	regreq.nr_mem_id = req->nr_mem_id;
 	hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-	hdr->nr_body = (uint64_t)®req;
+	hdr->nr_body = (uintptr_t)®req;
 	error = netmap_vi_create(hdr, 0 /* no autodelete */);
 	hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	hdr->nr_body = (uint64_t)req;
+	hdr->nr_body = (uintptr_t)req;
         /* Write back to the original struct. */
 	req->nr_tx_slots = regreq.nr_tx_slots;
 	req->nr_rx_slots = regreq.nr_rx_slots;
@@ -770,7 +770,7 @@ nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
 int
 netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 {
-	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
 	struct ifnet *ifp;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_mem_d *nmd = NULL;
@@ -975,7 +975,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 			/* Check if we need to skip the host rings. */
 			struct nmreq_vale_attach *areq =
-				(struct nmreq_vale_attach *)hdr->nr_body;
+				(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
 			if (areq->reg.nr_mode != NR_REG_NIC_SW) {
 				hostna = NULL;
 			}
@@ -1015,7 +1015,7 @@ int
 nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 {
 	struct nmreq_vale_attach *req =
-		(struct nmreq_vale_attach *)hdr->nr_body;
+		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
 	struct netmap_vp_adapter * vpna;
 	struct netmap_adapter *na;
 	struct netmap_mem_d *nmd = NULL;
@@ -1092,7 +1092,7 @@ nm_is_bwrap(struct netmap_adapter *na)
 int
 nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
 {
-	struct nmreq_vale_detach *nmreq_det = (void *)hdr->nr_body;
+	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	struct nm_bridge *b = NULL;
@@ -1411,7 +1411,7 @@ int
 nm_bdg_polling(struct nmreq_header *hdr)
 {
 	struct nmreq_vale_polling *req =
-		(struct nmreq_vale_polling *)hdr->nr_body;
+		(struct nmreq_vale_polling *)(uintptr_t)hdr->nr_body;
 	struct netmap_adapter *na = NULL;
 	int error = 0;
 
@@ -1444,7 +1444,7 @@ int
 netmap_bdg_list(struct nmreq_header *hdr)
 {
 	struct nmreq_vale_list *req =
-		(struct nmreq_vale_list *)hdr->nr_body;
+		(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
 	int namelen = strlen(hdr->nr_name);
 	struct nm_bridge *b, *bridges;
 	struct netmap_vp_adapter *vpna;
@@ -2446,7 +2446,7 @@ static int
 netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
-	struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_adapter *na;
 	int error = 0;
@@ -2973,7 +2973,7 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 
 	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
 		struct nmreq_vale_attach *req =
-			(struct nmreq_vale_attach *)hdr->nr_body;
+			(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
 		if (req->reg.nr_ringid != 0 ||
 			(req->reg.nr_mode != NR_REG_ALL_NIC &&
 				req->reg.nr_mode != NR_REG_NIC_SW)) {

From 836e778ba2c85d99f34aabba3dcada6ad6703a0c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 08:54:33 +0200
Subject: [PATCH 0823/2207] freebsd: fix compilation issue on i386-LINT

Reported by lwhsu@freebsd.org
---
 sys/dev/netmap/netmap_freebsd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 2e0801f2d..fe7269f1f 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -630,7 +630,7 @@ struct nm_os_extmem {
 void
 nm_os_extmem_delete(struct nm_os_extmem *e)
 {
-	D("freeing %lx bytes", e->size);
+	D("freeing %jx bytes", (uintmax_t)e->size);
 	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
 	nm_os_free(e);
 }
@@ -699,7 +699,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
 			VM_PROT_READ | VM_PROT_WRITE, 0);
 	if (rv != KERN_SUCCESS) {
-		D("vm_map_find(%lx) failed", e->size);
+		D("vm_map_find(%jx) failed", (uintmax_t)e->size);
 		goto out_rel;
 	}
 	rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,

From cb03797e7f6adc4f0f9a137ece5c537a5f5993b5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 09:18:50 +0200
Subject: [PATCH 0824/2207] linux: netmap.mak: extend format command

---
 LINUX/netmap.mak.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 08a10a6ff..451265b13 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -172,4 +172,4 @@ distclean: clean $(S_DRIVERS:%=distclean-%)
 	rm -rf build-utils
 
 format:
-	clang-format -i -style=file $(shell git ls-files "utils/*.[ch]" "apps/*.[ch]" "extra/*.[ch]" "LINUX/*.[ch]" "WINDOWS/*.[ch]")
+	clang-format -i -style=file $(shell git ls-files "utils/*.[ch]" "apps/*.[ch]" "extra/*.[ch]" "LINUX/*.[ch]" "WINDOWS/*.[ch]" "sys/*.[ch]")

From 1ad6b9c2ba77186587077495cea711e887d218e0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 09:28:31 +0200
Subject: [PATCH 0825/2207] sys/dev/netmap/: small indentation fixes

---
 sys/dev/netmap/netmap.c      | 12 ++++++------
 sys/dev/netmap/netmap_kern.h |  4 ++--
 sys/dev/netmap/netmap_mem2.c | 10 +++++-----
 sys/dev/netmap/netmap_pipe.c |  2 +-
 sys/dev/netmap/netmap_vale.c |  6 +++---
 5 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 95d1caeca..b7b4fbf83 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -828,7 +828,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	n[NR_TX] = na->num_tx_rings + 1;
 	n[NR_RX] = na->num_rx_rings + 1;
 
-	len = (n[NR_TX] + n[NR_RX]) * 
+	len = (n[NR_TX] + n[NR_RX]) *
 		(sizeof(struct netmap_kring) + sizeof(struct netmap_kring *))
 		+ tailroom;
 
@@ -839,7 +839,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	}
 	na->rx_rings = na->tx_rings + n[NR_TX];
 	na->tailroom = na->rx_rings + n[NR_RX];
- 
+
 	/* link the krings in the krings array */
 	kring = (struct netmap_kring *)((char *)na->tailroom + tailroom);
 	for (i = 0; i < n[NR_TX] + n[NR_RX]; i++) {
@@ -2920,7 +2920,7 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 			rerror = error;
 			goto out;
 		}
-		       
+
 		/* copy the option body only if there was no error */
 		if (!rerror && !src->nro_status) {
 			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
@@ -3647,9 +3647,9 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	 */
 	mbq_lock(q);
 
-        busy = kring->nr_hwtail - kring->nr_hwcur;
-        if (busy < 0)
-                busy += kring->nkr_num_slots;
+	busy = kring->nr_hwtail - kring->nr_hwcur;
+	if (busy < 0)
+		busy += kring->nkr_num_slots;
 	if (busy + mbq_len(q) >= kring->nkr_num_slots - 1) {
 		RD(2, "%s full hwcur %d hwtail %d qlen %d", na->name,
 			kring->nr_hwcur, kring->nr_hwtail, mbq_len(q));
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e2cc49611..7d1134d5e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -448,7 +448,7 @@ struct netmap_kring {
 
 	/* the adapter the owns this kring */
 	struct netmap_adapter *na;
-	
+
 	/* the adapter that wants to be notified when this kring has
 	 * new slots avaialable. This is usually the same as the above,
 	 * but wrappers may let it point to themselves
@@ -1821,7 +1821,7 @@ struct lut_entry {
 };
 #else /* linux & _WIN32 */
 /* dma-mapping in linux can assign a buffer a different address
- * depending on the device, so we need to have a separate 
+ * depending on the device, so we need to have a separate
  * physical-address look-up table for each na.
  * We can still share the vaddrs, though, therefore we split
  * the lut_entry structure.
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index dec807999..5629dc93c 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1644,7 +1644,7 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
  * allocator for private memory
  */
 static void *
-_netmap_mem_private_new(size_t size, struct netmap_obj_params *p, 
+_netmap_mem_private_new(size_t size, struct netmap_obj_params *p,
 		struct netmap_mem_ops *ops, int *perr)
 {
 	struct netmap_mem_d *d = NULL;
@@ -2155,7 +2155,7 @@ netmap_mem_ext_delete(struct netmap_mem_d *d)
 
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &d->pools[i];
-		
+
 		if (p->lut) {
 			nm_free_lut(p->lut, p->objtotal);
 			p->lut = NULL;
@@ -2215,7 +2215,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 			pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize,
 			pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize,
 			pi->nr_buf_pool_objtotal, pi->nr_buf_pool_objsize);
-		
+
 	os = nm_os_extmem_create(usrptr, pi, &error);
 	if (os == NULL) {
 		D("os extmem creation failed");
@@ -2238,7 +2238,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 			&error);
 	if (nme == NULL)
 		goto out_unmap;
-					
+
 	nr_pages = nm_os_extmem_nr_pages(os);
 
 	/* from now on pages will be released by nme destructor;
@@ -2262,7 +2262,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 			error = ENOMEM;
 			goto out_delete;
 		}
-		
+
 		p->bitmap_slots = (o->num + sizeof(uint32_t) - 1) / sizeof(uint32_t);
 		p->invalid_bitmap = nm_os_malloc(sizeof(uint32_t) * p->bitmap_slots);
 		if (p->invalid_bitmap == NULL) {
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 1b3bfcef9..eb59402a2 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -575,7 +575,7 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 
 	netmap_mem_rings_delete(na);
 	netmap_krings_delete(na); /* also zeroes tx_rings etc. */
-	
+
 	if (ona->tx_rings == NULL) {
 		/* already deleted, we must be on an
                  * cleanup-after-error path */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 6ffa29d85..a36cc3a82 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -229,7 +229,7 @@ struct nm_bridge {
 	 * The function is set by netmap_bdg_regops().
 	 */
 	struct netmap_bdg_ops *bdg_ops;
-	
+
 	/*
 	 * Contains the data structure used by the bdg_ops.lookup function.
 	 * By default points to *ht which is allocated on attach and used by the default lookup
@@ -540,7 +540,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	netmap_bdg_free(b);
 }
 
-static inline void * 
+static inline void *
 nm_bdg_get_auth_token(struct nm_bridge *b)
 {
 	return b->ht;
@@ -1526,7 +1526,7 @@ netmap_bdg_list(struct nmreq_header *hdr)
  *
  * Called without NMG_LOCK.
  */
- 
+
 int
 netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token)
 {

From c7de6a4fcab5d7310e5743ef6ee9705f1ecda07d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Apr 2018 09:13:19 +0200
Subject: [PATCH 0826/2207] linux/i40e: fix access to possibily unallocated
 kring

---
 LINUX/i40e_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index f828abf13..4a75c5816 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -171,12 +171,12 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 
 	na = NA(ring->netdev);
 	ring_nr = ring->queue_index;
-	kring = na->rx_rings[ring_nr];
 
 	slot = netmap_reset(na, NR_RX, ring_nr, 0);
 	if (!slot)
 		return 0;	// not in native netmap mode
 
+	kring = na->rx_rings[ring_nr];
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
 
 	for (i = 0; i < na->num_rx_desc; i++) {

From 4d667c468dca30a4257bec739914a8a045703466 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 09:40:31 +0200
Subject: [PATCH 0827/2207] apps: small indentation fixes

---
 apps/bridge/bridge.c     | 22 +++++++--------
 apps/dedup/dedup.c       |  6 ++---
 apps/lb/lb.c             |  6 ++---
 apps/pkt-gen/pkt-gen.c   | 44 +++++++++++++++---------------
 apps/tlem/tlem.c         | 58 ++++++++++++++++++++--------------------
 apps/vale-ctl/vale-ctl.c | 32 +++++++++++-----------
 6 files changed, 84 insertions(+), 84 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index b53b60e1b..35bfdc593 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -34,18 +34,18 @@ sigint_h(int sig)
 int
 pkt_queued(struct nm_desc *d, int tx)
 {
-        u_int i, tot = 0;
+	u_int i, tot = 0;
 
-        if (tx) {
-                for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) {
-                        tot += nm_ring_space(NETMAP_TXRING(d->nifp, i));
-                }
-        } else {
-                for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
-                        tot += nm_ring_space(NETMAP_RXRING(d->nifp, i));
-                }
-        }
-        return tot;
+	if (tx) {
+		for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) {
+			tot += nm_ring_space(NETMAP_TXRING(d->nifp, i));
+		}
+	} else {
+		for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
+			tot += nm_ring_space(NETMAP_RXRING(d->nifp, i));
+		}
+	}
+	return tot;
 }
 
 /*
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 537e0e2fe..95bdf633a 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -77,7 +77,7 @@ dedup_set_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t buf_h
 		return buf_head;
 	for (scan = buf_head, s = d->fifo_slot;
 	     scan != 0 && s != d->fifo_slot + d->fifo_size;
-             scan = *(uint32_t *)NETMAP_BUF(r, scan), s++) {
+	     scan = *(uint32_t *)NETMAP_BUF(r, scan), s++) {
 		s->len = r->nr_buf_size;
 		s->buf_idx = scan;
 	}
@@ -103,10 +103,10 @@ dedup_get_fifo_buffers(struct dedup *d, struct netmap_ring *ring, uint32_t *buf_
 	for (i = 0; i < d->fifo_size; i++) {
 		struct netmap_slot *s = d->fifo_slot + i;
 		uint32_t *new_head = (uint32_t *)NETMAP_BUF(r, s->buf_idx);
-		
+
 		*new_head = *buf_head;
 		*buf_head = s->buf_idx;
-	}	
+	}
 	free(d->fifo_slot);
 	d->fifo_slot = NULL;
 }
diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 51a678631..01d09b421 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -409,7 +409,7 @@ parse_pipes(char *spec)
 	char *end = index(spec, ':');
 	static int max_groups = 0;
 	struct group_des *g;
-       
+
 	ND("spec %s num_groups %d", spec, glob_arg.num_groups);
 	if (max_groups < glob_arg.num_groups + 1) {
 		size_t size = sizeof(*g) * (glob_arg.num_groups + 1);
@@ -655,7 +655,7 @@ int main(int argc, char **argv)
 	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
 	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
 		;
-	*nscan = '\0';	
+	*nscan = '\0';
 
 	if (glob_arg.num_groups == 0)
 		parse_pipes("");
@@ -887,7 +887,7 @@ int main(int argc, char **argv)
 		for (i = glob_arg.num_groups - 1U; i > 0; i--) {
 			struct group_des *g = &groups[i - 1];
 			int j;
-			
+
 			for (j = 0; j < g->nports; j++) {
 				struct port_des *p = &g->ports[j];
 				struct netmap_ring *ring = p->ring;
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 7a7b9f342..0355fa2e3 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -77,12 +77,12 @@ static void usage(int);
 #define cpuset_t        DWORD_PTR   //uint64_t
 static inline void CPU_ZERO(cpuset_t *p)
 {
-        *p = 0;
+	*p = 0;
 }
 
 static inline void CPU_SET(uint32_t i, cpuset_t *p)
 {
-        *p |= 1<< (i & 0x3f);
+	*p |= 1<< (i & 0x3f);
 }
 
 #define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c)    //((void)a, 0)
@@ -162,12 +162,12 @@ ether_ntoa(const struct ether_addr *n)
 #define cpuset_t        uint64_t        // XXX
 static inline void CPU_ZERO(cpuset_t *p)
 {
-        *p = 0;
+	*p = 0;
 }
 
 static inline void CPU_SET(uint32_t i, cpuset_t *p)
 {
-        *p |= 1<< (i & 0x3f);
+	*p |= 1<< (i & 0x3f);
 }
 
 #define pthread_setaffinity_np(a, b, c) ((void)a, 0)
@@ -176,7 +176,7 @@ static inline void CPU_SET(uint32_t i, cpuset_t *p)
 #define IFF_PPROMISC   IFF_PROMISC
 #include   /* LLADDR */
 #define clock_gettime(a,b)      \
-        do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
+	do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
 #endif  /* __APPLE__ */
 
 const char *default_payload="netmap pkt-gen DIRECT payload\n"
@@ -613,7 +613,7 @@ parse_nmr_config(const char* conf, struct nmreq *nmr)
 			nmr->nr_rx_rings, nmr->nr_rx_slots);
 	free(w);
 	return (nmr->nr_tx_rings || nmr->nr_tx_slots ||
-                        nmr->nr_rx_rings || nmr->nr_rx_slots) ?
+		nmr->nr_rx_rings || nmr->nr_rx_slots) ?
 		NM_OPEN_RING_CFG : 0;
 }
 
@@ -679,15 +679,15 @@ setaffinity(pthread_t me, int i)
 static uint32_t
 checksum(const void *data, uint16_t len, uint32_t sum)
 {
-        const uint8_t *addr = data;
+	const uint8_t *addr = data;
 	uint32_t i;
 
-        /* Checksum all the pairs of bytes first... */
-        for (i = 0; i < (len & ~1U); i += 2) {
-                sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
-                if (sum > 0xFFFF)
-                        sum -= 0xFFFF;
-        }
+	/* Checksum all the pairs of bytes first... */
+	for (i = 0; i < (len & ~1U); i += 2) {
+		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
 	/*
 	 * If there's a single byte left over, checksum it, too.
 	 * Network byte order is big-endian, so the remaining byte is
@@ -1037,7 +1037,7 @@ initialize_packet(struct targ *targ)
 		/* Magic: taken from sbin/dhclient/packet.c */
 		udp.uh_sum = wrapsum(
 		    checksum(&udp, sizeof(udp),	/* udp header */
-                    checksum(pkt->ipv4.body,	/* udp payload */
+		    checksum(pkt->ipv4.body,	/* udp payload */
 		    paylen - sizeof(udp),
 		    checksum(&pkt->ipv4.ip.ip_src, /* pseudo header */
 			2 * sizeof(pkt->ipv4.ip.ip_src),
@@ -1528,7 +1528,7 @@ sender_body(void *data)
 		wait_time(targ->tic);
 		nexttime = targ->tic;
 	}
-        if (targ->g->dev_type == DEV_TAP) {
+	if (targ->g->dev_type == DEV_TAP) {
 	    D("writing to file desc %d", targ->g->main_fd);
 
 	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
@@ -1766,7 +1766,7 @@ receiver_body(void *data)
 		/* XXX should we poll ? */
 		pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap,
 			(u_char *)&targ->ctr);
-                targ->ctr.events++;
+		targ->ctr.events++;
 	}
 #endif /* !NO_PCAP */
     } else {
@@ -2630,9 +2630,9 @@ tap_alloc(char *dev)
 	D("new name is %s", dev);
 #endif /* linux */
 
-        /* this is the special file descriptor that the caller will use to talk
-         * with the virtual interface */
-        return fd;
+	/* this is the special file descriptor that the caller will use to talk
+	 * with the virtual interface */
+	return fd;
 }
 
 int
@@ -2685,9 +2685,9 @@ main(int arc, char **argv)
 			usage(-1);
 			break;
 
-                case 'h':
-                        usage(0);
-                        break;
+		case 'h':
+			usage(0);
+			break;
 		case '4':
 			g.af = AF_INET;
 			break;
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 121fbc8ed..7b4b6a956 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -163,18 +163,18 @@ static int do_abort = 0;
 #define cpuset_t        uint64_t        // XXX
 static inline void CPU_ZERO(cpuset_t *p)
 {
-        *p = 0;
+	*p = 0;
 }
 
 static inline void CPU_SET(uint32_t i, cpuset_t *p)
 {
-        *p |= 1<< (i & 0x3f);
+	*p |= 1<< (i & 0x3f);
 }
 
 #define pthread_setaffinity_np(a, b, c) ((void)a, 0)
 #define sched_setscheduler(a, b, c)	(1) /* error */
 #define clock_gettime(a,b)      \
-        do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
+	do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
 
 #define	_P64	unsigned long
 #endif
@@ -394,30 +394,30 @@ struct pipe_args {
 static int
 setaffinity(int i)
 {
-        cpuset_t cpumask;
+	cpuset_t cpumask;
 	struct sched_param p;
 	int error;
 
-        if (i == -1)
-                return 0;
+	if (i == -1)
+		return 0;
 
-        /* Set thread affinity affinity.*/
-        CPU_ZERO(&cpumask);
-        CPU_SET(i, &cpumask);
+	/* Set thread affinity affinity.*/
+	CPU_ZERO(&cpumask);
+	CPU_SET(i, &cpumask);
 
-        if ( (error = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t), &cpumask)) != 0) {
-                ED("Unable to set affinity to cpu %d: %s", i, strerror(error));
-        }
+	if ( (error = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t), &cpumask)) != 0) {
+		ED("Unable to set affinity to cpu %d: %s", i, strerror(error));
+	}
 	if (setpriority(PRIO_PROCESS, 0, -10)) {; // XXX not meaningful
-                ED("Unable to set priority: %s", strerror(errno));
+		ED("Unable to set priority: %s", strerror(errno));
 	}
 	bzero(&p, sizeof(p));
 	p.sched_priority = 10; // 99 on linux ?
 	// use SCHED_RR or SCHED_FIFO
 	if (sched_setscheduler(0, SCHED_RR, &p)) {
-                ED("Unable to set scheduler: %s", strerror(errno));
+		ED("Unable to set scheduler: %s", strerror(errno));
 	}
-        return 0;
+	return 0;
 }
 
 
@@ -684,7 +684,7 @@ scan_ring(struct _qs *q, int next /* bool */)
 	continue;
     }
     if (q->si > pa->last_rx_ring) { /* no data, cur == tail */
-        ND(5, "no more pkts on %s", q->prod_ifname);
+	ND(5, "no more pkts on %s", q->prod_ifname);
 	return;
     }
 got_one:
@@ -807,7 +807,7 @@ cons(void *_pa)
 	pre_end = q->buf + p->next + 2048;
 #if 1
 	/* prefetch the first line saves 4ns */
-        (void)pre_end;//   __builtin_prefetch(pre_end - 2048);
+	(void)pre_end;//   __builtin_prefetch(pre_end - 2048);
 #else
 	/* prefetch, ideally up to a full packet not just one line.
 	 * this does not seem to have a huge effect.
@@ -1588,38 +1588,38 @@ exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 #define	PTS_D_EXP	512
 	uint64_t i, d_av, d_min, *t; /*table of values */
 
-        (void)q;
-        if (strcmp(av[0], "exp") != 0)
+	(void)q;
+	if (strcmp(av[0], "exp") != 0)
 		return 2; /* not recognised */
-        if (ac != 3)
-                return 1; /* error */
-        d_av = parse_time(av[1]);
-        d_min = parse_time(av[2]);
-        if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min)
-                return 1; /* error */
+	if (ac != 3)
+		return 1; /* error */
+	d_av = parse_time(av[1]);
+	d_min = parse_time(av[2]);
+	if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min)
+		return 1; /* error */
 	d_av -= d_min;
 	dst->arg_len = PTS_D_EXP * sizeof(uint64_t);
 	dst->arg = calloc(1, dst->arg_len);
 	if (dst->arg == NULL)
 		return 1; /* no memory */
 	t = (uint64_t *)dst->arg;
-        q->max_delay = d_av * 4 + d_min; /* exp(-4) */
+	q->max_delay = d_av * 4 + d_min; /* exp(-4) */
 	/* tabulate -ln(1-n)*delay  for n in 0..1 */
 	for (i = 0; i < PTS_D_EXP; i++) {
 		double d = -log2 ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min;
 		t[i] = (uint64_t)d;
 		ND(5, "%ld: %le", i, d);
 	}
-        return 0;
+	return 0;
 }
 
 static int
 exp_delay_run(struct _qs *q, struct _cfg *arg)
 {
 	uint64_t *t = (uint64_t *)arg->arg;
-        q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)];
+	q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)];
 	RD(5, "delay %llu", (unsigned long long)q->cur_delay);
-        return 0;
+	return 0;
 }
 
 
diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index 0b12abfae..98c1d333c 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -200,22 +200,22 @@ static void
 usage(int errcode)
 {
     fprintf(stderr,
-            "Usage:\n"
-            "vale-ctl arguments\n"
-            "\t-g interface	interface name to get info\n"
-            "\t-d interface	interface name to be detached\n"
-            "\t-a interface	interface name to be attached\n"
-            "\t-h interface	interface name to be attached with the host stack\n"
-            "\t-n interface	interface name to be created\n"
-            "\t-r interface	interface name to be deleted\n"
-            "\t-l list all or specified bridge's interfaces (default)\n"
-            "\t-C string ring/slot setting of an interface creating by -n\n"
-            "\t-p interface start polling. Additional -C x,y,z configures\n"
-            "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n"
-            "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n"
-            "\t\t z: (ONE_NIC only) num of total cores/rings\n"
-            "\t-P interface stop polling\n"
-            "\t-m memid to use when creating a new interface\n");
+	    "Usage:\n"
+	    "vale-ctl arguments\n"
+	    "\t-g interface	interface name to get info\n"
+	    "\t-d interface	interface name to be detached\n"
+	    "\t-a interface	interface name to be attached\n"
+	    "\t-h interface	interface name to be attached with the host stack\n"
+	    "\t-n interface	interface name to be created\n"
+	    "\t-r interface	interface name to be deleted\n"
+	    "\t-l list all or specified bridge's interfaces (default)\n"
+	    "\t-C string ring/slot setting of an interface creating by -n\n"
+	    "\t-p interface start polling. Additional -C x,y,z configures\n"
+	    "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n"
+	    "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n"
+	    "\t\t z: (ONE_NIC only) num of total cores/rings\n"
+	    "\t-P interface stop polling\n"
+	    "\t-m memid to use when creating a new interface\n");
     exit(errcode);
 }
 

From e6da37bc69ce385525178cbbf17c10e0891b13a2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 09:49:51 +0200
Subject: [PATCH 0828/2207] sys/dev/netmap: fix more indentation issues

---
 sys/dev/netmap/netmap.c         |  12 ++--
 sys/dev/netmap/netmap_freebsd.c |  38 +++++------
 sys/dev/netmap/netmap_generic.c |  10 +--
 sys/dev/netmap/netmap_mem2.c    |  28 ++++----
 sys/dev/netmap/netmap_monitor.c |  14 ++--
 sys/dev/netmap/netmap_pipe.c    |  98 ++++++++++++++--------------
 sys/dev/netmap/netmap_vale.c    | 110 ++++++++++++++++----------------
 7 files changed, 155 insertions(+), 155 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b7b4fbf83..5070854bc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1004,9 +1004,9 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 		if (netmap_verbose)
 			D("deleting last instance for %s", na->name);
 
-                if (nm_netmap_on(na)) {
-                    D("BUG: netmap on while going to delete the krings");
-                }
+		if (nm_netmap_on(na)) {
+			D("BUG: netmap on while going to delete the krings");
+		}
 
 		na->nm_krings_delete(na);
 	}
@@ -1322,7 +1322,7 @@ netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
 			m_copydata(m, 0, len, NMB(na, slot));
 			ND("nm %d len %d", nm_i, len);
 			if (netmap_verbose)
-                                D("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
+				D("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
 
 			slot->len = len;
 			slot->flags = 0;
@@ -2317,8 +2317,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		 * For convenince, the nr_body pointer and the pointers
 		 * in the options list will be replaced with their
 		 * kernel-space counterparts. The original pointers are
-                * saved internally and later restored by nmreq_copyout
-                */
+		 * saved internally and later restored by nmreq_copyout
+		 */
 		error = nmreq_copyin(hdr, nr_body_is_user);
 		if (error) {
 			return error;
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index fe7269f1f..b7b0bcd3e 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -136,13 +136,13 @@ nm_os_put_module(void)
 static void
 netmap_ifnet_arrival_handler(void *arg __unused, struct ifnet *ifp)
 {
-        netmap_undo_zombie(ifp);
+	netmap_undo_zombie(ifp);
 }
 
 static void
 netmap_ifnet_departure_handler(void *arg __unused, struct ifnet *ifp)
 {
-        netmap_make_zombie(ifp);
+	netmap_make_zombie(ifp);
 }
 
 static eventhandler_tag nm_ifnet_ah_tag;
@@ -151,33 +151,33 @@ static eventhandler_tag nm_ifnet_dh_tag;
 int
 nm_os_ifnet_init(void)
 {
-        nm_ifnet_ah_tag =
-                EVENTHANDLER_REGISTER(ifnet_arrival_event,
-                        netmap_ifnet_arrival_handler,
-                        NULL, EVENTHANDLER_PRI_ANY);
-        nm_ifnet_dh_tag =
-                EVENTHANDLER_REGISTER(ifnet_departure_event,
-                        netmap_ifnet_departure_handler,
-                        NULL, EVENTHANDLER_PRI_ANY);
-        return 0;
+	nm_ifnet_ah_tag =
+		EVENTHANDLER_REGISTER(ifnet_arrival_event,
+				netmap_ifnet_arrival_handler,
+				NULL, EVENTHANDLER_PRI_ANY);
+	nm_ifnet_dh_tag =
+		EVENTHANDLER_REGISTER(ifnet_departure_event,
+				netmap_ifnet_departure_handler,
+				NULL, EVENTHANDLER_PRI_ANY);
+	return 0;
 }
 
 void
 nm_os_ifnet_fini(void)
 {
-        EVENTHANDLER_DEREGISTER(ifnet_arrival_event,
-                nm_ifnet_ah_tag);
-        EVENTHANDLER_DEREGISTER(ifnet_departure_event,
-                nm_ifnet_dh_tag);
+	EVENTHANDLER_DEREGISTER(ifnet_arrival_event,
+			nm_ifnet_ah_tag);
+	EVENTHANDLER_DEREGISTER(ifnet_departure_event,
+			nm_ifnet_dh_tag);
 }
 
 unsigned
 nm_os_ifnet_mtu(struct ifnet *ifp)
 {
 #if __FreeBSD_version < 1100030
-       return ifp->if_data.ifi_mtu;
+	return ifp->if_data.ifi_mtu;
 #else /* __FreeBSD_version >= 1100030 */
-       return ifp->if_mtu;
+	return ifp->if_mtu;
 #endif
 }
 
@@ -623,7 +623,7 @@ nm_os_vi_detach(struct ifnet *ifp)
 struct nm_os_extmem {
 	vm_object_t obj;
 	vm_offset_t kva;
-        vm_offset_t size;
+	vm_offset_t size;
 	vm_pindex_t scan;
 };
 
@@ -1517,7 +1517,7 @@ freebsd_netmap_poll(struct cdev *cdevi __unused, int events, struct thread *td)
 
 static int
 freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
-        int ffla __unused, struct thread *td)
+		int ffla __unused, struct thread *td)
 {
 	int error;
 	struct netmap_priv_d *priv;
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index aab0bf013..3a6ad0fe3 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -233,14 +233,14 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 	for ((_k)=*(_karr), (_i) = 0; (_i) < (_n); (_i)++, (_k) = (_karr)[(_i)])
 
 #define for_each_tx_kring(_i, _k, _na) \
-            for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings)
+		for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings)
 #define for_each_tx_kring_h(_i, _k, _na) \
-            for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings + 1)
+		for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings + 1)
 
 #define for_each_rx_kring(_i, _k, _na) \
-            for_each_kring_n(_i, _k, (_na)->rx_rings, (_na)->num_rx_rings)
+		for_each_kring_n(_i, _k, (_na)->rx_rings, (_na)->num_rx_rings)
 #define for_each_rx_kring_h(_i, _k, _na) \
-            for_each_kring_n(_i, _k, (_na)->rx_rings, (_na)->num_rx_rings + 1)
+		for_each_kring_n(_i, _k, (_na)->rx_rings, (_na)->num_rx_rings + 1)
 
 
 /* ======================== PERFORMANCE STATISTICS =========================== */
@@ -584,7 +584,7 @@ generic_mbuf_destructor(struct mbuf *m)
 	 * MBUF_TXQ(m) under our feet. If the match is not found
 	 * on 'r', we try to see if it belongs to some other ring.
 	 */
-        for (;;) {
+	for (;;) {
 		bool match = false;
 
 		kring = na->tx_rings[r];
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 5629dc93c..4ac9f4cf0 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -671,10 +671,10 @@ nm_mem_assign_id_locked(struct netmap_mem_d *nmd)
 static int
 nm_mem_assign_id(struct netmap_mem_d *nmd)
 {
-        int ret;
+	int ret;
 
 	NM_MTX_LOCK(nm_mem_list_lock);
-        ret = nm_mem_assign_id_locked(nmd);
+	ret = nm_mem_assign_id_locked(nmd);
 	NM_MTX_UNLOCK(nm_mem_list_lock);
 
 	return ret;
@@ -1141,7 +1141,7 @@ netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n)
 static void
 netmap_extra_free(struct netmap_adapter *na, uint32_t head)
 {
-        struct lut_entry *lut = na->na_lut.lut;
+	struct lut_entry *lut = na->na_lut.lut;
 	struct netmap_mem_d *nmd = na->nm_mem;
 	struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL];
 	uint32_t i, cur, *buf;
@@ -1572,7 +1572,7 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	if (lut->plut == NULL) {
 		D("Failed to allocate physical lut for %s", na->name);
 		return ENOMEM;
-        }
+	}
 
 	for (i = 0; i < lim; i += p->_clustentries) {
 		lut->plut[i].paddr = 0;
@@ -1722,16 +1722,16 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 	if (p[NETMAP_RING_POOL].size < v)
 		p[NETMAP_RING_POOL].size = v;
 	/* each pipe endpoint needs two tx rings (1 normal + 1 host, fake)
-         * and two rx rings (again, 1 normal and 1 fake host)
-         */
+	 * and two rx rings (again, 1 normal and 1 fake host)
+	 */
 	v = txr + rxr + 8 * npipes;
 	if (p[NETMAP_RING_POOL].num < v)
 		p[NETMAP_RING_POOL].num = v;
 	/* for each pipe we only need the buffers for the 4 "real" rings.
-         * On the other end, the pipe ring dimension may be different from
-         * the parent port ring dimension. As a compromise, we allocate twice the
-         * space actually needed if the pipe rings were the same size as the parent rings
-         */
+	 * On the other end, the pipe ring dimension may be different from
+	 * the parent port ring dimension. As a compromise, we allocate twice the
+	 * space actually needed if the pipe rings were the same size as the parent rings
+	 */
 	v = (4 * npipes + rxr) * rxd + (4 * npipes + txr) * txd + 2 + extra_bufs;
 		/* the +2 is for the tx and rx fake buffers (indices 0 and 1) */
 	if (p[NETMAP_BUF_POOL].num < v)
@@ -2515,11 +2515,11 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 	if (error)
 		goto out;
 
-        /* Initialize the lut using the information contained in the
+	/* Initialize the lut using the information contained in the
 	 * ptnetmap memory device. */
-        bufsize = nm_os_pt_memdev_ioread(ptnmd->ptn_dev,
+	bufsize = nm_os_pt_memdev_ioread(ptnmd->ptn_dev,
 					 PTNET_MDEV_IO_BUF_POOL_OBJSZ);
-        nbuffers = nm_os_pt_memdev_ioread(ptnmd->ptn_dev,
+	nbuffers = nm_os_pt_memdev_ioread(ptnmd->ptn_dev,
 					 PTNET_MDEV_IO_BUF_POOL_OBJNUM);
 
 	/* allocate the lut */
@@ -2740,7 +2740,7 @@ netmap_mem_pt_guest_create(nm_memid_t mem_id)
 	ptnmd->host_mem_id = mem_id;
 	ptnmd->pt_ifs = NULL;
 
-        /* Assign new id in the guest (We have the lock) */
+	/* Assign new id in the guest (We have the lock) */
 	err = nm_mem_assign_id_locked(&ptnmd->up);
 	if (err)
 		goto error;
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index ebb96a5f9..461e2676c 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -139,7 +139,7 @@ nm_is_zmon(struct netmap_adapter *na)
 static int
 netmap_monitor_txsync(struct netmap_kring *kring, int flags)
 {
-        RD(1, "%s %x", kring->name, flags);
+	RD(1, "%s %x", kring->name, flags);
 	return EIO;
 }
 
@@ -152,10 +152,10 @@ netmap_monitor_txsync(struct netmap_kring *kring, int flags)
 static int
 netmap_monitor_rxsync(struct netmap_kring *kring, int flags)
 {
-        ND("%s %x", kring->name, flags);
+	ND("%s %x", kring->name, flags);
 	kring->nr_hwcur = kring->rhead;
 	mb();
-        return 0;
+	return 0;
 }
 
 /* nm_krings_create callbacks for monitors.
@@ -198,7 +198,7 @@ nm_monitor_alloc(struct netmap_kring *kring, u_int n)
 		return 0;
 
 	old_len = sizeof(struct netmap_kring *)*kring->max_monitors;
-        len = sizeof(struct netmap_kring *) * n;
+	len = sizeof(struct netmap_kring *) * n;
 	nm = nm_os_realloc(kring->monitors, len, old_len);
 	if (nm == NULL)
 		return ENOMEM;
@@ -621,14 +621,14 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 static int
 netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags)
 {
-        return netmap_zmon_parent_sync(kring, flags, NR_TX);
+	return netmap_zmon_parent_sync(kring, flags, NR_TX);
 }
 
 /* callback used to replace the nm_sync callback in the monitored rx rings */
 static int
 netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags)
 {
-        return netmap_zmon_parent_sync(kring, flags, NR_RX);
+	return netmap_zmon_parent_sync(kring, flags, NR_RX);
 }
 
 static int
@@ -802,7 +802,7 @@ netmap_monitor_parent_notify(struct netmap_kring *kring, int flags)
 		notify = kring->mon_notify;
 	}
 	nm_kr_put(kring);
-        return notify(kring, flags);
+	return notify(kring, flags);
 }
 
 
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index eb59402a2..bab41366f 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -99,7 +99,7 @@ nm_pipe_alloc(struct netmap_adapter *na, u_int npipes)
 		return EINVAL;
 
 	old_len = sizeof(struct netmap_pipe_adapter *)*na->na_max_pipes;
-        len = sizeof(struct netmap_pipe_adapter *) * npipes;
+	len = sizeof(struct netmap_pipe_adapter *) * npipes;
 	npa = nm_os_realloc(na->na_pipes, len, old_len);
 	if (npa == NULL)
 		return ENOMEM;
@@ -182,28 +182,28 @@ netmap_pipe_remove(struct netmap_adapter *parent, struct netmap_pipe_adapter *na
 int
 netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 {
-        struct netmap_kring *rxkring = txkring->pipe;
-        u_int k, lim = txkring->nkr_num_slots - 1;
-        int m; /* slots to transfer */
+	struct netmap_kring *rxkring = txkring->pipe;
+	u_int k, lim = txkring->nkr_num_slots - 1;
+	int m; /* slots to transfer */
 	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
-        ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
-        ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
+	ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
+	ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
 		txkring->nr_hwcur, txkring->nr_hwtail,
-                txkring->rcur, txkring->rhead, txkring->rtail);
+		txkring->rcur, txkring->rhead, txkring->rtail);
 
-        m = txkring->rhead - txkring->nr_hwcur; /* new slots */
-        if (m < 0)
-                m += txkring->nkr_num_slots;
+	m = txkring->rhead - txkring->nr_hwcur; /* new slots */
+	if (m < 0)
+		m += txkring->nkr_num_slots;
 
 	if (m == 0) {
 		/* nothing to send */
 		return 0;
 	}
 
-        for (k = txkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
-                struct netmap_slot *rs = &rxring->slot[k];
-                struct netmap_slot *ts = &txring->slot[k];
+	for (k = txkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
+		struct netmap_slot *rs = &rxring->slot[k];
+		struct netmap_slot *ts = &txring->slot[k];
 
 		rs->len = ts->len;
 		rs->ptr = ts->ptr;
@@ -213,17 +213,17 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 			rs->flags |= NS_BUF_CHANGED;
 			ts->flags &= ~NS_BUF_CHANGED;
 		}
-        }
+	}
 
-        mb(); /* make sure the slots are updated before publishing them */
-        rxkring->nr_hwtail = k;
-        txkring->nr_hwcur = k;
+	mb(); /* make sure the slots are updated before publishing them */
+	rxkring->nr_hwtail = k;
+	txkring->nr_hwcur = k;
 
-        ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
+	ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
 		txkring->nr_hwcur, txkring->nr_hwtail,
-                txkring->rcur, txkring->rhead, txkring->rtail, k);
+		txkring->rcur, txkring->rhead, txkring->rtail, k);
 
-        rxkring->nm_notify(rxkring, 0);
+	rxkring->nm_notify(rxkring, 0);
 
 	return 0;
 }
@@ -231,45 +231,45 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 int
 netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 {
-        struct netmap_kring *txkring = rxkring->pipe;
-        u_int k, lim = rxkring->nkr_num_slots - 1;
-        int m; /* slots to release */
+	struct netmap_kring *txkring = rxkring->pipe;
+	u_int k, lim = rxkring->nkr_num_slots - 1;
+	int m; /* slots to release */
 	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
-        ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
-        ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
+	ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
+	ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
 		rxkring->nr_hwcur, rxkring->nr_hwtail,
-                rxkring->rcur, rxkring->rhead, rxkring->rtail);
+		rxkring->rcur, rxkring->rhead, rxkring->rtail);
 
-        m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */
-        if (m < 0)
-                m += rxkring->nkr_num_slots;
+	m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */
+	if (m < 0)
+		m += rxkring->nkr_num_slots;
 
 	if (m == 0) {
 		/* nothing to release */
 		return 0;
 	}
 
-        for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
-                struct netmap_slot *rs = &rxring->slot[k];
-                struct netmap_slot *ts = &txring->slot[k];
+	for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
+		struct netmap_slot *rs = &rxring->slot[k];
+		struct netmap_slot *ts = &txring->slot[k];
 
 		if (rs->flags & NS_BUF_CHANGED) {
 			/* copy the slot and report the buffer change */
 			*ts = *rs;
 			rs->flags &= ~NS_BUF_CHANGED;
 		}
-        }
+	}
 
-        mb(); /* make sure the slots are updated before publishing them */
-        txkring->nr_hwtail = nm_prev(k, lim);
-        rxkring->nr_hwcur = k;
+	mb(); /* make sure the slots are updated before publishing them */
+	txkring->nr_hwtail = nm_prev(k, lim);
+	rxkring->nr_hwcur = k;
 
-        ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
+	ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
 		rxkring->nr_hwcur, rxkring->nr_hwtail,
-                rxkring->rcur, rxkring->rhead, rxkring->rtail, k);
+		rxkring->rcur, rxkring->rhead, rxkring->rtail, k);
 
-        txkring->nm_notify(txkring, 0);
+	txkring->nm_notify(txkring, 0);
 
 	return 0;
 }
@@ -578,7 +578,7 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 
 	if (ona->tx_rings == NULL) {
 		/* already deleted, we must be on an
-                 * cleanup-after-error path */
+		 * cleanup-after-error path */
 		return;
 	}
 	netmap_mem_rings_delete(ona);
@@ -694,8 +694,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			reqna = mna->peer;
 		}
 		/* the pipe we have found already holds a ref to the parent,
-                 * so we need to drop the one we got from netmap_get_na()
-                 */
+		 * so we need to drop the one we got from netmap_get_na()
+		 */
 		netmap_unget_na(pna, ifp);
 		goto found;
 	}
@@ -705,9 +705,9 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		goto put_out;
 	}
 	/* we create both master and slave.
-         * The endpoint we were asked for holds a reference to
-         * the other one.
-         */
+	 * The endpoint we were asked for holds a reference to
+	 * the other one.
+	 */
 	mna = nm_os_malloc(sizeof(*mna));
 	if (mna == NULL) {
 		error = ENOMEM;
@@ -772,8 +772,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	sna->peer = mna;
 
 	/* we already have a reference to the parent, but we
-         * need another one for the other endpoint we created
-         */
+	 * need another one for the other endpoint we created
+	 */
 	netmap_adapter_get(pna);
 	/* likewise for the ifp, if any */
 	if (ifp)
@@ -797,8 +797,8 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	netmap_adapter_get(*na);
 
 	/* keep the reference to the parent.
-         * It will be released by the req destructor
-         */
+	 * It will be released by the req destructor
+	 */
 
 	return 0;
 
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index a36cc3a82..6e47011b5 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -283,22 +283,22 @@ static struct nm_bridge *nm_bridges;
 static inline void
 pkt_copy(void *_src, void *_dst, int l)
 {
-        uint64_t *src = _src;
-        uint64_t *dst = _dst;
-        if (unlikely(l >= 1024)) {
-                memcpy(dst, src, l);
-                return;
-        }
-        for (; likely(l > 0); l-=64) {
-                *dst++ = *src++;
-                *dst++ = *src++;
-                *dst++ = *src++;
-                *dst++ = *src++;
-                *dst++ = *src++;
-                *dst++ = *src++;
-                *dst++ = *src++;
-                *dst++ = *src++;
-        }
+	uint64_t *src = _src;
+	uint64_t *dst = _dst;
+	if (unlikely(l >= 1024)) {
+		memcpy(dst, src, l);
+		return;
+	}
+	for (; likely(l > 0); l-=64) {
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+	}
 }
 
 
@@ -693,7 +693,7 @@ nm_vi_create(struct nmreq_header *hdr)
 	error = netmap_vi_create(hdr, 0 /* no autodelete */);
 	hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 	hdr->nr_body = (uintptr_t)req;
-        /* Write back to the original struct. */
+	/* Write back to the original struct. */
 	req->nr_tx_slots = regreq.nr_tx_slots;
 	req->nr_rx_slots = regreq.nr_rx_slots;
 	req->nr_tx_rings = regreq.nr_tx_rings;
@@ -1764,33 +1764,33 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end)
  */
 #define mix(a, b, c)                                                    \
 do {                                                                    \
-        a -= b; a -= c; a ^= (c >> 13);                                 \
-        b -= c; b -= a; b ^= (a << 8);                                  \
-        c -= a; c -= b; c ^= (b >> 13);                                 \
-        a -= b; a -= c; a ^= (c >> 12);                                 \
-        b -= c; b -= a; b ^= (a << 16);                                 \
-        c -= a; c -= b; c ^= (b >> 5);                                  \
-        a -= b; a -= c; a ^= (c >> 3);                                  \
-        b -= c; b -= a; b ^= (a << 10);                                 \
-        c -= a; c -= b; c ^= (b >> 15);                                 \
+	a -= b; a -= c; a ^= (c >> 13);                                 \
+	b -= c; b -= a; b ^= (a << 8);                                  \
+	c -= a; c -= b; c ^= (b >> 13);                                 \
+	a -= b; a -= c; a ^= (c >> 12);                                 \
+	b -= c; b -= a; b ^= (a << 16);                                 \
+	c -= a; c -= b; c ^= (b >> 5);                                  \
+	a -= b; a -= c; a ^= (c >> 3);                                  \
+	b -= c; b -= a; b ^= (a << 10);                                 \
+	c -= a; c -= b; c ^= (b >> 15);                                 \
 } while (/*CONSTCOND*/0)
 
 
 static __inline uint32_t
 nm_bridge_rthash(const uint8_t *addr)
 {
-        uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hask key
+	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hask key
 
-        b += addr[5] << 8;
-        b += addr[4];
-        a += addr[3] << 24;
-        a += addr[2] << 16;
-        a += addr[1] << 8;
-        a += addr[0];
+	b += addr[5] << 8;
+	b += addr[4];
+	a += addr[3] << 24;
+	a += addr[2] << 16;
+	a += addr[1] << 8;
+	a += addr[0];
 
-        mix(a, b, c);
+	mix(a, b, c);
 #define BRIDGE_RTHASH_MASK	(NM_BDG_HASH-1)
-        return (c & BRIDGE_RTHASH_MASK);
+	return (c & BRIDGE_RTHASH_MASK);
 }
 
 #undef mix
@@ -2113,10 +2113,10 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		needed = d->bq_len + brddst->bq_len;
 
 		if (unlikely(dst_na->up.virt_hdr_len != na->up.virt_hdr_len)) {
-                        if (netmap_verbose) {
-                            RD(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len,
-                                  dst_na->up.virt_hdr_len);
-                        }
+			if (netmap_verbose) {
+				RD(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len,
+						dst_na->up.virt_hdr_len);
+			}
 			/* There is a virtio-net header/offloadings mismatch between
 			 * source and destination. The slower mismatch datapath will
 			 * be used to cope with all the mismatches.
@@ -2495,7 +2495,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	vpna->last_smac = ~0llu;
 	/*if (vpna->mfs > netmap_buf_size)  TODO netmap_buf_size is zero??
 		vpna->mfs = netmap_buf_size; */
-        if (netmap_verbose)
+	if (netmap_verbose)
 		D("max frame size %u", vpna->mfs);
 
 	na->na_flags |= NAF_BDG_MAYSLEEP;
@@ -2827,11 +2827,11 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	}
 
 	/* increment the usage counter for all the hwna krings */
-        for_rx_tx(t) {
-                for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
 			NMR(hwna, t)[i]->users++;
 		}
-        }
+	}
 
 	/* now create the actual rings */
 	error = netmap_mem_rings_create(hwna);
@@ -2843,13 +2843,13 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	 * The original number of rings comes from hwna,
 	 * rx rings on one side equals tx rings on the other.
 	 */
-        for_rx_tx(t) {
-                enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-                for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
-                        NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
-                        NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
-                }
-        }
+	for_rx_tx(t) {
+		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
+		for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
+			NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
+			NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
+		}
+	}
 
 	if (na->na_flags & NAF_HOST_RINGS) {
 		/* the hostna rings are the host rings of the bwrap.
@@ -2865,9 +2865,9 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	return 0;
 
 err_dec_users:
-        for_rx_tx(t) {
+	for_rx_tx(t) {
 		NMR(hwna, t)[i]->users--;
-        }
+	}
 	hwna->nm_krings_delete(hwna);
 err_del_vp_rings:
 	netmap_vp_krings_delete(na);
@@ -2888,11 +2888,11 @@ netmap_bwrap_krings_delete(struct netmap_adapter *na)
 	ND("%s", na->name);
 
 	/* decrement the usage counter for all the hwna krings */
-        for_rx_tx(t) {
-                for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
 			NMR(hwna, t)[i]->users--;
 		}
-        }
+	}
 
 	/* delete any netmap rings that are no longer needed */
 	netmap_mem_rings_delete(hwna);

From 46c0acc779ebbcedfb755ab4cb797d9b151227f4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 10:10:45 +0200
Subject: [PATCH 0829/2207] fix remaining indentation problems

---
 sys/dev/netmap/netmap.c         | 30 +++++++++++++++---------------
 sys/dev/netmap/netmap_freebsd.c |  2 +-
 sys/dev/netmap/netmap_generic.c | 12 ++++++------
 sys/dev/netmap/netmap_pipe.c    |  2 +-
 sys/dev/netmap/netmap_vale.c    |  2 +-
 5 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5070854bc..eb18d03db 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -534,35 +534,35 @@ SYSBEGIN(main_init);
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
-    CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
+		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
-    CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
+		CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, CTLFLAG_RW, &netmap_no_pendintr,
-    0, "Always look for new received packets.");
+		0, "Always look for new received packets.");
 SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW,
-    &netmap_txsync_retry, 0, "Number of txsync loops in bridge's flush.");
+		&netmap_txsync_retry, 0, "Number of txsync loops in bridge's flush.");
 
 SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0,
-    "Force NR_FORWARD mode");
+		"Force NR_FORWARD mode");
 SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0,
-    "Adapter mode. 0 selects the best option available,"
-    "1 forces native adapter, 2 forces emulated adapter");
+		"Adapter mode. 0 selects the best option available,"
+		"1 forces native adapter, 2 forces emulated adapter");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit,
-    0, "RX notification interval in nanoseconds");
+		0, "RX notification interval in nanoseconds");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW,
-    &netmap_generic_ringsize, 0,
-    "Number of per-ring slots for emulated netmap mode");
+		&netmap_generic_ringsize, 0,
+		"Number of per-ring slots for emulated netmap mode");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW,
-    &netmap_generic_rings, 0,
-    "Number of TX/RX queues for emulated netmap adapters");
+		&netmap_generic_rings, 0,
+		"Number of TX/RX queues for emulated netmap adapters");
 #ifdef linux
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW,
-    &netmap_generic_txqdisc, 0, "Use qdisc for generic adapters");
+		&netmap_generic_txqdisc, 0, "Use qdisc for generic adapters");
 #endif
 SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr,
-    0, "Allow ptnet devices to use virtio-net headers");
+		0, "Allow ptnet devices to use virtio-net headers");
 SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW,
-    &ptnetmap_tx_workers, 0, "Use worker threads for pnetmap TX processing");
+		&ptnetmap_tx_workers, 0, "Use worker threads for pnetmap TX processing");
 
 SYSEND;
 
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index b7b0bcd3e..7f4079502 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -940,7 +940,7 @@ struct netmap_vm_handle_t {
 
 static int
 netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
-    vm_ooffset_t foff, struct ucred *cred, u_short *color)
+		vm_ooffset_t foff, struct ucred *cred, u_short *color)
 {
 	struct netmap_vm_handle_t *vmh = handle;
 
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 3a6ad0fe3..4bb87d000 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -295,12 +295,12 @@ static struct rate_context rate_ctx;
 
 void generic_rate(int txp, int txs, int txi, int rxp, int rxs, int rxi)
 {
-    if (txp) rate_ctx.new.txpkt++;
-    if (txs) rate_ctx.new.txsync++;
-    if (txi) rate_ctx.new.txirq++;
-    if (rxp) rate_ctx.new.rxpkt++;
-    if (rxs) rate_ctx.new.rxsync++;
-    if (rxi) rate_ctx.new.rxirq++;
+	if (txp) rate_ctx.new.txpkt++;
+	if (txs) rate_ctx.new.txsync++;
+	if (txi) rate_ctx.new.txirq++;
+	if (rxp) rate_ctx.new.rxpkt++;
+	if (rxs) rate_ctx.new.rxsync++;
+	if (rxi) rate_ctx.new.rxirq++;
 }
 
 #else /* !RATE */
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index bab41366f..473879cf2 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -81,7 +81,7 @@ static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
 SYSBEGIN(vars_pipes);
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW,
-    &netmap_default_pipes, 0, "For compatibility only");
+		&netmap_default_pipes, 0, "For compatibility only");
 SYSEND;
 
 /* allocate the pipe array in the parent adapter */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 6e47011b5..ac04e2b29 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -161,7 +161,7 @@ static int bridge_batch = NM_BDG_BATCH; /* bridge batch size */
 SYSBEGIN(vars_vale);
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
-    "Max batch size to be used in the bridge");
+		"Max batch size to be used in the bridge");
 SYSEND;
 
 static int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,

From e20295a4305612ee7acfdab5735b6aa18323ecd6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 10:13:57 +0200
Subject: [PATCH 0830/2207] add pre-commit hook script

---
 pre-commit | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100755 pre-commit

diff --git a/pre-commit b/pre-commit
new file mode 100755
index 000000000..adfbfa2db
--- /dev/null
+++ b/pre-commit
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ASCII filenames set this variable to true.
+allownonascii=$(git config --bool hooks.allownonascii)
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Cross platform projects tend to avoid non-ASCII filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+	# Note that the use of brackets around a tr range is ok here, (it's
+	# even required, for portability to Solaris 10's /usr/bin/tr), since
+	# the square bracket bytes happen to fall in the designated range.
+	test $(git diff --cached --name-only --diff-filter=A -z $against |
+	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+then
+	cat <<\EOF
+Error: Attempt to add a non-ASCII file name.
+
+This can cause problems if you want to work with people on other platforms.
+
+To be portable it is advisable to rename the file.
+
+If you know what you are doing you can disable this check using:
+
+  git config hooks.allownonascii true
+EOF
+	exit 1
+fi
+
+########### netmap specific checks ############
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c"
+
+for f in $files; do
+git grep --quiet "^\(    \)\+" $f
+	if [ "$?" == 0 ]; then
+		echo "Wrong indentation in $f"
+		exit 1
+	fi
+done
+
+for f in $files; do
+	git grep --quiet "[ ]\+$" $f
+	if [ "$?" == 0 ]; then
+		echo "Trailing whitespaces in $f"
+		exit 1
+	fi
+done
+########### end of netmap specific checks ############
+
+# If there are whitespace errors, print the offending file names and fail.
+exec git diff-index --check --cached $against --

From dcc12162b9925c63179fc71bbd9bd307377af2fc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 10:16:57 +0200
Subject: [PATCH 0831/2207] install pre-commit hook on configure

---
 configure | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/configure b/configure
index 1b1177979..2d8112f76 100755
--- a/configure
+++ b/configure
@@ -3,6 +3,8 @@
 os=$(uname -s)
 topdir=$(cd $(dirname $0); pwd)
 
+cp pre-commit .git/hooks
+
 case $os in
 	Linux)
 		$topdir/LINUX/configure "$@";;

From 8da85c59f0b9df04e9c657ddaf075911efbdb4dc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 10:21:58 +0200
Subject: [PATCH 0832/2207] fix indentation problems in netmap_linux.c, include
 it in pre-commit

---
 LINUX/netmap_linux.c | 152 +++++++++++++++++++++----------------------
 pre-commit           |   2 +-
 2 files changed, 77 insertions(+), 77 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1d5e6594c..f8128d881 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -429,64 +429,64 @@ nm_os_mbuf_has_offld(struct mbuf *m)
 static NETMAP_LINUX_TIMER_RTYPE
 generic_timer_handler(struct hrtimer *t)
 {
-    struct nm_generic_mit *mit =
-	container_of(t, struct nm_generic_mit, mit_timer);
-    u_int work_done;
+	struct nm_generic_mit *mit =
+		container_of(t, struct nm_generic_mit, mit_timer);
+	u_int work_done;
 
-    if (!mit->mit_pending) {
-        return HRTIMER_NORESTART;
-    }
+	if (!mit->mit_pending) {
+		return HRTIMER_NORESTART;
+	}
 
-    /* Some work arrived while the timer was counting down:
-     * Reset the pending work flag, restart the timer and send
-     * a notification.
-     */
-    mit->mit_pending = 0;
-    /* below is a variation of netmap_generic_irq  XXX revise */
-    if (nm_netmap_on(mit->mit_na)) {
-        netmap_common_irq(mit->mit_na, mit->mit_ring_idx, &work_done);
-        generic_rate(0, 0, 0, 0, 0, 1);
-    }
-    nm_os_mitigation_restart(mit);
+	/* Some work arrived while the timer was counting down:
+	 * Reset the pending work flag, restart the timer and send
+	 * a notification.
+	 */
+	mit->mit_pending = 0;
+	/* below is a variation of netmap_generic_irq  XXX revise */
+	if (nm_netmap_on(mit->mit_na)) {
+		netmap_common_irq(mit->mit_na, mit->mit_ring_idx, &work_done);
+		generic_rate(0, 0, 0, 0, 0, 1);
+	}
+	nm_os_mitigation_restart(mit);
 
-    return HRTIMER_RESTART;
+	return HRTIMER_RESTART;
 }
 
 
 void
 nm_os_mitigation_init(struct nm_generic_mit *mit, int idx,
-                                struct netmap_adapter *na)
+			struct netmap_adapter *na)
 {
-    hrtimer_init(&mit->mit_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-    mit->mit_timer.function = &generic_timer_handler;
-    mit->mit_pending = 0;
-    mit->mit_ring_idx = idx;
-    mit->mit_na = na;
+	hrtimer_init(&mit->mit_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	mit->mit_timer.function = &generic_timer_handler;
+	mit->mit_pending = 0;
+	mit->mit_ring_idx = idx;
+	mit->mit_na = na;
 }
 
 
 void
 nm_os_mitigation_start(struct nm_generic_mit *mit)
 {
-    hrtimer_start(&mit->mit_timer, ktime_set(0, netmap_generic_mit), HRTIMER_MODE_REL);
+	hrtimer_start(&mit->mit_timer, ktime_set(0, netmap_generic_mit), HRTIMER_MODE_REL);
 }
 
 void
 nm_os_mitigation_restart(struct nm_generic_mit *mit)
 {
-    hrtimer_forward_now(&mit->mit_timer, ktime_set(0, netmap_generic_mit));
+	hrtimer_forward_now(&mit->mit_timer, ktime_set(0, netmap_generic_mit));
 }
 
 int
 nm_os_mitigation_active(struct nm_generic_mit *mit)
 {
-    return hrtimer_active(&mit->mit_timer);
+	return hrtimer_active(&mit->mit_timer);
 }
 
 void
 nm_os_mitigation_cleanup(struct nm_generic_mit *mit)
 {
-    hrtimer_cancel(&mit->mit_timer);
+	hrtimer_cancel(&mit->mit_timer);
 }
 
 
@@ -567,26 +567,26 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 {
 #ifndef NETMAP_LINUX_HAVE_RX_REGISTER
 #warning "Packet reception with emulated (generic) mode not supported for this kernel version"
-    return 0;
+	return 0;
 #else /* HAVE_RX_REGISTER */
-    struct netmap_adapter *na = &gna->up.up;
-    struct ifnet *ifp = netmap_generic_getifp(gna);
-    int ret = 0;
-
-    if (!ifp) {
-        D("Failed to get ifp");
-        return -EBUSY;
-    }
-
-    nm_os_ifnet_lock();
-    if (intercept) {
-        ret = -netdev_rx_handler_register(ifp,
-                &linux_generic_rx_handler, na);
-    } else {
-        netdev_rx_handler_unregister(ifp);
-    }
-    nm_os_ifnet_unlock();
-    return ret;
+	struct netmap_adapter *na = &gna->up.up;
+	struct ifnet *ifp = netmap_generic_getifp(gna);
+	int ret = 0;
+
+	if (!ifp) {
+		D("Failed to get ifp");
+		return -EBUSY;
+	}
+
+	nm_os_ifnet_lock();
+	if (intercept) {
+		ret = -netdev_rx_handler_register(ifp,
+				&linux_generic_rx_handler, na);
+	} else {
+		netdev_rx_handler_unregister(ifp);
+	}
+	nm_os_ifnet_unlock();
+	return ret;
 #endif /* HAVE_RX_REGISTER */
 }
 
@@ -594,14 +594,14 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 static u16
 generic_ndo_select_queue(struct ifnet *ifp, struct mbuf *m
 #if NETMAP_LINUX_SELECT_QUEUE >= 3
-                                , void *accel_priv
+			, void *accel_priv
 #if NETMAP_LINUX_SELECT_QUEUE >= 4
 				, select_queue_fallback_t fallback
 #endif /* >= 4 */
 #endif /* >= 3 */
 		)
 {
-    return skb_get_queue_mapping(m); // actually 0 on 2.6.23 and before
+	return skb_get_queue_mapping(m); // actually 0 on 2.6.23 and before
 }
 #endif /* SELECT_QUEUE */
 
@@ -703,15 +703,15 @@ generic_qdisc_dequeue(struct Qdisc *qdisc)
 		return NULL;
 	}
 
-        if (unlikely(m->priority == NM_MAGIC_PRIORITY_TXQE)) {
-            /* nm_os_generic_xmit_frame() asked us an event on this mbuf.
-             * We have to set the priority to the normal TX token, so that
-             * generic_ndo_start_xmit can pass it to the driver. */
-            m->priority = NM_MAGIC_PRIORITY_TX;
-            ND(5, "Event met, notify %p", m);
-            netmap_generic_irq(NA(qdisc_dev(qdisc)),
-                               skb_get_queue_mapping(m), NULL);
-        }
+	if (unlikely(m->priority == NM_MAGIC_PRIORITY_TXQE)) {
+		/* nm_os_generic_xmit_frame() asked us an event on this mbuf.
+		 * We have to set the priority to the normal TX token, so that
+		 * generic_ndo_start_xmit can pass it to the driver. */
+		m->priority = NM_MAGIC_PRIORITY_TX;
+		ND(5, "Event met, notify %p", m);
+		netmap_generic_irq(NA(qdisc_dev(qdisc)),
+				skb_get_queue_mapping(m), NULL);
+	}
 
 	ND(5, "Dequeuing mbuf, len %u", qdisc_qlen(qdisc));
 
@@ -947,9 +947,9 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	skb_reset_tail_pointer(m);
 	skb_reset_mac_header(m);
 
-        /* Initialize the header pointers assuming this is an IPv4 packet.
-         * This is useful to make netmap interact well with TC when
-         * netmap_generic_txqdisc == 0.  */
+	/* Initialize the header pointers assuming this is an IPv4 packet.
+	 * This is useful to make netmap interact well with TC when
+	 * netmap_generic_txqdisc == 0.  */
 	skb_set_network_header(m, 14);
 	skb_set_transport_header(m, 34);
 	m->protocol = htons(ETH_P_IP);
@@ -1345,9 +1345,9 @@ linux_netmap_ioctl(struct file *file, u_int cmd, u_long data /* arg */)
 
 static long
 linux_netmap_compat_ioctl(struct file *file, unsigned int cmd,
-                          unsigned long arg)
+			unsigned long arg)
 {
-    return linux_netmap_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+	return linux_netmap_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 }
 #endif
 
@@ -1383,15 +1383,15 @@ linux_netmap_open(struct inode *inode, struct file *file)
 
 
 static struct file_operations netmap_fops = {
-    .owner = THIS_MODULE,
-    .open = linux_netmap_open,
-    .mmap = linux_netmap_mmap,
-    LIN_IOCTL_NAME = linux_netmap_ioctl,
+	.owner = THIS_MODULE,
+	.open = linux_netmap_open,
+	.mmap = linux_netmap_mmap,
+	LIN_IOCTL_NAME = linux_netmap_ioctl,
 #ifdef CONFIG_COMPAT
-    .compat_ioctl = linux_netmap_compat_ioctl,
+	.compat_ioctl = linux_netmap_compat_ioctl,
 #endif
-    .poll = linux_netmap_poll,
-    .release = linux_netmap_release,
+	.poll = linux_netmap_poll,
+	.release = linux_netmap_release,
 };
 
 
@@ -1963,7 +1963,7 @@ struct ptnetmap_memdev
  */
 int
 nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr,
-                      void **nm_addr, uint64_t *mem_size)
+			void **nm_addr, uint64_t *mem_size)
 {
 	struct pci_dev *pdev = ptn_dev->pdev;
 	phys_addr_t mem_paddr;
@@ -2350,7 +2350,7 @@ static int linux_netmap_init(void)
 	netmap_sink_fini();
 ptnetmap_fini:
 #endif /* WITH_SINK */
-        ptnetmap_guest_fini();
+	ptnetmap_guest_fini();
 netmap_fini:
 	netmap_fini();
 	return err;
@@ -2365,8 +2365,8 @@ static void linux_netmap_fini(void)
 #ifdef WITH_SINK
 	netmap_sink_fini();
 #endif /* WITH_SINK */
-        ptnetmap_guest_fini();
-        netmap_fini();
+	ptnetmap_guest_fini();
+	netmap_fini();
 }
 
 #ifndef NETMAP_LINUX_HAVE_LIVE_ADDR_CHANGE
@@ -2398,7 +2398,7 @@ static int linux_nm_vi_xmit(struct sk_buff *skb, struct net_device *netdev)
 }
 
 #ifdef NETMAP_LINUX_HAVE_GET_STATS64
-static 
+static
 #ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64
 struct rtnl_link_stats64 *
 #else /* !VOID */
@@ -2443,7 +2443,7 @@ linux_nm_vi_setup(struct ifnet *dev)
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 #ifdef NETMAP_LINUX_HAVE_NETDEV_DTOR
 	dev->destructor = linux_nm_vi_destructor;
-#else 
+#else
 	dev->needs_free_netdev = 1;
 #endif
 	dev->tx_queue_len = 0;
diff --git a/pre-commit b/pre-commit
index adfbfa2db..6b48f8e62 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From 39d83fce0a67342ca9c38a1caf8d8c3dad6c41ac Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:42:15 +0200
Subject: [PATCH 0833/2207] bsd_glue.h: fix indentation problems

---
 LINUX/bsd_glue.h | 22 +++++++++++-----------
 pre-commit       |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 03b59fcd6..2fdd5a00b 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -103,9 +103,9 @@
 #ifndef NETMAP_LINUX_HAVE_HRTIMER_FORWARD_NOW
 /* Forward a hrtimer so it expires after the hrtimer's current now */
 static inline u64 hrtimer_forward_now(struct hrtimer *timer,
-                                      ktime_t interval)
+					ktime_t interval)
 {
-        return hrtimer_forward(timer, timer->base->get_time(), interval);
+	return hrtimer_forward(timer, timer->base->get_time(), interval);
 }
 #endif
 
@@ -323,19 +323,19 @@ int linux_netmap_set_channels(struct net_device *, struct ethtool_channels *);
  * (hard) interrupt context.
  */
 typedef struct {
-        spinlock_t      sl;
-        ulong           flags;
+	spinlock_t      sl;
+	ulong           flags;
 } safe_spinlock_t;
 
 static inline void mtx_lock(safe_spinlock_t *m)
 {
-        spin_lock_irqsave(&(m->sl), m->flags);
+	spin_lock_irqsave(&(m->sl), m->flags);
 }
 
 static inline void mtx_unlock(safe_spinlock_t *m)
 {
 	ulong flags = *(volatile ulong *)&m->flags;
-        spin_unlock_irqrestore(&(m->sl), flags);
+	spin_unlock_irqrestore(&(m->sl), flags);
 }
 
 #define mtx_init(a, b, c, d)	spin_lock_init(&((a)->sl))
@@ -458,16 +458,16 @@ extern struct kernel_param_ops generic_sysctl_ops;
 			((_mode) == CTLFLAG_RD) ? 0444: 0644 )
 
 #define SYSCTL_INT(_base, _oid, _name, _mode, _var, _val, _desc)        \
-        _SYSCTL_BASE(_name, _var, int, _mode)
+	_SYSCTL_BASE(_name, _var, int, _mode)
 
 #define SYSCTL_LONG(_base, _oid, _name, _mode, _var, _val, _desc)       \
-        _SYSCTL_BASE(_name, _var, long, _mode)
+	_SYSCTL_BASE(_name, _var, long, _mode)
 
 #define SYSCTL_ULONG(_base, _oid, _name, _mode, _var, _val, _desc)      \
-        _SYSCTL_BASE(_name, _var, ulong, _mode)
+	_SYSCTL_BASE(_name, _var, ulong, _mode)
 
 #define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc)       \
-         _SYSCTL_BASE(_name, _var, uint, _mode)
+	_SYSCTL_BASE(_name, _var, uint, _mode)
 
 // #define TUNABLE_INT(_name, _ptr)
 
@@ -475,7 +475,7 @@ extern struct kernel_param_ops generic_sysctl_ops;
 #define SYSCTL_VNET_INT                 SYSCTL_INT
 
 #define SYSCTL_HANDLER_ARGS             \
-        struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req
+	struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req
 int sysctl_handle_int(SYSCTL_HANDLER_ARGS);
 int sysctl_handle_long(SYSCTL_HANDLER_ARGS);
 
diff --git a/pre-commit b/pre-commit
index 6b48f8e62..e083c30fd 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From 04dc254cb616e9798b02d5be43c906e6d2e5aa6b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:43:44 +0200
Subject: [PATCH 0834/2207] linux: i40e: fix indentation issues

---
 LINUX/i40e_netmap_linux.h | 12 ++++++------
 pre-commit                |  2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 4a75c5816..6ce0d55cc 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -77,11 +77,11 @@ extern int ix_rx_miss, ix_rx_miss_bufs, ix_crcstrip;
 SYSCTL_DECL(_dev_netmap);
 int ix_rx_miss = 0, ix_rx_miss_bufs = 0, ix_crcstrip = 1;
 SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
-    CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
+		CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
 SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss,
-    CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr");
+		CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr");
 SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss_bufs,
-    CTLFLAG_RW, &ix_rx_miss_bufs, 0, "potentially missed rx intr bufs");
+		CTLFLAG_RW, &ix_rx_miss_bufs, 0, "potentially missed rx intr bufs");
 
 #if 0
 static void
@@ -203,8 +203,8 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 {
 	struct ifnet *ifp = na->ifp;
 	struct i40e_netdev_priv *np = netdev_priv(ifp);
-        struct i40e_vsi  *vsi = np->vsi;
-        struct i40e_pf   *pf = (struct i40e_pf *)vsi->back;
+	struct i40e_vsi  *vsi = np->vsi;
+	struct i40e_pf   *pf = (struct i40e_pf *)vsi->back;
 	bool was_running;
 
 	while (test_and_set_bit(__I40E_CONFIG_BUSY, NM_I40E_STATE(pf)))
@@ -476,7 +476,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 	if (!netif_running(ifp))
 		return 0;
-       
+
 	rxr = NM_I40E_RX_RING(vsi, kring->ring_id);
 	if (unlikely(!rxr || !rxr->desc)) {
 		RD(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
diff --git a/pre-commit b/pre-commit
index e083c30fd..0ed4fcb00 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From f4924158dc6aac19f85b89783f6361a5da7c7ae1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:45:44 +0200
Subject: [PATCH 0835/2207] auto-install pre-commit hook in LINUX/configure

---
 LINUX/configure | 3 ++-
 configure       | 2 --
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index f62037fa7..1dc747656 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -664,8 +664,9 @@ rm -f config.log
 
 exec 2>> config.log
 
+cp pre-commit .git/hooks
+
 appl_arch=$($cc -dumpmachine | cut -d '-' -f 1)
-echo "Application arch is $appl_arch"
 if [ $appl_arch != "x86_64" ]; then
     # dedup uses inline x86_64 assembly
     app disable dedup
diff --git a/configure b/configure
index 2d8112f76..1b1177979 100755
--- a/configure
+++ b/configure
@@ -3,8 +3,6 @@
 os=$(uname -s)
 topdir=$(cd $(dirname $0); pwd)
 
-cp pre-commit .git/hooks
-
 case $os in
 	Linux)
 		$topdir/LINUX/configure "$@";;

From 32de3e08a4d3b7d203c7f4afcf6dae82d0e25836 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:48:11 +0200
Subject: [PATCH 0836/2207] igb: fix indentation errors

---
 LINUX/if_igb_netmap.h | 6 +++---
 pre-commit            | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 8ec587d72..695a5ba1a 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -163,7 +163,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 			// XXX check olinfo and cmd_type_len
 			curr->read.olinfo_status =
 			    htole32(olinfo_status |
-                                (len<< E1000_ADVTXD_PAYLEN_SHIFT));
+				(len<< E1000_ADVTXD_PAYLEN_SHIFT));
 			curr->read.cmd_type_len = htole32(len | hw_flags |
 				E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_DEXT |
 				E1000_ADVTXD_DCMD_IFCS);
@@ -312,7 +312,7 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 	void *addr;
 	uint64_t paddr;
 
-        slot = netmap_reset(na, NR_TX, ring_nr, 0);
+	slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
 		return 0;  // not in netmap native mode
 	for (i = 0; i < na->num_tx_desc; i++) {
@@ -346,7 +346,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	 *	srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
 	 *	srrctl |= E1000_SRRCTL_DROP_EN;
 	 */
-        slot = netmap_reset(na, NR_RX, reg_idx, 0);
+	slot = netmap_reset(na, NR_RX, reg_idx, 0);
 	if (!slot)
 		return 0;	// not in native netmap mode
 
diff --git a/pre-commit b/pre-commit
index 0ed4fcb00..bc4565f36 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From f01b554e81b72c9d34898488112750e47fc935dd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:49:42 +0200
Subject: [PATCH 0837/2207] ixgbe, re: fix indentation errors

---
 LINUX/if_re_netmap_linux.h |  4 ++--
 LINUX/ixgbe_netmap_linux.h | 10 +++++-----
 pre-commit                 |  2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/LINUX/if_re_netmap_linux.h b/LINUX/if_re_netmap_linux.h
index 3420e0248..30bc73f59 100644
--- a/LINUX/if_re_netmap_linux.h
+++ b/LINUX/if_re_netmap_linux.h
@@ -278,7 +278,7 @@ re_netmap_tx_init(struct SOFTC_T *sc)
 	int i, l;
 	uint64_t paddr;
 
-        slot = netmap_reset(na, NR_TX, 0, 0);
+	slot = netmap_reset(na, NR_TX, 0, 0);
 	if (!slot)
 		return 0;	// not in native netmap mode
 
@@ -302,7 +302,7 @@ re_netmap_rx_init(struct SOFTC_T *sc)
 	int i, lim, l;
 	uint64_t paddr;
 
-        slot = netmap_reset(na, NR_RX, 0, 0);
+	slot = netmap_reset(na, NR_RX, 0, 0);
 	if (!slot)
 		return 0;  // not in native netmap mode
 	/*
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 9386bb537..4782e515a 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -631,7 +631,7 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	u64 wba;
 #endif /* !NM_IXGBE_USE_TDH */
 
-        slot = netmap_reset(na, NR_TX, ring_nr, 0);
+	slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
 		return txdctl;	// not in native netmap mode
 
@@ -687,8 +687,8 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	int lim, i;
 	struct NM_IXGBE_RING *ring = NM_IXGBE_RX_RING(adapter, ring_nr);
 
-        slot = netmap_reset(na, NR_RX, ring_nr, 0);
-        /* same as in ixgbe_setup_transmit_ring() */
+	slot = netmap_reset(na, NR_RX, ring_nr, 0);
+	/* same as in ixgbe_setup_transmit_ring() */
 	if (!slot)
 		return 0;	// not in native netmap mode
 	// XXX can we move it later ?
@@ -793,8 +793,8 @@ ixgbe_netmap_krings_delete(struct netmap_adapter *na)
 static int
 ixgbe_netmap_krings_create(struct netmap_adapter *na)
 {
-        int ret;
-       
+	int ret;
+
 	ret = netmap_hw_krings_create(na);
 	if (ret)
 		return ret;
diff --git a/pre-commit b/pre-commit
index bc4565f36..50bda81f9 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From 029d37dcdaaf1ff56bba40ee5566d855e3d972a3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:51:24 +0200
Subject: [PATCH 0838/2207] linux: veth, virtio: fix indentation issues

---
 LINUX/veth_netmap.h | 2 +-
 pre-commit          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index be0843d97..e7ec5ff60 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -333,7 +333,7 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 
 	if (peer_na->tx_rings == NULL) {
 		/* already deleted, we must be on an
-                 * cleanup-after-error path */
+		 * cleanup-after-error path */
 		return;
 	}
 	netmap_mem_rings_delete(peer_na);
diff --git a/pre-commit b/pre-commit
index 50bda81f9..8447bdec3 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From 314d0289ddc65ac73308a9ceecd631561731c734 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:52:35 +0200
Subject: [PATCH 0839/2207] linux: ptnet: fix indentation issues

---
 LINUX/netmap_ptnet.c | 20 ++++++++++----------
 pre-commit           |  2 +-
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 0d65e5e9f..eef78b16d 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -148,7 +148,7 @@ ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(pthg, kring);
+	ptnetmap_guest_read_kring_csb(pthg, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -328,19 +328,19 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 					       kring->rhead);
 	}
 
-        /* Ask for a kick from a guest to the host if needed. */
+	/* Ask for a kick from a guest to the host if needed. */
 	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
 		ptgh->sync_flags = NAF_FORCE_RECLAIM;
 		iowrite32(0, pq->kick);
 	}
 
-        /* No more TX slots for further transmissions. We have to stop the
+	/* No more TX slots for further transmissions. We have to stop the
 	 * qdisc layer and enable notifications. */
 	if (ptnet_tx_slots(a.ring) < pi->min_tx_slots) {
 		netif_stop_subqueue(netdev, pq->kring_id);
 		ptgh->guest_need_kick = 1;
 
-                /* Double check. */
+		/* Double check. */
 		ptnet_sync_tail(pthg, kring);
 		if (unlikely(ptnet_tx_slots(a.ring) >= pi->min_tx_slots)) {
 			/* More TX space came in the meanwhile. */
@@ -701,20 +701,20 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		/* Budget was not fully consumed, since we have no more
 		 * completed RX slots. We can enable notifications and
 		 * exit polling mode. */
-                ptgh->guest_need_kick = 1;
+		ptgh->guest_need_kick = 1;
 #ifdef NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE
 		napi_complete_done(napi, work_done);
 #else
 		napi_complete(napi);
 #endif
 
-                /* Double check for more completed RX slots. */
+		/* Double check for more completed RX slots. */
 		ptnet_sync_tail(pthg, kring);
 		if (head != ring->tail) {
 			/* If there is more work to do, disable notifications
 			 * and reschedule. */
 			ptnet_napi_schedule(pq);
-                }
+		}
 #ifdef HANGCTRL
 		if (mod_timer(&prq->hang_timer,
 			      jiffies + msecs_to_jiffies(HANG_INTVAL_MS))) {
@@ -820,7 +820,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 		struct ptnet_queue *pq = pi->queues[i];
 		irq_handler_t handler = (i < pi->num_tx_rings) ?
 					ptnet_tx_intr : ptnet_rx_intr;
-                unsigned int vector = ptnet_get_irq_vector(pi, i);
+		unsigned int vector = ptnet_get_irq_vector(pi, i);
 
 		snprintf(pq->msix_name, sizeof(pq->msix_name),
 			 "%s-%d", pi->netdev->name, i);
@@ -831,7 +831,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 			goto err_irqs;
 		}
 		pr_info("%s: IRQ for ring #%d --> %u, handler %p\n",
-                        __func__, i, vector, handler);
+				__func__, i, vector, handler);
 	}
 
 	return 0;
@@ -1559,7 +1559,7 @@ ptnet_remove(struct pci_dev *pdev)
 	/* When the netdev is unregistered, ptnet_close() is invoked
 	 * for the device. Therefore, the uninitialization of the the
 	 * two netmap adapters (ptna, ptna->dr) must happen
-         * afterwards. */
+	 * afterwards. */
 	unregister_netdev(netdev);
 	pr_info("%s: device %s unregistered\n", __func__, netdev->name);
 
diff --git a/pre-commit b/pre-commit
index 8447bdec3..4fbe0ce87 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From c59d0bff68b8d0b51ec1c15e6b7f229a0d0c7565 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 16:53:41 +0200
Subject: [PATCH 0840/2207] linux: forcedeth: fix indentation issues

---
 LINUX/forcedeth_netmap.h | 4 ++--
 pre-commit               | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/forcedeth_netmap.h b/LINUX/forcedeth_netmap.h
index f271bfd23..5a9a1672b 100644
--- a/LINUX/forcedeth_netmap.h
+++ b/LINUX/forcedeth_netmap.h
@@ -73,7 +73,7 @@ This makes sure that there is always a free slot.
 static int
 forcedeth_netmap_reg(struct netmap_adapter *na, int onoff)
 {
-        struct ifnet *ifp = na->ifp;
+	struct ifnet *ifp = na->ifp;
 	struct SOFTC_T *np = netdev_priv(ifp);
 	u8 __iomem *base = get_hwbase(ifp);
 
@@ -323,7 +323,7 @@ forcedeth_netmap_tx_init(struct SOFTC_T *np)
 	struct netmap_adapter *na = NA(np->dev);
 	struct netmap_slot *slot;
 
-        slot = netmap_reset(na, NR_TX, 0, 0);
+	slot = netmap_reset(na, NR_TX, 0, 0);
 	/* slot is NULL if we are not in native netmap mode */
 	if (!slot)
 		return 0;
diff --git a/pre-commit b/pre-commit
index 4fbe0ce87..1c7c05725 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c LINUX/forcedeth_netmap.h"
 
 for f in $files; do
 git grep --quiet "^\(    \)\+" $f

From 0a27ff8a7fee7f1396bb1b76feb8b87a5c993769 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 17:07:12 +0200
Subject: [PATCH 0841/2207] linux: ixgbe: remove line with only spaces

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 4782e515a..e3e6d2c6d 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -638,7 +638,7 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 #ifndef NM_IXGBE_USE_TDH
 	/* we reset WTRESH (it must be 0 according to specs) */
 	txdctl &= ~(0x7f << 16);
-	
+
 	wba = (u64)ina->heads[ring_nr].map;
 	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAL(ring_nr),
 		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);

From f1ae2a42416edb4c4ac8eb5a7b30787e89471d92 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 17:07:27 +0200
Subject: [PATCH 0842/2207] pre-commit hook: print file and line number where
 error occurs

---
 pre-commit | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/pre-commit b/pre-commit
index 1c7c05725..abf35c17e 100755
--- a/pre-commit
+++ b/pre-commit
@@ -42,17 +42,28 @@ fi
 files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c LINUX/forcedeth_netmap.h"
 
 for f in $files; do
-git grep --quiet "^\(    \)\+" $f
-	if [ "$?" == 0 ]; then
+	ERR=$(git grep --line-number "^\(    \)\+" $f | head -n1)
+	if [ "$ERR" != "" ]; then
 		echo "Wrong indentation in $f"
+		echo "$ERR"
 		exit 1
 	fi
 done
 
 for f in $files; do
-	git grep --quiet "[ ]\+$" $f
-	if [ "$?" == 0 ]; then
+	ERR=$(git grep --line-number " \+$" $f | head -n1)
+	if [ "$ERR" != "" ]; then
 		echo "Trailing whitespaces in $f"
+		echo "$ERR"
+		exit 1
+	fi
+done
+
+for f in $files; do
+	ERR=$(git grep --line-number "^[$(printf '\t') ]\+$" $f | head -n1)
+	if [ "$ERR" != "" ]; then
+		echo "Line with only spaces or tabs in $f"
+		echo "$ERR"
 		exit 1
 	fi
 done

From 0514b96579f330602b6593b3ec9d58146be3b297 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 17:29:36 +0200
Subject: [PATCH 0843/2207] apps: vale-ctl: small indentation fix

---
 apps/vale-ctl/vale-ctl.c | 4 ++--
 pre-commit               | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index 98c1d333c..02027594d 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -199,7 +199,7 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2)
 static void
 usage(int errcode)
 {
-    fprintf(stderr,
+	fprintf(stderr,
 	    "Usage:\n"
 	    "vale-ctl arguments\n"
 	    "\t-g interface	interface name to get info\n"
@@ -216,7 +216,7 @@ usage(int errcode)
 	    "\t\t z: (ONE_NIC only) num of total cores/rings\n"
 	    "\t-P interface stop polling\n"
 	    "\t-m memid to use when creating a new interface\n");
-    exit(errcode);
+	exit(errcode);
 }
 
 int
diff --git a/pre-commit b/pre-commit
index abf35c17e..4c177f234 100755
--- a/pre-commit
+++ b/pre-commit
@@ -39,7 +39,7 @@ EOF
 fi
 
 ########### netmap specific checks ############
-files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c LINUX/forcedeth_netmap.h"
+files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c LINUX/forcedeth_netmap.h apps/bridge/bridge.c apps/lb/lb.c apps/vale-ctl/vale-ctl.c apps/dedup/dedup.c apps/include/ctrs.h"
 
 for f in $files; do
 	ERR=$(git grep --line-number "^\(    \)\+" $f | head -n1)

From 5b8ad405a594aae351bbfe393793c9d4dbb5d2af Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 13 Apr 2018 17:33:21 +0200
Subject: [PATCH 0844/2207] nmreplay: use proper C comments

---
 apps/nmreplay/nmreplay.c | 156 +++++++++++++++++++--------------------
 1 file changed, 76 insertions(+), 80 deletions(-)

diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index 4760d1894..c93e8f8c7 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -24,71 +24,68 @@
  */
 
 
-#if 0 /* COMMENT */
-
-This program implements NMREPLAY, a program to replay a pcap file
-enforcing the output rate and possibly random losses and delay
-distributions.
-It is meant to be run from the command line and implemented with a main
-control thread for monitoring, plus a thread to push packets out.
-
-The control thread parses command line arguments, prepares a
-schedule for transmission in a memory buffer and then sits
-in a loop where it periodically reads traffic statistics from
-the other threads and prints them out on the console.
-
-The transmit buffer contains headers and packets. Each header
-includes a timestamp that determines when the packet should be sent out.
-A "consumer" thread cons() reads from the queue and transmits packets
-on the output netmap port when their time has come.
-
-The program does CPU pinning and sets the scheduler and priority
-for the "cons" threads. Externally one should do the
-assignment of other threads (e.g. interrupt handlers) and
-make sure that network interfaces are configured properly.
-
---- Main functions of the program ---
-within each function, q is used as a pointer to the queue holding
-packets and parameters.
-
-pcap_prod()
-
-    reads from the pcap file and prepares packets to transmit.
-    After reading a packet from the pcap file, the following information
-    are extracted which can be used to determine the schedule:
-
-    	q->cur_pkt	points to the buffer containing the packet
-	q->cur_len	packet length, excluding CRC
-	q->cur_caplen	available packet length (may be shorter than cur_len)
-	q->cur_tt	transmission time for the packet, computed from the trace.
-
-    The following functions are then called in sequence:
-
-    q->c_loss (set with the -L command line option) decides
-    	whether the packet should be dropped before even queuing.
-	This is generally useful to emulate random loss.
-	The function is supposed to set q->c_drop = 1 if the
-	packet should be dropped, or leave it to 0 otherwise.
-
-    q->c_bw (set with the -B command line option) is used to
-        enforce the transmit bandwidth. The function must store
-	in q->cur_tt the transmission time (in nanoseconds) of
-	the packet, which is typically proportional to the length
-	of the packet, i.e. q->cur_tt = q->cur_len / 
-	Variants are possible, eg. to account for constant framing
-	bits as on the ethernet, or variable channel acquisition times,
-	etc.
-	This mechanism can also be used to simulate variable queueing
-	delay e.g. due to the presence of cross traffic.
-
-    q->c_delay (set with the -D option) implements delay emulation.
-	The function should set q->cur_delay to the additional
-	delay the packet is subject to. The framework will take care of
-	computing the actual exit time of a packet so that there is no
-	reordering.
-
-
-#endif /* COMMENT */
+/*
+ * This program implements NMREPLAY, a program to replay a pcap file
+ * enforcing the output rate and possibly random losses and delay
+ * distributions.
+ * It is meant to be run from the command line and implemented with a main
+ * control thread for monitoring, plus a thread to push packets out.
+ *
+ * The control thread parses command line arguments, prepares a
+ * schedule for transmission in a memory buffer and then sits
+ * in a loop where it periodically reads traffic statistics from
+ * the other threads and prints them out on the console.
+ *
+ * The transmit buffer contains headers and packets. Each header
+ * includes a timestamp that determines when the packet should be sent out.
+ * A "consumer" thread cons() reads from the queue and transmits packets
+ * on the output netmap port when their time has come.
+ *
+ * The program does CPU pinning and sets the scheduler and priority
+ * for the "cons" threads. Externally one should do the
+ * assignment of other threads (e.g. interrupt handlers) and
+ * make sure that network interfaces are configured properly.
+ *
+ * --- Main functions of the program ---
+ * within each function, q is used as a pointer to the queue holding
+ * packets and parameters.
+ *
+ * pcap_prod()
+ *
+ *	reads from the pcap file and prepares packets to transmit.
+ *	After reading a packet from the pcap file, the following information
+ *	are extracted which can be used to determine the schedule:
+ *
+ *   	q->cur_pkt	points to the buffer containing the packet
+ *	q->cur_len	packet length, excluding CRC
+ *	q->cur_caplen	available packet length (may be shorter than cur_len)
+ *	q->cur_tt	transmission time for the packet, computed from the trace.
+ *
+ *  The following functions are then called in sequence:
+ *
+ *  q->c_loss (set with the -L command line option) decides
+ *	whether the packet should be dropped before even queuing.
+ *	This is generally useful to emulate random loss.
+ *	The function is supposed to set q->c_drop = 1 if the
+ *	packet should be dropped, or leave it to 0 otherwise.
+ *
+ *   q->c_bw (set with the -B command line option) is used to
+ *      enforce the transmit bandwidth. The function must store
+ *	in q->cur_tt the transmission time (in nanoseconds) of
+ *	the packet, which is typically proportional to the length
+ *	of the packet, i.e. q->cur_tt = q->cur_len / 
+ *	Variants are possible, eg. to account for constant framing
+ *	bits as on the ethernet, or variable channel acquisition times,
+ *	etc.
+ *	This mechanism can also be used to simulate variable queueing
+ *	delay e.g. due to the presence of cross traffic.
+ *
+ *   q->c_delay (set with the -D option) implements delay emulation.
+ *	The function should set q->cur_delay to the additional
+ *	delay the packet is subject to. The framework will take care of
+ *	computing the actual exit time of a packet so that there is no
+ *	reordering.
+ */
 
 // debugging macros
 #define NED(_fmt, ...)	do {} while (0)
@@ -115,21 +112,20 @@ pcap_prod()
 
 /*
  *
-A packet in the queue is q_pkt plus the payload.
-
-For the packet descriptor we need the following:
-
-    -	position of next packet in the queue (can go backwards).
-	We can reduce to 32 bits if we consider alignments,
-	or we just store the length to be added to the current
-	value and assume 0 as a special index.
-    -	actual packet length (16 bits may be ok)
-    -	queue output time, in nanoseconds (64 bits)
-    -	delay line output time, in nanoseconds
-	One of the two can be packed to a 32bit value
-
-A convenient coding uses 32 bytes per packet.
-
+ * A packet in the queue is q_pkt plus the payload.
+ *
+ * For the packet descriptor we need the following:
+ *
+ *  -	position of next packet in the queue (can go backwards).
+ *	We can reduce to 32 bits if we consider alignments,
+ *	or we just store the length to be added to the current
+ *	value and assume 0 as a special index.
+ *  -	actual packet length (16 bits may be ok)
+ *  -	queue output time, in nanoseconds (64 bits)
+ *  -	delay line output time, in nanoseconds
+ *	One of the two can be packed to a 32bit value
+ *
+ * A convenient coding uses 32 bytes per packet.
  */
 
 struct q_pkt {

From 48d8ee8f033891bcc1eeedc1085b8d5c8e0a7a21 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Apr 2018 19:14:02 +0200
Subject: [PATCH 0845/2207] compute the ring ranges after updating the port
 config

---
 sys/dev/netmap/netmap.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index eb18d03db..88950d1cb 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2089,9 +2089,6 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 
 	NMG_LOCK_ASSERT();
 	priv->np_na = na;     /* store the reference */
-	error = netmap_set_ringid(priv, nr_mode, nr_ringid, nr_flags);
-	if (error)
-		goto err;
 	error = netmap_mem_finalize(na->nm_mem, na);
 	if (error)
 		goto err;
@@ -2107,7 +2104,14 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 
 		/* ring configuration may have changed, fetch from the card */
 		netmap_update_config(na);
+	}
 
+	/* compute the range of tx and rx rings to monitor */
+	error = netmap_set_ringid(priv, nr_mode, nr_ringid, nr_flags);
+	if (error)
+		goto err_put_lut;
+
+	if (na->active_fds == 0) {
 		/*
 		 * If this is the first registration of the adapter,
 		 * perform sanity checks and create the in-kernel view

From f990449cbeb2aff96d7162f86a8d1529bb65a71d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Apr 2018 19:26:00 +0200
Subject: [PATCH 0846/2207] fix cleanup of rings in error path

---
 sys/dev/netmap/netmap.c      | 5 ++---
 sys/dev/netmap/netmap_mem2.c | 6 +++++-
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 88950d1cb..a753f548d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2199,7 +2199,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	nifp = netmap_mem_if_new(na, priv);
 	if (nifp == NULL) {
 		error = ENOMEM;
-		goto err_del_rings;
+		goto err_rel_excl;
 	}
 
 	if (nm_kring_pending(priv)) {
@@ -2225,10 +2225,9 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 
 err_del_if:
 	netmap_mem_if_delete(na, nifp);
-err_del_rings:
-	netmap_mem_rings_delete(na);
 err_rel_excl:
 	netmap_krings_put(priv);
+	netmap_mem_rings_delete(na);
 err_del_krings:
 	if (na->active_fds == 0)
 		na->nm_krings_delete(na);
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 4ac9f4cf0..8e1b68884 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1942,7 +1942,11 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 	return 0;
 
 cleanup:
-	netmap_free_rings(na);
+	/* we cannot actually cleanup here, since we don't own kring->users
+	 * and kring->nr_klags & NKR_NEEDRING. The caller must decrement
+	 * the first or zero-out the second, then call netmap_free_rings()
+	 * to do the cleanup
+	 */
 
 	return ENOMEM;
 }

From dd9f111a9836e556bb3594231073f217a46eeff9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 16 Apr 2018 15:57:29 +0200
Subject: [PATCH 0847/2207] freebsd: import fix from 12-current

---
 sys/dev/netmap/netmap_freebsd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 7f4079502..aa483f00c 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -630,7 +630,7 @@ struct nm_os_extmem {
 void
 nm_os_extmem_delete(struct nm_os_extmem *e)
 {
-	D("freeing %jx bytes", (uintmax_t)e->size);
+	D("freeing %zx bytes", (size_t)e->size);
 	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
 	nm_os_free(e);
 }
@@ -699,7 +699,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
 			VM_PROT_READ | VM_PROT_WRITE, 0);
 	if (rv != KERN_SUCCESS) {
-		D("vm_map_find(%jx) failed", (uintmax_t)e->size);
+		D("vm_map_find(%zx) failed", (size_t)e->size);
 		goto out_rel;
 	}
 	rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,

From cc77a035120fb90fc1cf07645228496d2bee22f8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 16 Apr 2018 16:20:04 +0200
Subject: [PATCH 0848/2207] freebsd: re, vtnet: apply missing fixes

---
 sys/dev/netmap/if_re_netmap.h    | 6 +++---
 sys/dev/netmap/if_vtnet_netmap.h | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index 55f614c2b..c48b77b7e 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -302,7 +302,7 @@ re_netmap_tx_init(struct rl_softc *sc)
 	/* l points in the netmap ring, i points in the NIC ring */
 	for (i = 0; i < n; i++) {
 		uint64_t paddr;
-		int l = netmap_idx_n2k(&na->tx_rings[0], i);
+		int l = netmap_idx_n2k(na->tx_rings[0], i);
 		void *addr = PNMB(na, slot + l, &paddr);
 
 		desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
@@ -328,11 +328,11 @@ re_netmap_rx_init(struct rl_softc *sc)
 	 * Do not release the slots owned by userspace,
 	 * and also keep one empty.
 	 */
-	max_avail = n - 1 - nm_kr_rxspace(&na->rx_rings[0]);
+	max_avail = n - 1 - nm_kr_rxspace(na->rx_rings[0]);
 	for (nic_i = 0; nic_i < n; nic_i++) {
 		void *addr;
 		uint64_t paddr;
-		uint32_t nm_i = netmap_idx_n2k(&na->rx_rings[0], nic_i);
+		uint32_t nm_i = netmap_idx_n2k(na->rx_rings[0], nic_i);
 
 		addr = PNMB(na, slot + nm_i, &paddr);
 
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 7dc7716fc..e78cf0ee2 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -383,7 +383,7 @@ vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc)
 	if (!nm_native_on(na))
 		return 0;
 	for (r = 0; r < na->num_rx_rings; r++) {
-                struct netmap_kring *kring = &na->rx_rings[r];
+                struct netmap_kring *kring = na->rx_rings[r];
 		struct vtnet_rxq *rxq = &sc->vtnet_rxqs[r];
 		struct virtqueue *vq = rxq->vtnrx_vq;
 	        struct netmap_slot* slot;

From a1032d1ae9e8bd5a10bdfc13f4bf8ffb32bffa2e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 20 Apr 2018 15:25:54 +0200
Subject: [PATCH 0849/2207] linux/config: add suppor for mlx5

---
 LINUX/configure              |  1 +
 LINUX/default-config.mak.in_ | 18 +++++++++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 69a5e8ef9..1d66a4ce0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -132,6 +132,7 @@ edrv enable igb
 edrv enable ixgbe
 edrv enable ixgbevf
 edrv enable i40e
+edrv enable mlx5
 
 # drivers built by patching the system drivers
 setop internal_driver new driver
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index cfafc2f61..a9e1215fb 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -21,4 +21,20 @@ $(eval $(call default,e1000e,3.3.6))
 $(eval $(call default,igb,5.3.5.12))
 $(eval $(call default,i40e,2.3.6))
 
-$(foreach d,$(E_DRIVERS),$(eval $(call intel_driver,$d,$($(d)@v))))
+$(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
+
+define mellanox_driver
+$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://www.mellanox.com/downloads/Drivers/mlnx-en-$(2).tgz -P @SRCDIR@/ext-drivers
+$(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
+$(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
+$(1)@build	:= (cd $(1); scripts/mlnx_en_patch.sh --without-mlx4) && make -C $(1)
+$(1)@install	:= make -C $(1) install
+$(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi
+$(1)@distclean  := rm -rf mlnx-en-$($(1)@pv)
+$(1)@force	:= 1
+endef
+
+$(eval $(call default,mlx5,3.3-1.0.0.0))
+mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
+
+$(foreach d,$(filter mlx5,$(E_DRIVERS)),$(eval $(call mellanox_driver,$d,$($(d)@v))))

From a2954d07446aa0824e4d3add0ee196dab8daea16 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 23 Apr 2018 16:47:01 +0200
Subject: [PATCH 0850/2207] linux/mlx5: integrate with build-system

---
 LINUX/configure              |  7 +++++--
 LINUX/default-config.mak.in_ |  8 +++++---
 LINUX/mlx5-prepare.sh        | 17 +++++++++++++++++
 LINUX/netmap.mak.in          |  1 +
 4 files changed, 28 insertions(+), 5 deletions(-)
 create mode 100755 LINUX/mlx5-prepare.sh

diff --git a/LINUX/configure b/LINUX/configure
index 1d66a4ce0..8218f2a11 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -255,6 +255,7 @@ replace_vars()
 	sed \
 		-e "s|@BUILDDIR@|$BUILDDIR|g" \
 		-e "s|@SRCDIR@|$SRCDIR|g" \
+		-e "s|@TMPDIR@|$TMPDIR|g" \
 		-e "s|@KSRC@|$ksrc|g" \
 		-e "s|@SRC@|$src|g" \
 		-e "s|@KOPTS@|$kopts|g" \
@@ -468,7 +469,10 @@ get-$d:
 	\$($d@fetch)
 	\$($d@src)
 	touch get-$d
-build-$d: get-$d
+prepare-$d: get-$d
+	\$($d@prepare)
+	touch prepare-$d
+build-$d: prepare-$d
 	+\$($d@build)
 	touch build-$d
 patch-$d: get-$d
@@ -747,7 +751,6 @@ done
 
 replace_vars $SRCDIR/default-config.mak.in_ > default-config.mak
 
-
 ###############################################################
 # Makefile creation
 ###############################################################
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index a9e1215fb..9f7408d85 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -2,6 +2,7 @@ define intel_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sourceforge.net/projects/e1000/files/$(1)%20stable/$(2)/$(1)-$(2).tar.gz -P @SRCDIR@/ext-drivers/
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
+$(1)@prepare	:=
 $(1)@build 	:= make -C $(1) CFLAGS_EXTRA="$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 $(1)@install 	:= make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 $(1)@clean 	:= if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
@@ -27,10 +28,11 @@ define mellanox_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://www.mellanox.com/downloads/Drivers/mlnx-en-$(2).tgz -P @SRCDIR@/ext-drivers
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
-$(1)@build	:= (cd $(1); scripts/mlnx_en_patch.sh --without-mlx4) && make -C $(1)
-$(1)@install	:= make -C $(1) install
+$(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@ @TMPDIR@
+$(1)@build	:= make -C $(1)
+$(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@
 $(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi
-$(1)@distclean  := rm -rf mlnx-en-$($(1)@pv)
+$(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
diff --git a/LINUX/mlx5-prepare.sh b/LINUX/mlx5-prepare.sh
new file mode 100755
index 000000000..c03d45548
--- /dev/null
+++ b/LINUX/mlx5-prepare.sh
@@ -0,0 +1,17 @@
+#!/bin/sh -x
+
+KSRC=$1
+TMPDIR=$2
+
+if [ -e mlx5/config.mk ]; then
+	exit 0
+fi
+
+if [ -e $TMPDIR/mlx5/config.mk ]; then
+	sed "s|^CWD=.*|CWD=$PWD/mlx5|" $TMPDIR/mlx5/config.mk > mlx5/config.mk
+	cp -r $TMPDIR/mlx5/compat/* mlx5/compat/
+	exit 0
+fi
+
+cd mlx5
+scripts/mlnx_en_patch.sh --without-mlx4 -s $KSRC -j$(grep -c processor /proc/cpuinfo)
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 451265b13..78dfcdaed 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -54,6 +54,7 @@ get-$(1):
 	$($(1)@fetch)
 	$($(1)@src)
 	$(foreach p,$($(1)@patch),patch --posix --quiet --force -p1 < $(p);)
+	$($(1)@prepare)
 	$(if $($(1)@build),,$(if $(filter-out %.c,$(1)),mv $(1)/Makefile $(1)/orig.mak || mv $(1)/Kbuild $(1)/orig.mak; cp drv-subdir.mak $(1)/Makefile,))
 	touch get-$(1)
 distclean-$(1):

From 22d5c46e4ee42f04db0d7d1b2ac7ff9e48811810 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 24 Apr 2018 11:56:28 +0200
Subject: [PATCH 0851/2207] linux/mlx5: add support for driver suffix

---
 LINUX/default-config.mak.in_ | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 9f7408d85..f3729cfdf 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -29,9 +29,9 @@ $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://www.m
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
 $(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@ @TMPDIR@
-$(1)@build	:= make -C $(1)
-$(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@
-$(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi
+$(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
+$(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
+$(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef

From bde4c69eb32f0ce2cccd89f00761e78f2cd6c662 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 29 Apr 2018 18:31:38 +0200
Subject: [PATCH 0852/2207] LINUX: select correct CONFIG_* entry for mlx5
 driver

---
 LINUX/default-config.mak.in_ | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index f3729cfdf..a38f7075d 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -38,5 +38,6 @@ endef
 
 $(eval $(call default,mlx5,3.3-1.0.0.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
+mlx5@conf	= CONFIG_MLX5_CORE_EN
 
 $(foreach d,$(filter mlx5,$(E_DRIVERS)),$(eval $(call mellanox_driver,$d,$($(d)@v))))

From 366c53e86453f84412c51801382a8b3dd293f9d1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 May 2018 10:49:52 +0200
Subject: [PATCH 0853/2207] linux/configure: use -O option of make to improve
 readability of config.log

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 8218f2a11..bf62e5f62 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -495,7 +495,7 @@ EOF
 	} >> config.log
 	(
 		cd $TMPDIR
-		make -k -j $(grep -c processor /proc/cpuinfo)
+		make -O -k -j $(grep -c processor /proc/cpuinfo)
 	) >> config.log
 	eval "$TESTPOSTPROC"
 	cat >> config.log <
Date: Wed, 2 May 2018 11:08:18 +0200
Subject: [PATCH 0854/2207] linux/igb: Intel 5.3.5.18 version

---
 LINUX/final-patches/intel--igb--5.3.5.18 | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.18

diff --git a/LINUX/final-patches/intel--igb--5.3.5.18 b/LINUX/final-patches/intel--igb--5.3.5.18
new file mode 100644
index 000000000..e69de29bb

From 6800d631ba1d59867640b2bb55c2d27c0330e70c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 May 2018 11:32:26 +0200
Subject: [PATCH 0855/2207] linux: never ignore changes in final-patches

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 646430f4d..aa184804d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,6 +75,7 @@ read-vars.mak
 !LINUX/default-config.mak
 !LINUX/drv-subdir.mak
 !LINUX/read-vars.mak
+!LINUX/final-patches/*
 LINUX/scripts/conf
 config.mak
 *.rej

From 790d27380f989cea3ea1d31f12928cfce1c5b439 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 May 2018 11:44:18 +0200
Subject: [PATCH 0856/2207] linux/ixgbe: Intel 5.3.7 version

---
 LINUX/final-patches/intel--ixgbe--5.3.7 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.3.7

diff --git a/LINUX/final-patches/intel--ixgbe--5.3.7 b/LINUX/final-patches/intel--ixgbe--5.3.7
new file mode 100644
index 000000000..f656c7197
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.3.7
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 545489a..e085666 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index d1e70f1..392d1ab 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -734,6 +734,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -752,6 +769,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2033,6 +2061,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3320,6 +3358,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3967,6 +4009,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11245,6 +11291,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11290,6 +11340,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From d14d70cbb10f6f8ce6fca8abaf74d6e090c1eb0e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 May 2018 11:54:57 +0200
Subject: [PATCH 0857/2207] linux/ixgbevf: Intel 4.3.5 version

---
 LINUX/final-patches/intel--ixgbevf--4.3.5 | 177 ++++++++++++++++++++++
 1 file changed, 177 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.3.5

diff --git a/LINUX/final-patches/intel--ixgbevf--4.3.5 b/LINUX/final-patches/intel--ixgbevf--4.3.5
new file mode 100644
index 000000000..417284dcb
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.3.5
@@ -0,0 +1,177 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index c8d39f4..e16565a 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 6a3720f..2752402 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1192,6 +1220,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1825,6 +1863,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1835,7 +1877,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+- 
++
+ /**
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+@@ -2012,6 +2054,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4984,8 +5030,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5025,6 +5073,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 25e42e9..3374fb9 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 53caf0a8be56ec21d5d4c2f0945408ce31367589 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 May 2018 12:07:31 +0200
Subject: [PATCH 0858/2207] linux/igb: patch for Intel 5.3.5.18 version

---
 LINUX/final-patches/intel--igb--5.3.5.18 | 131 +++++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/LINUX/final-patches/intel--igb--5.3.5.18 b/LINUX/final-patches/intel--igb--5.3.5.18
index e69de29bb..6d099a9f5 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.18
+++ b/LINUX/final-patches/intel--igb--5.3.5.18
@@ -0,0 +1,131 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 02d49bb..47fd630 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -28,7 +28,7 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+ define igb-y
+ 	igb_main.o
+@@ -46,19 +46,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -114,6 +114,9 @@ sparse: clean
+ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Build manfiles
+ manfile:
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index b98cfa6..13b17ea 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * igb_init_module - Driver Registration Routine
+  *
+@@ -3073,6 +3077,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3276,6 +3284,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3686,6 +3698,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7240,6 +7255,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8256,6 +8276,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8575,6 +8600,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 7e438ad65db7a49b06ab0e22cad3eb900859b776 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 3 May 2018 15:28:52 +0200
Subject: [PATCH 0859/2207] pipe: also forward slot flags

---
 sys/dev/netmap/netmap_pipe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 473879cf2..ed57ceed3 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -206,11 +206,11 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 		struct netmap_slot *ts = &txring->slot[k];
 
 		rs->len = ts->len;
+		rs->flags = ts->flags;
 		rs->ptr = ts->ptr;
 
 		if (ts->flags & NS_BUF_CHANGED) {
 			rs->buf_idx = ts->buf_idx;
-			rs->flags |= NS_BUF_CHANGED;
 			ts->flags &= ~NS_BUF_CHANGED;
 		}
 	}

From d2582c5d6dc0cc3ecdcb32c53650d76d898fc34a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 10 May 2018 18:03:17 +0200
Subject: [PATCH 0860/2207] lb, vale-ctl: fix some warnings

---
 apps/lb/lb.c             | 2 +-
 apps/vale-ctl/vale-ctl.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 01d09b421..6af4adea0 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -652,7 +652,7 @@ int main(int argc, char **argv)
 	/* extract the base name */
 	char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ?
 			glob_arg.ifname : glob_arg.ifname + 7;
-	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
+	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN-1);
 	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
 		;
 	*nscan = '\0';
diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index 02027594d..fc909144a 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -96,7 +96,7 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2)
 	bzero(&nmr, sizeof(nmr));
 	nmr.nr_version = NETMAP_API;
 	if (name != NULL) /* might be NULL */
-		strncpy(nmr.nr_name, name, sizeof(nmr.nr_name));
+		strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)-1);
 	nmr.nr_cmd = nr_cmd;
 	parse_nmr_config(nmr_config, &nmr);
 	nmr.nr_arg2 = nr_arg2;

From e0d60ad7bc510c0f6e62f917355e989189a5fa2f Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Thu, 10 May 2018 19:18:25 +0100
Subject: [PATCH 0861/2207] mlx5: Move to faster download link

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index a38f7075d..81abdbeab 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -25,7 +25,7 @@ $(eval $(call default,i40e,2.3.6))
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 
 define mellanox_driver
-$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://www.mellanox.com/downloads/Drivers/mlnx-en-$(2).tgz -P @SRCDIR@/ext-drivers
+$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://content.mellanox.com/Drivers/mlnx-en-$(2).tgz -P @SRCDIR@/ext-drivers
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
 $(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@ @TMPDIR@

From bc74744dccd655834ec6d75c0d42286baf0de2f1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 May 2018 07:25:06 +0200
Subject: [PATCH 0862/2207] linux/configure: don't assume make -O option is
 available

---
 LINUX/configure | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index bf62e5f62..67f20c1ec 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -493,10 +493,18 @@ EOF
 ##############################################################################
 EOF
 	} >> config.log
+	NPROC=$(grep -c processor /proc/cpuinfo)
 	(
 		cd $TMPDIR
-		make -O -k -j $(grep -c processor /proc/cpuinfo)
+		LANG=C make -O -k -j $NPROC
 	) >> config.log
+	if grep -q ": invalid option -- 'O'" config.log; then
+		# let us try again without -O
+		(
+			cd $TMPDIR
+			make -k -j $NPROC
+		) >> config.log
+	fi
 	eval "$TESTPOSTPROC"
 	cat >> config.log <
Date: Mon, 23 Apr 2018 16:23:37 +0200
Subject: [PATCH 0863/2207] dkms: fix autoinstall

kernelver would not be set when calling dkms autoinstall --kernelver 4.13.0-39-generic,
and the build would use `uname -r`

This would break at kernel updates
---
 LINUX/dkms/dkms.conf | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/dkms/dkms.conf b/LINUX/dkms/dkms.conf
index a6502be72..1154cff91 100644
--- a/LINUX/dkms/dkms.conf
+++ b/LINUX/dkms/dkms.conf
@@ -5,7 +5,7 @@ REMAKE_INITRD=yes
 AUTOINSTALL=yes
 
 # netmap driver
-MAKE[0]=\'make\'
+MAKE[0]="'make' kernelver=$kernelver"
 BUILT_MODULE_NAME[0]=netmap
 DEST_MODULE_LOCATION[0]=/kernel/net/netmap/
 

From 6ce986ad300a28413e3fe5df3244b6f11b34f716 Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Fri, 11 May 2018 15:27:37 +0100
Subject: [PATCH 0864/2207] mlx5: fix nm_config call to match latest netmap
 revision

---
 LINUX/mlx5_netmap_linux.h | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index 42c4ccfe4..a1721f650 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -689,19 +689,14 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
   return 1;
 }
 
-int mlx5e_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
-                        u_int *rxr, u_int *rxd) {
-  struct ifnet *ifp = na->ifp;
-  struct NM_MLX5E_ADAPTER *adapter = netdev_priv(ifp);
+int mlx5e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info) {
+  int ret = netmap_rings_config_get(na, info);
 
-  /* each channel has 1 rx ring and a tx for each tc */
-  *txr = adapter->params.num_channels * adapter->params.num_tc;
-  *rxr = adapter->params.num_channels;
-  *txd = (1 << adapter->params.log_sq_size);
-  *rxd = (1 << adapter->params.log_rq_size);
+  if (ret) {
+    return ret;
+  }
 
-  D("TX: %d rings with %d slots;  RX: %d rings with %d slots", *txr, *txd, *rxr,
-    *rxd);
+  info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
   return 0;
 }
@@ -729,6 +724,7 @@ void mlx5e_netmap_attach(struct NM_MLX5E_ADAPTER *adapter) {
   /* each channel has 1 rx ring and a tx for each tc */
   na.num_tx_rings = adapter->params.num_channels * adapter->params.num_tc;
   na.num_rx_rings = adapter->params.num_channels;
+  na.rx_buf_maxsize = 1500; /* will be overwritten by nm_config */
   netmap_attach(&na);
 }
 

From 2b33e997d2b71d7c0c8c9fbe3cadd213f2e65a0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Mon, 14 May 2018 10:13:10 +0200
Subject: [PATCH 0865/2207] mlx5: fix compilation error introduced by
 cf9e6c7f0f7f57ad

---
 LINUX/mlx5_netmap_linux.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index a1721f650..79a002b5a 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -662,7 +662,7 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
   if (!slot)
     return 0; /* not in native netmap mode */
 
-  lim = na->num_rx_desc - 1 - nm_kr_rxspace(&na->rx_rings[ring_nr]);
+  lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 
   while (!mlx5_wq_ll_is_full(wq) && (count < lim)) {
 
@@ -680,7 +680,7 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
   D("populated %d WQEs in ring %d", count, ring_nr);
 
   /* tell netmap how many buffers we have prepared */
-  (na->rx_rings[ring_nr]).nr_hwcur = count;
+  na->rx_rings[ring_nr]->nr_hwcur = count;
 
   /* ensure wqes are visible to device before updating doorbell record */
   wmb();

From 6a1924658d5b5e465570782e44f0313fdcba8dd3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Mon, 14 May 2018 10:13:54 +0200
Subject: [PATCH 0866/2207] mlx5: do not include en.h

The CFLAGS seem not to be set correctly.
Compilation seems to succeed without this include.
---
 LINUX/mlx5_netmap_linux.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index 79a002b5a..852213b74 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -87,8 +87,6 @@
 
 #ifdef NETMAP_MLX5_MAIN
 
-#include "en.h"
-
 #define NM_MLX5E_ADAPTER mlx5e_priv
 
 /* These functions are in en_rx.c but needed here to

From 7ac473624fc093adb7e7929cb3db2daf66dd0acc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Mon, 14 May 2018 10:16:24 +0200
Subject: [PATCH 0867/2207] mlx5: actually enable netmap

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 81abdbeab..91be2b965 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -29,7 +29,7 @@ $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://conte
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
 $(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@ @TMPDIR@
-$(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
+$(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$(EXTRA_CFLAGS)"
 $(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)

From acfa04e6df63b031bf52c55d2732298d02ba4b01 Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Fri, 4 May 2018 15:00:25 +0100
Subject: [PATCH 0868/2207] netmap_linux: set mbuf protocol based on ethertype
 and reset ip_summed

---
 LINUX/netmap_linux.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index f8128d881..8279a3968 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -920,6 +920,9 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 	return 0;
 }
 
+/* Used to cover cases where ETH_P_802_3_MIN is undefined */
+#define NM_ETH_P_802_3_MIN 0x0600
+
 /* Transmit routine used by generic_netmap_txsync(). Returns 0 on success
    and -1 on error (which may be packet drops or other errors). */
 int
@@ -929,6 +932,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	struct ifnet *ifp = a->ifp;
 	u_int len = a->len;
 	netdev_tx_t ret;
+	uint16_t ethertype;
 
 	/* We know that the driver needs to prepend ifp->needed_headroom bytes
 	 * to each packet to be transmitted. We then reset the mbuf pointers
@@ -947,19 +951,28 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	skb_reset_tail_pointer(m);
 	skb_reset_mac_header(m);
 
-	/* Initialize the header pointers assuming this is an IPv4 packet.
-	 * This is useful to make netmap interact well with TC when
-	 * netmap_generic_txqdisc == 0.  */
-	skb_set_network_header(m, 14);
-	skb_set_transport_header(m, 34);
-	m->protocol = htons(ETH_P_IP);
-	m->pkt_type = PACKET_HOST;
-
 	/* Copy a netmap buffer into the mbuf.
 	 * TODO Support the slot flags (NS_MOREFRAG, NS_INDIRECT). */
 	skb_copy_to_linear_data(m, a->addr, len); // skb_store_bits(m, 0, addr, len);
 	skb_put(m, len);
 
+	/* Initialize the header pointers assuming this is an IP packet.
+	 * This is useful to make netmap interact well with TC when
+	 * netmap_generic_txqdisc == 0.  */
+	skb_set_network_header(m, ETH_HLEN);
+	ethertype = *((uint16_t*)(m->data + ETH_ALEN * 2));
+	m->protocol = ntohs(ethertype) >= NM_ETH_P_802_3_MIN ? ethertype : htons(ETH_P_802_3);
+	m->pkt_type = PACKET_HOST;
+	m->ip_summed = CHECKSUM_NONE;
+
+	if (m->protocol == htons(ETH_P_IPV6)) {
+		skb_set_transport_header(m, ETH_HLEN + sizeof(struct nm_ipv6hdr));
+	} else if (m->protocol == htons(ETH_P_IP)) {
+		skb_set_transport_header(m, ETH_HLEN + sizeof(struct nm_iphdr));
+	} else {
+		skb_reset_transport_header(m);
+	}
+
 	/* Hold a reference on this, we are going to recycle mbufs as
 	 * much as possible. */
 #ifdef NETMAP_LINUX_HAVE_REFCOUNT_T

From 7c3ea1b3e927d4fd86297c89cd27d3b9a7bda841 Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Fri, 4 May 2018 15:01:23 +0100
Subject: [PATCH 0869/2207] checksums: add checksum offload option for use with
 unmodified drivers

---
 LINUX/netmap_linux.c         | 22 ++++++++++++++++++++++
 sys/dev/netmap/netmap.c      | 14 +++++++++++---
 sys/dev/netmap/netmap_kern.h |  1 +
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 8279a3968..359711d49 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -33,6 +33,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -989,6 +990,27 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	m->dev = ifp;
 	skb_shinfo(m)->destructor_arg = m->dev;
 
+	/* Tell the NIC to compute checksums for outgoing TCP and UDP packets */
+	if (netmap_generic_hwcsum) {
+		uint8_t transport_proto = IPPROTO_IP;
+
+		if (m->protocol == htons(ETH_P_IPV6)) {
+			transport_proto = ((struct nm_ipv6hdr*)ip_hdr(m))->nexthdr;
+		} else if (m->protocol == htons(ETH_P_IP)) {
+			transport_proto = ((struct nm_iphdr*)ip_hdr(m))->protocol;
+		}
+
+		if (transport_proto == IPPROTO_TCP) {
+			m->ip_summed = CHECKSUM_PARTIAL;
+			m->csum_start = m->transport_header;
+			m->csum_offset = 16; /* offset to TCP checksum within TCP header */
+		} else if (transport_proto == IPPROTO_UDP) {
+			m->ip_summed = CHECKSUM_PARTIAL;
+			m->csum_start = m->transport_header;
+			m->csum_offset = 6; /* offset to UDP checksum within UDP header */
+		}
+	}
+
 	/* Tell generic_ndo_start_xmit() to pass this mbuf to the driver. */
 	skb_set_queue_mapping(m, a->ring_nr);
 	m->priority = a->qevent ? NM_MAGIC_PRIORITY_TXQE : NM_MAGIC_PRIORITY_TX;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a753f548d..7396eb1ca 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -519,6 +519,9 @@ int netmap_generic_txqdisc = 1;
 int netmap_generic_ringsize = 1024;
 int netmap_generic_rings = 1;
 
+/* Non-zero to enable checksum offloading in NIC drivers */
+int netmap_generic_hwcsum = 0;
+
 /* Non-zero if ptnet devices are allowed to use virtio-net headers. */
 int ptnet_vnet_hdr = 1;
 
@@ -547,6 +550,9 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0,
 SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0,
 		"Adapter mode. 0 selects the best option available,"
 		"1 forces native adapter, 2 forces emulated adapter");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_hwcsum, CTLFLAG_RW, &netmap_generic_hwcsum,
+		0, "Hardware checksums. 0 to disable checksum generation by the NIC (default),"
+		"1 to enable checksum generation by the NIC");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit,
 		0, "RX notification interval in nanoseconds");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW,
@@ -3637,9 +3643,11 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 		goto done;
 	}
 
-	if (nm_os_mbuf_has_offld(m)) {
-		RD(1, "%s drop mbuf that needs offloadings", na->name);
-		goto done;
+	if (!netmap_generic_hwcsum) {
+		if (nm_os_mbuf_has_offld(m)) {
+			RD(1, "%s drop mbuf that needs offloadings", na->name);
+			goto done;
+		}
 	}
 
 	/* protect against netmap_rxsync_from_host(), netmap_sw_to_nic()
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7d1134d5e..47938412e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1609,6 +1609,7 @@ enum {                                  /* verbose flags */
 
 extern int netmap_txsync_retry;
 extern int netmap_flags;
+extern int netmap_generic_hwcsum;
 extern int netmap_generic_mit;
 extern int netmap_generic_ringsize;
 extern int netmap_generic_rings;

From 03ba67b682fd287fdc1b3b2f5c9787cb5b4a6faa Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Tue, 15 May 2018 09:12:04 +0100
Subject: [PATCH 0870/2207] offloading: split mbuf check into two for
 segmentation and checksums

---
 LINUX/netmap_linux.c            | 10 ++++++++--
 WINDOWS/netmap_windows.c        |  8 +++++++-
 sys/dev/netmap/netmap.c         |  9 +++++++--
 sys/dev/netmap/netmap_freebsd.c | 10 ++++++++--
 sys/dev/netmap/netmap_kern.h    |  3 ++-
 5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 359711d49..0bc8e42f2 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -408,9 +408,15 @@ nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev)
 }
 
 int
-nm_os_mbuf_has_offld(struct mbuf *m)
+nm_os_mbuf_has_csum_offld(struct mbuf *m)
 {
-	return m->ip_summed == CHECKSUM_PARTIAL || skb_is_gso(m);
+	return m->ip_summed == CHECKSUM_PARTIAL;
+}
+
+int
+nm_os_mbuf_has_seg_offld(struct mbuf *m)
+{
+	return skb_is_gso(m);
 }
 
 #ifdef WITH_GENERIC
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 42d66a7d6..3c794eab1 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -1017,7 +1017,13 @@ nm_os_ncpus(void)
 }
 
 int
-nm_os_mbuf_has_offld(struct mbuf *m)
+nm_os_mbuf_has_csum_offld(struct mbuf *m)
+{
+	return 0;  // TODO
+}
+
+int
+nm_os_mbuf_has_seg_offld(struct mbuf *m)
 {
 	return 0;  // TODO
 }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7396eb1ca..64b61f2cf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3644,12 +3644,17 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	}
 
 	if (!netmap_generic_hwcsum) {
-		if (nm_os_mbuf_has_offld(m)) {
-			RD(1, "%s drop mbuf that needs offloadings", na->name);
+		if (nm_os_mbuf_has_csum_offld(m)) {
+			RD(1, "%s drop mbuf that needs checksum offload", na->name);
 			goto done;
 		}
 	}
 
+	if (nm_os_mbuf_has_seg_offld(m)) {
+		RD(1, "%s drop mbuf that needs generic segmentation offload", na->name);
+		goto done;
+	}
+
 	/* protect against netmap_rxsync_from_host(), netmap_sw_to_nic()
 	 * and maybe other instances of netmap_transmit (the latter
 	 * not possible on Linux).
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index aa483f00c..d4b8795c0 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -268,11 +268,17 @@ nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev)
 }
 
 int
-nm_os_mbuf_has_offld(struct mbuf *m)
+nm_os_mbuf_has_csum_offld(struct mbuf *m)
 {
 	return m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_SCTP |
 					 CSUM_TCP_IPV6 | CSUM_UDP_IPV6 |
-					 CSUM_SCTP_IPV6 | CSUM_TSO);
+					 CSUM_SCTP_IPV6);
+}
+
+int
+nm_os_mbuf_has_seg_offld(struct mbuf *m)
+{
+	return m->m_pkthdr.csum_flags & CSUM_TSO;
 }
 
 static void
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 47938412e..58b031fbc 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -311,7 +311,8 @@ void nm_os_vfree(void *);
  */
 void *nm_os_send_up(struct ifnet *, struct mbuf *m, struct mbuf *prev);
 
-int nm_os_mbuf_has_offld(struct mbuf *m);
+int nm_os_mbuf_has_seg_offld(struct mbuf *m);
+int nm_os_mbuf_has_csum_offld(struct mbuf *m);
 
 #include "netmap_mbq.h"
 

From 60cc73793205e0d831138fffd92f40c69acf1f10 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 14:22:37 +0200
Subject: [PATCH 0871/2207] linux/i40e: add missing calls to
 preconfigure_rx_ring in 2.4.3 and 2.4.6

---
 LINUX/final-patches/intel--i40e--2.4.3 | 19 +++++++++++++++----
 LINUX/final-patches/intel--i40e--2.4.6 | 19 +++++++++++++++----
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/LINUX/final-patches/intel--i40e--2.4.3 b/LINUX/final-patches/intel--i40e--2.4.3
index 19c245cd8..100e3a31f 100644
--- a/LINUX/final-patches/intel--i40e--2.4.3
+++ b/LINUX/final-patches/intel--i40e--2.4.3
@@ -46,7 +46,7 @@ index ff50970..8d7f7fb 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 52a661a..0289012 100644
+index 52a661a..487ccc0 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -72,7 +72,18 @@ index 52a661a..0289012 100644
  	return 0;
  }
  
-@@ -3361,6 +3370,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3333,6 +3342,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3361,6 +3374,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -84,7 +95,7 @@ index 52a661a..0289012 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10901,6 +10915,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10901,6 +10919,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -96,7 +107,7 @@ index 52a661a..0289012 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -11269,6 +11288,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -11269,6 +11292,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.4.6 b/LINUX/final-patches/intel--i40e--2.4.6
index 1927e489c..2d5289bf4 100644
--- a/LINUX/final-patches/intel--i40e--2.4.6
+++ b/LINUX/final-patches/intel--i40e--2.4.6
@@ -46,7 +46,7 @@ index d33d3a8..e5f49a0 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index ae669c3..42e541d 100644
+index ae669c3..0fa8375 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
@@ -72,7 +72,18 @@ index ae669c3..42e541d 100644
  	return 0;
  }
  
-@@ -3361,6 +3370,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3333,6 +3342,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3361,6 +3374,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -84,7 +95,7 @@ index ae669c3..42e541d 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -10914,6 +10928,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -10914,6 +10932,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -96,7 +107,7 @@ index ae669c3..42e541d 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -11282,6 +11301,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -11282,6 +11305,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}

From 67901e07d8895d58186616ba78b04bfd8df3bcb5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 14:13:01 +0200
Subject: [PATCH 0872/2207] linux/i40e: default to 2.4.6

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 81abdbeab..6277b143e 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -20,7 +20,7 @@ $(eval $(call default,ixgbe,5.3.3))
 $(eval $(call default,ixgbevf,4.3.2))
 $(eval $(call default,e1000e,3.3.6))
 $(eval $(call default,igb,5.3.5.12))
-$(eval $(call default,i40e,2.3.6))
+$(eval $(call default,i40e,2.4.6))
 
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 

From 70d4ab1607a3768444eb92892dddd2c922df13a3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 14:25:56 +0200
Subject: [PATCH 0873/2207] linux/e1000e: default to 3.4.0.2

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 6277b143e..59842c88a 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -18,7 +18,7 @@ e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 $(eval $(call default,ixgbe,5.3.3))
 $(eval $(call default,ixgbevf,4.3.2))
-$(eval $(call default,e1000e,3.3.6))
+$(eval $(call default,e1000e,3.4.0.2))
 $(eval $(call default,igb,5.3.5.12))
 $(eval $(call default,i40e,2.4.6))
 

From fc671e342ae9519d15024800a7dda054396dfe34 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 14:44:36 +0200
Subject: [PATCH 0874/2207] linux/build: let distclean remove all generated
 *.mak

---
 LINUX/netmap.mak.in | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 78dfcdaed..26969003b 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -163,7 +163,8 @@ install-docs:
 
 distclean: clean $(S_DRIVERS:%=distclean-%)
 	rm -f config.status config.log netmap_linux_config.h \
-		patches drivers.mak Kbuild netmap.mak default-config.mak
+		patches drivers.mak Kbuild netmap.mak default-config.mak \
+		extdrv-versions.mak
 	rm -rf netmap-tmpdir
 	rm -f *.orig *.rej
 	if [ -L GNUmakefile ]; then rm GNUmakefile; fi

From 88fea20f5eca6adcf70ea193de09f98996f2ffbe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 14:46:05 +0200
Subject: [PATCH 0875/2207] linux/ixgbe: default to 5.3.7

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 59842c88a..ca5793ad6 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -16,7 +16,7 @@ endef
 
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
-$(eval $(call default,ixgbe,5.3.3))
+$(eval $(call default,ixgbe,5.3.7))
 $(eval $(call default,ixgbevf,4.3.2))
 $(eval $(call default,e1000e,3.4.0.2))
 $(eval $(call default,igb,5.3.5.12))

From 7f9c15dc88bb680510499056b4aaa4eef221a36e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 15:34:51 +0200
Subject: [PATCH 0876/2207] linux: fix dma-syncs directions in drivers

---
 LINUX/i40e_netmap_linux.h    | 37 +++++++++++++++++++++++++-----------
 LINUX/if_e1000_netmap.h      | 19 ++++++++++++++++--
 LINUX/if_e1000e_netmap.h     | 21 +++++++++++++++++---
 LINUX/if_igb_netmap.h        | 21 +++++++++++++++++---
 LINUX/if_vmxnet3_netmap.h    |  7 +++++--
 LINUX/ixgbe_netmap_linux.h   | 31 +++++++++++++++++++++++-------
 sys/dev/netmap/netmap_kern.h | 20 ++++++++++++-------
 7 files changed, 121 insertions(+), 35 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 6ce0d55cc..5d69b6ae7 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -329,8 +329,6 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 		RD(1, "ring %s is missing (txr=%p)", kring->name, txr);
 		return ENXIO;
 	}
-	//bus_dmamap_sync(txr->dma.tag, txr->dma.map,
-	//		BUS_DMASYNC_POSTREAD);
 
 	/*
 	 * First part: process new packets to send.
@@ -405,6 +403,8 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, len, NR_TX);
 			/* Fill the slot in the NIC ring.
 			 * (we should investigate if using legacy descriptors
 			 * is faster). */
@@ -434,9 +434,22 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 	 */
 	nic_i = i40e_netmap_read_hwtail(txr->desc, kring->nkr_num_slots);
 	if (nic_i != txr->next_to_clean) {
+		u_int tosync;
+		nm_i = netmap_idx_n2k(kring, nic_i);
+
 		/* some tx completed, increment avail */
 		txr->next_to_clean = nic_i;
-		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+		tosync = nm_next(kring->nr_hwtail, lim);
+		/* sync all buffers that we are returning to userspace */
+		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+			struct netmap_slot *slot = &ring->slot[tosync];
+			uint64_t paddr;
+			(void)PNMB(na, slot, &paddr);
+
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_TX);
+		}
+		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 
 	return 0;
@@ -517,20 +530,24 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			uint32_t staterr = (qword & I40E_RXD_QW1_STATUS_MASK)
 				 >> I40E_RXD_QW1_STATUS_SHIFT;
 		        uint16_t slot_flags = 0;
+			struct netmap_slot *slot;
+			uint64_t paddr;
 
 			if ((staterr & (1<slot[nm_i].len = ((qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
+			slot = ring->slot + nm_i;
+			slot->len = ((qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
 			    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - crclen;
 
 			if (unlikely((staterr & (1<slot[nm_i].flags = slot_flags;
+			slot->flags = slot_flags;
+			PNMB(na, slot, &paddr);
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_RX);
 
-			//bus_dmamap_sync(rxr->ptag,
-			//    rxr->buffers[nic_i].pmap, BUS_DMASYNC_POSTREAD);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -574,15 +591,13 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			}
 			curr->read.pkt_addr = htole64(paddr);
 			curr->read.hdr_addr = 0; // XXX needed
-			//bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
-			//    BUS_DMASYNC_PREREAD);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
 		kring->nr_hwcur = head;
 
-		//bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
-		//    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 		/*
 		 * IMPORTANT: we must leave one free slot in the ring,
 		 * so move nic_i back by one unit
diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index a013aab40..bc204b7aa 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -139,7 +139,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 				curr->buffer_addr = htole64(paddr);
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
@@ -160,13 +160,26 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
+		u_int tosync;
+
 		/* record completed transmissions using TDH */
 		nic_i = readl(adapter->hw.hw_addr + txr->tdh);
 		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
 			D("TDH wrap %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
+		nm_i = netmap_idx_n2k(kring, nic_i);
 		txr->next_to_clean = nic_i;
+		tosync = nm_next(kring->nr_hwtail, lim);
+		/* sync all buffers that we are returning to userspace */
+		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+			struct netmap_slot *slot = &ring->slot[tosync];
+			uint64_t paddr;
+			(void)PNMB(na, slot, &paddr);
+
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_TX);
+		}
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
 	}
 out:
@@ -226,7 +239,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->length) - 4;
 			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -256,6 +269,8 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 				curr->buffer_addr = htole64(paddr);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			curr->status = 0;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 914997f93..9cdaef5b7 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -171,7 +171,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			/* Fill the slot in the NIC ring. */
 			curr->upper.data = 0;
 			curr->lower.data = htole32(len | hw_flags);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -188,6 +188,8 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
+		u_int tosync;
+
 		/* Record completed transmissions using TDH.
 		 * Alternative approach would be to scan descriptors and read
 		 * the DD bit until we found one that is not set. */
@@ -197,8 +199,19 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			D("Warning: TDH wrap %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
+		nm_i = netmap_idx_n2k(kring, nic_i);
 		txr->next_to_clean = nic_i;
-		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+		tosync = nm_next(kring->nr_hwtail, lim);
+		/* sync all buffers that we are returning to userspace */
+		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+			struct netmap_slot *slot = &ring->slot[tosync];
+			uint64_t paddr;
+			(void)PNMB(na, slot, &paddr);
+
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_TX);
+		}
+		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 out:
 
@@ -256,7 +269,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
 			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr,
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr,
 					slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -282,6 +295,8 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
 				goto ring_reset;
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			curr->NM_E1R_RX_BUFADDR = htole64(paddr); /* reload ext.desc. addr. */
 			if (slot->flags & NS_BUF_CHANGED) {
 				slot->flags &= ~NS_BUF_CHANGED;
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 695a5ba1a..584583cbf 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -156,7 +156,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 				hw_flags |= E1000_TXD_CMD_EOP;
 			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->read.buffer_addr = htole64(paddr);
@@ -183,13 +183,26 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
+		u_int tosync;
+
 		/* record completed transmissions using TDH */
 		nic_i = READ_TDH(adapter, txr);
 		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
 			D("TDH wrap %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
-		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+		nm_i = netmap_idx_n2k(kring, nic_i);
+		tosync = nm_next(kring->nr_hwtail, lim);
+		/* sync all buffers that we are returning to userspace */
+		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+			struct netmap_slot *slot = &ring->slot[tosync];
+			uint64_t paddr;
+			(void)PNMB(na, slot, &paddr);
+
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_TX);
+		}
+		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 out:
 
@@ -246,7 +259,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->wb.upper.length);
 			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -278,6 +291,8 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (slot->flags & NS_BUF_CHANGED) {
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			curr->read.pkt_addr = htole64(paddr);
 			curr->read.hdr_addr = 0;
 			nm_i = nm_next(nm_i, lim);
diff --git a/LINUX/if_vmxnet3_netmap.h b/LINUX/if_vmxnet3_netmap.h
index f3053598a..dd70dc6d8 100644
--- a/LINUX/if_vmxnet3_netmap.h
+++ b/LINUX/if_vmxnet3_netmap.h
@@ -172,7 +172,7 @@ static int vmxnet3_netmap_txsync(struct netmap_kring *kring, int flags)
 			void *packet_addr = PNMB(na, slot, &dma_addr);
 
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
-			netmap_sync_map(na, (bus_dma_tag_t)na->pdev, &dma_addr,
+			netmap_sync_map_dev(na, (bus_dma_tag_t)na->pdev, &dma_addr,
 					packet_len, NR_TX);
 
 			spin_lock_irqsave(&tq->tx_lock, lock_flags);
@@ -454,7 +454,7 @@ static int vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 				slot->flags = 0;
 
 				PNMB(na, slot, &dma_addr);
-				netmap_sync_map(na, (bus_dma_tag_t)na->pdev,
+				netmap_sync_map_cpu(na, (bus_dma_tag_t)na->pdev,
 						&dma_addr, slot->len, NR_RX);
 
 				num_pkts++;
@@ -522,6 +522,9 @@ static int vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			slot->flags &= ~NS_BUF_CHANGED;
 
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
+
 			nm_i = nm_next(nm_i, lim);
 		}
 		kring->nr_hwcur = head;
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index e3e6d2c6d..5d9dba7e9 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -275,6 +275,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int nic_i;	/* index into the NIC ring */
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
+	u_int tosync;
 	/*
 	 * interrupts on every tx packet are expensive so request
 	 * them every half ring, or where NS_REPORT is set
@@ -351,7 +352,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 
 				first->read.buffer_addr = htole64(paddr);
 				first->read.cmd_type_len = htole32(len | hw_flags);
-				netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
+				netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 						&paddr, len, NR_TX);
 				/* avoid setting the FCS flag in the
 				 * descriptors after the first, for safety
@@ -382,7 +383,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 					curr->read.olinfo_status = 0;
 					curr->read.cmd_type_len = htole32(len | hw_flags);
 
-					netmap_sync_map(na, (bus_dma_tag_t) na->pdev,
+					netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 							&paddr, len, NR_TX);
 				}
 				first->read.olinfo_status =
@@ -402,7 +403,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			curr->read.buffer_addr = htole64(paddr);
 			curr->read.olinfo_status = htole32(totlen << IXGBE_ADVTXD_PAYLEN_SHIFT);
 			curr->read.cmd_type_len = htole32(len | hw_flags);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -416,12 +417,14 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
+	tosync = nm_next(kring->nr_hwtail, lim);
 #ifndef NM_IXGBE_USE_TDH
 	(void)reclaim_tx;
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
-		u32 h = NM_ACCESS_ONCE(*ina->heads[ring_nr].phead);
+		nic_i = NM_ACCESS_ONCE(*ina->heads[ring_nr].phead);
+		nm_i = netmap_idx_n2k(kring, nic_i);
 		ND(5, "%s: h %d", kring->name, h);
-		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, h), lim);
+		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 #else /* NM_IXGBE_USE_TDH */
 	/*
@@ -468,11 +471,22 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			D("TDH wrap %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
+		nm_i = netmap_idx_n2k(kring, nic_i);
 		txr->next_to_clean = nic_i;
 		txr->next_to_use = txr->next_to_clean;
-		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 #endif /* NM_IXGBE_USE_TDH */
+	/* sync all buffers that we are returning to userspace.
+	 */
+	for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+		struct netmap_slot *slot = &ring->slot[tosync];
+		uint64_t paddr;
+		(void)PNMB(na, slot, &paddr);
+
+		netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+				&paddr, slot->len, NR_TX);
+	}
 out:
 
 	return 0;
@@ -553,7 +567,8 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			slot->len = size;
 			slot->flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			PNMB(na, slot, &paddr);
-			netmap_sync_map(na, (bus_dma_tag_t) na->pdev, &paddr, size, NR_RX);
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, size, NR_RX);
 
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -592,6 +607,8 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (slot->flags & NS_BUF_CHANGED) {
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			curr->wb.upper.length = 0;
 			curr->wb.upper.status_error = 0;
 			curr->read.pkt_addr = htole64(paddr);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7d1134d5e..39174ad46 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1751,16 +1751,22 @@ netmap_unload_map(struct netmap_adapter *na,
 }
 
 static inline void
-netmap_sync_map(struct netmap_adapter *na,
+netmap_sync_map_cpu(struct netmap_adapter *na,
 	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz, enum txrx t)
 {
 	if (*map) {
-		if (t == NR_RX)
-			dma_sync_single_for_cpu(na->pdev, *map, sz,
-					DMA_FROM_DEVICE);
-		else
-			dma_sync_single_for_device(na->pdev, *map, sz,
-					DMA_TO_DEVICE);
+		dma_sync_single_for_cpu(na->pdev, *map, sz,
+			(t == NR_TX ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+	}
+}
+
+static inline void
+netmap_sync_map_dev(struct netmap_adapter *na,
+	bus_dma_tag_t tag, bus_dmamap_t map, u_int sz, enum txrx t)
+{
+	if (*map) {
+		dma_sync_single_for_device(na->pdev, *map, sz,
+			(t == NR_TX ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
 	}
 }
 

From 8962f0137732529dbcd3120909f101212bbe2804 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 16 May 2018 18:06:03 +0200
Subject: [PATCH 0877/2207] bwrap: swap RX/TX when passing down kring pending
 mode

---
 sys/dev/netmap/netmap_vale.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index ac04e2b29..bb126567d 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2709,7 +2709,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 	/* pass down the pending ring state information */
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++)
-			NMR(hwna, t)[i]->nr_pending_mode =
+			NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode =
 				NMR(na, t)[i]->nr_pending_mode;
 	}
 
@@ -2721,7 +2721,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 	/* copy up the current ring state information */
 	for_rx_tx(t) {
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = NMR(hwna, t)[i];
+			struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i];
 			NMR(na, t)[i]->nr_mode = kring->nr_mode;
 		}
 	}

From 7ad073deadf1227908d2b3f64336c844ea9e9939 Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Fri, 4 May 2018 15:00:25 +0100
Subject: [PATCH 0878/2207] netmap_linux: set mbuf protocol based on ethertype
 and reset ip_summed

---
 LINUX/netmap_linux.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index f8128d881..8279a3968 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -920,6 +920,9 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 	return 0;
 }
 
+/* Used to cover cases where ETH_P_802_3_MIN is undefined */
+#define NM_ETH_P_802_3_MIN 0x0600
+
 /* Transmit routine used by generic_netmap_txsync(). Returns 0 on success
    and -1 on error (which may be packet drops or other errors). */
 int
@@ -929,6 +932,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	struct ifnet *ifp = a->ifp;
 	u_int len = a->len;
 	netdev_tx_t ret;
+	uint16_t ethertype;
 
 	/* We know that the driver needs to prepend ifp->needed_headroom bytes
 	 * to each packet to be transmitted. We then reset the mbuf pointers
@@ -947,19 +951,28 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	skb_reset_tail_pointer(m);
 	skb_reset_mac_header(m);
 
-	/* Initialize the header pointers assuming this is an IPv4 packet.
-	 * This is useful to make netmap interact well with TC when
-	 * netmap_generic_txqdisc == 0.  */
-	skb_set_network_header(m, 14);
-	skb_set_transport_header(m, 34);
-	m->protocol = htons(ETH_P_IP);
-	m->pkt_type = PACKET_HOST;
-
 	/* Copy a netmap buffer into the mbuf.
 	 * TODO Support the slot flags (NS_MOREFRAG, NS_INDIRECT). */
 	skb_copy_to_linear_data(m, a->addr, len); // skb_store_bits(m, 0, addr, len);
 	skb_put(m, len);
 
+	/* Initialize the header pointers assuming this is an IP packet.
+	 * This is useful to make netmap interact well with TC when
+	 * netmap_generic_txqdisc == 0.  */
+	skb_set_network_header(m, ETH_HLEN);
+	ethertype = *((uint16_t*)(m->data + ETH_ALEN * 2));
+	m->protocol = ntohs(ethertype) >= NM_ETH_P_802_3_MIN ? ethertype : htons(ETH_P_802_3);
+	m->pkt_type = PACKET_HOST;
+	m->ip_summed = CHECKSUM_NONE;
+
+	if (m->protocol == htons(ETH_P_IPV6)) {
+		skb_set_transport_header(m, ETH_HLEN + sizeof(struct nm_ipv6hdr));
+	} else if (m->protocol == htons(ETH_P_IP)) {
+		skb_set_transport_header(m, ETH_HLEN + sizeof(struct nm_iphdr));
+	} else {
+		skb_reset_transport_header(m);
+	}
+
 	/* Hold a reference on this, we are going to recycle mbufs as
 	 * much as possible. */
 #ifdef NETMAP_LINUX_HAVE_REFCOUNT_T

From d565acf8853dedb0f127cb161bf21b0428fb4c6a Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Fri, 4 May 2018 15:01:23 +0100
Subject: [PATCH 0879/2207] checksums: add checksum offload option for use with
 unmodified drivers

---
 LINUX/netmap_linux.c         | 22 ++++++++++++++++++++++
 sys/dev/netmap/netmap.c      | 14 +++++++++++---
 sys/dev/netmap/netmap_kern.h |  1 +
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 8279a3968..359711d49 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -33,6 +33,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -989,6 +990,27 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	m->dev = ifp;
 	skb_shinfo(m)->destructor_arg = m->dev;
 
+	/* Tell the NIC to compute checksums for outgoing TCP and UDP packets */
+	if (netmap_generic_hwcsum) {
+		uint8_t transport_proto = IPPROTO_IP;
+
+		if (m->protocol == htons(ETH_P_IPV6)) {
+			transport_proto = ((struct nm_ipv6hdr*)ip_hdr(m))->nexthdr;
+		} else if (m->protocol == htons(ETH_P_IP)) {
+			transport_proto = ((struct nm_iphdr*)ip_hdr(m))->protocol;
+		}
+
+		if (transport_proto == IPPROTO_TCP) {
+			m->ip_summed = CHECKSUM_PARTIAL;
+			m->csum_start = m->transport_header;
+			m->csum_offset = 16; /* offset to TCP checksum within TCP header */
+		} else if (transport_proto == IPPROTO_UDP) {
+			m->ip_summed = CHECKSUM_PARTIAL;
+			m->csum_start = m->transport_header;
+			m->csum_offset = 6; /* offset to UDP checksum within UDP header */
+		}
+	}
+
 	/* Tell generic_ndo_start_xmit() to pass this mbuf to the driver. */
 	skb_set_queue_mapping(m, a->ring_nr);
 	m->priority = a->qevent ? NM_MAGIC_PRIORITY_TXQE : NM_MAGIC_PRIORITY_TX;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a753f548d..7396eb1ca 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -519,6 +519,9 @@ int netmap_generic_txqdisc = 1;
 int netmap_generic_ringsize = 1024;
 int netmap_generic_rings = 1;
 
+/* Non-zero to enable checksum offloading in NIC drivers */
+int netmap_generic_hwcsum = 0;
+
 /* Non-zero if ptnet devices are allowed to use virtio-net headers. */
 int ptnet_vnet_hdr = 1;
 
@@ -547,6 +550,9 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0,
 SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0,
 		"Adapter mode. 0 selects the best option available,"
 		"1 forces native adapter, 2 forces emulated adapter");
+SYSCTL_INT(_dev_netmap, OID_AUTO, generic_hwcsum, CTLFLAG_RW, &netmap_generic_hwcsum,
+		0, "Hardware checksums. 0 to disable checksum generation by the NIC (default),"
+		"1 to enable checksum generation by the NIC");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit,
 		0, "RX notification interval in nanoseconds");
 SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW,
@@ -3637,9 +3643,11 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 		goto done;
 	}
 
-	if (nm_os_mbuf_has_offld(m)) {
-		RD(1, "%s drop mbuf that needs offloadings", na->name);
-		goto done;
+	if (!netmap_generic_hwcsum) {
+		if (nm_os_mbuf_has_offld(m)) {
+			RD(1, "%s drop mbuf that needs offloadings", na->name);
+			goto done;
+		}
 	}
 
 	/* protect against netmap_rxsync_from_host(), netmap_sw_to_nic()
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 39174ad46..c8683ae2b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1609,6 +1609,7 @@ enum {                                  /* verbose flags */
 
 extern int netmap_txsync_retry;
 extern int netmap_flags;
+extern int netmap_generic_hwcsum;
 extern int netmap_generic_mit;
 extern int netmap_generic_ringsize;
 extern int netmap_generic_rings;

From 7575d8af98839d99e492d9564037410d330d414d Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Tue, 15 May 2018 09:12:04 +0100
Subject: [PATCH 0880/2207] offloading: split mbuf check into two for
 segmentation and checksums

---
 LINUX/netmap_linux.c            | 10 ++++++++--
 WINDOWS/netmap_windows.c        |  8 +++++++-
 sys/dev/netmap/netmap.c         |  9 +++++++--
 sys/dev/netmap/netmap_freebsd.c | 10 ++++++++--
 sys/dev/netmap/netmap_kern.h    |  3 ++-
 5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 359711d49..0bc8e42f2 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -408,9 +408,15 @@ nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev)
 }
 
 int
-nm_os_mbuf_has_offld(struct mbuf *m)
+nm_os_mbuf_has_csum_offld(struct mbuf *m)
 {
-	return m->ip_summed == CHECKSUM_PARTIAL || skb_is_gso(m);
+	return m->ip_summed == CHECKSUM_PARTIAL;
+}
+
+int
+nm_os_mbuf_has_seg_offld(struct mbuf *m)
+{
+	return skb_is_gso(m);
 }
 
 #ifdef WITH_GENERIC
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 42d66a7d6..3c794eab1 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -1017,7 +1017,13 @@ nm_os_ncpus(void)
 }
 
 int
-nm_os_mbuf_has_offld(struct mbuf *m)
+nm_os_mbuf_has_csum_offld(struct mbuf *m)
+{
+	return 0;  // TODO
+}
+
+int
+nm_os_mbuf_has_seg_offld(struct mbuf *m)
 {
 	return 0;  // TODO
 }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7396eb1ca..64b61f2cf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3644,12 +3644,17 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	}
 
 	if (!netmap_generic_hwcsum) {
-		if (nm_os_mbuf_has_offld(m)) {
-			RD(1, "%s drop mbuf that needs offloadings", na->name);
+		if (nm_os_mbuf_has_csum_offld(m)) {
+			RD(1, "%s drop mbuf that needs checksum offload", na->name);
 			goto done;
 		}
 	}
 
+	if (nm_os_mbuf_has_seg_offld(m)) {
+		RD(1, "%s drop mbuf that needs generic segmentation offload", na->name);
+		goto done;
+	}
+
 	/* protect against netmap_rxsync_from_host(), netmap_sw_to_nic()
 	 * and maybe other instances of netmap_transmit (the latter
 	 * not possible on Linux).
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index aa483f00c..d4b8795c0 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -268,11 +268,17 @@ nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev)
 }
 
 int
-nm_os_mbuf_has_offld(struct mbuf *m)
+nm_os_mbuf_has_csum_offld(struct mbuf *m)
 {
 	return m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_SCTP |
 					 CSUM_TCP_IPV6 | CSUM_UDP_IPV6 |
-					 CSUM_SCTP_IPV6 | CSUM_TSO);
+					 CSUM_SCTP_IPV6);
+}
+
+int
+nm_os_mbuf_has_seg_offld(struct mbuf *m)
+{
+	return m->m_pkthdr.csum_flags & CSUM_TSO;
 }
 
 static void
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c8683ae2b..f495f9f41 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -311,7 +311,8 @@ void nm_os_vfree(void *);
  */
 void *nm_os_send_up(struct ifnet *, struct mbuf *m, struct mbuf *prev);
 
-int nm_os_mbuf_has_offld(struct mbuf *m);
+int nm_os_mbuf_has_seg_offld(struct mbuf *m);
+int nm_os_mbuf_has_csum_offld(struct mbuf *m);
 
 #include "netmap_mbq.h"
 

From ae1e9c80e5f75eb803d86fddc06a20509f224eb9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 12:02:56 +0200
Subject: [PATCH 0881/2207] linux/e1000e: patch for Intel 3.4.1.1 version

---
 LINUX/final-patches/intel--e1000e--3.4.1.1 | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.4.1.1

diff --git a/LINUX/final-patches/intel--e1000e--3.4.1.1 b/LINUX/final-patches/intel--e1000e--3.4.1.1
new file mode 100644
index 000000000..e99a7e090
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.4.1.1
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index 9bfa024..2c106f0 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -36,7 +36,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -139,7 +139,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -345,6 +345,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index 09c8487..fd3c723 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -500,6 +500,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1023,6 +1027,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1340,6 +1355,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4256,6 +4276,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8456,6 +8480,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8557,6 +8585,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 0da480dd17f897eeb50bc7744572a56b6c64856d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 14:50:36 +0200
Subject: [PATCH 0882/2207] nm_inject: support NS_MOREFRAG

---
 sys/net/netmap_user.h | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index e12b19de7..96ed19645 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1027,20 +1027,35 @@ nm_inject(struct nm_desc *d, const void *buf, size_t size)
 	for (c = 0; c < n ; c++, ri++) {
 		/* compute current ring to use */
 		struct netmap_ring *ring;
-		uint32_t i, idx;
+		uint32_t i, j, idx;
+		size_t rem;
 
 		if (ri > d->last_tx_ring)
 			ri = d->first_tx_ring;
 		ring = NETMAP_TXRING(d->nifp, ri);
-		if (nm_ring_empty(ring)) {
-			continue;
+		rem = size;
+		j = ring->cur;
+		while (rem > ring->nr_buf_size && j != ring->tail) {
+			rem -= ring->nr_buf_size;
+			j = nm_ring_next(ring, j);
 		}
+		if (j == ring->tail && rem > 0)
+			continue;
 		i = ring->cur;
+		while (i != j) {
+			idx = ring->slot[i].buf_idx;
+			ring->slot[i].len = ring->nr_buf_size;
+			ring->slot[i].flags = NS_MOREFRAG;
+			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
+			i = nm_ring_next(ring, i);
+			buf += ring->nr_buf_size;
+		}
 		idx = ring->slot[i].buf_idx;
-		ring->slot[i].len = size;
-		nm_pkt_copy(buf, NETMAP_BUF(ring, idx), size);
-		d->cur_tx_ring = ri;
+		ring->slot[i].len = rem;
+		ring->slot[i].flags = 0;
+		nm_pkt_copy(buf, NETMAP_BUF(ring, idx), rem);
 		ring->head = ring->cur = nm_ring_next(ring, i);
+		d->cur_tx_ring = ri;
 		return size;
 	}
 	return 0; /* fail */

From c0ae72b965da40c44ed63ffa2725907e5f03c691 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 15:15:18 +0200
Subject: [PATCH 0883/2207] pipe: slightly faster tx

---
 sys/dev/netmap/netmap_pipe.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index ed57ceed3..b47e25d91 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -205,12 +205,8 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 		struct netmap_slot *rs = &rxring->slot[k];
 		struct netmap_slot *ts = &txring->slot[k];
 
-		rs->len = ts->len;
-		rs->flags = ts->flags;
-		rs->ptr = ts->ptr;
-
+		*rs = *ts;
 		if (ts->flags & NS_BUF_CHANGED) {
-			rs->buf_idx = ts->buf_idx;
 			ts->flags &= ~NS_BUF_CHANGED;
 		}
 	}

From cecb90d9a0cb4ae0f6003de7769617490f5c281d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 15:42:14 +0200
Subject: [PATCH 0884/2207] pipe: support NS_MOREFRAG

---
 sys/dev/netmap/netmap_pipe.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index b47e25d91..1f044217a 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -183,8 +183,9 @@ int
 netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 {
 	struct netmap_kring *rxkring = txkring->pipe;
-	u_int k, lim = txkring->nkr_num_slots - 1;
+	u_int k, lim = txkring->nkr_num_slots - 1, nk;
 	int m; /* slots to transfer */
+	int complete; /* did we see a complete packet ? */
 	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
 	ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
@@ -201,7 +202,8 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 		return 0;
 	}
 
-	for (k = txkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
+	for (k = txkring->nr_hwcur, nk = lim + 1, complete = 0; m;
+			m--, k = nm_next(k, lim), nk = (complete ? k : nk)) {
 		struct netmap_slot *rs = &rxring->slot[k];
 		struct netmap_slot *ts = &txring->slot[k];
 
@@ -209,17 +211,20 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 		if (ts->flags & NS_BUF_CHANGED) {
 			ts->flags &= ~NS_BUF_CHANGED;
 		}
+		complete = !(ts->flags & NS_MOREFRAG);
 	}
 
-	mb(); /* make sure the slots are updated before publishing them */
-	rxkring->nr_hwtail = k;
 	txkring->nr_hwcur = k;
 
 	ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
 		txkring->nr_hwcur, txkring->nr_hwtail,
 		txkring->rcur, txkring->rhead, txkring->rtail, k);
 
-	rxkring->nm_notify(rxkring, 0);
+	if (likely(nk <= lim)) {
+		mb(); /* make sure the slots are updated before publishing them */
+		rxkring->nr_hwtail = nk; /* only publish complete packets */
+		rxkring->nm_notify(rxkring, 0);
+	}
 
 	return 0;
 }

From 88db7a1d02a3473b84dc45f67252a007cce81fa2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 11:57:24 -0400
Subject: [PATCH 0885/2207] linux/config: check for redhat change_mtu

---
 LINUX/configure         | 10 ++++++++++
 LINUX/netmap_linux.c    |  2 +-
 sys/dev/netmap/netmap.c |  2 +-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 67f20c1ec..523185ada 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1451,6 +1451,16 @@ EOF
 	}
 EOF
 
+# check for redhat ndo_change_mtu_rh74
+  add_test 'define CHANGE_MTU ndo_change_mtu_rh74' 'define CHANGE_MTU ndo_change_mtu' <
+
+	int
+	dummy(struct net_device_ops *ops, struct net_device *dev) {
+		return ops->ndo_change_mtu_rh74(dev, 0);
+	}
+EOF
+
 # check for fault arguments
   add_test 'have FAULT_VMA_ARG' <
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0bc8e42f2..58d3097a1 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2469,7 +2469,7 @@ static const struct net_device_ops nm_vi_ops = {
 	.ndo_stop = linux_nm_vi_stop,
 	.ndo_start_xmit = linux_nm_vi_xmit,
 	.ndo_set_mac_address = eth_mac_addr,
-	.ndo_change_mtu = linux_nm_vi_change_mtu,
+	.NETMAP_LINUX_CHANGE_MTU = linux_nm_vi_change_mtu,
 #ifdef NETMAP_LINUX_HAVE_GET_STATS64
 	.ndo_get_stats64 = linux_nm_vi_get_stats,
 #endif
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 64b61f2cf..6ac2c20eb 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3470,7 +3470,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 #endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
 	}
 	hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit;
-	hwna->nm_ndo.ndo_change_mtu = linux_netmap_change_mtu;
+	hwna->nm_ndo.NETMAP_LINUX_CHANGE_MTU = linux_netmap_change_mtu;
 	if (ifp->ethtool_ops) {
 		hwna->nm_eto = *ifp->ethtool_ops;
 	}

From cbad1b022c08b5d0adc16c4dc66cf1aedce34cbf Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 27 Dec 2017 17:14:11 +0900
Subject: [PATCH 0886/2207] multiple host queue

Internal mechanism only, defaulting to 1.
---
 sys/dev/netmap/netmap.c      | 28 ++++++++++++++-------
 sys/dev/netmap/netmap_kern.h | 29 ++++++++++++++++++++--
 sys/dev/netmap/netmap_mem2.c | 10 ++++----
 sys/dev/netmap/netmap_vale.c | 48 ++++++++++++++++++++++--------------
 4 files changed, 80 insertions(+), 35 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a753f548d..e83e4fdb6 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -825,8 +825,8 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	}
 
 	/* account for the (possibly fake) host rings */
-	n[NR_TX] = na->num_tx_rings + 1;
-	n[NR_RX] = na->num_rx_rings + 1;
+	n[NR_TX] = netmap_all_rings(na, NR_TX);
+	n[NR_RX] = netmap_all_rings(na, NR_RX);
 
 	len = (n[NR_TX] + n[NR_RX]) *
 		(sizeof(struct netmap_kring) + sizeof(struct netmap_kring *))
@@ -928,11 +928,14 @@ netmap_krings_delete(struct netmap_adapter *na)
 void
 netmap_hw_krings_delete(struct netmap_adapter *na)
 {
-	struct mbq *q = &na->rx_rings[na->num_rx_rings]->rx_queue;
+	u_int lim = netmap_real_rings(na, NR_RX), i;
 
-	ND("destroy sw mbq with len %d", mbq_len(q));
-	mbq_purge(q);
-	mbq_safe_fini(q);
+	for (i = nma_get_nrings(na, NR_RX); i < lim; i++) {
+		struct mbq *q = &NMR(na, NR_RX)[i]->rx_queue;
+		ND("destroy sw mbq with len %d", mbq_len(q));
+		mbq_purge(q);
+		mbq_safe_fini(q);
+	}
 	netmap_krings_delete(na);
 }
 
@@ -1825,7 +1828,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 			}
 			priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
 				nma_get_nrings(na, t) : 0);
-			priv->np_qlast[t] = nma_get_nrings(na, t) + 1;
+			priv->np_qlast[t] = netmap_all_rings(na, t);
 			ND("%s: %s %d %d", nr_mode == NR_REG_SW ? "SW" : "NIC+SW",
 				nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
@@ -3441,6 +3444,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		goto fail;
 	hwna->up = *arg;
 	hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE;
+	hwna->up.num_host_tx_rings = hwna->up.num_host_rx_rings = 1;
 	strncpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name));
 	if (override_reg) {
 		hwna->nm_hw_register = hwna->up.nm_register;
@@ -3543,7 +3547,10 @@ netmap_hw_krings_create(struct netmap_adapter *na)
 	int ret = netmap_krings_create(na, 0);
 	if (ret == 0) {
 		/* initialize the mbq for the sw rx ring */
-		mbq_safe_init(&na->rx_rings[na->num_rx_rings]->rx_queue);
+		u_int lim = netmap_real_rings(na, NR_RX), i;
+		for (i = na->num_rx_rings; i < lim; i++) {
+			mbq_safe_init(&NMR(na, NR_RX)[i]->rx_queue);
+		}
 		ND("initialized sw rx queue %d", na->num_rx_rings);
 	}
 	return ret;
@@ -3606,8 +3613,11 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	unsigned int txr;
 	struct mbq *q;
 	int busy;
+	u_int i;
+
+	i = MBUF_TXQ(m);
+	kring = NMR(na, NR_RX)[nma_get_nrings(na, NR_RX) + i];
 
-	kring = na->rx_rings[na->num_rx_rings];
 	// XXX [Linux] we do not need this lock
 	// if we follow the down/configure/up protocol -gl
 	// mtx_lock(&na->core_lock);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7d1134d5e..0baa34550 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -694,6 +694,8 @@ struct netmap_adapter {
 
 	u_int num_rx_rings; /* number of adapter receive rings */
 	u_int num_tx_rings; /* number of adapter transmit rings */
+	u_int num_host_rx_rings; /* number of host receive rings */
+	u_int num_host_tx_rings; /* number of host transmit rings */
 
 	u_int num_tx_desc;  /* number of descriptor in each queue */
 	u_int num_rx_desc;
@@ -864,6 +866,12 @@ nma_get_nrings(struct netmap_adapter *na, enum txrx t)
 	return (t == NR_TX ? na->num_tx_rings : na->num_rx_rings);
 }
 
+static __inline u_int
+nma_get_host_nrings(struct netmap_adapter *na, enum txrx t)
+{
+	return (t == NR_TX ? na->num_host_tx_rings : na->num_host_rx_rings);
+}
+
 static __inline void
 nma_set_nrings(struct netmap_adapter *na, enum txrx t, u_int v)
 {
@@ -873,6 +881,15 @@ nma_set_nrings(struct netmap_adapter *na, enum txrx t, u_int v)
 		na->num_rx_rings = v;
 }
 
+static __inline void
+nma_set_host_nrings(struct netmap_adapter *na, enum txrx t, u_int v)
+{
+	if (t == NR_TX)
+		na->num_host_tx_rings = v;
+	else
+		na->num_host_rx_rings = v;
+}
+
 static __inline struct netmap_kring**
 NMR(struct netmap_adapter *na, enum txrx t)
 {
@@ -962,10 +979,18 @@ struct netmap_generic_adapter {	/* emulated device */
 };
 #endif  /* WITH_GENERIC */
 
-static __inline int
+static __inline u_int
 netmap_real_rings(struct netmap_adapter *na, enum txrx t)
 {
-	return nma_get_nrings(na, t) + !!(na->na_flags & NAF_HOST_RINGS);
+	return nma_get_nrings(na, t) +
+		!!(na->na_flags & NAF_HOST_RINGS) * nma_get_host_nrings(na, t);
+}
+
+/* account for fake rings */
+static __inline u_int
+netmap_all_rings(struct netmap_adapter *na, enum txrx t)
+{
+	return max(nma_get_nrings(na, t) + 1, netmap_real_rings(na, t));
 }
 
 #ifdef WITH_VALE
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8e1b68884..32555af16 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1843,7 +1843,7 @@ netmap_free_rings(struct netmap_adapter *na)
 
 	for_rx_tx(t) {
 		u_int i;
-		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
 			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_ring *ring = kring->ring;
 
@@ -1882,7 +1882,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 	for_rx_tx(t) {
 		u_int i;
 
-		for (i = 0; i <= nma_get_nrings(na, t); i++) {
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
 			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_ring *ring = kring->ring;
 			u_int len, ndesc;
@@ -1978,7 +1978,7 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	ntot = 0;
 	for_rx_tx(t) {
 		/* account for the (eventually fake) host rings */
-		n[t] = nma_get_nrings(na, t) + 1;
+		n[t] = netmap_all_rings(na, t);
 		ntot += n[t];
 	}
 	/*
@@ -2652,14 +2652,14 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 
 	/* point each kring to the corresponding backend ring */
 	nifp = (struct netmap_if *)((char *)ptnmd->nm_addr + ptif->nifp_offset);
-	for (i = 0; i <= na->num_tx_rings; i++) {
+	for (i = 0; i < netmap_all_rings(na, NR_TX); i++) {
 		struct netmap_kring *kring = na->tx_rings[i];
 		if (kring->ring)
 			continue;
 		kring->ring = (struct netmap_ring *)
 			((char *)nifp + nifp->ring_ofs[i]);
 	}
-	for (i = 0; i <= na->num_rx_rings; i++) {
+	for (i = 0; i < netmap_all_rings(na, NR_RX); i++) {
 		struct netmap_kring *kring = na->rx_rings[i];
 		if (kring->ring)
 			continue;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index ac04e2b29..94e68dcd7 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -79,6 +79,7 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #include 	/* bus_dmamap_* */
 #include 
 #include 
+#include 
 
 
 #define BDG_RWLOCK_T		struct rwlock // struct rwlock
@@ -2708,9 +2709,10 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 
 	/* pass down the pending ring state information */
 	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(na, t) + 1; i++)
-			NMR(hwna, t)[i]->nr_pending_mode =
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
+			NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode =
 				NMR(na, t)[i]->nr_pending_mode;
+		}
 	}
 
 	/* forward the request to the hwna */
@@ -2720,8 +2722,8 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 
 	/* copy up the current ring state information */
 	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
-			struct netmap_kring *kring = NMR(hwna, t)[i];
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
+			struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i];
 			NMR(na, t)[i]->nr_mode = kring->nr_mode;
 		}
 	}
@@ -2740,10 +2742,15 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		}
 		i = hwna->num_rx_rings; /* for safety */
 		/* save the host ring notify unconditionally */
-		hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
-		if (hostna->na_bdg) {
-			/* also intercept the host ring notify */
-			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
+		for (; i < netmap_real_rings(hwna, NR_RX); i++) {
+			hwna->rx_rings[i]->save_notify =
+				hwna->rx_rings[i]->nm_notify;
+			if (hostna->na_bdg) {
+				/* also intercept the host ring notify */
+				hwna->rx_rings[i]->nm_notify =
+					netmap_bwrap_intr_notify;
+				na->tx_rings[i]->nm_sync = na->nm_txsync;
+			}
 		}
 		if (na->active_fds == 0)
 			na->na_flags |= NAF_NETMAP_ON;
@@ -2754,8 +2761,9 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 			na->na_flags &= ~NAF_NETMAP_ON;
 
 		/* reset all notify callbacks (including host ring) */
-		for (i = 0; i <= hwna->num_rx_rings; i++) {
-			hwna->rx_rings[i]->nm_notify = hwna->rx_rings[i]->save_notify;
+		for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) {
+			hwna->rx_rings[i]->nm_notify =
+				hwna->rx_rings[i]->save_notify;
 			hwna->rx_rings[i]->save_notify = NULL;
 		}
 		hwna->na_lut.lut = NULL;
@@ -2765,7 +2773,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 
 		/* pass ownership of the netmap rings to the hwna */
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < netmap_all_rings(na, t); i++) {
 				NMR(na, t)[i]->ring = NULL;
 			}
 		}
@@ -2813,8 +2821,6 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	int i, error = 0;
 	enum txrx t;
 
-	ND("%s", na->name);
-
 	/* impersonate a netmap_vp_adapter */
 	error = netmap_vp_krings_create(na);
 	if (error)
@@ -2827,8 +2833,8 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	}
 
 	/* increment the usage counter for all the hwna krings */
-	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
+        for_rx_tx(t) {
+                for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users++;
 		}
 	}
@@ -2845,7 +2851,7 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	 */
 	for_rx_tx(t) {
 		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-		for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) {
+		for (i = 0; i < netmap_all_rings(hwna, r); i++) {
 			NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
 			NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
 		}
@@ -2857,9 +2863,12 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 		 * hostna
 		 */
 		hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
-		hostna->tx_rings[0]->na = hostna;
 		hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
-		hostna->rx_rings[0]->na = hostna;
+		for_rx_tx(t) {
+			for (i = 0; i < nma_get_nrings(hostna, t); i++) {
+				NMR(hostna, t)[i]->na = hostna;
+			}
+		}
 	}
 
 	return 0;
@@ -2889,7 +2898,7 @@ netmap_bwrap_krings_delete(struct netmap_adapter *na)
 
 	/* decrement the usage counter for all the hwna krings */
 	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(hwna, t) + 1; i++) {
+		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users--;
 		}
 	}
@@ -3081,6 +3090,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		for_rx_tx(t) {
 			enum txrx r = nm_txrx_swap(t);
 			nma_set_nrings(hostna, t, 1);
+			nma_set_host_nrings(na, t, 1);
 			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
 		}
 		// hostna->nm_txsync = netmap_bwrap_host_txsync;

From 788b63d6ec075227ba4fc6166f5bc98a33830e92 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Sun, 25 Mar 2018 16:41:33 +0200
Subject: [PATCH 0887/2207] Export mbuf routines

Note: nm_os_get_mbuf() is exported only for stack support in FreeBSD.
Linux variant uses build_skb().
---
 sys/dev/netmap/netmap_kern.h | 113 +++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0baa34550..dc5124811 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2244,6 +2244,119 @@ void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
 #endif /* WITH_PTNETMAP_GUEST */
 
+#ifdef __FreeBSD__
+/*
+ * FreeBSD mbuf allocator/deallocator in emulation mode:
+ */
+#if __FreeBSD_version < 1100000
+
+/*
+ * For older versions of FreeBSD:
+ *
+ * We allocate EXT_PACKET mbuf+clusters, but need to set M_NOFREE
+ * so that the destructor, if invoked, will not free the packet.
+ * In principle we should set the destructor only on demand,
+ * but since there might be a race we better do it on allocation.
+ * As a consequence, we also need to set the destructor or we
+ * would leak buffers.
+ */
+
+/* mbuf destructor, also need to change the type to EXT_EXTREF,
+ * add an M_NOFREE flag, and then clear the flag and
+ * chain into uma_zfree(zone_pack, mf)
+ * (or reinstall the buffer ?)
+ */
+#define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
+	(m)->m_ext.ext_free = (void *)fn;	\
+	(m)->m_ext.ext_type = EXT_EXTREF;	\
+} while (0)
+
+static int
+void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2)
+{
+	/* restore original mbuf */
+	m->m_ext.ext_buf = m->m_data = m->m_ext.ext_arg1;
+	m->m_ext.ext_arg1 = NULL;
+	m->m_ext.ext_type = EXT_PACKET;
+	m->m_ext.ext_free = NULL;
+	if (MBUF_REFCNT(m) == 0)
+		SET_MBUF_REFCNT(m, 1);
+	uma_zfree(zone_pack, m);
+
+	return 0;
+}
+
+static inline struct mbuf *
+nm_os_get_mbuf(struct ifnet *ifp, int len)
+{
+	struct mbuf *m;
+
+	(void)ifp;
+	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (m) {
+		/* m_getcl() (mb_ctor_mbuf) has an assert that checks that
+		 * M_NOFREE flag is not specified as third argument,
+		 * so we have to set M_NOFREE after m_getcl(). */
+		m->m_flags |= M_NOFREE;
+		m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save
+		m->m_ext.ext_free = (void *)void_mbuf_dtor;
+		m->m_ext.ext_type = EXT_EXTREF;
+		ND(5, "create m %p refcnt %d", m, MBUF_REFCNT(m));
+	}
+	return m;
+}
+
+#else /* __FreeBSD_version >= 1100000 */
+
+/*
+ * Newer versions of FreeBSD, using a straightforward scheme.
+ *
+ * We allocate mbufs with m_gethdr(), since the mbuf header is needed
+ * by the driver. We also attach a customly-provided external storage,
+ * which in this case is a netmap buffer. When calling m_extadd(), however
+ * we pass a NULL address, since the real address (and length) will be
+ * filled in by nm_os_generic_xmit_frame() right before calling
+ * if_transmit().
+ *
+ * The dtor function does nothing, however we need it since mb_free_ext()
+ * has a KASSERT(), checking that the mbuf dtor function is not NULL.
+ */
+
+#if __FreeBSD_version <= 1200050
+static void void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { }
+#else  /* __FreeBSD_version >= 1200051 */
+/* The arg1 and arg2 pointers argument were removed by r324446, which
+ * in included since version 1200051. */
+static void void_mbuf_dtor(struct mbuf *m) { }
+#endif /* __FreeBSD_version >= 1200051 */
+
+#define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
+	(m)->m_ext.ext_free = (fn != NULL) ?		\
+	    (void *)fn : (void *)void_mbuf_dtor;	\
+} while (0)
+
+static inline struct mbuf *
+nm_os_get_mbuf(struct ifnet *ifp, int len)
+{
+	struct mbuf *m;
+
+	(void)ifp;
+	(void)len;
+
+	m = m_gethdr(M_NOWAIT, MT_DATA);
+	if (m == NULL) {
+		return m;
+	}
+
+	m_extadd(m, NULL /* buf */, 0 /* size */, void_mbuf_dtor,
+		 NULL, NULL, 0, EXT_NET_DRV);
+
+	return m;
+}
+
+#endif /* __FreeBSD_version >= 1100000 */
+#endif /* __FreeBSD__ */
+
 struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
 int nmreq_checkduplicate(struct nmreq_option *);
 

From eeade5e5e468d9382117404d2289c00dc342cf17 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 31 May 2018 15:44:37 +0200
Subject: [PATCH 0888/2207] avoid pointer arithmetic on void*

---
 apps/pkt-gen/pkt-gen.c | 6 +++---
 sys/net/netmap_user.h  | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 0355fa2e3..26157243a 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1234,7 +1234,7 @@ ping_body(void *data)
 	int rate_limit = targ->g->tx_rate, tosend = 0;
 
 	frame = &targ->pkt;
-	frame += sizeof(targ->pkt.vh) - targ->g->virt_header;
+	*((char **)frame) += sizeof(targ->pkt.vh) - targ->g->virt_header;
 	size = targ->g->pkt_size + targ->g->virt_header;
 
 
@@ -1509,7 +1509,7 @@ sender_body(void *data)
 
 	if (targ->frame == NULL) {
 		frame = pkt;
-		frame += sizeof(pkt->vh) - targ->g->virt_header;
+		*((char **)frame) += sizeof(pkt->vh) - targ->g->virt_header;
 		size = targ->g->pkt_size + targ->g->virt_header;
 	} else {
 		frame = targ->frame;
@@ -1862,7 +1862,7 @@ txseq_body(void *data)
 	}
 
 	frame = pkt;
-	frame += sizeof(pkt->vh) - targ->g->virt_header;
+	*((char **)frame) += sizeof(pkt->vh) - 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);
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 96ed19645..0cae62fdf 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1048,7 +1048,7 @@ nm_inject(struct nm_desc *d, const void *buf, size_t size)
 			ring->slot[i].flags = NS_MOREFRAG;
 			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
 			i = nm_ring_next(ring, i);
-			buf += ring->nr_buf_size;
+			*((char **)buf) += ring->nr_buf_size;
 		}
 		idx = ring->slot[i].buf_idx;
 		ring->slot[i].len = rem;

From ddb926b306a5075a63c21157c8ed1821e590a5f3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 14:51:57 +0200
Subject: [PATCH 0889/2207] linux/i40e: only expose complete packets on RX

---
 LINUX/i40e_netmap_linux.h | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 5d69b6ae7..90d95746d 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -477,6 +477,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 	struct netmap_ring *ring = kring->ring;
 	u_int nm_i;	/* index into the netmap ring */
 	u_int nic_i;	/* index into the NIC ring */
+	u_int ntail;	/* new tail for the user */
 	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
@@ -520,9 +521,13 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	if (netmap_no_pendintr || force_update) {
 		int crclen = ix_crcstrip ? 0 : 4;
+		int complete;
 
 		nic_i = rxr->next_to_clean; // or also k2n(kring->nr_hwtail)
 		nm_i = netmap_idx_n2k(kring, nic_i);
+		/* we advance tail only when we see a complete packet */
+		ntail = lim + 1;
+		complete = 0;
 
 		for (n = 0; ; n++) {
 			union i40e_rx_desc *curr = I40E_RX_DESC(rxr, nic_i);
@@ -533,6 +538,11 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot;
 			uint64_t paddr;
 
+			if (likely(complete)) {
+				ntail = nm_i;
+				complete = 0;
+			}
+
 			if ((staterr & (1<> I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - crclen;
 
 			if (unlikely((staterr & (1<flags = slot_flags;
 			PNMB(na, slot, &paddr);
@@ -558,7 +570,10 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 				ix_rx_miss_bufs += n;
 			}
 			rxr->next_to_clean = nic_i;
-			kring->nr_hwtail = nm_i;
+			if (likely(ntail <= lim)) {
+				kring->nr_hwtail = ntail;
+				ND("%s: nic_i %u nm_i %u ntail %u n %u", ifp->if_xname, nic_i, nm_i, ntail, n);
+			}
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}

From 7c1e71982e0ec2a46e0eb84fc5199684776b903d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 24 May 2018 07:57:38 +0200
Subject: [PATCH 0890/2207] linux: compile out dma-syncs when not-needed

---
 LINUX/configure              | 9 +++++++++
 sys/dev/netmap/netmap_kern.h | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 523185ada..deef12b1e 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -6,6 +6,7 @@ MODNAME=netmap
 DEBUG=1
 UTILS=
 DRVERRFAIL=
+DMASYNC=1
 
 # setelem2n  
 setelem2n()
@@ -328,6 +329,7 @@ Available options:
   --force-debug	       	       build the modules w/ debug symbols (default)
   --no-force-debug	       build the modules w/ or w/o debug symbols,
   --cache=		       dir for reusing/caching of netmap_linux_config.h
+  --without-dmasync	       use this if you are on x86 with a recent NIC and no IOMMU
 
   --cc=                        C compiler to be used for the apps and utils [$cc]
   --ld=                        linker to be used for the apps and utils [$ld]
@@ -653,6 +655,9 @@ for opt do
 	--fail-on-driver-errors)
 		DRVERRFAIL=1
 		;;
+	--without-dmasync)
+		DMASYNC=
+		;;
 	*)
 		echo "Unrecognized option: $opt" | warning
 	;;
@@ -1938,6 +1943,10 @@ EOF
   cat >> config.log <pdev, buf, sz,
 				DMA_BIDIRECTIONAL);
 }
+#else /* !NETMAP_LINUX_HAVE_DMASYNC */
+#define netmap_sync_map_cpu(na, tag, map, sz, t)
+#define netmap_sync_map_dev(na, tag, map, sz, t)
+#endif /* NETMAP_LINUX_HAVE_DMASYNC */
 
 #endif /* linux */
 

From 79bac01af30ed4e0376433fb05af19bb02dae2dd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 30 May 2018 07:56:57 -0400
Subject: [PATCH 0891/2207] functional: wait for tx completion before closing

---
 utils/functional.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/utils/functional.c b/utils/functional.c
index c8ecd3992..d69dbe33f 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -269,6 +269,39 @@ tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
 	return nm_ring_space(ring) * avail_per_slot;
 }
 
+static int
+tx_flush(struct Global *g)
+{
+	struct nm_desc *nmd = g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	int i;
+
+	for (;;) {
+		int pending = 0;
+		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+			pending += nm_tx_pending(ring);
+		}
+
+		if (!pending)
+			return 0;
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		if (elapsed_ms > 0) {
+			usleep(wait_ms * 1000);
+			elapsed_ms += wait_ms;
+		}
+
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+}
+
 /* Transmit a single packet using any TX ring. */
 static int
 tx_one(struct Global *g)
@@ -714,6 +747,7 @@ main(int argc, char **argv)
 			}
 
 			for (j = 0; j < e->num; j++) {
+				printf("%d: ", j);
 				switch (e->evtype) {
 				case EVENT_TYPE_TX:
 					if (tx_one(g)) {
@@ -738,6 +772,9 @@ main(int argc, char **argv)
 		}
 	}
 
+	/* if we have sent something, wait for all tx to complete */
+	tx_flush(g);
+
 	nm_close(g->nmd);
 
 	return 0;

From 0503531bf0d07589bfe206f2712e6963fbf9f8db Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 11:21:23 +0200
Subject: [PATCH 0892/2207] vale: fix indentation

---
 sys/dev/netmap/netmap_vale.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 94e68dcd7..20c819244 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -2833,8 +2833,8 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	}
 
 	/* increment the usage counter for all the hwna krings */
-        for_rx_tx(t) {
-                for (i = 0; i < netmap_all_rings(hwna, t); i++) {
+	for_rx_tx(t) {
+		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users++;
 		}
 	}

From 13bea6c6f08dd1d7e55cf04ff1976ae2bb5ca714 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 11:21:45 +0200
Subject: [PATCH 0893/2207] fix return value of netmap_attach_ext

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f8529a37d..f3760e15e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3433,7 +3433,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 	}
 
 	if (arg == NULL || arg->ifp == NULL)
-		goto fail;
+		return EINVAL;
 
 	ifp = arg->ifp;
 	if (NA(ifp) && !NM_NA_VALID(ifp)) {

From e918515af7d5e9b6ad3fdd50bc2075b2eee19183 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 13:39:23 +0200
Subject: [PATCH 0894/2207] linux: remove useless save during attach

---
 sys/dev/netmap/netmap.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f3760e15e..30b5cc3be 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3465,14 +3465,12 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 	NM_ATTACH_NA(ifp, &hwna->up);
 
 #ifdef linux
+#ifdef NETMAP_LINUX_HAVE_NETDEV_OPS
 	if (ifp->netdev_ops) {
 		/* prepare a clone of the netdev ops */
-#ifndef NETMAP_LINUX_HAVE_NETDEV_OPS
-		hwna->nm_ndo.ndo_start_xmit = ifp->netdev_ops;
-#else
 		hwna->nm_ndo = *ifp->netdev_ops;
-#endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
 	}
+#endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
 	hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit;
 	hwna->nm_ndo.NETMAP_LINUX_CHANGE_MTU = linux_netmap_change_mtu;
 	if (ifp->ethtool_ops) {

From 6515e8781e7707928557b9a4288f128e6661eb27 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 13:46:57 +0200
Subject: [PATCH 0895/2207] introduce NM_DETACH_NA

---
 sys/dev/netmap/netmap.c      | 2 +-
 sys/dev/netmap/netmap_kern.h | 2 ++
 sys/dev/netmap/netmap_vale.c | 2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 30b5cc3be..1fbabaa49 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3409,7 +3409,7 @@ netmap_hw_dtor(struct netmap_adapter *na)
 	if (nm_iszombie(na) || na->ifp == NULL)
 		return;
 
-	WNA(na->ifp) = NULL;
+	NM_DETACH_NA(na->ifp);
 }
 
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6f4c9a303..f680b34ac 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1669,6 +1669,8 @@ extern int ptnetmap_tx_workers;
 			((uint32_t)(uintptr_t)NA(ifp)) ^ NETMAP_MAGIC;	\
 } while(0)
 
+#define NM_DETACH_NA(ifp)	do { WNA(ifp) = NULL; } while (0)
+
 #define NM_IS_NATIVE(ifp)	(NM_NA_VALID(ifp) && NA(ifp)->nm_dtor == netmap_hw_dtor)
 
 #if defined(__FreeBSD__)
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 20c819244..d4601c853 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -663,7 +663,7 @@ netmap_vp_dtor(struct netmap_adapter *na)
 	}
 
 	if (na->ifp != NULL && !nm_iszombie(na)) {
-		WNA(na->ifp) = NULL;
+		NM_DETACH_NA(na->ifp);
 		if (vpna->autodelete) {
 			ND("releasing %s", na->ifp->if_xname);
 			NMG_UNLOCK();

From a94a6ee53800bf0853b0a0c6c2d90911699f7eca Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 14:15:39 +0200
Subject: [PATCH 0896/2207] introduce os-specific on attach/detach/enter/exit
 functions

---
 LINUX/netmap_linux.c            | 54 +++++++++++++++++++++++++-
 sys/dev/netmap/netmap.c         | 56 ++++++++++++++++----------
 sys/dev/netmap/netmap_freebsd.c | 22 +++++++++++
 sys/dev/netmap/netmap_kern.h    | 69 ++++-----------------------------
 4 files changed, 119 insertions(+), 82 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 58d3097a1..1ef2bfceb 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1139,7 +1139,7 @@ netmap_rings_config_get(struct netmap_adapter *na, struct nm_config_info *info)
 EXPORT_SYMBOL(netmap_rings_config_get);
 
 /* Default nm_config implementation for netmap_hw_adapter on Linux. */
-int
+static int
 netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	int ret = netmap_rings_config_get(na, info);
@@ -2558,6 +2558,56 @@ nm_os_selrecord(NM_SELRECORD_T *sr, NM_SELINFO_T *si)
 	poll_wait(sr->file, si, sr->pwait);
 }
 
+void
+nm_os_onattach(struct ifnet *ifp)
+{
+	struct netmap_adapter *na = NA(ifp);
+	struct netmap_hw_adapter *hwna = (struct netmap_hw_adapter *)na;
+
+#ifdef NETMAP_LINUX_HAVE_NETDEV_OPS
+	if (ifp->netdev_ops) {
+		/* prepare a clone of the netdev ops */
+		hwna->nm_ndo = *ifp->netdev_ops;
+	}
+#endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
+	hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit;
+	hwna->nm_ndo.NETMAP_LINUX_CHANGE_MTU = linux_netmap_change_mtu;
+	if (ifp->ethtool_ops) {
+		hwna->nm_eto = *ifp->ethtool_ops;
+	}
+	hwna->nm_eto.set_ringparam = linux_netmap_set_ringparam;
+#ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
+	hwna->nm_eto.set_channels = linux_netmap_set_channels;
+#endif /* NETMAP_LINUX_HAVE_SET_CHANNELS */
+	if (na->nm_config == NULL) {
+		hwna->up.nm_config = netmap_linux_config;
+	}
+}
+
+void
+nm_os_onenter(struct ifnet *ifp)
+{
+	struct netmap_adapter *na = NA(ifp);
+	struct netmap_hw_adapter *hwna = (struct netmap_hw_adapter *)na;
+
+	na->if_transmit = (void *)ifp->netdev_ops;
+	ifp->netdev_ops = &hwna->nm_ndo;
+	hwna->save_ethtool = ifp->ethtool_ops;
+	ifp->ethtool_ops = &hwna->nm_eto;
+
+}
+
+void
+nm_os_onexit(struct ifnet *ifp)
+{
+	struct netmap_adapter *na = NA(ifp);
+	struct netmap_hw_adapter *hwna = (struct netmap_hw_adapter *)na;
+
+	ifp->netdev_ops = (void *)na->if_transmit;
+	ifp->ethtool_ops = hwna->save_ethtool;
+}
+
+
 module_init(linux_netmap_init);
 module_exit(linux_netmap_fini);
 
@@ -2606,6 +2656,8 @@ EXPORT_SYMBOL(netmap_pipe_txsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_rxsync);	/* used by veth module */
 #endif /* WITH_PIPES */
 EXPORT_SYMBOL(netmap_verbose);
+EXPORT_SYMBOL(nm_set_native_flags);
+EXPORT_SYMBOL(nm_clear_native_flags);
 
 MODULE_AUTHOR("http://info.iet.unipi.it/~luigi/netmap/");
 MODULE_DESCRIPTION("The netmap packet I/O framework");
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1fbabaa49..d7bfefe77 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3464,26 +3464,8 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 
 	NM_ATTACH_NA(ifp, &hwna->up);
 
-#ifdef linux
-#ifdef NETMAP_LINUX_HAVE_NETDEV_OPS
-	if (ifp->netdev_ops) {
-		/* prepare a clone of the netdev ops */
-		hwna->nm_ndo = *ifp->netdev_ops;
-	}
-#endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
-	hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit;
-	hwna->nm_ndo.NETMAP_LINUX_CHANGE_MTU = linux_netmap_change_mtu;
-	if (ifp->ethtool_ops) {
-		hwna->nm_eto = *ifp->ethtool_ops;
-	}
-	hwna->nm_eto.set_ringparam = linux_netmap_set_ringparam;
-#ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
-	hwna->nm_eto.set_channels = linux_netmap_set_channels;
-#endif /* NETMAP_LINUX_HAVE_SET_CHANNELS */
-	if (arg->nm_config == NULL) {
-		hwna->up.nm_config = netmap_linux_config;
-	}
-#endif /* linux */
+	nm_os_onattach(ifp);
+
 	if (arg->nm_dtor == NULL) {
 		hwna->up.nm_dtor = netmap_hw_dtor;
 	}
@@ -3864,6 +3846,40 @@ netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done)
 	return netmap_common_irq(na, q, work_done);
 }
 
+/* set/clear native flags and if_transmit/netdev_ops */
+void
+nm_set_native_flags(struct netmap_adapter *na)
+{
+	struct ifnet *ifp = na->ifp;
+
+	/* We do the setup for intercepting packets only if we are the
+	 * first user of this adapapter. */
+	if (na->active_fds > 0) {
+		return;
+	}
+
+	na->na_flags |= NAF_NETMAP_ON;
+	nm_os_onenter(ifp);
+	nm_update_hostrings_mode(na);
+}
+
+void
+nm_clear_native_flags(struct netmap_adapter *na)
+{
+	struct ifnet *ifp = na->ifp;
+
+	/* We undo the setup for intercepting packets only if we are the
+	 * last user of this adapapter. */
+	if (na->active_fds > 0) {
+		return;
+	}
+
+	nm_update_hostrings_mode(na);
+	nm_os_onexit(ifp);
+
+	na->na_flags &= ~NAF_NETMAP_ON;
+}
+
 
 /*
  * Module loader and unloader
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index d4b8795c0..e9a622782 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1544,6 +1544,28 @@ freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
 	return error;
 }
 
+void
+nm_os_onattach(struct ifnet *ifp)
+{
+}
+
+void
+nm_os_onenter(struct ifnet *ifp)
+{
+	struct netmap_adapter *na = NA(ifp);
+
+	na->if_transmit = ifp->if_transmit;
+	ifp->if_transmit = netmap_transmit;
+	ifp->if_capenable |= IFCAP_NETMAP;
+}
+
+void
+nm_os_onexit(struct ifnet *ifp)
+{
+	ifp->if_transmit = na->if_transmit;
+	ifp->if_capenable &= ~IFCAP_NETMAP;
+}
+
 extern struct cdevsw netmap_cdevsw; /* XXX used in netmap.c, should go elsewhere */
 struct cdevsw netmap_cdevsw = {
 	.d_version = D_VERSION,
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f680b34ac..992351666 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -303,6 +303,12 @@ void *nm_os_realloc(void *, size_t new_size, size_t old_size);
 void nm_os_free(void *);
 void nm_os_vfree(void *);
 
+/* os specific attach/detach enter/exit-netmap-mode routines */
+void nm_os_onattach(struct ifnet *);
+void nm_os_ondetach(struct ifnet *);
+void nm_os_onenter(struct ifnet *);
+void nm_os_onexit(struct ifnet *);
+
 /* passes a packet up to the host stack.
  * If the packet is sent (or dropped) immediately it returns NULL,
  * otherwise it links the packet to prev and returns m.
@@ -1317,67 +1323,8 @@ nm_update_hostrings_mode(struct netmap_adapter *na)
 		na->rx_rings[na->num_rx_rings]->nr_pending_mode;
 }
 
-/* set/clear native flags and if_transmit/netdev_ops */
-static inline void
-nm_set_native_flags(struct netmap_adapter *na)
-{
-	struct ifnet *ifp = na->ifp;
-
-	/* We do the setup for intercepting packets only if we are the
-	 * first user of this adapapter. */
-	if (na->active_fds > 0) {
-		return;
-	}
-
-	na->na_flags |= NAF_NETMAP_ON;
-#ifdef IFCAP_NETMAP /* or FreeBSD ? */
-	ifp->if_capenable |= IFCAP_NETMAP;
-#endif
-#if defined (__FreeBSD__)
-	na->if_transmit = ifp->if_transmit;
-	ifp->if_transmit = netmap_transmit;
-#elif defined (_WIN32)
-	(void)ifp; /* prevent a warning */
-#elif defined (linux)
-	na->if_transmit = (void *)ifp->netdev_ops;
-	ifp->netdev_ops = &((struct netmap_hw_adapter *)na)->nm_ndo;
-	((struct netmap_hw_adapter *)na)->save_ethtool = ifp->ethtool_ops;
-	ifp->ethtool_ops = &((struct netmap_hw_adapter*)na)->nm_eto;
-#endif /* linux */
-	nm_update_hostrings_mode(na);
-}
-
-static inline void
-nm_clear_native_flags(struct netmap_adapter *na)
-{
-	struct ifnet *ifp = na->ifp;
-
-	/* We undo the setup for intercepting packets only if we are the
-	 * last user of this adapapter. */
-	if (na->active_fds > 0) {
-		return;
-	}
-
-	nm_update_hostrings_mode(na);
-
-#if defined(__FreeBSD__)
-	ifp->if_transmit = na->if_transmit;
-#elif defined(_WIN32)
-	(void)ifp; /* prevent a warning */
-#else
-	ifp->netdev_ops = (void *)na->if_transmit;
-	ifp->ethtool_ops = ((struct netmap_hw_adapter*)na)->save_ethtool;
-#endif
-	na->na_flags &= ~NAF_NETMAP_ON;
-#ifdef IFCAP_NETMAP /* or FreeBSD ? */
-	ifp->if_capenable &= ~IFCAP_NETMAP;
-#endif
-}
-
-#ifdef linux
-int netmap_linux_config(struct netmap_adapter *na,
-			struct nm_config_info *info);
-#endif /* linux */
+void nm_set_native_flags(struct netmap_adapter *);
+void nm_clear_native_flags(struct netmap_adapter *);
 
 /*
  * nm_*sync_prologue() functions are used in ioctl/poll and ptnetmap

From 41b62be246ad2cca33165ce169d18fa9033a9598 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 19:25:00 +0200
Subject: [PATCH 0897/2207] cleanup adapter pointer on module removal

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d7bfefe77..8942f474a 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3406,7 +3406,7 @@ netmap_hw_reg(struct netmap_adapter *na, int onoff)
 static void
 netmap_hw_dtor(struct netmap_adapter *na)
 {
-	if (nm_iszombie(na) || na->ifp == NULL)
+	if (na->ifp == NULL)
 		return;
 
 	NM_DETACH_NA(na->ifp);

From fc0ce1ddc116d95eea5f9eada5176614f8214ad2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 19:27:14 +0200
Subject: [PATCH 0898/2207] linux: attach to ethtool_ops if ax25_ptr is
 compiled-out

---
 LINUX/bsd_glue.h             | 36 ++++++++++++++++++++++++++++++++++
 LINUX/configure              | 10 ++++++++++
 LINUX/netmap_linux.c         | 38 ++++++++++++++++++++++++++++++++++--
 sys/dev/netmap/netmap.c      |  2 +-
 sys/dev/netmap/netmap_kern.h | 23 +++++++++++++++++++---
 5 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 2fdd5a00b..5a54bdb5a 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -277,6 +277,8 @@ struct thread;
 #define copyin(_from, _to, _len)	(copy_from_user(_to, _from, _len) ? EFAULT : 0)
 #define copyout(_from, _to, _len)	(copy_to_user(_to, _from, _len) ? EFAULT : 0)
 
+/* na attach/detach routines */
+#ifdef NETMAP_LINUX_HAVE_AX25_PTR
 /*
  * struct ifnet is remapped into struct net_device on linux.
  * ifnet has an if_softc field pointing to the device-specific struct
@@ -293,6 +295,40 @@ struct thread;
  * for netmap-capable is some magic in the area pointed by that.
  */
 #define WNA(_ifp)		(_ifp)->ax25_ptr
+/* use the default NM_ATTACH_NA/NM_DETACH_NA defined in netmap_kernel.h */
+#else /* !NETMAP_LINUX_HAVE_AX25_PTR */
+/*
+ * We hide behind the ethtool_ops
+ */
+int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *);
+struct netmap_linux_magic {
+	struct ethtool_ops eto;
+	const struct ethtool_ops *save_eto;
+};
+#define NM_OS_MAGIC	struct netmap_linux_magic
+#define WNA(ifp)	(ifp->ethtool_ops)
+#define NM_DETACH_NA(ifp)  do {						\
+	(ifp)->ethtool_ops = NA(ifp)->magic.save_eto;			\
+} while (0)
+#define NM_ATTACH_NA(ifp, na) do {					\
+	if ((na)->magic.save_eto == &(na)->magic.eto) {			\
+		NM_DETACH_NA(ifp);					\
+		break;							\
+	}								\
+	if ((ifp)->ethtool_ops) {					\
+		(na)->magic.eto = *(ifp)->ethtool_ops;			\
+		(na)->magic.save_eto = (ifp)->ethtool_ops;		\
+	} else {							\
+		memset(&(na)->magic, 0, sizeof((na)->magic));		\
+	}								\
+	(na)->magic.eto.set_ringparam = linux_netmap_set_ringparam;	\
+	(ifp)->ethtool_ops = &(na)->magic.eto;				\
+} while (0)
+#define NM_NA_VALID(ifp)						\
+	(NA(ifp) && NA(ifp)->magic.eto.set_ringparam == 		\
+		linux_netmap_set_ringparam)
+#define NM_NA_CLASH(ifp)	(0)	// XXX
+#endif /* NETAP_LINUX_HAVE_AX25_PTR */
 
 #define ifnet           	net_device      /* remap */
 #define	if_xname		name		/* field ifnet-> net_device */
diff --git a/LINUX/configure b/LINUX/configure
index deef12b1e..da9cd64dd 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1015,6 +1015,16 @@ EOF
 	  add_file_exists_check patch-$d true "drv_patch_error $d"
   done
 
+  # ax25_ptr
+  add_test 'have AX25PTR' <
+
+	void * dummy(struct net_device *dev)
+	{
+		return dev->ax25_ptr;
+	}
+EOF
+
   # iommu support
   add_test 'have IOMMU' <
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1ef2bfceb..eab7a6973 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1315,12 +1315,24 @@ linux_netmap_change_mtu(struct net_device *dev, int new_mtu)
 
 /* while in netmap mode, we cannot tolerate any change in the
  * number of rx/tx rings and descriptors
+ *
+ * Linux calls this while holding the rtnl_lock().
  */
 int
 linux_netmap_set_ringparam(struct net_device *dev,
 	struct ethtool_ringparam *e)
 {
+#ifdef NETMAP_LINUX_HAVE_AX25_PTR
 	return -EBUSY;
+#else /* !NETMAP_LINUX_HAVE_AX25_PTR */
+	struct netmap_adapter *na = NA(dev);
+
+	if (nm_netmap_on(na))
+		return -EBUSY;
+	if (na->magic.save_eto->set_ringparam)
+		return na->magic.save_eto->set_ringparam(dev, e);
+	return -EOPNOTSUPP;
+#endif /* NETMAP_LINUX_HAVE_AX25_PTR */
 }
 
 #ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
@@ -1328,7 +1340,17 @@ int
 linux_netmap_set_channels(struct net_device *dev,
 	struct ethtool_channels *e)
 {
+#ifdef NETMAP_LINUX_HAVE_AX25_PTR
 	return -EBUSY;
+#else /* !NETMAP_LINUX_HAVE_AX25_PTR */
+	struct netmap_adapter *na = NA(dev);
+
+	if (nm_netmap_on(na))
+		return -EBUSY;
+	if (na->magic.save_eto->set_channels)
+		return na->magic.save_eto->set_channels(dev, e);
+	return -EOPNOTSUPP;
+#endif /* NETMAP_LINUX_HAVE_AX25_PTR */
 }
 #endif
 
@@ -2572,6 +2594,7 @@ nm_os_onattach(struct ifnet *ifp)
 #endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */
 	hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit;
 	hwna->nm_ndo.NETMAP_LINUX_CHANGE_MTU = linux_netmap_change_mtu;
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
 	if (ifp->ethtool_ops) {
 		hwna->nm_eto = *ifp->ethtool_ops;
 	}
@@ -2579,6 +2602,11 @@ nm_os_onattach(struct ifnet *ifp)
 #ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
 	hwna->nm_eto.set_channels = linux_netmap_set_channels;
 #endif /* NETMAP_LINUX_HAVE_SET_CHANNELS */
+#else /* !NETMAP_LINUX_HAVE_AX25PTR */
+#ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
+	na->magic.eto.set_channels = linux_netmap_set_channels;
+#endif /* NETMAP_LINUX_HAVE_SET_CHANNELS */
+#endif /* NETMAP_LINUX_HAVE_AX25PTR */
 	if (na->nm_config == NULL) {
 		hwna->up.nm_config = netmap_linux_config;
 	}
@@ -2592,9 +2620,12 @@ nm_os_onenter(struct ifnet *ifp)
 
 	na->if_transmit = (void *)ifp->netdev_ops;
 	ifp->netdev_ops = &hwna->nm_ndo;
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
 	hwna->save_ethtool = ifp->ethtool_ops;
 	ifp->ethtool_ops = &hwna->nm_eto;
-
+#else /* NETMAP_LINUX_HAVE_AX25PTR */
+	(void)hwna;
+#endif /* NETMAP_LINUX_HAVE_AX25PTR */
 }
 
 void
@@ -2604,10 +2635,13 @@ nm_os_onexit(struct ifnet *ifp)
 	struct netmap_hw_adapter *hwna = (struct netmap_hw_adapter *)na;
 
 	ifp->netdev_ops = (void *)na->if_transmit;
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
 	ifp->ethtool_ops = hwna->save_ethtool;
+#else /* NETMAP_LINUX_HAVE_AX25PTR */
+	(void)hwna;
+#endif /* NETMAP_LINUX_HAVE_AX25PTR */
 }
 
-
 module_init(linux_netmap_init);
 module_exit(linux_netmap_fini);
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8942f474a..287f2c0bc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3436,7 +3436,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		return EINVAL;
 
 	ifp = arg->ifp;
-	if (NA(ifp) && !NM_NA_VALID(ifp)) {
+	if (NM_NA_CLASH(ifp)) {
 		/* If NA(ifp) is not null but there is no valid netmap
 		 * adapter it means that someone else is using the same
 		 * pointer (e.g. ax25_ptr on linux). This happens for
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 992351666..43c8cf4e6 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -649,6 +649,14 @@ struct nm_config_info {
 	unsigned rx_buf_maxsize;
 };
 
+/*
+ * default type for the magic field.
+ * May be overriden in glue code.
+ */
+#ifndef NM_OS_MAGIC
+#define NM_OS_MAGIC uint32_t
+#endif /* !NM_OS_MAGIC */
+
 /*
  * The "struct netmap_adapter" extends the "struct adapter"
  * (or equivalent) device descriptor.
@@ -665,7 +673,7 @@ struct netmap_adapter {
 	 * always exists and is at least 32 bits) contains a magic
 	 * value which we can use to detect that the interface is good.
 	 */
-	uint32_t magic;
+	NM_OS_MAGIC magic;
 	uint32_t na_flags;	/* enabled, and other flags */
 #define NAF_SKIP_INTR	1	/* use the regular interrupt handler.
 				 * useful during initialization
@@ -1592,11 +1600,17 @@ extern int netmap_generic_txqdisc;
 extern int ptnetmap_tx_workers;
 
 /*
- * NA returns a pointer to the struct netmap adapter from the ifp,
- * WNA is used to write it.
+ * NA returns a pointer to the struct netmap adapter from the ifp.
+ * WNA is os-specific and must be defined in glue code.
  */
 #define	NA(_ifp)	((struct netmap_adapter *)WNA(_ifp))
 
+/*
+ * we provide a default implementation of NM_ATTACH_NA/NM_DETACH_NA
+ * based on the WNA field.
+ * Glue code may override this by defining its own NM_ATTACH_NA
+ */
+#ifndef NM_ATTACH_NA
 /*
  * On old versions of FreeBSD, NA(ifp) is a pspare. On linux we
  * overload another pointer in the netdev.
@@ -1617,6 +1631,9 @@ extern int ptnetmap_tx_workers;
 } while(0)
 
 #define NM_DETACH_NA(ifp)	do { WNA(ifp) = NULL; } while (0)
+#define NM_NA_CLASH(ifp)	(NA(ifp) && !NM_NA_VALID(ifp))
+#endif /* !NM_ATTACH_NA */
+
 
 #define NM_IS_NATIVE(ifp)	(NM_NA_VALID(ifp) && NA(ifp)->nm_dtor == netmap_hw_dtor)
 

From 4568d1e96dff3e894801d167c511a621f7585cc0 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Tue, 5 Jun 2018 12:01:01 +0200
Subject: [PATCH 0899/2207] FreeBSD: fix compile error

---
 sys/dev/netmap/netmap_freebsd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index e9a622782..eb16586c8 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1562,6 +1562,8 @@ nm_os_onenter(struct ifnet *ifp)
 void
 nm_os_onexit(struct ifnet *ifp)
 {
+	struct netmap_adapter *na = NA(ifp);
+
 	ifp->if_transmit = na->if_transmit;
 	ifp->if_capenable &= ~IFCAP_NETMAP;
 }

From 1f1985744e3b2cfdd54319e04033efaf6a84f92d Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Tue, 5 Jun 2018 12:07:18 +0200
Subject: [PATCH 0900/2207] FreeBSD: fix compile error (fix of 788b63d6ec)

---
 sys/dev/netmap/netmap_generic.c | 111 --------------------------------
 1 file changed, 111 deletions(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 4bb87d000..671821e4a 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -87,117 +87,6 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap_generic.c 274353 2014-11-10 20:19
 #define MBUF_RXQ(m)	((m)->m_pkthdr.flowid)
 #define smp_mb()
 
-/*
- * FreeBSD mbuf allocator/deallocator in emulation mode:
- */
-#if __FreeBSD_version < 1100000
-
-/*
- * For older versions of FreeBSD:
- *
- * We allocate EXT_PACKET mbuf+clusters, but need to set M_NOFREE
- * so that the destructor, if invoked, will not free the packet.
- * In principle we should set the destructor only on demand,
- * but since there might be a race we better do it on allocation.
- * As a consequence, we also need to set the destructor or we
- * would leak buffers.
- */
-
-/* mbuf destructor, also need to change the type to EXT_EXTREF,
- * add an M_NOFREE flag, and then clear the flag and
- * chain into uma_zfree(zone_pack, mf)
- * (or reinstall the buffer ?)
- */
-#define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
-	(m)->m_ext.ext_free = (void *)fn;	\
-	(m)->m_ext.ext_type = EXT_EXTREF;	\
-} while (0)
-
-static int
-void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2)
-{
-	/* restore original mbuf */
-	m->m_ext.ext_buf = m->m_data = m->m_ext.ext_arg1;
-	m->m_ext.ext_arg1 = NULL;
-	m->m_ext.ext_type = EXT_PACKET;
-	m->m_ext.ext_free = NULL;
-	if (MBUF_REFCNT(m) == 0)
-		SET_MBUF_REFCNT(m, 1);
-	uma_zfree(zone_pack, m);
-
-	return 0;
-}
-
-static inline struct mbuf *
-nm_os_get_mbuf(struct ifnet *ifp, int len)
-{
-	struct mbuf *m;
-
-	(void)ifp;
-	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
-	if (m) {
-		/* m_getcl() (mb_ctor_mbuf) has an assert that checks that
-		 * M_NOFREE flag is not specified as third argument,
-		 * so we have to set M_NOFREE after m_getcl(). */
-		m->m_flags |= M_NOFREE;
-		m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save
-		m->m_ext.ext_free = (void *)void_mbuf_dtor;
-		m->m_ext.ext_type = EXT_EXTREF;
-		ND(5, "create m %p refcnt %d", m, MBUF_REFCNT(m));
-	}
-	return m;
-}
-
-#else /* __FreeBSD_version >= 1100000 */
-
-/*
- * Newer versions of FreeBSD, using a straightforward scheme.
- *
- * We allocate mbufs with m_gethdr(), since the mbuf header is needed
- * by the driver. We also attach a customly-provided external storage,
- * which in this case is a netmap buffer. When calling m_extadd(), however
- * we pass a NULL address, since the real address (and length) will be
- * filled in by nm_os_generic_xmit_frame() right before calling
- * if_transmit().
- *
- * The dtor function does nothing, however we need it since mb_free_ext()
- * has a KASSERT(), checking that the mbuf dtor function is not NULL.
- */
-
-#if __FreeBSD_version <= 1200050
-static void void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { }
-#else  /* __FreeBSD_version >= 1200051 */
-/* The arg1 and arg2 pointers argument were removed by r324446, which
- * in included since version 1200051. */
-static void void_mbuf_dtor(struct mbuf *m) { }
-#endif /* __FreeBSD_version >= 1200051 */
-
-#define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
-	(m)->m_ext.ext_free = (fn != NULL) ?		\
-	    (void *)fn : (void *)void_mbuf_dtor;	\
-} while (0)
-
-static inline struct mbuf *
-nm_os_get_mbuf(struct ifnet *ifp, int len)
-{
-	struct mbuf *m;
-
-	(void)ifp;
-	(void)len;
-
-	m = m_gethdr(M_NOWAIT, MT_DATA);
-	if (m == NULL) {
-		return m;
-	}
-
-	m_extadd(m, NULL /* buf */, 0 /* size */, void_mbuf_dtor,
-		 NULL, NULL, 0, EXT_NET_DRV);
-
-	return m;
-}
-
-#endif /* __FreeBSD_version >= 1100000 */
-
 #elif defined _WIN32
 
 #include "win_glue.h"

From 418da082341250fa206deb0379b7e52ba94bac88 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Jun 2018 15:36:35 +0200
Subject: [PATCH 0901/2207] linux: fix several AX25PTR typos

---
 LINUX/bsd_glue.h     |  6 +++---
 LINUX/netmap_linux.c | 15 +++++++++------
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 5a54bdb5a..f89f3d7ac 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -278,7 +278,7 @@ struct thread;
 #define copyout(_from, _to, _len)	(copy_to_user(_to, _from, _len) ? EFAULT : 0)
 
 /* na attach/detach routines */
-#ifdef NETMAP_LINUX_HAVE_AX25_PTR
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
 /*
  * struct ifnet is remapped into struct net_device on linux.
  * ifnet has an if_softc field pointing to the device-specific struct
@@ -296,7 +296,7 @@ struct thread;
  */
 #define WNA(_ifp)		(_ifp)->ax25_ptr
 /* use the default NM_ATTACH_NA/NM_DETACH_NA defined in netmap_kernel.h */
-#else /* !NETMAP_LINUX_HAVE_AX25_PTR */
+#else /* !NETMAP_LINUX_HAVE_AX25PTR */
 /*
  * We hide behind the ethtool_ops
  */
@@ -328,7 +328,7 @@ struct netmap_linux_magic {
 	(NA(ifp) && NA(ifp)->magic.eto.set_ringparam == 		\
 		linux_netmap_set_ringparam)
 #define NM_NA_CLASH(ifp)	(0)	// XXX
-#endif /* NETAP_LINUX_HAVE_AX25_PTR */
+#endif /* NETAP_LINUX_HAVE_AX25PTR */
 
 #define ifnet           	net_device      /* remap */
 #define	if_xname		name		/* field ifnet-> net_device */
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index eab7a6973..ff07a4783 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1322,9 +1322,9 @@ int
 linux_netmap_set_ringparam(struct net_device *dev,
 	struct ethtool_ringparam *e)
 {
-#ifdef NETMAP_LINUX_HAVE_AX25_PTR
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
 	return -EBUSY;
-#else /* !NETMAP_LINUX_HAVE_AX25_PTR */
+#else /* !NETMAP_LINUX_HAVE_AX25PTR */
 	struct netmap_adapter *na = NA(dev);
 
 	if (nm_netmap_on(na))
@@ -1332,7 +1332,7 @@ linux_netmap_set_ringparam(struct net_device *dev,
 	if (na->magic.save_eto->set_ringparam)
 		return na->magic.save_eto->set_ringparam(dev, e);
 	return -EOPNOTSUPP;
-#endif /* NETMAP_LINUX_HAVE_AX25_PTR */
+#endif /* NETMAP_LINUX_HAVE_AX25PTR */
 }
 
 #ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
@@ -1340,9 +1340,9 @@ int
 linux_netmap_set_channels(struct net_device *dev,
 	struct ethtool_channels *e)
 {
-#ifdef NETMAP_LINUX_HAVE_AX25_PTR
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
 	return -EBUSY;
-#else /* !NETMAP_LINUX_HAVE_AX25_PTR */
+#else /* !NETMAP_LINUX_HAVE_AX25PTR */
 	struct netmap_adapter *na = NA(dev);
 
 	if (nm_netmap_on(na))
@@ -1350,7 +1350,7 @@ linux_netmap_set_channels(struct net_device *dev,
 	if (na->magic.save_eto->set_channels)
 		return na->magic.save_eto->set_channels(dev, e);
 	return -EOPNOTSUPP;
-#endif /* NETMAP_LINUX_HAVE_AX25_PTR */
+#endif /* NETMAP_LINUX_HAVE_AX25PTR */
 }
 #endif
 
@@ -2692,6 +2692,9 @@ EXPORT_SYMBOL(netmap_pipe_rxsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_verbose);
 EXPORT_SYMBOL(nm_set_native_flags);
 EXPORT_SYMBOL(nm_clear_native_flags);
+#ifndef NETMAP_LINUX_HAVE_AX25PTR
+EXPORT_SYMBOL(netmap_linux_set_ringparam);
+#endif /* NETMAP_LINUX_HAVE_AX25PTR */
 
 MODULE_AUTHOR("http://info.iet.unipi.it/~luigi/netmap/");
 MODULE_DESCRIPTION("The netmap packet I/O framework");

From 8b1ef4d4fa4f43e8fa049401eed9e0abcbc788a1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 Jun 2018 10:26:02 +0200
Subject: [PATCH 0902/2207] linux: fix exported function name

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index ff07a4783..4d7297f53 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2693,7 +2693,7 @@ EXPORT_SYMBOL(netmap_verbose);
 EXPORT_SYMBOL(nm_set_native_flags);
 EXPORT_SYMBOL(nm_clear_native_flags);
 #ifndef NETMAP_LINUX_HAVE_AX25PTR
-EXPORT_SYMBOL(netmap_linux_set_ringparam);
+EXPORT_SYMBOL(linux_netmap_set_ringparam);
 #endif /* NETMAP_LINUX_HAVE_AX25PTR */
 
 MODULE_AUTHOR("http://info.iet.unipi.it/~luigi/netmap/");

From 444b71e8eab2e1143a7baa5ef2b4c3ee5aae178b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 Jun 2018 15:26:00 +0200
Subject: [PATCH 0903/2207] linux/i40e: patch for intel 2.4.10 version

---
 LINUX/final-patches/intel--i40e--2.4.10 | 165 ++++++++++++++++++++++++
 1 file changed, 165 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.4.10

diff --git a/LINUX/final-patches/intel--i40e--2.4.10 b/LINUX/final-patches/intel--i40e--2.4.10
new file mode 100644
index 000000000..8d719ca4b
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.4.10
@@ -0,0 +1,165 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index d33d3a8..e5f49a0 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -30,9 +30,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -46,13 +46,13 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index e60e81e..9af8153 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -141,6 +141,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3267,6 +3272,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3320,6 +3329,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3348,6 +3361,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -10944,6 +10962,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -11312,6 +11335,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index eea26ba..de76992 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -26,6 +26,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -788,6 +792,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2386,6 +2395,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+ 	bool failure = false;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 99adbefaec50b3841a026e0dfc7955a4fa45b035 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Jun 2018 13:41:12 +0200
Subject: [PATCH 0904/2207] netmap_transmit: fix access to non-existent host
 rings

---
 sys/dev/netmap/netmap.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 287f2c0bc..7e137cdf8 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3602,6 +3602,9 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	u_int i;
 
 	i = MBUF_TXQ(m);
+	if (i >= na->num_host_rx_rings) {
+		i = i % na->num_host_rx_rings;
+	}
 	kring = NMR(na, NR_RX)[nma_get_nrings(na, NR_RX) + i];
 
 	// XXX [Linux] we do not need this lock

From fe442ca16c873047f4584dc8102750b33683f845 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Jun 2018 17:27:41 +0200
Subject: [PATCH 0905/2207] provide a default value for num_host_[rt]x_rings

---
 sys/dev/netmap/netmap.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7e137cdf8..b978ede9d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3343,6 +3343,12 @@ netmap_attach_common(struct netmap_adapter *na)
 	}
 	na->pdev = na; /* make sure netmap_mem_map() is called */
 #endif /* __FreeBSD__ */
+	if (na->na_flags & NAF_HOST_RINGS) {
+		if (na->num_host_rx_rings == 0)
+			na->num_host_rx_rings = 1;
+		if (na->num_host_tx_rings == 0)
+			na->num_host_tx_rings = 1;
+	}
 	if (na->nm_krings_create == NULL) {
 		/* we assume that we have been called by a driver,
 		 * since other port types all provide their own
@@ -3450,7 +3456,6 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		goto fail;
 	hwna->up = *arg;
 	hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE;
-	hwna->up.num_host_tx_rings = hwna->up.num_host_rx_rings = 1;
 	strncpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name));
 	if (override_reg) {
 		hwna->nm_hw_register = hwna->up.nm_register;

From f61c3b2637b389cf23581a680802af198a592cc2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kai=20L=C3=BCke?= 
Date: Wed, 20 Jun 2018 10:55:26 +0900
Subject: [PATCH 0906/2207] pkt-gen: Use first_tx_ring instead of 0 (needed for
 host rings)

---
 apps/pkt-gen/pkt-gen.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 26157243a..69c478cd8 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1253,7 +1253,7 @@ ping_body(void *data)
 		nexttime = targ->tic;
 	}
 	while (!targ->cancel && (n == 0 || sent < n)) {
-		struct netmap_ring *ring = NETMAP_TXRING(nifp, 0);
+		struct netmap_ring *ring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
 		struct netmap_slot *slot;
 		char *p;
 		int rv;
@@ -1436,7 +1436,7 @@ pong_body(void *data)
 			continue;
 		}
 #endif
-		txring = NETMAP_TXRING(nifp, 0);
+		txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
 		txcur = txring->cur;
 		txavail = nm_ring_space(txring);
 		/* see what we got back */

From 89930171304ff14ebda399d7b67682f86fe9e522 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 19 Jun 2018 12:14:45 +0200
Subject: [PATCH 0907/2207] pkt-gen: fixed several gcc 8 warnings

---
 apps/pkt-gen/pkt-gen.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 69c478cd8..7e00f27be 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1361,7 +1361,7 @@ ping_body(void *data)
 		if (ts.tv_sec >= 1) {
 			D("count %d RTT: min %d av %d ns",
 				(int)count, (int)t_min, (int)(av/count));
-			int k, j, kmin;
+			int k, j, kmin, off;
 			char buf[512];
 
 			for (kmin = 0; kmin < 64; kmin ++)
@@ -1371,8 +1371,10 @@ ping_body(void *data)
 				if (buckets[k])
 					break;
 			buf[0] = '\0';
-			for (j = kmin; j <= k; j++)
-				sprintf(buf, "%s %5d", buf, (int)buckets[j]);
+			off = 0;
+			for (j = kmin; j <= k; j++) {
+				off += sprintf(buf + off, " %5d", (int)buckets[j]);
+			}
 			D("k: %d .. %d\n\t%s", 1< IFNAMSIZ) {
+			D("%s too long", dev);
+			return -1;
+		}
+		memcpy(ifr.ifr_name, dev, len);
 	}
 
 	/* try to create the device */

From 2428ace48f7fe53d064f6f7b33747507ecfe58ce Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Jun 2018 12:08:21 +0200
Subject: [PATCH 0908/2207] pkt-gen: correctly skip vnet header

---
 apps/pkt-gen/pkt-gen.c | 9 +++------
 sys/net/netmap_user.h  | 2 +-
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 7e00f27be..545db93c6 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1233,8 +1233,7 @@ ping_body(void *data)
 	uint64_t buckets[64];	/* bins for delays, ns */
 	int rate_limit = targ->g->tx_rate, tosend = 0;
 
-	frame = &targ->pkt;
-	*((char **)frame) += sizeof(targ->pkt.vh) - targ->g->virt_header;
+	frame = (char*)&targ->pkt + sizeof(targ->pkt.vh) - targ->g->virt_header;
 	size = targ->g->pkt_size + targ->g->virt_header;
 
 
@@ -1510,8 +1509,7 @@ sender_body(void *data)
 	int size;
 
 	if (targ->frame == NULL) {
-		frame = pkt;
-		*((char **)frame) += sizeof(pkt->vh) - targ->g->virt_header;
+		frame = (char *)pkt + sizeof(pkt->vh) - targ->g->virt_header;
 		size = targ->g->pkt_size + targ->g->virt_header;
 	} else {
 		frame = targ->frame;
@@ -1863,8 +1861,7 @@ txseq_body(void *data)
 		D("Ignoring -n argument");
 	}
 
-	frame = pkt;
-	*((char **)frame) += sizeof(pkt->vh) - targ->g->virt_header;
+	frame = (char *)pkt + sizeof(pkt->vh) - 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);
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 0cae62fdf..cffd65e2a 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1048,7 +1048,7 @@ nm_inject(struct nm_desc *d, const void *buf, size_t size)
 			ring->slot[i].flags = NS_MOREFRAG;
 			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
 			i = nm_ring_next(ring, i);
-			*((char **)buf) += ring->nr_buf_size;
+			buf = (char *buf) + ring->nr_buf_size;
 		}
 		idx = ring->slot[i].buf_idx;
 		ring->slot[i].len = rem;

From 21227d47ae995812412d1de22855c7fa8260f53a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Jun 2018 12:12:42 +0200
Subject: [PATCH 0909/2207] nm_inject: fix compile error

---
 sys/net/netmap_user.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index cffd65e2a..d3b157c1c 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1048,7 +1048,7 @@ nm_inject(struct nm_desc *d, const void *buf, size_t size)
 			ring->slot[i].flags = NS_MOREFRAG;
 			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
 			i = nm_ring_next(ring, i);
-			buf = (char *buf) + ring->nr_buf_size;
+			buf = (char *)buf + ring->nr_buf_size;
 		}
 		idx = ring->slot[i].buf_idx;
 		ring->slot[i].len = rem;

From 61a6700366fdad7ab0dd2759a7ab3a4929891e9b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jun 2018 12:20:16 +0200
Subject: [PATCH 0910/2207] pipe: fix regression with zero-copy monitors

---
 sys/dev/netmap/netmap_kern.h |  1 +
 sys/dev/netmap/netmap_pipe.c | 23 +++++++++++++++++------
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 43c8cf4e6..581f23ba9 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -512,6 +512,7 @@ struct netmap_kring {
 	struct netmap_kring *pipe;	/* if this is a pipe ring,
 					 * pointer to the other end
 					 */
+	uint32_t pipe_tail;		/* hwtail updated by the other end */
 #endif /* WITH_PIPES */
 
 #ifdef WITH_VALE
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 1f044217a..2d874cf09 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -193,6 +193,9 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 		txkring->nr_hwcur, txkring->nr_hwtail,
 		txkring->rcur, txkring->rhead, txkring->rtail);
 
+	/* update the hwtail */
+	txkring->nr_hwtail = txkring->pipe_tail;
+
 	m = txkring->rhead - txkring->nr_hwcur; /* new slots */
 	if (m < 0)
 		m += txkring->nkr_num_slots;
@@ -222,7 +225,7 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 
 	if (likely(nk <= lim)) {
 		mb(); /* make sure the slots are updated before publishing them */
-		rxkring->nr_hwtail = nk; /* only publish complete packets */
+		rxkring->pipe_tail = nk; /* only publish complete packets */
 		rxkring->nm_notify(rxkring, 0);
 	}
 
@@ -242,6 +245,9 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 		rxkring->nr_hwcur, rxkring->nr_hwtail,
 		rxkring->rcur, rxkring->rhead, rxkring->rtail);
 
+	/* update the hwtail */
+	rxkring->nr_hwtail = rxkring->pipe_tail;
+
 	m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */
 	if (m < 0)
 		m += rxkring->nkr_num_slots;
@@ -263,7 +269,7 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 	}
 
 	mb(); /* make sure the slots are updated before publishing them */
-	txkring->nr_hwtail = nm_prev(k, lim);
+	txkring->pipe_tail = nm_prev(k, lim);
 	rxkring->nr_hwcur = k;
 
 	ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
@@ -345,14 +351,19 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
 		if (error)
 			goto del_krings1;
 
-		/* cross link the krings */
+		/* cross link the krings and initialize the pipe_tails */
 		for_rx_tx(t) {
 			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				NMR(na, t)[i]->pipe = NMR(ona, r)[i];
-				NMR(ona, r)[i]->pipe = NMR(na, t)[i];
+				struct netmap_kring *k1 = NMR(na, t)[i],
+					            *k2 = NMR(ona, r)[i];
+				k1->pipe = k2;
+				k2->pipe = k1;
 				/* mark all peer-adapter rings as fake */
-				NMR(ona, r)[i]->nr_kflags |= NKR_FAKERING;
+				k2->nr_kflags |= NKR_FAKERING;
+				/* init tails */
+				k1->pipe_tail = k1->nr_hwtail;
+				k2->pipe_tail = k2->nr_hwtail;
 			}
 		}
 

From b17396eee7ba8ae7578b97875e36f041ca882bc2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jun 2018 16:54:17 +0200
Subject: [PATCH 0911/2207] monitor: better cleanup on monitored port exit

---
 sys/dev/netmap/netmap_monitor.c | 80 +++++++++++++++++++++------------
 1 file changed, 51 insertions(+), 29 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 461e2676c..30e58accc 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -244,6 +244,33 @@ static int netmap_monitor_parent_txsync(struct netmap_kring *, int);
 static int netmap_monitor_parent_rxsync(struct netmap_kring *, int);
 static int netmap_monitor_parent_notify(struct netmap_kring *, int);
 
+static void
+nm_monitor_intercept_callbacks(struct netmap_kring *kring)
+{
+	ND("intercept callbacks on %s", kring->name);
+	kring->mon_sync = kring->nm_sync;
+	kring->mon_notify = kring->nm_notify;
+	if (kring->tx == NR_TX) {
+		kring->nm_sync = netmap_monitor_parent_txsync;
+	} else {
+		kring->nm_sync = netmap_monitor_parent_rxsync;
+		kring->nm_notify = netmap_monitor_parent_notify;
+		kring->mon_tail = kring->nr_hwtail;
+	}
+}
+
+static void
+nm_monitor_restore_callbacks(struct netmap_kring *kring)
+{
+	ND("restoring callbacks on %s", kring->name);
+	kring->nm_sync = kring->mon_sync;
+	kring->mon_sync = NULL;
+	if (kring->tx == NR_RX) {
+		kring->nm_notify = kring->mon_notify;
+	}
+	kring->mon_notify = NULL;
+}
+
 /* add the monitor mkring to the list of monitors of kring.
  * If this is the first monitor, intercept the callbacks
  */
@@ -265,17 +292,8 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 	nm_kr_stop(kring, NM_KR_LOCKED);
 
 	if (nm_monitor_none(kring)) {
-		/* this is the first monitor, intercept callbacks */
-		ND("intercept callbacks on %s", kring->name);
-		kring->mon_sync = kring->nm_sync;
-		kring->mon_notify = kring->nm_notify;
-		if (kring->tx == NR_TX) {
-			kring->nm_sync = netmap_monitor_parent_txsync;
-		} else {
-			kring->nm_sync = netmap_monitor_parent_rxsync;
-			kring->nm_notify = netmap_monitor_parent_notify;
-			kring->mon_tail = kring->nr_hwtail;
-		}
+		/* this is the first monitor, intercept the callbacks */
+		nm_monitor_intercept_callbacks(kring);
 	}
 
 	if (zmon) {
@@ -336,11 +354,13 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring)
 			mz->prev->zmon_list[kring->tx].next = mz->next;
 		else
 			kring->zmon_list[kring->tx].next = mz->next;
+		mz->prev = NULL;
 		if (mz->next != NULL) {
 			mz->next->zmon_list[kring->tx].prev = mz->prev;
 		} else {
 			kring->zmon_list[kring->tx].prev = mz->prev;
 		}
+		mz->next = NULL;
 	} else {
 		/* this is a copy monitor */
 		uint32_t mon_pos = mkring->mon_pos[kring->tx];
@@ -358,16 +378,7 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring)
 
 	if (nm_monitor_none(kring)) {
 		/* this was the last monitor, restore the callbacks */
-		ND("%s: restoring sync on %s: %p", mkring->name, kring->name,
-				kring->mon_sync);
-		kring->nm_sync = kring->mon_sync;
-		kring->mon_sync = NULL;
-		if (kring->tx == NR_RX) {
-			ND("%s: restoring notify on %s: %p",
-					mkring->name, kring->name, kring->mon_notify);
-			kring->nm_notify = kring->mon_notify;
-			kring->mon_notify = NULL;
-		}
+		nm_monitor_restore_callbacks(kring);
 	}
 
 	nm_kr_start(kring);
@@ -404,29 +415,40 @@ netmap_monitor_stop(struct netmap_adapter *na)
 					netmap_adapter_put(mna->priv.np_na);
 					mna->priv.np_na = NULL;
 				}
+				kring->monitors[j] = NULL;
 			}
 
 			zkring = kring->zmon_list[kring->tx].next;
 			if (zkring != NULL) {
 				struct netmap_monitor_adapter *next =
 					(struct netmap_monitor_adapter *)zkring->na;
-				struct netmap_monitor_adapter *this =
-						(struct netmap_monitor_adapter *)na;
-				struct netmap_adapter *pna = this->priv.np_na;
 				/* let the next monitor forget about us */
 				if (next->priv.np_na != NULL) {
 					netmap_adapter_put(next->priv.np_na);
+					next->priv.np_na = NULL;
 				}
-				if (pna != NULL && nm_is_zmon(na)) {
+				if (nm_is_zmon(na)) {
+					struct netmap_monitor_adapter *this =
+							(struct netmap_monitor_adapter *)na;
+					struct netmap_adapter *pna = this->priv.np_na;
 					/* we are a monitor ourselves and we may
 					 * need to pass down the reference to
 					 * the previous adapter in the chain
 					 */
-					netmap_adapter_get(pna);
-					next->priv.np_na = pna;
-					continue;
+					if (pna != NULL) {
+						netmap_adapter_get(pna);
+						next->priv.np_na = pna;
+					}
 				}
-				next->priv.np_na = NULL;
+			}
+
+			if (!nm_monitor_none(kring)) {
+				struct netmap_zmon_list *z = &kring->zmon_list[t];
+
+				z->next = z->prev = NULL;
+				kring->n_monitors = 0;
+				nm_monitor_dealloc(kring);
+				nm_monitor_restore_callbacks(kring);
 			}
 		}
 	}

From f11f502f6e5d298093d64cbc2f7f5fdda728559c Mon Sep 17 00:00:00 2001
From: Pad 
Date: Tue, 26 Jun 2018 18:00:42 +0200
Subject: [PATCH 0912/2207] update README.ptnetmap

---
 README.ptnetmap | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/README.ptnetmap b/README.ptnetmap
index c082c4440..e2e7b80e8 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap
@@ -44,10 +44,15 @@ and in section 7 of this document.
 2. Configure Linux host and QEMU for ptnetmap
 ---------------------------------------------------------------------------
 
+(Warning! For ptnetmap use v11.4.
+In the current master, ptnetmap is disabled.
+Support for the current master will be re-added as soon as possible)
+
 On the Linux host, configure, build and install netmap with ptnetmap support:
 
     $ git clone https://github.com/luigirizzo/netmap.git
     $ cd netmap
+    $ git checkout v11.4
     $ ./configure --enable-ptnetmap [other options]
     $ make
     $ sudo make install
@@ -55,7 +60,8 @@ On the Linux host, configure, build and install netmap with ptnetmap support:
 Download, build and install the ptnetmap-enabled QEMU:
 
     $ git clone https://github.com/vmaffione/qemu
-    $ ./configure --target-list=x86_64-softmmu --enable-kvm --enable-vhost-net --disable-werror --enable-netmap --enable-ptnetmap
+    $ cd qemu
+    $ ./configure --target-list=x86_64-softmmu --enable-kvm --enable-vhost-net --disable-werror --enable-netmap
     $ make
     $ sudo make install
 
@@ -257,4 +263,3 @@ are used for guest-to-host notifications.
 The ptnetmap kthread infrastructure, moreover, has been already extended to
 suppor an arbitrary number of rings, where currently each ring is served
 by a different kernel thread.
-

From d22f604ec295988541a8b1ed011559ac04a1159d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jun 2018 18:59:05 +0200
Subject: [PATCH 0913/2207] pipe: don't rely on nr_hwcur during cleanup

---
 sys/dev/netmap/netmap_pipe.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 2d874cf09..202cb00ac 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -566,10 +566,10 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 			if (ring == NULL)
 				continue;
 
-			if (kring->nr_hwtail == kring->nr_hwcur)
-				ring->slot[kring->nr_hwtail].buf_idx = 0;
+			if (kring->pipe_tail == kring->nr_hwcur)
+				ring->slot[kring->pipe_tail].buf_idx = 0;
 
-			for (j = nm_next(kring->nr_hwtail, lim);
+			for (j = nm_next(kring->pipe_tail, lim);
 			     j != kring->nr_hwcur;
 			     j = nm_next(j, lim))
 			{

From 7a1f63ea3f57d5e1c30cbdbd3aee9ed23f72a409 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 27 Jun 2018 17:42:34 +0200
Subject: [PATCH 0914/2207] vale: split out (future) common bridge abstractions
 to netmap_bdg.*

---
 LINUX/Kbuild.in              |    2 +-
 sys/dev/netmap/netmap_bdg.c  | 1911 +++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_bdg.h  |  128 +++
 sys/dev/netmap/netmap_vale.c | 1946 +---------------------------------
 4 files changed, 2052 insertions(+), 1935 deletions(-)
 create mode 100644 sys/dev/netmap/netmap_bdg.c
 create mode 100644 sys/dev/netmap/netmap_bdg.h

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index 2617e7502..1fb190940 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,7 +8,7 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
new file mode 100644
index 000000000..8115f4ea5
--- /dev/null
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -0,0 +1,1911 @@
+/*
+ * Copyright (C) 2013-2016 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/*
+ * This module implements the VALE switch for netmap
+
+--- VALE SWITCH ---
+
+NMG_LOCK() serializes all modifications to switches and ports.
+A switch cannot be deleted until all ports are gone.
+
+For each switch, an SX lock (RWlock on linux) protects
+deletion of ports. When configuring or deleting a new port, the
+lock is acquired in exclusive mode (after holding NMG_LOCK).
+When forwarding, the lock is acquired in shared mode (without NMG_LOCK).
+The lock is held throughout the entire forwarding cycle,
+during which the thread may incur in a page fault.
+Hence it is important that sleepable shared locks are used.
+
+On the rx ring, the per-port lock is grabbed initially to reserve
+a number of slot in the ring, then the lock is released,
+packets are copied from source to destination, and then
+the lock is acquired again and the receive ring is updated.
+(A similar thing is done on the tx ring for NIC and host stack
+ports attached to the switch)
+
+ */
+
+/*
+ * OS-specific code that is used only within this file.
+ * Other OS-specific code that must be accessed by drivers
+ * is present in netmap_kern.h
+ */
+
+#if defined(__FreeBSD__)
+#include  /* prerequisite */
+__FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z glebius $");
+
+#include 
+#include 
+#include 	/* defines used in kernel.h */
+#include 	/* types used in module initialization */
+#include 	/* cdevsw struct, UID, GID */
+#include 
+#include 	/* struct socket */
+#include 
+#include 
+#include 
+#include  /* sockaddrs */
+#include 
+#include 
+#include 
+#include 
+#include 		/* BIOCIMMEDIATE */
+#include 	/* bus_dmamap_* */
+#include 
+#include 
+#include 
+
+
+#elif defined(linux)
+
+#include "bsd_glue.h"
+
+#elif defined(__APPLE__)
+
+#warning OSX support is only partial
+#include "osx_glue.h"
+
+#elif defined(_WIN32)
+#include "win_glue.h"
+
+#else
+
+#error	Unsupported platform
+
+#endif /* unsupported */
+
+/*
+ * common headers
+ */
+
+#include 
+#include 
+#include 
+
+#ifdef WITH_VALE
+#include 
+
+const char*
+netmap_bdg_name(struct netmap_vp_adapter *vp)
+{
+	struct nm_bridge *b = vp->na_bdg;
+	if (b == NULL)
+		return NULL;
+	return b->bdg_basename;
+}
+
+
+#ifndef CONFIG_NET_NS
+/*
+ * XXX in principle nm_bridges could be created dynamically
+ * Right now we have a static array and deletions are protected
+ * by an exclusive lock.
+ */
+static struct nm_bridge *nm_bridges;
+#endif /* !CONFIG_NET_NS */
+
+
+static int
+nm_is_id_char(const char c)
+{
+	return (c >= 'a' && c <= 'z') ||
+	       (c >= 'A' && c <= 'Z') ||
+	       (c >= '0' && c <= '9') ||
+	       (c == '_');
+}
+
+/* Validate the name of a VALE bridge port and return the
+ * position of the ":" character. */
+static int
+nm_vale_name_validate(const char *name)
+{
+	int colon_pos = -1;
+	int i;
+
+	if (!name || strlen(name) < strlen(NM_BDG_NAME)) {
+		return -1;
+	}
+
+	for (i = 0; i < NM_BDG_IFNAMSIZ && name[i]; i++) {
+		if (name[i] == ':') {
+			colon_pos = i;
+			break;
+		} else if (!nm_is_id_char(name[i])) {
+			return -1;
+		}
+	}
+
+	if (strlen(name) - colon_pos > IFNAMSIZ) {
+		/* interface name too long */
+		return -1;
+	}
+
+	return colon_pos;
+}
+
+/*
+ * locate a bridge among the existing ones.
+ * MUST BE CALLED WITH NMG_LOCK()
+ *
+ * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME.
+ * We assume that this is called with a name of at least NM_NAME chars.
+ */
+struct nm_bridge *
+nm_find_bridge(const char *name, int create)
+{
+	int i, namelen;
+	struct nm_bridge *b = NULL, *bridges;
+	u_int num_bridges;
+
+	NMG_LOCK_ASSERT();
+
+	netmap_bns_getbridges(&bridges, &num_bridges);
+
+	namelen = nm_vale_name_validate(name);
+	if (namelen < 0) {
+		D("invalid bridge name %s", name ? name : NULL);
+		return NULL;
+	}
+
+	/* lookup the name, remember empty slot if there is one */
+	for (i = 0; i < num_bridges; i++) {
+		struct nm_bridge *x = bridges + i;
+
+		if ((x->bdg_flags & NM_BDG_ACTIVE) + x->bdg_active_ports == 0) {
+			if (create && b == NULL)
+				b = x;	/* record empty slot */
+		} else if (x->bdg_namelen != namelen) {
+			continue;
+		} else if (strncmp(name, x->bdg_basename, namelen) == 0) {
+			ND("found '%.*s' at %d", namelen, name, i);
+			b = x;
+			break;
+		}
+	}
+	if (i == num_bridges && b) { /* name not found, can create entry */
+		/* initialize the bridge */
+		ND("create new bridge %s with ports %d", b->bdg_basename,
+			b->bdg_active_ports);
+		b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+		if (b->ht == NULL) {
+			D("failed to allocate hash table");
+			return NULL;
+		}
+		strncpy(b->bdg_basename, name, namelen);
+		b->bdg_namelen = namelen;
+		b->bdg_active_ports = 0;
+		for (i = 0; i < NM_BDG_MAXPORTS; i++)
+			b->bdg_port_index[i] = i;
+		/* set the default function */
+		b->bdg_ops = &default_bdg_ops;
+		b->private_data = b->ht;
+		b->bdg_flags = 0;
+		NM_BNS_GET(b);
+	}
+	return b;
+}
+
+
+static int
+netmap_bdg_free(struct nm_bridge *b)
+{
+	if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) {
+		return EBUSY;
+	}
+
+	ND("marking bridge %s as free", b->bdg_basename);
+	nm_os_free(b->ht);
+	b->bdg_ops = NULL;
+	b->bdg_flags = 0;
+	NM_BNS_PUT(b);
+	return 0;
+}
+
+
+/* remove from bridge b the ports in slots hw and sw
+ * (sw can be -1 if not needed)
+ */
+void
+netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
+{
+	int s_hw = hw, s_sw = sw;
+	int i, lim =b->bdg_active_ports;
+	uint32_t *tmp = b->tmp_bdg_port_index;
+
+	/*
+	New algorithm:
+	make a copy of bdg_port_index;
+	lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port
+	in the array of bdg_port_index, replacing them with
+	entries from the bottom of the array;
+	decrement bdg_active_ports;
+	acquire BDG_WLOCK() and copy back the array.
+	 */
+
+	if (netmap_verbose)
+		D("detach %d and %d (lim %d)", hw, sw, lim);
+	/* make a copy of the list of active ports, update it,
+	 * and then copy back within BDG_WLOCK().
+	 */
+	memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index));
+	for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) {
+		if (hw >= 0 && tmp[i] == hw) {
+			ND("detach hw %d at %d", hw, i);
+			lim--; /* point to last active port */
+			tmp[i] = tmp[lim]; /* swap with i */
+			tmp[lim] = hw;	/* now this is inactive */
+			hw = -1;
+		} else if (sw >= 0 && tmp[i] == sw) {
+			ND("detach sw %d at %d", sw, i);
+			lim--;
+			tmp[i] = tmp[lim];
+			tmp[lim] = sw;
+			sw = -1;
+		} else {
+			i++;
+		}
+	}
+	if (hw >= 0 || sw >= 0) {
+		D("XXX delete failed hw %d sw %d, should panic...", hw, sw);
+	}
+
+	BDG_WLOCK(b);
+	if (b->bdg_ops->dtor)
+		b->bdg_ops->dtor(b->bdg_ports[s_hw]);
+	b->bdg_ports[s_hw] = NULL;
+	if (s_sw >= 0) {
+		b->bdg_ports[s_sw] = NULL;
+	}
+	memcpy(b->bdg_port_index, b->tmp_bdg_port_index, sizeof(b->tmp_bdg_port_index));
+	b->bdg_active_ports = lim;
+	BDG_WUNLOCK(b);
+
+	ND("now %d active ports", lim);
+	netmap_bdg_free(b);
+}
+
+/* Allows external modules to create bridges in exclusive mode,
+ * returns an authentication token that the external module will need
+ * to provide during nm_bdg_ctl_{attach, detach}(), netmap_bdg_regops(),
+ * and nm_bdg_update_private_data() operations.
+ * Successfully executed if ret != NULL and *return_status == 0.
+ */
+void *
+netmap_bdg_create(const char *bdg_name, int *return_status)
+{
+	struct nm_bridge *b = NULL;
+	void *ret = NULL;
+
+	NMG_LOCK();
+	b = nm_find_bridge(bdg_name, 0 /* don't create */);
+	if (b) {
+		*return_status = EEXIST;
+		goto unlock_bdg_create;
+	}
+
+	b = nm_find_bridge(bdg_name, 1 /* create */);
+	if (!b) {
+		*return_status = ENOMEM;
+		goto unlock_bdg_create;
+	}
+
+	b->bdg_flags |= NM_BDG_ACTIVE | NM_BDG_EXCLUSIVE;
+	ret = nm_bdg_get_auth_token(b);
+	*return_status = 0;
+
+unlock_bdg_create:
+	NMG_UNLOCK();
+	return ret;
+}
+
+/* Allows external modules to destroy a bridge created through
+ * netmap_bdg_create(), the bridge must be empty.
+ */
+int
+netmap_bdg_destroy(const char *bdg_name, void *auth_token)
+{
+	struct nm_bridge *b = NULL;
+	int ret = 0;
+
+	NMG_LOCK();
+	b = nm_find_bridge(bdg_name, 0 /* don't create */);
+	if (!b) {
+		ret = ENXIO;
+		goto unlock_bdg_free;
+	}
+
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		ret = EACCES;
+		goto unlock_bdg_free;
+	}
+	if (!(b->bdg_flags & NM_BDG_EXCLUSIVE)) {
+		ret = EINVAL;
+		goto unlock_bdg_free;
+	}
+
+	b->bdg_flags &= ~(NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE);
+	ret = netmap_bdg_free(b);
+	if (ret) {
+		b->bdg_flags |= NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE;
+	}
+
+unlock_bdg_free:
+	NMG_UNLOCK();
+	return ret;
+}
+
+
+
+/* nm_bdg_ctl callback for VALE ports */
+int
+netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
+{
+	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
+	struct nm_bridge *b = vpna->na_bdg;
+
+	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+		return 0; /* nothing to do */
+	}
+	if (b) {
+		netmap_set_all_rings(na, 0 /* disable */);
+		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
+		vpna->na_bdg = NULL;
+		netmap_set_all_rings(na, 1 /* enable */);
+	}
+	/* I have took reference just for attach */
+	netmap_adapter_put(na);
+	return 0;
+}
+
+
+/* Try to get a reference to a netmap adapter attached to a VALE switch.
+ * If the adapter is found (or is created), this function returns 0, a
+ * non NULL pointer is returned into *na, and the caller holds a
+ * reference to the adapter.
+ * If an adapter is not found, then no reference is grabbed and the
+ * function returns an error code, or 0 if there is just a VALE prefix
+ * mismatch. Therefore the caller holds a reference when
+ * (*na != NULL && return == 0).
+ */
+int
+netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create)
+{
+	char *nr_name = hdr->nr_name;
+	const char *ifname;
+	struct ifnet *ifp = NULL;
+	int error = 0;
+	struct netmap_vp_adapter *vpna, *hostna = NULL;
+	struct nm_bridge *b;
+	uint32_t i, j;
+	uint32_t cand = NM_BDG_NOPORT, cand2 = NM_BDG_NOPORT;
+	int needed;
+
+	*na = NULL;     /* default return value */
+
+	/* first try to see if this is a bridge port. */
+	NMG_LOCK_ASSERT();
+	if (strncmp(nr_name, NM_BDG_NAME, sizeof(NM_BDG_NAME) - 1)) {
+		return 0;  /* no error, but no VALE prefix */
+	}
+
+	b = nm_find_bridge(nr_name, create);
+	if (b == NULL) {
+		ND("no bridges available for '%s'", nr_name);
+		return (create ? ENOMEM : ENXIO);
+	}
+	if (strlen(nr_name) < b->bdg_namelen) /* impossible */
+		panic("x");
+
+	/* Now we are sure that name starts with the bridge's name,
+	 * lookup the port in the bridge. We need to scan the entire
+	 * list. It is not important to hold a WLOCK on the bridge
+	 * during the search because NMG_LOCK already guarantees
+	 * that there are no other possible writers.
+	 */
+
+	/* lookup in the local list of ports */
+	for (j = 0; j < b->bdg_active_ports; j++) {
+		i = b->bdg_port_index[j];
+		vpna = b->bdg_ports[i];
+		ND("checking %s", vpna->up.name);
+		if (!strcmp(vpna->up.name, nr_name)) {
+			netmap_adapter_get(&vpna->up);
+			ND("found existing if %s refs %d", nr_name)
+			*na = &vpna->up;
+			return 0;
+		}
+	}
+	/* not found, should we create it? */
+	if (!create)
+		return ENXIO;
+	/* yes we should, see if we have space to attach entries */
+	needed = 2; /* in some cases we only need 1 */
+	if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) {
+		D("bridge full %d, cannot create new port", b->bdg_active_ports);
+		return ENOMEM;
+	}
+	/* record the next two ports available, but do not allocate yet */
+	cand = b->bdg_port_index[b->bdg_active_ports];
+	cand2 = b->bdg_port_index[b->bdg_active_ports + 1];
+	ND("+++ bridge %s port %s used %d avail %d %d",
+		b->bdg_basename, ifname, b->bdg_active_ports, cand, cand2);
+
+	/*
+	 * try see if there is a matching NIC with this name
+	 * (after the bridge's name)
+	 */
+	ifname = nr_name + b->bdg_namelen + 1;
+	ifp = ifunit_ref(ifname);
+	if (!ifp) {
+		/* Create an ephemeral virtual port.
+		 * This block contains all the ephemeral-specific logic.
+		 */
+
+		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+			error = EINVAL;
+			goto out;
+		}
+
+		/* bdg_netmap_attach creates a struct netmap_adapter */
+		error = netmap_vp_create(hdr, NULL, nmd, &vpna);
+		if (error) {
+			D("error %d", error);
+			goto out;
+		}
+		/* shortcut - we can skip get_hw_na(),
+		 * ownership check and nm_bdg_attach()
+		 */
+
+	} else {
+		struct netmap_adapter *hw;
+
+		/* the vale:nic syntax is only valid for some commands */
+		switch (hdr->nr_reqtype) {
+		case NETMAP_REQ_VALE_ATTACH:
+		case NETMAP_REQ_VALE_DETACH:
+		case NETMAP_REQ_VALE_POLLING_ENABLE:
+		case NETMAP_REQ_VALE_POLLING_DISABLE:
+			break; /* ok */
+		default:
+			error = EINVAL;
+			goto out;
+		}
+
+		error = netmap_get_hw_na(ifp, nmd, &hw);
+		if (error || hw == NULL)
+			goto out;
+
+		/* host adapter might not be created */
+		error = hw->nm_bdg_attach(nr_name, hw);
+		if (error)
+			goto out;
+		vpna = hw->na_vp;
+		hostna = hw->na_hostvp;
+		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+			/* Check if we need to skip the host rings. */
+			struct nmreq_vale_attach *areq =
+				(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
+			if (areq->reg.nr_mode != NR_REG_NIC_SW) {
+				hostna = NULL;
+			}
+		}
+	}
+
+	BDG_WLOCK(b);
+	vpna->bdg_port = cand;
+	ND("NIC  %p to bridge port %d", vpna, cand);
+	/* bind the port to the bridge (virtual ports are not active) */
+	b->bdg_ports[cand] = vpna;
+	vpna->na_bdg = b;
+	b->bdg_active_ports++;
+	if (hostna != NULL) {
+		/* also bind the host stack to the bridge */
+		b->bdg_ports[cand2] = hostna;
+		hostna->bdg_port = cand2;
+		hostna->na_bdg = b;
+		b->bdg_active_ports++;
+		ND("host %p to bridge port %d", hostna, cand2);
+	}
+	ND("if %s refs %d", ifname, vpna->up.na_refcount);
+	BDG_WUNLOCK(b);
+	*na = &vpna->up;
+	netmap_adapter_get(*na);
+
+out:
+	if (ifp)
+		if_rele(ifp);
+
+	return error;
+}
+
+/* Process NETMAP_REQ_VALE_ATTACH.
+ */
+int
+nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
+{
+	struct nmreq_vale_attach *req =
+		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
+	struct netmap_vp_adapter * vpna;
+	struct netmap_adapter *na;
+	struct netmap_mem_d *nmd = NULL;
+	struct nm_bridge *b = NULL;
+	int error;
+
+	NMG_LOCK();
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_exit;
+	}
+
+	if (req->reg.nr_mem_id) {
+		nmd = netmap_mem_find(req->reg.nr_mem_id);
+		if (nmd == NULL) {
+			error = EINVAL;
+			goto unlock_exit;
+		}
+	}
+
+	/* check for existing one */
+	error = netmap_get_bdg_na(hdr, &na, nmd, 0);
+	if (!error) {
+		error = EBUSY;
+		goto unref_exit;
+	}
+	error = netmap_get_bdg_na(hdr, &na,
+				nmd, 1 /* create if not exists */);
+	if (error) { /* no device */
+		goto unlock_exit;
+	}
+
+	if (na == NULL) { /* VALE prefix missing */
+		error = EINVAL;
+		goto unlock_exit;
+	}
+
+	if (NETMAP_OWNED_BY_ANY(na)) {
+		error = EBUSY;
+		goto unref_exit;
+	}
+
+	if (na->nm_bdg_ctl) {
+		/* nop for VALE ports. The bwrap needs to put the hwna
+		 * in netmap mode (see netmap_bwrap_bdg_ctl)
+		 */
+		error = na->nm_bdg_ctl(hdr, na);
+		if (error)
+			goto unref_exit;
+		ND("registered %s to netmap-mode", na->name);
+	}
+	vpna = (struct netmap_vp_adapter *)na;
+	req->port_index = vpna->bdg_port;
+	NMG_UNLOCK();
+	return 0;
+
+unref_exit:
+	netmap_adapter_put(na);
+unlock_exit:
+	NMG_UNLOCK();
+	return error;
+}
+
+static inline int
+nm_is_bwrap(struct netmap_adapter *na)
+{
+	return na->nm_register == netmap_bwrap_reg;
+}
+
+/* Process NETMAP_REQ_VALE_DETACH.
+ */
+int
+nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
+{
+	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
+	struct netmap_vp_adapter *vpna;
+	struct netmap_adapter *na;
+	struct nm_bridge *b = NULL;
+	int error;
+
+	NMG_LOCK();
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_exit;
+	}
+
+	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */);
+	if (error) { /* no device, or another bridge or user owns the device */
+		goto unlock_exit;
+	}
+
+	if (na == NULL) { /* VALE prefix missing */
+		error = EINVAL;
+		goto unlock_exit;
+	} else if (nm_is_bwrap(na) &&
+		   ((struct netmap_bwrap_adapter *)na)->na_polling_state) {
+		/* Don't detach a NIC with polling */
+		error = EBUSY;
+		goto unref_exit;
+	}
+
+	vpna = (struct netmap_vp_adapter *)na;
+	if (na->na_vp != vpna) {
+		/* trying to detach first attach of VALE persistent port attached
+		 * to 2 bridges
+		 */
+		error = EBUSY;
+		goto unref_exit;
+	}
+	nmreq_det->port_index = vpna->bdg_port;
+
+	if (na->nm_bdg_ctl) {
+		/* remove the port from bridge. The bwrap
+		 * also needs to put the hwna in normal mode
+		 */
+		error = na->nm_bdg_ctl(hdr, na);
+	}
+
+unref_exit:
+	netmap_adapter_put(na);
+unlock_exit:
+	NMG_UNLOCK();
+	return error;
+
+}
+
+struct nm_bdg_polling_state;
+struct
+nm_bdg_kthread {
+	struct nm_kctx *nmk;
+	u_int qfirst;
+	u_int qlast;
+	struct nm_bdg_polling_state *bps;
+};
+
+struct nm_bdg_polling_state {
+	bool configured;
+	bool stopped;
+	struct netmap_bwrap_adapter *bna;
+	uint32_t mode;
+	u_int qfirst;
+	u_int qlast;
+	u_int cpu_from;
+	u_int ncpus;
+	struct nm_bdg_kthread *kthreads;
+};
+
+static void
+netmap_bwrap_polling(void *data, int is_kthread)
+{
+	struct nm_bdg_kthread *nbk = data;
+	struct netmap_bwrap_adapter *bna;
+	u_int qfirst, qlast, i;
+	struct netmap_kring **kring0, *kring;
+
+	if (!nbk)
+		return;
+	qfirst = nbk->qfirst;
+	qlast = nbk->qlast;
+	bna = nbk->bps->bna;
+	kring0 = NMR(bna->hwna, NR_RX);
+
+	for (i = qfirst; i < qlast; i++) {
+		kring = kring0[i];
+		kring->nm_notify(kring, 0);
+	}
+}
+
+static int
+nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
+{
+	struct nm_kctx_cfg kcfg;
+	int i, j;
+
+	bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus);
+	if (bps->kthreads == NULL)
+		return ENOMEM;
+
+	bzero(&kcfg, sizeof(kcfg));
+	kcfg.worker_fn = netmap_bwrap_polling;
+	kcfg.use_kthread = 1;
+	for (i = 0; i < bps->ncpus; i++) {
+		struct nm_bdg_kthread *t = bps->kthreads + i;
+		int all = (bps->ncpus == 1 &&
+			bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU);
+		int affinity = bps->cpu_from + i;
+
+		t->bps = bps;
+		t->qfirst = all ? bps->qfirst /* must be 0 */: affinity;
+		t->qlast = all ? bps->qlast : t->qfirst + 1;
+		D("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst,
+			t->qlast);
+
+		kcfg.type = i;
+		kcfg.worker_private = t;
+		t->nmk = nm_os_kctx_create(&kcfg, NULL);
+		if (t->nmk == NULL) {
+			goto cleanup;
+		}
+		nm_os_kctx_worker_setaff(t->nmk, affinity);
+	}
+	return 0;
+
+cleanup:
+	for (j = 0; j < i; j++) {
+		struct nm_bdg_kthread *t = bps->kthreads + i;
+		nm_os_kctx_destroy(t->nmk);
+	}
+	nm_os_free(bps->kthreads);
+	return EFAULT;
+}
+
+/* A variant of ptnetmap_start_kthreads() */
+static int
+nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps)
+{
+	int error, i, j;
+
+	if (!bps) {
+		D("polling is not configured");
+		return EFAULT;
+	}
+	bps->stopped = false;
+
+	for (i = 0; i < bps->ncpus; i++) {
+		struct nm_bdg_kthread *t = bps->kthreads + i;
+		error = nm_os_kctx_worker_start(t->nmk);
+		if (error) {
+			D("error in nm_kthread_start()");
+			goto cleanup;
+		}
+	}
+	return 0;
+
+cleanup:
+	for (j = 0; j < i; j++) {
+		struct nm_bdg_kthread *t = bps->kthreads + i;
+		nm_os_kctx_worker_stop(t->nmk);
+	}
+	bps->stopped = true;
+	return error;
+}
+
+static void
+nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps)
+{
+	int i;
+
+	if (!bps)
+		return;
+
+	for (i = 0; i < bps->ncpus; i++) {
+		struct nm_bdg_kthread *t = bps->kthreads + i;
+		nm_os_kctx_worker_stop(t->nmk);
+		nm_os_kctx_destroy(t->nmk);
+	}
+	bps->stopped = true;
+}
+
+static int
+get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
+		struct nm_bdg_polling_state *bps)
+{
+	unsigned int avail_cpus, core_from;
+	unsigned int qfirst, qlast;
+	uint32_t i = req->nr_first_cpu_id;
+	uint32_t req_cpus = req->nr_num_polling_cpus;
+
+	avail_cpus = nm_os_ncpus();
+
+	if (req_cpus == 0) {
+		D("req_cpus must be > 0");
+		return EINVAL;
+	} else if (req_cpus >= avail_cpus) {
+		D("Cannot use all the CPUs in the system");
+		return EINVAL;
+	}
+
+	if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) {
+		/* Use a separate core for each ring. If nr_num_polling_cpus>1
+		 * more consecutive rings are polled.
+		 * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2,
+		 * ring 2 and 3 are polled by core 2 and 3, respectively. */
+		if (i + req_cpus > nma_get_nrings(na, NR_RX)) {
+			D("Rings %u-%u not in range (have %d rings)",
+				i, i + req_cpus, nma_get_nrings(na, NR_RX));
+			return EINVAL;
+		}
+		qfirst = i;
+		qlast = qfirst + req_cpus;
+		core_from = qfirst;
+
+	} else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) {
+		/* Poll all the rings using a core specified by nr_first_cpu_id.
+		 * the number of cores must be 1. */
+		if (req_cpus != 1) {
+			D("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
+				"(was %d)", req_cpus);
+			return EINVAL;
+		}
+		qfirst = 0;
+		qlast = nma_get_nrings(na, NR_RX);
+		core_from = i;
+	} else {
+		D("Invalid polling mode");
+		return EINVAL;
+	}
+
+	bps->mode = req->nr_mode;
+	bps->qfirst = qfirst;
+	bps->qlast = qlast;
+	bps->cpu_from = core_from;
+	bps->ncpus = req_cpus;
+	D("%s qfirst %u qlast %u cpu_from %u ncpus %u",
+		req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ?
+		"MULTI" : "SINGLE",
+		qfirst, qlast, core_from, req_cpus);
+	return 0;
+}
+
+static int
+nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na)
+{
+	struct nm_bdg_polling_state *bps;
+	struct netmap_bwrap_adapter *bna;
+	int error;
+
+	bna = (struct netmap_bwrap_adapter *)na;
+	if (bna->na_polling_state) {
+		D("ERROR adapter already in polling mode");
+		return EFAULT;
+	}
+
+	bps = nm_os_malloc(sizeof(*bps));
+	if (!bps)
+		return ENOMEM;
+	bps->configured = false;
+	bps->stopped = true;
+
+	if (get_polling_cfg(req, na, bps)) {
+		nm_os_free(bps);
+		return EINVAL;
+	}
+
+	if (nm_bdg_create_kthreads(bps)) {
+		nm_os_free(bps);
+		return EFAULT;
+	}
+
+	bps->configured = true;
+	bna->na_polling_state = bps;
+	bps->bna = bna;
+
+	/* disable interrupts if possible */
+	nma_intr_enable(bna->hwna, 0);
+	/* start kthread now */
+	error = nm_bdg_polling_start_kthreads(bps);
+	if (error) {
+		D("ERROR nm_bdg_polling_start_kthread()");
+		nm_os_free(bps->kthreads);
+		nm_os_free(bps);
+		bna->na_polling_state = NULL;
+		nma_intr_enable(bna->hwna, 1);
+	}
+	return error;
+}
+
+static int
+nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
+{
+	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na;
+	struct nm_bdg_polling_state *bps;
+
+	if (!bna->na_polling_state) {
+		D("ERROR adapter is not in polling mode");
+		return EFAULT;
+	}
+	bps = bna->na_polling_state;
+	nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state);
+	bps->configured = false;
+	nm_os_free(bps);
+	bna->na_polling_state = NULL;
+	/* reenable interrupts */
+	nma_intr_enable(bna->hwna, 1);
+	return 0;
+}
+
+int
+nm_bdg_polling(struct nmreq_header *hdr)
+{
+	struct nmreq_vale_polling *req =
+		(struct nmreq_vale_polling *)(uintptr_t)hdr->nr_body;
+	struct netmap_adapter *na = NULL;
+	int error = 0;
+
+	NMG_LOCK();
+	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0);
+	if (na && !error) {
+		if (!nm_is_bwrap(na)) {
+			error = EOPNOTSUPP;
+		} else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) {
+			error = nm_bdg_ctl_polling_start(req, na);
+			if (!error)
+				netmap_adapter_get(na);
+		} else {
+			error = nm_bdg_ctl_polling_stop(na);
+			if (!error)
+				netmap_adapter_put(na);
+		}
+		netmap_adapter_put(na);
+	} else if (!na && !error) {
+		/* Not VALE port. */
+		error = EINVAL;
+	}
+	NMG_UNLOCK();
+
+	return error;
+}
+
+/* Process NETMAP_REQ_VALE_LIST. */
+int
+netmap_bdg_list(struct nmreq_header *hdr)
+{
+	struct nmreq_vale_list *req =
+		(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
+	int namelen = strlen(hdr->nr_name);
+	struct nm_bridge *b, *bridges;
+	struct netmap_vp_adapter *vpna;
+	int error = 0, i, j;
+	u_int num_bridges;
+
+	netmap_bns_getbridges(&bridges, &num_bridges);
+
+	/* this is used to enumerate bridges and ports */
+	if (namelen) { /* look up indexes of bridge and port */
+		if (strncmp(hdr->nr_name, NM_BDG_NAME,
+					strlen(NM_BDG_NAME))) {
+			return EINVAL;
+		}
+		NMG_LOCK();
+		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+		if (!b) {
+			NMG_UNLOCK();
+			return ENOENT;
+		}
+
+		req->nr_bridge_idx = b - bridges; /* bridge index */
+		req->nr_port_idx = NM_BDG_NOPORT;
+		for (j = 0; j < b->bdg_active_ports; j++) {
+			i = b->bdg_port_index[j];
+			vpna = b->bdg_ports[i];
+			if (vpna == NULL) {
+				D("This should not happen");
+				continue;
+			}
+			/* the former and the latter identify a
+			 * virtual port and a NIC, respectively
+			 */
+			if (!strcmp(vpna->up.name, hdr->nr_name)) {
+				req->nr_port_idx = i; /* port index */
+				break;
+			}
+		}
+		NMG_UNLOCK();
+	} else {
+		/* return the first non-empty entry starting from
+		 * bridge nr_arg1 and port nr_arg2.
+		 *
+		 * Users can detect the end of the same bridge by
+		 * seeing the new and old value of nr_arg1, and can
+		 * detect the end of all the bridge by error != 0
+		 */
+		i = req->nr_bridge_idx;
+		j = req->nr_port_idx;
+
+		NMG_LOCK();
+		for (error = ENOENT; i < NM_BRIDGES; i++) {
+			b = bridges + i;
+			for ( ; j < NM_BDG_MAXPORTS; j++) {
+				if (b->bdg_ports[j] == NULL)
+					continue;
+				vpna = b->bdg_ports[j];
+				/* write back the VALE switch name */
+				strncpy(hdr->nr_name, vpna->up.name,
+					(size_t)IFNAMSIZ);
+				error = 0;
+				goto out;
+			}
+			j = 0; /* following bridges scan from 0 */
+		}
+	out:
+		req->nr_bridge_idx = i;
+		req->nr_port_idx = j;
+		NMG_UNLOCK();
+	}
+
+	return error;
+}
+
+/* Called by external kernel modules (e.g., Openvswitch).
+ * to set configure/lookup/dtor functions of a VALE instance.
+ * Register callbacks to the given bridge. 'name' may be just
+ * bridge's name (including ':' if it is not just NM_BDG_NAME).
+ *
+ * Called without NMG_LOCK.
+ */
+
+int
+netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token)
+{
+	struct nm_bridge *b;
+	int error = 0;
+
+	NMG_LOCK();
+	b = nm_find_bridge(name, 0 /* don't create */);
+	if (!b) {
+		error = ENXIO;
+		goto unlock_regops;
+	}
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_regops;
+	}
+
+	BDG_WLOCK(b);
+	if (!bdg_ops) {
+		/* resetting the bridge */
+		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
+		b->bdg_ops = &default_bdg_ops;
+		b->private_data = b->ht;
+	} else {
+		/* modifying the bridge */
+		b->private_data = private_data;
+		b->bdg_ops = bdg_ops;
+	}
+	BDG_WUNLOCK(b);
+
+unlock_regops:
+	NMG_UNLOCK();
+	return error;
+}
+
+
+int
+netmap_bdg_config(struct nm_ifreq *nr)
+{
+	struct nm_bridge *b;
+	int error = EINVAL;
+
+	NMG_LOCK();
+	b = nm_find_bridge(nr->nifr_name, 0);
+	if (!b) {
+		NMG_UNLOCK();
+		return error;
+	}
+	NMG_UNLOCK();
+	/* Don't call config() with NMG_LOCK() held */
+	BDG_RLOCK(b);
+	if (b->bdg_ops->config != NULL)
+		error = b->bdg_ops->config(nr);
+	BDG_RUNLOCK(b);
+	return error;
+}
+
+
+/* nm_register callback for VALE ports */
+int
+netmap_vp_reg(struct netmap_adapter *na, int onoff)
+{
+	struct netmap_vp_adapter *vpna =
+		(struct netmap_vp_adapter*)na;
+	enum txrx t;
+	int i;
+
+	/* persistent ports may be put in netmap mode
+	 * before being attached to a bridge
+	 */
+	if (vpna->na_bdg)
+		BDG_WLOCK(vpna->na_bdg);
+	if (onoff) {
+		for_rx_tx(t) {
+			for (i = 0; i < netmap_real_rings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+
+				if (nm_kring_pending_on(kring))
+					kring->nr_mode = NKR_NETMAP_ON;
+			}
+		}
+		if (na->active_fds == 0)
+			na->na_flags |= NAF_NETMAP_ON;
+		 /* XXX on FreeBSD, persistent VALE ports should also
+		 * toggle IFCAP_NETMAP in na->ifp (2014-03-16)
+		 */
+	} else {
+		if (na->active_fds == 0)
+			na->na_flags &= ~NAF_NETMAP_ON;
+		for_rx_tx(t) {
+			for (i = 0; i < netmap_real_rings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+
+				if (nm_kring_pending_off(kring))
+					kring->nr_mode = NKR_NETMAP_OFF;
+			}
+		}
+	}
+	if (vpna->na_bdg)
+		BDG_WUNLOCK(vpna->na_bdg);
+	return 0;
+}
+
+
+/* rxsync code used by VALE ports nm_rxsync callback and also
+ * internally by the brwap
+ */
+static int
+netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct netmap_ring *ring = kring->ring;
+	u_int nm_i, lim = kring->nkr_num_slots - 1;
+	u_int head = kring->rhead;
+	int n;
+
+	if (head > lim) {
+		D("ouch dangerous reset!!!");
+		n = netmap_ring_reinit(kring);
+		goto done;
+	}
+
+	/* First part, import newly received packets. */
+	/* actually nothing to do here, they are already in the kring */
+
+	/* Second part, skip past packets that userspace has released. */
+	nm_i = kring->nr_hwcur;
+	if (nm_i != head) {
+		/* consistency check, but nothing really important here */
+		for (n = 0; likely(nm_i != head); n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			void *addr = NMB(na, slot);
+
+			if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */
+				D("bad buffer index %d, ignore ?",
+					slot->buf_idx);
+			}
+			slot->flags &= ~NS_BUF_CHANGED;
+			nm_i = nm_next(nm_i, lim);
+		}
+		kring->nr_hwcur = head;
+	}
+
+	n = 0;
+done:
+	return n;
+}
+
+/*
+ * nm_rxsync callback for VALE ports
+ * user process reading from a VALE switch.
+ * Already protected against concurrent calls from userspace,
+ * but we must acquire the queue's lock to protect against
+ * writers on the same queue.
+ */
+int
+netmap_vp_rxsync(struct netmap_kring *kring, int flags)
+{
+	int n;
+
+	mtx_lock(&kring->q_lock);
+	n = netmap_vp_rxsync_locked(kring, flags);
+	mtx_unlock(&kring->q_lock);
+	return n;
+}
+
+
+/* nm_bdg_attach callback for VALE ports
+ * The na_vp port is this same netmap_adapter. There is no host port.
+ */
+int
+netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
+{
+	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
+
+	if (vpna->na_bdg) {
+		return netmap_bwrap_attach(name, na);
+	}
+	na->na_vp = vpna;
+	strncpy(na->name, name, sizeof(na->name));
+	na->na_hostvp = NULL;
+	return 0;
+}
+
+
+/* Bridge wrapper code (bwrap).
+ * This is used to connect a non-VALE-port netmap_adapter (hwna) to a
+ * VALE switch.
+ * The main task is to swap the meaning of tx and rx rings to match the
+ * expectations of the VALE switch code (see nm_bdg_flush).
+ *
+ * The bwrap works by interposing a netmap_bwrap_adapter between the
+ * rest of the system and the hwna. The netmap_bwrap_adapter looks like
+ * a netmap_vp_adapter to the rest the system, but, internally, it
+ * translates all callbacks to what the hwna expects.
+ *
+ * Note that we have to intercept callbacks coming from two sides:
+ *
+ *  - callbacks coming from the netmap module are intercepted by
+ *    passing around the netmap_bwrap_adapter instead of the hwna
+ *
+ *  - callbacks coming from outside of the netmap module only know
+ *    about the hwna. This, however, only happens in interrupt
+ *    handlers, where only the hwna->nm_notify callback is called.
+ *    What the bwrap does is to overwrite the hwna->nm_notify callback
+ *    with its own netmap_bwrap_intr_notify.
+ *    XXX This assumes that the hwna->nm_notify callback was the
+ *    standard netmap_notify(), as it is the case for nic adapters.
+ *    Any additional action performed by hwna->nm_notify will not be
+ *    performed by netmap_bwrap_intr_notify.
+ *
+ * Additionally, the bwrap can optionally attach the host rings pair
+ * of the wrapped adapter to a different port of the switch.
+ */
+
+
+static void
+netmap_bwrap_dtor(struct netmap_adapter *na)
+{
+	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
+	struct netmap_adapter *hwna = bna->hwna;
+	struct nm_bridge *b = bna->up.na_bdg,
+		*bh = bna->host.na_bdg;
+
+	if (bna->host.up.nm_mem)
+		netmap_mem_put(bna->host.up.nm_mem);
+
+	if (b) {
+		netmap_bdg_detach_common(b, bna->up.bdg_port,
+			    (bh ? bna->host.bdg_port : -1));
+	}
+
+	ND("na %p", na);
+	na->ifp = NULL;
+	bna->host.up.ifp = NULL;
+	hwna->na_vp = bna->saved_na_vp;
+	hwna->na_hostvp = NULL;
+	hwna->na_private = NULL;
+	hwna->na_flags &= ~NAF_BUSY;
+	netmap_adapter_put(hwna);
+
+}
+
+
+/*
+ * Intr callback for NICs connected to a bridge.
+ * Simply ignore tx interrupts (maybe we could try to recover space ?)
+ * and pass received packets from nic to the bridge.
+ *
+ * XXX TODO check locking: this is called from the interrupt
+ * handler so we should make sure that the interface is not
+ * disconnected while passing down an interrupt.
+ *
+ * Note, no user process can access this NIC or the host stack.
+ * The only part of the ring that is significant are the slots,
+ * and head/cur/tail are set from the kring as needed
+ * (part as a receive ring, part as a transmit ring).
+ *
+ * callback that overwrites the hwna notify callback.
+ * Packets come from the outside or from the host stack and are put on an
+ * hwna rx ring.
+ * The bridge wrapper then sends the packets through the bridge.
+ */
+static int
+netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct netmap_bwrap_adapter *bna = na->na_private;
+	struct netmap_kring *bkring;
+	struct netmap_vp_adapter *vpna = &bna->up;
+	u_int ring_nr = kring->ring_id;
+	int ret = NM_IRQ_COMPLETED;
+	int error;
+
+	if (netmap_verbose)
+	    D("%s %s 0x%x", na->name, kring->name, flags);
+
+	bkring = vpna->up.tx_rings[ring_nr];
+
+	/* make sure the ring is not disabled */
+	if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) {
+		return EIO;
+	}
+
+	if (netmap_verbose)
+	    D("%s head %d cur %d tail %d",  na->name,
+		kring->rhead, kring->rcur, kring->rtail);
+
+	/* simulate a user wakeup on the rx ring
+	 * fetch packets that have arrived.
+	 */
+	error = kring->nm_sync(kring, 0);
+	if (error)
+		goto put_out;
+	if (kring->nr_hwcur == kring->nr_hwtail) {
+		if (netmap_verbose)
+			D("how strange, interrupt with no packets on %s",
+			    na->name);
+		goto put_out;
+	}
+
+	/* new packets are kring->rcur to kring->nr_hwtail, and the bkring
+	 * had hwcur == bkring->rhead. So advance bkring->rhead to kring->nr_hwtail
+	 * to push all packets out.
+	 */
+	bkring->rhead = bkring->rcur = kring->nr_hwtail;
+
+	netmap_vp_txsync(bkring, flags);
+
+	/* mark all buffers as released on this ring */
+	kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail;
+	/* another call to actually release the buffers */
+	error = kring->nm_sync(kring, 0);
+
+	/* The second rxsync may have further advanced hwtail. If this happens,
+	 *  return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */
+	if (kring->rcur != kring->nr_hwtail) {
+		ret = NM_IRQ_RESCHED;
+	}
+put_out:
+	nm_kr_put(kring);
+
+	return error ? error : ret;
+}
+
+
+/* nm_register callback for bwrap */
+int
+netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
+{
+	struct netmap_bwrap_adapter *bna =
+		(struct netmap_bwrap_adapter *)na;
+	struct netmap_adapter *hwna = bna->hwna;
+	struct netmap_vp_adapter *hostna = &bna->host;
+	int error, i;
+	enum txrx t;
+
+	ND("%s %s", na->name, onoff ? "on" : "off");
+
+	if (onoff) {
+		/* netmap_do_regif has been called on the bwrap na.
+		 * We need to pass the information about the
+		 * memory allocator down to the hwna before
+		 * putting it in netmap mode
+		 */
+		hwna->na_lut = na->na_lut;
+
+		if (hostna->na_bdg) {
+			/* if the host rings have been attached to switch,
+			 * we need to copy the memory allocator information
+			 * in the hostna also
+			 */
+			hostna->up.na_lut = na->na_lut;
+		}
+
+	}
+
+	/* pass down the pending ring state information */
+	for_rx_tx(t) {
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
+			NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode =
+				NMR(na, t)[i]->nr_pending_mode;
+		}
+	}
+
+	/* forward the request to the hwna */
+	error = hwna->nm_register(hwna, onoff);
+	if (error)
+		return error;
+
+	/* copy up the current ring state information */
+	for_rx_tx(t) {
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
+			struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i];
+			NMR(na, t)[i]->nr_mode = kring->nr_mode;
+		}
+	}
+
+	/* impersonate a netmap_vp_adapter */
+	netmap_vp_reg(na, onoff);
+	if (hostna->na_bdg)
+		netmap_vp_reg(&hostna->up, onoff);
+
+	if (onoff) {
+		u_int i;
+		/* intercept the hwna nm_nofify callback on the hw rings */
+		for (i = 0; i < hwna->num_rx_rings; i++) {
+			hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
+			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
+		}
+		i = hwna->num_rx_rings; /* for safety */
+		/* save the host ring notify unconditionally */
+		for (; i < netmap_real_rings(hwna, NR_RX); i++) {
+			hwna->rx_rings[i]->save_notify =
+				hwna->rx_rings[i]->nm_notify;
+			if (hostna->na_bdg) {
+				/* also intercept the host ring notify */
+				hwna->rx_rings[i]->nm_notify =
+					netmap_bwrap_intr_notify;
+				na->tx_rings[i]->nm_sync = na->nm_txsync;
+			}
+		}
+		if (na->active_fds == 0)
+			na->na_flags |= NAF_NETMAP_ON;
+	} else {
+		u_int i;
+
+		if (na->active_fds == 0)
+			na->na_flags &= ~NAF_NETMAP_ON;
+
+		/* reset all notify callbacks (including host ring) */
+		for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) {
+			hwna->rx_rings[i]->nm_notify =
+				hwna->rx_rings[i]->save_notify;
+			hwna->rx_rings[i]->save_notify = NULL;
+		}
+		hwna->na_lut.lut = NULL;
+		hwna->na_lut.plut = NULL;
+		hwna->na_lut.objtotal = 0;
+		hwna->na_lut.objsize = 0;
+
+		/* pass ownership of the netmap rings to the hwna */
+		for_rx_tx(t) {
+			for (i = 0; i < netmap_all_rings(na, t); i++) {
+				NMR(na, t)[i]->ring = NULL;
+			}
+		}
+
+	}
+
+	return 0;
+}
+
+/* nm_config callback for bwrap */
+static int
+netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	struct netmap_bwrap_adapter *bna =
+		(struct netmap_bwrap_adapter *)na;
+	struct netmap_adapter *hwna = bna->hwna;
+	int error;
+
+	/* Forward the request to the hwna. It may happen that nobody
+	 * registered hwna yet, so netmap_mem_get_lut() may have not
+	 * been called yet. */
+	error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut);
+	if (error)
+		return error;
+	netmap_update_config(hwna);
+	/* swap the results and propagate */
+	info->num_tx_rings = hwna->num_rx_rings;
+	info->num_tx_descs = hwna->num_rx_desc;
+	info->num_rx_rings = hwna->num_tx_rings;
+	info->num_rx_descs = hwna->num_tx_desc;
+	info->rx_buf_maxsize = hwna->rx_buf_maxsize;
+
+	return 0;
+}
+
+
+/* nm_krings_create callback for bwrap */
+static int
+netmap_bwrap_krings_create(struct netmap_adapter *na)
+{
+	struct netmap_bwrap_adapter *bna =
+		(struct netmap_bwrap_adapter *)na;
+	struct netmap_adapter *hwna = bna->hwna;
+	struct netmap_adapter *hostna = &bna->host.up;
+	int i, error = 0;
+	enum txrx t;
+
+	/* impersonate a netmap_vp_adapter */
+	error = netmap_vp_krings_create(na);
+	if (error)
+		return error;
+
+	/* also create the hwna krings */
+	error = hwna->nm_krings_create(hwna);
+	if (error) {
+		goto err_del_vp_rings;
+	}
+
+	/* increment the usage counter for all the hwna krings */
+	for_rx_tx(t) {
+		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
+			NMR(hwna, t)[i]->users++;
+		}
+	}
+
+	/* now create the actual rings */
+	error = netmap_mem_rings_create(hwna);
+	if (error) {
+		goto err_dec_users;
+	}
+
+	/* cross-link the netmap rings
+	 * The original number of rings comes from hwna,
+	 * rx rings on one side equals tx rings on the other.
+	 */
+	for_rx_tx(t) {
+		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
+		for (i = 0; i < netmap_all_rings(hwna, r); i++) {
+			NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
+			NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
+		}
+	}
+
+	if (na->na_flags & NAF_HOST_RINGS) {
+		/* the hostna rings are the host rings of the bwrap.
+		 * The corresponding krings must point back to the
+		 * hostna
+		 */
+		hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
+		hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
+		for_rx_tx(t) {
+			for (i = 0; i < nma_get_nrings(hostna, t); i++) {
+				NMR(hostna, t)[i]->na = hostna;
+			}
+		}
+	}
+
+	return 0;
+
+err_dec_users:
+	for_rx_tx(t) {
+		NMR(hwna, t)[i]->users--;
+	}
+	hwna->nm_krings_delete(hwna);
+err_del_vp_rings:
+	netmap_vp_krings_delete(na);
+
+	return error;
+}
+
+
+static void
+netmap_bwrap_krings_delete(struct netmap_adapter *na)
+{
+	struct netmap_bwrap_adapter *bna =
+		(struct netmap_bwrap_adapter *)na;
+	struct netmap_adapter *hwna = bna->hwna;
+	enum txrx t;
+	int i;
+
+	ND("%s", na->name);
+
+	/* decrement the usage counter for all the hwna krings */
+	for_rx_tx(t) {
+		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
+			NMR(hwna, t)[i]->users--;
+		}
+	}
+
+	/* delete any netmap rings that are no longer needed */
+	netmap_mem_rings_delete(hwna);
+	hwna->nm_krings_delete(hwna);
+	netmap_vp_krings_delete(na);
+}
+
+
+/* notify method for the bridge-->hwna direction */
+static int
+netmap_bwrap_notify(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct netmap_bwrap_adapter *bna = na->na_private;
+	struct netmap_adapter *hwna = bna->hwna;
+	u_int ring_n = kring->ring_id;
+	u_int lim = kring->nkr_num_slots - 1;
+	struct netmap_kring *hw_kring;
+	int error;
+
+	ND("%s: na %s hwna %s",
+			(kring ? kring->name : "NULL!"),
+			(na ? na->name : "NULL!"),
+			(hwna ? hwna->name : "NULL!"));
+	hw_kring = hwna->tx_rings[ring_n];
+
+	if (nm_kr_tryget(hw_kring, 0, NULL)) {
+		return ENXIO;
+	}
+
+	/* first step: simulate a user wakeup on the rx ring */
+	netmap_vp_rxsync(kring, flags);
+	ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
+		na->name, ring_n,
+		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
+		ring->head, ring->cur, ring->tail,
+		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_ring->rtail);
+	/* second step: the new packets are sent on the tx ring
+	 * (which is actually the same ring)
+	 */
+	hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail;
+	error = hw_kring->nm_sync(hw_kring, flags);
+	if (error)
+		goto put_out;
+
+	/* third step: now we are back the rx ring */
+	/* claim ownership on all hw owned bufs */
+	kring->rhead = kring->rcur = nm_next(hw_kring->nr_hwtail, lim); /* skip past reserved slot */
+
+	/* fourth step: the user goes to sleep again, causing another rxsync */
+	netmap_vp_rxsync(kring, flags);
+	ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
+		na->name, ring_n,
+		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
+		ring->head, ring->cur, ring->tail,
+		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
+put_out:
+	nm_kr_put(hw_kring);
+
+	return error ? error : NM_IRQ_COMPLETED;
+}
+
+
+/* nm_bdg_ctl callback for the bwrap.
+ * Called on bridge-attach and detach, as an effect of vale-ctl -[ahd].
+ * On attach, it needs to provide a fake netmap_priv_d structure and
+ * perform a netmap_do_regif() on the bwrap. This will put both the
+ * bwrap and the hwna in netmap mode, with the netmap rings shared
+ * and cross linked. Moroever, it will start intercepting interrupts
+ * directed to hwna.
+ */
+static int
+netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
+{
+	struct netmap_priv_d *npriv;
+	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
+	int error = 0;
+
+	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
+		struct nmreq_vale_attach *req =
+			(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
+		if (req->reg.nr_ringid != 0 ||
+			(req->reg.nr_mode != NR_REG_ALL_NIC &&
+				req->reg.nr_mode != NR_REG_NIC_SW)) {
+			/* We only support attaching all the NIC rings
+			 * and/or the host stack. */
+			return EINVAL;
+		}
+		if (NETMAP_OWNED_BY_ANY(na)) {
+			return EBUSY;
+		}
+		if (bna->na_kpriv) {
+			/* nothing to do */
+			return 0;
+		}
+		npriv = netmap_priv_new();
+		if (npriv == NULL)
+			return ENOMEM;
+		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
+		error = netmap_do_regif(npriv, na, req->reg.nr_mode,
+					req->reg.nr_ringid, req->reg.nr_flags);
+		if (error) {
+			netmap_priv_delete(npriv);
+			return error;
+		}
+		bna->na_kpriv = npriv;
+		na->na_flags |= NAF_BUSY;
+	} else {
+		if (na->active_fds == 0) /* not registered */
+			return EINVAL;
+		netmap_priv_delete(bna->na_kpriv);
+		bna->na_kpriv = NULL;
+		na->na_flags &= ~NAF_BUSY;
+	}
+
+	return error;
+}
+
+/* attach a bridge wrapper to the 'real' device */
+int
+netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
+{
+	struct netmap_bwrap_adapter *bna;
+	struct netmap_adapter *na = NULL;
+	struct netmap_adapter *hostna = NULL;
+	int error = 0;
+	enum txrx t;
+
+	/* make sure the NIC is not already in use */
+	if (NETMAP_OWNED_BY_ANY(hwna)) {
+		D("NIC %s busy, cannot attach to bridge", hwna->name);
+		return EBUSY;
+	}
+
+	bna = nm_os_malloc(sizeof(*bna));
+	if (bna == NULL) {
+		return ENOMEM;
+	}
+
+	na = &bna->up.up;
+	/* make bwrap ifp point to the real ifp */
+	na->ifp = hwna->ifp;
+	if_ref(na->ifp);
+	na->na_private = bna;
+	strncpy(na->name, nr_name, sizeof(na->name));
+	/* fill the ring data for the bwrap adapter with rx/tx meanings
+	 * swapped. The real cross-linking will be done during register,
+	 * when all the krings will have been created.
+	 */
+	for_rx_tx(t) {
+		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
+		nma_set_nrings(na, t, nma_get_nrings(hwna, r));
+		nma_set_ndesc(na, t, nma_get_ndesc(hwna, r));
+	}
+	na->nm_dtor = netmap_bwrap_dtor;
+	na->nm_register = netmap_bwrap_reg;
+	// na->nm_txsync = netmap_bwrap_txsync;
+	// na->nm_rxsync = netmap_bwrap_rxsync;
+	na->nm_config = netmap_bwrap_config;
+	na->nm_krings_create = netmap_bwrap_krings_create;
+	na->nm_krings_delete = netmap_bwrap_krings_delete;
+	na->nm_notify = netmap_bwrap_notify;
+	na->nm_bdg_ctl = netmap_bwrap_bdg_ctl;
+	na->pdev = hwna->pdev;
+	na->nm_mem = netmap_mem_get(hwna->nm_mem);
+	na->virt_hdr_len = hwna->virt_hdr_len;
+	na->rx_buf_maxsize = hwna->rx_buf_maxsize;
+	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
+	/* Set the mfs, needed on the VALE mismatch datapath. */
+	bna->up.mfs = NM_BDG_MFS_DEFAULT;
+
+	bna->hwna = hwna;
+	netmap_adapter_get(hwna);
+	hwna->na_private = bna; /* weak reference */
+	bna->saved_na_vp = hwna->na_vp;
+	hwna->na_vp = &bna->up;
+	bna->up.up.na_vp = &(bna->up);
+
+	if (hwna->na_flags & NAF_HOST_RINGS) {
+		if (hwna->na_flags & NAF_SW_ONLY)
+			na->na_flags |= NAF_SW_ONLY;
+		na->na_flags |= NAF_HOST_RINGS;
+		hostna = &bna->host.up;
+		snprintf(hostna->name, sizeof(hostna->name), "%s^", nr_name);
+		hostna->ifp = hwna->ifp;
+		for_rx_tx(t) {
+			enum txrx r = nm_txrx_swap(t);
+			nma_set_nrings(hostna, t, 1);
+			nma_set_host_nrings(na, t, 1);
+			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
+		}
+		// hostna->nm_txsync = netmap_bwrap_host_txsync;
+		// hostna->nm_rxsync = netmap_bwrap_host_rxsync;
+		hostna->nm_notify = netmap_bwrap_notify;
+		hostna->nm_mem = netmap_mem_get(na->nm_mem);
+		hostna->na_private = bna;
+		hostna->na_vp = &bna->up;
+		na->na_hostvp = hwna->na_hostvp =
+			hostna->na_hostvp = &bna->host;
+		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
+		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
+		bna->host.mfs = NM_BDG_MFS_DEFAULT;
+	}
+
+	ND("%s<->%s txr %d txd %d rxr %d rxd %d",
+		na->name, ifp->if_xname,
+		na->num_tx_rings, na->num_tx_desc,
+		na->num_rx_rings, na->num_rx_desc);
+
+	error = netmap_attach_common(na);
+	if (error) {
+		goto err_free;
+	}
+	hwna->na_flags |= NAF_BUSY;
+	return 0;
+
+err_free:
+	hwna->na_vp = hwna->na_hostvp = NULL;
+	netmap_adapter_put(hwna);
+	nm_os_free(bna);
+	return error;
+
+}
+
+struct nm_bridge *
+netmap_init_bridges2(u_int n)
+{
+	int i;
+	struct nm_bridge *b;
+
+	b = nm_os_malloc(sizeof(struct nm_bridge) * n);
+	if (b == NULL)
+		return NULL;
+	for (i = 0; i < n; i++)
+		BDG_RWINIT(&b[i]);
+	return b;
+}
+
+void
+netmap_uninit_bridges2(struct nm_bridge *b, u_int n)
+{
+	int i;
+
+	if (b == NULL)
+		return;
+
+	for (i = 0; i < n; i++)
+		BDG_RWDESTROY(&b[i]);
+	nm_os_free(b);
+}
+
+int
+netmap_init_bridges(void)
+{
+#ifdef CONFIG_NET_NS
+	return netmap_bns_register();
+#else
+	nm_bridges = netmap_init_bridges2(NM_BRIDGES);
+	if (nm_bridges == NULL)
+		return ENOMEM;
+	return 0;
+#endif
+}
+
+void
+netmap_uninit_bridges(void)
+{
+#ifdef CONFIG_NET_NS
+	netmap_bns_unregister();
+#else
+	netmap_uninit_bridges2(nm_bridges, NM_BRIDGES);
+#endif
+}
+#endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
new file mode 100644
index 000000000..19b80b246
--- /dev/null
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -0,0 +1,128 @@
+#ifndef _NET_NETMAP_BDG_H_
+#define _NET_NETMAP_BDG_H_
+
+#if defined(__FreeBSD__)
+#define BDG_RWLOCK_T		struct rwlock // struct rwlock
+
+#define	BDG_RWINIT(b)		\
+	rw_init_flags(&(b)->bdg_lock, "bdg lock", RW_NOWITNESS)
+#define BDG_WLOCK(b)		rw_wlock(&(b)->bdg_lock)
+#define BDG_WUNLOCK(b)		rw_wunlock(&(b)->bdg_lock)
+#define BDG_RLOCK(b)		rw_rlock(&(b)->bdg_lock)
+#define BDG_RTRYLOCK(b)		rw_try_rlock(&(b)->bdg_lock)
+#define BDG_RUNLOCK(b)		rw_runlock(&(b)->bdg_lock)
+#define BDG_RWDESTROY(b)	rw_destroy(&(b)->bdg_lock)
+
+#endif /* __FreeBSD__ */
+
+/* XXX Should go away after fixing find_bridge() - Michio */
+#define NM_BDG_HASH		1024	/* forwarding table entries */
+
+/* XXX revise this */
+struct nm_hash_ent {
+	uint64_t	mac;	/* the top 2 bytes are the epoch */
+	uint64_t	ports;
+};
+
+/* Default size for the Maximum Frame Size. */
+#define NM_BDG_MFS_DEFAULT	1514
+
+/*
+ * nm_bridge is a descriptor for a VALE switch.
+ * Interfaces for a bridge are all in bdg_ports[].
+ * The array has fixed size, an empty entry does not terminate
+ * the search, but lookups only occur on attach/detach so we
+ * don't mind if they are slow.
+ *
+ * The bridge is non blocking on the transmit ports: excess
+ * packets are dropped if there is no room on the output port.
+ *
+ * bdg_lock protects accesses to the bdg_ports array.
+ * This is a rw lock (or equivalent).
+ */
+#define NM_BDG_IFNAMSIZ IFNAMSIZ
+struct nm_bridge {
+	/* XXX what is the proper alignment/layout ? */
+	BDG_RWLOCK_T	bdg_lock;	/* protects bdg_ports */
+	int		bdg_namelen;
+	uint32_t	bdg_active_ports;
+	char		bdg_basename[NM_BDG_IFNAMSIZ];
+
+	/* Indexes of active ports (up to active_ports)
+	 * and all other remaining ports.
+	 */
+	uint32_t	bdg_port_index[NM_BDG_MAXPORTS];
+	/* used by netmap_bdg_detach_common() */
+	uint32_t	tmp_bdg_port_index[NM_BDG_MAXPORTS];
+
+	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
+
+	/*
+	 * Programmable lookup functions to figure out the destination port.
+	 * It returns either of an index of the destination port,
+	 * NM_BDG_BROADCAST to broadcast this packet, or NM_BDG_NOPORT not to
+	 * forward this packet.  ring_nr is the source ring index, and the
+	 * function may overwrite this value to forward this packet to a
+	 * different ring index.
+	 * The function is set by netmap_bdg_regops().
+	 */
+	struct netmap_bdg_ops *bdg_ops;
+
+	/*
+	 * Contains the data structure used by the bdg_ops.lookup function.
+	 * By default points to *ht which is allocated on attach and used by the default lookup
+	 * otherwise will point to the data structure received by netmap_bdg_regops().
+	 */
+	void *private_data;
+	struct nm_hash_ent *ht;
+
+	/* Currently used to specify if the bridge is still in use while empty and
+	 * if it has been put in exclusive mode by an external module, see netmap_bdg_regops()
+	 * and netmap_bdg_create().
+	 */
+#define NM_BDG_ACTIVE		1
+#define NM_BDG_EXCLUSIVE	2
+	uint8_t			bdg_flags;
+
+
+#ifdef CONFIG_NET_NS
+	struct net *ns;
+#endif /* CONFIG_NET_NS */
+};
+
+static inline void *
+nm_bdg_get_auth_token(struct nm_bridge *b)
+{
+	return b->ht;
+}
+
+/* bridge not in exclusive mode ==> always valid
+ * bridge in exclusive mode (created through netmap_bdg_create()) ==> check authentication token
+ */
+static inline int
+nm_bdg_valid_auth_token(struct nm_bridge *b, void *auth_token)
+{
+	return !(b->bdg_flags & NM_BDG_EXCLUSIVE) || b->ht == auth_token;
+}
+
+struct nm_bridge *nm_find_bridge(const char *name, int create);
+void netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw);
+int netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na);
+int netmap_vp_reg(struct netmap_adapter *na, int onoff);
+int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
+int netmap_vp_reg(struct netmap_adapter *na, int onoff);
+int netmap_vp_rxsync(struct netmap_kring *kring, int flags);
+int netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na);
+/* XXX Should go away after fixing find_bridge() - Michio */
+#ifdef WITH_VALE
+extern struct netmap_bdg_ops default_bdg_ops;
+#endif
+/* XXX Below functions should be static after modularizing vp creation - Michio */
+int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
+		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
+int
+netmap_vp_txsync(struct netmap_kring *kring, int flags);
+int netmap_vp_krings_create(struct netmap_adapter *na);
+void netmap_vp_krings_delete(struct netmap_adapter *na);
+#endif /* _NET_NETMAP_BDG_H_ */
+
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index d4601c853..f32827fc6 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -25,37 +25,6 @@
  */
 
 
-/*
- * This module implements the VALE switch for netmap
-
---- VALE SWITCH ---
-
-NMG_LOCK() serializes all modifications to switches and ports.
-A switch cannot be deleted until all ports are gone.
-
-For each switch, an SX lock (RWlock on linux) protects
-deletion of ports. When configuring or deleting a new port, the
-lock is acquired in exclusive mode (after holding NMG_LOCK).
-When forwarding, the lock is acquired in shared mode (without NMG_LOCK).
-The lock is held throughout the entire forwarding cycle,
-during which the thread may incur in a page fault.
-Hence it is important that sleepable shared locks are used.
-
-On the rx ring, the per-port lock is grabbed initially to reserve
-a number of slot in the ring, then the lock is released,
-packets are copied from source to destination, and then
-the lock is acquired again and the receive ring is updated.
-(A similar thing is done on the tx ring for NIC and host stack
-ports attached to the switch)
-
- */
-
-/*
- * OS-specific code that is used only within this file.
- * Other OS-specific code that must be accessed by drivers
- * is present in netmap_kern.h
- */
-
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z glebius $");
@@ -82,18 +51,6 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #include 
 
 
-#define BDG_RWLOCK_T		struct rwlock // struct rwlock
-
-#define	BDG_RWINIT(b)		\
-	rw_init_flags(&(b)->bdg_lock, "bdg lock", RW_NOWITNESS)
-#define BDG_WLOCK(b)		rw_wlock(&(b)->bdg_lock)
-#define BDG_WUNLOCK(b)		rw_wunlock(&(b)->bdg_lock)
-#define BDG_RLOCK(b)		rw_rlock(&(b)->bdg_lock)
-#define BDG_RTRYLOCK(b)		rw_try_rlock(&(b)->bdg_lock)
-#define BDG_RUNLOCK(b)		rw_runlock(&(b)->bdg_lock)
-#define BDG_RWDESTROY(b)	rw_destroy(&(b)->bdg_lock)
-
-
 #elif defined(linux)
 
 #include "bsd_glue.h"
@@ -119,6 +76,7 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #include 
 #include 
 #include 
+#include 
 
 #ifdef WITH_VALE
 
@@ -142,15 +100,12 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #define NM_BDG_MAXRINGS		16	/* XXX unclear how many. */
 #define NM_BDG_MAXSLOTS		4096	/* XXX same as above */
 #define NM_BRIDGE_RINGSIZE	1024	/* in the device */
-#define NM_BDG_HASH		1024	/* forwarding table entries */
 #define NM_BDG_BATCH		1024	/* entries in the forwarding buffer */
 #define NM_MULTISEG		64	/* max size of a chain of bufs */
 /* actual size of the tables */
 #define NM_BDG_BATCH_MAX	(NM_BDG_BATCH + NM_MULTISEG)
 /* NM_FT_NULL terminates a list of slots in the ft */
 #define NM_FT_NULL		NM_BDG_BATCH_MAX
-/* Default size for the Maximum Frame Size. */
-#define NM_BDG_MFS_DEFAULT	1514
 
 
 /*
@@ -165,10 +120,6 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
 		"Max batch size to be used in the bridge");
 SYSEND;
 
-static int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
-		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
-static int netmap_vp_reg(struct netmap_adapter *na, int onoff);
-static int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
 
 /*
  * For each output interface, nm_bdg_q is used to construct a list.
@@ -181,96 +132,8 @@ struct nm_bdg_q {
 	uint32_t bq_len;	/* number of buffers */
 };
 
-/* XXX revise this */
-struct nm_hash_ent {
-	uint64_t	mac;	/* the top 2 bytes are the epoch */
-	uint64_t	ports;
-};
-
 /* Holds the default callbacks */
-static struct netmap_bdg_ops default_bdg_ops = {netmap_bdg_learning, NULL, NULL};
-
-/*
- * nm_bridge is a descriptor for a VALE switch.
- * Interfaces for a bridge are all in bdg_ports[].
- * The array has fixed size, an empty entry does not terminate
- * the search, but lookups only occur on attach/detach so we
- * don't mind if they are slow.
- *
- * The bridge is non blocking on the transmit ports: excess
- * packets are dropped if there is no room on the output port.
- *
- * bdg_lock protects accesses to the bdg_ports array.
- * This is a rw lock (or equivalent).
- */
-#define NM_BDG_IFNAMSIZ IFNAMSIZ
-struct nm_bridge {
-	/* XXX what is the proper alignment/layout ? */
-	BDG_RWLOCK_T	bdg_lock;	/* protects bdg_ports */
-	int		bdg_namelen;
-	uint32_t	bdg_active_ports;
-	char		bdg_basename[NM_BDG_IFNAMSIZ];
-
-	/* Indexes of active ports (up to active_ports)
-	 * and all other remaining ports.
-	 */
-	uint32_t	bdg_port_index[NM_BDG_MAXPORTS];
-	/* used by netmap_bdg_detach_common() */
-	uint32_t	tmp_bdg_port_index[NM_BDG_MAXPORTS];
-
-	struct netmap_vp_adapter *bdg_ports[NM_BDG_MAXPORTS];
-
-	/*
-	 * Programmable lookup functions to figure out the destination port.
-	 * It returns either of an index of the destination port,
-	 * NM_BDG_BROADCAST to broadcast this packet, or NM_BDG_NOPORT not to
-	 * forward this packet.  ring_nr is the source ring index, and the
-	 * function may overwrite this value to forward this packet to a
-	 * different ring index.
-	 * The function is set by netmap_bdg_regops().
-	 */
-	struct netmap_bdg_ops *bdg_ops;
-
-	/*
-	 * Contains the data structure used by the bdg_ops.lookup function.
-	 * By default points to *ht which is allocated on attach and used by the default lookup
-	 * otherwise will point to the data structure received by netmap_bdg_regops().
-	 */
-	void *private_data;
-	struct nm_hash_ent *ht;
-
-	/* Currently used to specify if the bridge is still in use while empty and
-	 * if it has been put in exclusive mode by an external module, see netmap_bdg_regops()
-	 * and netmap_bdg_create().
-	 */
-#define NM_BDG_ACTIVE		1
-#define NM_BDG_EXCLUSIVE	2
-	uint8_t			bdg_flags;
-
-
-#ifdef CONFIG_NET_NS
-	struct net *ns;
-#endif /* CONFIG_NET_NS */
-};
-
-const char*
-netmap_bdg_name(struct netmap_vp_adapter *vp)
-{
-	struct nm_bridge *b = vp->na_bdg;
-	if (b == NULL)
-		return NULL;
-	return b->bdg_basename;
-}
-
-
-#ifndef CONFIG_NET_NS
-/*
- * XXX in principle nm_bridges could be created dynamically
- * Right now we have a static array and deletions are protected
- * by an exclusive lock.
- */
-static struct nm_bridge *nm_bridges;
-#endif /* !CONFIG_NET_NS */
+struct netmap_bdg_ops default_bdg_ops = {netmap_bdg_learning, NULL, NULL};
 
 
 /*
@@ -303,107 +166,6 @@ pkt_copy(void *_src, void *_dst, int l)
 }
 
 
-static int
-nm_is_id_char(const char c)
-{
-	return (c >= 'a' && c <= 'z') ||
-	       (c >= 'A' && c <= 'Z') ||
-	       (c >= '0' && c <= '9') ||
-	       (c == '_');
-}
-
-/* Validate the name of a VALE bridge port and return the
- * position of the ":" character. */
-static int
-nm_vale_name_validate(const char *name)
-{
-	int colon_pos = -1;
-	int i;
-
-	if (!name || strlen(name) < strlen(NM_BDG_NAME)) {
-		return -1;
-	}
-
-	for (i = 0; i < NM_BDG_IFNAMSIZ && name[i]; i++) {
-		if (name[i] == ':') {
-			colon_pos = i;
-			break;
-		} else if (!nm_is_id_char(name[i])) {
-			return -1;
-		}
-	}
-
-	if (strlen(name) - colon_pos > IFNAMSIZ) {
-		/* interface name too long */
-		return -1;
-	}
-
-	return colon_pos;
-}
-
-/*
- * locate a bridge among the existing ones.
- * MUST BE CALLED WITH NMG_LOCK()
- *
- * a ':' in the name terminates the bridge name. Otherwise, just NM_NAME.
- * We assume that this is called with a name of at least NM_NAME chars.
- */
-static struct nm_bridge *
-nm_find_bridge(const char *name, int create)
-{
-	int i, namelen;
-	struct nm_bridge *b = NULL, *bridges;
-	u_int num_bridges;
-
-	NMG_LOCK_ASSERT();
-
-	netmap_bns_getbridges(&bridges, &num_bridges);
-
-	namelen = nm_vale_name_validate(name);
-	if (namelen < 0) {
-		D("invalid bridge name %s", name ? name : NULL);
-		return NULL;
-	}
-
-	/* lookup the name, remember empty slot if there is one */
-	for (i = 0; i < num_bridges; i++) {
-		struct nm_bridge *x = bridges + i;
-
-		if ((x->bdg_flags & NM_BDG_ACTIVE) + x->bdg_active_ports == 0) {
-			if (create && b == NULL)
-				b = x;	/* record empty slot */
-		} else if (x->bdg_namelen != namelen) {
-			continue;
-		} else if (strncmp(name, x->bdg_basename, namelen) == 0) {
-			ND("found '%.*s' at %d", namelen, name, i);
-			b = x;
-			break;
-		}
-	}
-	if (i == num_bridges && b) { /* name not found, can create entry */
-		/* initialize the bridge */
-		ND("create new bridge %s with ports %d", b->bdg_basename,
-			b->bdg_active_ports);
-		b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-		if (b->ht == NULL) {
-			D("failed to allocate hash table");
-			return NULL;
-		}
-		strncpy(b->bdg_basename, name, namelen);
-		b->bdg_namelen = namelen;
-		b->bdg_active_ports = 0;
-		for (i = 0; i < NM_BDG_MAXPORTS; i++)
-			b->bdg_port_index[i] = i;
-		/* set the default function */
-		b->bdg_ops = &default_bdg_ops;
-		b->private_data = b->ht;
-		b->bdg_flags = 0;
-		NM_BNS_GET(b);
-	}
-	return b;
-}
-
-
 /*
  * Free the forwarding tables for rings attached to switch ports.
  */
@@ -463,191 +225,6 @@ nm_alloc_bdgfwd(struct netmap_adapter *na)
 	return 0;
 }
 
-static int
-netmap_bdg_free(struct nm_bridge *b)
-{
-	if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) {
-		return EBUSY;
-	}
-
-	ND("marking bridge %s as free", b->bdg_basename);
-	nm_os_free(b->ht);
-	b->bdg_ops = NULL;
-	b->bdg_flags = 0;
-	NM_BNS_PUT(b);
-	return 0;
-}
-
-
-/* remove from bridge b the ports in slots hw and sw
- * (sw can be -1 if not needed)
- */
-static void
-netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
-{
-	int s_hw = hw, s_sw = sw;
-	int i, lim =b->bdg_active_ports;
-	uint32_t *tmp = b->tmp_bdg_port_index;
-
-	/*
-	New algorithm:
-	make a copy of bdg_port_index;
-	lookup NA(ifp)->bdg_port and SWNA(ifp)->bdg_port
-	in the array of bdg_port_index, replacing them with
-	entries from the bottom of the array;
-	decrement bdg_active_ports;
-	acquire BDG_WLOCK() and copy back the array.
-	 */
-
-	if (netmap_verbose)
-		D("detach %d and %d (lim %d)", hw, sw, lim);
-	/* make a copy of the list of active ports, update it,
-	 * and then copy back within BDG_WLOCK().
-	 */
-	memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index));
-	for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) {
-		if (hw >= 0 && tmp[i] == hw) {
-			ND("detach hw %d at %d", hw, i);
-			lim--; /* point to last active port */
-			tmp[i] = tmp[lim]; /* swap with i */
-			tmp[lim] = hw;	/* now this is inactive */
-			hw = -1;
-		} else if (sw >= 0 && tmp[i] == sw) {
-			ND("detach sw %d at %d", sw, i);
-			lim--;
-			tmp[i] = tmp[lim];
-			tmp[lim] = sw;
-			sw = -1;
-		} else {
-			i++;
-		}
-	}
-	if (hw >= 0 || sw >= 0) {
-		D("XXX delete failed hw %d sw %d, should panic...", hw, sw);
-	}
-
-	BDG_WLOCK(b);
-	if (b->bdg_ops->dtor)
-		b->bdg_ops->dtor(b->bdg_ports[s_hw]);
-	b->bdg_ports[s_hw] = NULL;
-	if (s_sw >= 0) {
-		b->bdg_ports[s_sw] = NULL;
-	}
-	memcpy(b->bdg_port_index, b->tmp_bdg_port_index, sizeof(b->tmp_bdg_port_index));
-	b->bdg_active_ports = lim;
-	BDG_WUNLOCK(b);
-
-	ND("now %d active ports", lim);
-	netmap_bdg_free(b);
-}
-
-static inline void *
-nm_bdg_get_auth_token(struct nm_bridge *b)
-{
-	return b->ht;
-}
-
-/* bridge not in exclusive mode ==> always valid
- * bridge in exclusive mode (created through netmap_bdg_create()) ==> check authentication token
- */
-static inline int
-nm_bdg_valid_auth_token(struct nm_bridge *b, void *auth_token)
-{
-	return !(b->bdg_flags & NM_BDG_EXCLUSIVE) || b->ht == auth_token;
-}
-
-/* Allows external modules to create bridges in exclusive mode,
- * returns an authentication token that the external module will need
- * to provide during nm_bdg_ctl_{attach, detach}(), netmap_bdg_regops(),
- * and nm_bdg_update_private_data() operations.
- * Successfully executed if ret != NULL and *return_status == 0.
- */
-void *
-netmap_bdg_create(const char *bdg_name, int *return_status)
-{
-	struct nm_bridge *b = NULL;
-	void *ret = NULL;
-
-	NMG_LOCK();
-	b = nm_find_bridge(bdg_name, 0 /* don't create */);
-	if (b) {
-		*return_status = EEXIST;
-		goto unlock_bdg_create;
-	}
-
-	b = nm_find_bridge(bdg_name, 1 /* create */);
-	if (!b) {
-		*return_status = ENOMEM;
-		goto unlock_bdg_create;
-	}
-
-	b->bdg_flags |= NM_BDG_ACTIVE | NM_BDG_EXCLUSIVE;
-	ret = nm_bdg_get_auth_token(b);
-	*return_status = 0;
-
-unlock_bdg_create:
-	NMG_UNLOCK();
-	return ret;
-}
-
-/* Allows external modules to destroy a bridge created through
- * netmap_bdg_create(), the bridge must be empty.
- */
-int
-netmap_bdg_destroy(const char *bdg_name, void *auth_token)
-{
-	struct nm_bridge *b = NULL;
-	int ret = 0;
-
-	NMG_LOCK();
-	b = nm_find_bridge(bdg_name, 0 /* don't create */);
-	if (!b) {
-		ret = ENXIO;
-		goto unlock_bdg_free;
-	}
-
-	if (!nm_bdg_valid_auth_token(b, auth_token)) {
-		ret = EACCES;
-		goto unlock_bdg_free;
-	}
-	if (!(b->bdg_flags & NM_BDG_EXCLUSIVE)) {
-		ret = EINVAL;
-		goto unlock_bdg_free;
-	}
-
-	b->bdg_flags &= ~(NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE);
-	ret = netmap_bdg_free(b);
-	if (ret) {
-		b->bdg_flags |= NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE;
-	}
-
-unlock_bdg_free:
-	NMG_UNLOCK();
-	return ret;
-}
-
-
-
-/* nm_bdg_ctl callback for VALE ports */
-static int
-netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
-{
-	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
-	struct nm_bridge *b = vpna->na_bdg;
-
-	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
-		return 0; /* nothing to do */
-	}
-	if (b) {
-		netmap_set_all_rings(na, 0 /* disable */);
-		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
-		vpna->na_bdg = NULL;
-		netmap_set_all_rings(na, 1 /* enable */);
-	}
-	/* I have took reference just for attach */
-	netmap_adapter_put(na);
-	return 0;
-}
 
 /* nm_dtor callback for ephemeral VALE ports */
 static void
@@ -849,719 +426,6 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 	return error;
 }
 
-/* Try to get a reference to a netmap adapter attached to a VALE switch.
- * If the adapter is found (or is created), this function returns 0, a
- * non NULL pointer is returned into *na, and the caller holds a
- * reference to the adapter.
- * If an adapter is not found, then no reference is grabbed and the
- * function returns an error code, or 0 if there is just a VALE prefix
- * mismatch. Therefore the caller holds a reference when
- * (*na != NULL && return == 0).
- */
-int
-netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create)
-{
-	char *nr_name = hdr->nr_name;
-	const char *ifname;
-	struct ifnet *ifp = NULL;
-	int error = 0;
-	struct netmap_vp_adapter *vpna, *hostna = NULL;
-	struct nm_bridge *b;
-	uint32_t i, j;
-	uint32_t cand = NM_BDG_NOPORT, cand2 = NM_BDG_NOPORT;
-	int needed;
-
-	*na = NULL;     /* default return value */
-
-	/* first try to see if this is a bridge port. */
-	NMG_LOCK_ASSERT();
-	if (strncmp(nr_name, NM_BDG_NAME, sizeof(NM_BDG_NAME) - 1)) {
-		return 0;  /* no error, but no VALE prefix */
-	}
-
-	b = nm_find_bridge(nr_name, create);
-	if (b == NULL) {
-		ND("no bridges available for '%s'", nr_name);
-		return (create ? ENOMEM : ENXIO);
-	}
-	if (strlen(nr_name) < b->bdg_namelen) /* impossible */
-		panic("x");
-
-	/* Now we are sure that name starts with the bridge's name,
-	 * lookup the port in the bridge. We need to scan the entire
-	 * list. It is not important to hold a WLOCK on the bridge
-	 * during the search because NMG_LOCK already guarantees
-	 * that there are no other possible writers.
-	 */
-
-	/* lookup in the local list of ports */
-	for (j = 0; j < b->bdg_active_ports; j++) {
-		i = b->bdg_port_index[j];
-		vpna = b->bdg_ports[i];
-		ND("checking %s", vpna->up.name);
-		if (!strcmp(vpna->up.name, nr_name)) {
-			netmap_adapter_get(&vpna->up);
-			ND("found existing if %s refs %d", nr_name)
-			*na = &vpna->up;
-			return 0;
-		}
-	}
-	/* not found, should we create it? */
-	if (!create)
-		return ENXIO;
-	/* yes we should, see if we have space to attach entries */
-	needed = 2; /* in some cases we only need 1 */
-	if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) {
-		D("bridge full %d, cannot create new port", b->bdg_active_ports);
-		return ENOMEM;
-	}
-	/* record the next two ports available, but do not allocate yet */
-	cand = b->bdg_port_index[b->bdg_active_ports];
-	cand2 = b->bdg_port_index[b->bdg_active_ports + 1];
-	ND("+++ bridge %s port %s used %d avail %d %d",
-		b->bdg_basename, ifname, b->bdg_active_ports, cand, cand2);
-
-	/*
-	 * try see if there is a matching NIC with this name
-	 * (after the bridge's name)
-	 */
-	ifname = nr_name + b->bdg_namelen + 1;
-	ifp = ifunit_ref(ifname);
-	if (!ifp) {
-		/* Create an ephemeral virtual port.
-		 * This block contains all the ephemeral-specific logic.
-		 */
-
-		if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
-			error = EINVAL;
-			goto out;
-		}
-
-		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = netmap_vp_create(hdr, NULL, nmd, &vpna);
-		if (error) {
-			D("error %d", error);
-			goto out;
-		}
-		/* shortcut - we can skip get_hw_na(),
-		 * ownership check and nm_bdg_attach()
-		 */
-
-	} else {
-		struct netmap_adapter *hw;
-
-		/* the vale:nic syntax is only valid for some commands */
-		switch (hdr->nr_reqtype) {
-		case NETMAP_REQ_VALE_ATTACH:
-		case NETMAP_REQ_VALE_DETACH:
-		case NETMAP_REQ_VALE_POLLING_ENABLE:
-		case NETMAP_REQ_VALE_POLLING_DISABLE:
-			break; /* ok */
-		default:
-			error = EINVAL;
-			goto out;
-		}
-
-		error = netmap_get_hw_na(ifp, nmd, &hw);
-		if (error || hw == NULL)
-			goto out;
-
-		/* host adapter might not be created */
-		error = hw->nm_bdg_attach(nr_name, hw);
-		if (error)
-			goto out;
-		vpna = hw->na_vp;
-		hostna = hw->na_hostvp;
-		if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
-			/* Check if we need to skip the host rings. */
-			struct nmreq_vale_attach *areq =
-				(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
-			if (areq->reg.nr_mode != NR_REG_NIC_SW) {
-				hostna = NULL;
-			}
-		}
-	}
-
-	BDG_WLOCK(b);
-	vpna->bdg_port = cand;
-	ND("NIC  %p to bridge port %d", vpna, cand);
-	/* bind the port to the bridge (virtual ports are not active) */
-	b->bdg_ports[cand] = vpna;
-	vpna->na_bdg = b;
-	b->bdg_active_ports++;
-	if (hostna != NULL) {
-		/* also bind the host stack to the bridge */
-		b->bdg_ports[cand2] = hostna;
-		hostna->bdg_port = cand2;
-		hostna->na_bdg = b;
-		b->bdg_active_ports++;
-		ND("host %p to bridge port %d", hostna, cand2);
-	}
-	ND("if %s refs %d", ifname, vpna->up.na_refcount);
-	BDG_WUNLOCK(b);
-	*na = &vpna->up;
-	netmap_adapter_get(*na);
-
-out:
-	if (ifp)
-		if_rele(ifp);
-
-	return error;
-}
-
-/* Process NETMAP_REQ_VALE_ATTACH.
- */
-int
-nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
-{
-	struct nmreq_vale_attach *req =
-		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
-	struct netmap_vp_adapter * vpna;
-	struct netmap_adapter *na;
-	struct netmap_mem_d *nmd = NULL;
-	struct nm_bridge *b = NULL;
-	int error;
-
-	NMG_LOCK();
-	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
-	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_exit;
-	}
-
-	if (req->reg.nr_mem_id) {
-		nmd = netmap_mem_find(req->reg.nr_mem_id);
-		if (nmd == NULL) {
-			error = EINVAL;
-			goto unlock_exit;
-		}
-	}
-
-	/* check for existing one */
-	error = netmap_get_bdg_na(hdr, &na, nmd, 0);
-	if (!error) {
-		error = EBUSY;
-		goto unref_exit;
-	}
-	error = netmap_get_bdg_na(hdr, &na,
-				nmd, 1 /* create if not exists */);
-	if (error) { /* no device */
-		goto unlock_exit;
-	}
-
-	if (na == NULL) { /* VALE prefix missing */
-		error = EINVAL;
-		goto unlock_exit;
-	}
-
-	if (NETMAP_OWNED_BY_ANY(na)) {
-		error = EBUSY;
-		goto unref_exit;
-	}
-
-	if (na->nm_bdg_ctl) {
-		/* nop for VALE ports. The bwrap needs to put the hwna
-		 * in netmap mode (see netmap_bwrap_bdg_ctl)
-		 */
-		error = na->nm_bdg_ctl(hdr, na);
-		if (error)
-			goto unref_exit;
-		ND("registered %s to netmap-mode", na->name);
-	}
-	vpna = (struct netmap_vp_adapter *)na;
-	req->port_index = vpna->bdg_port;
-	NMG_UNLOCK();
-	return 0;
-
-unref_exit:
-	netmap_adapter_put(na);
-unlock_exit:
-	NMG_UNLOCK();
-	return error;
-}
-
-static inline int
-nm_is_bwrap(struct netmap_adapter *na)
-{
-	return na->nm_register == netmap_bwrap_reg;
-}
-
-/* Process NETMAP_REQ_VALE_DETACH.
- */
-int
-nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
-{
-	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
-	struct netmap_vp_adapter *vpna;
-	struct netmap_adapter *na;
-	struct nm_bridge *b = NULL;
-	int error;
-
-	NMG_LOCK();
-	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
-	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_exit;
-	}
-
-	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */);
-	if (error) { /* no device, or another bridge or user owns the device */
-		goto unlock_exit;
-	}
-
-	if (na == NULL) { /* VALE prefix missing */
-		error = EINVAL;
-		goto unlock_exit;
-	} else if (nm_is_bwrap(na) &&
-		   ((struct netmap_bwrap_adapter *)na)->na_polling_state) {
-		/* Don't detach a NIC with polling */
-		error = EBUSY;
-		goto unref_exit;
-	}
-
-	vpna = (struct netmap_vp_adapter *)na;
-	if (na->na_vp != vpna) {
-		/* trying to detach first attach of VALE persistent port attached
-		 * to 2 bridges
-		 */
-		error = EBUSY;
-		goto unref_exit;
-	}
-	nmreq_det->port_index = vpna->bdg_port;
-
-	if (na->nm_bdg_ctl) {
-		/* remove the port from bridge. The bwrap
-		 * also needs to put the hwna in normal mode
-		 */
-		error = na->nm_bdg_ctl(hdr, na);
-	}
-
-unref_exit:
-	netmap_adapter_put(na);
-unlock_exit:
-	NMG_UNLOCK();
-	return error;
-
-}
-
-struct nm_bdg_polling_state;
-struct
-nm_bdg_kthread {
-	struct nm_kctx *nmk;
-	u_int qfirst;
-	u_int qlast;
-	struct nm_bdg_polling_state *bps;
-};
-
-struct nm_bdg_polling_state {
-	bool configured;
-	bool stopped;
-	struct netmap_bwrap_adapter *bna;
-	uint32_t mode;
-	u_int qfirst;
-	u_int qlast;
-	u_int cpu_from;
-	u_int ncpus;
-	struct nm_bdg_kthread *kthreads;
-};
-
-static void
-netmap_bwrap_polling(void *data, int is_kthread)
-{
-	struct nm_bdg_kthread *nbk = data;
-	struct netmap_bwrap_adapter *bna;
-	u_int qfirst, qlast, i;
-	struct netmap_kring **kring0, *kring;
-
-	if (!nbk)
-		return;
-	qfirst = nbk->qfirst;
-	qlast = nbk->qlast;
-	bna = nbk->bps->bna;
-	kring0 = NMR(bna->hwna, NR_RX);
-
-	for (i = qfirst; i < qlast; i++) {
-		kring = kring0[i];
-		kring->nm_notify(kring, 0);
-	}
-}
-
-static int
-nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
-{
-	struct nm_kctx_cfg kcfg;
-	int i, j;
-
-	bps->kthreads = nm_os_malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus);
-	if (bps->kthreads == NULL)
-		return ENOMEM;
-
-	bzero(&kcfg, sizeof(kcfg));
-	kcfg.worker_fn = netmap_bwrap_polling;
-	kcfg.use_kthread = 1;
-	for (i = 0; i < bps->ncpus; i++) {
-		struct nm_bdg_kthread *t = bps->kthreads + i;
-		int all = (bps->ncpus == 1 &&
-			bps->mode == NETMAP_POLLING_MODE_SINGLE_CPU);
-		int affinity = bps->cpu_from + i;
-
-		t->bps = bps;
-		t->qfirst = all ? bps->qfirst /* must be 0 */: affinity;
-		t->qlast = all ? bps->qlast : t->qfirst + 1;
-		D("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst,
-			t->qlast);
-
-		kcfg.type = i;
-		kcfg.worker_private = t;
-		t->nmk = nm_os_kctx_create(&kcfg, NULL);
-		if (t->nmk == NULL) {
-			goto cleanup;
-		}
-		nm_os_kctx_worker_setaff(t->nmk, affinity);
-	}
-	return 0;
-
-cleanup:
-	for (j = 0; j < i; j++) {
-		struct nm_bdg_kthread *t = bps->kthreads + i;
-		nm_os_kctx_destroy(t->nmk);
-	}
-	nm_os_free(bps->kthreads);
-	return EFAULT;
-}
-
-/* A variant of ptnetmap_start_kthreads() */
-static int
-nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps)
-{
-	int error, i, j;
-
-	if (!bps) {
-		D("polling is not configured");
-		return EFAULT;
-	}
-	bps->stopped = false;
-
-	for (i = 0; i < bps->ncpus; i++) {
-		struct nm_bdg_kthread *t = bps->kthreads + i;
-		error = nm_os_kctx_worker_start(t->nmk);
-		if (error) {
-			D("error in nm_kthread_start()");
-			goto cleanup;
-		}
-	}
-	return 0;
-
-cleanup:
-	for (j = 0; j < i; j++) {
-		struct nm_bdg_kthread *t = bps->kthreads + i;
-		nm_os_kctx_worker_stop(t->nmk);
-	}
-	bps->stopped = true;
-	return error;
-}
-
-static void
-nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps)
-{
-	int i;
-
-	if (!bps)
-		return;
-
-	for (i = 0; i < bps->ncpus; i++) {
-		struct nm_bdg_kthread *t = bps->kthreads + i;
-		nm_os_kctx_worker_stop(t->nmk);
-		nm_os_kctx_destroy(t->nmk);
-	}
-	bps->stopped = true;
-}
-
-static int
-get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
-		struct nm_bdg_polling_state *bps)
-{
-	unsigned int avail_cpus, core_from;
-	unsigned int qfirst, qlast;
-	uint32_t i = req->nr_first_cpu_id;
-	uint32_t req_cpus = req->nr_num_polling_cpus;
-
-	avail_cpus = nm_os_ncpus();
-
-	if (req_cpus == 0) {
-		D("req_cpus must be > 0");
-		return EINVAL;
-	} else if (req_cpus >= avail_cpus) {
-		D("Cannot use all the CPUs in the system");
-		return EINVAL;
-	}
-
-	if (req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU) {
-		/* Use a separate core for each ring. If nr_num_polling_cpus>1
-		 * more consecutive rings are polled.
-		 * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2,
-		 * ring 2 and 3 are polled by core 2 and 3, respectively. */
-		if (i + req_cpus > nma_get_nrings(na, NR_RX)) {
-			D("Rings %u-%u not in range (have %d rings)",
-				i, i + req_cpus, nma_get_nrings(na, NR_RX));
-			return EINVAL;
-		}
-		qfirst = i;
-		qlast = qfirst + req_cpus;
-		core_from = qfirst;
-
-	} else if (req->nr_mode == NETMAP_POLLING_MODE_SINGLE_CPU) {
-		/* Poll all the rings using a core specified by nr_first_cpu_id.
-		 * the number of cores must be 1. */
-		if (req_cpus != 1) {
-			D("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
-				"(was %d)", req_cpus);
-			return EINVAL;
-		}
-		qfirst = 0;
-		qlast = nma_get_nrings(na, NR_RX);
-		core_from = i;
-	} else {
-		D("Invalid polling mode");
-		return EINVAL;
-	}
-
-	bps->mode = req->nr_mode;
-	bps->qfirst = qfirst;
-	bps->qlast = qlast;
-	bps->cpu_from = core_from;
-	bps->ncpus = req_cpus;
-	D("%s qfirst %u qlast %u cpu_from %u ncpus %u",
-		req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ?
-		"MULTI" : "SINGLE",
-		qfirst, qlast, core_from, req_cpus);
-	return 0;
-}
-
-static int
-nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *na)
-{
-	struct nm_bdg_polling_state *bps;
-	struct netmap_bwrap_adapter *bna;
-	int error;
-
-	bna = (struct netmap_bwrap_adapter *)na;
-	if (bna->na_polling_state) {
-		D("ERROR adapter already in polling mode");
-		return EFAULT;
-	}
-
-	bps = nm_os_malloc(sizeof(*bps));
-	if (!bps)
-		return ENOMEM;
-	bps->configured = false;
-	bps->stopped = true;
-
-	if (get_polling_cfg(req, na, bps)) {
-		nm_os_free(bps);
-		return EINVAL;
-	}
-
-	if (nm_bdg_create_kthreads(bps)) {
-		nm_os_free(bps);
-		return EFAULT;
-	}
-
-	bps->configured = true;
-	bna->na_polling_state = bps;
-	bps->bna = bna;
-
-	/* disable interrupts if possible */
-	nma_intr_enable(bna->hwna, 0);
-	/* start kthread now */
-	error = nm_bdg_polling_start_kthreads(bps);
-	if (error) {
-		D("ERROR nm_bdg_polling_start_kthread()");
-		nm_os_free(bps->kthreads);
-		nm_os_free(bps);
-		bna->na_polling_state = NULL;
-		nma_intr_enable(bna->hwna, 1);
-	}
-	return error;
-}
-
-static int
-nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
-{
-	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na;
-	struct nm_bdg_polling_state *bps;
-
-	if (!bna->na_polling_state) {
-		D("ERROR adapter is not in polling mode");
-		return EFAULT;
-	}
-	bps = bna->na_polling_state;
-	nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state);
-	bps->configured = false;
-	nm_os_free(bps);
-	bna->na_polling_state = NULL;
-	/* reenable interrupts */
-	nma_intr_enable(bna->hwna, 1);
-	return 0;
-}
-
-int
-nm_bdg_polling(struct nmreq_header *hdr)
-{
-	struct nmreq_vale_polling *req =
-		(struct nmreq_vale_polling *)(uintptr_t)hdr->nr_body;
-	struct netmap_adapter *na = NULL;
-	int error = 0;
-
-	NMG_LOCK();
-	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0);
-	if (na && !error) {
-		if (!nm_is_bwrap(na)) {
-			error = EOPNOTSUPP;
-		} else if (hdr->nr_reqtype == NETMAP_BDG_POLLING_ON) {
-			error = nm_bdg_ctl_polling_start(req, na);
-			if (!error)
-				netmap_adapter_get(na);
-		} else {
-			error = nm_bdg_ctl_polling_stop(na);
-			if (!error)
-				netmap_adapter_put(na);
-		}
-		netmap_adapter_put(na);
-	} else if (!na && !error) {
-		/* Not VALE port. */
-		error = EINVAL;
-	}
-	NMG_UNLOCK();
-
-	return error;
-}
-
-/* Process NETMAP_REQ_VALE_LIST. */
-int
-netmap_bdg_list(struct nmreq_header *hdr)
-{
-	struct nmreq_vale_list *req =
-		(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
-	int namelen = strlen(hdr->nr_name);
-	struct nm_bridge *b, *bridges;
-	struct netmap_vp_adapter *vpna;
-	int error = 0, i, j;
-	u_int num_bridges;
-
-	netmap_bns_getbridges(&bridges, &num_bridges);
-
-	/* this is used to enumerate bridges and ports */
-	if (namelen) { /* look up indexes of bridge and port */
-		if (strncmp(hdr->nr_name, NM_BDG_NAME,
-					strlen(NM_BDG_NAME))) {
-			return EINVAL;
-		}
-		NMG_LOCK();
-		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
-		if (!b) {
-			NMG_UNLOCK();
-			return ENOENT;
-		}
-
-		req->nr_bridge_idx = b - bridges; /* bridge index */
-		req->nr_port_idx = NM_BDG_NOPORT;
-		for (j = 0; j < b->bdg_active_ports; j++) {
-			i = b->bdg_port_index[j];
-			vpna = b->bdg_ports[i];
-			if (vpna == NULL) {
-				D("This should not happen");
-				continue;
-			}
-			/* the former and the latter identify a
-			 * virtual port and a NIC, respectively
-			 */
-			if (!strcmp(vpna->up.name, hdr->nr_name)) {
-				req->nr_port_idx = i; /* port index */
-				break;
-			}
-		}
-		NMG_UNLOCK();
-	} else {
-		/* return the first non-empty entry starting from
-		 * bridge nr_arg1 and port nr_arg2.
-		 *
-		 * Users can detect the end of the same bridge by
-		 * seeing the new and old value of nr_arg1, and can
-		 * detect the end of all the bridge by error != 0
-		 */
-		i = req->nr_bridge_idx;
-		j = req->nr_port_idx;
-
-		NMG_LOCK();
-		for (error = ENOENT; i < NM_BRIDGES; i++) {
-			b = bridges + i;
-			for ( ; j < NM_BDG_MAXPORTS; j++) {
-				if (b->bdg_ports[j] == NULL)
-					continue;
-				vpna = b->bdg_ports[j];
-				/* write back the VALE switch name */
-				strncpy(hdr->nr_name, vpna->up.name,
-					(size_t)IFNAMSIZ);
-				error = 0;
-				goto out;
-			}
-			j = 0; /* following bridges scan from 0 */
-		}
-	out:
-		req->nr_bridge_idx = i;
-		req->nr_port_idx = j;
-		NMG_UNLOCK();
-	}
-
-	return error;
-}
-
-/* Called by external kernel modules (e.g., Openvswitch).
- * to set configure/lookup/dtor functions of a VALE instance.
- * Register callbacks to the given bridge. 'name' may be just
- * bridge's name (including ':' if it is not just NM_BDG_NAME).
- *
- * Called without NMG_LOCK.
- */
-
-int
-netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token)
-{
-	struct nm_bridge *b;
-	int error = 0;
-
-	NMG_LOCK();
-	b = nm_find_bridge(name, 0 /* don't create */);
-	if (!b) {
-		error = ENXIO;
-		goto unlock_regops;
-	}
-	if (!nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_regops;
-	}
-
-	BDG_WLOCK(b);
-	if (!bdg_ops) {
-		/* resetting the bridge */
-		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-		b->bdg_ops = &default_bdg_ops;
-		b->private_data = b->ht;
-	} else {
-		/* modifying the bridge */
-		b->private_data = private_data;
-		b->bdg_ops = bdg_ops;
-	}
-	BDG_WUNLOCK(b);
-
-unlock_regops:
-	NMG_UNLOCK();
-	return error;
-}
 
 /* Called by external kernel modules (e.g., Openvswitch).
  * to modify the private data previously given to regops().
@@ -1597,33 +461,12 @@ nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callba
 	return error;
 }
 
-int
-netmap_bdg_config(struct nm_ifreq *nr)
-{
-	struct nm_bridge *b;
-	int error = EINVAL;
-
-	NMG_LOCK();
-	b = nm_find_bridge(nr->nifr_name, 0);
-	if (!b) {
-		NMG_UNLOCK();
-		return error;
-	}
-	NMG_UNLOCK();
-	/* Don't call config() with NMG_LOCK() held */
-	BDG_RLOCK(b);
-	if (b->bdg_ops->config != NULL)
-		error = b->bdg_ops->config(nr);
-	BDG_RUNLOCK(b);
-	return error;
-}
-
 
 /* nm_krings_create callback for VALE ports.
  * Calls the standard netmap_krings_create, then adds leases on rx
  * rings and bdgfwd on tx rings.
  */
-static int
+int
 netmap_vp_krings_create(struct netmap_adapter *na)
 {
 	u_int tailroom;
@@ -1658,7 +501,7 @@ netmap_vp_krings_create(struct netmap_adapter *na)
 
 
 /* nm_krings_delete callback for VALE ports. */
-static void
+void
 netmap_vp_krings_delete(struct netmap_adapter *na)
 {
 	nm_free_bdgfwd(na);
@@ -1788,60 +631,14 @@ nm_bridge_rthash(const uint8_t *addr)
 	a += addr[2] << 16;
 	a += addr[1] << 8;
 	a += addr[0];
-
-	mix(a, b, c);
-#define BRIDGE_RTHASH_MASK	(NM_BDG_HASH-1)
-	return (c & BRIDGE_RTHASH_MASK);
-}
-
-#undef mix
-
-
-/* nm_register callback for VALE ports */
-static int
-netmap_vp_reg(struct netmap_adapter *na, int onoff)
-{
-	struct netmap_vp_adapter *vpna =
-		(struct netmap_vp_adapter*)na;
-	enum txrx t;
-	int i;
-
-	/* persistent ports may be put in netmap mode
-	 * before being attached to a bridge
-	 */
-	if (vpna->na_bdg)
-		BDG_WLOCK(vpna->na_bdg);
-	if (onoff) {
-		for_rx_tx(t) {
-			for (i = 0; i < netmap_real_rings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_on(kring))
-					kring->nr_mode = NKR_NETMAP_ON;
-			}
-		}
-		if (na->active_fds == 0)
-			na->na_flags |= NAF_NETMAP_ON;
-		 /* XXX on FreeBSD, persistent VALE ports should also
-		 * toggle IFCAP_NETMAP in na->ifp (2014-03-16)
-		 */
-	} else {
-		if (na->active_fds == 0)
-			na->na_flags &= ~NAF_NETMAP_ON;
-		for_rx_tx(t) {
-			for (i = 0; i < netmap_real_rings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_off(kring))
-					kring->nr_mode = NKR_NETMAP_OFF;
-			}
-		}
-	}
-	if (vpna->na_bdg)
-		BDG_WUNLOCK(vpna->na_bdg);
-	return 0;
+
+	mix(a, b, c);
+#define BRIDGE_RTHASH_MASK	(NM_BDG_HASH-1)
+	return (c & BRIDGE_RTHASH_MASK);
 }
 
+#undef mix
+
 
 /*
  * Lookup function for a learning bridge.
@@ -2325,7 +1122,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 }
 
 /* nm_txsync callback for VALE ports */
-static int
+int
 netmap_vp_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_vp_adapter *na =
@@ -2360,90 +1157,10 @@ netmap_vp_txsync(struct netmap_kring *kring, int flags)
 }
 
 
-/* rxsync code used by VALE ports nm_rxsync callback and also
- * internally by the brwap
- */
-static int
-netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags)
-{
-	struct netmap_adapter *na = kring->na;
-	struct netmap_ring *ring = kring->ring;
-	u_int nm_i, lim = kring->nkr_num_slots - 1;
-	u_int head = kring->rhead;
-	int n;
-
-	if (head > lim) {
-		D("ouch dangerous reset!!!");
-		n = netmap_ring_reinit(kring);
-		goto done;
-	}
-
-	/* First part, import newly received packets. */
-	/* actually nothing to do here, they are already in the kring */
-
-	/* Second part, skip past packets that userspace has released. */
-	nm_i = kring->nr_hwcur;
-	if (nm_i != head) {
-		/* consistency check, but nothing really important here */
-		for (n = 0; likely(nm_i != head); n++) {
-			struct netmap_slot *slot = &ring->slot[nm_i];
-			void *addr = NMB(na, slot);
-
-			if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */
-				D("bad buffer index %d, ignore ?",
-					slot->buf_idx);
-			}
-			slot->flags &= ~NS_BUF_CHANGED;
-			nm_i = nm_next(nm_i, lim);
-		}
-		kring->nr_hwcur = head;
-	}
-
-	n = 0;
-done:
-	return n;
-}
-
-/*
- * nm_rxsync callback for VALE ports
- * user process reading from a VALE switch.
- * Already protected against concurrent calls from userspace,
- * but we must acquire the queue's lock to protect against
- * writers on the same queue.
- */
-static int
-netmap_vp_rxsync(struct netmap_kring *kring, int flags)
-{
-	int n;
-
-	mtx_lock(&kring->q_lock);
-	n = netmap_vp_rxsync_locked(kring, flags);
-	mtx_unlock(&kring->q_lock);
-	return n;
-}
-
-
-/* nm_bdg_attach callback for VALE ports
- * The na_vp port is this same netmap_adapter. There is no host port.
- */
-static int
-netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
-{
-	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
-
-	if (vpna->na_bdg) {
-		return netmap_bwrap_attach(name, na);
-	}
-	na->na_vp = vpna;
-	strncpy(na->name, name, sizeof(na->name));
-	na->na_hostvp = NULL;
-	return 0;
-}
-
 /* create a netmap_vp_adapter that describes a VALE port.
  * Only persistent VALE ports have a non-null ifp.
  */
-static int
+int
 netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
@@ -2535,644 +1252,5 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	return error;
 }
 
-/* Bridge wrapper code (bwrap).
- * This is used to connect a non-VALE-port netmap_adapter (hwna) to a
- * VALE switch.
- * The main task is to swap the meaning of tx and rx rings to match the
- * expectations of the VALE switch code (see nm_bdg_flush).
- *
- * The bwrap works by interposing a netmap_bwrap_adapter between the
- * rest of the system and the hwna. The netmap_bwrap_adapter looks like
- * a netmap_vp_adapter to the rest the system, but, internally, it
- * translates all callbacks to what the hwna expects.
- *
- * Note that we have to intercept callbacks coming from two sides:
- *
- *  - callbacks coming from the netmap module are intercepted by
- *    passing around the netmap_bwrap_adapter instead of the hwna
- *
- *  - callbacks coming from outside of the netmap module only know
- *    about the hwna. This, however, only happens in interrupt
- *    handlers, where only the hwna->nm_notify callback is called.
- *    What the bwrap does is to overwrite the hwna->nm_notify callback
- *    with its own netmap_bwrap_intr_notify.
- *    XXX This assumes that the hwna->nm_notify callback was the
- *    standard netmap_notify(), as it is the case for nic adapters.
- *    Any additional action performed by hwna->nm_notify will not be
- *    performed by netmap_bwrap_intr_notify.
- *
- * Additionally, the bwrap can optionally attach the host rings pair
- * of the wrapped adapter to a different port of the switch.
- */
-
-
-static void
-netmap_bwrap_dtor(struct netmap_adapter *na)
-{
-	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
-	struct netmap_adapter *hwna = bna->hwna;
-	struct nm_bridge *b = bna->up.na_bdg,
-		*bh = bna->host.na_bdg;
-
-	if (bna->host.up.nm_mem)
-		netmap_mem_put(bna->host.up.nm_mem);
-
-	if (b) {
-		netmap_bdg_detach_common(b, bna->up.bdg_port,
-			    (bh ? bna->host.bdg_port : -1));
-	}
-
-	ND("na %p", na);
-	na->ifp = NULL;
-	bna->host.up.ifp = NULL;
-	hwna->na_vp = bna->saved_na_vp;
-	hwna->na_hostvp = NULL;
-	hwna->na_private = NULL;
-	hwna->na_flags &= ~NAF_BUSY;
-	netmap_adapter_put(hwna);
-
-}
-
-
-/*
- * Intr callback for NICs connected to a bridge.
- * Simply ignore tx interrupts (maybe we could try to recover space ?)
- * and pass received packets from nic to the bridge.
- *
- * XXX TODO check locking: this is called from the interrupt
- * handler so we should make sure that the interface is not
- * disconnected while passing down an interrupt.
- *
- * Note, no user process can access this NIC or the host stack.
- * The only part of the ring that is significant are the slots,
- * and head/cur/tail are set from the kring as needed
- * (part as a receive ring, part as a transmit ring).
- *
- * callback that overwrites the hwna notify callback.
- * Packets come from the outside or from the host stack and are put on an
- * hwna rx ring.
- * The bridge wrapper then sends the packets through the bridge.
- */
-static int
-netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
-{
-	struct netmap_adapter *na = kring->na;
-	struct netmap_bwrap_adapter *bna = na->na_private;
-	struct netmap_kring *bkring;
-	struct netmap_vp_adapter *vpna = &bna->up;
-	u_int ring_nr = kring->ring_id;
-	int ret = NM_IRQ_COMPLETED;
-	int error;
-
-	if (netmap_verbose)
-	    D("%s %s 0x%x", na->name, kring->name, flags);
-
-	bkring = vpna->up.tx_rings[ring_nr];
-
-	/* make sure the ring is not disabled */
-	if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) {
-		return EIO;
-	}
-
-	if (netmap_verbose)
-	    D("%s head %d cur %d tail %d",  na->name,
-		kring->rhead, kring->rcur, kring->rtail);
-
-	/* simulate a user wakeup on the rx ring
-	 * fetch packets that have arrived.
-	 */
-	error = kring->nm_sync(kring, 0);
-	if (error)
-		goto put_out;
-	if (kring->nr_hwcur == kring->nr_hwtail) {
-		if (netmap_verbose)
-			D("how strange, interrupt with no packets on %s",
-			    na->name);
-		goto put_out;
-	}
-
-	/* new packets are kring->rcur to kring->nr_hwtail, and the bkring
-	 * had hwcur == bkring->rhead. So advance bkring->rhead to kring->nr_hwtail
-	 * to push all packets out.
-	 */
-	bkring->rhead = bkring->rcur = kring->nr_hwtail;
-
-	netmap_vp_txsync(bkring, flags);
-
-	/* mark all buffers as released on this ring */
-	kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail;
-	/* another call to actually release the buffers */
-	error = kring->nm_sync(kring, 0);
-
-	/* The second rxsync may have further advanced hwtail. If this happens,
-	 *  return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */
-	if (kring->rcur != kring->nr_hwtail) {
-		ret = NM_IRQ_RESCHED;
-	}
-put_out:
-	nm_kr_put(kring);
-
-	return error ? error : ret;
-}
-
-
-/* nm_register callback for bwrap */
-static int
-netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
-{
-	struct netmap_bwrap_adapter *bna =
-		(struct netmap_bwrap_adapter *)na;
-	struct netmap_adapter *hwna = bna->hwna;
-	struct netmap_vp_adapter *hostna = &bna->host;
-	int error, i;
-	enum txrx t;
-
-	ND("%s %s", na->name, onoff ? "on" : "off");
-
-	if (onoff) {
-		/* netmap_do_regif has been called on the bwrap na.
-		 * We need to pass the information about the
-		 * memory allocator down to the hwna before
-		 * putting it in netmap mode
-		 */
-		hwna->na_lut = na->na_lut;
-
-		if (hostna->na_bdg) {
-			/* if the host rings have been attached to switch,
-			 * we need to copy the memory allocator information
-			 * in the hostna also
-			 */
-			hostna->up.na_lut = na->na_lut;
-		}
-
-	}
-
-	/* pass down the pending ring state information */
-	for_rx_tx(t) {
-		for (i = 0; i < netmap_all_rings(na, t); i++) {
-			NMR(hwna, nm_txrx_swap(t))[i]->nr_pending_mode =
-				NMR(na, t)[i]->nr_pending_mode;
-		}
-	}
-
-	/* forward the request to the hwna */
-	error = hwna->nm_register(hwna, onoff);
-	if (error)
-		return error;
-
-	/* copy up the current ring state information */
-	for_rx_tx(t) {
-		for (i = 0; i < netmap_all_rings(na, t); i++) {
-			struct netmap_kring *kring = NMR(hwna, nm_txrx_swap(t))[i];
-			NMR(na, t)[i]->nr_mode = kring->nr_mode;
-		}
-	}
-
-	/* impersonate a netmap_vp_adapter */
-	netmap_vp_reg(na, onoff);
-	if (hostna->na_bdg)
-		netmap_vp_reg(&hostna->up, onoff);
-
-	if (onoff) {
-		u_int i;
-		/* intercept the hwna nm_nofify callback on the hw rings */
-		for (i = 0; i < hwna->num_rx_rings; i++) {
-			hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
-			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
-		}
-		i = hwna->num_rx_rings; /* for safety */
-		/* save the host ring notify unconditionally */
-		for (; i < netmap_real_rings(hwna, NR_RX); i++) {
-			hwna->rx_rings[i]->save_notify =
-				hwna->rx_rings[i]->nm_notify;
-			if (hostna->na_bdg) {
-				/* also intercept the host ring notify */
-				hwna->rx_rings[i]->nm_notify =
-					netmap_bwrap_intr_notify;
-				na->tx_rings[i]->nm_sync = na->nm_txsync;
-			}
-		}
-		if (na->active_fds == 0)
-			na->na_flags |= NAF_NETMAP_ON;
-	} else {
-		u_int i;
-
-		if (na->active_fds == 0)
-			na->na_flags &= ~NAF_NETMAP_ON;
-
-		/* reset all notify callbacks (including host ring) */
-		for (i = 0; i < netmap_all_rings(hwna, NR_RX); i++) {
-			hwna->rx_rings[i]->nm_notify =
-				hwna->rx_rings[i]->save_notify;
-			hwna->rx_rings[i]->save_notify = NULL;
-		}
-		hwna->na_lut.lut = NULL;
-		hwna->na_lut.plut = NULL;
-		hwna->na_lut.objtotal = 0;
-		hwna->na_lut.objsize = 0;
-
-		/* pass ownership of the netmap rings to the hwna */
-		for_rx_tx(t) {
-			for (i = 0; i < netmap_all_rings(na, t); i++) {
-				NMR(na, t)[i]->ring = NULL;
-			}
-		}
-
-	}
-
-	return 0;
-}
-
-/* nm_config callback for bwrap */
-static int
-netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-	struct netmap_bwrap_adapter *bna =
-		(struct netmap_bwrap_adapter *)na;
-	struct netmap_adapter *hwna = bna->hwna;
-	int error;
-
-	/* Forward the request to the hwna. It may happen that nobody
-	 * registered hwna yet, so netmap_mem_get_lut() may have not
-	 * been called yet. */
-	error = netmap_mem_get_lut(hwna->nm_mem, &hwna->na_lut);
-	if (error)
-		return error;
-	netmap_update_config(hwna);
-	/* swap the results and propagate */
-	info->num_tx_rings = hwna->num_rx_rings;
-	info->num_tx_descs = hwna->num_rx_desc;
-	info->num_rx_rings = hwna->num_tx_rings;
-	info->num_rx_descs = hwna->num_tx_desc;
-	info->rx_buf_maxsize = hwna->rx_buf_maxsize;
-
-	return 0;
-}
-
-
-/* nm_krings_create callback for bwrap */
-static int
-netmap_bwrap_krings_create(struct netmap_adapter *na)
-{
-	struct netmap_bwrap_adapter *bna =
-		(struct netmap_bwrap_adapter *)na;
-	struct netmap_adapter *hwna = bna->hwna;
-	struct netmap_adapter *hostna = &bna->host.up;
-	int i, error = 0;
-	enum txrx t;
-
-	/* impersonate a netmap_vp_adapter */
-	error = netmap_vp_krings_create(na);
-	if (error)
-		return error;
-
-	/* also create the hwna krings */
-	error = hwna->nm_krings_create(hwna);
-	if (error) {
-		goto err_del_vp_rings;
-	}
-
-	/* increment the usage counter for all the hwna krings */
-	for_rx_tx(t) {
-		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
-			NMR(hwna, t)[i]->users++;
-		}
-	}
-
-	/* now create the actual rings */
-	error = netmap_mem_rings_create(hwna);
-	if (error) {
-		goto err_dec_users;
-	}
-
-	/* cross-link the netmap rings
-	 * The original number of rings comes from hwna,
-	 * rx rings on one side equals tx rings on the other.
-	 */
-	for_rx_tx(t) {
-		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-		for (i = 0; i < netmap_all_rings(hwna, r); i++) {
-			NMR(na, t)[i]->nkr_num_slots = NMR(hwna, r)[i]->nkr_num_slots;
-			NMR(na, t)[i]->ring = NMR(hwna, r)[i]->ring;
-		}
-	}
-
-	if (na->na_flags & NAF_HOST_RINGS) {
-		/* the hostna rings are the host rings of the bwrap.
-		 * The corresponding krings must point back to the
-		 * hostna
-		 */
-		hostna->tx_rings = &na->tx_rings[na->num_tx_rings];
-		hostna->rx_rings = &na->rx_rings[na->num_rx_rings];
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(hostna, t); i++) {
-				NMR(hostna, t)[i]->na = hostna;
-			}
-		}
-	}
-
-	return 0;
-
-err_dec_users:
-	for_rx_tx(t) {
-		NMR(hwna, t)[i]->users--;
-	}
-	hwna->nm_krings_delete(hwna);
-err_del_vp_rings:
-	netmap_vp_krings_delete(na);
-
-	return error;
-}
-
-
-static void
-netmap_bwrap_krings_delete(struct netmap_adapter *na)
-{
-	struct netmap_bwrap_adapter *bna =
-		(struct netmap_bwrap_adapter *)na;
-	struct netmap_adapter *hwna = bna->hwna;
-	enum txrx t;
-	int i;
-
-	ND("%s", na->name);
-
-	/* decrement the usage counter for all the hwna krings */
-	for_rx_tx(t) {
-		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
-			NMR(hwna, t)[i]->users--;
-		}
-	}
-
-	/* delete any netmap rings that are no longer needed */
-	netmap_mem_rings_delete(hwna);
-	hwna->nm_krings_delete(hwna);
-	netmap_vp_krings_delete(na);
-}
-
-
-/* notify method for the bridge-->hwna direction */
-static int
-netmap_bwrap_notify(struct netmap_kring *kring, int flags)
-{
-	struct netmap_adapter *na = kring->na;
-	struct netmap_bwrap_adapter *bna = na->na_private;
-	struct netmap_adapter *hwna = bna->hwna;
-	u_int ring_n = kring->ring_id;
-	u_int lim = kring->nkr_num_slots - 1;
-	struct netmap_kring *hw_kring;
-	int error;
-
-	ND("%s: na %s hwna %s",
-			(kring ? kring->name : "NULL!"),
-			(na ? na->name : "NULL!"),
-			(hwna ? hwna->name : "NULL!"));
-	hw_kring = hwna->tx_rings[ring_n];
-
-	if (nm_kr_tryget(hw_kring, 0, NULL)) {
-		return ENXIO;
-	}
-
-	/* first step: simulate a user wakeup on the rx ring */
-	netmap_vp_rxsync(kring, flags);
-	ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
-		na->name, ring_n,
-		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
-		ring->head, ring->cur, ring->tail,
-		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_ring->rtail);
-	/* second step: the new packets are sent on the tx ring
-	 * (which is actually the same ring)
-	 */
-	hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail;
-	error = hw_kring->nm_sync(hw_kring, flags);
-	if (error)
-		goto put_out;
-
-	/* third step: now we are back the rx ring */
-	/* claim ownership on all hw owned bufs */
-	kring->rhead = kring->rcur = nm_next(hw_kring->nr_hwtail, lim); /* skip past reserved slot */
-
-	/* fourth step: the user goes to sleep again, causing another rxsync */
-	netmap_vp_rxsync(kring, flags);
-	ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
-		na->name, ring_n,
-		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
-		ring->head, ring->cur, ring->tail,
-		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
-put_out:
-	nm_kr_put(hw_kring);
-
-	return error ? error : NM_IRQ_COMPLETED;
-}
-
-
-/* nm_bdg_ctl callback for the bwrap.
- * Called on bridge-attach and detach, as an effect of vale-ctl -[ahd].
- * On attach, it needs to provide a fake netmap_priv_d structure and
- * perform a netmap_do_regif() on the bwrap. This will put both the
- * bwrap and the hwna in netmap mode, with the netmap rings shared
- * and cross linked. Moroever, it will start intercepting interrupts
- * directed to hwna.
- */
-static int
-netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
-{
-	struct netmap_priv_d *npriv;
-	struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na;
-	int error = 0;
-
-	if (hdr->nr_reqtype == NETMAP_REQ_VALE_ATTACH) {
-		struct nmreq_vale_attach *req =
-			(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
-		if (req->reg.nr_ringid != 0 ||
-			(req->reg.nr_mode != NR_REG_ALL_NIC &&
-				req->reg.nr_mode != NR_REG_NIC_SW)) {
-			/* We only support attaching all the NIC rings
-			 * and/or the host stack. */
-			return EINVAL;
-		}
-		if (NETMAP_OWNED_BY_ANY(na)) {
-			return EBUSY;
-		}
-		if (bna->na_kpriv) {
-			/* nothing to do */
-			return 0;
-		}
-		npriv = netmap_priv_new();
-		if (npriv == NULL)
-			return ENOMEM;
-		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, req->reg.nr_mode,
-					req->reg.nr_ringid, req->reg.nr_flags);
-		if (error) {
-			netmap_priv_delete(npriv);
-			return error;
-		}
-		bna->na_kpriv = npriv;
-		na->na_flags |= NAF_BUSY;
-	} else {
-		if (na->active_fds == 0) /* not registered */
-			return EINVAL;
-		netmap_priv_delete(bna->na_kpriv);
-		bna->na_kpriv = NULL;
-		na->na_flags &= ~NAF_BUSY;
-	}
-
-	return error;
-}
-
-/* attach a bridge wrapper to the 'real' device */
-int
-netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
-{
-	struct netmap_bwrap_adapter *bna;
-	struct netmap_adapter *na = NULL;
-	struct netmap_adapter *hostna = NULL;
-	int error = 0;
-	enum txrx t;
-
-	/* make sure the NIC is not already in use */
-	if (NETMAP_OWNED_BY_ANY(hwna)) {
-		D("NIC %s busy, cannot attach to bridge", hwna->name);
-		return EBUSY;
-	}
-
-	bna = nm_os_malloc(sizeof(*bna));
-	if (bna == NULL) {
-		return ENOMEM;
-	}
-
-	na = &bna->up.up;
-	/* make bwrap ifp point to the real ifp */
-	na->ifp = hwna->ifp;
-	if_ref(na->ifp);
-	na->na_private = bna;
-	strncpy(na->name, nr_name, sizeof(na->name));
-	/* fill the ring data for the bwrap adapter with rx/tx meanings
-	 * swapped. The real cross-linking will be done during register,
-	 * when all the krings will have been created.
-	 */
-	for_rx_tx(t) {
-		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-		nma_set_nrings(na, t, nma_get_nrings(hwna, r));
-		nma_set_ndesc(na, t, nma_get_ndesc(hwna, r));
-	}
-	na->nm_dtor = netmap_bwrap_dtor;
-	na->nm_register = netmap_bwrap_reg;
-	// na->nm_txsync = netmap_bwrap_txsync;
-	// na->nm_rxsync = netmap_bwrap_rxsync;
-	na->nm_config = netmap_bwrap_config;
-	na->nm_krings_create = netmap_bwrap_krings_create;
-	na->nm_krings_delete = netmap_bwrap_krings_delete;
-	na->nm_notify = netmap_bwrap_notify;
-	na->nm_bdg_ctl = netmap_bwrap_bdg_ctl;
-	na->pdev = hwna->pdev;
-	na->nm_mem = netmap_mem_get(hwna->nm_mem);
-	na->virt_hdr_len = hwna->virt_hdr_len;
-	na->rx_buf_maxsize = hwna->rx_buf_maxsize;
-	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
-	/* Set the mfs, needed on the VALE mismatch datapath. */
-	bna->up.mfs = NM_BDG_MFS_DEFAULT;
-
-	bna->hwna = hwna;
-	netmap_adapter_get(hwna);
-	hwna->na_private = bna; /* weak reference */
-	bna->saved_na_vp = hwna->na_vp;
-	hwna->na_vp = &bna->up;
-	bna->up.up.na_vp = &(bna->up);
-
-	if (hwna->na_flags & NAF_HOST_RINGS) {
-		if (hwna->na_flags & NAF_SW_ONLY)
-			na->na_flags |= NAF_SW_ONLY;
-		na->na_flags |= NAF_HOST_RINGS;
-		hostna = &bna->host.up;
-		snprintf(hostna->name, sizeof(hostna->name), "%s^", nr_name);
-		hostna->ifp = hwna->ifp;
-		for_rx_tx(t) {
-			enum txrx r = nm_txrx_swap(t);
-			nma_set_nrings(hostna, t, 1);
-			nma_set_host_nrings(na, t, 1);
-			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
-		}
-		// hostna->nm_txsync = netmap_bwrap_host_txsync;
-		// hostna->nm_rxsync = netmap_bwrap_host_rxsync;
-		hostna->nm_notify = netmap_bwrap_notify;
-		hostna->nm_mem = netmap_mem_get(na->nm_mem);
-		hostna->na_private = bna;
-		hostna->na_vp = &bna->up;
-		na->na_hostvp = hwna->na_hostvp =
-			hostna->na_hostvp = &bna->host;
-		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
-		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
-		bna->host.mfs = NM_BDG_MFS_DEFAULT;
-	}
-
-	ND("%s<->%s txr %d txd %d rxr %d rxd %d",
-		na->name, ifp->if_xname,
-		na->num_tx_rings, na->num_tx_desc,
-		na->num_rx_rings, na->num_rx_desc);
-
-	error = netmap_attach_common(na);
-	if (error) {
-		goto err_free;
-	}
-	hwna->na_flags |= NAF_BUSY;
-	return 0;
-
-err_free:
-	hwna->na_vp = hwna->na_hostvp = NULL;
-	netmap_adapter_put(hwna);
-	nm_os_free(bna);
-	return error;
-
-}
-
-struct nm_bridge *
-netmap_init_bridges2(u_int n)
-{
-	int i;
-	struct nm_bridge *b;
-
-	b = nm_os_malloc(sizeof(struct nm_bridge) * n);
-	if (b == NULL)
-		return NULL;
-	for (i = 0; i < n; i++)
-		BDG_RWINIT(&b[i]);
-	return b;
-}
-
-void
-netmap_uninit_bridges2(struct nm_bridge *b, u_int n)
-{
-	int i;
-
-	if (b == NULL)
-		return;
-
-	for (i = 0; i < n; i++)
-		BDG_RWDESTROY(&b[i]);
-	nm_os_free(b);
-}
-
-int
-netmap_init_bridges(void)
-{
-#ifdef CONFIG_NET_NS
-	return netmap_bns_register();
-#else
-	nm_bridges = netmap_init_bridges2(NM_BRIDGES);
-	if (nm_bridges == NULL)
-		return ENOMEM;
-	return 0;
-#endif
-}
 
-void
-netmap_uninit_bridges(void)
-{
-#ifdef CONFIG_NET_NS
-	netmap_bns_unregister();
-#else
-	netmap_uninit_bridges2(nm_bridges, NM_BRIDGES);
-#endif
-}
 #endif /* WITH_VALE */

From 17302ab3a08dc39ffe3a177c486905260d9aea11 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 28 Jun 2018 09:51:26 +0200
Subject: [PATCH 0915/2207] pipe: do not re-initialize re-opened pipes

---
 sys/dev/netmap/netmap_pipe.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 202cb00ac..1b4a9253c 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -446,6 +446,16 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 				if (nm_kring_pending_on(kring)) {
 					struct netmap_kring *sring, *dring;
 
+					kring->nr_mode = NKR_NETMAP_ON;
+					if ((kring->nr_kflags & NKR_FAKERING) &&
+					    (kring->pipe->nr_kflags & NKR_FAKERING)) {
+						/* this is a re-open of a pipe
+						 * end-point kept alive by the other end.
+						 * We need to leave everything as it is
+						 */
+						continue;
+					}
+
 					/* copy the buffers from the non-fake ring */
 					if (kring->nr_kflags & NKR_FAKERING) {
 						sring = kring->pipe;

From 315d2ead69a8573b06d99662ef2971d36c26560c Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 27 Jun 2018 21:09:04 +0200
Subject: [PATCH 0916/2207] bdg: modular attach routines for virtual interface
 and bwrap.

XXX Todo: name validation in netmap_get_bdg_na()
---
 sys/dev/netmap/netmap.c      |   4 +-
 sys/dev/netmap/netmap_bdg.c  |  93 ++++----
 sys/dev/netmap/netmap_bdg.h  |  20 +-
 sys/dev/netmap/netmap_kern.h |  12 +-
 sys/dev/netmap/netmap_vale.c | 428 ++++++++++++++++++++---------------
 5 files changed, 322 insertions(+), 235 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b978ede9d..a90680cee 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1542,7 +1542,7 @@ netmap_get_na(struct nmreq_header *hdr,
 		goto out;
 
 	/* try to see if this is a bridge port */
-	error = netmap_get_bdg_na(hdr, na, nmd, create);
+	error = netmap_get_vale_na(hdr, na, nmd, create);
 	if (error)
 		goto out;
 
@@ -2550,7 +2550,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			hdr->nr_body = (uintptr_t)®req;
-			error = netmap_get_bdg_na(hdr, &na, NULL, 0);
+			error = netmap_get_vale_na(hdr, &na, NULL, 0);
 			hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
 			hdr->nr_body = (uintptr_t)req;
 			if (na && !error) {
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 8115f4ea5..9387cafb6 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -415,7 +415,7 @@ netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
  */
 int
 netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create)
+		struct netmap_mem_d *nmd, int create, struct nm_bdg_args *args)
 {
 	char *nr_name = hdr->nr_name;
 	const char *ifname;
@@ -435,6 +435,15 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		return 0;  /* no error, but no VALE prefix */
 	}
 
+	if (create) {
+		if (!args) {
+			return EINVAL;
+		}
+		if (strncmp(args->name, nr_name, strlen(args->name))) {
+			return 0;
+		}
+	}
+
 	b = nm_find_bridge(nr_name, create);
 	if (b == NULL) {
 		ND("no bridges available for '%s'", nr_name);
@@ -494,7 +503,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = netmap_vp_create(hdr, NULL, nmd, &vpna);
+		error = args->vp_attach(hdr, NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -523,7 +532,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			goto out;
 
 		/* host adapter might not be created */
-		error = hw->nm_bdg_attach(nr_name, hw);
+		error = hw->nm_bdg_attach(nr_name, hw, args);
 		if (error)
 			goto out;
 		vpna = hw->na_vp;
@@ -595,13 +604,23 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 	}
 
 	/* check for existing one */
-	error = netmap_get_bdg_na(hdr, &na, nmd, 0);
+	error = netmap_get_bdg_na(hdr, &na, nmd, 0, NULL);
 	if (!error) {
 		error = EBUSY;
 		goto unref_exit;
 	}
 	error = netmap_get_bdg_na(hdr, &na,
+				nmd, 1 /* create if not exists */, NULL);
+	do {
+		error = netmap_get_vale_na(hdr, &na,
 				nmd, 1 /* create if not exists */);
+		if (error) { /* no device */
+			goto unlock_exit;
+		} else if (na != NULL) {
+			break;
+		}
+		/* other bridge's get_na listed here */
+	} while (0);
 	if (error) { /* no device */
 		goto unlock_exit;
 	}
@@ -662,7 +681,7 @@ nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
 		goto unlock_exit;
 	}
 
-	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */);
+	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */, NULL);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
 	}
@@ -972,7 +991,7 @@ nm_bdg_polling(struct nmreq_header *hdr)
 	int error = 0;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0);
+	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0, NULL);
 	if (na && !error) {
 		if (!nm_is_bwrap(na)) {
 			error = EOPNOTSUPP;
@@ -1249,17 +1268,24 @@ netmap_vp_rxsync(struct netmap_kring *kring, int flags)
 	return n;
 }
 
+int
+netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna,
+		struct nm_bdg_args *args)
+{
+	return args->bwrap_attach(nr_name, hwna);
+}
 
 /* nm_bdg_attach callback for VALE ports
  * The na_vp port is this same netmap_adapter. There is no host port.
  */
 int
-netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na)
+netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na,
+		struct nm_bdg_args *args)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 
 	if (vpna->na_bdg) {
-		return netmap_bwrap_attach(name, na);
+		return netmap_bwrap_attach(name, na, args);
 	}
 	na->na_vp = vpna;
 	strncpy(na->name, name, sizeof(na->name));
@@ -1544,8 +1570,8 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 
 
 /* nm_krings_create callback for bwrap */
-static int
-netmap_bwrap_krings_create(struct netmap_adapter *na)
+int
+netmap_bwrap_krings_create_common(struct netmap_adapter *na)
 {
 	struct netmap_bwrap_adapter *bna =
 		(struct netmap_bwrap_adapter *)na;
@@ -1554,15 +1580,10 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 	int i, error = 0;
 	enum txrx t;
 
-	/* impersonate a netmap_vp_adapter */
-	error = netmap_vp_krings_create(na);
-	if (error)
-		return error;
-
 	/* also create the hwna krings */
 	error = hwna->nm_krings_create(hwna);
 	if (error) {
-		goto err_del_vp_rings;
+		return error;
 	}
 
 	/* increment the usage counter for all the hwna krings */
@@ -1611,15 +1632,12 @@ netmap_bwrap_krings_create(struct netmap_adapter *na)
 		NMR(hwna, t)[i]->users--;
 	}
 	hwna->nm_krings_delete(hwna);
-err_del_vp_rings:
-	netmap_vp_krings_delete(na);
-
 	return error;
 }
 
 
-static void
-netmap_bwrap_krings_delete(struct netmap_adapter *na)
+void
+netmap_bwrap_krings_delete_common(struct netmap_adapter *na)
 {
 	struct netmap_bwrap_adapter *bna =
 		(struct netmap_bwrap_adapter *)na;
@@ -1639,12 +1657,11 @@ netmap_bwrap_krings_delete(struct netmap_adapter *na)
 	/* delete any netmap rings that are no longer needed */
 	netmap_mem_rings_delete(hwna);
 	hwna->nm_krings_delete(hwna);
-	netmap_vp_krings_delete(na);
 }
 
 
 /* notify method for the bridge-->hwna direction */
-static int
+int
 netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
@@ -1755,10 +1772,10 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 
 /* attach a bridge wrapper to the 'real' device */
 int
-netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
+netmap_bwrap_attach_common(struct netmap_adapter *na,
+		struct netmap_adapter *hwna)
 {
 	struct netmap_bwrap_adapter *bna;
-	struct netmap_adapter *na = NULL;
 	struct netmap_adapter *hostna = NULL;
 	int error = 0;
 	enum txrx t;
@@ -1769,17 +1786,11 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		return EBUSY;
 	}
 
-	bna = nm_os_malloc(sizeof(*bna));
-	if (bna == NULL) {
-		return ENOMEM;
-	}
-
-	na = &bna->up.up;
+	bna = (struct netmap_bwrap_adapter *)na;
 	/* make bwrap ifp point to the real ifp */
 	na->ifp = hwna->ifp;
 	if_ref(na->ifp);
 	na->na_private = bna;
-	strncpy(na->name, nr_name, sizeof(na->name));
 	/* fill the ring data for the bwrap adapter with rx/tx meanings
 	 * swapped. The real cross-linking will be done during register,
 	 * when all the krings will have been created.
@@ -1790,21 +1801,12 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		nma_set_ndesc(na, t, nma_get_ndesc(hwna, r));
 	}
 	na->nm_dtor = netmap_bwrap_dtor;
-	na->nm_register = netmap_bwrap_reg;
-	// na->nm_txsync = netmap_bwrap_txsync;
-	// na->nm_rxsync = netmap_bwrap_rxsync;
 	na->nm_config = netmap_bwrap_config;
-	na->nm_krings_create = netmap_bwrap_krings_create;
-	na->nm_krings_delete = netmap_bwrap_krings_delete;
-	na->nm_notify = netmap_bwrap_notify;
 	na->nm_bdg_ctl = netmap_bwrap_bdg_ctl;
 	na->pdev = hwna->pdev;
 	na->nm_mem = netmap_mem_get(hwna->nm_mem);
 	na->virt_hdr_len = hwna->virt_hdr_len;
 	na->rx_buf_maxsize = hwna->rx_buf_maxsize;
-	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
-	/* Set the mfs, needed on the VALE mismatch datapath. */
-	bna->up.mfs = NM_BDG_MFS_DEFAULT;
 
 	bna->hwna = hwna;
 	netmap_adapter_get(hwna);
@@ -1818,7 +1820,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 			na->na_flags |= NAF_SW_ONLY;
 		na->na_flags |= NAF_HOST_RINGS;
 		hostna = &bna->host.up;
-		snprintf(hostna->name, sizeof(hostna->name), "%s^", nr_name);
+		snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name);
 		hostna->ifp = hwna->ifp;
 		for_rx_tx(t) {
 			enum txrx r = nm_txrx_swap(t);
@@ -1828,7 +1830,6 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		}
 		// hostna->nm_txsync = netmap_bwrap_host_txsync;
 		// hostna->nm_rxsync = netmap_bwrap_host_rxsync;
-		hostna->nm_notify = netmap_bwrap_notify;
 		hostna->nm_mem = netmap_mem_get(na->nm_mem);
 		hostna->na_private = bna;
 		hostna->na_vp = &bna->up;
@@ -1836,7 +1837,6 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 			hostna->na_hostvp = &bna->host;
 		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
 		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
-		bna->host.mfs = NM_BDG_MFS_DEFAULT;
 	}
 
 	ND("%s<->%s txr %d txd %d rxr %d rxd %d",
@@ -1846,15 +1846,14 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 
 	error = netmap_attach_common(na);
 	if (error) {
-		goto err_free;
+		goto err_put;
 	}
 	hwna->na_flags |= NAF_BUSY;
 	return 0;
 
-err_free:
+err_put:
 	hwna->na_vp = hwna->na_hostvp = NULL;
 	netmap_adapter_put(hwna);
-	nm_os_free(bna);
 	return error;
 
 }
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 19b80b246..13f3095a4 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -90,6 +90,13 @@ struct nm_bridge {
 #endif /* CONFIG_NET_NS */
 };
 
+struct nm_bdg_args {
+	char name[IFNAMSIZ];
+	int (*vp_attach)(struct nmreq_header *hdr, struct ifnet *ifp,
+		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret);
+	int (*bwrap_attach)(const char *nr_name, struct netmap_adapter *hwna);
+};
+
 static inline void *
 nm_bdg_get_auth_token(struct nm_bridge *b)
 {
@@ -105,6 +112,9 @@ nm_bdg_valid_auth_token(struct nm_bridge *b, void *auth_token)
 	return !(b->bdg_flags & NM_BDG_EXCLUSIVE) || b->ht == auth_token;
 }
 
+int netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create, struct nm_bdg_args *args);
+
 struct nm_bridge *nm_find_bridge(const char *name, int create);
 void netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw);
 int netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na);
@@ -112,14 +122,18 @@ int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
 int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_vp_rxsync(struct netmap_kring *kring, int flags);
-int netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na);
+int netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na,
+		struct nm_bdg_args *args);
+int netmap_bwrap_notify(struct netmap_kring *kring, int flags);
+int netmap_bwrap_attach_common(struct netmap_adapter *na,
+		struct netmap_adapter *hwna);
+int netmap_bwrap_krings_create_common(struct netmap_adapter *na);
+void netmap_bwrap_krings_delete_common(struct netmap_adapter *na);
 /* XXX Should go away after fixing find_bridge() - Michio */
 #ifdef WITH_VALE
 extern struct netmap_bdg_ops default_bdg_ops;
 #endif
 /* XXX Below functions should be static after modularizing vp creation - Michio */
-int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
-		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
 int
 netmap_vp_txsync(struct netmap_kring *kring, int flags);
 int netmap_vp_krings_create(struct netmap_adapter *na);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 581f23ba9..a892d1dce 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -273,6 +273,7 @@ struct netmap_adapter;
 struct nm_bdg_fwd;
 struct nm_bridge;
 struct netmap_priv_d;
+struct nm_bdg_args;
 
 /* os-specific NM_SELINFO_T initialzation/destruction functions */
 void nm_os_selinfo_init(NM_SELINFO_T *);
@@ -815,7 +816,8 @@ struct netmap_adapter {
 	 *      initializations
 	 *      Called with NMG_LOCK held.
 	 */
-	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *);
+	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *,
+			struct nm_bdg_args *);
 	int (*nm_bdg_ctl)(struct nmreq_header *, struct netmap_adapter *);
 
 	/* adapter used to attach this adapter to a VALE switch (if any) */
@@ -1077,7 +1079,7 @@ struct netmap_bwrap_adapter {
 int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_polling(struct nmreq_header *hdr);
-int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
+int netmap_bwrap_attach(const char *name, struct netmap_adapter *, struct nm_bdg_args *);
 int netmap_vi_create(struct nmreq_header *hdr, int);
 int nm_vi_create(struct nmreq_header *);
 int nm_vi_destroy(const char *name);
@@ -1458,6 +1460,7 @@ struct netmap_bdg_ops {
 	bdg_config_fn_t config;
 	bdg_dtor_fn_t	dtor;
 };
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
 
 uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *, void *private_data);
@@ -1468,13 +1471,12 @@ uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 #define	NM_BDG_NOPORT		(NM_BDG_MAXPORTS+1)
 
 /* these are redefined in case of no VALE support */
-int netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+int netmap_get_vale_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create);
 struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
 int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
 	void *callback_data, void *auth_token);
 int netmap_bdg_config(struct nm_ifreq *nifr);
@@ -1482,7 +1484,7 @@ void *netmap_bdg_create(const char *bdg_name, int *return_status);
 int netmap_bdg_destroy(const char *bdg_name, void *auth_token);
 
 #else /* !WITH_VALE */
-#define	netmap_get_bdg_na(_1, _2, _3, _4)	0
+#define	netmap_get_vale_na(_1, _2, _3, _4)	0
 #define netmap_init_bridges(_1) 0
 #define netmap_uninit_bridges()
 #define	netmap_bdg_regops(_1, _2)	EINVAL
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index f32827fc6..4cf4920e5 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -250,182 +250,6 @@ netmap_vp_dtor(struct netmap_adapter *na)
 	}
 }
 
-/* creates a persistent VALE port */
-int
-nm_vi_create(struct nmreq_header *hdr)
-{
-	struct nmreq_vale_newif *req =
-		(struct nmreq_vale_newif *)(uintptr_t)hdr->nr_body;
-	int error = 0;
-	/* Build a nmreq_register out of the nmreq_vale_newif,
-	 * so that we can call netmap_get_bdg_na(). */
-	struct nmreq_register regreq;
-	bzero(®req, sizeof(regreq));
-	regreq.nr_tx_slots = req->nr_tx_slots;
-	regreq.nr_rx_slots = req->nr_rx_slots;
-	regreq.nr_tx_rings = req->nr_tx_rings;
-	regreq.nr_rx_rings = req->nr_rx_rings;
-	regreq.nr_mem_id = req->nr_mem_id;
-	hdr->nr_reqtype = NETMAP_REQ_REGISTER;
-	hdr->nr_body = (uintptr_t)®req;
-	error = netmap_vi_create(hdr, 0 /* no autodelete */);
-	hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
-	hdr->nr_body = (uintptr_t)req;
-	/* Write back to the original struct. */
-	req->nr_tx_slots = regreq.nr_tx_slots;
-	req->nr_rx_slots = regreq.nr_rx_slots;
-	req->nr_tx_rings = regreq.nr_tx_rings;
-	req->nr_rx_rings = regreq.nr_rx_rings;
-	req->nr_mem_id = regreq.nr_mem_id;
-	return error;
-}
-
-/* remove a persistent VALE port from the system */
-int
-nm_vi_destroy(const char *name)
-{
-	struct ifnet *ifp;
-	struct netmap_vp_adapter *vpna;
-	int error;
-
-	ifp = ifunit_ref(name);
-	if (!ifp)
-		return ENXIO;
-	NMG_LOCK();
-	/* make sure this is actually a VALE port */
-	if (!NM_NA_VALID(ifp) || NA(ifp)->nm_register != netmap_vp_reg) {
-		error = EINVAL;
-		goto err;
-	}
-
-	vpna = (struct netmap_vp_adapter *)NA(ifp);
-
-	/* we can only destroy ports that were created via NETMAP_BDG_NEWIF */
-	if (vpna->autodelete) {
-		error = EINVAL;
-		goto err;
-	}
-
-	/* also make sure that nobody is using the inferface */
-	if (NETMAP_OWNED_BY_ANY(&vpna->up) ||
-	    vpna->up.na_refcount > 1 /* any ref besides the one in nm_vi_create()? */) {
-		error = EBUSY;
-		goto err;
-	}
-
-	NMG_UNLOCK();
-
-	D("destroying a persistent vale interface %s", ifp->if_xname);
-	/* Linux requires all the references are released
-	 * before unregister
-	 */
-	netmap_detach(ifp);
-	if_rele(ifp);
-	nm_os_vi_detach(ifp);
-	return 0;
-
-err:
-	NMG_UNLOCK();
-	if_rele(ifp);
-	return error;
-}
-
-static int
-nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
-{
-	req->nr_rx_rings = na->num_rx_rings;
-	req->nr_tx_rings = na->num_tx_rings;
-	req->nr_rx_slots = na->num_rx_desc;
-	req->nr_tx_slots = na->num_tx_desc;
-	return netmap_mem_get_info(na->nm_mem, &req->nr_memsize, NULL,
-					&req->nr_mem_id);
-}
-
-/*
- * Create a virtual interface registered to the system.
- * The interface will be attached to a bridge later.
- */
-int
-netmap_vi_create(struct nmreq_header *hdr, int autodelete)
-{
-	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
-	struct ifnet *ifp;
-	struct netmap_vp_adapter *vpna;
-	struct netmap_mem_d *nmd = NULL;
-	int error;
-
-	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
-		return EINVAL;
-	}
-
-	/* don't include VALE prefix */
-	if (!strncmp(hdr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
-		return EINVAL;
-	if (strlen(hdr->nr_name) >= IFNAMSIZ) {
-		return EINVAL;
-	}
-	ifp = ifunit_ref(hdr->nr_name);
-	if (ifp) { /* already exist, cannot create new one */
-		error = EEXIST;
-		NMG_LOCK();
-		if (NM_NA_VALID(ifp)) {
-			int update_err = nm_update_info(req, NA(ifp));
-			if (update_err)
-				error = update_err;
-		}
-		NMG_UNLOCK();
-		if_rele(ifp);
-		return error;
-	}
-	error = nm_os_vi_persist(hdr->nr_name, &ifp);
-	if (error)
-		return error;
-
-	NMG_LOCK();
-	if (req->nr_mem_id) {
-		nmd = netmap_mem_find(req->nr_mem_id);
-		if (nmd == NULL) {
-			error = EINVAL;
-			goto err_1;
-		}
-	}
-	/* netmap_vp_create creates a struct netmap_vp_adapter */
-	error = netmap_vp_create(hdr, ifp, nmd, &vpna);
-	if (error) {
-		D("error %d", error);
-		goto err_1;
-	}
-	/* persist-specific routines */
-	vpna->up.nm_bdg_ctl = netmap_vp_bdg_ctl;
-	if (!autodelete) {
-		netmap_adapter_get(&vpna->up);
-	} else {
-		vpna->autodelete = 1;
-	}
-	NM_ATTACH_NA(ifp, &vpna->up);
-	/* return the updated info */
-	error = nm_update_info(req, &vpna->up);
-	if (error) {
-		goto err_2;
-	}
-	ND("returning nr_mem_id %d", req->nr_mem_id);
-	if (nmd)
-		netmap_mem_put(nmd);
-	NMG_UNLOCK();
-	ND("created %s", ifp->if_xname);
-	return 0;
-
-err_2:
-	netmap_detach(ifp);
-err_1:
-	if (nmd)
-		netmap_mem_put(nmd);
-	NMG_UNLOCK();
-	nm_os_vi_detach(ifp);
-
-	return error;
-}
-
 
 /* Called by external kernel modules (e.g., Openvswitch).
  * to modify the private data previously given to regops().
@@ -1160,7 +984,7 @@ netmap_vp_txsync(struct netmap_kring *kring, int flags)
 /* create a netmap_vp_adapter that describes a VALE port.
  * Only persistent VALE ports have a non-null ifp.
  */
-int
+static int
 netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
@@ -1237,7 +1061,6 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 			req->nr_extra_bufs, npipes, &error);
 	if (na->nm_mem == NULL)
 		goto err;
-	na->nm_bdg_attach = netmap_vp_bdg_attach;
 	/* other nmd fields are set in the common routine */
 	error = netmap_attach_common(na);
 	if (error)
@@ -1252,5 +1075,254 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	return error;
 }
 
+static int
+netmap_vale_bwrap_krings_create(struct netmap_adapter *na)
+{
+	int error;
+
+	/* impersonate a netmap_vp_adapter */
+	error = netmap_vp_krings_create(na);
+	if (error)
+		return error;
+	error = netmap_bwrap_krings_create_common(na);
+	if (error) {
+		netmap_vp_krings_delete(na);
+	}
+	return error;
+}
+
+static void
+netmap_vale_bwrap_krings_delete(struct netmap_adapter *na)
+{
+	netmap_bwrap_krings_delete_common(na);
+	netmap_vp_krings_delete(na);
+}
+
+static int
+netmap_vale_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
+{
+	struct netmap_bwrap_adapter *bna;
+	struct netmap_adapter *na = NULL;
+	struct netmap_adapter *hostna = NULL;
+	int error;
+
+	bna = nm_os_malloc(sizeof(*bna));
+	if (bna == NULL) {
+		return ENOMEM;
+	}
+	na = &bna->up.up;
+	strncpy(na->name, nr_name, sizeof(na->name));
+	na->nm_register = netmap_bwrap_reg;
+	// na->nm_txsync = netmap_bwrap_txsync;
+	// na->nm_rxsync = netmap_bwrap_rxsync;
+	na->nm_krings_create = netmap_vale_bwrap_krings_create;
+	na->nm_krings_delete = netmap_vale_bwrap_krings_delete;
+	na->nm_notify = netmap_bwrap_notify;
+	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
+	/* Set the mfs, needed on the VALE mismatch datapath. */
+	bna->up.mfs = NM_BDG_MFS_DEFAULT;
+
+	if (hwna->na_flags & NAF_HOST_RINGS) {
+		hostna = &bna->host.up;
+		hostna->nm_notify = netmap_bwrap_notify;
+		bna->host.mfs = NM_BDG_MFS_DEFAULT;
+	}
+
+	error = netmap_bwrap_attach_common(na, hwna);
+	if (error) {
+		nm_os_free(bna);
+	}
+	return error;
+}
+
+struct nm_bdg_args vale_args = {
+	.name = NM_BDG_NAME,
+	.vp_attach = netmap_vp_create,
+	.bwrap_attach = netmap_vale_bwrap_attach,
+};
+
+int
+netmap_get_vale_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create)
+{
+	return netmap_get_bdg_na(hdr, na, nmd, create, &vale_args);
+}
+
+
+/* creates a persistent VALE port */
+int
+nm_vi_create(struct nmreq_header *hdr)
+{
+	struct nmreq_vale_newif *req =
+		(struct nmreq_vale_newif *)(uintptr_t)hdr->nr_body;
+	int error = 0;
+	/* Build a nmreq_register out of the nmreq_vale_newif,
+	 * so that we can call netmap_get_bdg_na(). */
+	struct nmreq_register regreq;
+	bzero(®req, sizeof(regreq));
+	regreq.nr_tx_slots = req->nr_tx_slots;
+	regreq.nr_rx_slots = req->nr_rx_slots;
+	regreq.nr_tx_rings = req->nr_tx_rings;
+	regreq.nr_rx_rings = req->nr_rx_rings;
+	regreq.nr_mem_id = req->nr_mem_id;
+	hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+	hdr->nr_body = (uintptr_t)®req;
+	error = netmap_vi_create(hdr, 0 /* no autodelete */);
+	hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+	hdr->nr_body = (uintptr_t)req;
+	/* Write back to the original struct. */
+	req->nr_tx_slots = regreq.nr_tx_slots;
+	req->nr_rx_slots = regreq.nr_rx_slots;
+	req->nr_tx_rings = regreq.nr_tx_rings;
+	req->nr_rx_rings = regreq.nr_rx_rings;
+	req->nr_mem_id = regreq.nr_mem_id;
+	return error;
+}
+
+/* remove a persistent VALE port from the system */
+int
+nm_vi_destroy(const char *name)
+{
+	struct ifnet *ifp;
+	struct netmap_vp_adapter *vpna;
+	int error;
+
+	ifp = ifunit_ref(name);
+	if (!ifp)
+		return ENXIO;
+	NMG_LOCK();
+	/* make sure this is actually a VALE port */
+	if (!NM_NA_VALID(ifp) || NA(ifp)->nm_register != netmap_vp_reg) {
+		error = EINVAL;
+		goto err;
+	}
+
+	vpna = (struct netmap_vp_adapter *)NA(ifp);
+
+	/* we can only destroy ports that were created via NETMAP_BDG_NEWIF */
+	if (vpna->autodelete) {
+		error = EINVAL;
+		goto err;
+	}
+
+	/* also make sure that nobody is using the inferface */
+	if (NETMAP_OWNED_BY_ANY(&vpna->up) ||
+	    vpna->up.na_refcount > 1 /* any ref besides the one in nm_vi_create()? */) {
+		error = EBUSY;
+		goto err;
+	}
+
+	NMG_UNLOCK();
+
+	D("destroying a persistent vale interface %s", ifp->if_xname);
+	/* Linux requires all the references are released
+	 * before unregister
+	 */
+	netmap_detach(ifp);
+	if_rele(ifp);
+	nm_os_vi_detach(ifp);
+	return 0;
+
+err:
+	NMG_UNLOCK();
+	if_rele(ifp);
+	return error;
+}
+
+static int
+nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
+{
+	req->nr_rx_rings = na->num_rx_rings;
+	req->nr_tx_rings = na->num_tx_rings;
+	req->nr_rx_slots = na->num_rx_desc;
+	req->nr_tx_slots = na->num_tx_desc;
+	return netmap_mem_get_info(na->nm_mem, &req->nr_memsize, NULL,
+					&req->nr_mem_id);
+}
+
+/*
+ * Create a virtual interface registered to the system.
+ * The interface will be attached to a bridge later.
+ */
+int
+netmap_vi_create(struct nmreq_header *hdr, int autodelete)
+{
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
+	struct ifnet *ifp;
+	struct netmap_vp_adapter *vpna;
+	struct netmap_mem_d *nmd = NULL;
+	int error;
+
+	if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
+		return EINVAL;
+	}
+
+	/* don't include VALE prefix */
+	if (!strncmp(hdr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME)))
+		return EINVAL;
+	if (strlen(hdr->nr_name) >= IFNAMSIZ) {
+		return EINVAL;
+	}
+	ifp = ifunit_ref(hdr->nr_name);
+	if (ifp) { /* already exist, cannot create new one */
+		error = EEXIST;
+		NMG_LOCK();
+		if (NM_NA_VALID(ifp)) {
+			int update_err = nm_update_info(req, NA(ifp));
+			if (update_err)
+				error = update_err;
+		}
+		NMG_UNLOCK();
+		if_rele(ifp);
+		return error;
+	}
+	error = nm_os_vi_persist(hdr->nr_name, &ifp);
+	if (error)
+		return error;
+
+	NMG_LOCK();
+	if (req->nr_mem_id) {
+		nmd = netmap_mem_find(req->nr_mem_id);
+		if (nmd == NULL) {
+			error = EINVAL;
+			goto err_1;
+		}
+	}
+	/* netmap_vp_create creates a struct netmap_vp_adapter */
+	error = netmap_vp_create(hdr, ifp, nmd, &vpna);
+	if (error) {
+		D("error %d", error);
+		goto err_1;
+	}
+	/* persist-specific routines */
+	vpna->up.nm_bdg_ctl = netmap_vp_bdg_ctl;
+	if (!autodelete) {
+		netmap_adapter_get(&vpna->up);
+	} else {
+		vpna->autodelete = 1;
+	}
+	NM_ATTACH_NA(ifp, &vpna->up);
+	/* return the updated info */
+	error = nm_update_info(req, &vpna->up);
+	if (error) {
+		goto err_2;
+	}
+	ND("returning nr_mem_id %d", req->nr_mem_id);
+	if (nmd)
+		netmap_mem_put(nmd);
+	NMG_UNLOCK();
+	ND("created %s", ifp->if_xname);
+	return 0;
+
+err_2:
+	netmap_detach(ifp);
+err_1:
+	if (nmd)
+		netmap_mem_put(nmd);
+	NMG_UNLOCK();
+	nm_os_vi_detach(ifp);
+
+	return error;
+}
 
 #endif /* WITH_VALE */

From cc2b7e36d54633d081579c642564469f1a34c330 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Jun 2018 20:15:33 +0200
Subject: [PATCH 0917/2207] bdg: modular organization of bridge

Generic bridge building blocks are now always
compiled-in.
---
 LINUX/netmap_linux.c         |   6 +-
 sys/dev/netmap/netmap.c      |   2 +-
 sys/dev/netmap/netmap_bdg.c  | 161 +++++++----------------------------
 sys/dev/netmap/netmap_bdg.h  |  24 +-----
 sys/dev/netmap/netmap_kern.h |  50 ++++++-----
 sys/dev/netmap/netmap_vale.c | 127 ++++++++++++++++++++++++---
 6 files changed, 178 insertions(+), 192 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4d7297f53..f8eae2986 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1458,7 +1458,6 @@ static struct file_operations netmap_fops = {
 };
 
 
-#ifdef WITH_VALE
 #ifdef CONFIG_NET_NS
 #include 
 
@@ -1595,7 +1594,6 @@ netmap_bns_unregister(void)
 #endif
 }
 #endif /* CONFIG_NET_NS */
-#endif /* WITH_VALE */
 
 /* ##################### kthread wrapper ##################### */
 #include 
@@ -2670,8 +2668,8 @@ EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
 EXPORT_SYMBOL(nm_bdg_update_private_data);
-EXPORT_SYMBOL(netmap_bdg_create);
-EXPORT_SYMBOL(netmap_bdg_destroy);
+EXPORT_SYMBOL(netmap_vale_create);
+EXPORT_SYMBOL(netmap_vale_destroy);
 EXPORT_SYMBOL(nm_bdg_ctl_attach);
 EXPORT_SYMBOL(nm_bdg_ctl_detach);
 EXPORT_SYMBOL(nm_vi_create);
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a90680cee..0837c0cc1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3370,7 +3370,7 @@ netmap_attach_common(struct netmap_adapter *na)
 		/* no special nm_bdg_attach callback. On VALE
 		 * attach, we need to interpose a bwrap
 		 */
-		na->nm_bdg_attach = netmap_bwrap_attach;
+		na->nm_bdg_attach = netmap_default_bdg_attach;
 #endif
 
 	return 0;
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 9387cafb6..77c23902d 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -108,7 +108,6 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #include 
 #include 
 
-#ifdef WITH_VALE
 #include 
 
 const char*
@@ -177,7 +176,7 @@ nm_vale_name_validate(const char *name)
  * We assume that this is called with a name of at least NM_NAME chars.
  */
 struct nm_bridge *
-nm_find_bridge(const char *name, int create)
+nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
 {
 	int i, namelen;
 	struct nm_bridge *b = NULL, *bridges;
@@ -223,7 +222,7 @@ nm_find_bridge(const char *name, int create)
 		for (i = 0; i < NM_BDG_MAXPORTS; i++)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
-		b->bdg_ops = &default_bdg_ops;
+		b->bdg_ops = ops;
 		b->private_data = b->ht;
 		b->bdg_flags = 0;
 		NM_BNS_GET(b);
@@ -232,7 +231,7 @@ nm_find_bridge(const char *name, int create)
 }
 
 
-static int
+int
 netmap_bdg_free(struct nm_bridge *b)
 {
 	if ((b->bdg_flags & NM_BDG_ACTIVE) + b->bdg_active_ports != 0) {
@@ -310,77 +309,6 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	netmap_bdg_free(b);
 }
 
-/* Allows external modules to create bridges in exclusive mode,
- * returns an authentication token that the external module will need
- * to provide during nm_bdg_ctl_{attach, detach}(), netmap_bdg_regops(),
- * and nm_bdg_update_private_data() operations.
- * Successfully executed if ret != NULL and *return_status == 0.
- */
-void *
-netmap_bdg_create(const char *bdg_name, int *return_status)
-{
-	struct nm_bridge *b = NULL;
-	void *ret = NULL;
-
-	NMG_LOCK();
-	b = nm_find_bridge(bdg_name, 0 /* don't create */);
-	if (b) {
-		*return_status = EEXIST;
-		goto unlock_bdg_create;
-	}
-
-	b = nm_find_bridge(bdg_name, 1 /* create */);
-	if (!b) {
-		*return_status = ENOMEM;
-		goto unlock_bdg_create;
-	}
-
-	b->bdg_flags |= NM_BDG_ACTIVE | NM_BDG_EXCLUSIVE;
-	ret = nm_bdg_get_auth_token(b);
-	*return_status = 0;
-
-unlock_bdg_create:
-	NMG_UNLOCK();
-	return ret;
-}
-
-/* Allows external modules to destroy a bridge created through
- * netmap_bdg_create(), the bridge must be empty.
- */
-int
-netmap_bdg_destroy(const char *bdg_name, void *auth_token)
-{
-	struct nm_bridge *b = NULL;
-	int ret = 0;
-
-	NMG_LOCK();
-	b = nm_find_bridge(bdg_name, 0 /* don't create */);
-	if (!b) {
-		ret = ENXIO;
-		goto unlock_bdg_free;
-	}
-
-	if (!nm_bdg_valid_auth_token(b, auth_token)) {
-		ret = EACCES;
-		goto unlock_bdg_free;
-	}
-	if (!(b->bdg_flags & NM_BDG_EXCLUSIVE)) {
-		ret = EINVAL;
-		goto unlock_bdg_free;
-	}
-
-	b->bdg_flags &= ~(NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE);
-	ret = netmap_bdg_free(b);
-	if (ret) {
-		b->bdg_flags |= NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE;
-	}
-
-unlock_bdg_free:
-	NMG_UNLOCK();
-	return ret;
-}
-
-
 
 /* nm_bdg_ctl callback for VALE ports */
 int
@@ -403,6 +331,12 @@ netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 	return 0;
 }
 
+int
+netmap_default_bdg_attach(const char *name, struct netmap_adapter *na,
+		struct nm_bridge *b)
+{
+	return NM_NEED_BWRAP;
+}
 
 /* Try to get a reference to a netmap adapter attached to a VALE switch.
  * If the adapter is found (or is created), this function returns 0, a
@@ -415,7 +349,7 @@ netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
  */
 int
 netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create, struct nm_bdg_args *args)
+	struct netmap_mem_d *nmd, int create, struct netmap_bdg_ops *ops)
 {
 	char *nr_name = hdr->nr_name;
 	const char *ifname;
@@ -431,20 +365,11 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	/* first try to see if this is a bridge port. */
 	NMG_LOCK_ASSERT();
-	if (strncmp(nr_name, NM_BDG_NAME, sizeof(NM_BDG_NAME) - 1)) {
+	if (strncmp(nr_name, ops->name, strlen(ops->name) - 1)) {
 		return 0;  /* no error, but no VALE prefix */
 	}
 
-	if (create) {
-		if (!args) {
-			return EINVAL;
-		}
-		if (strncmp(args->name, nr_name, strlen(args->name))) {
-			return 0;
-		}
-	}
-
-	b = nm_find_bridge(nr_name, create);
+	b = nm_find_bridge(nr_name, create, ops);
 	if (b == NULL) {
 		ND("no bridges available for '%s'", nr_name);
 		return (create ? ENOMEM : ENXIO);
@@ -503,7 +428,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = args->vp_attach(hdr, NULL, nmd, &vpna);
+		error = b->bdg_ops->vp_create(hdr, NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -532,7 +457,10 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			goto out;
 
 		/* host adapter might not be created */
-		error = hw->nm_bdg_attach(nr_name, hw, args);
+		error = hw->nm_bdg_attach(nr_name, hw, b);
+		if (error == NM_NEED_BWRAP) {
+			error = b->bdg_ops->bwrap_attach(nr_name, hw);
+		}
 		if (error)
 			goto out;
 		vpna = hw->na_vp;
@@ -589,7 +517,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 
 	NMG_LOCK();
 	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
 	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
 		error = EACCES;
 		goto unlock_exit;
@@ -604,23 +532,13 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 	}
 
 	/* check for existing one */
-	error = netmap_get_bdg_na(hdr, &na, nmd, 0, NULL);
+	error = netmap_get_vale_na(hdr, &na, nmd, 0);
 	if (!error) {
 		error = EBUSY;
 		goto unref_exit;
 	}
-	error = netmap_get_bdg_na(hdr, &na,
-				nmd, 1 /* create if not exists */, NULL);
-	do {
-		error = netmap_get_vale_na(hdr, &na,
+	error = netmap_get_vale_na(hdr, &na,
 				nmd, 1 /* create if not exists */);
-		if (error) { /* no device */
-			goto unlock_exit;
-		} else if (na != NULL) {
-			break;
-		}
-		/* other bridge's get_na listed here */
-	} while (0);
 	if (error) { /* no device */
 		goto unlock_exit;
 	}
@@ -675,13 +593,13 @@ nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
 
 	NMG_LOCK();
 	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
 	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
 		error = EACCES;
 		goto unlock_exit;
 	}
 
-	error = netmap_get_bdg_na(hdr, &na, NULL, 0 /* don't create */, NULL);
+	error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */);
 	if (error) { /* no device, or another bridge or user owns the device */
 		goto unlock_exit;
 	}
@@ -991,7 +909,7 @@ nm_bdg_polling(struct nmreq_header *hdr)
 	int error = 0;
 
 	NMG_LOCK();
-	error = netmap_get_bdg_na(hdr, &na, NULL, /*create=*/0, NULL);
+	error = netmap_get_vale_na(hdr, &na, NULL, /*create=*/0);
 	if (na && !error) {
 		if (!nm_is_bwrap(na)) {
 			error = EOPNOTSUPP;
@@ -1035,7 +953,7 @@ netmap_bdg_list(struct nmreq_header *hdr)
 			return EINVAL;
 		}
 		NMG_LOCK();
-		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */);
+		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
 		if (!b) {
 			NMG_UNLOCK();
 			return ENOENT;
@@ -1109,7 +1027,7 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *privat
 	int error = 0;
 
 	NMG_LOCK();
-	b = nm_find_bridge(name, 0 /* don't create */);
+	b = nm_find_bridge(name, 0 /* don't create */, NULL);
 	if (!b) {
 		error = ENXIO;
 		goto unlock_regops;
@@ -1123,7 +1041,7 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *privat
 	if (!bdg_ops) {
 		/* resetting the bridge */
 		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-		b->bdg_ops = &default_bdg_ops;
+		b->bdg_ops = NULL;
 		b->private_data = b->ht;
 	} else {
 		/* modifying the bridge */
@@ -1145,7 +1063,7 @@ netmap_bdg_config(struct nm_ifreq *nr)
 	int error = EINVAL;
 
 	NMG_LOCK();
-	b = nm_find_bridge(nr->nifr_name, 0);
+	b = nm_find_bridge(nr->nifr_name, 0, NULL);
 	if (!b) {
 		NMG_UNLOCK();
 		return error;
@@ -1270,27 +1188,9 @@ netmap_vp_rxsync(struct netmap_kring *kring, int flags)
 
 int
 netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna,
-		struct nm_bdg_args *args)
-{
-	return args->bwrap_attach(nr_name, hwna);
-}
-
-/* nm_bdg_attach callback for VALE ports
- * The na_vp port is this same netmap_adapter. There is no host port.
- */
-int
-netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na,
-		struct nm_bdg_args *args)
+		struct netmap_bdg_ops *ops)
 {
-	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
-
-	if (vpna->na_bdg) {
-		return netmap_bwrap_attach(name, na, args);
-	}
-	na->na_vp = vpna;
-	strncpy(na->name, name, sizeof(na->name));
-	na->na_hostvp = NULL;
-	return 0;
+	return ops->bwrap_attach(nr_name, hwna);
 }
 
 
@@ -1416,7 +1316,7 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 	 */
 	bkring->rhead = bkring->rcur = kring->nr_hwtail;
 
-	netmap_vp_txsync(bkring, flags);
+	bkring->nm_sync(bkring, flags);
 
 	/* mark all buffers as released on this ring */
 	kring->rhead = kring->rcur = kring->rtail = kring->nr_hwtail;
@@ -1907,4 +1807,3 @@ netmap_uninit_bridges(void)
 	netmap_uninit_bridges2(nm_bridges, NM_BRIDGES);
 #endif
 }
-#endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 13f3095a4..6e4048cec 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -90,13 +90,6 @@ struct nm_bridge {
 #endif /* CONFIG_NET_NS */
 };
 
-struct nm_bdg_args {
-	char name[IFNAMSIZ];
-	int (*vp_attach)(struct nmreq_header *hdr, struct ifnet *ifp,
-		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret);
-	int (*bwrap_attach)(const char *nr_name, struct netmap_adapter *hwna);
-};
-
 static inline void *
 nm_bdg_get_auth_token(struct nm_bridge *b)
 {
@@ -113,30 +106,21 @@ nm_bdg_valid_auth_token(struct nm_bridge *b, void *auth_token)
 }
 
 int netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create, struct nm_bdg_args *args);
+	struct netmap_mem_d *nmd, int create, struct netmap_bdg_ops *ops);
 
-struct nm_bridge *nm_find_bridge(const char *name, int create);
+struct nm_bridge *nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops);
+int netmap_bdg_free(struct nm_bridge *b);
 void netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw);
 int netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na);
 int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
 int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_vp_rxsync(struct netmap_kring *kring, int flags);
-int netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na,
-		struct nm_bdg_args *args);
 int netmap_bwrap_notify(struct netmap_kring *kring, int flags);
 int netmap_bwrap_attach_common(struct netmap_adapter *na,
 		struct netmap_adapter *hwna);
 int netmap_bwrap_krings_create_common(struct netmap_adapter *na);
 void netmap_bwrap_krings_delete_common(struct netmap_adapter *na);
-/* XXX Should go away after fixing find_bridge() - Michio */
-#ifdef WITH_VALE
-extern struct netmap_bdg_ops default_bdg_ops;
-#endif
-/* XXX Below functions should be static after modularizing vp creation - Michio */
-int
-netmap_vp_txsync(struct netmap_kring *kring, int flags);
-int netmap_vp_krings_create(struct netmap_adapter *na);
-void netmap_vp_krings_delete(struct netmap_adapter *na);
+#define NM_NEED_BWRAP (-2)
 #endif /* _NET_NETMAP_BDG_H_ */
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a892d1dce..31fb2b11c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -516,9 +516,7 @@ struct netmap_kring {
 	uint32_t pipe_tail;		/* hwtail updated by the other end */
 #endif /* WITH_PIPES */
 
-#ifdef WITH_VALE
 	int (*save_notify)(struct netmap_kring *kring, int flags);
-#endif
 
 #ifdef WITH_MONITOR
 	/* array of krings that are monitoring this kring */
@@ -641,6 +639,7 @@ struct netmap_lut {
 };
 
 struct netmap_vp_adapter; // forward
+struct nm_bridge;
 
 /* Struct to be filled by nm_config callbacks. */
 struct nm_config_info {
@@ -800,7 +799,6 @@ struct netmap_adapter {
 	int (*nm_config)(struct netmap_adapter *, struct nm_config_info *info);
 	int (*nm_krings_create)(struct netmap_adapter *);
 	void (*nm_krings_delete)(struct netmap_adapter *);
-#ifdef WITH_VALE
 	/*
 	 * nm_bdg_attach() initializes the na_vp field to point
 	 *      to an adapter that can be attached to a VALE switch. If the
@@ -817,7 +815,7 @@ struct netmap_adapter {
 	 *      Called with NMG_LOCK held.
 	 */
 	int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *,
-			struct nm_bdg_args *);
+			struct nm_bridge *);
 	int (*nm_bdg_ctl)(struct nmreq_header *, struct netmap_adapter *);
 
 	/* adapter used to attach this adapter to a VALE switch (if any) */
@@ -825,7 +823,6 @@ struct netmap_adapter {
 	/* adapter used to attach the host rings of this adapter
 	 * to a VALE switch (if any) */
 	struct netmap_vp_adapter *na_hostvp;
-#endif
 
 	/* standard refcount to control the lifetime of the adapter
 	 * (it should be equal to the lifetime of the corresponding ifp)
@@ -1011,7 +1008,8 @@ netmap_all_rings(struct netmap_adapter *na, enum txrx t)
 	return max(nma_get_nrings(na, t) + 1, netmap_real_rings(na, t));
 }
 
-#ifdef WITH_VALE
+int netmap_default_bdg_attach(const char *name, struct netmap_adapter *na,
+		struct nm_bridge *);
 struct nm_bdg_polling_state;
 /*
  * Bridge wrapper for non VALE ports attached to a VALE switch.
@@ -1079,12 +1077,12 @@ struct netmap_bwrap_adapter {
 int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_polling(struct nmreq_header *hdr);
-int netmap_bwrap_attach(const char *name, struct netmap_adapter *, struct nm_bdg_args *);
+int netmap_bdg_list(struct nmreq_header *hdr);
+
+#ifdef WITH_VALE
 int netmap_vi_create(struct nmreq_header *hdr, int);
 int nm_vi_create(struct nmreq_header *);
 int nm_vi_destroy(const char *name);
-int netmap_bdg_list(struct nmreq_header *hdr);
-
 #else /* !WITH_VALE */
 #define netmap_vi_create(hdr, a) (EOPNOTSUPP)
 #endif /* WITH_VALE */
@@ -1303,7 +1301,6 @@ const char *netmap_bdg_name(struct netmap_vp_adapter *);
 #define netmap_ifp_to_vp(_ifp)	NULL
 #define netmap_ifp_to_host_vp(_ifp) NULL
 #define netmap_bdg_idx(_vp)	-1
-#define netmap_bdg_name(_vp)	NULL
 #endif /* WITH_VALE */
 
 static inline int
@@ -1440,7 +1437,6 @@ int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
 
 
-#ifdef WITH_VALE
 /*
  * The following bridge-related functions are used by other
  * kernel modules.
@@ -1455,24 +1451,26 @@ typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
 typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
 typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
+typedef int (*bdg_vp_create_fn_t)(struct nmreq_header *hdr,
+		struct ifnet *ifp, struct netmap_mem_d *nmd,
+		struct netmap_vp_adapter **ret);
+typedef int (*bdg_bwrap_attach_fn_t)(const char *nr_name, struct netmap_adapter *hwna);
 struct netmap_bdg_ops {
 	bdg_lookup_fn_t lookup;
 	bdg_config_fn_t config;
 	bdg_dtor_fn_t	dtor;
+	bdg_vp_create_fn_t	vp_create;
+	bdg_bwrap_attach_fn_t	bwrap_attach;
+	char name[IFNAMSIZ];
 };
+int netmap_bwrap_attach(const char *name, struct netmap_adapter *, struct netmap_bdg_ops *);
 int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
 
-uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
-		struct netmap_vp_adapter *, void *private_data);
-
 #define	NM_BRIDGES		8	/* number of bridges */
 #define	NM_BDG_MAXPORTS		254	/* up to 254 */
 #define	NM_BDG_BROADCAST	NM_BDG_MAXPORTS
 #define	NM_BDG_NOPORT		(NM_BDG_MAXPORTS+1)
 
-/* these are redefined in case of no VALE support */
-int netmap_get_vale_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create);
 struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_init_bridges(void);
@@ -1480,14 +1478,22 @@ void netmap_uninit_bridges(void);
 int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
 	void *callback_data, void *auth_token);
 int netmap_bdg_config(struct nm_ifreq *nifr);
-void *netmap_bdg_create(const char *bdg_name, int *return_status);
-int netmap_bdg_destroy(const char *bdg_name, void *auth_token);
+
+#ifdef WITH_VALE
+uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
+		struct netmap_vp_adapter *, void *private_data);
+
+/* these are redefined in case of no VALE support */
+int netmap_get_vale_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create);
+void *netmap_vale_create(const char *bdg_name, int *return_status);
+int netmap_vale_destroy(const char *bdg_name, void *auth_token);
 
 #else /* !WITH_VALE */
+#define netmap_bdg_learning(_1, _2, _3, _4)	0
 #define	netmap_get_vale_na(_1, _2, _3, _4)	0
-#define netmap_init_bridges(_1) 0
-#define netmap_uninit_bridges()
-#define	netmap_bdg_regops(_1, _2)	EINVAL
+#define netmap_bdg_create(_1, _2)	NULL
+#define netmap_bdg_destroy(_1, _2)	0
 #endif /* !WITH_VALE */
 
 #ifdef WITH_PIPES
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 4cf4920e5..e5ce6db9c 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -120,6 +120,11 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
 		"Max batch size to be used in the bridge");
 SYSEND;
 
+static int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
+		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
+static int netmap_vp_bdg_attach(const char *, struct netmap_adapter *,
+		struct nm_bridge *);
+static int netmap_vale_bwrap_attach(const char *, struct netmap_adapter *);
 
 /*
  * For each output interface, nm_bdg_q is used to construct a list.
@@ -133,8 +138,14 @@ struct nm_bdg_q {
 };
 
 /* Holds the default callbacks */
-struct netmap_bdg_ops default_bdg_ops = {netmap_bdg_learning, NULL, NULL};
-
+struct netmap_bdg_ops vale_bdg_ops = {
+	.lookup = netmap_bdg_learning,
+	.config = NULL,
+	.dtor = NULL,
+	.vp_create = netmap_vp_create,
+	.bwrap_attach = netmap_vale_bwrap_attach,
+	.name = NM_BDG_NAME,
+};
 
 /*
  * this is a slightly optimized copy routine which rounds
@@ -225,6 +236,77 @@ nm_alloc_bdgfwd(struct netmap_adapter *na)
 	return 0;
 }
 
+/* Allows external modules to create bridges in exclusive mode,
+ * returns an authentication token that the external module will need
+ * to provide during nm_bdg_ctl_{attach, detach}(), netmap_bdg_regops(),
+ * and nm_bdg_update_private_data() operations.
+ * Successfully executed if ret != NULL and *return_status == 0.
+ */
+void *
+netmap_vale_create(const char *bdg_name, int *return_status)
+{
+	struct nm_bridge *b = NULL;
+	void *ret = NULL;
+
+	NMG_LOCK();
+	b = nm_find_bridge(bdg_name, 0 /* don't create */, NULL);
+	if (b) {
+		*return_status = EEXIST;
+		goto unlock_bdg_create;
+	}
+
+	b = nm_find_bridge(bdg_name, 1 /* create */, &vale_bdg_ops);
+	if (!b) {
+		*return_status = ENOMEM;
+		goto unlock_bdg_create;
+	}
+
+	b->bdg_flags |= NM_BDG_ACTIVE | NM_BDG_EXCLUSIVE;
+	ret = nm_bdg_get_auth_token(b);
+	*return_status = 0;
+
+unlock_bdg_create:
+	NMG_UNLOCK();
+	return ret;
+}
+
+/* Allows external modules to destroy a bridge created through
+ * netmap_bdg_create(), the bridge must be empty.
+ */
+int
+netmap_vale_destroy(const char *bdg_name, void *auth_token)
+{
+	struct nm_bridge *b = NULL;
+	int ret = 0;
+
+	NMG_LOCK();
+	b = nm_find_bridge(bdg_name, 0 /* don't create */, NULL);
+	if (!b) {
+		ret = ENXIO;
+		goto unlock_bdg_free;
+	}
+
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		ret = EACCES;
+		goto unlock_bdg_free;
+	}
+	if (!(b->bdg_flags & NM_BDG_EXCLUSIVE)) {
+		ret = EINVAL;
+		goto unlock_bdg_free;
+	}
+
+	b->bdg_flags &= ~(NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE);
+	ret = netmap_bdg_free(b);
+	if (ret) {
+		b->bdg_flags |= NM_BDG_EXCLUSIVE | NM_BDG_ACTIVE;
+	}
+
+unlock_bdg_free:
+	NMG_UNLOCK();
+	return ret;
+}
+
+
 
 /* nm_dtor callback for ephemeral VALE ports */
 static void
@@ -266,7 +348,7 @@ nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callba
 	int error = 0;
 
 	NMG_LOCK();
-	b = nm_find_bridge(name, 0 /* don't create */);
+	b = nm_find_bridge(name, 0 /* don't create */, NULL);
 	if (!b) {
 		error = EINVAL;
 		goto unlock_update_priv;
@@ -290,7 +372,7 @@ nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callba
  * Calls the standard netmap_krings_create, then adds leases on rx
  * rings and bdgfwd on tx rings.
  */
-int
+static int
 netmap_vp_krings_create(struct netmap_adapter *na)
 {
 	u_int tailroom;
@@ -325,7 +407,7 @@ netmap_vp_krings_create(struct netmap_adapter *na)
 
 
 /* nm_krings_delete callback for VALE ports. */
-void
+static void
 netmap_vp_krings_delete(struct netmap_adapter *na)
 {
 	nm_free_bdgfwd(na);
@@ -946,7 +1028,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 }
 
 /* nm_txsync callback for VALE ports */
-int
+static int
 netmap_vp_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_vp_adapter *na =
@@ -1061,6 +1143,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 			req->nr_extra_bufs, npipes, &error);
 	if (na->nm_mem == NULL)
 		goto err;
+	na->nm_bdg_attach = netmap_vp_bdg_attach;
 	/* other nmd fields are set in the common routine */
 	error = netmap_attach_common(na);
 	if (error)
@@ -1075,6 +1158,27 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	return error;
 }
 
+/* nm_bdg_attach callback for VALE ports
+ * The na_vp port is this same netmap_adapter. There is no host port.
+ */
+static int
+netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na,
+		struct nm_bridge *b)
+{
+	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
+
+	if (b->bdg_ops != &vale_bdg_ops) {
+		return NM_NEED_BWRAP;
+	}
+	if (vpna->na_bdg) {
+		return NM_NEED_BWRAP;
+	}
+	na->na_vp = vpna;
+	strncpy(na->name, name, sizeof(na->name));
+	na->na_hostvp = NULL;
+	return 0;
+}
+
 static int
 netmap_vale_bwrap_krings_create(struct netmap_adapter *na)
 {
@@ -1113,7 +1217,7 @@ netmap_vale_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	na = &bna->up.up;
 	strncpy(na->name, nr_name, sizeof(na->name));
 	na->nm_register = netmap_bwrap_reg;
-	// na->nm_txsync = netmap_bwrap_txsync;
+	na->nm_txsync = netmap_vp_txsync;
 	// na->nm_rxsync = netmap_bwrap_rxsync;
 	na->nm_krings_create = netmap_vale_bwrap_krings_create;
 	na->nm_krings_delete = netmap_vale_bwrap_krings_delete;
@@ -1135,17 +1239,11 @@ netmap_vale_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	return error;
 }
 
-struct nm_bdg_args vale_args = {
-	.name = NM_BDG_NAME,
-	.vp_attach = netmap_vp_create,
-	.bwrap_attach = netmap_vale_bwrap_attach,
-};
-
 int
 netmap_get_vale_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		struct netmap_mem_d *nmd, int create)
 {
-	return netmap_get_bdg_na(hdr, na, nmd, create, &vale_args);
+	return netmap_get_bdg_na(hdr, na, nmd, create, &vale_bdg_ops);
 }
 
 
@@ -1240,6 +1338,7 @@ nm_update_info(struct nmreq_register *req, struct netmap_adapter *na)
 					&req->nr_mem_id);
 }
 
+
 /*
  * Create a virtual interface registered to the system.
  * The interface will be attached to a bridge later.

From 960f303aedb5b8d3348c8962db5c0e562a39d856 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Jun 2018 22:16:22 +0200
Subject: [PATCH 0918/2207] bdg: correct error condition on nm_bdg_ctl_attach

---
 sys/dev/netmap/netmap_bdg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 77c23902d..5201d9829 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -510,7 +510,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 	struct nmreq_vale_attach *req =
 		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
 	struct netmap_vp_adapter * vpna;
-	struct netmap_adapter *na;
+	struct netmap_adapter *na = NULL;
 	struct netmap_mem_d *nmd = NULL;
 	struct nm_bridge *b = NULL;
 	int error;
@@ -533,7 +533,7 @@ nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
 
 	/* check for existing one */
 	error = netmap_get_vale_na(hdr, &na, nmd, 0);
-	if (!error) {
+	if (na) {
 		error = EBUSY;
 		goto unref_exit;
 	}

From 7c38612f380a5377e2d6653091a15d4ee7903900 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Fri, 29 Jun 2018 10:23:22 +0200
Subject: [PATCH 0919/2207] bdg: bug fix on ring allocation failure handling

---
 sys/dev/netmap/netmap_bdg.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 5201d9829..3929a057f 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1529,7 +1529,9 @@ netmap_bwrap_krings_create_common(struct netmap_adapter *na)
 
 err_dec_users:
 	for_rx_tx(t) {
-		NMR(hwna, t)[i]->users--;
+		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
+			NMR(hwna, t)[i]->users--;
+		}
 	}
 	hwna->nm_krings_delete(hwna);
 	return error;

From 21c6ade388558f0ba75bde0d68f03fc70d607516 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 30 Jun 2018 11:57:09 +0200
Subject: [PATCH 0920/2207] monitor: fix zmon chaining

---
 sys/dev/netmap/netmap_monitor.c | 134 +++++++++++++++++++-------------
 1 file changed, 82 insertions(+), 52 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 30e58accc..b35cf8f06 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -271,6 +271,21 @@ nm_monitor_restore_callbacks(struct netmap_kring *kring)
 	kring->mon_notify = NULL;
 }
 
+static struct netmap_kring *
+nm_zmon_list_head(struct netmap_kring *mkring, enum txrx t)
+{
+	struct netmap_adapter *na = mkring->na;
+	struct netmap_kring *kring = mkring;
+	struct netmap_zmon_list *z = &kring->zmon_list[t];
+	/* reach the head of the list */
+	while (nm_is_zmon(na) && z->prev != NULL) {
+		kring = z->prev;
+		na = kring->na;
+		z = &kring->zmon_list[t];
+	}
+	return nm_is_zmon(na) ? NULL : kring;
+}
+
 /* add the monitor mkring to the list of monitors of kring.
  * If this is the first monitor, intercept the callbacks
  */
@@ -281,19 +296,21 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 	enum txrx t = kring->tx;
 	struct netmap_zmon_list *z = &kring->zmon_list[t];
 	struct netmap_zmon_list *mz = &mkring->zmon_list[t];
+	struct netmap_kring *ikring = kring;
 
 	/* a zero-copy monitor which is not the first in the list
 	 * must monitor the previous monitor
 	 */
 	if (zmon && z->prev != NULL)
-		kring = z->prev;
+		ikring = z->prev; /* tail of the list */
 
 	/* synchronize with concurrently running nm_sync()s */
 	nm_kr_stop(kring, NM_KR_LOCKED);
 
-	if (nm_monitor_none(kring)) {
+	if (nm_monitor_none(ikring)) {
 		/* this is the first monitor, intercept the callbacks */
-		nm_monitor_intercept_callbacks(kring);
+		ND("%s: intercept callbacks on %s", mkring->name, ikring->name);
+		nm_monitor_intercept_callbacks(ikring);
 	}
 
 	if (zmon) {
@@ -302,18 +319,15 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 			(struct netmap_monitor_adapter *)mkring->na;
 		struct netmap_adapter *pna;
 
-		if (z->prev != NULL)
-			z->prev->zmon_list[t].next = mkring;
-		mz->prev = z->prev;
-		z->prev = mkring;
-		if (z->next == NULL)
-			z->next = mkring;
-
-		/* grap a reference to the previous netmap adapter
+		ikring->zmon_list[t].next = mkring;
+		z->prev = mkring; /* new tail */
+		mz->prev = ikring;
+		mz->next = NULL;
+		/* grab a reference to the previous netmap adapter
 		 * in the chain (this may be the monitored port
 		 * or another zero-copy monitor)
 		 */
-		pna = kring->na;
+		pna = ikring->na;
 		netmap_adapter_get(pna);
 		netmap_adapter_put(mna->priv.np_na);
 		mna->priv.np_na = pna;
@@ -336,30 +350,55 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
  * If this is the last monitor, restore the original callbacks
  */
 static void
-netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring)
+netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum txrx t)
 {
-	struct netmap_zmon_list *mz = &mkring->zmon_list[kring->tx];
 	int zmon = nm_is_zmon(mkring->na);
+	struct netmap_zmon_list *mz = &mkring->zmon_list[t];
+	struct netmap_kring *ikring = kring;
 
 
-	if (zmon && mz->prev != NULL)
-		kring = mz->prev;
+	if (zmon) {
+		/* get to the head of the list */
+		kring = nm_zmon_list_head(mkring, t);
+		ikring = mz->prev;
+	}
 
-	/* synchronize with concurrently running nm_sync()s */
-	nm_kr_stop(kring, NM_KR_LOCKED);
+	/* synchronize with concurrently running nm_sync()s
+	 * if kring is NULL (orphaned list) the monitored port
+	 * has exited netmap mode, so there is nothing to stop
+	 */
+	if (kring != NULL)
+		nm_kr_stop(kring, NM_KR_LOCKED);
 
 	if (zmon) {
+		struct netmap_monitor_adapter *mna =
+			(struct netmap_monitor_adapter *)mkring->na;
+
 		/* remove the monitor from the list */
-		if (mz->prev != NULL)
-			mz->prev->zmon_list[kring->tx].next = mz->next;
-		else
-			kring->zmon_list[kring->tx].next = mz->next;
-		mz->prev = NULL;
+		if (mz->prev != NULL) {
+			mz->prev->zmon_list[t].next = mz->next;
+		}
 		if (mz->next != NULL) {
-			mz->next->zmon_list[kring->tx].prev = mz->prev;
-		} else {
-			kring->zmon_list[kring->tx].prev = mz->prev;
+			struct netmap_adapter *pna = mna->priv.np_na;
+			struct netmap_monitor_adapter *next =
+				(struct netmap_monitor_adapter *)mz->next->na;
+			mz->next->zmon_list[t].prev = mz->prev;
+			/* we also need to let the next monitor drop the
+			 * reference to us and grab the reference to the
+			 * previous ring owner, instead
+			 */
+			if (pna != NULL)
+				netmap_adapter_get(pna);
+			netmap_adapter_put(next->priv.np_na); /* nop if null */
+			next->priv.np_na = pna;
+		} else if (kring != NULL) {
+			/* in the monitored kring, prev is actually the
+			 * pointer to the tail of the list
+			 */
+			kring->zmon_list[t].prev =
+				(mz->prev != kring ? mz->prev : NULL);
 		}
+		mz->prev = NULL;
 		mz->next = NULL;
 	} else {
 		/* this is a copy monitor */
@@ -376,12 +415,13 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring)
 		}
 	}
 
-	if (nm_monitor_none(kring)) {
+	if (ikring != NULL && nm_monitor_none(ikring)) {
 		/* this was the last monitor, restore the callbacks */
-		nm_monitor_restore_callbacks(kring);
+		nm_monitor_restore_callbacks(ikring);
 	}
 
-	nm_kr_start(kring);
+	if (kring != NULL)
+		nm_kr_start(kring);
 }
 
 
@@ -402,7 +442,7 @@ netmap_monitor_stop(struct netmap_adapter *na)
 
 		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
 			struct netmap_kring *kring = NMR(na, t)[i];
-			struct netmap_kring *zkring;
+			struct netmap_zmon_list *z = &kring->zmon_list[t];
 			u_int j;
 
 			for (j = 0; j < kring->n_monitors; j++) {
@@ -418,34 +458,24 @@ netmap_monitor_stop(struct netmap_adapter *na)
 				kring->monitors[j] = NULL;
 			}
 
-			zkring = kring->zmon_list[kring->tx].next;
-			if (zkring != NULL) {
-				struct netmap_monitor_adapter *next =
-					(struct netmap_monitor_adapter *)zkring->na;
-				/* let the next monitor forget about us */
-				if (next->priv.np_na != NULL) {
+			if (!nm_is_zmon(na)) {
+				/* we are the head of at most one list */
+				struct netmap_kring *zkring = z->next;
+				if (zkring != NULL) {
+					struct netmap_monitor_adapter *next =
+						(struct netmap_monitor_adapter *)zkring->na;
+					/* let the next monitor forget about us */
 					netmap_adapter_put(next->priv.np_na);
 					next->priv.np_na = NULL;
+					/* orhpan the zmon list */
+					zkring->zmon_list[t].prev = NULL;
 				}
-				if (nm_is_zmon(na)) {
-					struct netmap_monitor_adapter *this =
-							(struct netmap_monitor_adapter *)na;
-					struct netmap_adapter *pna = this->priv.np_na;
-					/* we are a monitor ourselves and we may
-					 * need to pass down the reference to
-					 * the previous adapter in the chain
-					 */
-					if (pna != NULL) {
-						netmap_adapter_get(pna);
-						next->priv.np_na = pna;
-					}
-				}
+				z->next = NULL;
+				z->prev = NULL;
 			}
 
 			if (!nm_monitor_none(kring)) {
-				struct netmap_zmon_list *z = &kring->zmon_list[t];
 
-				z->next = z->prev = NULL;
 				kring->n_monitors = 0;
 				nm_monitor_dealloc(kring);
 				nm_monitor_restore_callbacks(kring);
@@ -517,7 +547,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 						continue;
 					if (mna->flags & nm_txrx2flag(s)) {
 						kring = NMR(pna, s)[i];
-						netmap_monitor_del(mkring, kring);
+						netmap_monitor_del(mkring, kring, s);
 					}
 				}
 			}

From eed2978167bbc9786fe8414c206e8be9495ef95f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 30 Jun 2018 12:04:14 +0200
Subject: [PATCH 0921/2207] monitor: more useful monitor names

---
 sys/dev/netmap/netmap_kern.h    |  4 ++++
 sys/dev/netmap/netmap_monitor.c | 10 +++-------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 31fb2b11c..b14cde56e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -858,6 +858,10 @@ struct netmap_adapter {
 	unsigned rx_buf_maxsize;
 
 	char name[NETMAP_REQ_IFNAMSIZ]; /* used at least by pipes */
+
+#ifdef WITH_MONITOR
+	unsigned long	monitor_id;	/* debugging */
+#endif
 };
 
 static __inline u_int
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index b35cf8f06..2e68e05a5 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -888,7 +888,6 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct ifnet *ifp = NULL;
 	int  error;
 	int zcopy = (req->nr_flags & NR_ZCOPY_MON);
-	char monsuff[10] = "";
 
 	if (zcopy) {
 		req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
@@ -942,14 +941,11 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		D("ringid error");
 		goto free_out;
 	}
-	if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) {
-		snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]);
-	}
-	snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name,
-			monsuff,
+	snprintf(mna->up.name, sizeof(mna->up.name), "%s/%s%s%s#%lu", pna->name,
 			zcopy ? "z" : "",
 			(req->nr_flags & NR_MONITOR_RX) ? "r" : "",
-			(req->nr_flags & NR_MONITOR_TX) ? "t" : "");
+			(req->nr_flags & NR_MONITOR_TX) ? "t" : "",
+			pna->monitor_id++);
 
 	/* the monitor supports the host rings iff the parent does */
 	mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS);

From 37049c35442e6250210b8e693c05d76c0e34cf56 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 30 Jun 2018 14:13:50 +0200
Subject: [PATCH 0922/2207] monitor: don't assume there is only one host ring

---
 sys/dev/netmap/netmap_monitor.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 2e68e05a5..c6ada5a6a 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -440,7 +440,7 @@ netmap_monitor_stop(struct netmap_adapter *na)
 	for_rx_tx(t) {
 		u_int i;
 
-		for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
 			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_zmon_list *z = &kring->zmon_list[t];
 			u_int j;
@@ -507,7 +507,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 			return ENXIO;
 		}
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < netmap_all_rings(na, t); i++) {
 				mkring = NMR(na, t)[i];
 				if (!nm_kring_pending_on(mkring))
 					continue;
@@ -529,7 +529,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 		if (na->active_fds == 0)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < netmap_all_rings(na, t); i++) {
 				mkring = NMR(na, t)[i];
 				if (!nm_kring_pending_off(mkring))
 					continue;

From c5c2533e0fcd58c48a3b190bc75d3ee426677507 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 30 Jun 2018 16:56:21 +0200
Subject: [PATCH 0923/2207] monitor: fix reference counting

---
 sys/dev/netmap/netmap_monitor.c | 43 +++++++++++++++------------------
 1 file changed, 19 insertions(+), 24 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index c6ada5a6a..096f86c6e 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -152,6 +152,12 @@ netmap_monitor_txsync(struct netmap_kring *kring, int flags)
 static int
 netmap_monitor_rxsync(struct netmap_kring *kring, int flags)
 {
+	struct netmap_monitor_adapter *mna =
+		(struct netmap_monitor_adapter *)kring->na;
+	if (unlikely(mna->priv.np_na == NULL)) {
+		/* parent left netmap mode */
+		return EIO;
+	}
 	ND("%s %x", kring->name, flags);
 	kring->nr_hwcur = kring->rhead;
 	mb();
@@ -315,10 +321,6 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 
 	if (zmon) {
 		/* append the zmon to the list */
-		struct netmap_monitor_adapter *mna =
-			(struct netmap_monitor_adapter *)mkring->na;
-		struct netmap_adapter *pna;
-
 		ikring->zmon_list[t].next = mkring;
 		z->prev = mkring; /* new tail */
 		mz->prev = ikring;
@@ -327,10 +329,7 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 		 * in the chain (this may be the monitored port
 		 * or another zero-copy monitor)
 		 */
-		pna = ikring->na;
-		netmap_adapter_get(pna);
-		netmap_adapter_put(mna->priv.np_na);
-		mna->priv.np_na = pna;
+		netmap_adapter_get(ikring->na);
 	} else {
 		/* make sure the monitor array exists and is big enough */
 		error = nm_monitor_alloc(kring, kring->n_monitors + 1);
@@ -371,26 +370,19 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum
 		nm_kr_stop(kring, NM_KR_LOCKED);
 
 	if (zmon) {
-		struct netmap_monitor_adapter *mna =
-			(struct netmap_monitor_adapter *)mkring->na;
-
 		/* remove the monitor from the list */
 		if (mz->prev != NULL) {
 			mz->prev->zmon_list[t].next = mz->next;
 		}
 		if (mz->next != NULL) {
-			struct netmap_adapter *pna = mna->priv.np_na;
-			struct netmap_monitor_adapter *next =
-				(struct netmap_monitor_adapter *)mz->next->na;
 			mz->next->zmon_list[t].prev = mz->prev;
 			/* we also need to let the next monitor drop the
 			 * reference to us and grab the reference to the
 			 * previous ring owner, instead
 			 */
-			if (pna != NULL)
-				netmap_adapter_get(pna);
-			netmap_adapter_put(next->priv.np_na); /* nop if null */
-			next->priv.np_na = pna;
+			if (mz->prev != NULL)
+				netmap_adapter_get(mz->prev->na);
+			netmap_adapter_put(mkring->na);
 		} else if (kring != NULL) {
 			/* in the monitored kring, prev is actually the
 			 * pointer to the tail of the list
@@ -460,16 +452,19 @@ netmap_monitor_stop(struct netmap_adapter *na)
 
 			if (!nm_is_zmon(na)) {
 				/* we are the head of at most one list */
-				struct netmap_kring *zkring = z->next;
-				if (zkring != NULL) {
+				struct netmap_kring *zkring;
+				for (zkring = z->next; zkring != NULL;
+						zkring = zkring->zmon_list[t].next)
+				{
 					struct netmap_monitor_adapter *next =
 						(struct netmap_monitor_adapter *)zkring->na;
-					/* let the next monitor forget about us */
-					netmap_adapter_put(next->priv.np_na);
+					/* let the monitor forget about us */
+					netmap_adapter_put(next->priv.np_na); /* nop if null */
 					next->priv.np_na = NULL;
-					/* orhpan the zmon list */
-					zkring->zmon_list[t].prev = NULL;
 				}
+				/* orhpan the zmon list */
+				if (z->next != NULL)
+					z->next->zmon_list[t].prev = NULL;
 				z->next = NULL;
 				z->prev = NULL;
 			}

From 15d5daeb9d3e76867daef52f8529f5d908c6f239 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 15 Jun 2018 17:05:45 +0200
Subject: [PATCH 0924/2207] functional.c now uses a file descriptor server to
 retrieve netmap file descriptors

---
 utils/GNUmakefile       |   2 +-
 utils/file_des.h        |  45 ++++++
 utils/file_des_server.c | 345 ++++++++++++++++++++++++++++++++++++++++
 utils/functional.c      | 277 ++++++++++++++++++++++++++++++--
 4 files changed, 656 insertions(+), 13 deletions(-)
 create mode 100644 utils/file_des.h
 create mode 100644 utils/file_des_server.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 6169c3488..d8b04ccdb 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,6 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm functional ctrl-api-test
+PROGS	= test_select testmmap test_nm functional ctrl-api-test file_des_server
 X86PROGS = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/file_des.h b/utils/file_des.h
new file mode 100644
index 000000000..298c1125b
--- /dev/null
+++ b/utils/file_des.h
@@ -0,0 +1,45 @@
+#ifndef FD_LIB_H
+#define FD_LIB_H
+
+
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+
+
+
+struct fd_request {
+#define FD_GET		1
+#define FD_RELEASE	2
+#define FD_CLOSE	3
+#define FD_STOP		4
+	uint8_t action;
+	char if_name[IFNAMSIZ];
+};
+
+
+
+struct fd_response {
+	int32_t result;
+	struct nmreq req;
+};
+
+
+
+int
+send_fd(int socket, int fd, void *buf, size_t buf_size);
+
+
+
+int
+recv_fd(int socket, int *fd, void *buf, size_t buf_size);
+
+
+
+#endif /* FD_LIB_H */
\ No newline at end of file
diff --git a/utils/file_des_server.c b/utils/file_des_server.c
new file mode 100644
index 000000000..ea91ad804
--- /dev/null
+++ b/utils/file_des_server.c
@@ -0,0 +1,345 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "file_des.h"
+
+
+struct nmd_entry {
+	struct nm_desc *nmd;
+	uint8_t is_in_use;
+	uint8_t is_open;
+};
+
+
+#define SOCKET_NAME "/tmp/my_unix_socket"
+#define MAX_OPEN_IF 128
+struct nmd_entry entries[MAX_OPEN_IF];
+int num_entries = 0;
+
+
+
+static void
+print_request(struct fd_request *req)
+{
+
+	syslog(LOG_NOTICE, "d action: %s, if_name: %s\n",
+		req->action == FD_GET ? "FD_GET" :
+		req->action == FD_RELEASE ? "FD_RELEASE" :
+		req->action == FD_CLOSE ? "FD_CLOSE" :
+		"FD_STOP",
+		req->if_name
+	);
+}
+
+
+
+struct nmd_entry *
+search_des(const char *if_name)
+{
+	int i;
+
+	for (i = 0; i < num_entries; ++i) {
+		struct nmd_entry *entry = &entries[i];
+		struct nm_desc *nmd = entry->nmd;
+
+		if (entry->is_open == 0) {
+			continue;
+		}
+
+		if (strcmp(nmd->req.nr_name, if_name) == 0) {
+			return entry;
+		}
+	}
+
+	return NULL;
+}
+
+
+
+struct nmd_entry *
+get_free_des(int *ret)
+{
+
+	if (num_entries == MAX_OPEN_IF) {
+		*ret = -1;
+		return NULL;
+	}
+
+	*ret = 0;
+	return &entries[num_entries++];
+}
+
+
+
+int
+get_fd(const char *if_name, struct fd_response *res)
+{
+	struct nmd_entry *entry;
+	int ret;
+
+	entry = search_des(if_name);
+	if (entry != NULL) {
+		if (entry->is_in_use == 1) {
+			syslog(LOG_NOTICE, "if_name %s is in use\n", if_name);
+			res->result = EBUSY;
+			return -1;
+		}
+		memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
+		return entry->nmd->fd;
+	}
+
+	entry = get_free_des(&ret);
+	if (ret == -1) {
+		syslog(LOG_NOTICE, "Out of memory\n");
+		res->result = ENOMEM;
+		return -1;
+	}
+
+	entry->nmd = nm_open(if_name, NULL, 0, NULL);
+	if (entry->nmd == NULL) {
+		syslog(LOG_NOTICE, "Failed to nm_open(%s) with error %d\n", if_name, errno);
+		res->result = errno;
+		return -1;
+	}
+
+	memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
+	entry->is_in_use = 1;
+	entry->is_open = 1;
+	return entry->nmd->fd;
+}
+
+
+
+void
+release_fd(const char *if_name, struct fd_response *res)
+{
+	struct nmd_entry *entry;
+
+	entry = search_des(if_name);
+	if (entry == NULL) {
+		syslog(LOG_NOTICE, "if_name %s isn't open\n", if_name);
+		res->result = ENOENT;
+		return;
+	}
+
+	entry->is_in_use = 0;
+}
+
+
+
+void
+close_fd(const char *if_name, struct fd_response *res)
+{
+	struct nmd_entry *entry;
+	int ret;
+
+	if (if_name == NULL || strnlen(if_name, IFNAMSIZ) == 0) {
+		res->result = EINVAL;
+		return;
+	}
+
+	entry = search_des(if_name);
+	if (entry == NULL) {
+		res->result = ENOENT;
+		syslog(LOG_NOTICE, "if_name %s hasn't been opened\n", if_name);
+		return;
+	}
+
+	ret = nm_close(entry->nmd);
+	res->result = ret;
+	if (ret != 0) {
+		syslog(LOG_NOTICE, "error while close interface %s\n", if_name);
+		return;
+	}
+	entry->is_in_use = 0;
+	entry->is_open = 0;
+}
+
+
+
+int
+send_fd(int socket, int fd, void *buf, size_t buf_size)
+{
+	union {
+		char buf[CMSG_SPACE(sizeof(int))];
+		struct cmsghdr align;
+	} ancillary;
+	struct cmsghdr *cmsg;
+	struct iovec iov[1];
+	struct msghdr msg;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = buf_size;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+
+	if (fd >= 0) {
+		/* We need the ancillary data only when we're sending a file
+		 * descriptor, and a file descriptor cannot be negative.
+		 */
+		msg.msg_control = ancillary.buf;
+		msg.msg_controllen = sizeof(ancillary.buf);
+
+		cmsg = CMSG_FIRSTHDR(&msg);
+		cmsg->cmsg_level = SOL_SOCKET;
+		cmsg->cmsg_type = SCM_RIGHTS;
+		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+		*(int *)CMSG_DATA(cmsg) = fd;
+	}
+
+	return sendmsg(socket, &msg, 0);
+}
+
+
+
+int
+handle_request(int socket)
+{
+	struct fd_response res;
+	struct fd_request req;
+	int amount;
+	int fd = -1;
+
+	memset(&res, 0, sizeof(res));
+	memset(&req, 0, sizeof(req));
+
+	amount = recv(socket, &req, sizeof(struct fd_request), 0);
+	if (amount == -1) {
+		syslog(LOG_NOTICE, "error during recv()");
+		return -1;
+	}
+
+	print_request(&req);
+	memset(&res, 0, sizeof(res));
+	switch (req.action) {
+	case FD_GET:
+		fd = get_fd(req.if_name, &res);
+		break;
+	case FD_RELEASE:
+		release_fd(req.if_name, &res);
+		return 0;
+	case FD_CLOSE:
+		close_fd(req.if_name, &res);
+		return 0;
+	case FD_STOP:
+		syslog(LOG_NOTICE, "shutting down");
+		exit(EXIT_SUCCESS);
+		break;
+	default:
+		res.result = EOPNOTSUPP;
+	}
+
+	return send_fd(socket, fd, &res, sizeof(struct fd_response));
+}
+
+void
+main_loop(void)
+{
+	struct sockaddr_un name;
+	int socket_fd;
+	int ret;
+
+	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+	if (socket_fd == -1) {
+		syslog(LOG_NOTICE, "error during socket()");
+		exit(EXIT_FAILURE);
+	}
+
+	unlink(SOCKET_NAME);
+	memset(&name, 0, sizeof(struct sockaddr_un));
+	name.sun_family = AF_UNIX;
+	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
+	ret = bind(socket_fd, (const struct sockaddr *)&name,
+		sizeof(struct sockaddr_un));
+	if (ret == -1) {
+		syslog(LOG_NOTICE, "error during bind()");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = listen(socket_fd, 2);
+	if (ret == -1) {
+		syslog(LOG_NOTICE, "error during listen()");
+		exit(EXIT_FAILURE);
+	}
+
+	for (;;) {
+		int conn_fd;
+		int ret;
+
+		conn_fd = accept(socket_fd, NULL, NULL);
+		if (conn_fd == -1) {
+			syslog(LOG_NOTICE,
+				"error during accept(), shutting down");
+			exit(EXIT_FAILURE);
+		}
+
+		syslog(LOG_NOTICE, "handling a request");
+		ret = handle_request(conn_fd);
+		(void)ret;
+		close(conn_fd);
+	}
+}
+
+void
+daemonize(void)
+{
+	pid_t pid;
+	int i;
+
+	pid = fork();
+	if (pid < 0) {
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		exit(EXIT_SUCCESS);
+	}
+
+	if (setsid() < 0) {
+		exit(EXIT_FAILURE);
+	}
+
+	signal(SIGCHLD, SIG_IGN);
+	signal(SIGHUP, SIG_IGN);
+
+	pid = fork();
+	if (pid < 0) {
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		exit(EXIT_SUCCESS);
+	}
+
+	umask(0);
+	if (chdir("/") == -1) {
+		perror("chdir()");
+		exit(EXIT_FAILURE);
+	}
+	for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
+		close(i);
+	}
+
+	openlog("nm_fd_server", LOG_PID, LOG_DAEMON);
+}
+
+
+int
+main()
+{
+
+	daemonize();
+	main_loop();
+	return 0;
+}
\ No newline at end of file
diff --git a/utils/functional.c b/utils/functional.c
index d69dbe33f..9157bcc88 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -39,6 +39,16 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "file_des.h"
 
 #define ETH_ADDR_LEN 6
 
@@ -58,7 +68,7 @@ struct Event {
 };
 
 struct Global {
-	struct nm_desc *nmd;
+	struct nm_desc nmd;
 	const char *ifname;
 	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
@@ -86,6 +96,16 @@ struct Global {
 	unsigned num_loops;
 };
 
+void release_if_file_des(const char *);
+
+void
+clean_exit(struct Global *g)
+{
+
+	release_if_file_des(g->ifname);
+	exit(EXIT_FAILURE);
+}
+
 static void
 fill_packet_field(struct Global *g, unsigned offset, const char *content,
 		  unsigned content_len)
@@ -93,7 +113,7 @@ fill_packet_field(struct Global *g, unsigned offset, const char *content,
 	if (offset + content_len > sizeof(g->pktm)) {
 		printf("Packet layout overflow: %u + %u > %lu\n", offset,
 		       content_len, sizeof(g->pktm));
-		exit(EXIT_FAILURE);
+		clean_exit(g);
 	}
 
 	memcpy(g->pktm + offset, content, content_len);
@@ -272,7 +292,7 @@ tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
 static int
 tx_flush(struct Global *g)
 {
-	struct nm_desc *nmd = g->nmd;
+	struct nm_desc *nmd = &g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	int i;
@@ -306,7 +326,7 @@ tx_flush(struct Global *g)
 static int
 tx_one(struct Global *g)
 {
-	struct nm_desc *nmd = g->nmd;
+	struct nm_desc *nmd = &g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	unsigned int i;
@@ -394,7 +414,7 @@ ignore_received_frame(struct Global *g)
 static int
 rx_one(struct Global *g)
 {
-	struct nm_desc *nmd = g->nmd;
+	struct nm_desc *nmd = &g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	unsigned int i;
@@ -422,7 +442,7 @@ rx_one(struct Global *g)
 					       "large "
 					       "(>= %u bytes) ",
 					       g->pktr_len + slot->len);
-					exit(EXIT_FAILURE);
+					clean_exit(g);
 				}
 				memcpy(g->pktr + g->pktr_len, buf, slot->len);
 				g->pktr_len += slot->len;
@@ -467,6 +487,7 @@ rx_one(struct Global *g)
 			return -1;
 		}
 
+		printf("sleeping\n");
 		/* Retry after a short while. */
 		usleep(wait_ms * 1000);
 		elapsed_ms += wait_ms;
@@ -594,7 +615,8 @@ static struct Global _g;
 static void
 usage(void)
 {
-	printf("usage: ./functional [-h]\n"
+	printf("usage: ./functional [-h] "
+	       "[-s (shuts down the file descriptor server)]\n"
 	       "    -i NETMAP_PORT\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	       "    [-T TIMEOUT_SECS (=5)]\n"
@@ -613,6 +635,235 @@ usage(void)
 	       "40:b:2\n");
 }
 
+
+/* Copied from nm_open() */
+void
+fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
+{
+	uint32_t nr_reg;
+
+	memset(des, 0, sizeof(*des));
+	des->self = des;
+	des->fd = fd;
+	memcpy(&des->req, req, sizeof(des->req));
+	nr_reg = req->nr_flags & NR_REG_MASK;
+
+	if (nr_reg == NR_REG_SW) { /* host stack */
+		des->first_tx_ring = des->last_tx_ring = des->req.nr_tx_rings;
+		des->first_rx_ring = des->last_rx_ring = des->req.nr_rx_rings;
+	} else if (nr_reg ==  NR_REG_ALL_NIC) { /* only nic */
+		des->first_tx_ring = 0;
+		des->first_rx_ring = 0;
+		des->last_tx_ring = des->req.nr_tx_rings - 1;
+		des->last_rx_ring = des->req.nr_rx_rings - 1;
+	} else if (nr_reg ==  NR_REG_NIC_SW) {
+		des->first_tx_ring = 0;
+		des->first_rx_ring = 0;
+		des->last_tx_ring = des->req.nr_tx_rings;
+		des->last_rx_ring = des->req.nr_rx_rings;
+	} else if (nr_reg == NR_REG_ONE_NIC) {
+		/* XXX check validity */
+		des->first_tx_ring = des->last_tx_ring =
+		des->first_rx_ring = des->last_rx_ring = des->req.nr_ringid & NETMAP_RING_MASK;
+	} else { /* pipes */
+		des->first_tx_ring = des->last_tx_ring = 0;
+		des->first_rx_ring = des->last_rx_ring = 0;
+	}
+}
+
+#define MS_WAIT 50
+
+void
+start_file_des_server(void)
+{
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0) {
+		perror("fork()");
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		/* The fd_server needs to create the unix socket. Sleeping does
+		 * not guarantee a correct synchronization, but should be good
+		 * enough.
+		 */
+		usleep(MS_WAIT * 1000);
+		return;
+	}
+
+	execl("file_des_server",
+		"file_des_server",
+		(char *)NULL);
+}
+
+#define SOCKET_NAME "/tmp/my_unix_socket"
+
+int
+connect_to_fd_server(void)
+{
+	struct sockaddr_un name;
+	int socket_fd;
+	int ret;
+
+	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+	if (socket_fd == -1) {
+		perror("socket()");
+		return -1;
+	}
+
+	memset(&name, 0, sizeof(struct sockaddr_un));
+	name.sun_family = AF_UNIX;
+	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
+	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
+
+	ret = connect(socket_fd, (const struct sockaddr *)&name,
+		sizeof(struct sockaddr_un));
+	if (ret == 0) {
+		return socket_fd;
+	}
+	perror("connect()");
+
+	start_file_des_server();
+	ret = connect(socket_fd, (const struct sockaddr *)&name,
+		sizeof(struct sockaddr_un));
+	if (ret == -1) {
+		perror("Cannot connect to fd_server even after starting it");
+		return -1;
+	}
+
+	return socket_fd;
+}
+
+int
+recv_fd(int socket, int *fd, void *buf, size_t buf_size)
+{
+	union {
+		char buf[CMSG_SPACE(sizeof(int))];
+		struct cmsghdr align;
+	} ancillary;
+	struct fd_response *res;
+	struct cmsghdr *cmsg;
+	struct iovec iov[1];
+	struct msghdr msg;
+	int amount;
+
+	errno = 0;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = buf_size;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+
+	memset(ancillary.buf, 0, sizeof(ancillary.buf));
+	msg.msg_control = ancillary.buf;
+	msg.msg_controllen = sizeof(ancillary.buf);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+	amount = recvmsg(socket, &msg, 0);
+	if (amount < 0) {
+		return amount;
+	}
+
+	res = iov[0].iov_base;
+	if (res->result != 0) {
+		errno = res->result;
+		return -1;
+	}
+
+	/* If res->result == 0, we know for sure that a file descriptor has been
+	 * sent through the ancillary data.
+	 */
+	if (amount > 0) {
+		cmsg = CMSG_FIRSTHDR(&msg);
+		*fd = *(int *)CMSG_DATA(cmsg);
+	}
+
+	return amount;
+}
+
+int
+get_if_file_des(const char *if_name, struct nm_desc *nmd)
+{
+	struct fd_response res;
+	struct fd_request req;
+	int socket_fd;
+	int new_fd;
+	int ret;
+
+	socket_fd = connect_to_fd_server();
+
+	memset(&req, 0, sizeof(req));
+	req.action = FD_GET;
+	strncpy(req.if_name, if_name, sizeof(req.if_name));
+	ret = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	if (ret < 0) {
+		perror("send()");
+		return -1;
+	}
+
+	memset(&res, 0, sizeof(res));
+	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(struct fd_response));
+	if (ret < 0) {
+		perror("recv_fd()");
+		return -1;
+	}
+
+	fill_nm_desc(nmd, &res.req, new_fd);
+	if (nm_mmap(nmd, NULL) != 0) {
+		perror("nm_mmap()");
+		return -1;
+	}
+
+	close(socket_fd);
+	return 0;
+}
+
+void
+release_if_file_des(const char *if_name)
+{
+	struct fd_request req;
+	int socket_fd;
+	int ret;
+
+	socket_fd = connect_to_fd_server();
+
+	memset(&req, 0, sizeof(req));
+	req.action = FD_RELEASE;
+	strncpy(req.if_name, if_name, sizeof(req.if_name));
+
+	ret = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	if (ret <= 0) {
+		perror("send()");
+	}
+
+	close(socket_fd);
+}
+
+void
+stop_file_des_server(void)
+{
+	struct fd_request req;
+	int socket_fd;
+	int ret;
+
+	socket_fd = connect_to_fd_server();
+
+	memset(&req, 0, sizeof(req));
+	req.action = FD_STOP;
+	ret = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	if (ret <= 0) {
+		perror("send()");
+	}
+	close(socket_fd);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -621,7 +872,6 @@ main(int argc, char **argv)
 	int opt;
 
 	g->ifname	 = NULL;
-	g->nmd		  = NULL;
 	g->wait_link_secs = 0;
 	g->timeout_secs   = 5;
 	g->pktm_len       = 60;
@@ -637,12 +887,16 @@ main(int argc, char **argv)
 	g->ignore_if_not_matching = /*false=*/0;
 	g->verbose		  = 0;
 	g->num_loops		  = 1;
+	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hi:w:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hsi:w:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
 			return 0;
+		case 's':
+			stop_file_des_server();
+			return 0;
 
 		case 'i':
 			g->ifname = optarg;
@@ -724,8 +978,7 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	g->nmd = nm_open(g->ifname, NULL, 0, NULL);
-	if (g->nmd == NULL) {
+	if (get_if_file_des(g->ifname, &g->nmd) < 0) {
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		return -1;
 	}
@@ -775,7 +1028,7 @@ main(int argc, char **argv)
 	/* if we have sent something, wait for all tx to complete */
 	tx_flush(g);
 
-	nm_close(g->nmd);
+	release_if_file_des(g->ifname);
 
 	return 0;
 }

From ea083bff19a6279350b217b3d6b0592a60c41174 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 15 Jun 2018 22:37:16 +0200
Subject: [PATCH 0925/2207] can specify source and destination mac address when
 executing functional.c

---
 utils/GNUmakefile                        |  2 +-
 utils/{file_des_server.c => fd_server.c} |  2 +-
 utils/{file_des.h => fd_server.h}        |  0
 utils/functional.c                       | 66 +++++++++++++++++-------
 4 files changed, 48 insertions(+), 22 deletions(-)
 rename utils/{file_des_server.c => fd_server.c} (99%)
 rename utils/{file_des.h => fd_server.h} (100%)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index d8b04ccdb..d9d2458a5 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,6 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm functional ctrl-api-test file_des_server
+PROGS	= test_select testmmap test_nm functional ctrl-api-test fd_server
 X86PROGS = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/file_des_server.c b/utils/fd_server.c
similarity index 99%
rename from utils/file_des_server.c
rename to utils/fd_server.c
index ea91ad804..5e8bf2e50 100644
--- a/utils/file_des_server.c
+++ b/utils/fd_server.c
@@ -12,7 +12,7 @@
 #include 
 #include 
 
-#include "file_des.h"
+#include "fd_server.h"
 
 
 struct nmd_entry {
diff --git a/utils/file_des.h b/utils/fd_server.h
similarity index 100%
rename from utils/file_des.h
rename to utils/fd_server.h
diff --git a/utils/functional.c b/utils/functional.c
index 9157bcc88..ec41ccbfd 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -48,7 +48,7 @@
 #include 
 #include 
 #include 
-#include "file_des.h"
+#include "fd_server.h"
 
 #define ETH_ADDR_LEN 6
 
@@ -96,13 +96,13 @@ struct Global {
 	unsigned num_loops;
 };
 
-void release_if_file_des(const char *);
+void release_if_fd(const char *);
 
 void
 clean_exit(struct Global *g)
 {
 
-	release_if_file_des(g->ifname);
+	release_if_fd(g->ifname);
 	exit(EXIT_FAILURE);
 }
 
@@ -487,7 +487,6 @@ rx_one(struct Global *g)
 			return -1;
 		}
 
-		printf("sleeping\n");
 		/* Retry after a short while. */
 		usleep(wait_ms * 1000);
 		elapsed_ms += wait_ms;
@@ -674,7 +673,7 @@ fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
 #define MS_WAIT 50
 
 void
-start_file_des_server(void)
+start_fd_server(void)
 {
 	pid_t pid;
 
@@ -692,9 +691,7 @@ start_file_des_server(void)
 		return;
 	}
 
-	execl("file_des_server",
-		"file_des_server",
-		(char *)NULL);
+	execl("fd_server", "fd_server", (char *)NULL);
 }
 
 #define SOCKET_NAME "/tmp/my_unix_socket"
@@ -724,7 +721,7 @@ connect_to_fd_server(void)
 	}
 	perror("connect()");
 
-	start_file_des_server();
+	start_fd_server();
 	ret = connect(socket_fd, (const struct sockaddr *)&name,
 		sizeof(struct sockaddr_un));
 	if (ret == -1) {
@@ -789,7 +786,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 }
 
 int
-get_if_file_des(const char *if_name, struct nm_desc *nmd)
+get_if_fd(const char *if_name, struct nm_desc *nmd)
 {
 	struct fd_response res;
 	struct fd_request req;
@@ -826,7 +823,7 @@ get_if_file_des(const char *if_name, struct nm_desc *nmd)
 }
 
 void
-release_if_file_des(const char *if_name)
+release_if_fd(const char *if_name)
 {
 	struct fd_request req;
 	int socket_fd;
@@ -847,7 +844,7 @@ release_if_file_des(const char *if_name)
 }
 
 void
-stop_file_des_server(void)
+stop_fd_server(void)
 {
 	struct fd_request req;
 	int socket_fd;
@@ -864,12 +861,24 @@ stop_file_des_server(void)
 	close(socket_fd);
 }
 
+int
+parse_mac_address(const char *opt, char *mac)
+{
+	if (6 == sscanf(opt, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+			&mac[0], &mac[1], &mac[2],
+			&mac[3], &mac[4], &mac[5])) {
+		return 0;
+	}
+	return -1;
+}
+
 int
 main(int argc, char **argv)
 {
 	struct Global *g = &_g;
 	unsigned int i, c;
 	int opt;
+	int ret;
 
 	g->ifname	 = NULL;
 	g->wait_link_secs = 0;
@@ -889,15 +898,32 @@ main(int argc, char **argv)
 	g->num_loops		  = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hsi:w:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hcs:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
 			return 0;
-		case 's':
-			stop_file_des_server();
+
+		case 'c':
+			stop_fd_server();
 			return 0;
 
+		case 's':
+			ret = parse_mac_address(optarg, g->src_mac);
+			if (ret == -1) {
+				printf("Invalid source MAC address\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+
+		case 'd':
+			ret = parse_mac_address(optarg, g->dst_mac);
+			if (ret == -1) {
+				printf("Invalid destination MAC address\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+
 		case 'i':
 			g->ifname = optarg;
 			break;
@@ -978,7 +1004,7 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	if (get_if_file_des(g->ifname, &g->nmd) < 0) {
+	if (get_if_fd(g->ifname, &g->nmd) < 0) {
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		return -1;
 	}
@@ -1004,16 +1030,16 @@ main(int argc, char **argv)
 				switch (e->evtype) {
 				case EVENT_TYPE_TX:
 					if (tx_one(g)) {
-						return -1;
+						clean_exit(g);
 					}
 					break;
 
 				case EVENT_TYPE_RX:
 					if (rx_one(g)) {
-						return -1;
+						clean_exit(g);
 					}
 					if (rx_check(g)) {
-						return -1;
+						clean_exit(g);
 					}
 					break;
 
@@ -1028,7 +1054,7 @@ main(int argc, char **argv)
 	/* if we have sent something, wait for all tx to complete */
 	tx_flush(g);
 
-	release_if_file_des(g->ifname);
+	release_if_fd(g->ifname);
 
 	return 0;
 }

From b79f5e8e83a99fa1b73f30e2f33aa19ed98e9355 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 15 Jun 2018 23:41:51 +0200
Subject: [PATCH 0926/2207] added -n cli argument to functional.c, if specified
 the exit status will be 0 when no frames are received (the program timeouts)

---
 utils/functional.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index ec41ccbfd..050e1da24 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -73,6 +73,7 @@ struct Global {
 	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
+	int success_if_no_receive;
 	int verbose;
 
 #define MAX_PKT_SIZE 65536
@@ -479,12 +480,12 @@ rx_one(struct Global *g)
 			       "from RX "
 			       "ring #%d\n",
 			       g->pktr_len, frags, i);
-			return 0;
+			return g->success_if_no_receive == 1 ? -1 : 0;
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
 			printf("%s: Timeout\n", __func__);
-			return -1;
+			return g->success_if_no_receive == 1 ? 0 : -1;
 		}
 
 		/* Retry after a short while. */
@@ -719,8 +720,8 @@ connect_to_fd_server(void)
 	if (ret == 0) {
 		return socket_fd;
 	}
-	perror("connect()");
 
+	printf("fd_server down, trying to start it\n");
 	start_fd_server();
 	ret = connect(socket_fd, (const struct sockaddr *)&name,
 		sizeof(struct sockaddr_un));
@@ -851,6 +852,7 @@ stop_fd_server(void)
 	int ret;
 
 	socket_fd = connect_to_fd_server();
+	printf("shutting down fd_server\n");
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_STOP;
@@ -894,11 +896,12 @@ main(int argc, char **argv)
 	g->filler		  = 'a';
 	g->num_events		  = 0;
 	g->ignore_if_not_matching = /*false=*/0;
+	g->success_if_no_receive  = /*false=*/0;
 	g->verbose		  = 0;
 	g->num_loops		  = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hcs:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hcns:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -908,6 +911,11 @@ main(int argc, char **argv)
 			stop_fd_server();
 			return 0;
 
+		case 'n':
+			/* Not receiving means timing out */
+			g->success_if_no_receive = 1;
+			return 0;
+
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
 			if (ret == -1) {

From 43b7bf00f6d503f00e298cdba3db61619fe6617a Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 15 Jun 2018 23:42:22 +0200
Subject: [PATCH 0927/2207] created a bash script to check if functional.c
 works correctly

---
 utils/functional_tests/learning_bridge_test | 39 +++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100755 utils/functional_tests/learning_bridge_test

diff --git a/utils/functional_tests/learning_bridge_test b/utils/functional_tests/learning_bridge_test
new file mode 100755
index 000000000..a61cd0d4c
--- /dev/null
+++ b/utils/functional_tests/learning_bridge_test
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+./functional -c &>/dev/null
+sleep 0.1s
+echo "First send, every port should receive the frame."
+./functional -i vale:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
+p1=$!
+echo "PID 1: $p1"
+./functional -i vale:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
+p2=$!
+echo "PID 2: $p2"
+./functional -p 1s -i vale:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+echo "Exit value 1: $e1"
+echo "Exit value 2: $e2"
+
+echo "Second send, only v2 should receive the frame."
+./functional -i vale:v2 -r 100:c -d 10:10:10:10:10:10 -T 1 &>/dev/null &
+p3=$!
+./functional -n -i vale:v1 -r 100:c -T 1 -d 10:10:10:10:10:10 &>/dev/null &
+p4=$!
+./functional -i vale:v0 -t 100:c -d 10:10:10:10:10:10 &>/dev/null
+wait $p3
+e3=$?
+wait $p4
+e4=$?
+echo "Exit value 1: $e3"
+echo "Exit value 2: $e4"
+echo "=============================================="
+result=$(($e1 + $e2 + $e3 + $e4))
+if [ $result = 0 ] ; then
+	echo "Test successful"
+	exit 0
+else
+	echo "Test failed"
+	exit 1
+fi
\ No newline at end of file

From a33c378370e57124f9bc253d72b41be59fcef3da Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Sun, 17 Jun 2018 00:24:40 +0200
Subject: [PATCH 0928/2207] to avoid race conditions, fd_server is no longer
 started automatically after a failed connect() call. instead one must use the
 new cli argument -o.

---
 utils/functional.c                          | 25 ++++++++++-----------
 utils/functional_tests/learning_bridge_test |  7 +++---
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 050e1da24..af2408b11 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -671,7 +671,7 @@ fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
 	}
 }
 
-#define MS_WAIT 50
+#define MS_WAIT 10
 
 void
 start_fd_server(void)
@@ -714,23 +714,14 @@ connect_to_fd_server(void)
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
-
 	ret = connect(socket_fd, (const struct sockaddr *)&name,
 		sizeof(struct sockaddr_un));
 	if (ret == 0) {
 		return socket_fd;
 	}
 
-	printf("fd_server down, trying to start it\n");
-	start_fd_server();
-	ret = connect(socket_fd, (const struct sockaddr *)&name,
-		sizeof(struct sockaddr_un));
-	if (ret == -1) {
-		perror("Cannot connect to fd_server even after starting it");
-		return -1;
-	}
-
-	return socket_fd;
+	printf("fd_server offline\n");
+	return ret;
 }
 
 int
@@ -852,6 +843,10 @@ stop_fd_server(void)
 	int ret;
 
 	socket_fd = connect_to_fd_server();
+	if (socket_fd == -1) {
+		printf("server alredy down\n");
+		return;
+	}
 	printf("shutting down fd_server\n");
 
 	memset(&req, 0, sizeof(req));
@@ -901,7 +896,7 @@ main(int argc, char **argv)
 	g->num_loops		  = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hcns:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hcons:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -911,6 +906,10 @@ main(int argc, char **argv)
 			stop_fd_server();
 			return 0;
 
+		case 'o':
+			start_fd_server();
+			return 0;
+
 		case 'n':
 			/* Not receiving means timing out */
 			g->success_if_no_receive = 1;
diff --git a/utils/functional_tests/learning_bridge_test b/utils/functional_tests/learning_bridge_test
index a61cd0d4c..895bdff8b 100755
--- a/utils/functional_tests/learning_bridge_test
+++ b/utils/functional_tests/learning_bridge_test
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
-./functional -c &>/dev/null
-sleep 0.1s
+./functional -c
+./functional -o
 echo "First send, every port should receive the frame."
 ./functional -i vale:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p1=$!
@@ -8,7 +8,8 @@ echo "PID 1: $p1"
 ./functional -i vale:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p2=$!
 echo "PID 2: $p2"
-./functional -p 1s -i vale:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
+sleep 0.1s
+./functional -i vale:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
 wait $p1
 e1=$?
 wait $p2

From 31198f8801417de33566adebb50f60c1e5610a9b Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 18 Jun 2018 20:20:10 +0200
Subject: [PATCH 0929/2207] code formatted using clang-format

---
 utils/fd_server.c                             | 77 ++++++++-----------
 utils/fd_server.h                             | 30 ++------
 utils/functional.c                            | 65 ++++++++--------
 .../learning_bridge_test                      |  0
 4 files changed, 70 insertions(+), 102 deletions(-)
 rename utils/{functional_tests => }/learning_bridge_test (100%)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 5e8bf2e50..de56c383a 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -1,49 +1,44 @@
-#include 
-#include 
-#include 
-#include 
+#include 
 #include 
-#include 
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 #include 
+#include 
+#include 
 
 #include "fd_server.h"
 
-
 struct nmd_entry {
 	struct nm_desc *nmd;
 	uint8_t is_in_use;
 	uint8_t is_open;
 };
 
-
 #define SOCKET_NAME "/tmp/my_unix_socket"
 #define MAX_OPEN_IF 128
 struct nmd_entry entries[MAX_OPEN_IF];
 int num_entries = 0;
 
-
-
 static void
 print_request(struct fd_request *req)
 {
 
 	syslog(LOG_NOTICE, "d action: %s, if_name: %s\n",
-		req->action == FD_GET ? "FD_GET" :
-		req->action == FD_RELEASE ? "FD_RELEASE" :
-		req->action == FD_CLOSE ? "FD_CLOSE" :
-		"FD_STOP",
-		req->if_name
-	);
+	       req->action == FD_GET
+		       ? "FD_GET"
+		       : req->action == FD_RELEASE
+				 ? "FD_RELEASE"
+				 : req->action == FD_CLOSE ? "FD_CLOSE"
+							   : "FD_STOP",
+	       req->if_name);
 }
 
-
-
 struct nmd_entry *
 search_des(const char *if_name)
 {
@@ -51,7 +46,7 @@ search_des(const char *if_name)
 
 	for (i = 0; i < num_entries; ++i) {
 		struct nmd_entry *entry = &entries[i];
-		struct nm_desc *nmd = entry->nmd;
+		struct nm_desc *nmd     = entry->nmd;
 
 		if (entry->is_open == 0) {
 			continue;
@@ -65,8 +60,6 @@ search_des(const char *if_name)
 	return NULL;
 }
 
-
-
 struct nmd_entry *
 get_free_des(int *ret)
 {
@@ -80,8 +73,6 @@ get_free_des(int *ret)
 	return &entries[num_entries++];
 }
 
-
-
 int
 get_fd(const char *if_name, struct fd_response *res)
 {
@@ -108,19 +99,18 @@ get_fd(const char *if_name, struct fd_response *res)
 
 	entry->nmd = nm_open(if_name, NULL, 0, NULL);
 	if (entry->nmd == NULL) {
-		syslog(LOG_NOTICE, "Failed to nm_open(%s) with error %d\n", if_name, errno);
+		syslog(LOG_NOTICE, "Failed to nm_open(%s) with error %d\n",
+		       if_name, errno);
 		res->result = errno;
 		return -1;
 	}
 
 	memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
 	entry->is_in_use = 1;
-	entry->is_open = 1;
+	entry->is_open   = 1;
 	return entry->nmd->fd;
 }
 
-
-
 void
 release_fd(const char *if_name, struct fd_response *res)
 {
@@ -136,8 +126,6 @@ release_fd(const char *if_name, struct fd_response *res)
 	entry->is_in_use = 0;
 }
 
-
-
 void
 close_fd(const char *if_name, struct fd_response *res)
 {
@@ -156,18 +144,16 @@ close_fd(const char *if_name, struct fd_response *res)
 		return;
 	}
 
-	ret = nm_close(entry->nmd);
+	ret	 = nm_close(entry->nmd);
 	res->result = ret;
 	if (ret != 0) {
 		syslog(LOG_NOTICE, "error while close interface %s\n", if_name);
 		return;
 	}
 	entry->is_in_use = 0;
-	entry->is_open = 0;
+	entry->is_open   = 0;
 }
 
-
-
 int
 send_fd(int socket, int fd, void *buf, size_t buf_size)
 {
@@ -180,31 +166,29 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 	struct msghdr msg;
 
 	iov[0].iov_base = buf;
-	iov[0].iov_len = buf_size;
+	iov[0].iov_len  = buf_size;
 
 	memset(&msg, 0, sizeof(struct msghdr));
-	msg.msg_iov = iov;
+	msg.msg_iov    = iov;
 	msg.msg_iovlen = 1;
 
 	if (fd >= 0) {
 		/* We need the ancillary data only when we're sending a file
 		 * descriptor, and a file descriptor cannot be negative.
 		 */
-		msg.msg_control = ancillary.buf;
+		msg.msg_control    = ancillary.buf;
 		msg.msg_controllen = sizeof(ancillary.buf);
 
-		cmsg = CMSG_FIRSTHDR(&msg);
-		cmsg->cmsg_level = SOL_SOCKET;
-		cmsg->cmsg_type = SCM_RIGHTS;
-		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+		cmsg			= CMSG_FIRSTHDR(&msg);
+		cmsg->cmsg_level	= SOL_SOCKET;
+		cmsg->cmsg_type		= SCM_RIGHTS;
+		cmsg->cmsg_len		= CMSG_LEN(sizeof(int));
 		*(int *)CMSG_DATA(cmsg) = fd;
 	}
 
 	return sendmsg(socket, &msg, 0);
 }
 
-
-
 int
 handle_request(int socket)
 {
@@ -263,7 +247,7 @@ main_loop(void)
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	ret = bind(socket_fd, (const struct sockaddr *)&name,
-		sizeof(struct sockaddr_un));
+		   sizeof(struct sockaddr_un));
 	if (ret == -1) {
 		syslog(LOG_NOTICE, "error during bind()");
 		exit(EXIT_FAILURE);
@@ -282,7 +266,7 @@ main_loop(void)
 		conn_fd = accept(socket_fd, NULL, NULL);
 		if (conn_fd == -1) {
 			syslog(LOG_NOTICE,
-				"error during accept(), shutting down");
+			       "error during accept(), shutting down");
 			exit(EXIT_FAILURE);
 		}
 
@@ -334,7 +318,6 @@ daemonize(void)
 	openlog("nm_fd_server", LOG_PID, LOG_DAEMON);
 }
 
-
 int
 main()
 {
diff --git a/utils/fd_server.h b/utils/fd_server.h
index 298c1125b..027afd3c2 100644
--- a/utils/fd_server.h
+++ b/utils/fd_server.h
@@ -1,45 +1,31 @@
 #ifndef FD_LIB_H
 #define FD_LIB_H
 
-
-
-#include 
-#include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #define NETMAP_WITH_LIBS
 #include 
 
-
-
 struct fd_request {
-#define FD_GET		1
-#define FD_RELEASE	2
-#define FD_CLOSE	3
-#define FD_STOP		4
+#define FD_GET 1
+#define FD_RELEASE 2
+#define FD_CLOSE 3
+#define FD_STOP 4
 	uint8_t action;
 	char if_name[IFNAMSIZ];
 };
 
-
-
 struct fd_response {
 	int32_t result;
 	struct nmreq req;
 };
 
+int send_fd(int socket, int fd, void *buf, size_t buf_size);
 
-
-int
-send_fd(int socket, int fd, void *buf, size_t buf_size);
-
-
-
-int
-recv_fd(int socket, int *fd, void *buf, size_t buf_size);
-
-
+int recv_fd(int socket, int *fd, void *buf, size_t buf_size);
 
 #endif /* FD_LIB_H */
\ No newline at end of file
diff --git a/utils/functional.c b/utils/functional.c
index af2408b11..f3822350f 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -25,30 +25,30 @@
  * SUCH DAMAGE.
  */
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
 #define NETMAP_WITH_LIBS
+#include "fd_server.h"
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
-#include 
-#include 
 #include 
-#include 
-#include 
 #include 
-#include "fd_server.h"
 
 #define ETH_ADDR_LEN 6
 
@@ -635,7 +635,6 @@ usage(void)
 	       "40:b:2\n");
 }
 
-
 /* Copied from nm_open() */
 void
 fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
@@ -644,27 +643,28 @@ fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
 
 	memset(des, 0, sizeof(*des));
 	des->self = des;
-	des->fd = fd;
+	des->fd   = fd;
 	memcpy(&des->req, req, sizeof(des->req));
 	nr_reg = req->nr_flags & NR_REG_MASK;
 
 	if (nr_reg == NR_REG_SW) { /* host stack */
 		des->first_tx_ring = des->last_tx_ring = des->req.nr_tx_rings;
 		des->first_rx_ring = des->last_rx_ring = des->req.nr_rx_rings;
-	} else if (nr_reg ==  NR_REG_ALL_NIC) { /* only nic */
+	} else if (nr_reg == NR_REG_ALL_NIC) { /* only nic */
 		des->first_tx_ring = 0;
 		des->first_rx_ring = 0;
-		des->last_tx_ring = des->req.nr_tx_rings - 1;
-		des->last_rx_ring = des->req.nr_rx_rings - 1;
-	} else if (nr_reg ==  NR_REG_NIC_SW) {
+		des->last_tx_ring  = des->req.nr_tx_rings - 1;
+		des->last_rx_ring  = des->req.nr_rx_rings - 1;
+	} else if (nr_reg == NR_REG_NIC_SW) {
 		des->first_tx_ring = 0;
 		des->first_rx_ring = 0;
-		des->last_tx_ring = des->req.nr_tx_rings;
-		des->last_rx_ring = des->req.nr_rx_rings;
+		des->last_tx_ring  = des->req.nr_tx_rings;
+		des->last_rx_ring  = des->req.nr_rx_rings;
 	} else if (nr_reg == NR_REG_ONE_NIC) {
 		/* XXX check validity */
-		des->first_tx_ring = des->last_tx_ring =
-		des->first_rx_ring = des->last_rx_ring = des->req.nr_ringid & NETMAP_RING_MASK;
+		des->first_tx_ring = des->last_tx_ring = des->first_rx_ring =
+			des->last_rx_ring =
+				des->req.nr_ringid & NETMAP_RING_MASK;
 	} else { /* pipes */
 		des->first_tx_ring = des->last_tx_ring = 0;
 		des->first_rx_ring = des->last_rx_ring = 0;
@@ -715,7 +715,7 @@ connect_to_fd_server(void)
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
 	ret = connect(socket_fd, (const struct sockaddr *)&name,
-		sizeof(struct sockaddr_un));
+		      sizeof(struct sockaddr_un));
 	if (ret == 0) {
 		return socket_fd;
 	}
@@ -740,20 +740,20 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	errno = 0;
 
 	iov[0].iov_base = buf;
-	iov[0].iov_len = buf_size;
+	iov[0].iov_len  = buf_size;
 
 	memset(&msg, 0, sizeof(struct msghdr));
-	msg.msg_iov = iov;
+	msg.msg_iov    = iov;
 	msg.msg_iovlen = 1;
 
 	memset(ancillary.buf, 0, sizeof(ancillary.buf));
-	msg.msg_control = ancillary.buf;
+	msg.msg_control    = ancillary.buf;
 	msg.msg_controllen = sizeof(ancillary.buf);
 
-	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg		 = CMSG_FIRSTHDR(&msg);
 	cmsg->cmsg_level = SOL_SOCKET;
-	cmsg->cmsg_type = SCM_RIGHTS;
-	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+	cmsg->cmsg_type  = SCM_RIGHTS;
+	cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
 
 	amount = recvmsg(socket, &msg, 0);
 	if (amount < 0) {
@@ -771,7 +771,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	 */
 	if (amount > 0) {
 		cmsg = CMSG_FIRSTHDR(&msg);
-		*fd = *(int *)CMSG_DATA(cmsg);
+		*fd  = *(int *)CMSG_DATA(cmsg);
 	}
 
 	return amount;
@@ -851,7 +851,7 @@ stop_fd_server(void)
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_STOP;
-	ret = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	ret	= send(socket_fd, &req, sizeof(struct fd_request), 0);
 	if (ret <= 0) {
 		perror("send()");
 	}
@@ -861,9 +861,8 @@ stop_fd_server(void)
 int
 parse_mac_address(const char *opt, char *mac)
 {
-	if (6 == sscanf(opt, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
-			&mac[0], &mac[1], &mac[2],
-			&mac[3], &mac[4], &mac[5])) {
+	if (6 == sscanf(opt, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1],
+			&mac[2], &mac[3], &mac[4], &mac[5])) {
 		return 0;
 	}
 	return -1;
@@ -882,10 +881,10 @@ main(int argc, char **argv)
 	g->timeout_secs   = 5;
 	g->pktm_len       = 60;
 	g->max_frag_size  = ~0U; /* unlimited */
-	for (i = 0; i < ETH_ADDR_LEN; i++)
+	for (i		      = 0; i < ETH_ADDR_LEN; i++)
 		g->src_mac[i] = 0x00;
-	for (i = 0; i < ETH_ADDR_LEN; i++)
-		g->dst_mac[i] = 0xFF;
+	for (i			  = 0; i < ETH_ADDR_LEN; i++)
+		g->dst_mac[i]     = 0xFF;
 	g->src_ip		  = 0x0A000005; /* 10.0.0.5 */
 	g->dst_ip		  = 0x0A000007; /* 10.0.0.7 */
 	g->filler		  = 'a';
diff --git a/utils/functional_tests/learning_bridge_test b/utils/learning_bridge_test
similarity index 100%
rename from utils/functional_tests/learning_bridge_test
rename to utils/learning_bridge_test

From cabbcb801a7f11d0a3e2396930fe37fd667a5d1d Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 18 Jun 2018 22:03:31 +0200
Subject: [PATCH 0930/2207] use NETMAP_REQ_IFNAMSIZ instead of IFNAMSIZ for
 interface name max length

---
 utils/fd_server.c | 2 +-
 utils/fd_server.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index de56c383a..a1591b1a6 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -132,7 +132,7 @@ close_fd(const char *if_name, struct fd_response *res)
 	struct nmd_entry *entry;
 	int ret;
 
-	if (if_name == NULL || strnlen(if_name, IFNAMSIZ) == 0) {
+	if (if_name == NULL || strnlen(if_name, NETMAP_REQ_IFNAMSIZ) == 0) {
 		res->result = EINVAL;
 		return;
 	}
diff --git a/utils/fd_server.h b/utils/fd_server.h
index 027afd3c2..8497aea1c 100644
--- a/utils/fd_server.h
+++ b/utils/fd_server.h
@@ -16,7 +16,7 @@ struct fd_request {
 #define FD_CLOSE 3
 #define FD_STOP 4
 	uint8_t action;
-	char if_name[IFNAMSIZ];
+	char if_name[NETMAP_REQ_IFNAMSIZ];
 };
 
 struct fd_response {

From ca4fc5341ac8bb8a8ab5b7c699a9113f239f6d4b Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 19 Jun 2018 13:15:07 +0200
Subject: [PATCH 0931/2207] fix clang-format alignment for consecutive
 assignments

---
 .clang-format      |   2 +-
 utils/fd_server.c  |  22 +++++-----
 utils/functional.c | 105 ++++++++++++++++++++++++---------------------
 3 files changed, 67 insertions(+), 62 deletions(-)

diff --git a/.clang-format b/.clang-format
index 75ada3d24..b9155064a 100644
--- a/.clang-format
+++ b/.clang-format
@@ -8,4 +8,4 @@ ConstructorInitializerIndentWidth: 8
 ContinuationIndentWidth: 8
 IndentCaseLabels: false
 IndentWidth: 8
-UseTab: Always
+UseTab: ForIndentation
\ No newline at end of file
diff --git a/utils/fd_server.c b/utils/fd_server.c
index a1591b1a6..4fdac41c1 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -31,11 +31,11 @@ print_request(struct fd_request *req)
 
 	syslog(LOG_NOTICE, "d action: %s, if_name: %s\n",
 	       req->action == FD_GET
-		       ? "FD_GET"
-		       : req->action == FD_RELEASE
-				 ? "FD_RELEASE"
-				 : req->action == FD_CLOSE ? "FD_CLOSE"
-							   : "FD_STOP",
+	               ? "FD_GET"
+	               : req->action == FD_RELEASE
+	                         ? "FD_RELEASE"
+	                         : req->action == FD_CLOSE ? "FD_CLOSE"
+	                                                   : "FD_STOP",
 	       req->if_name);
 }
 
@@ -144,7 +144,7 @@ close_fd(const char *if_name, struct fd_response *res)
 		return;
 	}
 
-	ret	 = nm_close(entry->nmd);
+	ret         = nm_close(entry->nmd);
 	res->result = ret;
 	if (ret != 0) {
 		syslog(LOG_NOTICE, "error while close interface %s\n", if_name);
@@ -179,10 +179,10 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 		msg.msg_control    = ancillary.buf;
 		msg.msg_controllen = sizeof(ancillary.buf);
 
-		cmsg			= CMSG_FIRSTHDR(&msg);
-		cmsg->cmsg_level	= SOL_SOCKET;
-		cmsg->cmsg_type		= SCM_RIGHTS;
-		cmsg->cmsg_len		= CMSG_LEN(sizeof(int));
+		cmsg                    = CMSG_FIRSTHDR(&msg);
+		cmsg->cmsg_level        = SOL_SOCKET;
+		cmsg->cmsg_type         = SCM_RIGHTS;
+		cmsg->cmsg_len          = CMSG_LEN(sizeof(int));
 		*(int *)CMSG_DATA(cmsg) = fd;
 	}
 
@@ -247,7 +247,7 @@ main_loop(void)
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	ret = bind(socket_fd, (const struct sockaddr *)&name,
-		   sizeof(struct sockaddr_un));
+	           sizeof(struct sockaddr_un));
 	if (ret == -1) {
 		syslog(LOG_NOTICE, "error during bind()");
 		exit(EXIT_FAILURE);
diff --git a/utils/functional.c b/utils/functional.c
index f3822350f..203efeb2c 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -109,7 +109,7 @@ clean_exit(struct Global *g)
 
 static void
 fill_packet_field(struct Global *g, unsigned offset, const char *content,
-		  unsigned content_len)
+                  unsigned content_len)
 {
 	if (offset + content_len > sizeof(g->pktm)) {
 		printf("Packet layout overflow: %u + %u > %lu\n", offset,
@@ -150,8 +150,9 @@ checksum(const void *data, uint16_t len, uint32_t sum /* host endianness */)
 	/* Checksum all the pairs of bytes first... */
 	for (i = 0; i < (len & ~1U); i += 2) {
 		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
-		if (sum > 0xFFFF)
+		if (sum > 0xFFFF) {
 			sum -= 0xFFFF;
+		}
 	}
 	/*
 	 * If there's a single byte left over, checksum it, too.
@@ -160,8 +161,9 @@ checksum(const void *data, uint16_t len, uint32_t sum /* host endianness */)
 	 */
 	if (i < len) {
 		sum += addr[i] << 8;
-		if (sum > 0xFFFF)
+		if (sum > 0xFFFF) {
 			sum -= 0xFFFF;
+		}
 	}
 	return sum;
 }
@@ -203,7 +205,7 @@ build_packet(struct Global *g)
 	ipofs = ofs;
 	/* First byte of IP header. */
 	fill_packet_8bit(g, ofs,
-			 (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
+	                 (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
 	ofs += 1;
 	/* Skip QoS byte. */
 	ofs += 1;
@@ -231,8 +233,8 @@ build_packet(struct Global *g)
 	ofs += 4;
 	/* Now put the checksum. */
 	fill_packet_16bit(
-		g, ipofs + 10,
-		wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
+	        g, ipofs + 10,
+	        wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
 	if (g->verbose) {
 		printf("%s: ip done, ofs %u\n", __func__, ofs);
 	}
@@ -265,17 +267,17 @@ build_packet(struct Global *g)
 	/* Put the UDP checksum now.
 	 * Magic: taken from sbin/dhclient/packet.c */
 	fill_packet_16bit(
-		g, udpofs + 6,
-		wrapsum(checksum(
-			/* udp header */ g->pktm + udpofs,
-			sizeof(struct udphdr),
-			checksum(/* udp payload */ g->pktm + pldofs,
-				 g->pktm_len - pldofs,
-				 checksum(/* pseudo header */ g->pktm + ipofs +
-						  12,
-					  2 * sizeof(g->src_ip),
-					  IPPROTO_UDP + (uint32_t)(g->pktm_len -
-								   udpofs))))));
+	        g, udpofs + 6,
+	        wrapsum(checksum(
+	                /* udp header */ g->pktm + udpofs,
+	                sizeof(struct udphdr),
+	                checksum(/* udp payload */ g->pktm + pldofs,
+	                         g->pktm_len - pldofs,
+	                         checksum(/* pseudo header */ g->pktm + ipofs +
+	                                          12,
+	                                  2 * sizeof(g->src_ip),
+	                                  IPPROTO_UDP + (uint32_t)(g->pktm_len -
+	                                                           udpofs))))));
 }
 
 static unsigned
@@ -306,8 +308,9 @@ tx_flush(struct Global *g)
 			pending += nm_tx_pending(ring);
 		}
 
-		if (!pending)
+		if (!pending) {
 			return 0;
+		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
 			printf("%s: Timeout\n", __func__);
@@ -335,9 +338,9 @@ tx_one(struct Global *g)
 	for (;;) {
 		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
-			unsigned head		 = ring->head;
-			unsigned frags		 = 0;
-			unsigned ofs		 = 0;
+			unsigned head            = ring->head;
+			unsigned frags           = 0;
+			unsigned ofs             = 0;
 
 			if (tx_bytes_avail(ring, g->max_frag_size) <
 			    g->pktm_len) {
@@ -360,7 +363,7 @@ tx_one(struct Global *g)
 				ofs += copysize;
 				slot->len   = copysize;
 				slot->flags = NS_MOREFRAG;
-				head	= nm_ring_next(ring, head);
+				head        = nm_ring_next(ring, head);
 				frags++;
 				if (ofs >= g->pktm_len) {
 					/* Last fragment. */
@@ -424,9 +427,9 @@ rx_one(struct Global *g)
 	again:
 		for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
-			unsigned int head	= ring->head;
+			unsigned int head        = ring->head;
 			unsigned int frags       = 0;
-			int truncated		 = 0;
+			int truncated            = 0;
 
 			if (nm_ring_empty(ring)) {
 				continue;
@@ -540,8 +543,8 @@ parse_txrx_event(const char *opt, unsigned event_type, struct Event *event)
 
 	for (c = strbuf; *c != '\0' && *c != ':'; c++) {
 	}
-	more	   = (*c == ':');
-	*c	     = '\0';
+	more           = (*c == ':');
+	*c             = '\0';
 	event->pkt_len = atoi(strbuf);
 	if (event->pkt_len == 0) {
 		goto out;
@@ -550,8 +553,8 @@ parse_txrx_event(const char *opt, unsigned event_type, struct Event *event)
 		strbuf = c + 1;
 		for (c = strbuf; *c != '\0' && *c != ':'; c++) {
 		}
-		more	  = (*c == ':');
-		*c	    = '\0';
+		more          = (*c == ':');
+		*c            = '\0';
 		event->filler = strbuf[0];
 	}
 	if (more) {
@@ -601,7 +604,7 @@ parse_pause_event(const char *opt, struct Event *event)
 	}
 	event->usecs *= mul;
 	event->num = 1;
-	ret	= 0;
+	ret        = 0;
 out:
 #if 0
 	printf("parsed %llu usecs\n", event->usecs);
@@ -663,8 +666,8 @@ fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
 	} else if (nr_reg == NR_REG_ONE_NIC) {
 		/* XXX check validity */
 		des->first_tx_ring = des->last_tx_ring = des->first_rx_ring =
-			des->last_rx_ring =
-				des->req.nr_ringid & NETMAP_RING_MASK;
+		        des->last_rx_ring =
+		                des->req.nr_ringid & NETMAP_RING_MASK;
 	} else { /* pipes */
 		des->first_tx_ring = des->last_tx_ring = 0;
 		des->first_rx_ring = des->last_rx_ring = 0;
@@ -715,7 +718,7 @@ connect_to_fd_server(void)
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
 	ret = connect(socket_fd, (const struct sockaddr *)&name,
-		      sizeof(struct sockaddr_un));
+	              sizeof(struct sockaddr_un));
 	if (ret == 0) {
 		return socket_fd;
 	}
@@ -750,7 +753,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	msg.msg_control    = ancillary.buf;
 	msg.msg_controllen = sizeof(ancillary.buf);
 
-	cmsg		 = CMSG_FIRSTHDR(&msg);
+	cmsg             = CMSG_FIRSTHDR(&msg);
 	cmsg->cmsg_level = SOL_SOCKET;
 	cmsg->cmsg_type  = SCM_RIGHTS;
 	cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
@@ -851,7 +854,7 @@ stop_fd_server(void)
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_STOP;
-	ret	= send(socket_fd, &req, sizeof(struct fd_request), 0);
+	ret        = send(socket_fd, &req, sizeof(struct fd_request), 0);
 	if (ret <= 0) {
 		perror("send()");
 	}
@@ -862,7 +865,7 @@ int
 parse_mac_address(const char *opt, char *mac)
 {
 	if (6 == sscanf(opt, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1],
-			&mac[2], &mac[3], &mac[4], &mac[5])) {
+	                &mac[2], &mac[3], &mac[4], &mac[5])) {
 		return 0;
 	}
 	return -1;
@@ -876,23 +879,25 @@ main(int argc, char **argv)
 	int opt;
 	int ret;
 
-	g->ifname	 = NULL;
+	g->ifname         = NULL;
 	g->wait_link_secs = 0;
 	g->timeout_secs   = 5;
 	g->pktm_len       = 60;
 	g->max_frag_size  = ~0U; /* unlimited */
-	for (i		      = 0; i < ETH_ADDR_LEN; i++)
+	for (i = 0; i < ETH_ADDR_LEN; i++) {
 		g->src_mac[i] = 0x00;
-	for (i			  = 0; i < ETH_ADDR_LEN; i++)
-		g->dst_mac[i]     = 0xFF;
-	g->src_ip		  = 0x0A000005; /* 10.0.0.5 */
-	g->dst_ip		  = 0x0A000007; /* 10.0.0.7 */
-	g->filler		  = 'a';
-	g->num_events		  = 0;
+	}
+	for (i = 0; i < ETH_ADDR_LEN; i++) {
+		g->dst_mac[i] = 0xFF;
+	}
+	g->src_ip                 = 0x0A000005; /* 10.0.0.5 */
+	g->dst_ip                 = 0x0A000007; /* 10.0.0.7 */
+	g->filler                 = 'a';
+	g->num_events             = 0;
 	g->ignore_if_not_matching = /*false=*/0;
 	g->success_if_no_receive  = /*false=*/0;
-	g->verbose		  = 0;
-	g->num_loops		  = 1;
+	g->verbose                = 0;
+	g->num_loops              = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
 	while ((opt = getopt(argc, argv, "hcons:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
@@ -958,13 +963,13 @@ main(int argc, char **argv)
 
 			if (opt == 'p') {
 				ret = parse_pause_event(
-					optarg, g->events + g->num_events);
+				        optarg, g->events + g->num_events);
 			} else {
 				ret = parse_txrx_event(
-					optarg,
-					(opt == 't') ? EVENT_TYPE_TX
-						     : EVENT_TYPE_RX,
-					g->events + g->num_events);
+				        optarg,
+				        (opt == 't') ? EVENT_TYPE_TX
+				                     : EVENT_TYPE_RX,
+				        g->events + g->num_events);
 			}
 			if (ret) {
 				printf("Invalid event syntax '%s'\n", optarg);

From f10b997c2d08f1865dbe4c869da4eedf1bab732f Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 19 Jun 2018 15:23:00 +0200
Subject: [PATCH 0932/2207] functional.c retries to connect to the fd_server

---
 utils/fd_server.c          | 56 ++++++++++++++++++-----------
 utils/functional.c         | 73 ++++++++++++++++++--------------------
 utils/learning_bridge_test | 34 +++++++++++-------
 3 files changed, 93 insertions(+), 70 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 4fdac41c1..3df167a43 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -10,7 +10,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #include "fd_server.h"
 
@@ -20,6 +19,8 @@ struct nmd_entry {
 	uint8_t is_open;
 };
 
+#define printf(format, ...) syslog(LOG_NOTICE, format, ##__VA_ARGS__)
+
 #define SOCKET_NAME "/tmp/my_unix_socket"
 #define MAX_OPEN_IF 128
 struct nmd_entry entries[MAX_OPEN_IF];
@@ -29,7 +30,7 @@ static void
 print_request(struct fd_request *req)
 {
 
-	syslog(LOG_NOTICE, "d action: %s, if_name: %s\n",
+	printf("d action: %s, if_name: %s\n",
 	       req->action == FD_GET
 	               ? "FD_GET"
 	               : req->action == FD_RELEASE
@@ -82,7 +83,7 @@ get_fd(const char *if_name, struct fd_response *res)
 	entry = search_des(if_name);
 	if (entry != NULL) {
 		if (entry->is_in_use == 1) {
-			syslog(LOG_NOTICE, "if_name %s is in use\n", if_name);
+			printf("if_name %s is in use\n", if_name);
 			res->result = EBUSY;
 			return -1;
 		}
@@ -92,14 +93,14 @@ get_fd(const char *if_name, struct fd_response *res)
 
 	entry = get_free_des(&ret);
 	if (ret == -1) {
-		syslog(LOG_NOTICE, "Out of memory\n");
+		printf("Out of memory\n");
 		res->result = ENOMEM;
 		return -1;
 	}
 
 	entry->nmd = nm_open(if_name, NULL, 0, NULL);
 	if (entry->nmd == NULL) {
-		syslog(LOG_NOTICE, "Failed to nm_open(%s) with error %d\n",
+		printf("Failed to nm_open(%s) with error %d",
 		       if_name, errno);
 		res->result = errno;
 		return -1;
@@ -118,7 +119,7 @@ release_fd(const char *if_name, struct fd_response *res)
 
 	entry = search_des(if_name);
 	if (entry == NULL) {
-		syslog(LOG_NOTICE, "if_name %s isn't open\n", if_name);
+		printf("if_name %s isn't open", if_name);
 		res->result = ENOENT;
 		return;
 	}
@@ -140,14 +141,14 @@ close_fd(const char *if_name, struct fd_response *res)
 	entry = search_des(if_name);
 	if (entry == NULL) {
 		res->result = ENOENT;
-		syslog(LOG_NOTICE, "if_name %s hasn't been opened\n", if_name);
+		printf("if_name %s hasn't been opened", if_name);
 		return;
 	}
 
 	ret         = nm_close(entry->nmd);
 	res->result = ret;
 	if (ret != 0) {
-		syslog(LOG_NOTICE, "error while close interface %s\n", if_name);
+		printf("error while close interface %s", if_name);
 		return;
 	}
 	entry->is_in_use = 0;
@@ -164,6 +165,7 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 	struct cmsghdr *cmsg;
 	struct iovec iov[1];
 	struct msghdr msg;
+	int ret;
 
 	iov[0].iov_base = buf;
 	iov[0].iov_len  = buf_size;
@@ -186,7 +188,12 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 		*(int *)CMSG_DATA(cmsg) = fd;
 	}
 
-	return sendmsg(socket, &msg, 0);
+	ret = sendmsg(socket, &msg, 0);
+	if (ret == -1) {
+		return -1;
+	}
+
+	return ret;
 }
 
 int
@@ -194,15 +201,16 @@ handle_request(int socket)
 {
 	struct fd_response res;
 	struct fd_request req;
-	int amount;
 	int fd = -1;
+	int amount;
+	int ret;
 
 	memset(&res, 0, sizeof(res));
 	memset(&req, 0, sizeof(req));
 
 	amount = recv(socket, &req, sizeof(struct fd_request), 0);
 	if (amount == -1) {
-		syslog(LOG_NOTICE, "error during recv()");
+		printf("error while receiving the request\n");
 		return -1;
 	}
 
@@ -219,14 +227,18 @@ handle_request(int socket)
 		close_fd(req.if_name, &res);
 		return 0;
 	case FD_STOP:
-		syslog(LOG_NOTICE, "shutting down");
+		printf("shutting down\n");
 		exit(EXIT_SUCCESS);
 		break;
 	default:
 		res.result = EOPNOTSUPP;
 	}
 
-	return send_fd(socket, fd, &res, sizeof(struct fd_response));
+	ret = send_fd(socket, fd, &res, sizeof(struct fd_response));
+	if (ret == -1) {
+		printf("error while sending the reponse\n");
+	}
+	return ret;
 }
 
 void
@@ -236,26 +248,29 @@ main_loop(void)
 	int socket_fd;
 	int ret;
 
+	if (unlink(SOCKET_NAME) == -1) {
+		printf("error during unlink()");
+		exit(EXIT_FAILURE);
+	}
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
-		syslog(LOG_NOTICE, "error during socket()");
+		printf("error during socket()\n");
 		exit(EXIT_FAILURE);
 	}
 
-	unlink(SOCKET_NAME);
 	memset(&name, 0, sizeof(struct sockaddr_un));
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	ret = bind(socket_fd, (const struct sockaddr *)&name,
 	           sizeof(struct sockaddr_un));
 	if (ret == -1) {
-		syslog(LOG_NOTICE, "error during bind()");
+		printf("error during bind()\n");
 		exit(EXIT_FAILURE);
 	}
 
 	ret = listen(socket_fd, 2);
 	if (ret == -1) {
-		syslog(LOG_NOTICE, "error during listen()");
+		printf("error during listen()");
 		exit(EXIT_FAILURE);
 	}
 
@@ -265,13 +280,14 @@ main_loop(void)
 
 		conn_fd = accept(socket_fd, NULL, NULL);
 		if (conn_fd == -1) {
-			syslog(LOG_NOTICE,
-			       "error during accept(), shutting down");
+			printf("error during accept(), shutting down\n");
 			exit(EXIT_FAILURE);
 		}
 
-		syslog(LOG_NOTICE, "handling a request");
 		ret = handle_request(conn_fd);
+		if (ret == -1) {
+			printf("error while handling a request\n");
+		}
 		(void)ret;
 		close(conn_fd);
 	}
diff --git a/utils/functional.c b/utils/functional.c
index 203efeb2c..b27a882ac 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -97,13 +97,13 @@ struct Global {
 	unsigned num_loops;
 };
 
-void release_if_fd(const char *);
+void release_if_fd(struct Global *, const char *);
 
 void
 clean_exit(struct Global *g)
 {
 
-	release_if_fd(g->ifname);
+	release_if_fd(g, g->ifname);
 	exit(EXIT_FAILURE);
 }
 
@@ -313,7 +313,7 @@ tx_flush(struct Global *g)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout\n", __func__);
+			printf("%s: Timeout (connecting to server)\n", __func__);
 			return -1;
 		}
 
@@ -687,25 +687,25 @@ start_fd_server(void)
 		exit(EXIT_FAILURE);
 	}
 	if (pid > 0) {
-		/* The fd_server needs to create the unix socket. Sleeping does
-		 * not guarantee a correct synchronization, but should be good
-		 * enough.
-		 */
-		usleep(MS_WAIT * 1000);
+		wait(NULL);
 		return;
 	}
 
-	execl("fd_server", "fd_server", (char *)NULL);
+	if (execl("fd_server", "./fd_server", (char *)NULL)) {
+		perror("exec()");
+		exit(EXIT_FAILURE);
+	}
 }
 
 #define SOCKET_NAME "/tmp/my_unix_socket"
 
 int
-connect_to_fd_server(void)
+connect_to_fd_server(struct Global *g)
 {
 	struct sockaddr_un name;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms = 100;
 	int socket_fd;
-	int ret;
 
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
@@ -717,14 +717,18 @@ connect_to_fd_server(void)
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
-	ret = connect(socket_fd, (const struct sockaddr *)&name,
-	              sizeof(struct sockaddr_un));
-	if (ret == 0) {
-		return socket_fd;
+	while (connect(socket_fd, (const struct sockaddr *)&name,
+	              sizeof(struct sockaddr_un)) == -1) {
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
 	}
 
-	printf("fd_server offline\n");
-	return ret;
+	return socket_fd;
 }
 
 int
@@ -741,26 +745,21 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	int amount;
 
 	errno = 0;
-
 	iov[0].iov_base = buf;
 	iov[0].iov_len  = buf_size;
-
 	memset(&msg, 0, sizeof(struct msghdr));
 	msg.msg_iov    = iov;
 	msg.msg_iovlen = 1;
-
 	memset(ancillary.buf, 0, sizeof(ancillary.buf));
 	msg.msg_control    = ancillary.buf;
 	msg.msg_controllen = sizeof(ancillary.buf);
-
 	cmsg             = CMSG_FIRSTHDR(&msg);
 	cmsg->cmsg_level = SOL_SOCKET;
 	cmsg->cmsg_type  = SCM_RIGHTS;
 	cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
-
 	amount = recvmsg(socket, &msg, 0);
-	if (amount < 0) {
-		return amount;
+	if (amount == -1) {
+		return -1;
 	}
 
 	res = iov[0].iov_base;
@@ -772,16 +771,14 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	/* If res->result == 0, we know for sure that a file descriptor has been
 	 * sent through the ancillary data.
 	 */
-	if (amount > 0) {
-		cmsg = CMSG_FIRSTHDR(&msg);
-		*fd  = *(int *)CMSG_DATA(cmsg);
-	}
+	cmsg = CMSG_FIRSTHDR(&msg);
+	*fd  = *(int *)CMSG_DATA(cmsg);
 
 	return amount;
 }
 
 int
-get_if_fd(const char *if_name, struct nm_desc *nmd)
+get_if_fd(struct Global *g, const char *if_name, struct nm_desc *nmd)
 {
 	struct fd_response res;
 	struct fd_request req;
@@ -789,7 +786,7 @@ get_if_fd(const char *if_name, struct nm_desc *nmd)
 	int new_fd;
 	int ret;
 
-	socket_fd = connect_to_fd_server();
+	socket_fd = connect_to_fd_server(g);
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_GET;
@@ -802,7 +799,7 @@ get_if_fd(const char *if_name, struct nm_desc *nmd)
 
 	memset(&res, 0, sizeof(res));
 	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(struct fd_response));
-	if (ret < 0) {
+	if (ret == -1) {
 		perror("recv_fd()");
 		return -1;
 	}
@@ -818,13 +815,13 @@ get_if_fd(const char *if_name, struct nm_desc *nmd)
 }
 
 void
-release_if_fd(const char *if_name)
+release_if_fd(struct Global *g, const char *if_name)
 {
 	struct fd_request req;
 	int socket_fd;
 	int ret;
 
-	socket_fd = connect_to_fd_server();
+	socket_fd = connect_to_fd_server(g);
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_RELEASE;
@@ -839,13 +836,13 @@ release_if_fd(const char *if_name)
 }
 
 void
-stop_fd_server(void)
+stop_fd_server(struct Global *g)
 {
 	struct fd_request req;
 	int socket_fd;
 	int ret;
 
-	socket_fd = connect_to_fd_server();
+	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
 		printf("server alredy down\n");
 		return;
@@ -907,7 +904,7 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'c':
-			stop_fd_server();
+			stop_fd_server(g);
 			return 0;
 
 		case 'o':
@@ -1015,7 +1012,7 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	if (get_if_fd(g->ifname, &g->nmd) < 0) {
+	if (get_if_fd(g, g->ifname, &g->nmd) < 0) {
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		return -1;
 	}
@@ -1065,7 +1062,7 @@ main(int argc, char **argv)
 	/* if we have sent something, wait for all tx to complete */
 	tx_flush(g);
 
-	release_if_fd(g->ifname);
+	release_if_fd(g, g->ifname);
 
 	return 0;
 }
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 895bdff8b..a5baf6fc6 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -1,23 +1,33 @@
 #!/usr/bin/env bash
-./functional -c
-./functional -o
-echo "First send, every port should receive the frame."
+# restarting fd_server
+./functional -c &>/dev/null
+./functional -o &>/dev/null
+sleep 0.2s
+
+# echo "First send, every port should receive the frame."
 ./functional -i vale:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p1=$!
-echo "PID 1: $p1"
 ./functional -i vale:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p2=$!
-echo "PID 2: $p2"
-sleep 0.1s
+# At the moment there's a race condition between the 2 background receiving
+# processes and the foreground receiving process.
+# If the sending process manages to send the frame before one of the background
+# process retrieves the file descriptor, the bg process will not receive the
+# frame and therefore the test will fail.
+# Sleeping basically prevents the race condition from happening 99.9999% of the
+# times.
+# For a more robust approach, functional.c should send a signal after receiving
+# the file descriptor and we should wait for that signal to send the frame.
+sleep 0.2s
 ./functional -i vale:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
 wait $p1
 e1=$?
 wait $p2
 e2=$?
-echo "Exit value 1: $e1"
-echo "Exit value 2: $e2"
+# echo "Exit value 1: $e1"
+# echo "Exit value 2: $e2"
 
-echo "Second send, only v2 should receive the frame."
+# echo "Second send, only v2 should receive the frame."
 ./functional -i vale:v2 -r 100:c -d 10:10:10:10:10:10 -T 1 &>/dev/null &
 p3=$!
 ./functional -n -i vale:v1 -r 100:c -T 1 -d 10:10:10:10:10:10 &>/dev/null &
@@ -27,9 +37,9 @@ wait $p3
 e3=$?
 wait $p4
 e4=$?
-echo "Exit value 1: $e3"
-echo "Exit value 2: $e4"
-echo "=============================================="
+# echo "Exit value 1: $e3"
+# echo "Exit value 2: $e4"
+# echo "=============================================="
 result=$(($e1 + $e2 + $e3 + $e4))
 if [ $result = 0 ] ; then
 	echo "Test successful"

From 0b236e29a2f939be94eeacf858c1035ab5cc4137 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 19 Jun 2018 16:45:30 +0200
Subject: [PATCH 0933/2207] fixed learning_bridge_test race condition by
 preopening every interface, functional.c changed to allow calls without an
 event.

---
 utils/fd_server.c          |  15 ++---
 utils/functional.c         | 109 +++++++++++++++++++++----------------
 utils/learning_bridge_test |  58 ++++++++++----------
 3 files changed, 96 insertions(+), 86 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 3df167a43..6f80fdb41 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -30,7 +30,7 @@ static void
 print_request(struct fd_request *req)
 {
 
-	printf("d action: %s, if_name: %s\n",
+	printf("action: %s, if_name: %s\n",
 	       req->action == FD_GET
 	               ? "FD_GET"
 	               : req->action == FD_RELEASE
@@ -100,8 +100,7 @@ get_fd(const char *if_name, struct fd_response *res)
 
 	entry->nmd = nm_open(if_name, NULL, 0, NULL);
 	if (entry->nmd == NULL) {
-		printf("Failed to nm_open(%s) with error %d",
-		       if_name, errno);
+		printf("Failed to nm_open(%s) with error %d", if_name, errno);
 		res->result = errno;
 		return -1;
 	}
@@ -169,7 +168,6 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 
 	iov[0].iov_base = buf;
 	iov[0].iov_len  = buf_size;
-
 	memset(&msg, 0, sizeof(struct msghdr));
 	msg.msg_iov    = iov;
 	msg.msg_iovlen = 1;
@@ -178,9 +176,8 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 		/* We need the ancillary data only when we're sending a file
 		 * descriptor, and a file descriptor cannot be negative.
 		 */
-		msg.msg_control    = ancillary.buf;
-		msg.msg_controllen = sizeof(ancillary.buf);
-
+		msg.msg_control         = ancillary.buf;
+		msg.msg_controllen      = sizeof(ancillary.buf);
 		cmsg                    = CMSG_FIRSTHDR(&msg);
 		cmsg->cmsg_level        = SOL_SOCKET;
 		cmsg->cmsg_type         = SCM_RIGHTS;
@@ -189,10 +186,6 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 	}
 
 	ret = sendmsg(socket, &msg, 0);
-	if (ret == -1) {
-		return -1;
-	}
-
 	return ret;
 }
 
diff --git a/utils/functional.c b/utils/functional.c
index b27a882ac..acdcf65b7 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -313,14 +313,12 @@ tx_flush(struct Global *g)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout (connecting to server)\n", __func__);
+			printf("%s: Timeout\n", __func__);
 			return -1;
 		}
 
-		if (elapsed_ms > 0) {
-			usleep(wait_ms * 1000);
-			elapsed_ms += wait_ms;
-		}
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
 
 		ioctl(nmd->fd, NIOCTXSYNC, NULL);
 	}
@@ -483,12 +481,22 @@ rx_one(struct Global *g)
 			       "from RX "
 			       "ring #%d\n",
 			       g->pktr_len, frags, i);
-			return g->success_if_no_receive == 1 ? -1 : 0;
+			/* frame received */
+			if (g->success_if_no_receive == 1) {
+				return -1;
+			} else {
+				return -0;
+			}
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
 			printf("%s: Timeout\n", __func__);
-			return g->success_if_no_receive == 1 ? 0 : -1;
+			/* frame not received */
+			if (g->success_if_no_receive == 1) {
+				return 0;
+			} else {
+				return -1;
+			}
 		}
 
 		/* Retry after a short while. */
@@ -674,29 +682,6 @@ fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
 	}
 }
 
-#define MS_WAIT 10
-
-void
-start_fd_server(void)
-{
-	pid_t pid;
-
-	pid = fork();
-	if (pid < 0) {
-		perror("fork()");
-		exit(EXIT_FAILURE);
-	}
-	if (pid > 0) {
-		wait(NULL);
-		return;
-	}
-
-	if (execl("fd_server", "./fd_server", (char *)NULL)) {
-		perror("exec()");
-		exit(EXIT_FAILURE);
-	}
-}
-
 #define SOCKET_NAME "/tmp/my_unix_socket"
 
 int
@@ -704,7 +689,7 @@ connect_to_fd_server(struct Global *g)
 {
 	struct sockaddr_un name;
 	unsigned elapsed_ms = 0;
-	unsigned wait_ms = 100;
+	unsigned wait_ms    = 100;
 	int socket_fd;
 
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
@@ -718,7 +703,7 @@ connect_to_fd_server(struct Global *g)
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
 	while (connect(socket_fd, (const struct sockaddr *)&name,
-	              sizeof(struct sockaddr_un)) == -1) {
+	               sizeof(struct sockaddr_un)) == -1) {
 		if (elapsed_ms > g->timeout_secs * 1000) {
 			printf("%s: Timeout\n", __func__);
 			return -1;
@@ -731,6 +716,35 @@ connect_to_fd_server(struct Global *g)
 	return socket_fd;
 }
 
+void
+start_fd_server(struct Global *g)
+{
+	int socket_fd;
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0) {
+		perror("fork()");
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		wait(NULL);
+		return;
+	}
+
+	if (execl("fd_server", "./fd_server", (char *)NULL)) {
+		perror("exec()");
+		exit(EXIT_FAILURE);
+	}
+
+	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		printf("Couldn't connect to fd_server after starting it\n");
+		exit(EXIT_FAILURE);
+	}
+	close(socket_fd);
+}
+
 int
 recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 {
@@ -744,7 +758,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	struct msghdr msg;
 	int amount;
 
-	errno = 0;
+	errno           = 0;
 	iov[0].iov_base = buf;
 	iov[0].iov_len  = buf_size;
 	memset(&msg, 0, sizeof(struct msghdr));
@@ -753,11 +767,11 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	memset(ancillary.buf, 0, sizeof(ancillary.buf));
 	msg.msg_control    = ancillary.buf;
 	msg.msg_controllen = sizeof(ancillary.buf);
-	cmsg             = CMSG_FIRSTHDR(&msg);
-	cmsg->cmsg_level = SOL_SOCKET;
-	cmsg->cmsg_type  = SCM_RIGHTS;
-	cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
-	amount = recvmsg(socket, &msg, 0);
+	cmsg               = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level   = SOL_SOCKET;
+	cmsg->cmsg_type    = SCM_RIGHTS;
+	cmsg->cmsg_len     = CMSG_LEN(sizeof(int));
+	amount             = recvmsg(socket, &msg, 0);
 	if (amount == -1) {
 		return -1;
 	}
@@ -908,13 +922,13 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'o':
-			start_fd_server();
+			start_fd_server(g);
 			return 0;
 
 		case 'n':
 			/* Not receiving means timing out */
-			g->success_if_no_receive = 1;
-			return 0;
+			g->success_if_no_receive = /*true=*/1;
+			break;
 
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
@@ -1006,11 +1020,11 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	if (g->num_events < 1) {
-		printf("No transmit/receive/pause events specified\n");
-		usage();
-		return -1;
-	}
+	// if (g->num_events < 1) {
+	// 	printf("No transmit/receive/pause events specified\n");
+	// 	usage();
+	// 	return -1;
+	// }
 
 	if (get_if_fd(g, g->ifname, &g->nmd) < 0) {
 		printf("Failed to nm_open(%s)\n", g->ifname);
@@ -1046,7 +1060,8 @@ main(int argc, char **argv)
 					if (rx_one(g)) {
 						clean_exit(g);
 					}
-					if (rx_check(g)) {
+					if (g->success_if_no_receive == 0 &&
+					    rx_check(g)) {
 						clean_exit(g);
 					}
 					break;
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index a5baf6fc6..4d27dcb15 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -1,46 +1,48 @@
 #!/usr/bin/env bash
 # restarting fd_server
-./functional -c &>/dev/null
-./functional -o &>/dev/null
-sleep 0.2s
+./functional -c
+./functional -o
+echo "Server restarted"
+
+# preopening interface that will be needed
+./functional -i vale0:v0
+./functional -i vale0:v1
+./functional -i vale0:v2
+echo "Interfaces preopened"
 
 # echo "First send, every port should receive the frame."
-./functional -i vale:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p1=$!
-./functional -i vale:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p2=$!
-# At the moment there's a race condition between the 2 background receiving
-# processes and the foreground receiving process.
-# If the sending process manages to send the frame before one of the background
-# process retrieves the file descriptor, the bg process will not receive the
-# frame and therefore the test will fail.
-# Sleeping basically prevents the race condition from happening 99.9999% of the
-# times.
-# For a more robust approach, functional.c should send a signal after receiving
-# the file descriptor and we should wait for that signal to send the frame.
-sleep 0.2s
-./functional -i vale:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
+./functional -i vale0:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
+e3=$?
+
 wait $p1
 e1=$?
 wait $p2
 e2=$?
-# echo "Exit value 1: $e1"
-# echo "Exit value 2: $e2"
+echo "Exit value 1: $e1"
+echo "Exit value 2: $e2"
+echo "Exit value 3: $e3"
 
 # echo "Second send, only v2 should receive the frame."
-./functional -i vale:v2 -r 100:c -d 10:10:10:10:10:10 -T 1 &>/dev/null &
-p3=$!
-./functional -n -i vale:v1 -r 100:c -T 1 -d 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v2 -r 100:c -T 1 -d 10:10:10:10:10:10 &>/dev/null &
 p4=$!
-./functional -i vale:v0 -t 100:c -d 10:10:10:10:10:10 &>/dev/null
-wait $p3
-e3=$?
+./functional -i vale0:v1 -r 100:c -T 1 -d 10:10:10:10:10:10 -n &>/dev/null &
+p5=$!
+./functional -i vale0:v0 -t 100:c -d 10:10:10:10:10:10 &>/dev/null
+e6=$?
+
 wait $p4
 e4=$?
-# echo "Exit value 1: $e3"
-# echo "Exit value 2: $e4"
-# echo "=============================================="
-result=$(($e1 + $e2 + $e3 + $e4))
+wait $p5
+e5=$?
+echo "Exit value 4: $e4"
+echo "Exit value 5: $e5"
+echo "Exit value 6: $e6"
+echo "=============================================="
+result=$(($e1 + $e2 + $e3 + $e4 + $e5 + $e6))
 if [ $result = 0 ] ; then
 	echo "Test successful"
 	exit 0

From f8f8d823b7eee09f4e8ec09a5d2e95e5fd4bf023 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 19 Jun 2018 17:20:57 +0200
Subject: [PATCH 0934/2207] added a simple Bash support library to write tests,
 modified learning_bridge_test to use it.

---
 utils/learning_bridge_test | 44 ++++++++++++++++++++------------------
 utils/test_lib             | 29 +++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 21 deletions(-)
 create mode 100755 utils/test_lib

diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 4d27dcb15..bb2a229d2 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -1,52 +1,54 @@
 #!/usr/bin/env bash
-# restarting fd_server
+
+source test_lib
+
+# Restarting fd_server.
 ./functional -c
+check_exit $? "close_server"
 ./functional -o
+check_exit $? "start_server"
 echo "Server restarted"
 
-# preopening interface that will be needed
+# Preopening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
 ./functional -i vale0:v0
+check_exit $? "open vale0:v0"
 ./functional -i vale0:v1
+check_exit $? "open vale0:v1"
 ./functional -i vale0:v2
+check_exit $? "open vale0:v2"
 echo "Interfaces preopened"
 
-# echo "First send, every port should receive the frame."
+# First send, every port should receive the frame.
 ./functional -i vale0:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p1=$!
 ./functional -i vale0:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
 p2=$!
 ./functional -i vale0:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
 e3=$?
-
 wait $p1
 e1=$?
 wait $p2
 e2=$?
-echo "Exit value 1: $e1"
-echo "Exit value 2: $e2"
-echo "Exit value 3: $e3"
+check_exit $e1 "receive vale0:v0"
+check_exit $e2 "receive vale0:v1"
+check_exit $e3 "send vale0:v2"
 
-# echo "Second send, only v2 should receive the frame."
+# Second send, only v2 should receive the frame.
 ./functional -i vale0:v2 -r 100:c -T 1 -d 10:10:10:10:10:10 &>/dev/null &
 p4=$!
 ./functional -i vale0:v1 -r 100:c -T 1 -d 10:10:10:10:10:10 -n &>/dev/null &
 p5=$!
 ./functional -i vale0:v0 -t 100:c -d 10:10:10:10:10:10 &>/dev/null
 e6=$?
-
 wait $p4
 e4=$?
 wait $p5
 e5=$?
-echo "Exit value 4: $e4"
-echo "Exit value 5: $e5"
-echo "Exit value 6: $e6"
-echo "=============================================="
-result=$(($e1 + $e2 + $e3 + $e4 + $e5 + $e6))
-if [ $result = 0 ] ; then
-	echo "Test successful"
-	exit 0
-else
-	echo "Test failed"
-	exit 1
-fi
\ No newline at end of file
+check_exit $e1 "receive vale0:v0"
+check_exit $e2 "receive vale0:v1"
+check_exit $e3 "send vale0:v2"
+
+echo "================================================================================"
+echo "Test successful"
+exit 0
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
new file mode 100755
index 000000000..483baeae0
--- /dev/null
+++ b/utils/test_lib
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+################################################################################
+# Checks the exit value, if it's != 0 cleans up and terminates the script.
+# Arguments:
+#   $1 -> exit value to check
+#   $2 -> string printed
+################################################################################
+function check_exit() {
+	local exit_value="$1"
+	if [ $exit_value != 0 ] ; then
+		echo "$2 has failed with exit value = $exit_value."
+		exit 1
+	else
+		echo "$2 was successful."
+	fi
+}
+
+################################################################################
+# Creates a VALE persistent port, and sets a cleanup handler which will be
+# called when the script exits.
+# Arguments:
+#   $1 -> name of the VALE persistent port
+################################################################################
+function create_vale_persistent_port() {
+	local if_name="$1"
+	vale-ctl -n "$if_name"
+	trap "vale-ctl -r $if_name" EXIT
+}
\ No newline at end of file

From b27e1a179e133fdddc63296510db9551b7bc458b Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 19 Jun 2018 17:26:32 +0200
Subject: [PATCH 0935/2207] check_exit prints only if exit_value != 0

---
 utils/learning_bridge_test | 24 +++++++++++-------------
 utils/test_lib             |  6 +++---
 2 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index bb2a229d2..85fe031a3 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -3,21 +3,19 @@
 source test_lib
 
 # Restarting fd_server.
-./functional -c
+./functional -c &>/dev/null
 check_exit $? "close_server"
-./functional -o
+./functional -o &>/dev/null
 check_exit $? "start_server"
-echo "Server restarted"
 
-# Preopening interface that will be needed. This is needed to avoid a race
+# Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
-check_exit $? "open vale0:v0"
-./functional -i vale0:v1
-check_exit $? "open vale0:v1"
-./functional -i vale0:v2
-check_exit $? "open vale0:v2"
-echo "Interfaces preopened"
+./functional -i vale0:v0 &>/dev/null
+check_exit $? "pre-open vale0:v0"
+./functional -i vale0:v1 &>/dev/null
+check_exit $? "pre-open vale0:v1"
+./functional -i vale0:v2 &>/dev/null
+check_exit $? "pre-open vale0:v2"
 
 # First send, every port should receive the frame.
 ./functional -i vale0:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
@@ -49,6 +47,6 @@ check_exit $e1 "receive vale0:v0"
 check_exit $e2 "receive vale0:v1"
 check_exit $e3 "send vale0:v2"
 
-echo "================================================================================"
-echo "Test successful"
+# echo "================================================================================"
+echo "Test successful."
 exit 0
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 483baeae0..6ad08af29 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -9,10 +9,10 @@
 function check_exit() {
 	local exit_value="$1"
 	if [ $exit_value != 0 ] ; then
-		echo "$2 has failed with exit value = $exit_value."
+		echo "$2 FAIL($exit_value)."
 		exit 1
-	else
-		echo "$2 was successful."
+	# else
+		# echo "$2 was successful."
 	fi
 }
 

From 5dd0ea64048689741b6335b66d058230c550564a Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 19 Jun 2018 17:54:49 +0200
Subject: [PATCH 0936/2207] fixex a possible race condition that might occuring
 during a server restart

---
 utils/fd_server.c          |  7 +++++--
 utils/functional.c         | 10 +++++++++-
 utils/learning_bridge_test |  2 +-
 utils/test_lib             |  3 +++
 4 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 6f80fdb41..0c5a207e1 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -241,6 +241,7 @@ main_loop(void)
 	int socket_fd;
 	int ret;
 
+	printf("starting up.\n");
 	if (unlink(SOCKET_NAME) == -1) {
 		printf("error during unlink()");
 		exit(EXIT_FAILURE);
@@ -267,6 +268,7 @@ main_loop(void)
 		exit(EXIT_FAILURE);
 	}
 
+	printf("listening\n");
 	for (;;) {
 		int conn_fd;
 		int ret;
@@ -300,7 +302,7 @@ daemonize(void)
 		exit(EXIT_SUCCESS);
 	}
 
-	if (setsid() < 0) {
+	if (setsid() == -1) {
 		exit(EXIT_FAILURE);
 	}
 
@@ -316,10 +318,11 @@ daemonize(void)
 	}
 
 	umask(0);
+
 	if (chdir("/") == -1) {
-		perror("chdir()");
 		exit(EXIT_FAILURE);
 	}
+
 	for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
 		close(i);
 	}
diff --git a/utils/functional.c b/utils/functional.c
index acdcf65b7..e484bc5b9 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -866,9 +866,17 @@ stop_fd_server(struct Global *g)
 	memset(&req, 0, sizeof(req));
 	req.action = FD_STOP;
 	ret        = send(socket_fd, &req, sizeof(struct fd_request), 0);
-	if (ret <= 0) {
+	if (ret == -1) {
 		perror("send()");
 	}
+	/* By calling recv() we synchronize with the fd_server closing the
+	 * socket.
+	 * This way we're sure that during the next call to ./functional
+	 * the fd_server has alredy closed its end and we avoid a possible race
+	 * condition. Otherwise the call to functional might connect to the
+	 * previous fd_server backlog.
+	 */
+	recv(socket_fd, &req, sizeof(struct fd_request), 0);
 	close(socket_fd);
 }
 
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 85fe031a3..179de9775 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -10,7 +10,7 @@ check_exit $? "start_server"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0 &>/dev/null
+./functional -i vale0:v0
 check_exit $? "pre-open vale0:v0"
 ./functional -i vale0:v1 &>/dev/null
 check_exit $? "pre-open vale0:v1"
diff --git a/utils/test_lib b/utils/test_lib
index 6ad08af29..3950ae4da 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -25,5 +25,8 @@ function check_exit() {
 function create_vale_persistent_port() {
 	local if_name="$1"
 	vale-ctl -n "$if_name"
+	# The interface might still be opened by the fd_server, if that's the
+	# case we can't remove the VALE persistent port.
+	# TODO: decide what to do (we can call ./functional -c)
 	trap "vale-ctl -r $if_name" EXIT
 }
\ No newline at end of file

From 0247a1090dc90cd60a2183871f3e4573fae50a85 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 13:52:32 +0200
Subject: [PATCH 0937/2207] changed default timeout to 1 second. fixed the trap
 handlers for vale persistent ports.

---
 utils/fd_server.c          |  4 +--
 utils/functional.c         |  4 +--
 utils/learning_bridge_test |  5 +---
 utils/test_lib             | 53 +++++++++++++++++++++++++++++++++++---
 4 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 0c5a207e1..f1cc0320a 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -242,8 +242,8 @@ main_loop(void)
 	int ret;
 
 	printf("starting up.\n");
-	if (unlink(SOCKET_NAME) == -1) {
-		printf("error during unlink()");
+	if (unlink(SOCKET_NAME) == -1 && errno != ENOENT) {
+		printf("error %d during unlink()", errno);
 		exit(EXIT_FAILURE);
 	}
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
diff --git a/utils/functional.c b/utils/functional.c
index e484bc5b9..eb1cb73c1 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -630,7 +630,7 @@ usage(void)
 	       "[-s (shuts down the file descriptor server)]\n"
 	       "    -i NETMAP_PORT\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
-	       "    [-T TIMEOUT_SECS (=5)]\n"
+	       "    [-T TIMEOUT_SECS (=1)]\n"
 	       "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
 	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
 	       "LEN bytes)]\n"
@@ -900,7 +900,7 @@ main(int argc, char **argv)
 
 	g->ifname         = NULL;
 	g->wait_link_secs = 0;
-	g->timeout_secs   = 5;
+	g->timeout_secs   = 1;
 	g->pktm_len       = 60;
 	g->max_frag_size  = ~0U; /* unlimited */
 	for (i = 0; i < ETH_ADDR_LEN; i++) {
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 179de9775..63f2e52c3 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -1,5 +1,4 @@
 #!/usr/bin/env bash
-
 source test_lib
 
 # Restarting fd_server.
@@ -47,6 +46,4 @@ check_exit $e1 "receive vale0:v0"
 check_exit $e2 "receive vale0:v1"
 check_exit $e3 "send vale0:v2"
 
-# echo "================================================================================"
-echo "Test successful."
-exit 0
\ No newline at end of file
+echo "Test successful."
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 3950ae4da..82be70ba9 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -8,6 +8,7 @@
 ################################################################################
 function check_exit() {
 	local exit_value="$1"
+
 	if [ $exit_value != 0 ] ; then
 		echo "$2 FAIL($exit_value)."
 		exit 1
@@ -16,17 +17,61 @@ function check_exit() {
 	fi
 }
 
+################################################################################
+# Set a trap while maintaining the one currently set. The new one will be
+# executed first.
+# Arguments:
+#   $1 -> new command to execute during the trap
+#   $2 -> signal to trap
+################################################################################
+function cumulative_trap() {
+	local new_command="$1"
+	local signal="$2"
+	local current_command=""
+
+	# https://unix.stackexchange.com/a/334593
+	shopt -s lastpipe
+	trap -p "$signal" | read current_command
+	shopt -u lastpipe
+
+	current_command="$(echo $current_command | awk -F\' '{print $2}')"
+	new_command="$new_command; $current_command"
+	trap "$new_command" "$signal"
+}
+
 ################################################################################
 # Creates a VALE persistent port, and sets a cleanup handler which will be
 # called when the script exits.
 # Arguments:
 #   $1 -> name of the VALE persistent port
+#   $2 -> name of the VALE switch that the port will be to be attached to
 ################################################################################
 function create_vale_persistent_port() {
 	local if_name="$1"
+	local bdg_name="$2"
+
 	vale-ctl -n "$if_name"
-	# The interface might still be opened by the fd_server, if that's the
-	# case we can't remove the VALE persistent port.
-	# TODO: decide what to do (we can call ./functional -c)
-	trap "vale-ctl -r $if_name" EXIT
+	check_exit $? "create $if_name"
+	cumulative_trap "vale-ctl -r $if_name" "EXIT"
+	check_exit $? "trap-remove $if_name"
+
+	vale-ctl -a "$bdg_name:$if_name"
+	check_exit $? "attach $bdg_name:$if_name"
+	cumulative_trap "vale-ctl -d $bdg_name:$if_name" "EXIT"
+	# We first need to close the file descriptor of the interface, otherwise
+	# the detach will fail. To accomplish that we shut down fd_server
+	cumulative_trap "./functional -c" "EXIT"
+	check_exit $? "trap-detach $bdg_name:$if_name"
+}
+
+################################################################################
+# Restarts the file descriptor server.
+# Arguments:
+#   None
+################################################################################
+function restart_fd_server() {
+	./functional -c &>/dev/null
+	check_exit $? "close_server"
+	./functional -o &>/dev/null
+	check_exit $? "start_server"
 }
\ No newline at end of file

From f9c0b14034bad33ec5a88eb845d2e1dc23d0fc4a Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 17:21:38 +0200
Subject: [PATCH 0938/2207] Fixed a fd_server bug. functional.c doesn't try
 reconnecting to the server during stop_fd_server(). Fixed trap handlers
 inside test_lib. Added a function to create veth ports to test_lib. Added a
 bunch of new tests.

---
 utils/fd_server.c               | 34 ++++++++++--------
 utils/functional.c              |  5 ++-
 utils/learning_bridge_test      | 18 ++++++----
 utils/rec_cp_mon_pipe_test      | 47 +++++++++++++++++++++++++
 utils/rec_cp_mon_vale_port_test | 52 ++++++++++++++++++++++++++++
 utils/test_lib                  | 61 +++++++++++++++++++++++++++------
 utils/veth_test                 | 32 +++++++++++++++++
 7 files changed, 217 insertions(+), 32 deletions(-)
 create mode 100755 utils/rec_cp_mon_pipe_test
 create mode 100755 utils/rec_cp_mon_vale_port_test
 create mode 100755 utils/veth_test

diff --git a/utils/fd_server.c b/utils/fd_server.c
index f1cc0320a..91b13b1cb 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -14,6 +14,7 @@
 #include "fd_server.h"
 
 struct nmd_entry {
+	char if_name[NETMAP_REQ_IFNAMSIZ];
 	struct nm_desc *nmd;
 	uint8_t is_in_use;
 	uint8_t is_open;
@@ -30,7 +31,7 @@ static void
 print_request(struct fd_request *req)
 {
 
-	printf("action: %s, if_name: %s\n",
+	printf("action: %s, if_name: '%s'\n",
 	       req->action == FD_GET
 	               ? "FD_GET"
 	               : req->action == FD_RELEASE
@@ -45,32 +46,34 @@ search_des(const char *if_name)
 {
 	int i;
 
+	// printf("searching %s\n", if_name);
 	for (i = 0; i < num_entries; ++i) {
 		struct nmd_entry *entry = &entries[i];
-		struct nm_desc *nmd     = entry->nmd;
+
+		// printf("i=%d, is_open=%d, is_in_use=%d, if_name=%s\n",
+		// 	i, entry->is_open, entry->is_in_use, entry->if_name);
 
 		if (entry->is_open == 0) {
 			continue;
 		}
 
-		if (strcmp(nmd->req.nr_name, if_name) == 0) {
+		if (strncmp(entry->if_name, if_name, IFNAMSIZ) == 0) {
+			// printf("finished searching with a match\n");
 			return entry;
 		}
 	}
 
+	// printf("finished searching without a match\n");
 	return NULL;
 }
 
 struct nmd_entry *
-get_free_des(int *ret)
+get_free_des(void)
 {
-
 	if (num_entries == MAX_OPEN_IF) {
-		*ret = -1;
 		return NULL;
 	}
 
-	*ret = 0;
 	return &entries[num_entries++];
 }
 
@@ -78,7 +81,6 @@ int
 get_fd(const char *if_name, struct fd_response *res)
 {
 	struct nmd_entry *entry;
-	int ret;
 
 	entry = search_des(if_name);
 	if (entry != NULL) {
@@ -91,8 +93,8 @@ get_fd(const char *if_name, struct fd_response *res)
 		return entry->nmd->fd;
 	}
 
-	entry = get_free_des(&ret);
-	if (ret == -1) {
+	entry = get_free_des();
+	if (entry == NULL) {
 		printf("Out of memory\n");
 		res->result = ENOMEM;
 		return -1;
@@ -100,10 +102,12 @@ get_fd(const char *if_name, struct fd_response *res)
 
 	entry->nmd = nm_open(if_name, NULL, 0, NULL);
 	if (entry->nmd == NULL) {
-		printf("Failed to nm_open(%s) with error %d", if_name, errno);
+		printf("Failed to nm_open(%s) with error %d\n", if_name, errno);
 		res->result = errno;
 		return -1;
 	}
+	strncpy(entry->if_name, if_name, sizeof(entry->if_name));
+	entry->if_name[sizeof(entry->if_name) - 1] = '\0';
 
 	memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
 	entry->is_in_use = 1;
@@ -118,7 +122,7 @@ release_fd(const char *if_name, struct fd_response *res)
 
 	entry = search_des(if_name);
 	if (entry == NULL) {
-		printf("if_name %s isn't open", if_name);
+		printf("if_name %s isn't open\n", if_name);
 		res->result = ENOENT;
 		return;
 	}
@@ -140,14 +144,14 @@ close_fd(const char *if_name, struct fd_response *res)
 	entry = search_des(if_name);
 	if (entry == NULL) {
 		res->result = ENOENT;
-		printf("if_name %s hasn't been opened", if_name);
+		printf("if_name %s hasn't been opened\n", if_name);
 		return;
 	}
 
 	ret         = nm_close(entry->nmd);
 	res->result = ret;
 	if (ret != 0) {
-		printf("error while close interface %s", if_name);
+		printf("error while close interface %s\n", if_name);
 		return;
 	}
 	entry->is_in_use = 0;
@@ -176,6 +180,7 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 		/* We need the ancillary data only when we're sending a file
 		 * descriptor, and a file descriptor cannot be negative.
 		 */
+		printf("sending a file descriptor\n");
 		msg.msg_control         = ancillary.buf;
 		msg.msg_controllen      = sizeof(ancillary.buf);
 		cmsg                    = CMSG_FIRSTHDR(&msg);
@@ -333,7 +338,6 @@ daemonize(void)
 int
 main()
 {
-
 	daemonize();
 	main_loop();
 	return 0;
diff --git a/utils/functional.c b/utils/functional.c
index eb1cb73c1..1b6f77ee7 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -852,11 +852,14 @@ release_if_fd(struct Global *g, const char *if_name)
 void
 stop_fd_server(struct Global *g)
 {
+	unsigned old_timeout_secs = g->timeout_secs;
 	struct fd_request req;
 	int socket_fd;
 	int ret;
 
-	socket_fd = connect_to_fd_server(g);
+	g->timeout_secs = 0;
+	socket_fd       = connect_to_fd_server(g);
+	g->timeout_secs = old_timeout_secs;
 	if (socket_fd == -1) {
 		printf("server alredy down\n");
 		return;
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 63f2e52c3..274cfdcbb 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -1,15 +1,21 @@
 #!/usr/bin/env bash
+################################################################################
+# Test objective: check if the switch learning algorithm is working.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) connect 3 ephemeral VALE ports (v0, v1, v2) to the same VALE switch.
+# 2) send from v2 specifying a source MAC address and check that v0 and v1
+#    receive the frame.
+# 3) send from v0 using the previous MAC address as the destination MAC address
+#    and check that v2 receives the frame while v1 does not.
+################################################################################
 source test_lib
 
-# Restarting fd_server.
-./functional -c &>/dev/null
-check_exit $? "close_server"
-./functional -o &>/dev/null
-check_exit $? "start_server"
+restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+./functional -i vale0:v0 &>/dev/null
 check_exit $? "pre-open vale0:v0"
 ./functional -i vale0:v1 &>/dev/null
 check_exit $? "pre-open vale0:v1"
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
new file mode 100755
index 000000000..cb4cfb4ed
--- /dev/null
+++ b/utils/rec_cp_mon_pipe_test
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if receiving copy monitors correctly block VALE pipes
+#                 from receiving.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 3) open a receiving copy monitor pipe{1/r for pipe{1.
+# 4) send from pipe}1 without receiving from pipe{1/r, check that pipe{1 doesn't
+#    receive the frame.
+# 5) receive from pipe{1/r, check that pipe{1 receives the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:pipe{1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/r" &>/dev/null
+check_exit $? "pre-open netmap:pipe{1/r"
+./functional -i "netmap:pipe}1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe}1"
+
+# Initially we don't receive with the monitor, therefore pipe{1 should not
+# receive the frame.
+./functional -i netmap:pipe{1 -r 150:d -n &>/dev/null &
+p1=$!
+./functional -i netmap:pipe}1 -t 150:d    &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "no-receive netmap:pipe{1"
+check_exit $e2 "send vale0:v1"
+
+# Now we receive with the monitor, therefore pipe{1 should receive the frame.
+./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null &
+p3=$!
+./functional -i "netmap:pipe{1/r" -r 150:d &>/dev/null
+e4=$?
+wait $p3
+e3=$?
+check_exit $e3 "receive netmap:pipe{1"
+check_exit $e4 "receive netmap:pipe{1/r"
+
+echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
new file mode 100755
index 000000000..18928206e
--- /dev/null
+++ b/utils/rec_cp_mon_vale_port_test
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if receiving copy monitors correctly block VALE ports
+#                 from receiving.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a persistent VALE port (v0).
+# 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
+# 3) open a receiving copy monitor for v0/r.
+# 4) send from v1 without receiving from v0/r, check that v0 doesn't receive
+#    the frame.
+# 5) receive from v0/r, check that v0 receives the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+create_vale_persistent_port "v0" "vale0"
+./functional -i vale0:v0    &>/dev/null
+check_exit $? "pre-open vale0:v0"
+# Receiving copy monitor for vale0:v0
+./functional -i netmap:v0/r &>/dev/null
+check_exit $? "pre-open netmap:v0/r"
+./functional -i vale0:v1    &>/dev/null
+check_exit $? "pre-open vale0:v1"
+
+# Initially we don't receive with the monitor, therefore vale0:v1 should not
+# receive the frame.
+./functional -i vale0:v0 -r 150:d -n &>/dev/null &
+p1=$!
+./functional -i vale0:v1 -t 150:d    &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "no-receive vale0:v0"
+check_exit $e2 "send vale0:v1"
+
+# Now we receive with the monitor, therefore vale0:v1 should receive the frame.
+./functional -i vale0:v0    -r 150:d &>/dev/null &
+p3=$!
+./functional -i netmap:v0/r -r 150:d &>/dev/null
+p4=$!
+wait $p3
+e3=$?
+wait $p4
+e4=$?
+check_exit $e3 "receive vale:v0"
+check_exit $e4 "receive netmap:v0/r"
+
+echo "Test successful."
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 82be70ba9..7115c2b23 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -1,4 +1,33 @@
 #!/usr/bin/env bash
+################################################################################
+# Closes the file descriptor server.
+# Arguments:
+#   None
+################################################################################
+function close_fd_server() {
+	./functional -c &>/dev/null
+	check_exit $? "close_fd_server"
+}
+
+################################################################################
+# Starts the file descriptor server.
+# Arguments:
+#   None
+################################################################################
+function start_fd_server() {
+	./functional -o &>/dev/null
+	check_exit $? "start_fd_server"
+}
+
+################################################################################
+# Restarts the file descriptor server.
+# Arguments:
+#   None
+################################################################################
+function restart_fd_server() {
+	close_fd_server
+	start_fd_server
+}
 
 ################################################################################
 # Checks the exit value, if it's != 0 cleans up and terminates the script.
@@ -29,6 +58,8 @@ function cumulative_trap() {
 	local signal="$2"
 	local current_command=""
 
+	# If we run "trap -p SIGNAL" in a subshell we read the traps for that
+	# subshell, instead of the current one.
 	# https://unix.stackexchange.com/a/334593
 	shopt -s lastpipe
 	trap -p "$signal" | read current_command
@@ -40,7 +71,7 @@ function cumulative_trap() {
 }
 
 ################################################################################
-# Creates a VALE persistent port, and sets a cleanup handler which will be
+# Creates a VALE persistent port and sets a cleanup handler which will be
 # called when the script exits.
 # Arguments:
 #   $1 -> name of the VALE persistent port
@@ -59,19 +90,29 @@ function create_vale_persistent_port() {
 	check_exit $? "attach $bdg_name:$if_name"
 	cumulative_trap "vale-ctl -d $bdg_name:$if_name" "EXIT"
 	# We first need to close the file descriptor of the interface, otherwise
-	# the detach will fail. To accomplish that we shut down fd_server
-	cumulative_trap "./functional -c" "EXIT"
+	# the detach will fail. To accomplish that we shut down fd_server.
+	cumulative_trap "close_fd_server" "EXIT"
 	check_exit $? "trap-detach $bdg_name:$if_name"
 }
 
 ################################################################################
-# Restarts the file descriptor server.
+# Creates a pair of veth interfaces and sets a cleanup handler which will be
+# called when the script exits.
 # Arguments:
-#   None
+#   $1 -> base name of the veth devices
 ################################################################################
-function restart_fd_server() {
-	./functional -c &>/dev/null
-	check_exit $? "close_server"
-	./functional -o &>/dev/null
-	check_exit $? "start_server"
+function create_veth_interfaces() {
+	local if_name="$1"
+	local if_name1="${if_name}A"
+	local if_name2="${if_name}B"
+
+	ip link add "$if_name1" type veth peer name "$if_name2"
+	check_exit $? "create $if_name"
+	# We first need to close the file descriptor of the interfaces,
+	# otherwise the delete will fail. To accomplish that we shut down
+	# fd_server.
+	cumulative_trap "ip link delete $if_name1" "EXIT"
+	check_exit $? "trap-delete $if_name1"
+	cumulative_trap "close_fd_server" "EXIT"
+	check_exit $? "trap-detach $bdg_name:$if_name"
 }
\ No newline at end of file
diff --git a/utils/veth_test b/utils/veth_test
new file mode 100755
index 000000000..4fc7fa995
--- /dev/null
+++ b/utils/veth_test
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive through veth interfaces.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of veth interfaces (veth1A, veth1B).
+# 2) send from veth1A and check if veth1B receives it.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+create_veth_interfaces "veth1"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i netmap:veth1A &>/dev/null
+check_exit $? "pre-open netmap:veth1A"
+./functional -i netmap:veth1B &>/dev/null
+check_exit $? "pre-open netmap:veth1B"
+
+# During the first send we don't receive with the monitor, vale0:v1 should not
+# receive the frame.
+./functional -i netmap:veth1A -r 150:d &>/dev/null &
+p1=$!
+./functional -i netmap:veth1B -t 150:d &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive netmap:veth1A"
+check_exit $e2 "send netmap:veth1B"
+
+echo "Test successful."
\ No newline at end of file

From 4b9ebcb707a711ba2b8841246c19d4ed0e0fc06c Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 17:34:37 +0200
Subject: [PATCH 0939/2207] fixed a typo

---
 utils/rec_cp_mon_pipe_test | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index cb4cfb4ed..a171bee51 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -32,7 +32,7 @@ e2=$?
 wait $p1
 e1=$?
 check_exit $e1 "no-receive netmap:pipe{1"
-check_exit $e2 "send vale0:v1"
+check_exit $e2 "send netmap:pipe{1"
 
 # Now we receive with the monitor, therefore pipe{1 should receive the frame.
 ./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null &

From eed06354948fcfed693baa5fdfe116f27ea66d05 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 17:35:24 +0200
Subject: [PATCH 0940/2207] new test on send copy monitor

---
 utils/send_cp_mon_pipe_test | 47 +++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100755 utils/send_cp_mon_pipe_test

diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
new file mode 100755
index 000000000..edf22493a
--- /dev/null
+++ b/utils/send_cp_mon_pipe_test
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if send copy monitors correctly block VALE pipes
+#                 from sending.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 3) open a send copy monitor pipe{1/t for pipe{1.
+# 4) send from pipe{1 without receiving from pipe{1/t, check that pipe}1 doesn't
+#    receive the frame.
+# 5) receive from pipe{1/t, check that pipe}1 receives the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:pipe{1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/t" &>/dev/null
+check_exit $? "pre-open netmap:pipe{1/t"
+./functional -i "netmap:pipe}1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe}1"
+
+# Initially we don't receive with the monitor, therefore pipe{1 should not
+# receive the frame.
+./functional -i netmap:pipe}1 -r 150:d -n &>/dev/null &
+p1=$!
+./functional -i netmap:pipe{1 -t 150:d    &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "no-receive netmap:pipe}1"
+check_exit $e2 "send netmap:pipe{1"
+
+# Now we receive with the monitor, therefore pipe}1 should receive the frame.
+./functional -i "netmap:pipe}1"   -r 150:d &>/dev/null &
+p3=$!
+./functional -i "netmap:pipe{1/t" -r 150:d &>/dev/null
+e4=$?
+wait $p3
+e3=$?
+check_exit $e3 "receive netmap:pipe}1"
+check_exit $e4 "receive netmap:pipe{1/t"
+
+echo "Test successful."
\ No newline at end of file

From 396de53e0985271082a3f34949b9a8cac1dce3d9 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 17:55:32 +0200
Subject: [PATCH 0941/2207] zero-copy monitor test on receiving VALE port

---
 utils/rec_zcp_mon_vale_port_test | 50 ++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100755 utils/rec_zcp_mon_vale_port_test

diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
new file mode 100755
index 000000000..33baed291
--- /dev/null
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a zero-copy monitor is correctly blocked until the
+#                 monitored VALE port reads the frame.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a persistent VALE port (v0).
+# 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch (vale0).
+# 3) open a zero-copy monitor v0/z for v0.
+# 4) send from v1 without receiving from v0, check that v0/z doesn't receive the
+#    rame.
+# 5) receive from v0, check that v0/z receives the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+create_vale_persistent_port "v0" "vale0"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "vale0:v0"   &>/dev/null
+check_exit $? "pre-open vale0:v0"
+./functional -i "vale0:v0/z" &>/dev/null
+check_exit $? "pre-open vale0:v0/z"
+./functional -i "vale0:v1"   &>/dev/null
+check_exit $? "pre-open vale0:v1"
+
+# Initially we don't receive with the monitored VALE port v0, therefore the
+# monitor should not receive the frame.
+./functional -i vale0:v0/z -r 150:d -n &>/dev/null &
+p1=$!
+./functional -i vale0:v1   -t 150:d    &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "no-receive vale0:v0/z"
+check_exit $e2 "send vale0:v0"
+
+# Now we receive with the monitored VALE port v0, therefore the monitor should
+# receive the frame.
+./functional -i "vale0:v0"   -r 150:d &>/dev/null &
+p3=$!
+./functional -i "vale0:v0/z" -r 150:d &>/dev/null
+e4=$?
+wait $p3
+e3=$?
+check_exit $e3 "receive vale0:v0"
+check_exit $e4 "receive vale0:v0/z"
+
+echo "Test successful."
\ No newline at end of file

From b63750b511f157767e68e9fe7a4d9425bbc43224 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 17:55:55 +0200
Subject: [PATCH 0942/2207] zero-copy monitor test on receiving VALE pipe

---
 utils/rec_zcp_mon_pipe_test | 48 +++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100755 utils/rec_zcp_mon_pipe_test

diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
new file mode 100755
index 000000000..39e911adb
--- /dev/null
+++ b/utils/rec_zcp_mon_pipe_test
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a zero-copy monitor is correctly blocked until the
+#                 monitored VALE pipe reads the frame.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 2) open a zero-copy monitor pipe{1/z for pipe{1.
+# 3) send from pipe}1 without receiving from pipe{1, check that pipe{1/z doesn't
+#    receive the frame.
+# 4) receive from pipe{1, check that pipe{1/z receives the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:pipe{1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/z" &>/dev/null
+check_exit $? "pre-open netmap:pipe{1/z"
+./functional -i "netmap:pipe}1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe}1"
+
+# Initially we don't receive with the monitored pipe pipe{1, therefore the
+# monitor should not receive the frame.
+./functional -i netmap:pipe{1/z -r 150:d -n &>/dev/null &
+p1=$!
+./functional -i netmap:pipe}1   -t 150:d    &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "no-receive netmap:pipe{1"
+check_exit $e2 "send netmap:pipe{1"
+
+# Now we receive with the monitored pipe pipe{1, therefore the monitor should
+# receive the frame.
+./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null &
+p3=$!
+./functional -i "netmap:pipe{1/z" -r 150:d &>/dev/null
+e4=$?
+wait $p3
+e3=$?
+check_exit $e3 "receive netmap:pipe{1"
+check_exit $e4 "receive netmap:pipe{1/z"
+
+echo "Test successful."
\ No newline at end of file

From ab9d47bd5b842f1eb31919b66b9110fd794b4062 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 18:16:49 +0200
Subject: [PATCH 0943/2207] fixed copy monitors tests

---
 utils/rec_cp_mon_pipe_test      | 38 +++++++++++---------------
 utils/rec_cp_mon_vale_port_test | 39 ++++++++++-----------------
 utils/send_cp_mon_pipe_test     | 35 +++++++++---------------
 utils/send_zcp_mon_pipe_test    | 48 +++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+), 70 deletions(-)
 create mode 100755 utils/send_zcp_mon_pipe_test

diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index a171bee51..1a590e403 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -1,14 +1,12 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if receiving copy monitors correctly block VALE pipes
-#                 from receiving.
+# Test objective: check if receive copy monitors receives frames when its
+#                 monitored VALE pipe is receiving.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of VALE pipes (pipe{1, pipe}1).
-# 3) open a receiving copy monitor pipe{1/r for pipe{1.
-# 4) send from pipe}1 without receiving from pipe{1/r, check that pipe{1 doesn't
-#    receive the frame.
-# 5) receive from pipe{1/r, check that pipe{1 receives the frame.
+# 2) open a receive copy monitor pipe{1/r for pipe{1.
+# 3) send from pipe}1, check that both pipe{1/r and pipe{1 receive the frame.
 ################################################################################
 source test_lib
 
@@ -23,25 +21,19 @@ check_exit $? "pre-open netmap:pipe{1/r"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-# Initially we don't receive with the monitor, therefore pipe{1 should not
-# receive the frame.
-./functional -i netmap:pipe{1 -r 150:d -n &>/dev/null &
-p1=$!
-./functional -i netmap:pipe}1 -t 150:d    &>/dev/null
-e2=$?
-wait $p1
-e1=$?
-check_exit $e1 "no-receive netmap:pipe{1"
-check_exit $e2 "send netmap:pipe{1"
 
-# Now we receive with the monitor, therefore pipe{1 should receive the frame.
+./functional -i "netmap:pipe{1/r" -r 150:d &>/dev/null &
+p1=$!
 ./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null &
-p3=$!
-./functional -i "netmap:pipe{1/r" -r 150:d &>/dev/null
-e4=$?
-wait $p3
+p2=$!
+./functional -i "netmap:pipe}1"   -t 150:d &>/dev/null
 e3=$?
-check_exit $e3 "receive netmap:pipe{1"
-check_exit $e4 "receive netmap:pipe{1/r"
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+check_exit $e1 "receive netmap:pipe{1/r"
+check_exit $e2 "receive netmap:pipe{1"
+check_exit $e3 "send netmap:pipe{1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index 18928206e..98fc75403 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -1,23 +1,21 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if receiving copy monitors correctly block VALE ports
-#                 from receiving.
+# Test objective: check if receive copy monitors receives frames when its
+#                 monitored VALE port is receiving.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
 # 3) open a receiving copy monitor for v0/r.
-# 4) send from v1 without receiving from v0/r, check that v0 doesn't receive
-#    the frame.
-# 5) receive from v0/r, check that v0 receives the frame.
+# 4) send from v1, check that both v0 and v0/r receive the frame.
 ################################################################################
 source test_lib
 
 restart_fd_server
 
+create_vale_persistent_port "v0" "vale0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-create_vale_persistent_port "v0" "vale0"
 ./functional -i vale0:v0    &>/dev/null
 check_exit $? "pre-open vale0:v0"
 # Receiving copy monitor for vale0:v0
@@ -26,27 +24,18 @@ check_exit $? "pre-open netmap:v0/r"
 ./functional -i vale0:v1    &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
-# Initially we don't receive with the monitor, therefore vale0:v1 should not
-# receive the frame.
-./functional -i vale0:v0 -r 150:d -n &>/dev/null &
+./functional -i netmap:v0/r -r 150:d &>/dev/null &
 p1=$!
-./functional -i vale0:v1 -t 150:d    &>/dev/null
-e2=$?
-wait $p1
-e1=$?
-check_exit $e1 "no-receive vale0:v0"
-check_exit $e2 "send vale0:v1"
-
-# Now we receive with the monitor, therefore vale0:v1 should receive the frame.
 ./functional -i vale0:v0    -r 150:d &>/dev/null &
-p3=$!
-./functional -i netmap:v0/r -r 150:d &>/dev/null
-p4=$!
-wait $p3
+p2=$!
+./functional -i vale0:v1    -t 150:d &>/dev/null
 e3=$?
-wait $p4
-e4=$?
-check_exit $e3 "receive vale:v0"
-check_exit $e4 "receive netmap:v0/r"
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+check_exit $e1 "receive netmap:v0/r"
+check_exit $e2 "receive vale0:v0"
+check_exit $e3 "send vale0:v1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index edf22493a..f50035588 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -1,14 +1,12 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if send copy monitors correctly block VALE pipes
-#                 from sending.
+# Test objective: check if send copy monitors receives frames when its monitored
+#                 VALE pipe is sending.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of VALE pipes (pipe{1, pipe}1).
-# 3) open a send copy monitor pipe{1/t for pipe{1.
-# 4) send from pipe{1 without receiving from pipe{1/t, check that pipe}1 doesn't
-#    receive the frame.
-# 5) receive from pipe{1/t, check that pipe}1 receives the frame.
+# 2) open a send copy monitor pipe{1/t for pipe{1.
+# 3) send from pipe{1, check that both pipe{1/r and pipe}1 receive the frame.
 ################################################################################
 source test_lib
 
@@ -23,25 +21,18 @@ check_exit $? "pre-open netmap:pipe{1/t"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-# Initially we don't receive with the monitor, therefore pipe{1 should not
-# receive the frame.
-./functional -i netmap:pipe}1 -r 150:d -n &>/dev/null &
+./functional -i "netmap:pipe{1/t" -r 150:d &>/dev/null &
 p1=$!
-./functional -i netmap:pipe{1 -t 150:d    &>/dev/null
-e2=$?
+./functional -i "netmap:pipe}1"   -r 150:d &>/dev/null &
+p2=$!
+./functional -i "netmap:pipe{1"   -t 150:d &>/dev/null &
+e3=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive netmap:pipe}1"
+wait $p2
+e2=$?
+check_exit $e1 "receive netmap:pipe{1/t"
+check_exit $e1 "receive netmap:pipe}1"
 check_exit $e2 "send netmap:pipe{1"
 
-# Now we receive with the monitor, therefore pipe}1 should receive the frame.
-./functional -i "netmap:pipe}1"   -r 150:d &>/dev/null &
-p3=$!
-./functional -i "netmap:pipe{1/t" -r 150:d &>/dev/null
-e4=$?
-wait $p3
-e3=$?
-check_exit $e3 "receive netmap:pipe}1"
-check_exit $e4 "receive netmap:pipe{1/t"
-
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
new file mode 100755
index 000000000..b5f5e4399
--- /dev/null
+++ b/utils/send_zcp_mon_pipe_test
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a zero-copy monitor is correctly blocked until the
+#                 monitored VALE pipe reads the frame.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 2) open a zero-copy monitor pipe{1/z for pipe{1.
+# 3) send from pipe{1 without receiving from pipe{1/z, check that pipe}1 doesn't
+#    receive the frame.
+# 4) receive from pipe{1/z, check that pipe}1 receives the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:pipe{1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/z" &>/dev/null
+check_exit $? "pre-open netmap:pipe{1/z"
+./functional -i "netmap:pipe}1"   &>/dev/null
+check_exit $? "pre-open netmap:pipe}1"
+
+# Initially we don't receive with the monitor, therefore the other end of the
+# pipe should not receive the frame.
+./functional -i netmap:pipe{1/z -r 150:d -n &>/dev/null &
+p1=$!
+./functional -i netmap:pipe{1   -t 150:d    &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "no-receive netmap:pipe{1/z"
+check_exit $e2 "send netmap:pipe{1"
+
+# Now we receive with the monitor, therefore the other end of the pipe should
+# receive the frame.
+./functional -i "netmap:pipe{1/z" -r 150:d &>/dev/null &
+p3=$!
+./functional -i "netmap:pipe}1"   -r 150:d &>/dev/null
+e4=$?
+wait $p3
+e3=$?
+check_exit $e3 "receive netmap:pipe{1/z"
+check_exit $e4 "receive netmap:pipe}1"
+
+echo "Test successful."
\ No newline at end of file

From 707b5bda86adcdad5ba15baa4115c46e65aa0ae8 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 20 Jun 2018 21:47:16 +0200
Subject: [PATCH 0944/2207] comments updated for send_zcp_mon_pipe_test

---
 utils/send_zcp_mon_pipe_test | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index b5f5e4399..e0c468f8b 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -1,14 +1,15 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a zero-copy monitor is correctly blocked until the
-#                 monitored VALE pipe reads the frame.
+#                 non-monitored VALE pipe reads the frame (and the slot is given
+#                 back to the sending pipe).
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of VALE pipes (pipe{1, pipe}1).
 # 2) open a zero-copy monitor pipe{1/z for pipe{1.
-# 3) send from pipe{1 without receiving from pipe{1/z, check that pipe}1 doesn't
+# 3) send from pipe{1 without receiving from pipe}1, check that pipe{1/z doesn't
 #    receive the frame.
-# 4) receive from pipe{1/z, check that pipe}1 receives the frame.
+# 4) receive from pipe}1, check that pipe{1/z receives the frame.
 ################################################################################
 source test_lib
 
@@ -23,18 +24,18 @@ check_exit $? "pre-open netmap:pipe{1/z"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-# Initially we don't receive with the monitor, therefore the other end of the
-# pipe should not receive the frame.
-./functional -i netmap:pipe{1/z -r 150:d -n &>/dev/null &
+# Initially we don't receive with the non-monitored pipe end, therefore the
+# monitor should not receive the frame.
+./functional -i "netmap:pipe{1/z" -r 150:d -n &>/dev/null &
 p1=$!
-./functional -i netmap:pipe{1   -t 150:d    &>/dev/null
+./functional -i "netmap:pipe{1"   -t 150:d    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
 check_exit $e1 "no-receive netmap:pipe{1/z"
 check_exit $e2 "send netmap:pipe{1"
 
-# Now we receive with the monitor, therefore the other end of the pipe should
+# Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
 ./functional -i "netmap:pipe{1/z" -r 150:d &>/dev/null &
 p3=$!

From 5ab5770c46f88e82783f15c4ab7f824abb08ce85 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 21 Jun 2018 15:59:09 +0200
Subject: [PATCH 0945/2207] comment typos fixed, improved copy-monitor
 behaviour tests

---
 utils/rec_cp_mon_pipe_test      | 25 ++++++++++++++-----------
 utils/rec_cp_mon_vale_port_test | 26 ++++++++++++++------------
 utils/send_cp_mon_pipe_test     | 24 ++++++++++++++----------
 utils/test_lib                  |  3 ++-
 4 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 1a590e403..5bce8338f 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -1,12 +1,15 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if receive copy monitors receives frames when its
-#                 monitored VALE pipe is receiving.
+# Test objective: check if a receive copy monitor receives frames when its
+#                 monitored VALE pipe is receiving, even if the monitored pipe
+#                 hasn't yet read the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of VALE pipes (pipe{1, pipe}1).
 # 2) open a receive copy monitor pipe{1/r for pipe{1.
-# 3) send from pipe}1, check that both pipe{1/r and pipe{1 receive the frame.
+# 3) send from pipe}1 and don't read from pipe{1, check that pipe{1/r receives
+#    the frame.
+# 4) receive from pipe{1.
 ################################################################################
 source test_lib
 
@@ -21,19 +24,19 @@ check_exit $? "pre-open netmap:pipe{1/r"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-
+# First we send without reading from pipe{1
 ./functional -i "netmap:pipe{1/r" -r 150:d &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null &
-p2=$!
 ./functional -i "netmap:pipe}1"   -t 150:d &>/dev/null
-e3=$?
+e2=$?
 wait $p1
 e1=$?
-wait $p2
-e2=$?
 check_exit $e1 "receive netmap:pipe{1/r"
-check_exit $e2 "receive netmap:pipe{1"
-check_exit $e3 "send netmap:pipe{1"
+check_exit $e2 "send netmap:pipe}1"
+
+# Then we read from pipe{1
+./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null
+e3=$?
+check_exit $e3 "receive netmap:pipe{1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index 98fc75403..1685cd0d7 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -1,13 +1,15 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if receive copy monitors receives frames when its
-#                 monitored VALE port is receiving.
+# Test objective: check if a receive copy monitor receives frames when its
+#                 monitored VALE port is receiving, even if the monitored port
+#                 hasn't yet read the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
-# 3) open a receiving copy monitor for v0/r.
-# 4) send from v1, check that both v0 and v0/r receive the frame.
+# 3) open a receiving copy monitor vo/r for v0.
+# 4) send from v1 and don't read from v0, check that v0/r receives the frame.
+# 5) receive from v0.
 ################################################################################
 source test_lib
 
@@ -18,24 +20,24 @@ create_vale_persistent_port "v0" "vale0"
 # condition between the sending and receiving ports.
 ./functional -i vale0:v0    &>/dev/null
 check_exit $? "pre-open vale0:v0"
-# Receiving copy monitor for vale0:v0
 ./functional -i netmap:v0/r &>/dev/null
 check_exit $? "pre-open netmap:v0/r"
 ./functional -i vale0:v1    &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
+# First we send without reading from v0
 ./functional -i netmap:v0/r -r 150:d &>/dev/null &
 p1=$!
-./functional -i vale0:v0    -r 150:d &>/dev/null &
-p2=$!
 ./functional -i vale0:v1    -t 150:d &>/dev/null
-e3=$?
+e2=$?
 wait $p1
 e1=$?
-wait $p2
-e2=$?
 check_exit $e1 "receive netmap:v0/r"
-check_exit $e2 "receive vale0:v0"
-check_exit $e3 "send vale0:v1"
+check_exit $e2 "send vale0:v1"
+
+# Then we read from v0
+./functional -i vale0:v0    -r 150:d &>/dev/null
+e3=$?
+check_exit $e3 "receive vale0:v0"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index f50035588..c1dbe8e8e 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -1,12 +1,15 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if send copy monitors receives frames when its monitored
-#                 VALE pipe is sending.
+# Test objective: check if a send copy monitor receives frames when its
+#                 monitored VALE pipe is sending, even if the non-monitored port
+#                 hasn't yet read the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of VALE pipes (pipe{1, pipe}1).
 # 2) open a send copy monitor pipe{1/t for pipe{1.
-# 3) send from pipe{1, check that both pipe{1/r and pipe}1 receive the frame.
+# 3) send from pipe{1 and don't read from pipe}1, check that pipe{1/t receives
+#    the frame.
+# 4) receive from pipe}1.
 ################################################################################
 source test_lib
 
@@ -21,18 +24,19 @@ check_exit $? "pre-open netmap:pipe{1/t"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
+# First we send without reading from pipe}1
 ./functional -i "netmap:pipe{1/t" -r 150:d &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe}1"   -r 150:d &>/dev/null &
-p2=$!
-./functional -i "netmap:pipe{1"   -t 150:d &>/dev/null &
-e3=$?
+./functional -i "netmap:pipe{1"   -t 150:d &>/dev/null
+e2=$?
 wait $p1
 e1=$?
-wait $p2
-e2=$?
 check_exit $e1 "receive netmap:pipe{1/t"
-check_exit $e1 "receive netmap:pipe}1"
 check_exit $e2 "send netmap:pipe{1"
 
+# Then we read from pipe}1
+./functional -i "netmap:pipe}1" -r 150:d &>/dev/null
+e3=$?
+check_exit $e3 "receive netmap:pipe}1"
+
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 7115c2b23..84ad57611 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -37,9 +37,10 @@ function restart_fd_server() {
 ################################################################################
 function check_exit() {
 	local exit_value="$1"
+	local string_to_print="$2"
 
 	if [ $exit_value != 0 ] ; then
-		echo "$2 FAIL($exit_value)."
+		echo "$string_to_print FAIL($exit_value)."
 		exit 1
 	# else
 		# echo "$2 was successful."

From 0e8b3832bce3e98eba2f3c1bd79c86cd82e3275d Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 21 Jun 2018 16:24:16 +0200
Subject: [PATCH 0946/2207] packet length and fill are now stored in a
 variable, instead of being hardcoded

---
 utils/rec_cp_mon_pipe_test       | 12 +++++++-----
 utils/rec_cp_mon_vale_port_test  |  8 +++++---
 utils/rec_zcp_mon_pipe_test      | 14 ++++++++------
 utils/rec_zcp_mon_vale_port_test | 10 ++++++----
 utils/send_cp_mon_pipe_test      | 14 ++++++++------
 utils/send_zcp_mon_pipe_test     | 16 +++++++++-------
 6 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 5bce8338f..9ef9505be 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -1,11 +1,11 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a receive copy monitor receives frames when its
-#                 monitored VALE pipe is receiving, even if the monitored pipe
+#                 monitored netmap pipe is receiving, even if the monitored pipe
 #                 hasn't yet read the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
-# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a receive copy monitor pipe{1/r for pipe{1.
 # 3) send from pipe}1 and don't read from pipe{1, check that pipe{1/r receives
 #    the frame.
@@ -24,10 +24,12 @@ check_exit $? "pre-open netmap:pipe{1/r"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
+fill='d'
+len=150
 # First we send without reading from pipe{1
-./functional -i "netmap:pipe{1/r" -r 150:d &>/dev/null &
+./functional -i "netmap:pipe{1/r" -r "${len}:${fill}" &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe}1"   -t 150:d &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -35,7 +37,7 @@ check_exit $e1 "receive netmap:pipe{1/r"
 check_exit $e2 "send netmap:pipe}1"
 
 # Then we read from pipe{1
-./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}" &>/dev/null
 e3=$?
 check_exit $e3 "receive netmap:pipe{1"
 
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index 1685cd0d7..1e91e1992 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -25,10 +25,12 @@ check_exit $? "pre-open netmap:v0/r"
 ./functional -i vale0:v1    &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
+fill='d'
+len=150
 # First we send without reading from v0
-./functional -i netmap:v0/r -r 150:d &>/dev/null &
+./functional -i netmap:v0/r -r "${len}:${fill}" &>/dev/null &
 p1=$!
-./functional -i vale0:v1    -t 150:d &>/dev/null
+./functional -i vale0:v1    -t "${len}:${fill}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -36,7 +38,7 @@ check_exit $e1 "receive netmap:v0/r"
 check_exit $e2 "send vale0:v1"
 
 # Then we read from v0
-./functional -i vale0:v0    -r 150:d &>/dev/null
+./functional -i vale0:v0    -r "${len}:${fill}" &>/dev/null
 e3=$?
 check_exit $e3 "receive vale0:v0"
 
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index 39e911adb..62b68fb29 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -1,10 +1,10 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a zero-copy monitor is correctly blocked until the
-#                 monitored VALE pipe reads the frame.
+#                 monitored netmap pipe reads the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
-# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a zero-copy monitor pipe{1/z for pipe{1.
 # 3) send from pipe}1 without receiving from pipe{1, check that pipe{1/z doesn't
 #    receive the frame.
@@ -23,11 +23,13 @@ check_exit $? "pre-open netmap:pipe{1/z"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
+fill='d'
+len=150
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-./functional -i netmap:pipe{1/z -r 150:d -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" -n &>/dev/null &
 p1=$!
-./functional -i netmap:pipe}1   -t 150:d    &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -36,9 +38,9 @@ check_exit $e2 "send netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1"   -r 150:d &>/dev/null &
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}" &>/dev/null &
 p3=$!
-./functional -i "netmap:pipe{1/z" -r 150:d &>/dev/null
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
index 33baed291..a161c662b 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -25,11 +25,13 @@ check_exit $? "pre-open vale0:v0/z"
 ./functional -i "vale0:v1"   &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
+fill='d'
+len=150
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i vale0:v0/z -r 150:d -n &>/dev/null &
+./functional -i vale0:v0/z -r "${len}:${fill}" -n &>/dev/null &
 p1=$!
-./functional -i vale0:v1   -t 150:d    &>/dev/null
+./functional -i vale0:v1   -t "${len}:${fill}"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -38,9 +40,9 @@ check_exit $e2 "send vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-./functional -i "vale0:v0"   -r 150:d &>/dev/null &
+./functional -i "vale0:v0"   -r "${len}:${fill}" &>/dev/null &
 p3=$!
-./functional -i "vale0:v0/z" -r 150:d &>/dev/null
+./functional -i "vale0:v0/z" -r "${len}:${fill}" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index c1dbe8e8e..30f79a85a 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -1,11 +1,11 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a send copy monitor receives frames when its
-#                 monitored VALE pipe is sending, even if the non-monitored port
-#                 hasn't yet read the frame.
+#                 monitored netmap pipe is sending, even if the non-monitored
+#                 port hasn't yet read the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
-# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a send copy monitor pipe{1/t for pipe{1.
 # 3) send from pipe{1 and don't read from pipe}1, check that pipe{1/t receives
 #    the frame.
@@ -24,10 +24,12 @@ check_exit $? "pre-open netmap:pipe{1/t"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
+fill='d'
+len=150
 # First we send without reading from pipe}1
-./functional -i "netmap:pipe{1/t" -r 150:d &>/dev/null &
+./functional -i "netmap:pipe{1/t" -r "${len}:${fill}" &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -t 150:d &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -35,7 +37,7 @@ check_exit $e1 "receive netmap:pipe{1/t"
 check_exit $e2 "send netmap:pipe{1"
 
 # Then we read from pipe}1
-./functional -i "netmap:pipe}1" -r 150:d &>/dev/null
+./functional -i "netmap:pipe}1" -r "${len}:${fill}" &>/dev/null
 e3=$?
 check_exit $e3 "receive netmap:pipe}1"
 
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index e0c468f8b..9aa0b703e 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -1,11 +1,11 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a zero-copy monitor is correctly blocked until the
-#                 non-monitored VALE pipe reads the frame (and the slot is given
-#                 back to the sending pipe).
+#                 non-monitored netmap pipe reads the frame (and the slot is
+#                 given back to the sending pipe).
 # Operations:
 # 0) restart fd_server to have a clean starting state
-# 1) create a pair of VALE pipes (pipe{1, pipe}1).
+# 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a zero-copy monitor pipe{1/z for pipe{1.
 # 3) send from pipe{1 without receiving from pipe}1, check that pipe{1/z doesn't
 #    receive the frame.
@@ -24,11 +24,13 @@ check_exit $? "pre-open netmap:pipe{1/z"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
+fill='d'
+len=150
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r 150:d -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" -n &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -t 150:d    &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -37,9 +39,9 @@ check_exit $e2 "send netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1/z" -r 150:d &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" &>/dev/null &
 p3=$!
-./functional -i "netmap:pipe}1"   -r 150:d &>/dev/null
+./functional -i "netmap:pipe}1"   -r "${len}:${fill}" &>/dev/null
 e4=$?
 wait $p3
 e3=$?

From ce604ce0d7f4cb866c035607e58a89c3c067d79b Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 21 Jun 2018 16:27:49 +0200
Subject: [PATCH 0947/2207] new tests

---
 utils/pipe_test                   | 41 +++++++++++++++++++++++++++
 utils/send_cp_mon_vale_port_test  | 43 +++++++++++++++++++++++++++++
 utils/send_zcp_mon_vale_port_test | 46 +++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+)
 create mode 100755 utils/pipe_test
 create mode 100755 utils/send_cp_mon_vale_port_test
 create mode 100755 utils/send_zcp_mon_vale_port_test

diff --git a/utils/pipe_test b/utils/pipe_test
new file mode 100755
index 000000000..19fc0f31a
--- /dev/null
+++ b/utils/pipe_test
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive through netmap pipes.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
+# 2) send from pipeA{1 and check if pipeA}1 receives it.
+# 2) send from pipeA}1 and check if pipeA{1 receives it.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i netmap:pipeA{1 &>/dev/null
+check_exit $? "pre-open netmap:pipeA{1"
+./functional -i netmap:pipeA}1 &>/dev/null
+check_exit $? "pre-open netmap:pipeA}1"
+
+# pipeA}1 ---> pipeA{1
+./functional -i netmap:pipeA{1 -r 274:h &>/dev/null &
+p1=$!
+./functional -i netmap:pipeA}1 -t 274:h &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive netmap:pipeA{1"
+check_exit $e2 "send netmap:pipeA}1"
+
+# pipeA{1 ---> pipeA}1
+./functional -i netmap:pipeA}1 -r 274:h &>/dev/null &
+p1=$!
+./functional -i netmap:pipeA{1 -t 274:h &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive netmap:pipeA}1"
+check_exit $e2 "send netmap:pipeA{1"
+
+echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_vale_port_test
new file mode 100755
index 000000000..a41fcaec3
--- /dev/null
+++ b/utils/send_cp_mon_vale_port_test
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a send copy monitor receives frames when its monitored
+#                 VALE port is sending.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a persistent VALE port (v0).
+# 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
+# 3) open a send copy monitor v0/t for v0.
+# 4) send from v0, check that both v0/t and v1 receive the frame.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+create_vale_persistent_port "v0" "vale0"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i vale0:v0    &>/dev/null
+check_exit $? "pre-open vale0:v0"
+./functional -i netmap:v0/t &>/dev/null
+check_exit $? "pre-open netmap:v0/t"
+./functional -i vale0:v1    &>/dev/null
+check_exit $? "pre-open vale0:v1"
+
+fill='d'
+len=150
+# First we send without reading from v1
+./functional -i netmap:v0/t -r "${len}:${fill}" &>/dev/null &
+p1=$!
+./functional -i vale0:v0    -t "${len}:${fill}" &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive netmap:v0/t"
+check_exit $e2 "send vale0:v0"
+
+# Then we read from v1
+./functional -i vale0:v1 -r "${len}:${fill}" &>/dev/null
+e3=$?
+check_exit $e3 "receive vale0:v1"
+
+echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_vale_port_test
new file mode 100755
index 000000000..0f27fc335
--- /dev/null
+++ b/utils/send_zcp_mon_vale_port_test
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a zero-copy monitor receives frames when its
+#                 monitored VALE port is sending, even if the destination port
+#                 hasn't yet read the frame (this happens because VALE switches
+#                 do not use zero-copy).
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a persistent VALE port (v0).
+# 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
+# 3) open a zero-copy monitor v0/z for v0.
+# 4) send from v0 and don't read from v1, check that v0/z receives the frame.
+# 5) receive from v1.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+create_vale_persistent_port "v0" "vale0"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i vale0:v0    &>/dev/null
+check_exit $? "pre-open vale0:v0"
+./functional -i netmap:v0/z &>/dev/null
+check_exit $? "pre-open netmap:v0/z"
+./functional -i vale0:v1    &>/dev/null
+check_exit $? "pre-open vale0:v1"
+
+fill='d'
+len=150
+# First we send without reading from v1
+./functional -i netmap:v0/z -r "${len}:${fill}" &>/dev/null &
+p1=$!
+./functional -i vale0:v0    -t "${len}:${fill}" &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive netmap:v0/z"
+check_exit $e2 "send vale0:v0"
+
+# Then we read from v1
+./functional -i vale0:v1 -r "${len}:${fill}" &>/dev/null
+e3=$?
+check_exit $e3 "receive vale0:v1"
+
+echo "Test successful."
\ No newline at end of file

From 24a8facaad47e88f03009470ea3cf81906dfdaaf Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 21 Jun 2018 17:29:36 +0200
Subject: [PATCH 0948/2207] added functional.c multi-packet tx support

---
 utils/functional.c | 197 ++++++++++++++++++++++++++-------------------
 1 file changed, 115 insertions(+), 82 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 1b6f77ee7..097b4b86d 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -37,6 +37,7 @@
 #include "fd_server.h"
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -280,17 +281,17 @@ build_packet(struct Global *g)
 	                                                           udpofs))))));
 }
 
-static unsigned
-tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
-{
-	unsigned avail_per_slot = ring->nr_buf_size;
+// static unsigned
+// tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
+// {
+// 	unsigned avail_per_slot = ring->nr_buf_size;
 
-	if (max_frag_size < avail_per_slot) {
-		avail_per_slot = max_frag_size;
-	}
+// 	if (max_frag_size < avail_per_slot) {
+// 		avail_per_slot = max_frag_size;
+// 	}
 
-	return nm_ring_space(ring) * avail_per_slot;
-}
+// 	return nm_ring_space(ring) * avail_per_slot;
+// }
 
 static int
 tx_flush(struct Global *g)
@@ -324,59 +325,81 @@ tx_flush(struct Global *g)
 	}
 }
 
-/* Transmit a single packet using any TX ring. */
-static int
-tx_one(struct Global *g)
+uint64_t
+ring_avail_sends(struct netmap_ring *ring, unsigned pkt_len)
 {
-	struct nm_desc *nmd = &g->nmd;
-	unsigned elapsed_ms = 0;
-	unsigned wait_ms    = 100;
+	uint64_t slot_per_packet;
+
+	slot_per_packet = ceil((double)pkt_len / (double)ring->nr_buf_size);
+	return nm_ring_space(ring) / slot_per_packet;
+}
+
+uint64_t
+adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t sends_available = 0;
 	unsigned int i;
 
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+		sends_available += ring_avail_sends(ring, pkt_len);
+	}
+
+	return sends_available;
+}
+
+void
+put_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+	unsigned head  = ring->head;
+	unsigned frags = 0;
+	unsigned ofs   = 0;
+
 	for (;;) {
-		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
-			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
-			unsigned head            = ring->head;
-			unsigned frags           = 0;
-			unsigned ofs             = 0;
+		struct netmap_slot *slot = &ring->slot[head];
+		char *buf                = NETMAP_BUF(ring, slot->buf_idx);
+		unsigned copysize        = g->pktm_len - ofs;
 
-			if (tx_bytes_avail(ring, g->max_frag_size) <
-			    g->pktm_len) {
-				continue;
-			}
+		if (copysize > ring->nr_buf_size) {
+			copysize = ring->nr_buf_size;
+		}
+		if (copysize > g->max_frag_size) {
+			copysize = g->max_frag_size;
+		}
 
-			for (;;) {
-				struct netmap_slot *slot = &ring->slot[head];
-				char *buf = NETMAP_BUF(ring, slot->buf_idx);
-				unsigned copysize = g->pktm_len - ofs;
+		memcpy(buf, g->pktm + ofs, copysize);
+		ofs += copysize;
+		slot->len   = copysize;
+		slot->flags = NS_MOREFRAG;
+		head        = nm_ring_next(ring, head);
+		frags++;
+		if (ofs >= g->pktm_len) {
+			/* Last fragment. */
+			assert(ofs == g->pktm_len);
+			slot->flags = NS_REPORT;
+			break;
+		}
+	}
 
-				if (copysize > ring->nr_buf_size) {
-					copysize = ring->nr_buf_size;
-				}
-				if (copysize > g->max_frag_size) {
-					copysize = g->max_frag_size;
-				}
+	ring->head = ring->cur = head;
+	printf("packet (%u bytes, %u frags) placed to TX\n", g->pktm_len,
+	       frags);
+}
 
-				memcpy(buf, g->pktm + ofs, copysize);
-				ofs += copysize;
-				slot->len   = copysize;
-				slot->flags = NS_MOREFRAG;
-				head        = nm_ring_next(ring, head);
-				frags++;
-				if (ofs >= g->pktm_len) {
-					/* Last fragment. */
-					assert(ofs == g->pktm_len);
-					slot->flags = NS_REPORT;
-					break;
-				}
-			}
+/* Transmit packets_num packets using any combination of TX rings. */
+static int
+tx(struct Global *g, unsigned packets_num)
+{
+	struct nm_desc *nmd = &g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	unsigned int i;
 
-			ring->head = ring->cur = head;
-			ioctl(nmd->fd, NIOCTXSYNC, NULL);
-			printf("packet (%u bytes, %u frags) transmitted to TX "
-			       "ring #%d\n",
-			       g->pktm_len, frags, i);
-			return 0;
+	/* We cycle here until either we timeout or we find enough space. */
+	for (;;) {
+		if (adapter_avail_sends(nmd, g->pktm_len) >= packets_num) {
+			break;
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
@@ -390,7 +413,27 @@ tx_one(struct Global *g)
 		ioctl(nmd->fd, NIOCTXSYNC, NULL);
 	}
 
-	/* never reached */
+	/* Once we have enough space, we start filling slots. We might use
+	 * multiple rings.
+	 */
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+		uint64_t num_ring_sends;
+
+		for (num_ring_sends = ring_avail_sends(ring, g->pktm_len);
+		     num_ring_sends > 0 && packets_num > 0;
+		     --num_ring_sends, --packets_num) {
+			put_one_packet(g, ring);
+		}
+
+		if (packets_num == 0) {
+			break;
+		}
+	}
+
+	assert(packets_num == 0);
+	/* Once we're done we sync, sending all packets at once. */
+	ioctl(nmd->fd, NIOCTXSYNC, NULL);
 	return 0;
 }
 
@@ -1031,12 +1074,6 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	// if (g->num_events < 1) {
-	// 	printf("No transmit/receive/pause events specified\n");
-	// 	usage();
-	// 	return -1;
-	// }
-
 	if (get_if_fd(g, g->ifname, &g->nmd) < 0) {
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		return -1;
@@ -1049,7 +1086,6 @@ main(int argc, char **argv)
 	for (c = 0; c < g->num_loops; c++) {
 		for (i = 0; i < g->num_events; i++) {
 			const struct Event *e = g->events + i;
-			unsigned j;
 
 			if (e->evtype == EVENT_TYPE_TX ||
 			    e->evtype == EVENT_TYPE_RX) {
@@ -1058,29 +1094,26 @@ main(int argc, char **argv)
 				build_packet(g);
 			}
 
-			for (j = 0; j < e->num; j++) {
-				printf("%d: ", j);
-				switch (e->evtype) {
-				case EVENT_TYPE_TX:
-					if (tx_one(g)) {
-						clean_exit(g);
-					}
-					break;
-
-				case EVENT_TYPE_RX:
-					if (rx_one(g)) {
-						clean_exit(g);
-					}
-					if (g->success_if_no_receive == 0 &&
-					    rx_check(g)) {
-						clean_exit(g);
-					}
-					break;
+			switch (e->evtype) {
+			case EVENT_TYPE_TX:
+				if (tx(g, e->num)) {
+					clean_exit(g);
+				}
+				break;
 
-				case EVENT_TYPE_PAUSE:
-					usleep(e->usecs);
-					break;
+			case EVENT_TYPE_RX:
+				if (rx_one(g)) {
+					clean_exit(g);
+				}
+				if (g->success_if_no_receive == 0 &&
+				    rx_check(g)) {
+					clean_exit(g);
 				}
+				break;
+
+			case EVENT_TYPE_PAUSE:
+				usleep(e->usecs);
+				break;
 			}
 		}
 	}

From b0243e46bf32ffc72c139c8e63a25800e72ba26a Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 15:12:20 +0200
Subject: [PATCH 0949/2207] added functional.c multi-packet rx support

---
 utils/functional.c | 166 ++++++++++++++++++++++++++-------------------
 1 file changed, 98 insertions(+), 68 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 097b4b86d..2f376ce8a 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -326,7 +326,7 @@ tx_flush(struct Global *g)
 }
 
 uint64_t
-ring_avail_sends(struct netmap_ring *ring, unsigned pkt_len)
+ring_avail_packets(struct netmap_ring *ring, unsigned pkt_len)
 {
 	uint64_t slot_per_packet;
 
@@ -343,7 +343,7 @@ adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
 	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
 		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
 
-		sends_available += ring_avail_sends(ring, pkt_len);
+		sends_available += ring_avail_packets(ring, pkt_len);
 	}
 
 	return sends_available;
@@ -420,7 +420,7 @@ tx(struct Global *g, unsigned packets_num)
 		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
 		uint64_t num_ring_sends;
 
-		for (num_ring_sends = ring_avail_sends(ring, g->pktm_len);
+		for (num_ring_sends = ring_avail_packets(ring, g->pktm_len);
 		     num_ring_sends > 0 && packets_num > 0;
 		     --num_ring_sends, --packets_num) {
 			put_one_packet(g, ring);
@@ -455,27 +455,89 @@ ignore_received_frame(struct Global *g)
 	return 0; /* don't ignore */
 }
 
-/* Receive a single packet from any RX ring. */
+uint64_t
+adapter_avail_receives(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t receives_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+
+		receives_available += ring_avail_packets(ring, pkt_len);
+	}
+
+	return receives_available;
+}
+
+static int
+rx_check(struct Global *g)
+{
+	unsigned i;
+
+	if (g->pktr_len != g->pktm_len) {
+		printf("Received packet length (%u) different from "
+		       "expected (%u bytes)\n",
+		       g->pktr_len, g->pktm_len);
+		return -1;
+	}
+
+	for (i = 0; i < g->pktr_len; i++) {
+		if (g->pktr[i] != g->pktm[i]) {
+			printf("Received packet differs from model at "
+			       "offset %u (0x%02x!=0x%02x)\n",
+			       i, g->pktr[i], (uint8_t)g->pktm[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* Receive packets_num packets from any combination of RX rings. */
 static int
-rx_one(struct Global *g)
+rx(struct Global *g, unsigned packets_num)
 {
 	struct nm_desc *nmd = &g->nmd;
 	unsigned elapsed_ms = 0;
-	unsigned wait_ms    = 100;
+	unsigned wait_ms = 100;
 	unsigned int i;
 
+	/* We cycle here until either we timeout or we find enough space. */
 	for (;;) {
 	again:
-		for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
-			struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
-			unsigned int head        = ring->head;
-			unsigned int frags       = 0;
-			int truncated            = 0;
-
-			if (nm_ring_empty(ring)) {
-				continue;
-			}
+		if (adapter_avail_receives(nmd, g->pktm_len) >= packets_num) {
+			break;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			printf("%s: Timeout\n", __func__);
+			/* -n flag */
+			return g->success_if_no_receive == 1 ? 0 : -1;
+		}
+
+		/* Retry after a short while. */
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+		ioctl(nmd->fd, NIOCRXSYNC, NULL);
+	}
 
+
+	/* Once we have enough space, we start reading packets. We might use
+	 * multiple rings.
+	 */
+	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+		unsigned head = ring->head;
+		uint64_t num_ring_receives;
+
+		for (num_ring_receives = ring_avail_packets(ring, g->pktm_len);
+		     num_ring_receives > 0 && packets_num > 0;
+		     --num_ring_receives, --packets_num) {
+			unsigned int frags = 0;
+			int truncated = 0;
+
+			/* Read one packet from the ring. */
 			g->pktr_len = 0;
 			for (;;) {
 				struct netmap_slot *slot = &ring->slot[head];
@@ -504,11 +566,13 @@ rx_one(struct Global *g)
 					break;
 				}
 			}
+
+			/* Update ring status, without telling netmap. */
+			ring->head = ring->cur = head;
 			if (truncated) {
-				continue; /* skip this ring */
+				break; /* skip this ring */
 			}
-			ring->head = ring->cur = head;
-			ioctl(nmd->fd, NIOCRXSYNC, NULL);
+
 			if (ignore_received_frame(g)) {
 				if (g->verbose) {
 					printf("(ignoring packet with %u bytes "
@@ -518,60 +582,30 @@ rx_one(struct Global *g)
 					       g->pktr_len, frags, i);
 				}
 				elapsed_ms = 0;
+				/* We can go back there, because we're
+				 * decrementing packets_num each time, therefore
+				 * the we will wait only for the remaining
+				 * packets.
+				 */
 				goto again;
 			}
-			printf("packet (%u bytes, %u frags) received "
-			       "from RX "
-			       "ring #%d\n",
-			       g->pktr_len, frags, i);
-			/* frame received */
-			if (g->success_if_no_receive == 1) {
-				return -1;
-			} else {
-				return -0;
-			}
-		}
 
-		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout\n", __func__);
-			/* frame not received */
-			if (g->success_if_no_receive == 1) {
-				return 0;
-			} else {
-				return -1;
+			/* As soon as we find a packet wich doesn't match our
+			 * packet model we exit with status EXIT_FAILURE.
+			 */
+			if (rx_check(g)) {
+				clean_exit(g);
 			}
 		}
 
-		/* Retry after a short while. */
-		usleep(wait_ms * 1000);
-		elapsed_ms += wait_ms;
-		ioctl(nmd->fd, NIOCRXSYNC, NULL);
-	}
-
-	return 0;
-}
-
-static int
-rx_check(struct Global *g)
-{
-	unsigned i;
-
-	if (g->pktr_len != g->pktm_len) {
-		printf("Received packet length (%u) different from "
-		       "expected (%u bytes)\n",
-		       g->pktr_len, g->pktm_len);
-		return -1;
-	}
-
-	for (i = 0; i < g->pktr_len; i++) {
-		if (g->pktr[i] != g->pktm[i]) {
-			printf("Received packet differs from model at "
-			       "offset %u (0x%02x!=0x%02x)\n",
-			       i, g->pktr[i], (uint8_t)g->pktm[i]);
-			return -1;
+		if (packets_num == 0) {
+			break;
 		}
 	}
 
+	assert(packets_num == 0);
+	/* Once we're done we sync, freeing all slots at once. */
+	ioctl(nmd->fd, NIOCRXSYNC, NULL);
 	return 0;
 }
 
@@ -1102,11 +1136,7 @@ main(int argc, char **argv)
 				break;
 
 			case EVENT_TYPE_RX:
-				if (rx_one(g)) {
-					clean_exit(g);
-				}
-				if (g->success_if_no_receive == 0 &&
-				    rx_check(g)) {
+				if (rx(g, e->num)) {
 					clean_exit(g);
 				}
 				break;

From 87075d341ff706d9cdcbacdd6a6b81e23e463684 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 16:01:15 +0200
Subject: [PATCH 0950/2207] refactored rx()

---
 utils/functional.c | 106 ++++++++++++++++++++++++---------------------
 1 file changed, 57 insertions(+), 49 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 2f376ce8a..56f259ccb 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -418,11 +418,11 @@ tx(struct Global *g, unsigned packets_num)
 	 */
 	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
 		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
-		uint64_t num_ring_sends;
+		uint64_t ring_sends_num;
 
-		for (num_ring_sends = ring_avail_packets(ring, g->pktm_len);
-		     num_ring_sends > 0 && packets_num > 0;
-		     --num_ring_sends, --packets_num) {
+		for (ring_sends_num = ring_avail_packets(ring, g->pktm_len);
+		     ring_sends_num > 0 && packets_num > 0;
+		     --ring_sends_num, --packets_num) {
 			put_one_packet(g, ring);
 		}
 
@@ -494,13 +494,55 @@ rx_check(struct Global *g)
 	return 0;
 }
 
+int
+read_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+	unsigned head = ring->head;
+	int frags     = 0;
+
+	g->pktr_len = 0;
+	for (;;) {
+		struct netmap_slot *slot = &ring->slot[head];
+		char *buf                = NETMAP_BUF(ring, slot->buf_idx);
+
+		if (g->pktr_len + slot->len > sizeof(g->pktr)) {
+			/* Sanity check. */
+			printf("Error: received packet too "
+			       "large "
+			       "(>= %u bytes) ",
+			       g->pktr_len + slot->len);
+			clean_exit(g);
+		}
+		memcpy(g->pktr + g->pktr_len, buf, slot->len);
+		g->pktr_len += slot->len;
+		head = nm_ring_next(ring, head);
+		frags++;
+		if (!(slot->flags & NS_MOREFRAG)) {
+			break;
+		}
+		if (head == ring->tail) {
+			printf("warning: truncated packet "
+			       "(len=%u)\n",
+			       g->pktr_len);
+			frags = -1;
+			break;
+		}
+	}
+
+	ring->head = ring->cur = head;
+	printf("packet (%u bytes, %d frags) received "
+	       "from RX\n",
+	       g->pktr_len, frags);
+	return frags;
+}
+
 /* Receive packets_num packets from any combination of RX rings. */
 static int
 rx(struct Global *g, unsigned packets_num)
 {
 	struct nm_desc *nmd = &g->nmd;
 	unsigned elapsed_ms = 0;
-	unsigned wait_ms = 100;
+	unsigned wait_ms    = 100;
 	unsigned int i;
 
 	/* We cycle here until either we timeout or we find enough space. */
@@ -522,62 +564,28 @@ rx(struct Global *g, unsigned packets_num)
 		ioctl(nmd->fd, NIOCRXSYNC, NULL);
 	}
 
-
 	/* Once we have enough space, we start reading packets. We might use
 	 * multiple rings.
 	 */
 	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
 		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
-		unsigned head = ring->head;
-		uint64_t num_ring_receives;
-
-		for (num_ring_receives = ring_avail_packets(ring, g->pktm_len);
-		     num_ring_receives > 0 && packets_num > 0;
-		     --num_ring_receives, --packets_num) {
-			unsigned int frags = 0;
-			int truncated = 0;
-
-			/* Read one packet from the ring. */
-			g->pktr_len = 0;
-			for (;;) {
-				struct netmap_slot *slot = &ring->slot[head];
-				char *buf = NETMAP_BUF(ring, slot->buf_idx);
-
-				if (g->pktr_len + slot->len > sizeof(g->pktr)) {
-					/* Sanity check. */
-					printf("Error: received packet too "
-					       "large "
-					       "(>= %u bytes) ",
-					       g->pktr_len + slot->len);
-					clean_exit(g);
-				}
-				memcpy(g->pktr + g->pktr_len, buf, slot->len);
-				g->pktr_len += slot->len;
-				head = nm_ring_next(ring, head);
-				frags++;
-				if (!(slot->flags & NS_MOREFRAG)) {
-					break;
-				}
-				if (head == ring->tail) {
-					printf("warning: truncated packet "
-					       "(len=%u)\n",
-					       g->pktr_len);
-					truncated = 1;
-					break;
-				}
-			}
+		uint64_t ring_receives_num;
+
+		for (ring_receives_num = ring_avail_packets(ring, g->pktm_len);
+		     ring_receives_num > 0 && packets_num > 0;
+		     --ring_receives_num, --packets_num) {
+			int frags = 0;
 
-			/* Update ring status, without telling netmap. */
-			ring->head = ring->cur = head;
-			if (truncated) {
-				break; /* skip this ring */
+			frags = read_one_packet(g, ring);
+			if (frags == -1) {
+				break; /* Truncated packet, skip this ring. */
 			}
 
 			if (ignore_received_frame(g)) {
 				if (g->verbose) {
 					printf("(ignoring packet with %u bytes "
 					       "and "
-					       "%u frags received from RX ring "
+					       "%d frags received from RX ring "
 					       "#%d)\n",
 					       g->pktr_len, frags, i);
 				}

From 9146854dcf585dca722eb0ef8ee6f6ce0067249e Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 17:10:26 +0200
Subject: [PATCH 0951/2207] moved #include's from fd_server.h to .c files.

---
 utils/fd_server.c  | 10 ++++++++--
 utils/fd_server.h  |  9 ---------
 utils/functional.c |  9 ++++++++-
 3 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 91b13b1cb..262c4d073 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -10,6 +10,14 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#define NETMAP_WITH_LIBS
+#include 
 
 #include "fd_server.h"
 
@@ -203,9 +211,7 @@ handle_request(int socket)
 	int amount;
 	int ret;
 
-	memset(&res, 0, sizeof(res));
 	memset(&req, 0, sizeof(req));
-
 	amount = recv(socket, &req, sizeof(struct fd_request), 0);
 	if (amount == -1) {
 		printf("error while receiving the request\n");
diff --git a/utils/fd_server.h b/utils/fd_server.h
index 8497aea1c..120d4ba91 100644
--- a/utils/fd_server.h
+++ b/utils/fd_server.h
@@ -1,15 +1,6 @@
 #ifndef FD_LIB_H
 #define FD_LIB_H
 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-#define NETMAP_WITH_LIBS
-#include 
-
 struct fd_request {
 #define FD_GET 1
 #define FD_RELEASE 2
diff --git a/utils/functional.c b/utils/functional.c
index 56f259ccb..d45037e5f 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -34,7 +34,6 @@
 #include 
 #include 
 #define NETMAP_WITH_LIBS
-#include "fd_server.h"
 #include 
 #include 
 #include 
@@ -51,6 +50,8 @@
 #include 
 #include 
 
+#include "fd_server.h"
+
 #define ETH_ADDR_LEN 6
 
 struct Event {
@@ -886,6 +887,9 @@ get_if_fd(struct Global *g, const char *if_name, struct nm_desc *nmd)
 	int ret;
 
 	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		exit(EXIT_FAILURE);
+	}
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_GET;
@@ -921,6 +925,9 @@ release_if_fd(struct Global *g, const char *if_name)
 	int ret;
 
 	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		exit(EXIT_FAILURE);
+	}
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_RELEASE;

From e7efb74ebf83a75da1aadc63415c992a6ae9beac Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 17:48:31 +0200
Subject: [PATCH 0952/2207] added support for multi-packet send/receive inside
 test script

---
 utils/learning_bridge_test        | 14 +++++-----
 utils/pipe_test                   | 41 ----------------------------
 utils/rec_cp_mon_pipe_test        | 13 ++++-----
 utils/rec_cp_mon_vale_port_test   | 13 ++++-----
 utils/rec_zcp_mon_pipe_test       | 17 ++++++------
 utils/rec_zcp_mon_vale_port_test  | 17 ++++++------
 utils/send_cp_mon_pipe_test       | 13 ++++-----
 utils/send_cp_mon_vale_port_test  | 13 ++++-----
 utils/send_rec_pipe_test          | 45 +++++++++++++++++++++++++++++++
 utils/send_zcp_mon_pipe_test      | 17 ++++++------
 utils/send_zcp_mon_vale_port_test | 13 ++++-----
 utils/veth_test                   | 11 +++++---
 12 files changed, 122 insertions(+), 105 deletions(-)
 delete mode 100755 utils/pipe_test
 create mode 100755 utils/send_rec_pipe_test

diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 274cfdcbb..8b34b2ff6 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -22,12 +22,14 @@ check_exit $? "pre-open vale0:v1"
 ./functional -i vale0:v2 &>/dev/null
 check_exit $? "pre-open vale0:v2"
 
+fill='c'
+len=100
 # First send, every port should receive the frame.
-./functional -i vale0:v0 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v0 -r "${len}:${fill}" -s 10:10:10:10:10:10 &>/dev/null &
 p1=$!
-./functional -i vale0:v1 -r 100:c -T 1 -s 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v1 -r "${len}:${fill}" -s 10:10:10:10:10:10 &>/dev/null &
 p2=$!
-./functional -i vale0:v2 -t 100:c -s 10:10:10:10:10:10 &>/dev/null
+./functional -i vale0:v2 -t "${len}:${fill}" -s 10:10:10:10:10:10 &>/dev/null
 e3=$?
 wait $p1
 e1=$?
@@ -38,11 +40,11 @@ check_exit $e2 "receive vale0:v1"
 check_exit $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-./functional -i vale0:v2 -r 100:c -T 1 -d 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v2 -r "${len}:${fill}" -d 10:10:10:10:10:10    &>/dev/null &
 p4=$!
-./functional -i vale0:v1 -r 100:c -T 1 -d 10:10:10:10:10:10 -n &>/dev/null &
+./functional -i vale0:v1 -r "${len}:${fill}" -d 10:10:10:10:10:10 -n &>/dev/null &
 p5=$!
-./functional -i vale0:v0 -t 100:c -d 10:10:10:10:10:10 &>/dev/null
+./functional -i vale0:v0 -t "${len}:${fill}" -d 10:10:10:10:10:10    &>/dev/null
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/pipe_test b/utils/pipe_test
deleted file mode 100755
index 19fc0f31a..000000000
--- a/utils/pipe_test
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-################################################################################
-# Test objective: check if we can send and receive through netmap pipes.
-# Operations:
-# 0) restart fd_server to have a clean starting state
-# 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
-# 2) send from pipeA{1 and check if pipeA}1 receives it.
-# 2) send from pipeA}1 and check if pipeA{1 receives it.
-################################################################################
-source test_lib
-
-restart_fd_server
-
-# Pre-opening interface that will be needed. This is needed to avoid a race
-# condition between the sending and receiving ports.
-./functional -i netmap:pipeA{1 &>/dev/null
-check_exit $? "pre-open netmap:pipeA{1"
-./functional -i netmap:pipeA}1 &>/dev/null
-check_exit $? "pre-open netmap:pipeA}1"
-
-# pipeA}1 ---> pipeA{1
-./functional -i netmap:pipeA{1 -r 274:h &>/dev/null &
-p1=$!
-./functional -i netmap:pipeA}1 -t 274:h &>/dev/null
-e2=$?
-wait $p1
-e1=$?
-check_exit $e1 "receive netmap:pipeA{1"
-check_exit $e2 "send netmap:pipeA}1"
-
-# pipeA{1 ---> pipeA}1
-./functional -i netmap:pipeA}1 -r 274:h &>/dev/null &
-p1=$!
-./functional -i netmap:pipeA{1 -t 274:h &>/dev/null
-e2=$?
-wait $p1
-e1=$?
-check_exit $e1 "receive netmap:pipeA}1"
-check_exit $e2 "send netmap:pipeA{1"
-
-echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 9ef9505be..470b9a550 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -26,19 +26,20 @@ check_exit $? "pre-open netmap:pipe}1"
 
 fill='d'
 len=150
+num=1
 # First we send without reading from pipe{1
-./functional -i "netmap:pipe{1/r" -r "${len}:${fill}" &>/dev/null &
+./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}" &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive netmap:pipe{1/r"
-check_exit $e2 "send netmap:pipe}1"
+check_exit $e1 "receive-${num} netmap:pipe{1/r"
+check_exit $e2 "send-${num} netmap:pipe}1"
 
 # Then we read from pipe{1
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}" &>/dev/null
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" &>/dev/null
 e3=$?
-check_exit $e3 "receive netmap:pipe{1"
+check_exit $e3 "receive-${num} netmap:pipe{1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index 1e91e1992..aaeca925a 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -27,19 +27,20 @@ check_exit $? "pre-open vale0:v1"
 
 fill='d'
 len=150
+num=1
 # First we send without reading from v0
-./functional -i netmap:v0/r -r "${len}:${fill}" &>/dev/null &
+./functional -i netmap:v0/r -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
-./functional -i vale0:v1    -t "${len}:${fill}" &>/dev/null
+./functional -i vale0:v1    -t "${len}:${fill}:${num}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive netmap:v0/r"
-check_exit $e2 "send vale0:v1"
+check_exit $e1 "receive-${num} netmap:v0/r"
+check_exit $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-./functional -i vale0:v0    -r "${len}:${fill}" &>/dev/null
+./functional -i vale0:v0 -r "${len}:${fill}:${num}" &>/dev/null
 e3=$?
-check_exit $e3 "receive vale0:v0"
+check_exit $e3 "receive-${num} vale0:v0"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index 62b68fb29..a4f687a8f 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -25,26 +25,27 @@ check_exit $? "pre-open netmap:pipe}1"
 
 fill='d'
 len=150
+num=1
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}"    &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive netmap:pipe{1"
-check_exit $e2 "send netmap:pipe{1"
+check_exit $e1 "no-receive-${num} netmap:pipe{1"
+check_exit $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}" &>/dev/null &
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" &>/dev/null &
 p3=$!
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" &>/dev/null
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
-check_exit $e3 "receive netmap:pipe{1"
-check_exit $e4 "receive netmap:pipe{1/z"
+check_exit $e3 "receive-${num} netmap:pipe{1"
+check_exit $e4 "receive-${num} netmap:pipe{1/z"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
index a161c662b..7f63b85a8 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -27,26 +27,27 @@ check_exit $? "pre-open vale0:v1"
 
 fill='d'
 len=150
+num=1
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i vale0:v0/z -r "${len}:${fill}" -n &>/dev/null &
+./functional -i vale0:v0/z -r "${len}:${fill}:${num}" -n &>/dev/null &
 p1=$!
-./functional -i vale0:v1   -t "${len}:${fill}"    &>/dev/null
+./functional -i vale0:v1   -t "${len}:${fill}:${num}"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive vale0:v0/z"
-check_exit $e2 "send vale0:v0"
+check_exit $e1 "no-receive-${num} vale0:v0/z"
+check_exit $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-./functional -i "vale0:v0"   -r "${len}:${fill}" &>/dev/null &
+./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" &>/dev/null &
 p3=$!
-./functional -i "vale0:v0/z" -r "${len}:${fill}" &>/dev/null
+./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
-check_exit $e3 "receive vale0:v0"
-check_exit $e4 "receive vale0:v0/z"
+check_exit $e3 "receive-${num} vale0:v0"
+check_exit $e4 "receive-${num} vale0:v0/z"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index 30f79a85a..1e60e6f64 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -26,19 +26,20 @@ check_exit $? "pre-open netmap:pipe}1"
 
 fill='d'
 len=150
+num=1
 # First we send without reading from pipe}1
-./functional -i "netmap:pipe{1/t" -r "${len}:${fill}" &>/dev/null &
+./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}" &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive netmap:pipe{1/t"
-check_exit $e2 "send netmap:pipe{1"
+check_exit $e1 "receive-${num} netmap:pipe{1/t"
+check_exit $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-./functional -i "netmap:pipe}1" -r "${len}:${fill}" &>/dev/null
+./functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" &>/dev/null
 e3=$?
-check_exit $e3 "receive netmap:pipe}1"
+check_exit $e3 "receive-${num} netmap:pipe}1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_vale_port_test
index a41fcaec3..310f09393 100755
--- a/utils/send_cp_mon_vale_port_test
+++ b/utils/send_cp_mon_vale_port_test
@@ -25,19 +25,20 @@ check_exit $? "pre-open vale0:v1"
 
 fill='d'
 len=150
+num=1
 # First we send without reading from v1
-./functional -i netmap:v0/t -r "${len}:${fill}" &>/dev/null &
+./functional -i netmap:v0/t -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}" &>/dev/null
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive netmap:v0/t"
-check_exit $e2 "send vale0:v0"
+check_exit $e1 "receive-${num} netmap:v0/t"
+check_exit $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}" &>/dev/null
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" &>/dev/null
 e3=$?
-check_exit $e3 "receive vale0:v1"
+check_exit $e3 "receive-${num} vale0:v1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
new file mode 100755
index 000000000..30ae32cd5
--- /dev/null
+++ b/utils/send_rec_pipe_test
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive multiple packet at once
+#                 through netmap pipes.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
+# 2) send multiple packets from pipeA{1 and check if pipeA}1 receives them.
+# 2) send multiple packets from pipeA}1 and check if pipeA{1 receives them.
+################################################################################
+source test_lib
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:pipeA{1" &>/dev/null
+check_exit $? "pre-open netmap:pipeA{1"
+./functional -i "netmap:pipeA}1" &>/dev/null
+check_exit $? "pre-open netmap:pipeA}1"
+
+fill='h'
+len=274
+num=10
+# pipeA}1 ---> pipeA{1
+./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" &>/dev/null &
+p1=$!
+./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive-${num} netmap:pipeA{1"
+check_exit $e2 "send-${num} netmap:pipeA}1"
+
+# pipeA{1 ---> pipeA}1
+./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" &>/dev/null &
+p1=$!
+./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" &>/dev/null
+e2=$?
+wait $p1
+e1=$?
+check_exit $e1 "receive-${num} netmap:pipeA}1"
+check_exit $e2 "send-${num} netmap:pipeA{1"
+
+echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index 9aa0b703e..f63f0a782 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -26,26 +26,27 @@ check_exit $? "pre-open netmap:pipe}1"
 
 fill='d'
 len=150
+num=1
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}"    &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive netmap:pipe{1/z"
-check_exit $e2 "send netmap:pipe{1"
+check_exit $e1 "no-receive-${num} netmap:pipe{1/z"
+check_exit $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}" &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" &>/dev/null &
 p3=$!
-./functional -i "netmap:pipe}1"   -r "${len}:${fill}" &>/dev/null
+./functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
-check_exit $e3 "receive netmap:pipe{1/z"
-check_exit $e4 "receive netmap:pipe}1"
+check_exit $e3 "receive-${num} netmap:pipe{1/z"
+check_exit $e4 "receive-${num} netmap:pipe}1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_vale_port_test
index 0f27fc335..e64d6a5d8 100755
--- a/utils/send_zcp_mon_vale_port_test
+++ b/utils/send_zcp_mon_vale_port_test
@@ -28,19 +28,20 @@ check_exit $? "pre-open vale0:v1"
 
 fill='d'
 len=150
+num=1
 # First we send without reading from v1
-./functional -i netmap:v0/z -r "${len}:${fill}" &>/dev/null &
+./functional -i netmap:v0/z -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}" &>/dev/null
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive netmap:v0/z"
-check_exit $e2 "send vale0:v0"
+check_exit $e1 "receive-${num} netmap:v0/z"
+check_exit $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}" &>/dev/null
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" &>/dev/null
 e3=$?
-check_exit $e3 "receive vale0:v1"
+check_exit $e3 "receive-${num} vale0:v1"
 
 echo "Test successful."
\ No newline at end of file
diff --git a/utils/veth_test b/utils/veth_test
index 4fc7fa995..70ed1ad21 100755
--- a/utils/veth_test
+++ b/utils/veth_test
@@ -18,15 +18,18 @@ check_exit $? "pre-open netmap:veth1A"
 ./functional -i netmap:veth1B &>/dev/null
 check_exit $? "pre-open netmap:veth1B"
 
+fill='d'
+len=150
+num=1
 # During the first send we don't receive with the monitor, vale0:v1 should not
 # receive the frame.
-./functional -i netmap:veth1A -r 150:d &>/dev/null &
+./functional -i netmap:veth1A -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
-./functional -i netmap:veth1B -t 150:d &>/dev/null
+./functional -i netmap:veth1B -t "${len}:${fill}:${num}" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive netmap:veth1A"
-check_exit $e2 "send netmap:veth1B"
+check_exit $e1 "receive-${num} netmap:veth1A"
+check_exit $e2 "send-${num} netmap:veth1B"
 
 echo "Test successful."
\ No newline at end of file

From 57881547ca957ccc5d1346e358f43811b26898ac Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 18:31:32 +0200
Subject: [PATCH 0953/2207] updated usage()

---
 utils/functional.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index d45037e5f..d113f76a8 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -712,19 +712,21 @@ static struct Global _g;
 static void
 usage(void)
 {
-	printf("usage: ./functional [-h] "
-	       "[-s (shuts down the file descriptor server)]\n"
-	       "    -i NETMAP_PORT\n"
+	printf("usage: ./functional [-h]\n"
+	       "    [-c (shuts down the fd server)]\n"
+	       "    [-o (starts the fd server)]\n"
+	       "    [-i NETMAP_PORT (requests the interface from the fd server)]\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	       "    [-T TIMEOUT_SECS (=1)]\n"
 	       "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
 	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
 	       "LEN bytes)]\n"
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
-	       "with size LEN bytes)\n"
+	       "with size LEN bytes)]\n"
 	       "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
 	       "    [-I (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
+	       "    [-n (exit status = 0 if no frame was received)]"
 	       "    [-v (increment verbosity level)]\n"
 	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	       "\nExample:\n"

From 0f9432311070d4c0b42c9bf8b48d6d47e682d13c Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 18:33:44 +0200
Subject: [PATCH 0954/2207] added parse_arguments() and parse_arguments_usage()

---
 utils/test_lib | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/utils/test_lib b/utils/test_lib
index 84ad57611..813a822b3 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -116,4 +116,41 @@ function create_veth_interfaces() {
 	check_exit $? "trap-delete $if_name1"
 	cumulative_trap "close_fd_server" "EXIT"
 	check_exit $? "trap-detach $bdg_name:$if_name"
+}
+
+
+
+################################################################################
+# Prints general tests usage.
+# Arguments:
+#   None
+################################################################################
+function parse_arguments_usage() {
+	echo "usage: [-h] "
+	echo "       [-l packet_length]"
+	echo "       [-f fill_character]"
+	echo "       [-n packets_to_send]"
+}
+
+
+################################################################################
+# Parse the command line arguments of the calling script.
+# Arguments:
+#   It must be always called like like this 'parse_arguments "$@"'
+################################################################################
+function parse_arguments() {
+	while getopts "hl:f:n:" opt; do
+		case $opt in
+			l) len="$OPTARG"
+			;;
+			f) fill="$OPTARG"
+			;;
+			n) num="$OPTARG"
+			;;
+			h) parse_arguments_usage ; exit 0
+			;;
+			\?) parse_arguments_usage ; exit 1
+			;;
+		esac
+	done
 }
\ No newline at end of file

From 20b9ec12a62e7093b3923f3929b0f2f2eee4b560 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 22 Jun 2018 18:34:59 +0200
Subject: [PATCH 0955/2207] added arguments to set fill, len, num

---
 utils/rec_zcp_mon_pipe_test | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index a4f687a8f..cffb74cb3 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -23,9 +23,10 @@ check_exit $? "pre-open netmap:pipe{1/z"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-fill='d'
-len=150
-num=1
+parse_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
 ./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &

From 0d014a512ba0c93064e870cde5a8867c4ac9d048 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Sun, 24 Jun 2018 20:08:23 +0200
Subject: [PATCH 0956/2207] updated usage()

---
 utils/functional.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/utils/functional.c b/utils/functional.c
index d113f76a8..0aa161c7b 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -716,6 +716,8 @@ usage(void)
 	       "    [-c (shuts down the fd server)]\n"
 	       "    [-o (starts the fd server)]\n"
 	       "    [-i NETMAP_PORT (requests the interface from the fd server)]\n"
+	       "    [-s source MAC address (=0:0:0:0:0:0)]\n"
+	       "    [-d destination MAC address (=FF:FF:FF:FF:FF:FF)]\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	       "    [-T TIMEOUT_SECS (=1)]\n"
 	       "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
@@ -726,7 +728,7 @@ usage(void)
 	       "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
 	       "    [-I (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
-	       "    [-n (exit status = 0 if no frame was received)]"
+	       "    [-n (exit status = 0 <==> no frames were received)]\n"
 	       "    [-v (increment verbosity level)]\n"
 	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	       "\nExample:\n"

From 24cfbec9b808cfda6080c523bd1e754700b98101 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Sun, 24 Jun 2018 20:09:08 +0200
Subject: [PATCH 0957/2207] added a function to create a random MAC address

---
 utils/test_lib | 48 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/utils/test_lib b/utils/test_lib
index 813a822b3..618d8ca69 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -118,27 +118,24 @@ function create_veth_interfaces() {
 	check_exit $? "trap-detach $bdg_name:$if_name"
 }
 
-
-
 ################################################################################
-# Prints general tests usage.
+# Prints accepted command line arguments.
 # Arguments:
 #   None
 ################################################################################
-function parse_arguments_usage() {
+function send_recv_usage() {
 	echo "usage: [-h] "
 	echo "       [-l packet_length]"
 	echo "       [-f fill_character]"
 	echo "       [-n packets_to_send]"
 }
 
-
 ################################################################################
 # Parse the command line arguments of the calling script.
 # Arguments:
 #   It must be always called like like this 'parse_arguments "$@"'
 ################################################################################
-function parse_arguments() {
+function parse_send_recv_arguments() {
 	while getopts "hl:f:n:" opt; do
 		case $opt in
 			l) len="$OPTARG"
@@ -147,10 +144,45 @@ function parse_arguments() {
 			;;
 			n) num="$OPTARG"
 			;;
-			h) parse_arguments_usage ; exit 0
+			h) send_recv_usage ; exit 0
 			;;
-			\?) parse_arguments_usage ; exit 1
+			\?) send_recv_usage ; exit 1
 			;;
 		esac
 	done
+}
+
+
+################################################################################
+# Prints to stdout the hexadecimal representation of the received integer.
+# Arguments:
+#   $1 -> integer to translate
+################################################################################
+# https://superuser.com/a/218349
+int_to_hex() {
+	local my_int=$1
+	echo $(echo "obase=16; $my_int" | bc)
+}
+
+################################################################################
+# Prints to stdout a random MAC address. FF:FF:FF:FF:FF:FF and 0:0:0:0:0:0 are
+# excluded.
+# Arguments:
+#   None
+################################################################################
+# https://superuser.com/a/218349
+function get_random_MAC() {
+	local range=256
+	local MAC1=$(int_to_hex $((RANDOM % range)))
+	local MAC2=$(int_to_hex $((RANDOM % range)))
+	local MAC3=$(int_to_hex $((RANDOM % range)))
+	local MAC4=$(int_to_hex $((RANDOM % range)))
+	local MAC5=$(int_to_hex $((RANDOM % range)))
+	local MAC6=$(int_to_hex $((RANDOM % range)))
+	local MAC="${MAC1}:${MAC2}:${MAC3}:${MAC4}:${MAC5}:${MAC6}"
+	if [ $MAC = "FF:FF:FF:FF:FF:FF" ] || [ $MAC = "0:0:0:0:0:0" ] ; then
+		get_random_MAC
+	else
+		echo "$MAC"
+	fi
 }
\ No newline at end of file

From 9de4309b11f7602e9eba74abbdd689a34d60a625 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Sun, 24 Jun 2018 20:10:08 +0200
Subject: [PATCH 0958/2207] tests make use of randomly generated MAC addresses
 and command line arguments to set num, len e fill

---
 utils/learning_bridge_test        | 20 ++++++++++++--------
 utils/rec_cp_mon_pipe_test        |  8 +++++---
 utils/rec_cp_mon_vale_port_test   |  8 +++++---
 utils/rec_zcp_mon_pipe_test       |  9 +++++----
 utils/rec_zcp_mon_vale_port_test  |  8 +++++---
 utils/send_cp_mon_pipe_test       |  8 +++++---
 utils/send_cp_mon_vale_port_test  |  8 +++++---
 utils/send_rec_pipe_test          | 11 ++++++-----
 utils/send_zcp_mon_pipe_test      |  8 +++++---
 utils/send_zcp_mon_vale_port_test |  8 +++++---
 utils/veth_test                   |  8 +++++---
 11 files changed, 63 insertions(+), 41 deletions(-)

diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 8b34b2ff6..7dbe416a5 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -11,6 +11,12 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+s_MAC=$(get_random_MAC)
+d_MAC="FF:FF:FF:FF:FF:FF"
+
 restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -22,14 +28,12 @@ check_exit $? "pre-open vale0:v1"
 ./functional -i vale0:v2 &>/dev/null
 check_exit $? "pre-open vale0:v2"
 
-fill='c'
-len=100
 # First send, every port should receive the frame.
-./functional -i vale0:v0 -r "${len}:${fill}" -s 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &>/dev/null &
 p1=$!
-./functional -i vale0:v1 -r "${len}:${fill}" -s 10:10:10:10:10:10 &>/dev/null &
+./functional -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &>/dev/null &
 p2=$!
-./functional -i vale0:v2 -t "${len}:${fill}" -s 10:10:10:10:10:10 &>/dev/null
+./functional -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &>/dev/null
 e3=$?
 wait $p1
 e1=$?
@@ -40,11 +44,11 @@ check_exit $e2 "receive vale0:v1"
 check_exit $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-./functional -i vale0:v2 -r "${len}:${fill}" -d 10:10:10:10:10:10    &>/dev/null &
+./functional -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &>/dev/null &
 p4=$!
-./functional -i vale0:v1 -r "${len}:${fill}" -d 10:10:10:10:10:10 -n &>/dev/null &
+./functional -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &>/dev/null &
 p5=$!
-./functional -i vale0:v0 -t "${len}:${fill}" -d 10:10:10:10:10:10    &>/dev/null
+./functional -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"    &>/dev/null
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 470b9a550..501d83339 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -13,6 +13,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -24,9 +29,6 @@ check_exit $? "pre-open netmap:pipe{1/r"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-fill='d'
-len=150
-num=1
 # First we send without reading from pipe{1
 ./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index aaeca925a..250d521e2 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -13,6 +13,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 create_vale_persistent_port "v0" "vale0"
@@ -25,9 +30,6 @@ check_exit $? "pre-open netmap:v0/r"
 ./functional -i vale0:v1    &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
-fill='d'
-len=150
-num=1
 # First we send without reading from v0
 ./functional -i netmap:v0/r -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index cffb74cb3..49e15e662 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -12,6 +12,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -23,10 +28,6 @@ check_exit $? "pre-open netmap:pipe{1/z"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-parse_arguments "$@"
-fill="${fill:-d}"
-len="${len:-150}"
-num="${num:-1}"
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
 ./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
index 7f63b85a8..f98369426 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -13,6 +13,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 create_vale_persistent_port "v0" "vale0"
@@ -25,9 +30,6 @@ check_exit $? "pre-open vale0:v0/z"
 ./functional -i "vale0:v1"   &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
-fill='d'
-len=150
-num=1
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
 ./functional -i vale0:v0/z -r "${len}:${fill}:${num}" -n &>/dev/null &
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index 1e60e6f64..174b4eec7 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -13,6 +13,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -24,9 +29,6 @@ check_exit $? "pre-open netmap:pipe{1/t"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-fill='d'
-len=150
-num=1
 # First we send without reading from pipe}1
 ./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_vale_port_test
index 310f09393..252972b37 100755
--- a/utils/send_cp_mon_vale_port_test
+++ b/utils/send_cp_mon_vale_port_test
@@ -11,6 +11,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 create_vale_persistent_port "v0" "vale0"
@@ -23,9 +28,6 @@ check_exit $? "pre-open netmap:v0/t"
 ./functional -i vale0:v1    &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
-fill='d'
-len=150
-num=1
 # First we send without reading from v1
 ./functional -i netmap:v0/t -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index 30ae32cd5..367b2e1df 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -1,7 +1,6 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if we can send and receive multiple packet at once
-#                 through netmap pipes.
+# Test objective: check if we can send and receive packets through netmap pipes.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
@@ -10,6 +9,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-c}"
+len="${len:-274}"
+num="${num:-1}"
+
 restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -19,9 +23,6 @@ check_exit $? "pre-open netmap:pipeA{1"
 ./functional -i "netmap:pipeA}1" &>/dev/null
 check_exit $? "pre-open netmap:pipeA}1"
 
-fill='h'
-len=274
-num=10
 # pipeA}1 ---> pipeA{1
 ./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index f63f0a782..da4168e3b 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -13,6 +13,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -24,9 +29,6 @@ check_exit $? "pre-open netmap:pipe{1/z"
 ./functional -i "netmap:pipe}1"   &>/dev/null
 check_exit $? "pre-open netmap:pipe}1"
 
-fill='d'
-len=150
-num=1
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
 ./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_vale_port_test
index e64d6a5d8..ff3e5a5c7 100755
--- a/utils/send_zcp_mon_vale_port_test
+++ b/utils/send_zcp_mon_vale_port_test
@@ -14,6 +14,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 create_vale_persistent_port "v0" "vale0"
@@ -26,9 +31,6 @@ check_exit $? "pre-open netmap:v0/z"
 ./functional -i vale0:v1    &>/dev/null
 check_exit $? "pre-open vale0:v1"
 
-fill='d'
-len=150
-num=1
 # First we send without reading from v1
 ./functional -i netmap:v0/z -r "${len}:${fill}:${num}" &>/dev/null &
 p1=$!
diff --git a/utils/veth_test b/utils/veth_test
index 70ed1ad21..7f0c2f4d9 100755
--- a/utils/veth_test
+++ b/utils/veth_test
@@ -8,6 +8,11 @@
 ################################################################################
 source test_lib
 
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+
 restart_fd_server
 
 create_veth_interfaces "veth1"
@@ -18,9 +23,6 @@ check_exit $? "pre-open netmap:veth1A"
 ./functional -i netmap:veth1B &>/dev/null
 check_exit $? "pre-open netmap:veth1B"
 
-fill='d'
-len=150
-num=1
 # During the first send we don't receive with the monitor, vale0:v1 should not
 # receive the frame.
 ./functional -i netmap:veth1A -r "${len}:${fill}:${num}" &>/dev/null &

From 396666aee9426c0755e2dd0dc2a9bed9eec9f6bd Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Sun, 24 Jun 2018 20:53:30 +0200
Subject: [PATCH 0959/2207] added sequence check

---
 utils/functional.c                | 32 ++++++++++++++++++++++++--
 utils/rec_cp_mon_pipe_test        |  7 +++---
 utils/rec_cp_mon_vale_port_test   |  7 +++---
 utils/rec_zcp_mon_pipe_test       |  9 ++++----
 utils/rec_zcp_mon_vale_port_test  |  9 ++++----
 utils/send_cp_mon_pipe_test       |  7 +++---
 utils/send_cp_mon_vale_port_test  |  7 +++---
 utils/send_rec_pipe_test          |  9 ++++----
 utils/send_zcp_mon_pipe_test      |  9 ++++----
 utils/send_zcp_mon_vale_port_test |  7 +++---
 utils/test_lib                    |  5 ++++-
 utils/veth_test                   | 37 -------------------------------
 12 files changed, 74 insertions(+), 71 deletions(-)
 delete mode 100755 utils/veth_test

diff --git a/utils/functional.c b/utils/functional.c
index 0aa161c7b..a738137c0 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -76,6 +76,7 @@ struct Global {
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
 	int success_if_no_receive;
+	int sequential_fill;
 	int verbose;
 
 #define MAX_PKT_SIZE 65536
@@ -388,6 +389,16 @@ put_one_packet(struct Global *g, struct netmap_ring *ring)
 	       frags);
 }
 
+char
+next_fill(char cur_fill)
+{
+	if (cur_fill == 'z')
+		return 'a';
+	if (cur_fill == 'Z')
+		return 'A';
+	return ++cur_fill;
+}
+
 /* Transmit packets_num packets using any combination of TX rings. */
 static int
 tx(struct Global *g, unsigned packets_num)
@@ -425,6 +436,13 @@ tx(struct Global *g, unsigned packets_num)
 		     ring_sends_num > 0 && packets_num > 0;
 		     --ring_sends_num, --packets_num) {
 			put_one_packet(g, ring);
+
+			if (g->sequential_fill == 1) {
+				g->filler = next_fill(g->filler);
+				build_packet(g);
+			}
+
+
 		}
 
 		if (packets_num == 0) {
@@ -605,6 +623,11 @@ rx(struct Global *g, unsigned packets_num)
 			if (rx_check(g)) {
 				clean_exit(g);
 			}
+
+			if (g->sequential_fill == 1) {
+				g->filler = next_fill(g->filler);
+				build_packet(g);
+			}
 		}
 
 		if (packets_num == 0) {
@@ -729,6 +752,7 @@ usage(void)
 	       "    [-I (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
 	       "    [-n (exit status = 0 <==> no frames were received)]\n"
+	       "    [-q (during multi-packets send/receive increments fill character after each operation)]\n"
 	       "    [-v (increment verbosity level)]\n"
 	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	       "\nExample:\n"
@@ -1014,11 +1038,12 @@ main(int argc, char **argv)
 	g->num_events             = 0;
 	g->ignore_if_not_matching = /*false=*/0;
 	g->success_if_no_receive  = /*false=*/0;
+	g->sequential_fill  = /*false=*/0;
 	g->verbose                = 0;
 	g->num_loops              = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hcons:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hconqs:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1033,10 +1058,13 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'n':
-			/* Not receiving means timing out */
 			g->success_if_no_receive = /*true=*/1;
 			break;
 
+		case 'q':
+			g->sequential_fill = /*true=*/1;
+			break;
+
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
 			if (ret == -1) {
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 501d83339..13a9c0505 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -17,6 +17,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -30,9 +31,9 @@ check_exit $? "pre-open netmap:pipe{1/r"
 check_exit $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -40,7 +41,7 @@ check_exit $e1 "receive-${num} netmap:pipe{1/r"
 check_exit $e2 "send-${num} netmap:pipe}1"
 
 # Then we read from pipe{1
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e3=$?
 check_exit $e3 "receive-${num} netmap:pipe{1"
 
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index 250d521e2..b2031fe97 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -17,6 +17,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -31,9 +32,9 @@ check_exit $? "pre-open netmap:v0/r"
 check_exit $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-./functional -i netmap:v0/r -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p1=$!
-./functional -i vale0:v1    -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -41,7 +42,7 @@ check_exit $e1 "receive-${num} netmap:v0/r"
 check_exit $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-./functional -i vale0:v0 -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e3=$?
 check_exit $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index 49e15e662..a33577bb9 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -16,6 +16,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -30,9 +31,9 @@ check_exit $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}"    &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -41,9 +42,9 @@ check_exit $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p3=$!
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
index f98369426..5661f0575 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -17,6 +17,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -32,9 +33,9 @@ check_exit $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i vale0:v0/z -r "${len}:${fill}:${num}" -n &>/dev/null &
+./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &>/dev/null &
 p1=$!
-./functional -i vale0:v1   -t "${len}:${fill}:${num}"    &>/dev/null
+./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -43,9 +44,9 @@ check_exit $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p3=$!
-./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index 174b4eec7..86b301a06 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -17,6 +17,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -30,9 +31,9 @@ check_exit $? "pre-open netmap:pipe{1/t"
 check_exit $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -40,7 +41,7 @@ check_exit $e1 "receive-${num} netmap:pipe{1/t"
 check_exit $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-./functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e3=$?
 check_exit $e3 "receive-${num} netmap:pipe}1"
 
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_vale_port_test
index 252972b37..147c90512 100755
--- a/utils/send_cp_mon_vale_port_test
+++ b/utils/send_cp_mon_vale_port_test
@@ -15,6 +15,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -29,9 +30,9 @@ check_exit $? "pre-open netmap:v0/t"
 check_exit $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i netmap:v0/t -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -39,7 +40,7 @@ check_exit $e1 "receive-${num} netmap:v0/t"
 check_exit $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e3=$?
 check_exit $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index 367b2e1df..8f64192f6 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -13,6 +13,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -24,9 +25,9 @@ check_exit $? "pre-open netmap:pipeA{1"
 check_exit $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" -q &>/dev/null &
 p1=$!
-./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -q &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -34,9 +35,9 @@ check_exit $e1 "receive-${num} netmap:pipeA{1"
 check_exit $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" -q &>/dev/null &
 p1=$!
-./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq" -q &>/dev/null
 e2=$?
 wait $p1
 e1=$?
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index da4168e3b..bb2c2abbb 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -17,6 +17,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -31,9 +32,9 @@ check_exit $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &>/dev/null &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}"    &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"    &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -42,9 +43,9 @@ check_exit $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p3=$!
-./functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_vale_port_test
index ff3e5a5c7..2eb48d65b 100755
--- a/utils/send_zcp_mon_vale_port_test
+++ b/utils/send_zcp_mon_vale_port_test
@@ -18,6 +18,7 @@ parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
+seq="${seq:-}"
 
 restart_fd_server
 
@@ -32,9 +33,9 @@ check_exit $? "pre-open netmap:v0/z"
 check_exit $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i netmap:v0/z -r "${len}:${fill}:${num}" &>/dev/null &
+./functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" &>/dev/null
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq" &>/dev/null
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +43,7 @@ check_exit $e1 "receive-${num} netmap:v0/z"
 check_exit $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" &>/dev/null
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq" &>/dev/null
 e3=$?
 check_exit $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/test_lib b/utils/test_lib
index 618d8ca69..353399a7a 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -128,6 +128,7 @@ function send_recv_usage() {
 	echo "       [-l packet_length]"
 	echo "       [-f fill_character]"
 	echo "       [-n packets_to_send]"
+	echo "       [-q (sequential send/read)]"
 }
 
 ################################################################################
@@ -136,7 +137,7 @@ function send_recv_usage() {
 #   It must be always called like like this 'parse_arguments "$@"'
 ################################################################################
 function parse_send_recv_arguments() {
-	while getopts "hl:f:n:" opt; do
+	while getopts "hql:f:n:" opt; do
 		case $opt in
 			l) len="$OPTARG"
 			;;
@@ -144,6 +145,8 @@ function parse_send_recv_arguments() {
 			;;
 			n) num="$OPTARG"
 			;;
+			q) seq="-q"
+			;;
 			h) send_recv_usage ; exit 0
 			;;
 			\?) send_recv_usage ; exit 1
diff --git a/utils/veth_test b/utils/veth_test
deleted file mode 100755
index 7f0c2f4d9..000000000
--- a/utils/veth_test
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env bash
-################################################################################
-# Test objective: check if we can send and receive through veth interfaces.
-# Operations:
-# 0) restart fd_server to have a clean starting state
-# 1) create a pair of veth interfaces (veth1A, veth1B).
-# 2) send from veth1A and check if veth1B receives it.
-################################################################################
-source test_lib
-
-parse_send_recv_arguments "$@"
-fill="${fill:-d}"
-len="${len:-150}"
-num="${num:-1}"
-
-restart_fd_server
-
-create_veth_interfaces "veth1"
-# Pre-opening interface that will be needed. This is needed to avoid a race
-# condition between the sending and receiving ports.
-./functional -i netmap:veth1A &>/dev/null
-check_exit $? "pre-open netmap:veth1A"
-./functional -i netmap:veth1B &>/dev/null
-check_exit $? "pre-open netmap:veth1B"
-
-# During the first send we don't receive with the monitor, vale0:v1 should not
-# receive the frame.
-./functional -i netmap:veth1A -r "${len}:${fill}:${num}" &>/dev/null &
-p1=$!
-./functional -i netmap:veth1B -t "${len}:${fill}:${num}" &>/dev/null
-e2=$?
-wait $p1
-e1=$?
-check_exit $e1 "receive-${num} netmap:veth1A"
-check_exit $e2 "send-${num} netmap:veth1B"
-
-echo "Test successful."
\ No newline at end of file

From 1398a8104558318c23fda0afb4017d7ddcd1485f Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 17:30:35 +0200
Subject: [PATCH 0960/2207] Added utility function to redirect stdout and
 stderr to /dev/null, before doing that we create a new fd (3) which is
 redirected to stdout. This way we simplify the job needed to filter the
 output of a script

---
 utils/learning_bridge_test        |  40 ++++-----
 utils/rec_cp_mon_pipe_test        |  28 ++++---
 utils/rec_cp_mon_vale_port_test   |  31 +++----
 utils/rec_zcp_mon_pipe_test       |  32 ++++----
 utils/rec_zcp_mon_vale_port_test  |  35 ++++----
 utils/send_cp_mon_pipe_test       |  28 ++++---
 utils/send_cp_mon_vale_port_test  |  31 +++----
 utils/send_rec_pipe_test          |  28 ++++---
 utils/send_zcp_mon_pipe_test      |  32 ++++----
 utils/send_zcp_mon_vale_port_test |  31 +++----
 utils/test_lib                    | 132 ++++++++++++++++++++++++------
 11 files changed, 278 insertions(+), 170 deletions(-)

diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 7dbe416a5..273bebf0b 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -11,6 +11,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -21,41 +23,41 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0 &>/dev/null
-check_exit $? "pre-open vale0:v0"
-./functional -i vale0:v1 &>/dev/null
-check_exit $? "pre-open vale0:v1"
-./functional -i vale0:v2 &>/dev/null
-check_exit $? "pre-open vale0:v2"
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
+./functional -i vale0:v2
+check_success $? "pre-open vale0:v2"
 
 # First send, every port should receive the frame.
-./functional -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &>/dev/null &
+./functional -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p1=$!
-./functional -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &>/dev/null &
+./functional -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p2=$!
-./functional -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &>/dev/null
+./functional -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
 e3=$?
 wait $p1
 e1=$?
 wait $p2
 e2=$?
-check_exit $e1 "receive vale0:v0"
-check_exit $e2 "receive vale0:v1"
-check_exit $e3 "send vale0:v2"
+check_success $e1 "receive vale0:v0"
+check_success $e2 "receive vale0:v1"
+check_success $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-./functional -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &>/dev/null &
+./functional -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
 p4=$!
-./functional -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &>/dev/null &
+./functional -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
 p5=$!
-./functional -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"    &>/dev/null
+./functional -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
 e6=$?
 wait $p4
 e4=$?
 wait $p5
 e5=$?
-check_exit $e1 "receive vale0:v0"
-check_exit $e2 "receive vale0:v1"
-check_exit $e3 "send vale0:v2"
+check_success $e1 "receive vale0:v0"
+check_success $e2 "receive vale0:v1"
+check_success $e3 "send vale0:v2"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 13a9c0505..6dd0ef50b 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -13,6 +13,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -23,26 +25,26 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/r" &>/dev/null
-check_exit $? "pre-open netmap:pipe{1/r"
-./functional -i "netmap:pipe}1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe}1"
+./functional -i "netmap:pipe{1"
+check_success $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/r"
+check_success $? "pre-open netmap:pipe{1/r"
+./functional -i "netmap:pipe}1"
+check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:pipe{1/r"
-check_exit $e2 "send-${num} netmap:pipe}1"
+check_success $e1 "receive-${num} netmap:pipe{1/r"
+check_success $e2 "send-${num} netmap:pipe}1"
 
 # Then we read from pipe{1
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
 e3=$?
-check_exit $e3 "receive-${num} netmap:pipe{1"
+check_success $e3 "receive-${num} netmap:pipe{1"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index b2031fe97..83aab913f 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -13,6 +13,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -21,29 +23,30 @@ seq="${seq:-}"
 
 restart_fd_server
 
-create_vale_persistent_port "v0" "vale0"
+create_vale_persistent_port "v0"
+attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0    &>/dev/null
-check_exit $? "pre-open vale0:v0"
-./functional -i netmap:v0/r &>/dev/null
-check_exit $? "pre-open netmap:v0/r"
-./functional -i vale0:v1    &>/dev/null
-check_exit $? "pre-open vale0:v1"
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i netmap:v0/r
+check_success $? "pre-open netmap:v0/r"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-./functional -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:v0/r"
-check_exit $e2 "send-${num} vale0:v1"
+check_success $e1 "receive-${num} netmap:v0/r"
+check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-./functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
-check_exit $e3 "receive-${num} vale0:v0"
+check_success $e3 "receive-${num} vale0:v0"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index a33577bb9..2c2a56269 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -12,6 +12,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -22,33 +24,33 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/z" &>/dev/null
-check_exit $? "pre-open netmap:pipe{1/z"
-./functional -i "netmap:pipe}1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe}1"
+./functional -i "netmap:pipe{1"
+check_success $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/z"
+check_success $? "pre-open netmap:pipe{1/z"
+./functional -i "netmap:pipe}1"
+check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"    &>/dev/null
+./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive-${num} netmap:pipe{1"
-check_exit $e2 "send-${num} netmap:pipe{1"
+check_success $e1 "no-receive-${num} netmap:pipe{1"
+check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
-check_exit $e3 "receive-${num} netmap:pipe{1"
-check_exit $e4 "receive-${num} netmap:pipe{1/z"
+check_success $e3 "receive-${num} netmap:pipe{1"
+check_success $e4 "receive-${num} netmap:pipe{1/z"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
index 5661f0575..0c0bd1828 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -13,6 +13,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -21,36 +23,37 @@ seq="${seq:-}"
 
 restart_fd_server
 
-create_vale_persistent_port "v0" "vale0"
+create_vale_persistent_port "v0"
+attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v0"   &>/dev/null
-check_exit $? "pre-open vale0:v0"
-./functional -i "vale0:v0/z" &>/dev/null
-check_exit $? "pre-open vale0:v0/z"
-./functional -i "vale0:v1"   &>/dev/null
-check_exit $? "pre-open vale0:v1"
+./functional -i "vale0:v0"
+check_success $? "pre-open vale0:v0"
+./functional -i "vale0:v0/z"
+check_success $? "pre-open vale0:v0/z"
+./functional -i "vale0:v1"
+check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &>/dev/null &
+./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"    &>/dev/null
+./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive-${num} vale0:v0/z"
-check_exit $e2 "send-${num} vale0:v0"
+check_success $e1 "no-receive-${num} vale0:v0/z"
+check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
-check_exit $e3 "receive-${num} vale0:v0"
-check_exit $e4 "receive-${num} vale0:v0/z"
+check_success $e3 "receive-${num} vale0:v0"
+check_success $e4 "receive-${num} vale0:v0/z"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index 86b301a06..8ba528e2f 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -13,6 +13,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -23,26 +25,26 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/t" &>/dev/null
-check_exit $? "pre-open netmap:pipe{1/t"
-./functional -i "netmap:pipe}1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe}1"
+./functional -i "netmap:pipe{1"
+check_success $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/t"
+check_success $? "pre-open netmap:pipe{1/t"
+./functional -i "netmap:pipe}1"
+check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:pipe{1/t"
-check_exit $e2 "send-${num} netmap:pipe{1"
+check_success $e1 "receive-${num} netmap:pipe{1/t"
+check_success $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-./functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
 e3=$?
-check_exit $e3 "receive-${num} netmap:pipe}1"
+check_success $e3 "receive-${num} netmap:pipe}1"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_vale_port_test
index 147c90512..6c2d39e65 100755
--- a/utils/send_cp_mon_vale_port_test
+++ b/utils/send_cp_mon_vale_port_test
@@ -11,6 +11,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -19,29 +21,30 @@ seq="${seq:-}"
 
 restart_fd_server
 
-create_vale_persistent_port "v0" "vale0"
+create_vale_persistent_port "v0"
+attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0    &>/dev/null
-check_exit $? "pre-open vale0:v0"
-./functional -i netmap:v0/t &>/dev/null
-check_exit $? "pre-open netmap:v0/t"
-./functional -i vale0:v1    &>/dev/null
-check_exit $? "pre-open vale0:v1"
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i netmap:v0/t
+check_success $? "pre-open netmap:v0/t"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:v0/t"
-check_exit $e2 "send-${num} vale0:v0"
+check_success $e1 "receive-${num} netmap:v0/t"
+check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
-check_exit $e3 "receive-${num} vale0:v1"
+check_success $e3 "receive-${num} vale0:v1"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index 8f64192f6..2c93a9798 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -9,6 +9,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-c}"
 len="${len:-274}"
@@ -19,29 +21,29 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipeA{1" &>/dev/null
-check_exit $? "pre-open netmap:pipeA{1"
-./functional -i "netmap:pipeA}1" &>/dev/null
-check_exit $? "pre-open netmap:pipeA}1"
+./functional -i "netmap:pipeA{1"
+check_success $? "pre-open netmap:pipeA{1"
+./functional -i "netmap:pipeA}1"
+check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" -q &>/dev/null &
+./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" -q &
 p1=$!
-./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -q &>/dev/null
+./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -q
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:pipeA{1"
-check_exit $e2 "send-${num} netmap:pipeA}1"
+check_success $e1 "receive-${num} netmap:pipeA{1"
+check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" -q &>/dev/null &
+./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" -q &
 p1=$!
-./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq" -q &>/dev/null
+./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq" -q
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:pipeA}1"
-check_exit $e2 "send-${num} netmap:pipeA{1"
+check_success $e1 "receive-${num} netmap:pipeA}1"
+check_success $e2 "send-${num} netmap:pipeA{1"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index bb2c2abbb..66711048c 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -13,6 +13,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -23,33 +25,33 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/z" &>/dev/null
-check_exit $? "pre-open netmap:pipe{1/z"
-./functional -i "netmap:pipe}1"   &>/dev/null
-check_exit $? "pre-open netmap:pipe}1"
+./functional -i "netmap:pipe{1"
+check_success $? "pre-open netmap:pipe{1"
+./functional -i "netmap:pipe{1/z"
+check_success $? "pre-open netmap:pipe{1/z"
+./functional -i "netmap:pipe}1"
+check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"    &>/dev/null
+./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "no-receive-${num} netmap:pipe{1/z"
-check_exit $e2 "send-${num} netmap:pipe{1"
+check_success $e1 "no-receive-${num} netmap:pipe{1/z"
+check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
-check_exit $e3 "receive-${num} netmap:pipe{1/z"
-check_exit $e4 "receive-${num} netmap:pipe}1"
+check_success $e3 "receive-${num} netmap:pipe{1/z"
+check_success $e4 "receive-${num} netmap:pipe}1"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_vale_port_test
index 2eb48d65b..3eb666d87 100755
--- a/utils/send_zcp_mon_vale_port_test
+++ b/utils/send_zcp_mon_vale_port_test
@@ -14,6 +14,8 @@
 ################################################################################
 source test_lib
 
+redirect_std
+
 parse_send_recv_arguments "$@"
 fill="${fill:-d}"
 len="${len:-150}"
@@ -22,29 +24,30 @@ seq="${seq:-}"
 
 restart_fd_server
 
-create_vale_persistent_port "v0" "vale0"
+create_vale_persistent_port "v0"
+attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0    &>/dev/null
-check_exit $? "pre-open vale0:v0"
-./functional -i netmap:v0/z &>/dev/null
-check_exit $? "pre-open netmap:v0/z"
-./functional -i vale0:v1    &>/dev/null
-check_exit $? "pre-open vale0:v1"
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i netmap:v0/z
+check_success $? "pre-open netmap:v0/z"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &>/dev/null &
+./functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_exit $e1 "receive-${num} netmap:v0/z"
-check_exit $e2 "send-${num} vale0:v0"
+check_success $e1 "receive-${num} netmap:v0/z"
+check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq" &>/dev/null
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
-check_exit $e3 "receive-${num} vale0:v1"
+check_success $e3 "receive-${num} vale0:v1"
 
-echo "Test successful."
\ No newline at end of file
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 353399a7a..ba71412a3 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -1,4 +1,27 @@
 #!/usr/bin/env bash
+################################################################################
+# Creates the new file descriptor "3" and redirects it to stdout, then redirects
+# stderr e stdout to /dev/null. This way only the stuff we redirect to 3 is
+# printed simplifying the work required to filter our output.
+# Arguments:
+#   None
+################################################################################
+function redirect_std() {
+	exec 3>&1
+	exec 1>/dev/null
+	exec 2>&1
+}
+
+################################################################################
+# Calls echo on the correct file descriptor (it needs to match the new file
+# descriptor created by redirect_std()).
+# Arguments:
+#   None
+################################################################################
+function stdout_echo() {
+	echo "$@" 1>&3
+}
+
 ################################################################################
 # Closes the file descriptor server.
 # Arguments:
@@ -6,7 +29,7 @@
 ################################################################################
 function close_fd_server() {
 	./functional -c &>/dev/null
-	check_exit $? "close_fd_server"
+	check_success "$?" "close_fd_server"
 }
 
 ################################################################################
@@ -16,7 +39,7 @@ function close_fd_server() {
 ################################################################################
 function start_fd_server() {
 	./functional -o &>/dev/null
-	check_exit $? "start_fd_server"
+	check_success "$?" "start_fd_server"
 }
 
 ################################################################################
@@ -30,23 +53,51 @@ function restart_fd_server() {
 }
 
 ################################################################################
-# Checks the exit value, if it's != 0 cleans up and terminates the script.
+# Checks the exit value, if it's different from the expected exit value
+# terminates the script.
 # Arguments:
 #   $1 -> exit value to check
-#   $2 -> string printed
+#   $2 -> expected exit value to check against
+#   $3 -> string printed
 ################################################################################
 function check_exit() {
 	local exit_value="$1"
-	local string_to_print="$2"
+	local expected_value="$2"
+	local string_to_print="$3"
 
-	if [ $exit_value != 0 ] ; then
-		echo "$string_to_print FAIL($exit_value)."
+	if [ $exit_value != $expected_value ] ; then
+		stdout_echo "$string_to_print FAIL($exit_value != $expected_value)."
 		exit 1
-	# else
-		# echo "$2 was successful."
 	fi
 }
 
+################################################################################
+# Checks the exit value, if it's different from 0 terminates the script.
+# Arguments:
+#   $1 -> exit value to check
+#   $2 -> string printed
+################################################################################
+function check_success() {
+	local exit_value="$1"
+	local string_to_print="$2"
+
+	check_exit "$exit_value" 0 "$string_to_print"
+}
+
+################################################################################
+# Checks the exit value, if it's different from 1 (only 1 is considered failure
+# at the moment) terminates the script.
+# Arguments:
+#   $1 -> exit value to check
+#   $2 -> string printed
+################################################################################
+function check_failure() {
+	local exit_value="$1"
+	local string_to_print="$2"
+
+	check_exit "$exit_value" 1 "$string_to_print"
+}
+
 ################################################################################
 # Set a trap while maintaining the one currently set. The new one will be
 # executed first.
@@ -76,24 +127,57 @@ function cumulative_trap() {
 # called when the script exits.
 # Arguments:
 #   $1 -> name of the VALE persistent port
-#   $2 -> name of the VALE switch that the port will be to be attached to
+#   $2 -> expected exit value of vale-ctl (optional, default = 0)
 ################################################################################
 function create_vale_persistent_port() {
 	local if_name="$1"
-	local bdg_name="$2"
+	local create_exit_value="$2"
+	create_exit_value="${create_exit_value:-0}"
 
-	vale-ctl -n "$if_name"
-	check_exit $? "create $if_name"
+	vale-ctl -n "$if_name" &>/dev/null
+	check_exit "$?" "$create_exit_value" "create $if_name"
 	cumulative_trap "vale-ctl -r $if_name" "EXIT"
-	check_exit $? "trap-remove $if_name"
+	check_success "$?" "trap-remove $if_name"
+}
+
+################################################################################
+# Attaches an interface registered to the os to a VALE bridge and sets a cleanup
+# handler which will be called when the script exits.
+# Arguments:
+#   $1 -> name of the VALE bridge that the port will be to be attached to
+#   $2 -> name of the interface
+#   $3 -> expected exit value of vale-ctl (optional, default = 0)
+################################################################################
+function attach_to_vale_bridge() {
+	local bdg_name="$1"
+	local if_name="$2"
+	local attach_exit_value="$3"
+	attach_exit_value="${attach_exit_value:-0}"
 
 	vale-ctl -a "$bdg_name:$if_name"
-	check_exit $? "attach $bdg_name:$if_name"
+	check_exit "$?" "$attach_exit_value" "attach $bdg_name:$if_name"
 	cumulative_trap "vale-ctl -d $bdg_name:$if_name" "EXIT"
 	# We first need to close the file descriptor of the interface, otherwise
 	# the detach will fail. To accomplish that we shut down fd_server.
 	cumulative_trap "close_fd_server" "EXIT"
-	check_exit $? "trap-detach $bdg_name:$if_name"
+	check_success "$?" "trap-detach $bdg_name:$if_name"
+}
+
+################################################################################
+# Detaches an interface registered to the os from a VALE bridge.
+# Arguments:
+#   $1 -> name of the VALE bridge that the port will be to be attached to
+#   $2 -> name of the interface
+#   $3 -> expected exit value of vale-ctl (optional, default = 0)
+################################################################################
+function detach_from_vale_bridge() {
+	local bdg_name="$1"
+	local if_name="$2"
+	local detach_exit_value="$3"
+	detach_exit_value="${detach_exit_value:-0}"
+
+	vale-ctl -d "$bdg_name:$if_name"
+	check_exit "$?" "$detach_exit_value" "detach $bdg_name:$if_name"
 }
 
 ################################################################################
@@ -108,14 +192,14 @@ function create_veth_interfaces() {
 	local if_name2="${if_name}B"
 
 	ip link add "$if_name1" type veth peer name "$if_name2"
-	check_exit $? "create $if_name"
+	check_success "$?" "create $if_name"
 	# We first need to close the file descriptor of the interfaces,
 	# otherwise the delete will fail. To accomplish that we shut down
 	# fd_server.
 	cumulative_trap "ip link delete $if_name1" "EXIT"
-	check_exit $? "trap-delete $if_name1"
+	check_success "$?" "trap-delete $if_name1"
 	cumulative_trap "close_fd_server" "EXIT"
-	check_exit $? "trap-detach $bdg_name:$if_name"
+	check_success "$?" "trap-detach $bdg_name:$if_name"
 }
 
 ################################################################################
@@ -124,11 +208,11 @@ function create_veth_interfaces() {
 #   None
 ################################################################################
 function send_recv_usage() {
-	echo "usage: [-h] "
-	echo "       [-l packet_length]"
-	echo "       [-f fill_character]"
-	echo "       [-n packets_to_send]"
-	echo "       [-q (sequential send/read)]"
+	stdout_echo "usage: [-h] "
+	stdout_echo "       [-l packet_length]"
+	stdout_echo "       [-f fill_character]"
+	stdout_echo "       [-n packets_to_send]"
+	stdout_echo "       [-q (sequential send/read)]"
 }
 
 ################################################################################

From c78c377a501874e07dfe586f3ed74de2be0ce842 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 18:38:02 +0200
Subject: [PATCH 0961/2207] added option to directly open an interface, without
 requesting it to the fd_server

---
 utils/functional.c | 56 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index a738137c0..62148bdad 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -75,8 +75,9 @@ struct Global {
 	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
-	int success_if_no_receive;
-	int sequential_fill;
+	int success_if_no_receive;  /* exit status 0 if we receive no packets */
+	int sequential_fill;        /* increment fill char for multi-packets operations */
+	int request_from_fd_server;
 	int verbose;
 
 #define MAX_PKT_SIZE 65536
@@ -739,6 +740,7 @@ usage(void)
 	       "    [-c (shuts down the fd server)]\n"
 	       "    [-o (starts the fd server)]\n"
 	       "    [-i NETMAP_PORT (requests the interface from the fd server)]\n"
+	       "    [-I NETMAP_PORT (directly opens the interface)]\n"
 	       "    [-s source MAC address (=0:0:0:0:0:0)]\n"
 	       "    [-d destination MAC address (=FF:FF:FF:FF:FF:FF)]\n"
 	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
@@ -749,7 +751,7 @@ usage(void)
 	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	       "with size LEN bytes)]\n"
 	       "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
-	       "    [-I (ignore ethernet frames with unmatching Ethernet "
+	       "    [-g (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
 	       "    [-n (exit status = 0 <==> no frames were received)]\n"
 	       "    [-q (during multi-packets send/receive increments fill character after each operation)]\n"
@@ -1016,6 +1018,7 @@ parse_mac_address(const char *opt, char *mac)
 int
 main(int argc, char **argv)
 {
+	struct nm_desc *nmd = NULL;
 	struct Global *g = &_g;
 	unsigned int i, c;
 	int opt;
@@ -1038,12 +1041,13 @@ main(int argc, char **argv)
 	g->num_events             = 0;
 	g->ignore_if_not_matching = /*false=*/0;
 	g->success_if_no_receive  = /*false=*/0;
+	g->request_from_fd_server = /*true=*/1;
 	g->sequential_fill  = /*false=*/0;
 	g->verbose                = 0;
 	g->num_loops              = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hconqs:d:i:w:F:T:t:r:Ivp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hconqs:d:i:I:w:F:T:t:r:gvp:C:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1085,6 +1089,11 @@ main(int argc, char **argv)
 			g->ifname = optarg;
 			break;
 
+		case 'I':
+			g->ifname = optarg;
+			g->request_from_fd_server = /*false=*/0;
+			break;
+
 		case 'F':
 			g->max_frag_size = atoi(optarg);
 			break;
@@ -1104,7 +1113,7 @@ main(int argc, char **argv)
 
 			if (g->num_events >= MAX_EVENTS) {
 				printf("Too many events\n");
-				return -1;
+				exit(EXIT_FAILURE);
 			}
 
 			if (opt == 'p') {
@@ -1120,13 +1129,13 @@ main(int argc, char **argv)
 			if (ret) {
 				printf("Invalid event syntax '%s'\n", optarg);
 				usage();
-				return -1;
+				exit(EXIT_FAILURE);
 			}
 			g->num_events++;
 			break;
 		}
 
-		case 'I':
+		case 'g':
 			g->ignore_if_not_matching = 1;
 			break;
 
@@ -1138,26 +1147,38 @@ main(int argc, char **argv)
 			g->num_loops = atoi(optarg);
 			if (g->num_loops == 0) {
 				printf("Invalid -C option '%s'\n", optarg);
-				return -1;
+				exit(EXIT_FAILURE);
 			}
 			break;
 
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage();
-			return -1;
+			exit(EXIT_FAILURE);
 		}
 	}
 
 	if (!g->ifname) {
 		printf("Missing ifname\n");
 		usage();
-		return -1;
+		exit(EXIT_FAILURE);
 	}
 
-	if (get_if_fd(g, g->ifname, &g->nmd) < 0) {
+	ret = 0;
+	if (g->request_from_fd_server == 0) {
+		/* We directly open the file descriptor. */
+		nmd = nm_open(g->ifname, NULL, 0, NULL);
+		if (nmd == NULL) {
+			ret = -1;
+		} else {
+			memcpy(&g->nmd, nmd, sizeof(struct nm_desc));
+		}
+	} else {
+		ret = get_if_fd(g, g->ifname, &g->nmd);
+	}
+	if (ret == -1) {
 		printf("Failed to nm_open(%s)\n", g->ifname);
-		return -1;
+		exit(EXIT_FAILURE);
 	}
 
 	if (g->wait_link_secs > 0) {
@@ -1198,7 +1219,16 @@ main(int argc, char **argv)
 	/* if we have sent something, wait for all tx to complete */
 	tx_flush(g);
 
-	release_if_fd(g, g->ifname);
+	if (g->request_from_fd_server == 0) {
+		ret = nm_close(nmd);
+	} else {
+		release_if_fd(g, g->ifname);
+		ret = 0;
+	}
+
+	if (ret == -1) {
+		printf("Failed to nm_close(%s)\n", g->ifname);
+	}
 
 	return 0;
 }

From 5359e4b37d211bf9b9a82dd74a5ba928952ddb7e Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 18:38:49 +0200
Subject: [PATCH 0962/2207] added function to destroy persistent VALE port

---
 utils/test_lib | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/utils/test_lib b/utils/test_lib
index ba71412a3..1dcd32378 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 ################################################################################
 # Creates the new file descriptor "3" and redirects it to stdout, then redirects
-# stderr e stdout to /dev/null. This way only the stuff we redirect to 3 is
+# stderr e stdout to /dev/null. This way only the stuff we redirect to fd 3 is
 # printed simplifying the work required to filter our output.
 # Arguments:
 #   None
@@ -28,7 +28,7 @@ function stdout_echo() {
 #   None
 ################################################################################
 function close_fd_server() {
-	./functional -c &>/dev/null
+	./functional -c
 	check_success "$?" "close_fd_server"
 }
 
@@ -38,7 +38,7 @@ function close_fd_server() {
 #   None
 ################################################################################
 function start_fd_server() {
-	./functional -o &>/dev/null
+	./functional -o
 	check_success "$?" "start_fd_server"
 }
 
@@ -134,12 +134,27 @@ function create_vale_persistent_port() {
 	local create_exit_value="$2"
 	create_exit_value="${create_exit_value:-0}"
 
-	vale-ctl -n "$if_name" &>/dev/null
+	vale-ctl -n "$if_name"
 	check_exit "$?" "$create_exit_value" "create $if_name"
 	cumulative_trap "vale-ctl -r $if_name" "EXIT"
 	check_success "$?" "trap-remove $if_name"
 }
 
+################################################################################
+# Destroys a VALE persistent port.
+# Arguments:
+#   $1 -> name of the VALE persistent port
+#   $2 -> expected exit value of vale-ctl (optional, default = 0)
+################################################################################
+function destroy_vale_persistent_port() {
+	local if_name="$1"
+	local destroy_exit_value="$2"
+	destroy_exit_value="${destroy_exit_value:-0}"
+
+	vale-ctl -r "$if_name"
+	check_exit "$?" "$destroy_exit_value" "create $if_name"
+}
+
 ################################################################################
 # Attaches an interface registered to the os to a VALE bridge and sets a cleanup
 # handler which will be called when the script exits.

From c4c4c6baedd3273e1c83443eeb6d0df0925d15ee Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 18:39:45 +0200
Subject: [PATCH 0963/2207] added attach/detach/destroy tests for persistent
 VALE ports

---
 utils/vale_port_destroy       | 32 ++++++++++++++++++++++++++++++++
 utils/vale_port_double_attach | 21 +++++++++++++++++++++
 utils/vale_port_double_create | 24 ++++++++++++++++++++++++
 3 files changed, 77 insertions(+)
 create mode 100755 utils/vale_port_destroy
 create mode 100755 utils/vale_port_double_attach
 create mode 100755 utils/vale_port_double_create

diff --git a/utils/vale_port_destroy b/utils/vale_port_destroy
new file mode 100755
index 000000000..fe7cdc3f6
--- /dev/null
+++ b/utils/vale_port_destroy
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check that we can't create two VALE persistent ports with the
+#                 same name.
+################################################################################
+source test_lib
+
+redirect_std
+
+bridge="vale0"
+bridgeA="${bridge}A"
+bridgeB="${bridge}B"
+port="v0"
+
+create_vale_persistent_port "$port" 0
+destroy_vale_persistent_port "$port" 0
+
+create_vale_persistent_port "$port" 0
+
+attach_to_vale_bridge "$bridgeA" "$port" 0
+destroy_vale_persistent_port "$port" 1
+
+attach_to_vale_bridge "$bridgeB" "$port" 0
+destroy_vale_persistent_port "$port" 1
+
+detach_from_vale_bridge "$bridgeB" "$port" 0
+destroy_vale_persistent_port "$port" 1
+
+detach_from_vale_bridge "$bridgeA" "$port" 0
+destroy_vale_persistent_port "$port" 0
+
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/vale_port_double_attach b/utils/vale_port_double_attach
new file mode 100755
index 000000000..c0ba34214
--- /dev/null
+++ b/utils/vale_port_double_attach
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check that a VALE persistent port can't be attached 2 times
+#                 to the same VALE bridge, but can be attached to 2 different
+#                 bridges.
+################################################################################
+source test_lib
+
+redirect_std
+
+bridge="vale0"
+bridgeA="${bridge}A"
+bridgeB="${bridge}B"
+port="v0"
+
+create_vale_persistent_port "$port" 0
+attach_to_vale_bridge "$bridgeA" "$port" 0
+attach_to_vale_bridge "$bridgeA" "$port" 1
+attach_to_vale_bridge "$bridgeB" "$port" 0
+
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/vale_port_double_create b/utils/vale_port_double_create
new file mode 100755
index 000000000..6f460f87a
--- /dev/null
+++ b/utils/vale_port_double_create
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check that we can't create two VALE persistent ports with the
+#                 same name.
+################################################################################
+source test_lib
+
+redirect_std
+
+bridge="vale0"
+bridgeA="${bridge}A"
+bridgeB="${bridge}B"
+port="v0"
+
+create_vale_persistent_port "$port" 0
+create_vale_persistent_port "$port" 1
+
+attach_to_vale_bridge "$bridgeA" "$port" 0
+create_vale_persistent_port "$port" 1
+
+attach_to_vale_bridge "$bridgeB" "$port" 0
+create_vale_persistent_port "$port" 1
+
+stdout_echo "Test successful."
\ No newline at end of file

From 635725ce5ecb159b511c82e5ef2c4d629fb45317 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 18:41:34 +0200
Subject: [PATCH 0964/2207] added open with exclusive flag tests for VALE ports
 and netmap pipes

---
 utils/exclusive_open_ephemeral_vale_port_test | 27 +++++++++++++++++
 .../exclusive_open_persistent_vale_port_test  | 30 +++++++++++++++++++
 utils/exclusive_open_pipe_test                | 26 ++++++++++++++++
 3 files changed, 83 insertions(+)
 create mode 100755 utils/exclusive_open_ephemeral_vale_port_test
 create mode 100755 utils/exclusive_open_persistent_vale_port_test
 create mode 100755 utils/exclusive_open_pipe_test

diff --git a/utils/exclusive_open_ephemeral_vale_port_test b/utils/exclusive_open_ephemeral_vale_port_test
new file mode 100755
index 000000000..6466f20e1
--- /dev/null
+++ b/utils/exclusive_open_ephemeral_vale_port_test
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check that an ephemeral VALE port opened with the exclusive
+#                 flag can't be opened again.
+################################################################################
+source test_lib
+
+redirect_std
+
+restart_fd_server
+
+bridge="vale0"
+port="v0"
+# We open ${bridge}:${port} with the exclusive flag from the file descriptor.
+./functional -i "${bridge}:${port}/x"
+check_success $? "exclusive-open ${bridge}:${port}/x"
+
+# Then we open the same interface again, this time without requesting it from
+# the file descriptor, causing a second nm_open().
+./functional -I "${bridge}:${port}"
+check_failure $? "no-open ${bridge}:${port}"
+
+# Check that another exclusive open request fails.
+./functional -I "${bridge}:${port}/x"
+check_failure $? "no-open ${bridge}:${port}/x"
+
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/exclusive_open_persistent_vale_port_test b/utils/exclusive_open_persistent_vale_port_test
new file mode 100755
index 000000000..8cb06a71d
--- /dev/null
+++ b/utils/exclusive_open_persistent_vale_port_test
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check that an persistent VALE port opened with the exclusive
+#                 flag can't be opened again.
+################################################################################
+source test_lib
+
+redirect_std
+
+restart_fd_server
+
+bridge="vale0"
+port="v0"
+create_vale_persistent_port "$port"
+attach_to_vale_bridge "$bridge" "$port"
+
+# We open the persistent port with the exclusive flag from the file descriptor.
+./functional -i "${bridge}:${port}/x"
+check_success $? "exclusive-open ${bridge}:${port}/x"
+
+# Then we open the same interface again, this time without requesting it from
+# the file descriptor, causing a second nm_open().
+./functional -I "${bridge}:${port}"
+check_failure $? "no-open ${bridge}:${port}"
+
+# Check that another exclusive open request fails.
+./functional -I "${bridge}:${port}/x"
+check_failure $? "no-open ${bridge}:${port}/x"
+
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/exclusive_open_pipe_test b/utils/exclusive_open_pipe_test
new file mode 100755
index 000000000..675175d1b
--- /dev/null
+++ b/utils/exclusive_open_pipe_test
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check that a netmap pipe opened with the exclusive flag can't
+#                 be opened again.
+################################################################################
+source test_lib
+
+redirect_std
+
+restart_fd_server
+
+pipe="pipeA{1"
+# We open pipeA{1 with the exclusive flag from the file descriptor.
+./functional -i "netmap:${pipe}/x"
+check_success $? "exclusive-open netmap:${pipe}/x"
+
+# Then we open the same interface again, this time without requesting it from
+# the file descriptor, causing a second nm_open().
+./functional -I "netmap:${pipe}"
+check_failure $? "no-open netmap:${pipe}"
+
+# Check that another exclusive open request fails.
+./functional -I "netmap:${pipe}/x"
+check_failure $? "no-open netmap:${pipe}/x"
+
+stdout_echo "Test successful."
\ No newline at end of file

From 6143cb41903fa261602d47f7643f7edd77a78cad Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 18:42:09 +0200
Subject: [PATCH 0965/2207] send/receive test for veth ports

---
 utils/send_rec_veth_test | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100755 utils/send_rec_veth_test

diff --git a/utils/send_rec_veth_test b/utils/send_rec_veth_test
new file mode 100755
index 000000000..15615481d
--- /dev/null
+++ b/utils/send_rec_veth_test
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive through veth interfaces.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of veth interfaces (veth1A, veth1B).
+# 2) send from veth1A and check if veth1B receives it.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+create_veth_interfaces "veth1"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i netmap:veth1A
+check_success $? "pre-open netmap:veth1A"
+./functional -i netmap:veth1B
+check_success $? "pre-open netmap:veth1B"
+
+# During the first send we don't receive with the monitor, vale0:v1 should not
+# receive the frame.
+./functional -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "receive-${num} netmap:veth1A"
+check_success $e2 "send-${num} netmap:veth1B"
+
+stdout_echo "Test successful."
\ No newline at end of file

From a6cc12e3ca0f22b76848efc9f38c1f26cf3c7a73 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 25 Jun 2018 22:12:30 +0200
Subject: [PATCH 0966/2207] added partial read test for netmap pipes

---
 utils/GNUmakefile                |  2 +-
 utils/get_tx_rings_avail_sends.c | 73 ++++++++++++++++++++++++++++++++
 utils/get_tx_rings_max_sends.c   | 73 ++++++++++++++++++++++++++++++++
 utils/partial_read_pipe_test     | 68 +++++++++++++++++++++++++++++
 utils/send_rec_pipe_test         |  8 ++--
 5 files changed, 219 insertions(+), 5 deletions(-)
 create mode 100644 utils/get_tx_rings_avail_sends.c
 create mode 100644 utils/get_tx_rings_max_sends.c
 create mode 100755 utils/partial_read_pipe_test

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index d9d2458a5..9a7756a4e 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,6 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm functional ctrl-api-test fd_server
+PROGS	= test_select testmmap test_nm functional ctrl-api-test fd_server get_tx_rings_avail_sends get_tx_rings_max_sends
 X86PROGS = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/get_tx_rings_avail_sends.c b/utils/get_tx_rings_avail_sends.c
new file mode 100644
index 000000000..cdc39a985
--- /dev/null
+++ b/utils/get_tx_rings_avail_sends.c
@@ -0,0 +1,73 @@
+#include 
+#include 
+#include 
+
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+
+uint64_t
+slot_per_send(struct netmap_ring *ring, unsigned pkt_len)
+{
+	return (uint64_t)(ceil((double)pkt_len / (double)ring->nr_buf_size));
+}
+
+uint64_t
+ring_avail_sends(struct netmap_ring *ring, unsigned pkt_len)
+{
+	if (pkt_len == 0) {
+		return nm_ring_space(ring);
+	}
+
+	return nm_ring_space(ring) / slot_per_send(ring, pkt_len);
+}
+
+
+uint64_t
+adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t sends_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+		sends_available += ring_avail_sends(ring, pkt_len);
+	}
+
+	return sends_available;
+}
+
+int
+main(int argc, char **argv)
+{
+	uint64_t avail_sends;
+	struct nm_desc *nmd;
+	const char *if_name;
+	uint64_t pkt_len;
+
+	if (argc == 2) {
+		pkt_len = 0;
+	} else if (argc == 3) {
+		pkt_len = atoi(argv[2]);
+		if (pkt_len == 0) {
+			printf("-1");
+			exit(EXIT_FAILURE);
+		}
+	} else {
+		printf("-1");
+		exit(EXIT_FAILURE);
+	}
+
+	fclose(stderr);
+	if_name = argv[1];
+	nmd = nm_open(if_name, NULL, 0, NULL);
+	if (nmd == NULL) {
+		printf("-1");
+		exit(EXIT_FAILURE);
+	}
+
+	avail_sends = adapter_avail_sends(nmd, pkt_len);
+	printf("%" PRId64, avail_sends);
+	return 0;
+}
\ No newline at end of file
diff --git a/utils/get_tx_rings_max_sends.c b/utils/get_tx_rings_max_sends.c
new file mode 100644
index 000000000..1eabc21f5
--- /dev/null
+++ b/utils/get_tx_rings_max_sends.c
@@ -0,0 +1,73 @@
+#include 
+#include 
+#include 
+
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+
+uint64_t
+slot_per_send(struct netmap_ring *ring, unsigned pkt_len)
+{
+	return (uint64_t)(ceil((double)pkt_len / (double)ring->nr_buf_size));
+}
+
+uint64_t
+ring_max_sends(struct netmap_ring *ring, unsigned pkt_len)
+{
+	if (pkt_len == 0) {
+		return nm_ring_space(ring) - 1;
+	}
+
+	return (ring->num_slots - 1) / slot_per_send(ring, pkt_len);
+}
+
+
+uint64_t
+adapter_max_sends(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t sends_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+		sends_available += ring_max_sends(ring, pkt_len);
+	}
+
+	return sends_available;
+}
+
+int
+main(int argc, char **argv)
+{
+	uint64_t max_sends;
+	struct nm_desc *nmd;
+	const char *if_name;
+	uint64_t pkt_len;
+
+	if (argc == 2) {
+		pkt_len = 0;
+	} else if (argc == 3) {
+		pkt_len = atoi(argv[2]);
+		if (pkt_len == 0) {
+			printf("-1");
+			exit(EXIT_FAILURE);
+		}
+	} else {
+		printf("-1");
+		exit(EXIT_FAILURE);
+	}
+
+	fclose(stderr);
+	if_name = argv[1];
+	nmd = nm_open(if_name, NULL, 0, NULL);
+	if (nmd == NULL) {
+		printf("-1");
+		exit(EXIT_FAILURE);
+	}
+
+	max_sends = adapter_max_sends(nmd, pkt_len);
+	printf("%" PRId64, max_sends);
+	return 0;
+}
\ No newline at end of file
diff --git a/utils/partial_read_pipe_test b/utils/partial_read_pipe_test
new file mode 100755
index 000000000..5fd6d136c
--- /dev/null
+++ b/utils/partial_read_pipe_test
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive through netmap pipes.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of netmap pipes (${pipe}{1, ${pipe}}1).
+# 2) send from ${pipe}{1 and check if ${pipe}}1 receives it.
+# 2) send from ${pipe}}1 and check if ${pipe}{1 receives it.
+################################################################################
+source test_lib
+
+redirect_std
+
+restart_fd_server
+
+fill='h'
+len=274
+num_send=10
+num_recv=7
+pipe="pipeA"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:${pipe}{1"
+check_success $? "pre-open netmap:${pipe}{1"
+./functional -i "netmap:${pipe}}1"
+check_success $? "pre-open netmap:${pipe}}1"
+
+# ${pipe}}1 ---> ${pipe}{1
+./functional -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
+p1=$!
+./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "receive-7 netmap:${pipe}{1"
+check_success $e2 "send-10 netmap:${pipe}}1"
+
+# At the moment get_tx_rings_max_sends and get_tx_rings_avail_sends do not
+# get the interface fd from fd_server, but they still read the correct values
+# from the rings. I don't know if that's something we can relay on.
+exit_status=0
+ring_max_sends=$(./get_tx_rings_max_sends "netmap:${pipe}}1" "$len") 1>&3
+if [ $ring_max_sends = -1 ] ; then
+	exit_status=1
+fi
+check_success $exit_status "get_tx_rings_max_sends netmap:${pipe}}1 $len"
+
+exit_status=0
+ring_avail_sends=$(./get_tx_rings_avail_sends "netmap:${pipe}}1" "$len")
+if [ $ring_avail_sends = -1 ] ; then
+	exit_status=1
+fi
+check_success $exit_status "get_tx_rings_avail_sends netmap:${pipe}}1 $len"
+
+exit_status=0
+ring_used_sends="$(($ring_max_sends - $ring_avail_sends))"
+pending_sends="$(($num_send - $num_recv))"
+if [ $ring_used_sends != $pending_sends ] ; then
+	exit_status = 1
+fi
+check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
+
+
+num_send="$(($ring_avail_sends + 1))"
+./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+check_failure $? "send-${num_send} netmap:${pipe}}1"
+
+stdout_echo "Test successful."
\ No newline at end of file
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index 2c93a9798..00591c50b 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -27,9 +27,9 @@ check_success $? "pre-open netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" -q &
+./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -q
+./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -37,9 +37,9 @@ check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" -q &
+./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq" -q
+./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?

From 4c72d2276b199849b23307b7111c2170716095b9 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 14:36:47 +0200
Subject: [PATCH 0967/2207] added comments to explain get_tx_rings_{avail,
 max}_sends.c

---
 utils/get_tx_rings_avail_sends.c | 9 +++++++++
 utils/get_tx_rings_max_sends.c   | 8 ++++++++
 2 files changed, 17 insertions(+)

diff --git a/utils/get_tx_rings_avail_sends.c b/utils/get_tx_rings_avail_sends.c
index cdc39a985..d4fc0efc6 100644
--- a/utils/get_tx_rings_avail_sends.c
+++ b/utils/get_tx_rings_avail_sends.c
@@ -1,3 +1,12 @@
+/* Given an interface name and a packet length (optional), prints to stdout
+ * the number of packets that can be send through the interface rings. If the
+ * packet length is missing, the number of available slot is printed instead.
+ * Prints "-1" if something went wrong.
+ * Arguments:
+ *    $1 -> interface name
+ *    $2 -> packet length
+ */
+
 #include 
 #include 
 #include 
diff --git a/utils/get_tx_rings_max_sends.c b/utils/get_tx_rings_max_sends.c
index 1eabc21f5..192faf583 100644
--- a/utils/get_tx_rings_max_sends.c
+++ b/utils/get_tx_rings_max_sends.c
@@ -1,3 +1,11 @@
+/* Given an interface name and a packet length (optional), prints to stdout
+ * the max number of packets that can be send through the interface rings.
+ * If packet length is missing, the total number of slot is printed instead.
+ * Prints "-1" if something went wrong.
+ * Arguments:
+ *    $1 -> interface name
+ *    $2 -> packet length
+ */
 #include 
 #include 
 #include 

From b7e64d9322fd858ac39e5340f043dee88c36b5b5 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 15:47:09 +0200
Subject: [PATCH 0968/2207] added main test script which calls tests with
 randomized values for packets length, number of packets and fill character

---
 utils/exclusive_open_ephemeral_vale_port_test |  2 +-
 .../exclusive_open_persistent_vale_port_test  |  2 +-
 utils/exclusive_open_pipe_test                |  2 +-
 utils/functional.c                            |  2 +
 utils/learning_bridge_test                    |  2 +-
 utils/partial_read_pipe_test                  |  2 +-
 utils/randomized_tests                        | 65 +++++++++++++++++++
 utils/rec_cp_mon_pipe_test                    |  8 +--
 utils/rec_cp_mon_vale_port_test               |  2 +-
 utils/rec_zcp_mon_pipe_test                   |  2 +-
 utils/rec_zcp_mon_vale_port_test              |  2 +-
 utils/send_cp_mon_pipe_test                   |  2 +-
 utils/send_cp_mon_vale_port_test              |  2 +-
 utils/send_rec_pipe_test                      |  2 +-
 utils/send_rec_veth_test                      |  2 +-
 utils/send_zcp_mon_pipe_test                  |  2 +-
 utils/send_zcp_mon_vale_port_test             |  2 +-
 utils/test_lib                                | 13 +++-
 utils/vale_port_destroy                       |  2 +-
 utils/vale_port_double_attach                 |  2 +-
 utils/vale_port_double_create                 |  2 +-
 21 files changed, 100 insertions(+), 22 deletions(-)
 create mode 100755 utils/randomized_tests

diff --git a/utils/exclusive_open_ephemeral_vale_port_test b/utils/exclusive_open_ephemeral_vale_port_test
index 6466f20e1..50b829765 100755
--- a/utils/exclusive_open_ephemeral_vale_port_test
+++ b/utils/exclusive_open_ephemeral_vale_port_test
@@ -24,4 +24,4 @@ check_failure $? "no-open ${bridge}:${port}"
 ./functional -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "exclusive_open_ephemeral_vale_port_test"
\ No newline at end of file
diff --git a/utils/exclusive_open_persistent_vale_port_test b/utils/exclusive_open_persistent_vale_port_test
index 8cb06a71d..35ba6d2a3 100755
--- a/utils/exclusive_open_persistent_vale_port_test
+++ b/utils/exclusive_open_persistent_vale_port_test
@@ -27,4 +27,4 @@ check_failure $? "no-open ${bridge}:${port}"
 ./functional -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "exclusive_open_persistent_vale_port_test"
\ No newline at end of file
diff --git a/utils/exclusive_open_pipe_test b/utils/exclusive_open_pipe_test
index 675175d1b..20f15b2b8 100755
--- a/utils/exclusive_open_pipe_test
+++ b/utils/exclusive_open_pipe_test
@@ -23,4 +23,4 @@ check_failure $? "no-open netmap:${pipe}"
 ./functional -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "exclusive_open_pipe_test"
\ No newline at end of file
diff --git a/utils/functional.c b/utils/functional.c
index 62148bdad..1712149f4 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -533,6 +533,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 			       g->pktr_len + slot->len);
 			clean_exit(g);
 		}
+
 		memcpy(g->pktr + g->pktr_len, buf, slot->len);
 		g->pktr_len += slot->len;
 		head = nm_ring_next(ring, head);
@@ -540,6 +541,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 		if (!(slot->flags & NS_MOREFRAG)) {
 			break;
 		}
+
 		if (head == ring->tail) {
 			printf("warning: truncated packet "
 			       "(len=%u)\n",
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 273bebf0b..7fa7ea664 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -60,4 +60,4 @@ check_success $e1 "receive vale0:v0"
 check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "learning_bridge_test"
\ No newline at end of file
diff --git a/utils/partial_read_pipe_test b/utils/partial_read_pipe_test
index 5fd6d136c..fd81de1d2 100755
--- a/utils/partial_read_pipe_test
+++ b/utils/partial_read_pipe_test
@@ -65,4 +65,4 @@ num_send="$(($ring_avail_sends + 1))"
 ./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "partial_read_pipe_test"
\ No newline at end of file
diff --git a/utils/randomized_tests b/utils/randomized_tests
new file mode 100755
index 000000000..131f48079
--- /dev/null
+++ b/utils/randomized_tests
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+################################################################################
+# Runs all the tests using randomized values for number of packets, fill
+# character and packets length.
+################################################################################
+
+random_num="$((65 + $RANDOM % 58))"
+# https://stackoverflow.com/a/10503163
+random_fill=$(printf \\$(printf '%03o' $random_num))
+# We need to make sure that we can send this number of packets with this length
+# at once. At the moment i just put max values which works for the defaults
+# number of rings and buffer size.
+random_len="$((50 + $RANDOM % 10000))"
+random_packet_num="$((1 + $RANDOM % 100))"
+# Use and empty string instead of "-q" if you don't want to perform a sequential
+# send/receive check
+seq_check="-q"
+echo "Running tests with"
+echo "   number of packets: ${random_packet_num}"
+echo "   fill character   : ${random_fill}"
+echo "   sequence check   : ${seq_check}"
+echo "   packet length    : ${random_len}"
+echo ""
+
+echo "send/receive pipe"
+./send_rec_pipe_test          -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "partial read pipe"
+./partial_read_pipe_test
+# echo "send/receive veth"
+# ./send_rec_veth_test          -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+
+echo "destroy VALE port"
+./vale_port_destroy
+echo "double create VALE port"
+./vale_port_double_create
+echo "double attach VALE port"
+./vale_port_double_attach
+
+echo "exclusive open ephemeral VALE port"
+./exclusive_open_ephemeral_vale_port_test
+echo "exclusive open persistent VALE port"
+./exclusive_open_persistent_vale_port_test
+echo "exclusive open pipe"
+./exclusive_open_pipe_test
+
+echo "receive copy monitor attached to pipe"
+./rec_cp_mon_pipe_test        -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "receive copy monitor attached to persistent VALE port"
+./rec_cp_mon_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "zero-copy monitor attached to receiving pipe"
+./rec_zcp_mon_pipe_test       -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "zero-copy monitor attached to receiving persistent VALE port"
+./rec_zcp_mon_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+
+echo "send copy monitor attached to pipe"
+./send_cp_mon_pipe_test       -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send copy monitor attached to persistent VALE port"
+./send_cp_mon_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "zero-copy monitor attached to sending pipe"
+./send_zcp_mon_pipe_test      -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "zero-copy monitor attached to sending persistent VALE port"
+./send_zcp_mon_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+
+echo "learning bridge algorithm"
+./learning_bridge_test                              -l $random_len -f $random_fill
\ No newline at end of file
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index 6dd0ef50b..cb20334db 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -39,12 +39,12 @@ p1=$!
 e2=$?
 wait $p1
 e1=$?
-check_success $e1 "receive-${num} netmap:pipe{1/r"
-check_success $e2 "send-${num} netmap:pipe}1"
+check_success $e1 "receive-${num}${seq} netmap:pipe{1/r"
+check_success $e2 "send-${num}${seq} netmap:pipe}1"
 
 # Then we read from pipe{1
 ./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
 e3=$?
-check_success $e3 "receive-${num} netmap:pipe{1"
+check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "rec_cp_mon_pipe_test"
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_vale_port_test
index 83aab913f..372e3c5c9 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_vale_port_test
@@ -49,4 +49,4 @@ check_success $e2 "send-${num} vale0:v1"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "rec_cp_mon_vale_port_test"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index 2c2a56269..1e1d6e48b 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -53,4 +53,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:pipe{1"
 check_success $e4 "receive-${num} netmap:pipe{1/z"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "rec_zcp_mon_pipe_test"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_vale_port_test
index 0c0bd1828..38702dff6 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_vale_port_test
@@ -56,4 +56,4 @@ e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} vale0:v0/z"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "rec_zcp_mon_vale_port_test"
\ No newline at end of file
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index 8ba528e2f..c259b7313 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -47,4 +47,4 @@ check_success $e2 "send-${num} netmap:pipe{1"
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "send_cp_mon_pipe_test"
\ No newline at end of file
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_vale_port_test
index 6c2d39e65..474c32dfe 100755
--- a/utils/send_cp_mon_vale_port_test
+++ b/utils/send_cp_mon_vale_port_test
@@ -47,4 +47,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "send_cp_mon_vale_port_test"
\ No newline at end of file
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index 00591c50b..9beffd02f 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -46,4 +46,4 @@ e1=$?
 check_success $e1 "receive-${num} netmap:pipeA}1"
 check_success $e2 "send-${num} netmap:pipeA{1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "send_rec_pipe_test"
\ No newline at end of file
diff --git a/utils/send_rec_veth_test b/utils/send_rec_veth_test
index 15615481d..30be82acf 100755
--- a/utils/send_rec_veth_test
+++ b/utils/send_rec_veth_test
@@ -37,4 +37,4 @@ e1=$?
 check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "send_rec_veth_test"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index 66711048c..5550d0fc5 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -54,4 +54,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:pipe{1/z"
 check_success $e4 "receive-${num} netmap:pipe}1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "send_zcp_mon_pipe_test"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_vale_port_test
index 3eb666d87..5066dade7 100755
--- a/utils/send_zcp_mon_vale_port_test
+++ b/utils/send_zcp_mon_vale_port_test
@@ -50,4 +50,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "send_zcp_mon_vale_port_test"
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 1dcd32378..1fd2dcd2a 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -52,6 +52,17 @@ function restart_fd_server() {
 	start_fd_server
 }
 
+################################################################################
+# Can be called, when a test script successfully terminates, to perform a
+# specific action.
+# Arguments:
+#   $1 -> string containing the test script name
+################################################################################
+function test_successful() {
+	local test_name="$1"
+	stdout_echo "   Success."
+}
+
 ################################################################################
 # Checks the exit value, if it's different from the expected exit value
 # terminates the script.
@@ -66,7 +77,7 @@ function check_exit() {
 	local string_to_print="$3"
 
 	if [ $exit_value != $expected_value ] ; then
-		stdout_echo "$string_to_print FAIL($exit_value != $expected_value)."
+		stdout_echo "   $string_to_print FAIL($exit_value != $expected_value)."
 		exit 1
 	fi
 }
diff --git a/utils/vale_port_destroy b/utils/vale_port_destroy
index fe7cdc3f6..bd42d8fef 100755
--- a/utils/vale_port_destroy
+++ b/utils/vale_port_destroy
@@ -29,4 +29,4 @@ destroy_vale_persistent_port "$port" 1
 detach_from_vale_bridge "$bridgeA" "$port" 0
 destroy_vale_persistent_port "$port" 0
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "vale_port_destroy"
\ No newline at end of file
diff --git a/utils/vale_port_double_attach b/utils/vale_port_double_attach
index c0ba34214..f6dbeb090 100755
--- a/utils/vale_port_double_attach
+++ b/utils/vale_port_double_attach
@@ -18,4 +18,4 @@ attach_to_vale_bridge "$bridgeA" "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "vale_port_double_attach"
\ No newline at end of file
diff --git a/utils/vale_port_double_create b/utils/vale_port_double_create
index 6f460f87a..f680afe60 100755
--- a/utils/vale_port_double_create
+++ b/utils/vale_port_double_create
@@ -21,4 +21,4 @@ create_vale_persistent_port "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 create_vale_persistent_port "$port" 1
 
-stdout_echo "Test successful."
\ No newline at end of file
+test_successful "vale_port_double_create"
\ No newline at end of file

From 003e4b905acab804920c66b03240751409104ef1 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 17:09:07 +0200
Subject: [PATCH 0969/2207] fixed (?) fragmented frames not being seen as such
 from netmap monitors

---
 sys/dev/netmap/netmap_monitor.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 096f86c6e..92ad81b16 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -640,6 +640,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 		ms->len = s->len;
 		s->len = tmp;
 
+		ms->flags = s->flags;
 		s->flags |= NS_BUF_CHANGED;
 
 		beg = nm_next(beg, lim);
@@ -757,6 +758,7 @@ netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_
 
 			memcpy(dst, src, copy_len);
 			ms->len = copy_len;
+			ms->flags = s->flags;
 			sent++;
 
 			beg = nm_next(beg, lim);

From 01e41ab29c2cab563764eadf8dd26a5619a0510b Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 21:06:11 +0200
Subject: [PATCH 0970/2207] updated partial_read_pipe_test comments

---
 utils/partial_read_pipe_test | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/utils/partial_read_pipe_test b/utils/partial_read_pipe_test
index fd81de1d2..0821b6a51 100755
--- a/utils/partial_read_pipe_test
+++ b/utils/partial_read_pipe_test
@@ -1,11 +1,13 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if we can send and receive through netmap pipes.
+# Test objective: check that if the receiving pipe receives less than the
+#                 sending pipe sent, the non-received slot are left inside the
+#                 sending pipe ring.
 # Operations:
 # 0) restart fd_server to have a clean starting state
-# 1) create a pair of netmap pipes (${pipe}{1, ${pipe}}1).
-# 2) send from ${pipe}{1 and check if ${pipe}}1 receives it.
-# 2) send from ${pipe}}1 and check if ${pipe}{1 receives it.
+# 1) create a pair of netmap pipes (pipe{1, pipe}1).
+# 2) send X packets from pipe{1 and receive X-Y packets from pipe}1.
+# 2) check that pipe{1 still has X-Y slots pending for transmission.
 ################################################################################
 source test_lib
 
@@ -25,7 +27,6 @@ check_success $? "pre-open netmap:${pipe}{1"
 ./functional -i "netmap:${pipe}}1"
 check_success $? "pre-open netmap:${pipe}}1"
 
-# ${pipe}}1 ---> ${pipe}{1
 ./functional -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
 p1=$!
 ./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
@@ -36,8 +37,13 @@ check_success $e1 "receive-7 netmap:${pipe}{1"
 check_success $e2 "send-10 netmap:${pipe}}1"
 
 # At the moment get_tx_rings_max_sends and get_tx_rings_avail_sends do not
-# get the interface fd from fd_server, but they still read the correct values
-# from the rings. I don't know if that's something we can relay on.
+# get the interface fd from fd_server, they request it directly through an
+# nm_open(), but they still read the correct values stored inside each struct
+# netmap ring. This only happens if the multiple processes / threads synchronize
+# with each other when sharing the same netmap interface. This happens
+# implicitly for us because get_tx_rings_max_sends and get_tx_rings_avail_sends
+# are called after the first send-receive action, and the second one doesn't
+# happen until they terminate.
 exit_status=0
 ring_max_sends=$(./get_tx_rings_max_sends "netmap:${pipe}}1" "$len") 1>&3
 if [ $ring_max_sends = -1 ] ; then

From c62bbfaa8e83ae55ee4cf62c4f74972c192d9720 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 21:11:06 +0200
Subject: [PATCH 0971/2207] code reformatted

---
 utils/fd_server.c                |  6 ++----
 utils/functional.c               | 21 ++++++++++++---------
 utils/get_tx_rings_avail_sends.c |  5 ++---
 utils/get_tx_rings_max_sends.c   |  5 ++---
 4 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 262c4d073..63ef9b804 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -1,5 +1,7 @@
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -10,10 +12,6 @@
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
-#include 
 
 #include 
 #define NETMAP_WITH_LIBS
diff --git a/utils/functional.c b/utils/functional.c
index 1712149f4..44333f476 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -76,7 +76,9 @@ struct Global {
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
 	int success_if_no_receive;  /* exit status 0 if we receive no packets */
-	int sequential_fill;        /* increment fill char for multi-packets operations */
+	int
+	        sequential_fill; /* increment fill char for multi-packets
+	                            operations */
 	int request_from_fd_server;
 	int verbose;
 
@@ -442,8 +444,6 @@ tx(struct Global *g, unsigned packets_num)
 				g->filler = next_fill(g->filler);
 				build_packet(g);
 			}
-
-
 		}
 
 		if (packets_num == 0) {
@@ -741,7 +741,8 @@ usage(void)
 	printf("usage: ./functional [-h]\n"
 	       "    [-c (shuts down the fd server)]\n"
 	       "    [-o (starts the fd server)]\n"
-	       "    [-i NETMAP_PORT (requests the interface from the fd server)]\n"
+	       "    [-i NETMAP_PORT (requests the interface from the fd "
+	       "server)]\n"
 	       "    [-I NETMAP_PORT (directly opens the interface)]\n"
 	       "    [-s source MAC address (=0:0:0:0:0:0)]\n"
 	       "    [-d destination MAC address (=FF:FF:FF:FF:FF:FF)]\n"
@@ -756,7 +757,8 @@ usage(void)
 	       "    [-g (ignore ethernet frames with unmatching Ethernet "
 	       "header)]\n"
 	       "    [-n (exit status = 0 <==> no frames were received)]\n"
-	       "    [-q (during multi-packets send/receive increments fill character after each operation)]\n"
+	       "    [-q (during multi-packets send/receive increments fill "
+	       "character after each operation)]\n"
 	       "    [-v (increment verbosity level)]\n"
 	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	       "\nExample:\n"
@@ -1021,7 +1023,7 @@ int
 main(int argc, char **argv)
 {
 	struct nm_desc *nmd = NULL;
-	struct Global *g = &_g;
+	struct Global *g    = &_g;
 	unsigned int i, c;
 	int opt;
 	int ret;
@@ -1044,12 +1046,13 @@ main(int argc, char **argv)
 	g->ignore_if_not_matching = /*false=*/0;
 	g->success_if_no_receive  = /*false=*/0;
 	g->request_from_fd_server = /*true=*/1;
-	g->sequential_fill  = /*false=*/0;
+	g->sequential_fill        = /*false=*/0;
 	g->verbose                = 0;
 	g->num_loops              = 1;
 	memset(&g->nmd, 0, sizeof(struct nm_desc));
 
-	while ((opt = getopt(argc, argv, "hconqs:d:i:I:w:F:T:t:r:gvp:C:")) != -1) {
+	while ((opt = getopt(argc, argv, "hconqs:d:i:I:w:F:T:t:r:gvp:C:")) !=
+	       -1) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1092,7 +1095,7 @@ main(int argc, char **argv)
 			break;
 
 		case 'I':
-			g->ifname = optarg;
+			g->ifname                 = optarg;
 			g->request_from_fd_server = /*false=*/0;
 			break;
 
diff --git a/utils/get_tx_rings_avail_sends.c b/utils/get_tx_rings_avail_sends.c
index d4fc0efc6..618c15f2f 100644
--- a/utils/get_tx_rings_avail_sends.c
+++ b/utils/get_tx_rings_avail_sends.c
@@ -8,8 +8,8 @@
  */
 
 #include 
-#include 
 #include 
+#include 
 
 #include 
 #define NETMAP_WITH_LIBS
@@ -31,7 +31,6 @@ ring_avail_sends(struct netmap_ring *ring, unsigned pkt_len)
 	return nm_ring_space(ring) / slot_per_send(ring, pkt_len);
 }
 
-
 uint64_t
 adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
 {
@@ -70,7 +69,7 @@ main(int argc, char **argv)
 
 	fclose(stderr);
 	if_name = argv[1];
-	nmd = nm_open(if_name, NULL, 0, NULL);
+	nmd     = nm_open(if_name, NULL, 0, NULL);
 	if (nmd == NULL) {
 		printf("-1");
 		exit(EXIT_FAILURE);
diff --git a/utils/get_tx_rings_max_sends.c b/utils/get_tx_rings_max_sends.c
index 192faf583..865e4b0e7 100644
--- a/utils/get_tx_rings_max_sends.c
+++ b/utils/get_tx_rings_max_sends.c
@@ -7,8 +7,8 @@
  *    $2 -> packet length
  */
 #include 
-#include 
 #include 
+#include 
 
 #include 
 #define NETMAP_WITH_LIBS
@@ -30,7 +30,6 @@ ring_max_sends(struct netmap_ring *ring, unsigned pkt_len)
 	return (ring->num_slots - 1) / slot_per_send(ring, pkt_len);
 }
 
-
 uint64_t
 adapter_max_sends(struct nm_desc *nmd, unsigned pkt_len)
 {
@@ -69,7 +68,7 @@ main(int argc, char **argv)
 
 	fclose(stderr);
 	if_name = argv[1];
-	nmd = nm_open(if_name, NULL, 0, NULL);
+	nmd     = nm_open(if_name, NULL, 0, NULL);
 	if (nmd == NULL) {
 		printf("-1");
 		exit(EXIT_FAILURE);

From b91c216413128842df0745856503b229fcc9e233 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 23:30:47 +0200
Subject: [PATCH 0972/2207] new tests for ephimeral VALE ports and monitors,
 changed file names accordingly

---
 ...t_destroy => persistent_vale_port_destroy} |  4 +-
 ...ach => persistent_vale_port_double_attach} |  4 +-
 ...ate => persistent_vale_port_double_create} |  4 +-
 utils/randomized_tests                        | 28 ++++++----
 utils/rec_cp_mon_ephemeral_vale_port_test     | 49 ++++++++++++++++
 ...t => rec_cp_mon_persistent_vale_port_test} |  6 +-
 utils/rec_zcp_mon_ephemeral_vale_port_test    | 56 +++++++++++++++++++
 ... => rec_zcp_mon_persistent_vale_port_test} | 16 +++---
 utils/send_cp_mon_ephemeral_vale_port_test    | 47 ++++++++++++++++
 ... => send_cp_mon_persistent_vale_port_test} |  6 +-
 utils/send_zcp_mon_ephemeral_vale_port_test   | 50 +++++++++++++++++
 ...=> send_zcp_mon_persistent_vale_port_test} |  6 +-
 12 files changed, 243 insertions(+), 33 deletions(-)
 rename utils/{vale_port_destroy => persistent_vale_port_destroy} (87%)
 rename utils/{vale_port_double_attach => persistent_vale_port_double_attach} (83%)
 rename utils/{vale_port_double_create => persistent_vale_port_double_create} (83%)
 create mode 100755 utils/rec_cp_mon_ephemeral_vale_port_test
 rename utils/{rec_cp_mon_vale_port_test => rec_cp_mon_persistent_vale_port_test} (89%)
 create mode 100755 utils/rec_zcp_mon_ephemeral_vale_port_test
 rename utils/{rec_zcp_mon_vale_port_test => rec_zcp_mon_persistent_vale_port_test} (79%)
 create mode 100755 utils/send_cp_mon_ephemeral_vale_port_test
 rename utils/{send_cp_mon_vale_port_test => send_cp_mon_persistent_vale_port_test} (92%)
 create mode 100755 utils/send_zcp_mon_ephemeral_vale_port_test
 rename utils/{send_zcp_mon_vale_port_test => send_zcp_mon_persistent_vale_port_test} (88%)

diff --git a/utils/vale_port_destroy b/utils/persistent_vale_port_destroy
similarity index 87%
rename from utils/vale_port_destroy
rename to utils/persistent_vale_port_destroy
index bd42d8fef..abd8bf46c 100755
--- a/utils/vale_port_destroy
+++ b/utils/persistent_vale_port_destroy
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check that we can't create two VALE persistent ports with the
+# Test objective: check that we can't create two persistent VALE ports with the
 #                 same name.
 ################################################################################
 source test_lib
@@ -29,4 +29,4 @@ destroy_vale_persistent_port "$port" 1
 detach_from_vale_bridge "$bridgeA" "$port" 0
 destroy_vale_persistent_port "$port" 0
 
-test_successful "vale_port_destroy"
\ No newline at end of file
+test_successful "persistent_vale_port_destroy"
\ No newline at end of file
diff --git a/utils/vale_port_double_attach b/utils/persistent_vale_port_double_attach
similarity index 83%
rename from utils/vale_port_double_attach
rename to utils/persistent_vale_port_double_attach
index f6dbeb090..5f43749e6 100755
--- a/utils/vale_port_double_attach
+++ b/utils/persistent_vale_port_double_attach
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check that a VALE persistent port can't be attached 2 times
+# Test objective: check that a persistent VALE port can't be attached 2 times
 #                 to the same VALE bridge, but can be attached to 2 different
 #                 bridges.
 ################################################################################
@@ -18,4 +18,4 @@ attach_to_vale_bridge "$bridgeA" "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 
-test_successful "vale_port_double_attach"
\ No newline at end of file
+test_successful "persistent_vale_port_double_attach"
\ No newline at end of file
diff --git a/utils/vale_port_double_create b/utils/persistent_vale_port_double_create
similarity index 83%
rename from utils/vale_port_double_create
rename to utils/persistent_vale_port_double_create
index f680afe60..b04031173 100755
--- a/utils/vale_port_double_create
+++ b/utils/persistent_vale_port_double_create
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check that we can't create two VALE persistent ports with the
+# Test objective: check that we can't create two persistent VALE ports with the
 #                 same name.
 ################################################################################
 source test_lib
@@ -21,4 +21,4 @@ create_vale_persistent_port "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 create_vale_persistent_port "$port" 1
 
-test_successful "vale_port_double_create"
\ No newline at end of file
+test_successful "persistent_vale_port_double_create"
\ No newline at end of file
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 131f48079..17dededc0 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -29,12 +29,12 @@ echo "partial read pipe"
 # echo "send/receive veth"
 # ./send_rec_veth_test          -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
-echo "destroy VALE port"
-./vale_port_destroy
-echo "double create VALE port"
-./vale_port_double_create
-echo "double attach VALE port"
-./vale_port_double_attach
+echo "destroy persistent VALE port"
+./persistent_vale_port_destroy
+echo "double create persistent VALE port"
+./persistent_vale_port_double_create
+echo "double attach persistent VALE port"
+./persistent_vale_port_double_attach
 
 echo "exclusive open ephemeral VALE port"
 ./exclusive_open_ephemeral_vale_port_test
@@ -46,20 +46,28 @@ echo "exclusive open pipe"
 echo "receive copy monitor attached to pipe"
 ./rec_cp_mon_pipe_test        -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "receive copy monitor attached to persistent VALE port"
-./rec_cp_mon_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./rec_cp_mon_persistent_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "receive copy monitor attached to ephemeral VALE port"
+./rec_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to receiving pipe"
 ./rec_zcp_mon_pipe_test       -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to receiving persistent VALE port"
-./rec_zcp_mon_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./rec_zcp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "zero-copy monitor attached to receiving ephemeral VALE port"
+./rec_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
 echo "send copy monitor attached to pipe"
 ./send_cp_mon_pipe_test       -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "send copy monitor attached to persistent VALE port"
-./send_cp_mon_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./send_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send copy monitor attached to ephemeral VALE port"
+./send_cp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to sending pipe"
 ./send_zcp_mon_pipe_test      -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to sending persistent VALE port"
-./send_zcp_mon_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./send_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "zero-copy monitor attached to sending ephemeral VALE port"
+./send_zcp_mon_ephemeral_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
 echo "learning bridge algorithm"
 ./learning_bridge_test                              -l $random_len -f $random_fill
\ No newline at end of file
diff --git a/utils/rec_cp_mon_ephemeral_vale_port_test b/utils/rec_cp_mon_ephemeral_vale_port_test
new file mode 100755
index 000000000..003d2aed2
--- /dev/null
+++ b/utils/rec_cp_mon_ephemeral_vale_port_test
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a receive copy monitor receives frames when its
+#                 monitored ephemeral VALE port is receiving, even if the
+#                 monitored port hasn't yet read the frame.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) connect two ephemeral VALE ports (v0, v1) to the same VALE switch.
+# 2) open a receiving copy monitor vo/r for v0.
+# 3) send from v1 and don't read from v0, check that v0/r receives the frame.
+# 4) receive from v0.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i vale0:v0/r
+check_success $? "pre-open vale0:v0/r"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
+
+# First we send without reading from v0
+./functional -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "receive-${num} vale0:v0/r"
+check_success $e2 "send-${num} vale0:v1"
+
+# Then we read from v0
+./functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+e3=$?
+check_success $e3 "receive-${num} vale0:v0"
+
+test_successful "rec_cp_mon_ephemeral_vale_port_test"
\ No newline at end of file
diff --git a/utils/rec_cp_mon_vale_port_test b/utils/rec_cp_mon_persistent_vale_port_test
similarity index 89%
rename from utils/rec_cp_mon_vale_port_test
rename to utils/rec_cp_mon_persistent_vale_port_test
index 372e3c5c9..24e44ac18 100755
--- a/utils/rec_cp_mon_vale_port_test
+++ b/utils/rec_cp_mon_persistent_vale_port_test
@@ -1,8 +1,8 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a receive copy monitor receives frames when its
-#                 monitored VALE port is receiving, even if the monitored port
-#                 hasn't yet read the frame.
+#                 monitored persistent VALE port is receiving, even if the
+#                 monitored port hasn't yet read the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
@@ -49,4 +49,4 @@ check_success $e2 "send-${num} vale0:v1"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
-test_successful "rec_cp_mon_vale_port_test"
\ No newline at end of file
+test_successful "rec_cp_mon_persistent_vale_port_test"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_ephemeral_vale_port_test b/utils/rec_zcp_mon_ephemeral_vale_port_test
new file mode 100755
index 000000000..2805df2b8
--- /dev/null
+++ b/utils/rec_zcp_mon_ephemeral_vale_port_test
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a zero-copy monitor is correctly blocked until the
+#                 monitored ephemeral VALE port reads the frame.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) connect two ephemeral VALE ports (v0, v1) to the same VALE switch.
+# 2) open a zero-copy monitor v0/z for v0.
+# 3) send from v1 without receiving from v0, check that v0/z doesn't receive the
+#    rame.
+# 4) receive from v0, check that v0/z receives the frame.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "vale0:v0"
+check_success $? "pre-open vale0:v0"
+./functional -i "vale0:v0/z"
+check_success $? "pre-open vale0:v0/z"
+./functional -i "vale0:v1"
+check_success $? "pre-open vale0:v1"
+
+# Initially we don't receive with the monitored VALE port v0, therefore the
+# monitor should not receive the frame.
+./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+p1=$!
+./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "no-receive-${num} vale0:v0/z"
+check_success $e2 "send-${num} vale0:v0"
+
+# Now we receive with the monitored VALE port v0, therefore the monitor should
+# receive the frame.
+./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+p3=$!
+./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
+e4=$?
+wait $p3
+e3=$?
+check_success $e3 "receive-${num} vale0:v0"
+check_success $e4 "receive-${num} vale0:v0/z"
+
+test_successful "rec_zcp_mon_ephemeral_vale_port_test"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_vale_port_test b/utils/rec_zcp_mon_persistent_vale_port_test
similarity index 79%
rename from utils/rec_zcp_mon_vale_port_test
rename to utils/rec_zcp_mon_persistent_vale_port_test
index 38702dff6..1536b4b83 100755
--- a/utils/rec_zcp_mon_vale_port_test
+++ b/utils/rec_zcp_mon_persistent_vale_port_test
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a zero-copy monitor is correctly blocked until the
-#                 monitored VALE port reads the frame.
+#                 monitored persistent VALE port reads the frame.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
@@ -29,31 +29,31 @@ attach_to_vale_bridge "vale0" "v0"
 # condition between the sending and receiving ports.
 ./functional -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-./functional -i "vale0:v0/z"
-check_success $? "pre-open vale0:v0/z"
+./functional -i "netmap:v0/z"
+check_success $? "pre-open netmap:v0/z"
 ./functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+./functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
 ./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
-check_success $e1 "no-receive-${num} vale0:v0/z"
+check_success $e1 "no-receive-${num} netmap:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
 ./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
+./functional -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
-check_success $e4 "receive-${num} vale0:v0/z"
+check_success $e4 "receive-${num} netmap:v0/z"
 
-test_successful "rec_zcp_mon_vale_port_test"
\ No newline at end of file
+test_successful "rec_zcp_mon_persistent_vale_port_test"
\ No newline at end of file
diff --git a/utils/send_cp_mon_ephemeral_vale_port_test b/utils/send_cp_mon_ephemeral_vale_port_test
new file mode 100755
index 000000000..9592d01a3
--- /dev/null
+++ b/utils/send_cp_mon_ephemeral_vale_port_test
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a send copy monitor receives frames when its
+#                 monitored ephemeral VALE port is sending.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a persistent VALE port (v0).
+# 2) open a send copy monitor v0/t for v0.
+# 3) send from v0, check that both v0/t and v1 receive the frame.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i vale0:v0/t
+check_success $? "pre-open vale0:v0/t"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
+
+# First we send without reading from v1
+./functional -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "receive-${num} vale0:v0/t"
+check_success $e2 "send-${num} vale0:v0"
+
+# Then we read from v1
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+e3=$?
+check_success $e3 "receive-${num} vale0:v1"
+
+test_successful "send_cp_mon_ephemeral_vale_port_test"
\ No newline at end of file
diff --git a/utils/send_cp_mon_vale_port_test b/utils/send_cp_mon_persistent_vale_port_test
similarity index 92%
rename from utils/send_cp_mon_vale_port_test
rename to utils/send_cp_mon_persistent_vale_port_test
index 474c32dfe..890462e51 100755
--- a/utils/send_cp_mon_vale_port_test
+++ b/utils/send_cp_mon_persistent_vale_port_test
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 ################################################################################
-# Test objective: check if a send copy monitor receives frames when its monitored
-#                 VALE port is sending.
+# Test objective: check if a send copy monitor receives frames when its
+#                 monitored persistent VALE port is sending.
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
@@ -47,4 +47,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "send_cp_mon_vale_port_test"
\ No newline at end of file
+test_successful "send_cp_mon_persistent_vale_port_test"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_ephemeral_vale_port_test b/utils/send_zcp_mon_ephemeral_vale_port_test
new file mode 100755
index 000000000..829c62bac
--- /dev/null
+++ b/utils/send_zcp_mon_ephemeral_vale_port_test
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if a zero-copy monitor receives frames when its
+#                 monitored ephemeral VALE port is sending, even if the
+#                 destination port hasn't yet read the frame (this happens
+#                 because VALE switches do not use zero-copy).
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) connect two ephemeral VALE ports (v0, v1) to the same VALE switch.
+# 2) open a zero-copy monitor v0/z for v0.
+# 3) send from v0 and don't read from v1, check that v0/z receives the frame.
+# 4) receive from v1.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-d}"
+len="${len:-150}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i vale0:v0
+check_success $? "pre-open vale0:v0"
+./functional -i vale0:v0/z
+check_success $? "pre-open vale0:v0/z"
+./functional -i vale0:v1
+check_success $? "pre-open vale0:v1"
+
+# First we send without reading from v1
+./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "receive-${num} vale0:v0/z"
+check_success $e2 "send-${num} vale0:v0"
+
+# Then we read from v1
+./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+e3=$?
+check_success $e3 "receive-${num} vale0:v1"
+
+test_successful "send_zcp_mon_ephemeral_vale_port_test"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_vale_port_test b/utils/send_zcp_mon_persistent_vale_port_test
similarity index 88%
rename from utils/send_zcp_mon_vale_port_test
rename to utils/send_zcp_mon_persistent_vale_port_test
index 5066dade7..cb0bf008f 100755
--- a/utils/send_zcp_mon_vale_port_test
+++ b/utils/send_zcp_mon_persistent_vale_port_test
@@ -1,9 +1,9 @@
 #!/usr/bin/env bash
 ################################################################################
 # Test objective: check if a zero-copy monitor receives frames when its
-#                 monitored VALE port is sending, even if the destination port
-#                 hasn't yet read the frame (this happens because VALE switches
-#                 do not use zero-copy).
+#                 monitored persistent VALE port is sending, even if the
+#                 destination port hasn't yet read the frame (this happens
+#                 because VALE switches do not use zero-copy).
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).

From 0055a59416cbe1c0540c4935378e6611b1def1c3 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 23:38:18 +0200
Subject: [PATCH 0973/2207] fixed comments

---
 utils/send_rec_veth_test | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/utils/send_rec_veth_test b/utils/send_rec_veth_test
index 30be82acf..b39b70f4e 100755
--- a/utils/send_rec_veth_test
+++ b/utils/send_rec_veth_test
@@ -4,7 +4,7 @@
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of veth interfaces (veth1A, veth1B).
-# 2) send from veth1A and check if veth1B receives it.
+# 2) send from veth1A and check if veth1B receives.
 ################################################################################
 source test_lib
 
@@ -26,8 +26,7 @@ check_success $? "pre-open netmap:veth1A"
 ./functional -i netmap:veth1B
 check_success $? "pre-open netmap:veth1B"
 
-# During the first send we don't receive with the monitor, vale0:v1 should not
-# receive the frame.
+# veth1B --> veth1A
 ./functional -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
 ./functional -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
@@ -37,4 +36,14 @@ e1=$?
 check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
+# veth1A --> veth1B
+./functional -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
+p3=$!
+./functional -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
+e4=$?
+wait $p3
+e3=$?
+check_success $e3 "receive-${num} netmap:veth1B"
+check_success $e4 "send-${num} netmap:veth1A"
+
 test_successful "send_rec_veth_test"
\ No newline at end of file

From 9c0bf380a8835cbb13a7b25be3d2872e28874204 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Tue, 26 Jun 2018 23:48:10 +0200
Subject: [PATCH 0974/2207] added two new basic tests for ephemeral and
 persistent VALE ports

---
 utils/randomized_tests                       | 32 +++++----
 utils/send_rec_ephemeral_vale_ports_test     | 61 ++++++++++++++++++
 utils/send_rec_persistent_vale_ports_test    | 68 ++++++++++++++++++++
 utils/send_rec_pipe_test                     | 14 ++--
 utils/send_rec_veth_test                     |  3 +-
 utils/send_zcp_mon_persistent_vale_port_test |  2 +-
 6 files changed, 158 insertions(+), 22 deletions(-)
 create mode 100755 utils/send_rec_ephemeral_vale_ports_test
 create mode 100755 utils/send_rec_persistent_vale_ports_test

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 17dededc0..2bd84b4b6 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -22,12 +22,18 @@ echo "   sequence check   : ${seq_check}"
 echo "   packet length    : ${random_len}"
 echo ""
 
-echo "send/receive pipe"
-./send_rec_pipe_test          -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send/receive pipes"
+./send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send/receive ephemeral VALE ports"
+./send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send/receive persistent VALE ports"
+./send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+# echo "send/receive veth"
+# ./send_rec_veth_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+
+
 echo "partial read pipe"
 ./partial_read_pipe_test
-# echo "send/receive veth"
-# ./send_rec_veth_test          -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
 echo "destroy persistent VALE port"
 ./persistent_vale_port_destroy
@@ -44,30 +50,30 @@ echo "exclusive open pipe"
 ./exclusive_open_pipe_test
 
 echo "receive copy monitor attached to pipe"
-./rec_cp_mon_pipe_test        -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./rec_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "receive copy monitor attached to persistent VALE port"
-./rec_cp_mon_persistent_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./rec_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "receive copy monitor attached to ephemeral VALE port"
 ./rec_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to receiving pipe"
-./rec_zcp_mon_pipe_test       -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./rec_zcp_mon_pipe_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to receiving persistent VALE port"
-./rec_zcp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./rec_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to receiving ephemeral VALE port"
 ./rec_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
 echo "send copy monitor attached to pipe"
-./send_cp_mon_pipe_test       -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./send_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "send copy monitor attached to persistent VALE port"
 ./send_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "send copy monitor attached to ephemeral VALE port"
-./send_cp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./send_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to sending pipe"
-./send_zcp_mon_pipe_test      -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./send_zcp_mon_pipe_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to sending persistent VALE port"
 ./send_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "zero-copy monitor attached to sending ephemeral VALE port"
-./send_zcp_mon_ephemeral_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+./send_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
 echo "learning bridge algorithm"
-./learning_bridge_test                              -l $random_len -f $random_fill
\ No newline at end of file
+./learning_bridge_test -l $random_len -f $random_fill
\ No newline at end of file
diff --git a/utils/send_rec_ephemeral_vale_ports_test b/utils/send_rec_ephemeral_vale_ports_test
new file mode 100755
index 000000000..fda78d0bc
--- /dev/null
+++ b/utils/send_rec_ephemeral_vale_ports_test
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive packets through ephimeral
+#                 VALE ports.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) send from vale0:v0 and check if vale0:v1 receives.
+# 2) send from vale0:v1 and check if vale0:v0 receives.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-c}"
+len="${len:-274}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "vale0:v0"
+check_success $? "pre-open vale0:v0"
+./functional -i "vale0:v1"
+check_success $? "pre-open vale0:v1"
+./functional -i "vale0:v2"
+check_success $? "pre-open vale0:v2"
+
+# v2 ---> v0, v1
+./functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+p2=$!
+./functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+e3=$?
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+check_success $e1 "receive-${num} vale0:v0"
+check_success $e2 "receive-${num} vale0:v1"
+check_success $e3 "send-${num} vale0:v2"
+
+# v0 ---> v1, v2
+./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+p4=$!
+./functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+p5=$!
+./functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+e6=$?
+wait $p4
+e4=$?
+wait $p5
+e5=$?
+check_success $e4 "receive-${num} vale0:v1"
+check_success $e5 "receive-${num} vale0:v2"
+check_success $e6 "send-${num} vale0:v0"
+
+test_successful "send_rec_ephemeral_vale_ports_test"
\ No newline at end of file
diff --git a/utils/send_rec_persistent_vale_ports_test b/utils/send_rec_persistent_vale_ports_test
new file mode 100755
index 000000000..c68c0c5d4
--- /dev/null
+++ b/utils/send_rec_persistent_vale_ports_test
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send and receive packets through persistent
+#                 VALE ports.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create 3 persistent VALE ports (v0, v1, v2) and attach them to vale0.
+# 2) send from vale0:v0 and check if vale0:v1 receives.
+# 3) send from vale0:v1 and check if vale0:v0 receives.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-c}"
+len="${len:-274}"
+num="${num:-1}"
+seq="${seq:-}"
+
+restart_fd_server
+
+create_vale_persistent_port "v0"
+create_vale_persistent_port "v1"
+create_vale_persistent_port "v2"
+attach_to_vale_bridge "vale0" "v0"
+attach_to_vale_bridge "vale0" "v1"
+attach_to_vale_bridge "vale0" "v2"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "vale0:v0"
+check_success $? "pre-open vale0:v0"
+./functional -i "vale0:v1"
+check_success $? "pre-open vale0:v1"
+./functional -i "vale0:v2"
+check_success $? "pre-open vale0:v2"
+
+# v2 ---> v0, v1
+./functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+p2=$!
+./functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+e3=$?
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+check_success $e1 "receive-${num} vale0:v0"
+check_success $e2 "receive-${num} vale0:v1"
+check_success $e3 "send-${num} vale0:v2"
+
+# v0 ---> v1, v2
+./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+p4=$!
+./functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+p5=$!
+./functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+e6=$?
+wait $p4
+e4=$?
+wait $p5
+e5=$?
+check_success $e4 "receive-${num} vale0:v1"
+check_success $e5 "receive-${num} vale0:v2"
+check_success $e6 "send-${num} vale0:v0"
+
+test_successful "send_rec_ephemeral_vale_ports_test"
\ No newline at end of file
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index 9beffd02f..b1e310809 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -4,8 +4,8 @@
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
-# 2) send multiple packets from pipeA{1 and check if pipeA}1 receives them.
-# 2) send multiple packets from pipeA}1 and check if pipeA{1 receives them.
+# 2) send from pipeA{1 and check if pipeA}1 receives.
+# 3) send from pipeA}1 and check if pipeA{1 receives.
 ################################################################################
 source test_lib
 
@@ -38,12 +38,12 @@ check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
 ./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
-p1=$!
+p3=$!
 ./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
+e4=$?
+wait $p3
 e2=$?
-wait $p1
-e1=$?
-check_success $e1 "receive-${num} netmap:pipeA}1"
-check_success $e2 "send-${num} netmap:pipeA{1"
+check_success $e2 "receive-${num} netmap:pipeA}1"
+check_success $e4 "send-${num} netmap:pipeA{1"
 
 test_successful "send_rec_pipe_test"
\ No newline at end of file
diff --git a/utils/send_rec_veth_test b/utils/send_rec_veth_test
index b39b70f4e..c6d82eda0 100755
--- a/utils/send_rec_veth_test
+++ b/utils/send_rec_veth_test
@@ -4,7 +4,8 @@
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create a pair of veth interfaces (veth1A, veth1B).
-# 2) send from veth1A and check if veth1B receives.
+# 2) send from veth1B and check if veth1A receives.
+# 3) send from veth1A and check if veth1B receives.
 ################################################################################
 source test_lib
 
diff --git a/utils/send_zcp_mon_persistent_vale_port_test b/utils/send_zcp_mon_persistent_vale_port_test
index cb0bf008f..1ce23d23a 100755
--- a/utils/send_zcp_mon_persistent_vale_port_test
+++ b/utils/send_zcp_mon_persistent_vale_port_test
@@ -50,4 +50,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "send_zcp_mon_vale_port_test"
\ No newline at end of file
+test_successful "send_zcp_mon_persistent_vale_port_test"
\ No newline at end of file

From 2453bed753b35cad5ebecc23c9807166a9b74325 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 28 Jun 2018 16:34:13 +0200
Subject: [PATCH 0975/2207] Added extra buffers support (only during tx) to
 functional.c. Moved socket name to fd_server.h

---
 utils/fd_server.c  |   1 -
 utils/fd_server.h  |   2 +
 utils/functional.c | 292 ++++++++++++++++++++++++++++++++++++---------
 3 files changed, 239 insertions(+), 56 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 63ef9b804..8b9962b05 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -28,7 +28,6 @@ struct nmd_entry {
 
 #define printf(format, ...) syslog(LOG_NOTICE, format, ##__VA_ARGS__)
 
-#define SOCKET_NAME "/tmp/my_unix_socket"
 #define MAX_OPEN_IF 128
 struct nmd_entry entries[MAX_OPEN_IF];
 int num_entries = 0;
diff --git a/utils/fd_server.h b/utils/fd_server.h
index 120d4ba91..d4bb07329 100644
--- a/utils/fd_server.h
+++ b/utils/fd_server.h
@@ -1,6 +1,8 @@
 #ifndef FD_LIB_H
 #define FD_LIB_H
 
+#define SOCKET_NAME "/tmp/my_unix_socket"
+
 struct fd_request {
 #define FD_GET 1
 #define FD_RELEASE 2
diff --git a/utils/functional.c b/utils/functional.c
index 44333f476..b21e3b101 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -43,6 +43,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -69,19 +70,33 @@ struct Event {
 	unsigned long long usecs;
 };
 
+struct swapped_out_buf {
+	uint32_t buf_idx;
+	LIST_ENTRY(swapped_out_buf) list_entry;
+};
+
+;
+
 struct Global {
-	struct nm_desc nmd;
+	struct nm_desc *nmd;
 	const char *ifname;
 	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
 	int ignore_if_not_matching; /* ignore certain received packets */
 	int success_if_no_receive;  /* exit status 0 if we receive no packets */
-	int
-	        sequential_fill; /* increment fill char for multi-packets
+	int sequential_fill;        /* increment fill char for multi-packets
 	                            operations */
-	int request_from_fd_server;
+	int request_from_fd_server; /* false --> directly open the interface */
 	int verbose;
 
+	/* List of currently not in use normal buffers. */
+	LIST_HEAD(n_buf_head, swapped_out_buf) normal_buffers_head;
+	/* List of currently not in use extra buffers. */
+	LIST_HEAD(e_buf_head, swapped_out_buf) extra_buffers_head;
+	/* Points to an array containing all extra buffer indexes */
+	uint32_t *extra_buffers_indexes;
+	unsigned extra_buffers_num; /* number of granted extra buffers */
+
 #define MAX_PKT_SIZE 65536
 	char pktm[MAX_PKT_SIZE]; /* packet model */
 	unsigned pktm_len;       /* packet model length */
@@ -104,13 +119,20 @@ struct Global {
 };
 
 void release_if_fd(struct Global *, const char *);
+void release_extra_buffers(struct Global *);
 
 void
-clean_exit(struct Global *g)
+cleanup(struct Global *g)
 {
+	if (g->extra_buffers_num > 0) {
+		release_extra_buffers(g);
+	}
 
-	release_if_fd(g, g->ifname);
-	exit(EXIT_FAILURE);
+	if (g->request_from_fd_server) {
+		release_if_fd(g, g->ifname);
+	} else {
+		nm_close(g->nmd);
+	}
 }
 
 static void
@@ -120,7 +142,8 @@ fill_packet_field(struct Global *g, unsigned offset, const char *content,
 	if (offset + content_len > sizeof(g->pktm)) {
 		printf("Packet layout overflow: %u + %u > %lu\n", offset,
 		       content_len, sizeof(g->pktm));
-		clean_exit(g);
+		cleanup(g);
+		exit(EXIT_FAILURE);
 	}
 
 	memcpy(g->pktm + offset, content, content_len);
@@ -301,7 +324,7 @@ build_packet(struct Global *g)
 static int
 tx_flush(struct Global *g)
 {
-	struct nm_desc *nmd = &g->nmd;
+	struct nm_desc *nmd = g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	int i;
@@ -406,7 +429,7 @@ next_fill(char cur_fill)
 static int
 tx(struct Global *g, unsigned packets_num)
 {
-	struct nm_desc *nmd = &g->nmd;
+	struct nm_desc *nmd = g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	unsigned int i;
@@ -531,7 +554,8 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 			       "large "
 			       "(>= %u bytes) ",
 			       g->pktr_len + slot->len);
-			clean_exit(g);
+			cleanup(g);
+			exit(EXIT_FAILURE);
 		}
 
 		memcpy(g->pktr + g->pktr_len, buf, slot->len);
@@ -562,7 +586,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 static int
 rx(struct Global *g, unsigned packets_num)
 {
-	struct nm_desc *nmd = &g->nmd;
+	struct nm_desc *nmd = g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	unsigned int i;
@@ -624,7 +648,8 @@ rx(struct Global *g, unsigned packets_num)
 			 * packet model we exit with status EXIT_FAILURE.
 			 */
 			if (rx_check(g)) {
-				clean_exit(g);
+				cleanup(g);
+				exit(EXIT_FAILURE);
 			}
 
 			if (g->sequential_fill == 1) {
@@ -759,6 +784,8 @@ usage(void)
 	       "    [-n (exit status = 0 <==> no frames were received)]\n"
 	       "    [-q (during multi-packets send/receive increments fill "
 	       "character after each operation)]\n"
+	       "    [-e (use extra buffers to send packets, "
+	       "can only be used when directly opening an interface)]\n"
 	       "    [-v (increment verbosity level)]\n"
 	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	       "\nExample:\n"
@@ -802,8 +829,6 @@ fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
 	}
 }
 
-#define SOCKET_NAME "/tmp/my_unix_socket"
-
 int
 connect_to_fd_server(struct Global *g)
 {
@@ -818,7 +843,7 @@ connect_to_fd_server(struct Global *g)
 		return -1;
 	}
 
-	memset(&name, 0, sizeof(struct sockaddr_un));
+	memset(&name, 0, sizeof(name));
 	name.sun_family = AF_UNIX;
 	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
 	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
@@ -881,7 +906,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	errno           = 0;
 	iov[0].iov_base = buf;
 	iov[0].iov_len  = buf_size;
-	memset(&msg, 0, sizeof(struct msghdr));
+	memset(&msg, 0, sizeof(msg));
 	msg.msg_iov    = iov;
 	msg.msg_iovlen = 1;
 	memset(ancillary.buf, 0, sizeof(ancillary.buf));
@@ -911,11 +936,12 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	return amount;
 }
 
-int
-get_if_fd(struct Global *g, const char *if_name, struct nm_desc *nmd)
+struct nm_desc *
+get_if_fd(struct Global *g, const char *if_name)
 {
 	struct fd_response res;
 	struct fd_request req;
+	struct nm_desc *nmd;
 	int socket_fd;
 	int new_fd;
 	int ret;
@@ -928,27 +954,33 @@ get_if_fd(struct Global *g, const char *if_name, struct nm_desc *nmd)
 	memset(&req, 0, sizeof(req));
 	req.action = FD_GET;
 	strncpy(req.if_name, if_name, sizeof(req.if_name));
-	ret = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret < 0) {
 		perror("send()");
-		return -1;
+		return NULL;
 	}
 
 	memset(&res, 0, sizeof(res));
-	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(struct fd_response));
+	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(res));
 	if (ret == -1) {
 		perror("recv_fd()");
-		return -1;
+		return NULL;
+	}
+	close(socket_fd);
+
+	nmd = malloc(sizeof(*nmd));
+	if (nmd == NULL) {
+		perror("malloc()");
+		return NULL;
 	}
 
 	fill_nm_desc(nmd, &res.req, new_fd);
 	if (nm_mmap(nmd, NULL) != 0) {
 		perror("nm_mmap()");
-		return -1;
+		return NULL;
 	}
 
-	close(socket_fd);
-	return 0;
+	return nmd;
 }
 
 void
@@ -967,7 +999,7 @@ release_if_fd(struct Global *g, const char *if_name)
 	req.action = FD_RELEASE;
 	strncpy(req.if_name, if_name, sizeof(req.if_name));
 
-	ret = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret <= 0) {
 		perror("send()");
 	}
@@ -994,7 +1026,7 @@ stop_fd_server(struct Global *g)
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_STOP;
-	ret        = send(socket_fd, &req, sizeof(struct fd_request), 0);
+	ret        = send(socket_fd, &req, sizeof(req), 0);
 	if (ret == -1) {
 		perror("send()");
 	}
@@ -1005,7 +1037,7 @@ stop_fd_server(struct Global *g)
 	 * condition. Otherwise the call to functional might connect to the
 	 * previous fd_server backlog.
 	 */
-	recv(socket_fd, &req, sizeof(struct fd_request), 0);
+	recv(socket_fd, &req, sizeof(req), 0);
 	close(socket_fd);
 }
 
@@ -1019,15 +1051,133 @@ parse_mac_address(const char *opt, char *mac)
 	return -1;
 }
 
+/* Uses the first adapter slot (any will do) to save the extra buffers indexes.
+ */
+int
+parse_extra_buffers_indexes(struct Global *g)
+{
+	struct netmap_if *nifp   = g->nmd->nifp;
+	struct netmap_ring *ring = NETMAP_TXRING(nifp, g->nmd->first_tx_ring);
+	struct netmap_slot *slot = &ring->slot[ring->head];
+	uint32_t e_buf_index     = nifp->ni_bufs_head;
+	uint32_t real_index      = slot->buf_idx;
+	struct swapped_out_buf *u_buf;
+	unsigned i;
+
+	for (i = 0; i < g->extra_buffers_num; i++) {
+		if (e_buf_index == 0) {
+			printf("Extra buffer index = 0\n");
+			return -1;
+		}
+
+		u_buf = malloc(sizeof(*u_buf));
+		if (u_buf == NULL) {
+			perror("malloc()");
+			return -1;
+		}
+		u_buf->buf_idx = e_buf_index;
+		LIST_INSERT_HEAD(&g->extra_buffers_head, u_buf, list_entry);
+		g->extra_buffers_indexes[i] = e_buf_index;
+		slot->buf_idx               = e_buf_index;
+		e_buf_index = *(uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+	}
+	slot->buf_idx = real_index;
+
+	return 0;
+}
+
+/* Loops through the adapter slots, swapping the default buffers with the
+ * extra buffers. Keeps going until we run out of extra buffers, or adapter
+ * slots.
+ */
+int
+swap_in_extra_buffers(struct Global *g)
+{
+	unsigned int i;
+
+	for (i = g->nmd->first_tx_ring; i <= g->nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(g->nmd->nifp, i);
+		unsigned head;
+
+		for (head = ring->head; head != ring->tail;
+		     head = nm_ring_next(ring, head)) {
+			struct swapped_out_buf *u_buf =
+			        LIST_FIRST(&g->extra_buffers_head);
+			struct netmap_slot *slot = &ring->slot[head];
+			uint32_t real_index      = slot->buf_idx;
+
+			if (u_buf == NULL) {
+				/* We finished swapping in extra buffers */
+				return 0;
+			}
+
+			slot->buf_idx = u_buf->buf_idx;
+			slot->flags |= NS_BUF_CHANGED;
+			u_buf->buf_idx = real_index;
+			LIST_REMOVE(u_buf, list_entry);
+			LIST_INSERT_HEAD(&g->normal_buffers_head, u_buf,
+			                 list_entry);
+		}
+	}
+
+	if (!LIST_EMPTY(&g->extra_buffers_head)) {
+		/* This happens if the number of slots in our adapter is less
+		 * than the number of extra buffers requested, thus should not
+		 * be regarded as an error (?)
+		 */
+		return 0;
+	}
+
+	return 0;
+}
+
+/* We only re-build the extra buffers list, as requested from netmap. We don't
+ * undo the swapping that we did at the start of the program to swap in the
+ * extra buffer. This probably leaves the netmap adapter in an incosistent
+ * state, that's why we only support this option for interfaces requested
+ * directly.
+ */
+void
+release_extra_buffers(struct Global *g)
+{
+	struct netmap_if *nifp   = g->nmd->nifp;
+	struct netmap_ring *ring = NETMAP_TXRING(nifp, g->nmd->first_tx_ring);
+	struct netmap_slot *slot = &ring->slot[ring->head];
+	uint32_t real_index      = slot->buf_idx;
+	unsigned i;
+
+	nifp->ni_bufs_head = g->extra_buffers_indexes[0];
+	for (i = 0; i < g->extra_buffers_num; i++) {
+		uint32_t *extra_buffer;
+
+		slot->buf_idx = g->extra_buffers_indexes[i];
+		extra_buffer  = (uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+		if (i == g->extra_buffers_num - 1) {
+			*extra_buffer = 0;
+		} else {
+			*extra_buffer = g->extra_buffers_indexes[i + 1];
+		}
+	}
+	slot->buf_idx = real_index;
+
+	while (!LIST_EMPTY(&g->extra_buffers_head)) {
+		struct swapped_out_buf *u_buf =
+		        LIST_FIRST(&g->extra_buffers_head);
+
+		LIST_REMOVE(u_buf, list_entry);
+		free(u_buf);
+	}
+}
+
 int
 main(int argc, char **argv)
 {
-	struct nm_desc *nmd = NULL;
-	struct Global *g    = &_g;
+	struct Global *g = &_g;
 	unsigned int i, c;
 	int opt;
 	int ret;
 
+	g->nmd            = NULL;
 	g->ifname         = NULL;
 	g->wait_link_secs = 0;
 	g->timeout_secs   = 1;
@@ -1047,11 +1197,14 @@ main(int argc, char **argv)
 	g->success_if_no_receive  = /*false=*/0;
 	g->request_from_fd_server = /*true=*/1;
 	g->sequential_fill        = /*false=*/0;
+	g->extra_buffers_num      = 0;
 	g->verbose                = 0;
 	g->num_loops              = 1;
-	memset(&g->nmd, 0, sizeof(struct nm_desc));
+	g->extra_buffers_num      = 0;
+	LIST_INIT(&g->normal_buffers_head);
+	LIST_INIT(&g->extra_buffers_head);
 
-	while ((opt = getopt(argc, argv, "hconqs:d:i:I:w:F:T:t:r:gvp:C:")) !=
+	while ((opt = getopt(argc, argv, "hconqe:s:d:i:I:w:F:T:t:r:gvp:C:")) !=
 	       -1) {
 		switch (opt) {
 		case 'h':
@@ -1074,6 +1227,15 @@ main(int argc, char **argv)
 			g->sequential_fill = /*true=*/1;
 			break;
 
+		case 'e':
+			printf("sdsdas\n");
+			g->extra_buffers_num = atoi(optarg);
+			if (g->extra_buffers_num <= 0) {
+				printf("Invalid number of extra buffers\n");
+				exit(EXIT_FAILURE);
+			};
+			break;
+
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
 			if (ret == -1) {
@@ -1157,7 +1319,7 @@ main(int argc, char **argv)
 			break;
 
 		default:
-			printf("    Unrecognized option %c\n", opt);
+			printf("Unrecognized option %c\n", opt);
 			usage();
 			exit(EXIT_FAILURE);
 		}
@@ -1169,23 +1331,52 @@ main(int argc, char **argv)
 		exit(EXIT_FAILURE);
 	}
 
-	ret = 0;
+	if (g->request_from_fd_server == 1 && g->extra_buffers_num > 0) {
+		printf("Extra buffers can only be used when requesting an "
+		       "interface directly\n");
+		exit(EXIT_FAILURE);
+	}
+
 	if (g->request_from_fd_server == 0) {
 		/* We directly open the file descriptor. */
-		nmd = nm_open(g->ifname, NULL, 0, NULL);
-		if (nmd == NULL) {
-			ret = -1;
+		if (g->extra_buffers_num > 0) {
+			struct nmreq req;
+
+			memset(&req, 0, sizeof(req));
+			req.nr_arg3 = g->extra_buffers_num;
+			g->nmd      = nm_open(g->ifname, &req, 0, NULL);
 		} else {
-			memcpy(&g->nmd, nmd, sizeof(struct nm_desc));
+			g->nmd = nm_open(g->ifname, NULL, 0, NULL);
 		}
 	} else {
-		ret = get_if_fd(g, g->ifname, &g->nmd);
+		g->nmd = get_if_fd(g, g->ifname);
 	}
-	if (ret == -1) {
+	if (g->nmd == NULL) {
+		;
 		printf("Failed to nm_open(%s)\n", g->ifname);
 		exit(EXIT_FAILURE);
 	}
 
+	if (g->extra_buffers_num > 0) {
+		g->extra_buffers_num = g->nmd->req.nr_arg3; /* Stores the real
+		                                               number of extra
+		                                               buffers. */
+		g->extra_buffers_indexes =
+		        malloc(g->extra_buffers_num * sizeof(uint32_t));
+		if (g->extra_buffers_indexes == NULL) {
+			perror("malloc()");
+			exit(EXIT_FAILURE);
+		}
+
+		ret = parse_extra_buffers_indexes(g);
+		if (ret == -1) {
+			cleanup(g);
+			exit(EXIT_FAILURE);
+		}
+
+		swap_in_extra_buffers(g);
+	}
+
 	if (g->wait_link_secs > 0) {
 		sleep(g->wait_link_secs);
 	}
@@ -1204,13 +1395,15 @@ main(int argc, char **argv)
 			switch (e->evtype) {
 			case EVENT_TYPE_TX:
 				if (tx(g, e->num)) {
-					clean_exit(g);
+					cleanup(g);
+					exit(EXIT_FAILURE);
 				}
 				break;
 
 			case EVENT_TYPE_RX:
 				if (rx(g, e->num)) {
-					clean_exit(g);
+					cleanup(g);
+					exit(EXIT_FAILURE);
 				}
 				break;
 
@@ -1223,17 +1416,6 @@ main(int argc, char **argv)
 
 	/* if we have sent something, wait for all tx to complete */
 	tx_flush(g);
-
-	if (g->request_from_fd_server == 0) {
-		ret = nm_close(nmd);
-	} else {
-		release_if_fd(g, g->ifname);
-		ret = 0;
-	}
-
-	if (ret == -1) {
-		printf("Failed to nm_close(%s)\n", g->ifname);
-	}
-
+	cleanup(g);
 	return 0;
 }

From 0c10ec92f015d5328556cb1b9d953a11b78555df Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 28 Jun 2018 16:36:41 +0200
Subject: [PATCH 0976/2207] extra buffers tests

---
 ...tra_buf_send_rec_ephemeral_vale_ports_test | 46 ++++++++++++++++
 ...ra_buf_send_rec_persistent_vale_ports_test | 53 +++++++++++++++++++
 utils/extra_buf_send_rec_pipe_test            | 39 ++++++++++++++
 utils/partial_read_pipe_test                  |  2 +-
 utils/randomized_tests                        | 36 +++++++------
 utils/send_rec_ephemeral_vale_ports_test      |  4 +-
 utils/send_rec_persistent_vale_ports_test     |  6 +--
 7 files changed, 165 insertions(+), 21 deletions(-)
 create mode 100755 utils/extra_buf_send_rec_ephemeral_vale_ports_test
 create mode 100755 utils/extra_buf_send_rec_persistent_vale_ports_test
 create mode 100755 utils/extra_buf_send_rec_pipe_test

diff --git a/utils/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/extra_buf_send_rec_ephemeral_vale_ports_test
new file mode 100755
index 000000000..bc8f8b0da
--- /dev/null
+++ b/utils/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send packets through ephimeral VALE ports
+#                 while using extra buffers.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) send from vale0:v0 using extra buffers, and check that both, vale0:v1 and
+#    vale0:v2, receive.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-c}"
+len="${len:-274}"
+num="${num:-1}"
+seq="${seq:-}"
+
+e_buf_num="${e_buf_num:-12}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "vale0:v1"
+check_success $? "pre-open vale0:v1"
+./functional -i "vale0:v2"
+check_success $? "pre-open vale0:v2"
+
+# v0 ---> v1, v2
+./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+p2=$!
+./functional -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+e3=$?
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+check_success $e1 "receive-${num} vale0:v1"
+check_success $e2 "receive-${num} vale0:v2"
+check_success $e3 "send-${num} vale0:v0"
+
+test_successful "extra_buf_send_rec_ephemeral_vale_ports_test"
\ No newline at end of file
diff --git a/utils/extra_buf_send_rec_persistent_vale_ports_test b/utils/extra_buf_send_rec_persistent_vale_ports_test
new file mode 100755
index 000000000..b4237068d
--- /dev/null
+++ b/utils/extra_buf_send_rec_persistent_vale_ports_test
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send packets through persistent VALE ports
+#                 while using extra buffers.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create 3 persistent VALE ports (v0, v1, v2) and attach them to vale0.
+# 2) send from vale0:v2 using extra buffers, and check that both, vale0:v0 and
+#    vale0:v1, receive.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-c}"
+len="${len:-274}"
+num="${num:-1}"
+seq="${seq:-}"
+
+e_buf_num="${e_buf_num:-12}"
+
+restart_fd_server
+
+create_vale_persistent_port "v0"
+create_vale_persistent_port "v1"
+create_vale_persistent_port "v2"
+attach_to_vale_bridge "vale0" "v0"
+attach_to_vale_bridge "vale0" "v1"
+attach_to_vale_bridge "vale0" "v2"
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "vale0:v0"
+check_success $? "pre-open vale0:v0"
+./functional -i "vale0:v1"
+check_success $? "pre-open vale0:v1"
+
+# v2 ---> v0, v1
+./functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+p2=$!
+./functional -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+e3=$?
+wait $p1
+e1=$?
+wait $p2
+e2=$?
+check_success $e1 "receive-${num} vale0:v0"
+check_success $e2 "receive-${num} vale0:v1"
+check_success $e3 "send-${num} vale0:v2"
+
+test_successful "extra_buf_send_rec_persistent_vale_ports_test"
\ No newline at end of file
diff --git a/utils/extra_buf_send_rec_pipe_test b/utils/extra_buf_send_rec_pipe_test
new file mode 100755
index 000000000..04eb17bee
--- /dev/null
+++ b/utils/extra_buf_send_rec_pipe_test
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+################################################################################
+# Test objective: check if we can send packets through netmap pipes while using
+#                 extra buffers.
+# Operations:
+# 0) restart fd_server to have a clean starting state
+# 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
+# 2) send from pipeA{1 using extra buffers and check if pipeA}1 receives.
+################################################################################
+source test_lib
+
+redirect_std
+
+parse_send_recv_arguments "$@"
+fill="${fill:-c}"
+len="${len:-274}"
+num="${num:-1}"
+seq="${seq:-}"
+
+e_buf_num="${e_buf_num:-12}"
+
+restart_fd_server
+
+# Pre-opening interface that will be needed. This is needed to avoid a race
+# condition between the sending and receiving ports.
+./functional -i "netmap:pipeA{1"
+check_success $? "pre-open netmap:pipeA{1"
+
+# pipeA}1 ---> pipeA{1
+./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+p1=$!
+./functional -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+e2=$?
+wait $p1
+e1=$?
+check_success $e1 "receive-${num} netmap:pipeA{1"
+check_success $e2 "send-${num} netmap:pipeA}1"
+
+test_successful "send_rec_pipe_test"
\ No newline at end of file
diff --git a/utils/partial_read_pipe_test b/utils/partial_read_pipe_test
index 0821b6a51..8192ed4a1 100755
--- a/utils/partial_read_pipe_test
+++ b/utils/partial_read_pipe_test
@@ -45,7 +45,7 @@ check_success $e2 "send-10 netmap:${pipe}}1"
 # are called after the first send-receive action, and the second one doesn't
 # happen until they terminate.
 exit_status=0
-ring_max_sends=$(./get_tx_rings_max_sends "netmap:${pipe}}1" "$len") 1>&3
+ring_max_sends=$(./get_tx_rings_max_sends "netmap:${pipe}}1" "$len")
 if [ $ring_max_sends = -1 ] ; then
 	exit_status=1
 fi
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 2bd84b4b6..3faaf0dd6 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -22,19 +22,6 @@ echo "   sequence check   : ${seq_check}"
 echo "   packet length    : ${random_len}"
 echo ""
 
-echo "send/receive pipes"
-./send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "send/receive ephemeral VALE ports"
-./send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "send/receive persistent VALE ports"
-./send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-# echo "send/receive veth"
-# ./send_rec_veth_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-
-
-echo "partial read pipe"
-./partial_read_pipe_test
-
 echo "destroy persistent VALE port"
 ./persistent_vale_port_destroy
 echo "double create persistent VALE port"
@@ -49,6 +36,20 @@ echo "exclusive open persistent VALE port"
 echo "exclusive open pipe"
 ./exclusive_open_pipe_test
 
+echo "learning bridge algorithm"
+./learning_bridge_test -l $random_len -f $random_fill
+
+echo "send/receive pipes"
+./send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send/receive ephemeral VALE ports"
+./send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "send/receive persistent VALE ports"
+./send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+# echo "send/receive veth"
+# ./send_rec_veth_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "partial read pipe"
+./partial_read_pipe_test              -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+
 echo "receive copy monitor attached to pipe"
 ./rec_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 echo "receive copy monitor attached to persistent VALE port"
@@ -75,5 +76,10 @@ echo "zero-copy monitor attached to sending persistent VALE port"
 echo "zero-copy monitor attached to sending ephemeral VALE port"
 ./send_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
-echo "learning bridge algorithm"
-./learning_bridge_test -l $random_len -f $random_fill
\ No newline at end of file
+
+echo "extra buffer send/receive pipes"
+./extra_buf_send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "extra buffer send/receive ephemeral VALE ports"
+./extra_buf_send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+echo "extra buffer send/receive persistent VALE ports"
+./extra_buf_send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
\ No newline at end of file
diff --git a/utils/send_rec_ephemeral_vale_ports_test b/utils/send_rec_ephemeral_vale_ports_test
index fda78d0bc..b59e2fd9c 100755
--- a/utils/send_rec_ephemeral_vale_ports_test
+++ b/utils/send_rec_ephemeral_vale_ports_test
@@ -4,8 +4,8 @@
 #                 VALE ports.
 # Operations:
 # 0) restart fd_server to have a clean starting state
-# 1) send from vale0:v0 and check if vale0:v1 receives.
-# 2) send from vale0:v1 and check if vale0:v0 receives.
+# 1) send from vale0:v2 and check that both, vale0:v0 and vale0:v1, receive.
+# 2) send from vale0:v0 and check that both, vale0:v1 and vale0:v2, receive.
 ################################################################################
 source test_lib
 
diff --git a/utils/send_rec_persistent_vale_ports_test b/utils/send_rec_persistent_vale_ports_test
index c68c0c5d4..bf789c3de 100755
--- a/utils/send_rec_persistent_vale_ports_test
+++ b/utils/send_rec_persistent_vale_ports_test
@@ -5,8 +5,8 @@
 # Operations:
 # 0) restart fd_server to have a clean starting state
 # 1) create 3 persistent VALE ports (v0, v1, v2) and attach them to vale0.
-# 2) send from vale0:v0 and check if vale0:v1 receives.
-# 3) send from vale0:v1 and check if vale0:v0 receives.
+# 2) send from vale0:v2 and check that both, vale0:v0 and vale0:v1, receive.
+# 3) send from vale0:v0 and check that both, vale0:v1 and vale0:v2, receive.
 ################################################################################
 source test_lib
 
@@ -65,4 +65,4 @@ check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
 
-test_successful "send_rec_ephemeral_vale_ports_test"
\ No newline at end of file
+test_successful "send_rec_persistent_vale_ports_test"
\ No newline at end of file

From e89d9979d9a5f96f060a1063fe4b94754c3b1a8e Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 29 Jun 2018 13:38:24 +0200
Subject: [PATCH 0977/2207] Disabled clang-format includes reordering (causes
 compile errors on FreeBSD). functional.c uses struct ip instead of struct
 iphdr (Linux specific).

---
 .clang-format      | 1 +
 utils/GNUmakefile  | 4 ++--
 utils/functional.c | 6 +++---
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/.clang-format b/.clang-format
index b9155064a..95a24534b 100644
--- a/.clang-format
+++ b/.clang-format
@@ -8,4 +8,5 @@ ConstructorInitializerIndentWidth: 8
 ContinuationIndentWidth: 8
 IndentCaseLabels: false
 IndentWidth: 8
+SortIncludes: false
 UseTab: ForIndentation
\ No newline at end of file
diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 9a7756a4e..c92c042e1 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -22,9 +22,9 @@ else
 CFLAGS += -DNO_PCAP
 endif
 
-LDLIBS += -lpthread
+LDLIBS += -lpthread -lm
 ifeq ($(shell uname),Linux)
-	LDLIBS += -lrt -lm	# on linux
+	LDLIBS += -lrt 	# on linux
 endif
 #SRCS = pkt-gen.c
 
diff --git a/utils/functional.c b/utils/functional.c
index b21e3b101..0d6e4631e 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -25,6 +25,7 @@
  * SUCH DAMAGE.
  */
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -46,7 +47,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -234,7 +234,7 @@ build_packet(struct Global *g)
 	ipofs = ofs;
 	/* First byte of IP header. */
 	fill_packet_8bit(g, ofs,
-	                 (IPVERSION << 4) | ((sizeof(struct iphdr)) >> 2));
+	                 (IPVERSION << 4) | ((sizeof(struct ip)) >> 2));
 	ofs += 1;
 	/* Skip QoS byte. */
 	ofs += 1;
@@ -263,7 +263,7 @@ build_packet(struct Global *g)
 	/* Now put the checksum. */
 	fill_packet_16bit(
 	        g, ipofs + 10,
-	        wrapsum(checksum(g->pktm + ipofs, sizeof(struct iphdr), 0)));
+	        wrapsum(checksum(g->pktm + ipofs, sizeof(struct ip), 0)));
 	if (g->verbose) {
 		printf("%s: ip done, ofs %u\n", __func__, ofs);
 	}

From 816d4764d10fc9b19dfa89307d48906975603ab7 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 29 Jun 2018 16:50:58 +0200
Subject: [PATCH 0978/2207] Changed ./randomized_tests output style

---
 utils/exclusive_open_ephemeral_vale_port_test |  2 +-
 .../exclusive_open_persistent_vale_port_test  |  2 +-
 utils/exclusive_open_pipe_test                |  2 +-
 ...tra_buf_send_rec_ephemeral_vale_ports_test |  2 +-
 ...ra_buf_send_rec_persistent_vale_ports_test |  2 +-
 utils/extra_buf_send_rec_pipe_test            |  2 +-
 utils/learning_bridge_test                    |  2 +-
 utils/partial_read_pipe_test                  |  2 +-
 utils/persistent_vale_port_destroy            |  2 +-
 utils/persistent_vale_port_double_attach      |  2 +-
 utils/persistent_vale_port_double_create      |  2 +-
 utils/randomized_tests                        | 27 -------------------
 utils/rec_cp_mon_ephemeral_vale_port_test     |  2 +-
 utils/rec_cp_mon_persistent_vale_port_test    |  2 +-
 utils/rec_cp_mon_pipe_test                    |  2 +-
 utils/rec_zcp_mon_ephemeral_vale_port_test    |  2 +-
 utils/rec_zcp_mon_persistent_vale_port_test   |  2 +-
 utils/rec_zcp_mon_pipe_test                   |  2 +-
 utils/send_cp_mon_ephemeral_vale_port_test    |  2 +-
 utils/send_cp_mon_persistent_vale_port_test   |  2 +-
 utils/send_cp_mon_pipe_test                   |  2 +-
 utils/send_rec_ephemeral_vale_ports_test      |  2 +-
 utils/send_rec_persistent_vale_ports_test     |  2 +-
 utils/send_rec_pipe_test                      |  2 +-
 utils/send_rec_veth_test                      |  2 +-
 utils/send_zcp_mon_ephemeral_vale_port_test   |  2 +-
 utils/send_zcp_mon_persistent_vale_port_test  |  2 +-
 utils/send_zcp_mon_pipe_test                  |  2 +-
 utils/test_lib                                |  8 +++---
 29 files changed, 32 insertions(+), 57 deletions(-)

diff --git a/utils/exclusive_open_ephemeral_vale_port_test b/utils/exclusive_open_ephemeral_vale_port_test
index 50b829765..7bd2dd102 100755
--- a/utils/exclusive_open_ephemeral_vale_port_test
+++ b/utils/exclusive_open_ephemeral_vale_port_test
@@ -24,4 +24,4 @@ check_failure $? "no-open ${bridge}:${port}"
 ./functional -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
-test_successful "exclusive_open_ephemeral_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/exclusive_open_persistent_vale_port_test b/utils/exclusive_open_persistent_vale_port_test
index 35ba6d2a3..94fae2159 100755
--- a/utils/exclusive_open_persistent_vale_port_test
+++ b/utils/exclusive_open_persistent_vale_port_test
@@ -27,4 +27,4 @@ check_failure $? "no-open ${bridge}:${port}"
 ./functional -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
-test_successful "exclusive_open_persistent_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/exclusive_open_pipe_test b/utils/exclusive_open_pipe_test
index 20f15b2b8..881b44ae1 100755
--- a/utils/exclusive_open_pipe_test
+++ b/utils/exclusive_open_pipe_test
@@ -23,4 +23,4 @@ check_failure $? "no-open netmap:${pipe}"
 ./functional -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
 
-test_successful "exclusive_open_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/extra_buf_send_rec_ephemeral_vale_ports_test
index bc8f8b0da..41677f035 100755
--- a/utils/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -43,4 +43,4 @@ check_success $e1 "receive-${num} vale0:v1"
 check_success $e2 "receive-${num} vale0:v2"
 check_success $e3 "send-${num} vale0:v0"
 
-test_successful "extra_buf_send_rec_ephemeral_vale_ports_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/extra_buf_send_rec_persistent_vale_ports_test b/utils/extra_buf_send_rec_persistent_vale_ports_test
index b4237068d..b6bf148f0 100755
--- a/utils/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/extra_buf_send_rec_persistent_vale_ports_test
@@ -50,4 +50,4 @@ check_success $e1 "receive-${num} vale0:v0"
 check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
-test_successful "extra_buf_send_rec_persistent_vale_ports_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/extra_buf_send_rec_pipe_test b/utils/extra_buf_send_rec_pipe_test
index 04eb17bee..8cf35648b 100755
--- a/utils/extra_buf_send_rec_pipe_test
+++ b/utils/extra_buf_send_rec_pipe_test
@@ -36,4 +36,4 @@ e1=$?
 check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
-test_successful "send_rec_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/learning_bridge_test b/utils/learning_bridge_test
index 7fa7ea664..a4cfd0c61 100755
--- a/utils/learning_bridge_test
+++ b/utils/learning_bridge_test
@@ -60,4 +60,4 @@ check_success $e1 "receive vale0:v0"
 check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
-test_successful "learning_bridge_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/partial_read_pipe_test b/utils/partial_read_pipe_test
index 8192ed4a1..fb35697da 100755
--- a/utils/partial_read_pipe_test
+++ b/utils/partial_read_pipe_test
@@ -71,4 +71,4 @@ num_send="$(($ring_avail_sends + 1))"
 ./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
-test_successful "partial_read_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/persistent_vale_port_destroy b/utils/persistent_vale_port_destroy
index abd8bf46c..778d9ef89 100755
--- a/utils/persistent_vale_port_destroy
+++ b/utils/persistent_vale_port_destroy
@@ -29,4 +29,4 @@ destroy_vale_persistent_port "$port" 1
 detach_from_vale_bridge "$bridgeA" "$port" 0
 destroy_vale_persistent_port "$port" 0
 
-test_successful "persistent_vale_port_destroy"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/persistent_vale_port_double_attach b/utils/persistent_vale_port_double_attach
index 5f43749e6..2fd271c5b 100755
--- a/utils/persistent_vale_port_double_attach
+++ b/utils/persistent_vale_port_double_attach
@@ -18,4 +18,4 @@ attach_to_vale_bridge "$bridgeA" "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 
-test_successful "persistent_vale_port_double_attach"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/persistent_vale_port_double_create b/utils/persistent_vale_port_double_create
index b04031173..6fe3321e2 100755
--- a/utils/persistent_vale_port_double_create
+++ b/utils/persistent_vale_port_double_create
@@ -21,4 +21,4 @@ create_vale_persistent_port "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 create_vale_persistent_port "$port" 1
 
-test_successful "persistent_vale_port_double_create"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 3faaf0dd6..0d09895b2 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -22,64 +22,37 @@ echo "   sequence check   : ${seq_check}"
 echo "   packet length    : ${random_len}"
 echo ""
 
-echo "destroy persistent VALE port"
 ./persistent_vale_port_destroy
-echo "double create persistent VALE port"
 ./persistent_vale_port_double_create
-echo "double attach persistent VALE port"
 ./persistent_vale_port_double_attach
 
-echo "exclusive open ephemeral VALE port"
 ./exclusive_open_ephemeral_vale_port_test
-echo "exclusive open persistent VALE port"
 ./exclusive_open_persistent_vale_port_test
-echo "exclusive open pipe"
 ./exclusive_open_pipe_test
 
-echo "learning bridge algorithm"
 ./learning_bridge_test -l $random_len -f $random_fill
 
-echo "send/receive pipes"
 ./send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "send/receive ephemeral VALE ports"
 ./send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "send/receive persistent VALE ports"
 ./send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-# echo "send/receive veth"
 # ./send_rec_veth_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "partial read pipe"
 ./partial_read_pipe_test              -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
-echo "receive copy monitor attached to pipe"
 ./rec_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "receive copy monitor attached to persistent VALE port"
 ./rec_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "receive copy monitor attached to ephemeral VALE port"
 ./rec_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "zero-copy monitor attached to receiving pipe"
 ./rec_zcp_mon_pipe_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "zero-copy monitor attached to receiving persistent VALE port"
 ./rec_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "zero-copy monitor attached to receiving ephemeral VALE port"
 ./rec_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
-echo "send copy monitor attached to pipe"
 ./send_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "send copy monitor attached to persistent VALE port"
 ./send_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "send copy monitor attached to ephemeral VALE port"
 ./send_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "zero-copy monitor attached to sending pipe"
 ./send_zcp_mon_pipe_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "zero-copy monitor attached to sending persistent VALE port"
 ./send_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "zero-copy monitor attached to sending ephemeral VALE port"
 ./send_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 
 
-echo "extra buffer send/receive pipes"
 ./extra_buf_send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "extra buffer send/receive ephemeral VALE ports"
 ./extra_buf_send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-echo "extra buffer send/receive persistent VALE ports"
 ./extra_buf_send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
\ No newline at end of file
diff --git a/utils/rec_cp_mon_ephemeral_vale_port_test b/utils/rec_cp_mon_ephemeral_vale_port_test
index 003d2aed2..543a3c9aa 100755
--- a/utils/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/rec_cp_mon_ephemeral_vale_port_test
@@ -46,4 +46,4 @@ check_success $e2 "send-${num} vale0:v1"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
-test_successful "rec_cp_mon_ephemeral_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/rec_cp_mon_persistent_vale_port_test b/utils/rec_cp_mon_persistent_vale_port_test
index 24e44ac18..e6373f55f 100755
--- a/utils/rec_cp_mon_persistent_vale_port_test
+++ b/utils/rec_cp_mon_persistent_vale_port_test
@@ -49,4 +49,4 @@ check_success $e2 "send-${num} vale0:v1"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
-test_successful "rec_cp_mon_persistent_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/rec_cp_mon_pipe_test b/utils/rec_cp_mon_pipe_test
index cb20334db..0b8d91f95 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/rec_cp_mon_pipe_test
@@ -47,4 +47,4 @@ check_success $e2 "send-${num}${seq} netmap:pipe}1"
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
-test_successful "rec_cp_mon_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_ephemeral_vale_port_test b/utils/rec_zcp_mon_ephemeral_vale_port_test
index 2805df2b8..adeba75e9 100755
--- a/utils/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/rec_zcp_mon_ephemeral_vale_port_test
@@ -53,4 +53,4 @@ e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} vale0:v0/z"
 
-test_successful "rec_zcp_mon_ephemeral_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_persistent_vale_port_test b/utils/rec_zcp_mon_persistent_vale_port_test
index 1536b4b83..8f9853d3b 100755
--- a/utils/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/rec_zcp_mon_persistent_vale_port_test
@@ -56,4 +56,4 @@ e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} netmap:v0/z"
 
-test_successful "rec_zcp_mon_persistent_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/rec_zcp_mon_pipe_test
index 1e1d6e48b..69b183330 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/rec_zcp_mon_pipe_test
@@ -53,4 +53,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:pipe{1"
 check_success $e4 "receive-${num} netmap:pipe{1/z"
 
-test_successful "rec_zcp_mon_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_cp_mon_ephemeral_vale_port_test b/utils/send_cp_mon_ephemeral_vale_port_test
index 9592d01a3..dd4308fc6 100755
--- a/utils/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/send_cp_mon_ephemeral_vale_port_test
@@ -44,4 +44,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "send_cp_mon_ephemeral_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_cp_mon_persistent_vale_port_test b/utils/send_cp_mon_persistent_vale_port_test
index 890462e51..4a601deb3 100755
--- a/utils/send_cp_mon_persistent_vale_port_test
+++ b/utils/send_cp_mon_persistent_vale_port_test
@@ -47,4 +47,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "send_cp_mon_persistent_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_cp_mon_pipe_test b/utils/send_cp_mon_pipe_test
index c259b7313..285e6f7b6 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/send_cp_mon_pipe_test
@@ -47,4 +47,4 @@ check_success $e2 "send-${num} netmap:pipe{1"
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
-test_successful "send_cp_mon_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_rec_ephemeral_vale_ports_test b/utils/send_rec_ephemeral_vale_ports_test
index b59e2fd9c..195daaed5 100755
--- a/utils/send_rec_ephemeral_vale_ports_test
+++ b/utils/send_rec_ephemeral_vale_ports_test
@@ -58,4 +58,4 @@ check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
 
-test_successful "send_rec_ephemeral_vale_ports_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_rec_persistent_vale_ports_test b/utils/send_rec_persistent_vale_ports_test
index bf789c3de..1938adb5f 100755
--- a/utils/send_rec_persistent_vale_ports_test
+++ b/utils/send_rec_persistent_vale_ports_test
@@ -65,4 +65,4 @@ check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
 
-test_successful "send_rec_persistent_vale_ports_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_rec_pipe_test b/utils/send_rec_pipe_test
index b1e310809..9f090c953 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/send_rec_pipe_test
@@ -46,4 +46,4 @@ e2=$?
 check_success $e2 "receive-${num} netmap:pipeA}1"
 check_success $e4 "send-${num} netmap:pipeA{1"
 
-test_successful "send_rec_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_rec_veth_test b/utils/send_rec_veth_test
index c6d82eda0..b95064760 100755
--- a/utils/send_rec_veth_test
+++ b/utils/send_rec_veth_test
@@ -47,4 +47,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:veth1B"
 check_success $e4 "send-${num} netmap:veth1A"
 
-test_successful "send_rec_veth_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_ephemeral_vale_port_test b/utils/send_zcp_mon_ephemeral_vale_port_test
index 829c62bac..d119556ad 100755
--- a/utils/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/send_zcp_mon_ephemeral_vale_port_test
@@ -47,4 +47,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "send_zcp_mon_ephemeral_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_persistent_vale_port_test b/utils/send_zcp_mon_persistent_vale_port_test
index 1ce23d23a..eda1920c6 100755
--- a/utils/send_zcp_mon_persistent_vale_port_test
+++ b/utils/send_zcp_mon_persistent_vale_port_test
@@ -50,4 +50,4 @@ check_success $e2 "send-${num} vale0:v0"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "send_zcp_mon_persistent_vale_port_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/send_zcp_mon_pipe_test b/utils/send_zcp_mon_pipe_test
index 5550d0fc5..dc13e981f 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/send_zcp_mon_pipe_test
@@ -54,4 +54,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:pipe{1/z"
 check_success $e4 "receive-${num} netmap:pipe}1"
 
-test_successful "send_zcp_mon_pipe_test"
\ No newline at end of file
+test_successful "$0"
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 1fd2dcd2a..dd8744d69 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -60,7 +60,7 @@ function restart_fd_server() {
 ################################################################################
 function test_successful() {
 	local test_name="$1"
-	stdout_echo "   Success."
+	stdout_echo "$test_name: success."
 }
 
 ################################################################################
@@ -70,14 +70,16 @@ function test_successful() {
 #   $1 -> exit value to check
 #   $2 -> expected exit value to check against
 #   $3 -> string printed
+#   $4 -> string containing the test script name
 ################################################################################
 function check_exit() {
 	local exit_value="$1"
 	local expected_value="$2"
 	local string_to_print="$3"
+	local test_name="$0"
 
 	if [ $exit_value != $expected_value ] ; then
-		stdout_echo "   $string_to_print FAIL($exit_value != $expected_value)."
+		stdout_echo "$test_name: $string_to_print FAIL($exit_value != $expected_value)."
 		exit 1
 	fi
 }
@@ -298,4 +300,4 @@ function get_random_MAC() {
 	else
 		echo "$MAC"
 	fi
-}
\ No newline at end of file
+}

From 81b61bd66d476bdd861410e58f730a4f8a0e0945 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 29 Jun 2018 18:59:34 +0200
Subject: [PATCH 0979/2207] Moved all tests to utils/tests. randomized_tests
 now executes all files contained in tests/ ending with _test. Added new make
 target inttest.

---
 utils/GNUmakefile                             | 21 +++++++----
 utils/fd_server.h                             |  4 ++
 utils/randomized_tests                        | 37 ++-----------------
 utils/test_lib                                |  4 +-
 .../exclusive_open_ephemeral_vale_port_test   |  6 +--
 .../exclusive_open_persistent_vale_port_test  |  6 +--
 utils/{ => tests}/exclusive_open_pipe_test    |  6 +--
 ...tra_buf_send_rec_ephemeral_vale_ports_test | 10 ++---
 ...ra_buf_send_rec_persistent_vale_ports_test | 10 ++---
 .../{ => tests}/extra_buf_send_rec_pipe_test  |  6 +--
 utils/{ => tests}/learning_bridge_test        | 18 ++++-----
 utils/{ => tests}/partial_read_pipe_test      | 10 ++---
 .../{ => tests}/persistent_vale_port_destroy  |  0
 .../persistent_vale_port_double_attach        |  0
 .../persistent_vale_port_double_create        |  0
 .../rec_cp_mon_ephemeral_vale_port_test       | 12 +++---
 .../rec_cp_mon_persistent_vale_port_test      | 12 +++---
 utils/{ => tests}/rec_cp_mon_pipe_test        | 12 +++---
 .../rec_zcp_mon_ephemeral_vale_port_test      | 14 +++----
 .../rec_zcp_mon_persistent_vale_port_test     | 14 +++----
 utils/{ => tests}/rec_zcp_mon_pipe_test       | 14 +++----
 .../send_cp_mon_ephemeral_vale_port_test      | 12 +++---
 .../send_cp_mon_persistent_vale_port_test     | 12 +++---
 utils/{ => tests}/send_cp_mon_pipe_test       | 12 +++---
 .../send_rec_ephemeral_vale_ports_test        | 18 ++++-----
 .../send_rec_persistent_vale_ports_test       | 18 ++++-----
 utils/{ => tests}/send_rec_pipe_test          | 12 +++---
 utils/{ => tests}/send_rec_veth_test          | 14 ++++---
 .../send_zcp_mon_ephemeral_vale_port_test     | 12 +++---
 .../send_zcp_mon_persistent_vale_port_test    | 12 +++---
 utils/{ => tests}/send_zcp_mon_pipe_test      | 14 +++----
 31 files changed, 167 insertions(+), 185 deletions(-)
 rename utils/{ => tests}/exclusive_open_ephemeral_vale_port_test (87%)
 rename utils/{ => tests}/exclusive_open_persistent_vale_port_test (88%)
 rename utils/{ => tests}/exclusive_open_pipe_test (88%)
 rename utils/{ => tests}/extra_buf_send_rec_ephemeral_vale_ports_test (80%)
 rename utils/{ => tests}/extra_buf_send_rec_persistent_vale_ports_test (84%)
 rename utils/{ => tests}/extra_buf_send_rec_pipe_test (84%)
 rename utils/{ => tests}/learning_bridge_test (75%)
 rename utils/{ => tests}/partial_read_pipe_test (89%)
 rename utils/{ => tests}/persistent_vale_port_destroy (100%)
 rename utils/{ => tests}/persistent_vale_port_double_attach (100%)
 rename utils/{ => tests}/persistent_vale_port_double_create (100%)
 rename utils/{ => tests}/rec_cp_mon_ephemeral_vale_port_test (83%)
 rename utils/{ => tests}/rec_cp_mon_persistent_vale_port_test (84%)
 rename utils/{ => tests}/rec_cp_mon_pipe_test (81%)
 rename utils/{ => tests}/rec_zcp_mon_ephemeral_vale_port_test (81%)
 rename utils/{ => tests}/rec_zcp_mon_persistent_vale_port_test (82%)
 rename utils/{ => tests}/rec_zcp_mon_pipe_test (80%)
 rename utils/{ => tests}/send_cp_mon_ephemeral_vale_port_test (81%)
 rename utils/{ => tests}/send_cp_mon_persistent_vale_port_test (83%)
 rename utils/{ => tests}/send_cp_mon_pipe_test (81%)
 rename utils/{ => tests}/send_rec_ephemeral_vale_ports_test (74%)
 rename utils/{ => tests}/send_rec_persistent_vale_ports_test (77%)
 rename utils/{ => tests}/send_rec_pipe_test (77%)
 rename utils/{ => tests}/send_rec_veth_test (78%)
 rename utils/{ => tests}/send_zcp_mon_ephemeral_vale_port_test (84%)
 rename utils/{ => tests}/send_zcp_mon_persistent_vale_port_test (85%)
 rename utils/{ => tests}/send_zcp_mon_pipe_test (81%)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index c92c042e1..efcedc6c6 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,16 +1,17 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
-PROGS	= test_select testmmap test_nm functional ctrl-api-test fd_server get_tx_rings_avail_sends get_tx_rings_max_sends
-X86PROGS = testlock testcsum producer
+PROGS	  = test_select testmmap test_nm functional ctrl-api-test fd_server
+PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends
+X86PROGS  = testlock testcsum producer
 LIBNETMAP =
 
 CLEANFILES = $(PROGS) $(X86PROGS) *.o
 
 SRCDIR ?= ..
-VPATH = $(SRCDIR)/utils
+VPATH   = $(SRCDIR)/utils
 
 NO_MAN=
-CFLAGS = -O2 -pipe
+CFLAGS  = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys # -I/home/luigi/FreeBSD/head/sys -I../sys
 CFLAGS += -Wextra
@@ -30,20 +31,26 @@ endif
 
 PREFIX ?= /usr/local
 
+.PHONY: install clean all-x86 all inttest
+
 all: $(PROGS)
 
+inttest:
+	./randomized_tests
+
+functional: fd_server.h
+
+fd_server: fd_server.h
+
 all-x86: $(PROGS) $(X86PROGS)
 
 kern_test: testmod/kern_test.c
 
-test_nm: test_nm.o
-
 clean:
 	-@rm -rf $(CLEANFILES)
 
 testlock: testlock.c
 
-.PHONY: install
 install: $(PROGS:%=install-%)
 
 install-%:
diff --git a/utils/fd_server.h b/utils/fd_server.h
index d4bb07329..197d93505 100644
--- a/utils/fd_server.h
+++ b/utils/fd_server.h
@@ -1,6 +1,10 @@
 #ifndef FD_LIB_H
 #define FD_LIB_H
 
+#include 
+#include 
+#include 
+
 #define SOCKET_NAME "/tmp/my_unix_socket"
 
 struct fd_request {
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 0d09895b2..e8c4a63a5 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -22,37 +22,6 @@ echo "   sequence check   : ${seq_check}"
 echo "   packet length    : ${random_len}"
 echo ""
 
-./persistent_vale_port_destroy
-./persistent_vale_port_double_create
-./persistent_vale_port_double_attach
-
-./exclusive_open_ephemeral_vale_port_test
-./exclusive_open_persistent_vale_port_test
-./exclusive_open_pipe_test
-
-./learning_bridge_test -l $random_len -f $random_fill
-
-./send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-# ./send_rec_veth_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./partial_read_pipe_test              -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-
-./rec_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./rec_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./rec_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./rec_zcp_mon_pipe_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./rec_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./rec_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-
-./send_cp_mon_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_cp_mon_persistent_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_cp_mon_ephemeral_vale_port_test   -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_zcp_mon_pipe_test                 -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_zcp_mon_persistent_vale_port_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./send_zcp_mon_ephemeral_vale_port_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-
-
-./extra_buf_send_rec_pipe_test                  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./extra_buf_send_rec_ephemeral_vale_ports_test  -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-./extra_buf_send_rec_persistent_vale_ports_test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
\ No newline at end of file
+for test in tests/*_test ; do
+	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+done
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index dd8744d69..46d00fe64 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -28,7 +28,7 @@ function stdout_echo() {
 #   None
 ################################################################################
 function close_fd_server() {
-	./functional -c
+	functional -c
 	check_success "$?" "close_fd_server"
 }
 
@@ -38,7 +38,7 @@ function close_fd_server() {
 #   None
 ################################################################################
 function start_fd_server() {
-	./functional -o
+	functional -o
 	check_success "$?" "start_fd_server"
 }
 
diff --git a/utils/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
similarity index 87%
rename from utils/exclusive_open_ephemeral_vale_port_test
rename to utils/tests/exclusive_open_ephemeral_vale_port_test
index 7bd2dd102..526765c3f 100755
--- a/utils/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -12,16 +12,16 @@ restart_fd_server
 bridge="vale0"
 port="v0"
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
-./functional -i "${bridge}:${port}/x"
+functional -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-./functional -I "${bridge}:${port}"
+functional -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-./functional -I "${bridge}:${port}/x"
+functional -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/exclusive_open_persistent_vale_port_test b/utils/tests/exclusive_open_persistent_vale_port_test
similarity index 88%
rename from utils/exclusive_open_persistent_vale_port_test
rename to utils/tests/exclusive_open_persistent_vale_port_test
index 94fae2159..a70439703 100755
--- a/utils/exclusive_open_persistent_vale_port_test
+++ b/utils/tests/exclusive_open_persistent_vale_port_test
@@ -15,16 +15,16 @@ create_vale_persistent_port "$port"
 attach_to_vale_bridge "$bridge" "$port"
 
 # We open the persistent port with the exclusive flag from the file descriptor.
-./functional -i "${bridge}:${port}/x"
+functional -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-./functional -I "${bridge}:${port}"
+functional -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-./functional -I "${bridge}:${port}/x"
+functional -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/exclusive_open_pipe_test b/utils/tests/exclusive_open_pipe_test
similarity index 88%
rename from utils/exclusive_open_pipe_test
rename to utils/tests/exclusive_open_pipe_test
index 881b44ae1..f7edeeaf0 100755
--- a/utils/exclusive_open_pipe_test
+++ b/utils/tests/exclusive_open_pipe_test
@@ -11,16 +11,16 @@ restart_fd_server
 
 pipe="pipeA{1"
 # We open pipeA{1 with the exclusive flag from the file descriptor.
-./functional -i "netmap:${pipe}/x"
+functional -i "netmap:${pipe}/x"
 check_success $? "exclusive-open netmap:${pipe}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-./functional -I "netmap:${pipe}"
+functional -I "netmap:${pipe}"
 check_failure $? "no-open netmap:${pipe}"
 
 # Check that another exclusive open request fails.
-./functional -I "netmap:${pipe}/x"
+functional -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
similarity index 80%
rename from utils/extra_buf_send_rec_ephemeral_vale_ports_test
rename to utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 41677f035..3d8a47f33 100755
--- a/utils/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -23,17 +23,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v1"
+functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-./functional -i "vale0:v2"
+functional -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v0 ---> v1, v2
-./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-./functional -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
similarity index 84%
rename from utils/extra_buf_send_rec_persistent_vale_ports_test
rename to utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index b6bf148f0..1c66bbfaa 100755
--- a/utils/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -30,17 +30,17 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v0"
+functional -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-./functional -i "vale0:v1"
+functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # v2 ---> v0, v1
-./functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-./functional -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
similarity index 84%
rename from utils/extra_buf_send_rec_pipe_test
rename to utils/tests/extra_buf_send_rec_pipe_test
index 8cf35648b..9ee01cd31 100755
--- a/utils/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -23,13 +23,13 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipeA{1"
+functional -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
 
 # pipeA}1 ---> pipeA{1
-./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e2=$?
 wait $p1
 e1=$?
diff --git a/utils/learning_bridge_test b/utils/tests/learning_bridge_test
similarity index 75%
rename from utils/learning_bridge_test
rename to utils/tests/learning_bridge_test
index a4cfd0c61..a44fa67ca 100755
--- a/utils/learning_bridge_test
+++ b/utils/tests/learning_bridge_test
@@ -23,19 +23,19 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
-./functional -i vale0:v2
+functional -i vale0:v2
 check_success $? "pre-open vale0:v2"
 
 # First send, every port should receive the frame.
-./functional -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+functional -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p1=$!
-./functional -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+functional -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p2=$!
-./functional -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
+functional -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
 e3=$?
 wait $p1
 e1=$?
@@ -46,11 +46,11 @@ check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-./functional -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
+functional -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
 p4=$!
-./functional -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
+functional -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
 p5=$!
-./functional -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
+functional -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
similarity index 89%
rename from utils/partial_read_pipe_test
rename to utils/tests/partial_read_pipe_test
index fb35697da..5fa277cf3 100755
--- a/utils/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -22,14 +22,14 @@ num_recv=7
 pipe="pipeA"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:${pipe}{1"
+functional -i "netmap:${pipe}{1"
 check_success $? "pre-open netmap:${pipe}{1"
-./functional -i "netmap:${pipe}}1"
+functional -i "netmap:${pipe}}1"
 check_success $? "pre-open netmap:${pipe}}1"
 
-./functional -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
+functional -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
 p1=$!
-./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 e2=$?
 wait $p1
 e1=$?
@@ -68,7 +68,7 @@ check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
 
 
 num_send="$(($ring_avail_sends + 1))"
-./functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/persistent_vale_port_destroy b/utils/tests/persistent_vale_port_destroy
similarity index 100%
rename from utils/persistent_vale_port_destroy
rename to utils/tests/persistent_vale_port_destroy
diff --git a/utils/persistent_vale_port_double_attach b/utils/tests/persistent_vale_port_double_attach
similarity index 100%
rename from utils/persistent_vale_port_double_attach
rename to utils/tests/persistent_vale_port_double_attach
diff --git a/utils/persistent_vale_port_double_create b/utils/tests/persistent_vale_port_double_create
similarity index 100%
rename from utils/persistent_vale_port_double_create
rename to utils/tests/persistent_vale_port_double_create
diff --git a/utils/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
similarity index 83%
rename from utils/rec_cp_mon_ephemeral_vale_port_test
rename to utils/tests/rec_cp_mon_ephemeral_vale_port_test
index 543a3c9aa..ab3ddc4f0 100755
--- a/utils/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -24,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i vale0:v0/r
+functional -i vale0:v0/r
 check_success $? "pre-open vale0:v0/r"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-./functional -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} vale0:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-./functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
similarity index 84%
rename from utils/rec_cp_mon_persistent_vale_port_test
rename to utils/tests/rec_cp_mon_persistent_vale_port_test
index e6373f55f..d2f56591b 100755
--- a/utils/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -27,17 +27,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i netmap:v0/r
+functional -i netmap:v0/r
 check_success $? "pre-open netmap:v0/r"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-./functional -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -45,7 +45,7 @@ check_success $e1 "receive-${num} netmap:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-./functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
similarity index 81%
rename from utils/rec_cp_mon_pipe_test
rename to utils/tests/rec_cp_mon_pipe_test
index 0b8d91f95..2bce38cf5 100755
--- a/utils/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -25,17 +25,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"
+functional -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/r"
+functional -i "netmap:pipe{1/r"
 check_success $? "pre-open netmap:pipe{1/r"
-./functional -i "netmap:pipe}1"
+functional -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-./functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +43,7 @@ check_success $e1 "receive-${num}${seq} netmap:pipe{1/r"
 check_success $e2 "send-${num}${seq} netmap:pipe}1"
 
 # Then we read from pipe{1
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
diff --git a/utils/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
similarity index 81%
rename from utils/rec_zcp_mon_ephemeral_vale_port_test
rename to utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index adeba75e9..906fb6f97 100755
--- a/utils/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -24,18 +24,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v0"
+functional -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-./functional -i "vale0:v0/z"
+functional -i "vale0:v0/z"
 check_success $? "pre-open vale0:v0/z"
-./functional -i "vale0:v1"
+functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -44,9 +44,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
similarity index 82%
rename from utils/rec_zcp_mon_persistent_vale_port_test
rename to utils/tests/rec_zcp_mon_persistent_vale_port_test
index 8f9853d3b..73887b3ff 100755
--- a/utils/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -27,18 +27,18 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v0"
+functional -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-./functional -i "netmap:v0/z"
+functional -i "netmap:v0/z"
 check_success $? "pre-open netmap:v0/z"
-./functional -i "vale0:v1"
+functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-./functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -47,9 +47,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-./functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
similarity index 80%
rename from utils/rec_zcp_mon_pipe_test
rename to utils/tests/rec_zcp_mon_pipe_test
index 69b183330..9dcfac05e 100755
--- a/utils/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -24,18 +24,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"
+functional -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/z"
+functional -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-./functional -i "netmap:pipe}1"
+functional -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -44,9 +44,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
similarity index 81%
rename from utils/send_cp_mon_ephemeral_vale_port_test
rename to utils/tests/send_cp_mon_ephemeral_vale_port_test
index dd4308fc6..191fe63d9 100755
--- a/utils/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -22,17 +22,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i vale0:v0/t
+functional -i vale0:v0/t
 check_success $? "pre-open vale0:v0/t"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -40,7 +40,7 @@ check_success $e1 "receive-${num} vale0:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
similarity index 83%
rename from utils/send_cp_mon_persistent_vale_port_test
rename to utils/tests/send_cp_mon_persistent_vale_port_test
index 4a601deb3..e0def41f9 100755
--- a/utils/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -25,17 +25,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i netmap:v0/t
+functional -i netmap:v0/t
 check_success $? "pre-open netmap:v0/t"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +43,7 @@ check_success $e1 "receive-${num} netmap:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
similarity index 81%
rename from utils/send_cp_mon_pipe_test
rename to utils/tests/send_cp_mon_pipe_test
index 285e6f7b6..11439e5e2 100755
--- a/utils/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -25,17 +25,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"
+functional -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/t"
+functional -i "netmap:pipe{1/t"
 check_success $? "pre-open netmap:pipe{1/t"
-./functional -i "netmap:pipe}1"
+functional -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-./functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +43,7 @@ check_success $e1 "receive-${num} netmap:pipe{1/t"
 check_success $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-./functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
diff --git a/utils/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
similarity index 74%
rename from utils/send_rec_ephemeral_vale_ports_test
rename to utils/tests/send_rec_ephemeral_vale_ports_test
index 195daaed5..128df37d4 100755
--- a/utils/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -21,19 +21,19 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v0"
+functional -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-./functional -i "vale0:v1"
+functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-./functional -i "vale0:v2"
+functional -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-./functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-./functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
 e3=$?
 wait $p1
 e1=$?
@@ -44,11 +44,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p4=$!
-./functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p5=$!
-./functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
similarity index 77%
rename from utils/send_rec_persistent_vale_ports_test
rename to utils/tests/send_rec_persistent_vale_ports_test
index 1938adb5f..7a2ba00a0 100755
--- a/utils/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -28,19 +28,19 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "vale0:v0"
+functional -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-./functional -i "vale0:v1"
+functional -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-./functional -i "vale0:v2"
+functional -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-./functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-./functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
 e3=$?
 wait $p1
 e1=$?
@@ -51,11 +51,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-./functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p4=$!
-./functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p5=$!
-./functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
similarity index 77%
rename from utils/send_rec_pipe_test
rename to utils/tests/send_rec_pipe_test
index 9f090c953..6a7afdd8a 100755
--- a/utils/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -21,15 +21,15 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipeA{1"
+functional -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
-./functional -i "netmap:pipeA}1"
+functional -i "netmap:pipeA}1"
 check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-./functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -37,9 +37,9 @@ check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-./functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e2=$?
diff --git a/utils/send_rec_veth_test b/utils/tests/send_rec_veth_test
similarity index 78%
rename from utils/send_rec_veth_test
rename to utils/tests/send_rec_veth_test
index b95064760..b14c626e6 100755
--- a/utils/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -19,18 +19,20 @@ seq="${seq:-}"
 
 restart_fd_server
 
+exit 0
+
 create_veth_interfaces "veth1"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i netmap:veth1A
+functional -i netmap:veth1A
 check_success $? "pre-open netmap:veth1A"
-./functional -i netmap:veth1B
+functional -i netmap:veth1B
 check_success $? "pre-open netmap:veth1B"
 
 # veth1B --> veth1A
-./functional -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
+functional -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
+functional -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -38,9 +40,9 @@ check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
 # veth1A --> veth1B
-./functional -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
+functional -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
+functional -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
similarity index 84%
rename from utils/send_zcp_mon_ephemeral_vale_port_test
rename to utils/tests/send_zcp_mon_ephemeral_vale_port_test
index d119556ad..c28cafa33 100755
--- a/utils/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -25,17 +25,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i vale0:v0/z
+functional -i vale0:v0/z
 check_success $? "pre-open vale0:v0/z"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +43,7 @@ check_success $e1 "receive-${num} vale0:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
similarity index 85%
rename from utils/send_zcp_mon_persistent_vale_port_test
rename to utils/tests/send_zcp_mon_persistent_vale_port_test
index eda1920c6..99384480b 100755
--- a/utils/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -28,17 +28,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i vale0:v0
+functional -i vale0:v0
 check_success $? "pre-open vale0:v0"
-./functional -i netmap:v0/z
+functional -i netmap:v0/z
 check_success $? "pre-open netmap:v0/z"
-./functional -i vale0:v1
+functional -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-./functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-./functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -46,7 +46,7 @@ check_success $e1 "receive-${num} netmap:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-./functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
similarity index 81%
rename from utils/send_zcp_mon_pipe_test
rename to utils/tests/send_zcp_mon_pipe_test
index dc13e981f..aa1871c7e 100755
--- a/utils/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -25,18 +25,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-./functional -i "netmap:pipe{1"
+functional -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-./functional -i "netmap:pipe{1/z"
+functional -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-./functional -i "netmap:pipe}1"
+functional -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-./functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -45,9 +45,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-./functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
+functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-./functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
+functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?

From f1b1936fb78dbf3940e101fc3c1dba3a152b89a8 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Sun, 1 Jul 2018 19:15:33 +0200
Subject: [PATCH 0980/2207] randomized_tests adds the current directory to
 PATH.

---
 utils/randomized_tests | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index e8c4a63a5..1cdbf794b 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -22,6 +22,11 @@ echo "   sequence check   : ${seq_check}"
 echo "   packet length    : ${random_len}"
 echo ""
 
+# We add the current directory to the PATH. This way we can directly run
+# functional, get_tx_rings_avail_sends and get_tx_rings_max_sends from the test
+# scripts.
+PATH="$(pwd):${PATH}"
+
 for test in tests/*_test ; do
 	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 done
\ No newline at end of file

From e8ec73d2f5dd9c7c6403f1a9985724707b2d3f39 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 2 Jul 2018 12:56:35 +0200
Subject: [PATCH 0981/2207] Added verbosity levels to functional.c output.
 randomized_tests normally executes tests with verbosity level = 0. After a
 failed tests, the test is then executed again with increased verbosity level,
 so that it's possible to see what went wrong.

---
 utils/functional.c                            | 299 +++++++++++-------
 utils/randomized_tests                        |  15 +-
 utils/test_lib                                |  11 +-
 .../exclusive_open_ephemeral_vale_port_test   |   9 +-
 .../exclusive_open_persistent_vale_port_test  |   9 +-
 utils/tests/exclusive_open_pipe_test          |   9 +-
 ...tra_buf_send_rec_ephemeral_vale_ports_test |  13 +-
 ...ra_buf_send_rec_persistent_vale_ports_test |  13 +-
 utils/tests/extra_buf_send_rec_pipe_test      |   9 +-
 utils/tests/learning_bridge_test              |  22 +-
 utils/tests/partial_read_pipe_test            |  18 +-
 utils/tests/persistent_vale_port_destroy      |   3 +-
 .../tests/persistent_vale_port_double_attach  |   3 +-
 .../tests/persistent_vale_port_double_create  |   3 +-
 .../tests/rec_cp_mon_ephemeral_vale_port_test |  15 +-
 .../rec_cp_mon_persistent_vale_port_test      |  15 +-
 utils/tests/rec_cp_mon_pipe_test              |  15 +-
 .../rec_zcp_mon_ephemeral_vale_port_test      |  17 +-
 .../rec_zcp_mon_persistent_vale_port_test     |  17 +-
 utils/tests/rec_zcp_mon_pipe_test             |  17 +-
 .../send_cp_mon_ephemeral_vale_port_test      |  15 +-
 .../send_cp_mon_persistent_vale_port_test     |  15 +-
 utils/tests/send_cp_mon_pipe_test             |  15 +-
 .../tests/send_rec_ephemeral_vale_ports_test  |  21 +-
 .../tests/send_rec_persistent_vale_ports_test |  21 +-
 utils/tests/send_rec_pipe_test                |  15 +-
 utils/tests/send_rec_veth_test                |  15 +-
 .../send_zcp_mon_ephemeral_vale_port_test     |  15 +-
 .../send_zcp_mon_persistent_vale_port_test    |  15 +-
 utils/tests/send_zcp_mon_pipe_test            |  17 +-
 30 files changed, 379 insertions(+), 317 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index 0d6e4631e..a99b202ed 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -32,6 +32,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #define NETMAP_WITH_LIBS
@@ -87,7 +88,11 @@ struct Global {
 	int sequential_fill;        /* increment fill char for multi-packets
 	                            operations */
 	int request_from_fd_server; /* false --> directly open the interface */
-	int verbose;
+#define LV_ERROR_MSG 1
+#define LV_DEBUG_SEND_RECV 2
+#define LV_DEBUG_BUILD_PACKET 3
+#define LV_DEBUG_PARSE_ARGS 4
+	int verbosity_level;
 
 	/* List of currently not in use normal buffers. */
 	LIST_HEAD(n_buf_head, swapped_out_buf) normal_buffers_head;
@@ -135,13 +140,35 @@ cleanup(struct Global *g)
 	}
 }
 
+void
+verbose_print(int current_verbosity, int required_verbosity, char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	if (current_verbosity >= required_verbosity) {
+		vprintf(format, args);
+	}
+
+	va_end(args);
+}
+
+void
+verbose_perror(int current_verbosity, int required_verbosity, char *str)
+{
+	if (current_verbosity >= required_verbosity) {
+		perror(str);
+	}
+}
+
 static void
 fill_packet_field(struct Global *g, unsigned offset, const char *content,
                   unsigned content_len)
 {
 	if (offset + content_len > sizeof(g->pktm)) {
-		printf("Packet layout overflow: %u + %u > %lu\n", offset,
-		       content_len, sizeof(g->pktm));
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Packet layout overflow: %u + %u > %lu\n", offset,
+		              content_len, sizeof(g->pktm));
 		cleanup(g);
 		exit(EXIT_FAILURE);
 	}
@@ -214,9 +241,8 @@ build_packet(struct Global *g)
 	unsigned pldofs;
 
 	memset(g->pktm, 0, sizeof(g->pktm));
-	if (g->verbose) {
-		printf("%s: starting at ofs %u\n", __func__, ofs);
-	}
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: starting at ofs %u\n", __func__, ofs);
 
 	ethofs = ofs;
 	(void)ethofs;
@@ -227,14 +253,12 @@ build_packet(struct Global *g)
 	ofs += ETH_ADDR_LEN;
 	fill_packet_16bit(g, ofs, ETHERTYPE_IP);
 	ofs += 2;
-	if (g->verbose) {
-		printf("%s: eth done, ofs %u\n", __func__, ofs);
-	}
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: eth done, ofs %u\n", __func__, ofs);
 
 	ipofs = ofs;
 	/* First byte of IP header. */
-	fill_packet_8bit(g, ofs,
-	                 (IPVERSION << 4) | ((sizeof(struct ip)) >> 2));
+	fill_packet_8bit(g, ofs, (IPVERSION << 4) | ((sizeof(struct ip)) >> 2));
 	ofs += 1;
 	/* Skip QoS byte. */
 	ofs += 1;
@@ -264,9 +288,8 @@ build_packet(struct Global *g)
 	fill_packet_16bit(
 	        g, ipofs + 10,
 	        wrapsum(checksum(g->pktm + ipofs, sizeof(struct ip), 0)));
-	if (g->verbose) {
-		printf("%s: ip done, ofs %u\n", __func__, ofs);
-	}
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: ip done, ofs %u\n", __func__, ofs);
 
 	udpofs = ofs;
 	/* UDP source port. */
@@ -280,18 +303,16 @@ build_packet(struct Global *g)
 	ofs += 2;
 	/* Skip the UDP checksum for now. */
 	ofs += 2;
-	if (g->verbose) {
-		printf("%s: udp done, ofs %u\n", __func__, ofs);
-	}
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: udp done, ofs %u\n", __func__, ofs);
 
 	/* Fill UDP payload. */
 	pldofs = ofs;
 	for (; ofs < g->pktm_len; ofs++) {
 		fill_packet_8bit(g, ofs, g->filler);
 	}
-	if (g->verbose) {
-		printf("%s: payload done, ofs %u\n", __func__, ofs);
-	}
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: payload done, ofs %u\n", __func__, ofs);
 
 	/* Put the UDP checksum now.
 	 * Magic: taken from sbin/dhclient/packet.c */
@@ -342,7 +363,8 @@ tx_flush(struct Global *g)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout\n", __func__);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
 			return -1;
 		}
 
@@ -411,8 +433,9 @@ put_one_packet(struct Global *g, struct netmap_ring *ring)
 	}
 
 	ring->head = ring->cur = head;
-	printf("packet (%u bytes, %u frags) placed to TX\n", g->pktm_len,
-	       frags);
+	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+	              "packet (%u bytes, %u frags) placed to TX\n", g->pktm_len,
+	              frags);
 }
 
 char
@@ -441,7 +464,8 @@ tx(struct Global *g, unsigned packets_num)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout\n", __func__);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
 			return -1;
 		}
 
@@ -519,17 +543,19 @@ rx_check(struct Global *g)
 	unsigned i;
 
 	if (g->pktr_len != g->pktm_len) {
-		printf("Received packet length (%u) different from "
-		       "expected (%u bytes)\n",
-		       g->pktr_len, g->pktm_len);
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Received packet length (%u) different from "
+		              "expected (%u bytes)\n",
+		              g->pktr_len, g->pktm_len);
 		return -1;
 	}
 
 	for (i = 0; i < g->pktr_len; i++) {
 		if (g->pktr[i] != g->pktm[i]) {
-			printf("Received packet differs from model at "
-			       "offset %u (0x%02x!=0x%02x)\n",
-			       i, g->pktr[i], (uint8_t)g->pktm[i]);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Received packet differs from model at "
+			              "offset %u (0x%02x!=0x%02x)\n",
+			              i, g->pktr[i], (uint8_t)g->pktm[i]);
 			return -1;
 		}
 	}
@@ -550,10 +576,11 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 
 		if (g->pktr_len + slot->len > sizeof(g->pktr)) {
 			/* Sanity check. */
-			printf("Error: received packet too "
-			       "large "
-			       "(>= %u bytes) ",
-			       g->pktr_len + slot->len);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Error: received packet too "
+			              "large "
+			              "(>= %u bytes) ",
+			              g->pktr_len + slot->len);
 			cleanup(g);
 			exit(EXIT_FAILURE);
 		}
@@ -567,18 +594,20 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 		}
 
 		if (head == ring->tail) {
-			printf("warning: truncated packet "
-			       "(len=%u)\n",
-			       g->pktr_len);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "warning: truncated packet "
+			              "(len=%u)\n",
+			              g->pktr_len);
 			frags = -1;
 			break;
 		}
 	}
 
 	ring->head = ring->cur = head;
-	printf("packet (%u bytes, %d frags) received "
-	       "from RX\n",
-	       g->pktr_len, frags);
+	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+	              "packet (%u bytes, %d frags) received "
+	              "from RX\n",
+	              g->pktr_len, frags);
 	return frags;
 }
 
@@ -599,7 +628,8 @@ rx(struct Global *g, unsigned packets_num)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout\n", __func__);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
 			/* -n flag */
 			return g->success_if_no_receive == 1 ? 0 : -1;
 		}
@@ -628,13 +658,13 @@ rx(struct Global *g, unsigned packets_num)
 			}
 
 			if (ignore_received_frame(g)) {
-				if (g->verbose) {
-					printf("(ignoring packet with %u bytes "
-					       "and "
-					       "%d frags received from RX ring "
-					       "#%d)\n",
-					       g->pktr_len, frags, i);
-				}
+				verbose_print(g->verbosity_level,
+				              LV_DEBUG_SEND_RECV,
+				              "(ignoring packet with %u bytes "
+				              "and "
+				              "%d frags received from RX ring "
+				              "#%d)\n",
+				              g->pktr_len, frags, i);
 				elapsed_ms = 0;
 				/* We can go back there, because we're
 				 * decrementing packets_num each time, therefore
@@ -670,7 +700,8 @@ rx(struct Global *g, unsigned packets_num)
 }
 
 static int
-parse_txrx_event(const char *opt, unsigned event_type, struct Event *event)
+parse_txrx_event(const char *opt, unsigned event_type, struct Event *event,
+                 int verbosity_level)
 {
 	char *strbuf = strdup(opt);
 	char *save   = strbuf;
@@ -713,9 +744,8 @@ parse_txrx_event(const char *opt, unsigned event_type, struct Event *event)
 	}
 
 	ret = 0;
-#if 0
-	printf("parsed %u:%c:%u\n", event->pkt_len, event->filler, event->num);
-#endif
+	verbose_print(verbosity_level, LV_DEBUG_PARSE_ARGS, "parsed %u:%c:%u\n",
+	              event->pkt_len, event->filler, event->num);
 out:
 	if (save) {
 		free(save);
@@ -724,7 +754,7 @@ parse_txrx_event(const char *opt, unsigned event_type, struct Event *event)
 }
 
 static int
-parse_pause_event(const char *opt, struct Event *event)
+parse_pause_event(const char *opt, struct Event *event, int verbosity_level)
 {
 	char *strbuf = strdup(opt);
 	char *save   = strbuf;
@@ -747,13 +777,13 @@ parse_pause_event(const char *opt, struct Event *event)
 	if (event->usecs == 0) {
 		goto out;
 	}
+
 	event->usecs *= mul;
 	event->num = 1;
 	ret        = 0;
+	verbose_print(verbosity_level, LV_DEBUG_PARSE_ARGS,
+	              "parsed %llu usecs\n", event->usecs);
 out:
-#if 0
-	printf("parsed %llu usecs\n", event->usecs);
-#endif
 	free(save);
 	return ret;
 }
@@ -761,36 +791,37 @@ parse_pause_event(const char *opt, struct Event *event)
 static struct Global _g;
 
 static void
-usage(void)
+usage(FILE *stream)
 {
-	printf("usage: ./functional [-h]\n"
-	       "    [-c (shuts down the fd server)]\n"
-	       "    [-o (starts the fd server)]\n"
-	       "    [-i NETMAP_PORT (requests the interface from the fd "
-	       "server)]\n"
-	       "    [-I NETMAP_PORT (directly opens the interface)]\n"
-	       "    [-s source MAC address (=0:0:0:0:0:0)]\n"
-	       "    [-d destination MAC address (=FF:FF:FF:FF:FF:FF)]\n"
-	       "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
-	       "    [-T TIMEOUT_SECS (=1)]\n"
-	       "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
-	       "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
-	       "LEN bytes)]\n"
-	       "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
-	       "with size LEN bytes)]\n"
-	       "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
-	       "    [-g (ignore ethernet frames with unmatching Ethernet "
-	       "header)]\n"
-	       "    [-n (exit status = 0 <==> no frames were received)]\n"
-	       "    [-q (during multi-packets send/receive increments fill "
-	       "character after each operation)]\n"
-	       "    [-e (use extra buffers to send packets, "
-	       "can only be used when directly opening an interface)]\n"
-	       "    [-v (increment verbosity level)]\n"
-	       "    [-C [NUM (=1)] (how many times to run the events)]\n"
-	       "\nExample:\n"
-	       "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
-	       "40:b:2\n");
+	fprintf(stream,
+	        "usage: ./functional [-h]\n"
+	        "    [-c (shuts down the fd server)]\n"
+	        "    [-o (starts the fd server)]\n"
+	        "    [-i NETMAP_PORT (requests the interface from the fd "
+	        "server)]\n"
+	        "    [-I NETMAP_PORT (directly opens the interface)]\n"
+	        "    [-s source MAC address (=0:0:0:0:0:0)]\n"
+	        "    [-d destination MAC address (=FF:FF:FF:FF:FF:FF)]\n"
+	        "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
+	        "    [-T TIMEOUT_SECS (=1)]\n"
+	        "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
+	        "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
+	        "LEN bytes)]\n"
+	        "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
+	        "with size LEN bytes)]\n"
+	        "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
+	        "    [-g (ignore ethernet frames with unmatching Ethernet "
+	        "header)]\n"
+	        "    [-n (exit status = 0 <==> no frames were received)]\n"
+	        "    [-q (during multi-packets send/receive increments fill "
+	        "character after each operation)]\n"
+	        "    [-e (use extra buffers to send packets, "
+	        "can only be used when directly opening an interface)]\n"
+	        "    [-v (increment verbosity level)]\n"
+	        "    [-C [NUM (=1)] (how many times to run the events)]\n"
+	        "\nExample:\n"
+	        "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
+	        "40:b:2\n");
 }
 
 /* Copied from nm_open() */
@@ -839,7 +870,7 @@ connect_to_fd_server(struct Global *g)
 
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
-		perror("socket()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "socket()");
 		return -1;
 	}
 
@@ -850,7 +881,8 @@ connect_to_fd_server(struct Global *g)
 	while (connect(socket_fd, (const struct sockaddr *)&name,
 	               sizeof(struct sockaddr_un)) == -1) {
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			printf("%s: Timeout\n", __func__);
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
 			return -1;
 		}
 
@@ -869,7 +901,7 @@ start_fd_server(struct Global *g)
 
 	pid = fork();
 	if (pid < 0) {
-		perror("fork()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "fork()");
 		exit(EXIT_FAILURE);
 	}
 	if (pid > 0) {
@@ -877,14 +909,15 @@ start_fd_server(struct Global *g)
 		return;
 	}
 
-	if (execl("fd_server", "./fd_server", (char *)NULL)) {
-		perror("exec()");
+	if (execl("fd_server", "fd_server", (char *)NULL)) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "exec()");
 		exit(EXIT_FAILURE);
 	}
 
 	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
-		printf("Couldn't connect to fd_server after starting it\n");
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Can't connect to fd_server\n");
 		exit(EXIT_FAILURE);
 	}
 	close(socket_fd);
@@ -956,27 +989,27 @@ get_if_fd(struct Global *g, const char *if_name)
 	strncpy(req.if_name, if_name, sizeof(req.if_name));
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret < 0) {
-		perror("send()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
 		return NULL;
 	}
 
 	memset(&res, 0, sizeof(res));
 	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(res));
 	if (ret == -1) {
-		perror("recv_fd()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "recv_fd()");
 		return NULL;
 	}
 	close(socket_fd);
 
 	nmd = malloc(sizeof(*nmd));
 	if (nmd == NULL) {
-		perror("malloc()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "malloc()");
 		return NULL;
 	}
 
 	fill_nm_desc(nmd, &res.req, new_fd);
 	if (nm_mmap(nmd, NULL) != 0) {
-		perror("nm_mmap()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "nm_mmap()");
 		return NULL;
 	}
 
@@ -1001,7 +1034,7 @@ release_if_fd(struct Global *g, const char *if_name)
 
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret <= 0) {
-		perror("send()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
 	}
 
 	close(socket_fd);
@@ -1019,16 +1052,18 @@ stop_fd_server(struct Global *g)
 	socket_fd       = connect_to_fd_server(g);
 	g->timeout_secs = old_timeout_secs;
 	if (socket_fd == -1) {
-		printf("server alredy down\n");
+		verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+		              "fd_server alredy down\n");
 		return;
 	}
-	printf("shutting down fd_server\n");
+	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+	              "Shutting down fd_server\n");
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_STOP;
 	ret        = send(socket_fd, &req, sizeof(req), 0);
 	if (ret == -1) {
-		perror("send()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
 	}
 	/* By calling recv() we synchronize with the fd_server closing the
 	 * socket.
@@ -1066,13 +1101,15 @@ parse_extra_buffers_indexes(struct Global *g)
 
 	for (i = 0; i < g->extra_buffers_num; i++) {
 		if (e_buf_index == 0) {
-			printf("Extra buffer index = 0\n");
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Extra buffer index = 0\n");
 			return -1;
 		}
 
 		u_buf = malloc(sizeof(*u_buf));
 		if (u_buf == NULL) {
-			perror("malloc()");
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
+			               "malloc()");
 			return -1;
 		}
 		u_buf->buf_idx = e_buf_index;
@@ -1198,7 +1235,7 @@ main(int argc, char **argv)
 	g->request_from_fd_server = /*true=*/1;
 	g->sequential_fill        = /*false=*/0;
 	g->extra_buffers_num      = 0;
-	g->verbose                = 0;
+	g->verbosity_level        = 0;
 	g->num_loops              = 1;
 	g->extra_buffers_num      = 0;
 	LIST_INIT(&g->normal_buffers_head);
@@ -1208,7 +1245,7 @@ main(int argc, char **argv)
 	       -1) {
 		switch (opt) {
 		case 'h':
-			usage();
+			usage(stdout);
 			return 0;
 
 		case 'c':
@@ -1228,10 +1265,11 @@ main(int argc, char **argv)
 			break;
 
 		case 'e':
-			printf("sdsdas\n");
 			g->extra_buffers_num = atoi(optarg);
 			if (g->extra_buffers_num <= 0) {
-				printf("Invalid number of extra buffers\n");
+				verbose_print(
+				        g->verbosity_level, LV_ERROR_MSG,
+				        "Invalid number of extra buffers\n");
 				exit(EXIT_FAILURE);
 			};
 			break;
@@ -1239,7 +1277,8 @@ main(int argc, char **argv)
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
 			if (ret == -1) {
-				printf("Invalid source MAC address\n");
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Invalid source MAC address\n");
 				exit(EXIT_FAILURE);
 			}
 			break;
@@ -1247,7 +1286,9 @@ main(int argc, char **argv)
 		case 'd':
 			ret = parse_mac_address(optarg, g->dst_mac);
 			if (ret == -1) {
-				printf("Invalid destination MAC address\n");
+				verbose_print(
+				        g->verbosity_level, LV_ERROR_MSG,
+				        "Invalid destination MAC address\n");
 				exit(EXIT_FAILURE);
 			}
 			break;
@@ -1279,23 +1320,28 @@ main(int argc, char **argv)
 			int ret = 0;
 
 			if (g->num_events >= MAX_EVENTS) {
-				printf("Too many events\n");
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Too many events\n");
 				exit(EXIT_FAILURE);
 			}
 
 			if (opt == 'p') {
 				ret = parse_pause_event(
-				        optarg, g->events + g->num_events);
+				        optarg, g->events + g->num_events,
+				        g->verbosity_level);
 			} else {
 				ret = parse_txrx_event(
 				        optarg,
 				        (opt == 't') ? EVENT_TYPE_TX
 				                     : EVENT_TYPE_RX,
-				        g->events + g->num_events);
+				        g->events + g->num_events,
+				        g->verbosity_level);
 			}
 			if (ret) {
-				printf("Invalid event syntax '%s'\n", optarg);
-				usage();
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Invalid event syntax '%s'\n",
+				              optarg);
+				usage(stderr);
 				exit(EXIT_FAILURE);
 			}
 			g->num_events++;
@@ -1307,33 +1353,39 @@ main(int argc, char **argv)
 			break;
 
 		case 'v':
-			g->verbose++;
+			g->verbosity_level++;
 			break;
 
 		case 'C':
 			g->num_loops = atoi(optarg);
 			if (g->num_loops == 0) {
-				printf("Invalid -C option '%s'\n", optarg);
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Invalid -C option '%s'\n",
+				              optarg);
 				exit(EXIT_FAILURE);
 			}
 			break;
 
 		default:
-			printf("Unrecognized option %c\n", opt);
-			usage();
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Unrecognized option %c\n", opt);
+			usage(stderr);
 			exit(EXIT_FAILURE);
 		}
 	}
 
 	if (!g->ifname) {
-		printf("Missing ifname\n");
-		usage();
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Missing ifname\n");
+		usage(stderr);
 		exit(EXIT_FAILURE);
 	}
 
 	if (g->request_from_fd_server == 1 && g->extra_buffers_num > 0) {
-		printf("Extra buffers can only be used when requesting an "
-		       "interface directly\n");
+		verbose_print(
+		        g->verbosity_level, LV_ERROR_MSG,
+		        "Extra buffers can only be used when requesting an "
+		        "interface directly\n");
 		exit(EXIT_FAILURE);
 	}
 
@@ -1352,8 +1404,8 @@ main(int argc, char **argv)
 		g->nmd = get_if_fd(g, g->ifname);
 	}
 	if (g->nmd == NULL) {
-		;
-		printf("Failed to nm_open(%s)\n", g->ifname);
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Failed to nm_open(%s)\n", g->ifname);
 		exit(EXIT_FAILURE);
 	}
 
@@ -1364,7 +1416,8 @@ main(int argc, char **argv)
 		g->extra_buffers_indexes =
 		        malloc(g->extra_buffers_num * sizeof(uint32_t));
 		if (g->extra_buffers_indexes == NULL) {
-			perror("malloc()");
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
+			               "malloc()");
 			exit(EXIT_FAILURE);
 		}
 
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 1cdbf794b..a18ee32a7 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -3,6 +3,10 @@
 # Runs all the tests using randomized values for number of packets, fill
 # character and packets length.
 ################################################################################
+source test_lib
+
+modprobe netmap
+check_success $? "Failed to load netmap."
 
 random_num="$((65 + $RANDOM % 58))"
 # https://stackoverflow.com/a/10503163
@@ -28,5 +32,14 @@ echo ""
 PATH="$(pwd):${PATH}"
 
 for test in tests/*_test ; do
-	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
+	if [ $? != 0 ] ; then
+		# Select verbosity of output during after an error occurred:
+		#    -v    -> prints error messages
+		#    -vv   -> -v, send and receive actions
+		#    -vvv  -> -vv and packet building
+		#    -vvvv -> -vvv and arguments parsing
+		$test -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+		exit $?
+	fi
 done
\ No newline at end of file
diff --git a/utils/test_lib b/utils/test_lib
index 46d00fe64..3a5906333 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -19,7 +19,7 @@ function redirect_std() {
 #   None
 ################################################################################
 function stdout_echo() {
-	echo "$@" 1>&3
+	echo "$@"
 }
 
 ################################################################################
@@ -241,6 +241,7 @@ function send_recv_usage() {
 	stdout_echo "       [-f fill_character]"
 	stdout_echo "       [-n packets_to_send]"
 	stdout_echo "       [-q (sequential send/read)]"
+	stdout_echo "       [-v (increases verbosity level)]"
 }
 
 ################################################################################
@@ -249,7 +250,7 @@ function send_recv_usage() {
 #   It must be always called like like this 'parse_arguments "$@"'
 ################################################################################
 function parse_send_recv_arguments() {
-	while getopts "hql:f:n:" opt; do
+	while getopts "hvql:f:n:" opt; do
 		case $opt in
 			l) len="$OPTARG"
 			;;
@@ -259,6 +260,12 @@ function parse_send_recv_arguments() {
 			;;
 			q) seq="-q"
 			;;
+			v) if [ -z $verbosity ] ; then
+					verbosity="-v"
+				else
+					erbosity="${verbosity}v"
+			   fi
+			;;
 			h) send_recv_usage ; exit 0
 			;;
 			\?) send_recv_usage ; exit 1
diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
index 526765c3f..1e056dd03 100755
--- a/utils/tests/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -5,23 +5,24 @@
 ################################################################################
 source test_lib
 
-redirect_std
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 restart_fd_server
 
 bridge="vale0"
 port="v0"
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
-functional -i "${bridge}:${port}/x"
+functional "$verbosity" -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional -I "${bridge}:${port}"
+functional "$verbosity" -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-functional -I "${bridge}:${port}/x"
+functional "$verbosity" -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/exclusive_open_persistent_vale_port_test b/utils/tests/exclusive_open_persistent_vale_port_test
index a70439703..05f303309 100755
--- a/utils/tests/exclusive_open_persistent_vale_port_test
+++ b/utils/tests/exclusive_open_persistent_vale_port_test
@@ -5,7 +5,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 restart_fd_server
 
@@ -15,16 +16,16 @@ create_vale_persistent_port "$port"
 attach_to_vale_bridge "$bridge" "$port"
 
 # We open the persistent port with the exclusive flag from the file descriptor.
-functional -i "${bridge}:${port}/x"
+functional "$verbosity" -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional -I "${bridge}:${port}"
+functional "$verbosity" -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-functional -I "${bridge}:${port}/x"
+functional "$verbosity" -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/exclusive_open_pipe_test b/utils/tests/exclusive_open_pipe_test
index f7edeeaf0..d0ce59c22 100755
--- a/utils/tests/exclusive_open_pipe_test
+++ b/utils/tests/exclusive_open_pipe_test
@@ -5,22 +5,23 @@
 ################################################################################
 source test_lib
 
-redirect_std
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 restart_fd_server
 
 pipe="pipeA{1"
 # We open pipeA{1 with the exclusive flag from the file descriptor.
-functional -i "netmap:${pipe}/x"
+functional "$verbosity" -i "netmap:${pipe}/x"
 check_success $? "exclusive-open netmap:${pipe}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional -I "netmap:${pipe}"
+functional "$verbosity" -I "netmap:${pipe}"
 check_failure $? "no-open netmap:${pipe}"
 
 # Check that another exclusive open request fails.
-functional -I "netmap:${pipe}/x"
+functional "$verbosity" -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 3d8a47f33..5ed4a8dce 100755
--- a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -9,9 +9,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
@@ -23,17 +22,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "vale0:v1"
+functional "$verbosity" -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional -i "vale0:v2"
+functional "$verbosity" -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v0 ---> v1, v2
-functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional "$verbosity" -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index 1c66bbfaa..8a78fdad7 100755
--- a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -10,9 +10,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
@@ -30,17 +29,17 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "vale0:v0"
+functional "$verbosity" -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional -i "vale0:v1"
+functional "$verbosity" -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # v2 ---> v0, v1
-functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional "$verbosity" -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
index 9ee01cd31..133bbc7f2 100755
--- a/utils/tests/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -9,9 +9,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
@@ -23,13 +22,13 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:pipeA{1"
+functional "$verbosity" -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
 
 # pipeA}1 ---> pipeA{1
-functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional "$verbosity" -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e2=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/learning_bridge_test b/utils/tests/learning_bridge_test
index a44fa67ca..d6b2f3e14 100755
--- a/utils/tests/learning_bridge_test
+++ b/utils/tests/learning_bridge_test
@@ -11,11 +11,11 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
+
 s_MAC=$(get_random_MAC)
 d_MAC="FF:FF:FF:FF:FF:FF"
 
@@ -23,19 +23,19 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
-functional -i vale0:v2
+functional "$verbosity" -i vale0:v2
 check_success $? "pre-open vale0:v2"
 
 # First send, every port should receive the frame.
-functional -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+functional "$verbosity" -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p1=$!
-functional -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+functional "$verbosity" -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p2=$!
-functional -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
+functional "$verbosity" -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
 e3=$?
 wait $p1
 e1=$?
@@ -46,11 +46,11 @@ check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-functional -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
+functional "$verbosity" -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
 p4=$!
-functional -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
+functional "$verbosity" -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
 p5=$!
-functional -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
+functional "$verbosity" -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index 5fa277cf3..e6e0493aa 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -11,25 +11,27 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
-restart_fd_server
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 fill='h'
 len=274
 num_send=10
 num_recv=7
 pipe="pipeA"
+
+restart_fd_server
+
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:${pipe}{1"
+functional "$verbosity" -i "netmap:${pipe}{1"
 check_success $? "pre-open netmap:${pipe}{1"
-functional -i "netmap:${pipe}}1"
+functional "$verbosity" -i "netmap:${pipe}}1"
 check_success $? "pre-open netmap:${pipe}}1"
 
-functional -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
+functional "$verbosity" -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
 p1=$!
-functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional "$verbosity" -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 e2=$?
 wait $p1
 e1=$?
@@ -68,7 +70,7 @@ check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
 
 
 num_send="$(($ring_avail_sends + 1))"
-functional -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional "$verbosity" -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/persistent_vale_port_destroy b/utils/tests/persistent_vale_port_destroy
index 778d9ef89..4a1b22a8a 100755
--- a/utils/tests/persistent_vale_port_destroy
+++ b/utils/tests/persistent_vale_port_destroy
@@ -5,7 +5,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 bridge="vale0"
 bridgeA="${bridge}A"
diff --git a/utils/tests/persistent_vale_port_double_attach b/utils/tests/persistent_vale_port_double_attach
index 2fd271c5b..81260b5d1 100755
--- a/utils/tests/persistent_vale_port_double_attach
+++ b/utils/tests/persistent_vale_port_double_attach
@@ -6,7 +6,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 bridge="vale0"
 bridgeA="${bridge}A"
diff --git a/utils/tests/persistent_vale_port_double_create b/utils/tests/persistent_vale_port_double_create
index 6fe3321e2..b58b43d1e 100755
--- a/utils/tests/persistent_vale_port_double_create
+++ b/utils/tests/persistent_vale_port_double_create
@@ -5,7 +5,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
+parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 
 bridge="vale0"
 bridgeA="${bridge}A"
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
index ab3ddc4f0..478694530 100755
--- a/utils/tests/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -12,9 +12,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -24,17 +23,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i vale0:v0/r
+functional "$verbosity" -i vale0:v0/r
 check_success $? "pre-open vale0:v0/r"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +41,7 @@ check_success $e1 "receive-${num} vale0:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
index d2f56591b..efe38f20b 100755
--- a/utils/tests/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -13,9 +13,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -27,17 +26,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i netmap:v0/r
+functional "$verbosity" -i netmap:v0/r
 check_success $? "pre-open netmap:v0/r"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -45,7 +44,7 @@ check_success $e1 "receive-${num} netmap:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
index 2bce38cf5..920ca2957 100755
--- a/utils/tests/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -13,9 +13,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -25,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:pipe{1"
+functional "$verbosity" -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional -i "netmap:pipe{1/r"
+functional "$verbosity" -i "netmap:pipe{1/r"
 check_success $? "pre-open netmap:pipe{1/r"
-functional -i "netmap:pipe}1"
+functional "$verbosity" -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-functional -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +42,7 @@ check_success $e1 "receive-${num}${seq} netmap:pipe{1/r"
 check_success $e2 "send-${num}${seq} netmap:pipe}1"
 
 # Then we read from pipe{1
-functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index 906fb6f97..2dcea34d2 100755
--- a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -12,9 +12,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -24,18 +23,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "vale0:v0"
+functional "$verbosity" -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional -i "vale0:v0/z"
+functional "$verbosity" -i "vale0:v0/z"
 check_success $? "pre-open vale0:v0/z"
-functional -i "vale0:v1"
+functional "$verbosity" -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional "$verbosity" -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -44,9 +43,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
index 73887b3ff..35c64a9a5 100755
--- a/utils/tests/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -13,9 +13,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -27,18 +26,18 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "vale0:v0"
+functional "$verbosity" -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional -i "netmap:v0/z"
+functional "$verbosity" -i "netmap:v0/z"
 check_success $? "pre-open netmap:v0/z"
-functional -i "vale0:v1"
+functional "$verbosity" -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional "$verbosity" -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -47,9 +46,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
index 9dcfac05e..3774d9aa9 100755
--- a/utils/tests/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -12,9 +12,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -24,18 +23,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:pipe{1"
+functional "$verbosity" -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional -i "netmap:pipe{1/z"
+functional "$verbosity" -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-functional -i "netmap:pipe}1"
+functional "$verbosity" -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -44,9 +43,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-functional -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
index 191fe63d9..15d9132b3 100755
--- a/utils/tests/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -10,9 +10,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -22,17 +21,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i vale0:v0/t
+functional "$verbosity" -i vale0:v0/t
 check_success $? "pre-open vale0:v0/t"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -40,7 +39,7 @@ check_success $e1 "receive-${num} vale0:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
index e0def41f9..0797178d5 100755
--- a/utils/tests/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -11,9 +11,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -25,17 +24,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i netmap:v0/t
+functional "$verbosity" -i netmap:v0/t
 check_success $? "pre-open netmap:v0/t"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +42,7 @@ check_success $e1 "receive-${num} netmap:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
index 11439e5e2..e094febe3 100755
--- a/utils/tests/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -13,9 +13,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -25,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:pipe{1"
+functional "$verbosity" -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional -i "netmap:pipe{1/t"
+functional "$verbosity" -i "netmap:pipe{1/t"
 check_success $? "pre-open netmap:pipe{1/t"
-functional -i "netmap:pipe}1"
+functional "$verbosity" -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-functional -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +42,7 @@ check_success $e1 "receive-${num} netmap:pipe{1/t"
 check_success $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-functional -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
index 128df37d4..fadb030ea 100755
--- a/utils/tests/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -9,9 +9,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
@@ -21,19 +20,19 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "vale0:v0"
+functional "$verbosity" -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional -i "vale0:v1"
+functional "$verbosity" -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional -i "vale0:v2"
+functional "$verbosity" -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
 e3=$?
 wait $p1
 e1=$?
@@ -44,11 +43,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p4=$!
-functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p5=$!
-functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
index 7a2ba00a0..3a6538624 100755
--- a/utils/tests/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -10,9 +10,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
@@ -28,19 +27,19 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "vale0:v0"
+functional "$verbosity" -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional -i "vale0:v1"
+functional "$verbosity" -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional -i "vale0:v2"
+functional "$verbosity" -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
 e3=$?
 wait $p1
 e1=$?
@@ -51,11 +50,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p4=$!
-functional -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p5=$!
-functional -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
index 6a7afdd8a..aaf6507f8 100755
--- a/utils/tests/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -9,9 +9,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-c}"
 len="${len:-274}"
 num="${num:-1}"
@@ -21,15 +20,15 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:pipeA{1"
+functional "$verbosity" -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
-functional -i "netmap:pipeA}1"
+functional "$verbosity" -i "netmap:pipeA}1"
 check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-functional -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -37,9 +36,9 @@ check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-functional -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e2=$?
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/send_rec_veth_test
index b14c626e6..9520bf908 100755
--- a/utils/tests/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -9,9 +9,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -24,15 +23,15 @@ exit 0
 create_veth_interfaces "veth1"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i netmap:veth1A
+functional "$verbosity" -i netmap:veth1A
 check_success $? "pre-open netmap:veth1A"
-functional -i netmap:veth1B
+functional "$verbosity" -i netmap:veth1B
 check_success $? "pre-open netmap:veth1B"
 
 # veth1B --> veth1A
-functional -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -40,9 +39,9 @@ check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
 # veth1A --> veth1B
-functional -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
index c28cafa33..ecb98d136 100755
--- a/utils/tests/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -13,9 +13,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -25,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i vale0:v0/z
+functional "$verbosity" -i vale0:v0/z
 check_success $? "pre-open vale0:v0/z"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,7 +42,7 @@ check_success $e1 "receive-${num} vale0:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
index 99384480b..ab025580a 100755
--- a/utils/tests/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -14,9 +14,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -28,17 +27,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i vale0:v0
+functional "$verbosity" -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional -i netmap:v0/z
+functional "$verbosity" -i netmap:v0/z
 check_success $? "pre-open netmap:v0/z"
-functional -i vale0:v1
+functional "$verbosity" -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -46,7 +45,7 @@ check_success $e1 "receive-${num} netmap:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index aa1871c7e..a53267538 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -13,9 +13,8 @@
 ################################################################################
 source test_lib
 
-redirect_std
-
 parse_send_recv_arguments "$@"
+verbosity="${verbosity:-}"
 fill="${fill:-d}"
 len="${len:-150}"
 num="${num:-1}"
@@ -25,18 +24,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional -i "netmap:pipe{1"
+functional "$verbosity" -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional -i "netmap:pipe{1/z"
+functional "$verbosity" -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-functional -i "netmap:pipe}1"
+functional "$verbosity" -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -45,9 +44,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-functional -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
+functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
+functional "$verbosity" -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?

From 34ea82e22fd82c3f05e23463567f5dca4378f32b Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 2 Jul 2018 13:08:06 +0200
Subject: [PATCH 0982/2207] Comments

---
 utils/functional.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/utils/functional.c b/utils/functional.c
index a99b202ed..ee3c95552 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -438,6 +438,7 @@ put_one_packet(struct Global *g, struct netmap_ring *ring)
 	              frags);
 }
 
+/* Used for multi-packets sequential send/receive actions */
 char
 next_fill(char cur_fill)
 {
@@ -824,6 +825,7 @@ usage(FILE *stream)
 	        "40:b:2\n");
 }
 
+/* TODO: Move functions to communicate to the fd_server to another file */
 /* Copied from nm_open() */
 void
 fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
@@ -1248,10 +1250,12 @@ main(int argc, char **argv)
 			usage(stdout);
 			return 0;
 
+		/* TODO: move this option to fd_server */
 		case 'c':
 			stop_fd_server(g);
 			return 0;
 
+		/* TODO: move this option to fd_server */
 		case 'o':
 			start_fd_server(g);
 			return 0;

From fa55ad2c9de770bd391780c9c00acec05107b170 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Mon, 2 Jul 2018 16:15:44 +0200
Subject: [PATCH 0983/2207] updated functional.c help output

---
 utils/functional.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index ee3c95552..fc188a763 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -795,14 +795,16 @@ static void
 usage(FILE *stream)
 {
 	fprintf(stream,
-	        "usage: ./functional [-h]\n"
-	        "    [-c (shuts down the fd server)]\n"
-	        "    [-o (starts the fd server)]\n"
-	        "    [-i NETMAP_PORT (requests the interface from the fd "
-	        "server)]\n"
-	        "    [-I NETMAP_PORT (directly opens the interface)]\n"
-	        "    [-s source MAC address (=0:0:0:0:0:0)]\n"
-	        "    [-d destination MAC address (=FF:FF:FF:FF:FF:FF)]\n"
+	        "usage: ./functional {-c | -o | -i | -I}\n"
+	        "Required:\n"
+	        "    -c (shuts down the fd server),\n"
+	        "    -o (starts the fd server),\n"
+	        "    -i NETMAP_PORT (requests the interface from the fd "
+	        "server),\n"
+	        "    -I NETMAP_PORT (directly opens the interface)\n"
+	        "Optional:\n"
+	        "    [-s SOURCE MAC ADDRESS (=0:0:0:0:0:0)]\n"
+	        "    [-d DESTINATION MAC ADDRESS (=FF:FF:FF:FF:FF:FF)]\n"
 	        "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	        "    [-T TIMEOUT_SECS (=1)]\n"
 	        "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
@@ -816,8 +818,8 @@ usage(FILE *stream)
 	        "    [-n (exit status = 0 <==> no frames were received)]\n"
 	        "    [-q (during multi-packets send/receive increments fill "
 	        "character after each operation)]\n"
-	        "    [-e (use extra buffers to send packets, "
-	        "can only be used when directly opening an interface)]\n"
+	        "    [-e NUM (use NUM extra buffers to send packets, "
+	        "can only be used when with -I)]\n"
 	        "    [-v (increment verbosity level)]\n"
 	        "    [-C [NUM (=1)] (how many times to run the events)]\n"
 	        "\nExample:\n"

From 087b05fb1683fb587b51ced10a96f37023fcd006 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 4 Jul 2018 21:41:58 +0200
Subject: [PATCH 0984/2207] Moved modprobe netmap from randomized_tests to
 GNUmakefile (as a conditional statement based on the current os)

---
 utils/GNUmakefile                             |  5 +-
 utils/fd_server.c                             | 10 +--
 utils/functional.c                            | 72 +++++++++----------
 utils/randomized_tests                        |  5 --
 .../exclusive_open_ephemeral_vale_port_test   |  7 +-
 5 files changed, 46 insertions(+), 53 deletions(-)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index efcedc6c6..2083feae1 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -36,12 +36,9 @@ PREFIX ?= /usr/local
 all: $(PROGS)
 
 inttest:
+	$(shell if [ "$(shell uname)" = "Linux" ] ; then modprobe netmap ;fi)
 	./randomized_tests
 
-functional: fd_server.h
-
-fd_server: fd_server.h
-
 all-x86: $(PROGS) $(X86PROGS)
 
 kern_test: testmod/kern_test.c
diff --git a/utils/fd_server.c b/utils/fd_server.c
index 8b9962b05..dc87c9e50 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -200,7 +200,7 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 }
 
 int
-handle_request(int socket)
+handle_request(int accept_socket, int listen_socket)
 {
 	struct fd_response res;
 	struct fd_request req;
@@ -209,7 +209,7 @@ handle_request(int socket)
 	int ret;
 
 	memset(&req, 0, sizeof(req));
-	amount = recv(socket, &req, sizeof(struct fd_request), 0);
+	amount = recv(accept_socket, &req, sizeof(struct fd_request), 0);
 	if (amount == -1) {
 		printf("error while receiving the request\n");
 		return -1;
@@ -229,13 +229,15 @@ handle_request(int socket)
 		return 0;
 	case FD_STOP:
 		printf("shutting down\n");
+		close(accept_socket);
+		close(listen_socket);
 		exit(EXIT_SUCCESS);
 		break;
 	default:
 		res.result = EOPNOTSUPP;
 	}
 
-	ret = send_fd(socket, fd, &res, sizeof(struct fd_response));
+	ret = send_fd(accept_socket, fd, &res, sizeof(struct fd_response));
 	if (ret == -1) {
 		printf("error while sending the reponse\n");
 	}
@@ -287,7 +289,7 @@ main_loop(void)
 			exit(EXIT_FAILURE);
 		}
 
-		ret = handle_request(conn_fd);
+		ret = handle_request(conn_fd, socket_fd);
 		if (ret == -1) {
 			printf("error while handling a request\n");
 		}
diff --git a/utils/functional.c b/utils/functional.c
index fc188a763..bec462f4b 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -166,7 +166,7 @@ fill_packet_field(struct Global *g, unsigned offset, const char *content,
                   unsigned content_len)
 {
 	if (offset + content_len > sizeof(g->pktm)) {
-		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		verbose_print(g->verbosity_level, 0 /*change after */,
 		              "Packet layout overflow: %u + %u > %lu\n", offset,
 		              content_len, sizeof(g->pktm));
 		cleanup(g);
@@ -363,7 +363,7 @@ tx_flush(struct Global *g)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -465,7 +465,7 @@ tx(struct Global *g, unsigned packets_num)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -544,7 +544,7 @@ rx_check(struct Global *g)
 	unsigned i;
 
 	if (g->pktr_len != g->pktm_len) {
-		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		verbose_print(g->verbosity_level, 0 /*change after */,
 		              "Received packet length (%u) different from "
 		              "expected (%u bytes)\n",
 		              g->pktr_len, g->pktm_len);
@@ -553,7 +553,7 @@ rx_check(struct Global *g)
 
 	for (i = 0; i < g->pktr_len; i++) {
 		if (g->pktr[i] != g->pktm[i]) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "Received packet differs from model at "
 			              "offset %u (0x%02x!=0x%02x)\n",
 			              i, g->pktr[i], (uint8_t)g->pktm[i]);
@@ -577,7 +577,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 
 		if (g->pktr_len + slot->len > sizeof(g->pktr)) {
 			/* Sanity check. */
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "Error: received packet too "
 			              "large "
 			              "(>= %u bytes) ",
@@ -595,7 +595,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 		}
 
 		if (head == ring->tail) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "warning: truncated packet "
 			              "(len=%u)\n",
 			              g->pktr_len);
@@ -629,7 +629,7 @@ rx(struct Global *g, unsigned packets_num)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "%s: Timeout\n", __func__);
 			/* -n flag */
 			return g->success_if_no_receive == 1 ? 0 : -1;
@@ -874,7 +874,7 @@ connect_to_fd_server(struct Global *g)
 
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "socket()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "socket()");
 		return -1;
 	}
 
@@ -885,7 +885,7 @@ connect_to_fd_server(struct Global *g)
 	while (connect(socket_fd, (const struct sockaddr *)&name,
 	               sizeof(struct sockaddr_un)) == -1) {
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -905,7 +905,7 @@ start_fd_server(struct Global *g)
 
 	pid = fork();
 	if (pid < 0) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "fork()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "fork()");
 		exit(EXIT_FAILURE);
 	}
 	if (pid > 0) {
@@ -914,13 +914,13 @@ start_fd_server(struct Global *g)
 	}
 
 	if (execl("fd_server", "fd_server", (char *)NULL)) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "exec()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "exec()");
 		exit(EXIT_FAILURE);
 	}
 
 	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
-		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		verbose_print(g->verbosity_level, 0 /*change after */,
 		              "Can't connect to fd_server\n");
 		exit(EXIT_FAILURE);
 	}
@@ -993,27 +993,27 @@ get_if_fd(struct Global *g, const char *if_name)
 	strncpy(req.if_name, if_name, sizeof(req.if_name));
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret < 0) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "send()");
 		return NULL;
 	}
 
 	memset(&res, 0, sizeof(res));
 	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(res));
 	if (ret == -1) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "recv_fd()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "recv_fd()");
 		return NULL;
 	}
 	close(socket_fd);
 
 	nmd = malloc(sizeof(*nmd));
 	if (nmd == NULL) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "malloc()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "malloc()");
 		return NULL;
 	}
 
 	fill_nm_desc(nmd, &res.req, new_fd);
 	if (nm_mmap(nmd, NULL) != 0) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "nm_mmap()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "nm_mmap()");
 		return NULL;
 	}
 
@@ -1038,7 +1038,7 @@ release_if_fd(struct Global *g, const char *if_name)
 
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret <= 0) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "send()");
 	}
 
 	close(socket_fd);
@@ -1047,14 +1047,11 @@ release_if_fd(struct Global *g, const char *if_name)
 void
 stop_fd_server(struct Global *g)
 {
-	unsigned old_timeout_secs = g->timeout_secs;
 	struct fd_request req;
 	int socket_fd;
 	int ret;
 
-	g->timeout_secs = 0;
-	socket_fd       = connect_to_fd_server(g);
-	g->timeout_secs = old_timeout_secs;
+	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
 		verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
 		              "fd_server alredy down\n");
@@ -1067,7 +1064,7 @@ stop_fd_server(struct Global *g)
 	req.action = FD_STOP;
 	ret        = send(socket_fd, &req, sizeof(req), 0);
 	if (ret == -1) {
-		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
+		verbose_perror(g->verbosity_level, 0 /*change after */, "send()");
 	}
 	/* By calling recv() we synchronize with the fd_server closing the
 	 * socket.
@@ -1105,14 +1102,14 @@ parse_extra_buffers_indexes(struct Global *g)
 
 	for (i = 0; i < g->extra_buffers_num; i++) {
 		if (e_buf_index == 0) {
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "Extra buffer index = 0\n");
 			return -1;
 		}
 
 		u_buf = malloc(sizeof(*u_buf));
 		if (u_buf == NULL) {
-			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
+			verbose_perror(g->verbosity_level, 0 /*change after */,
 			               "malloc()");
 			return -1;
 		}
@@ -1274,7 +1271,7 @@ main(int argc, char **argv)
 			g->extra_buffers_num = atoi(optarg);
 			if (g->extra_buffers_num <= 0) {
 				verbose_print(
-				        g->verbosity_level, LV_ERROR_MSG,
+				        g->verbosity_level, 0 /*change after */,
 				        "Invalid number of extra buffers\n");
 				exit(EXIT_FAILURE);
 			};
@@ -1283,7 +1280,7 @@ main(int argc, char **argv)
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
 			if (ret == -1) {
-				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				verbose_print(g->verbosity_level, 0 /*change after */,
 				              "Invalid source MAC address\n");
 				exit(EXIT_FAILURE);
 			}
@@ -1293,7 +1290,7 @@ main(int argc, char **argv)
 			ret = parse_mac_address(optarg, g->dst_mac);
 			if (ret == -1) {
 				verbose_print(
-				        g->verbosity_level, LV_ERROR_MSG,
+				        g->verbosity_level, 0 /*change after */,
 				        "Invalid destination MAC address\n");
 				exit(EXIT_FAILURE);
 			}
@@ -1301,6 +1298,7 @@ main(int argc, char **argv)
 
 		case 'i':
 			g->ifname = optarg;
+			printf("g->if_name = %s\n", g->ifname);
 			break;
 
 		case 'I':
@@ -1326,7 +1324,7 @@ main(int argc, char **argv)
 			int ret = 0;
 
 			if (g->num_events >= MAX_EVENTS) {
-				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				verbose_print(g->verbosity_level, 0 /*change after */,
 				              "Too many events\n");
 				exit(EXIT_FAILURE);
 			}
@@ -1344,7 +1342,7 @@ main(int argc, char **argv)
 				        g->verbosity_level);
 			}
 			if (ret) {
-				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				verbose_print(g->verbosity_level, 0 /*change after */,
 				              "Invalid event syntax '%s'\n",
 				              optarg);
 				usage(stderr);
@@ -1365,7 +1363,7 @@ main(int argc, char **argv)
 		case 'C':
 			g->num_loops = atoi(optarg);
 			if (g->num_loops == 0) {
-				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				verbose_print(g->verbosity_level, 0 /*change after */,
 				              "Invalid -C option '%s'\n",
 				              optarg);
 				exit(EXIT_FAILURE);
@@ -1373,15 +1371,15 @@ main(int argc, char **argv)
 			break;
 
 		default:
-			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			verbose_print(g->verbosity_level, 0 /*change after */,
 			              "Unrecognized option %c\n", opt);
 			usage(stderr);
 			exit(EXIT_FAILURE);
 		}
 	}
 
-	if (!g->ifname) {
-		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+	if (g->ifname == NULL) {
+		verbose_print(g->verbosity_level, 0 /*change after */,
 		              "Missing ifname\n");
 		usage(stderr);
 		exit(EXIT_FAILURE);
@@ -1389,7 +1387,7 @@ main(int argc, char **argv)
 
 	if (g->request_from_fd_server == 1 && g->extra_buffers_num > 0) {
 		verbose_print(
-		        g->verbosity_level, LV_ERROR_MSG,
+		        g->verbosity_level, 0 /*change after */,
 		        "Extra buffers can only be used when requesting an "
 		        "interface directly\n");
 		exit(EXIT_FAILURE);
@@ -1410,7 +1408,7 @@ main(int argc, char **argv)
 		g->nmd = get_if_fd(g, g->ifname);
 	}
 	if (g->nmd == NULL) {
-		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		verbose_print(g->verbosity_level, 0 /*change after */,
 		              "Failed to nm_open(%s)\n", g->ifname);
 		exit(EXIT_FAILURE);
 	}
@@ -1422,7 +1420,7 @@ main(int argc, char **argv)
 		g->extra_buffers_indexes =
 		        malloc(g->extra_buffers_num * sizeof(uint32_t));
 		if (g->extra_buffers_indexes == NULL) {
-			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
+			verbose_perror(g->verbosity_level, 0 /*change after */,
 			               "malloc()");
 			exit(EXIT_FAILURE);
 		}
diff --git a/utils/randomized_tests b/utils/randomized_tests
index a18ee32a7..0cf9a214e 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -3,11 +3,6 @@
 # Runs all the tests using randomized values for number of packets, fill
 # character and packets length.
 ################################################################################
-source test_lib
-
-modprobe netmap
-check_success $? "Failed to load netmap."
-
 random_num="$((65 + $RANDOM % 58))"
 # https://stackoverflow.com/a/10503163
 random_fill=$(printf \\$(printf '%03o' $random_num))
diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
index 1e056dd03..062641998 100755
--- a/utils/tests/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -5,16 +5,17 @@
 ################################################################################
 source test_lib
 
+restart_fd_server
+
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 
-restart_fd_server
-
 bridge="vale0"
 port="v0"
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
+echo "functional ${verbosity} -i ${bridge}:${port}/x"
 functional "$verbosity" -i "${bridge}:${port}/x"
-check_success $? "exclusive-open ${bridge}:${port}/x"
+check_success $? "exclusive-open verbosity ${verbosity} ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().

From c441213e79b4ebdca5f1884c5958d4a4e4a3fcc5 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 4 Jul 2018 21:28:25 +0200
Subject: [PATCH 0985/2207] After receive an FD_STOP request fd_server first
 closes the "listening socket", then the "communication socket". This way the
 command following the fd_server restart cannot connect to the old fd_server.

---
 utils/fd_server.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index dc87c9e50..b54a7258c 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -229,8 +229,8 @@ handle_request(int accept_socket, int listen_socket)
 		return 0;
 	case FD_STOP:
 		printf("shutting down\n");
-		close(accept_socket);
 		close(listen_socket);
+		close(accept_socket);
 		exit(EXIT_SUCCESS);
 		break;
 	default:

From 24277bf2de5b9084dd33b02133bc5c2b45a596f9 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 4 Jul 2018 21:29:42 +0200
Subject: [PATCH 0986/2207] Fixed verbosity levels.

---
 utils/functional.c | 65 +++++++++++++++++++++++-----------------------
 1 file changed, 32 insertions(+), 33 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index bec462f4b..f8bcfed92 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -166,7 +166,7 @@ fill_packet_field(struct Global *g, unsigned offset, const char *content,
                   unsigned content_len)
 {
 	if (offset + content_len > sizeof(g->pktm)) {
-		verbose_print(g->verbosity_level, 0 /*change after */,
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
 		              "Packet layout overflow: %u + %u > %lu\n", offset,
 		              content_len, sizeof(g->pktm));
 		cleanup(g);
@@ -363,7 +363,7 @@ tx_flush(struct Global *g)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -465,7 +465,7 @@ tx(struct Global *g, unsigned packets_num)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -544,7 +544,7 @@ rx_check(struct Global *g)
 	unsigned i;
 
 	if (g->pktr_len != g->pktm_len) {
-		verbose_print(g->verbosity_level, 0 /*change after */,
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
 		              "Received packet length (%u) different from "
 		              "expected (%u bytes)\n",
 		              g->pktr_len, g->pktm_len);
@@ -553,7 +553,7 @@ rx_check(struct Global *g)
 
 	for (i = 0; i < g->pktr_len; i++) {
 		if (g->pktr[i] != g->pktm[i]) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "Received packet differs from model at "
 			              "offset %u (0x%02x!=0x%02x)\n",
 			              i, g->pktr[i], (uint8_t)g->pktm[i]);
@@ -577,7 +577,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 
 		if (g->pktr_len + slot->len > sizeof(g->pktr)) {
 			/* Sanity check. */
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "Error: received packet too "
 			              "large "
 			              "(>= %u bytes) ",
@@ -595,7 +595,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 		}
 
 		if (head == ring->tail) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "warning: truncated packet "
 			              "(len=%u)\n",
 			              g->pktr_len);
@@ -629,7 +629,7 @@ rx(struct Global *g, unsigned packets_num)
 		}
 
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "%s: Timeout\n", __func__);
 			/* -n flag */
 			return g->success_if_no_receive == 1 ? 0 : -1;
@@ -874,7 +874,7 @@ connect_to_fd_server(struct Global *g)
 
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "socket()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "socket()");
 		return -1;
 	}
 
@@ -885,7 +885,7 @@ connect_to_fd_server(struct Global *g)
 	while (connect(socket_fd, (const struct sockaddr *)&name,
 	               sizeof(struct sockaddr_un)) == -1) {
 		if (elapsed_ms > g->timeout_secs * 1000) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "%s: Timeout\n", __func__);
 			return -1;
 		}
@@ -905,7 +905,7 @@ start_fd_server(struct Global *g)
 
 	pid = fork();
 	if (pid < 0) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "fork()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "fork()");
 		exit(EXIT_FAILURE);
 	}
 	if (pid > 0) {
@@ -914,13 +914,13 @@ start_fd_server(struct Global *g)
 	}
 
 	if (execl("fd_server", "fd_server", (char *)NULL)) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "exec()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "exec()");
 		exit(EXIT_FAILURE);
 	}
 
 	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
-		verbose_print(g->verbosity_level, 0 /*change after */,
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
 		              "Can't connect to fd_server\n");
 		exit(EXIT_FAILURE);
 	}
@@ -993,27 +993,27 @@ get_if_fd(struct Global *g, const char *if_name)
 	strncpy(req.if_name, if_name, sizeof(req.if_name));
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret < 0) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "send()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
 		return NULL;
 	}
 
 	memset(&res, 0, sizeof(res));
 	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(res));
 	if (ret == -1) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "recv_fd()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "recv_fd()");
 		return NULL;
 	}
 	close(socket_fd);
 
 	nmd = malloc(sizeof(*nmd));
 	if (nmd == NULL) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "malloc()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "malloc()");
 		return NULL;
 	}
 
 	fill_nm_desc(nmd, &res.req, new_fd);
 	if (nm_mmap(nmd, NULL) != 0) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "nm_mmap()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "nm_mmap()");
 		return NULL;
 	}
 
@@ -1038,7 +1038,7 @@ release_if_fd(struct Global *g, const char *if_name)
 
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret <= 0) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "send()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
 	}
 
 	close(socket_fd);
@@ -1064,7 +1064,7 @@ stop_fd_server(struct Global *g)
 	req.action = FD_STOP;
 	ret        = send(socket_fd, &req, sizeof(req), 0);
 	if (ret == -1) {
-		verbose_perror(g->verbosity_level, 0 /*change after */, "send()");
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
 	}
 	/* By calling recv() we synchronize with the fd_server closing the
 	 * socket.
@@ -1102,14 +1102,14 @@ parse_extra_buffers_indexes(struct Global *g)
 
 	for (i = 0; i < g->extra_buffers_num; i++) {
 		if (e_buf_index == 0) {
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "Extra buffer index = 0\n");
 			return -1;
 		}
 
 		u_buf = malloc(sizeof(*u_buf));
 		if (u_buf == NULL) {
-			verbose_perror(g->verbosity_level, 0 /*change after */,
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
 			               "malloc()");
 			return -1;
 		}
@@ -1271,7 +1271,7 @@ main(int argc, char **argv)
 			g->extra_buffers_num = atoi(optarg);
 			if (g->extra_buffers_num <= 0) {
 				verbose_print(
-				        g->verbosity_level, 0 /*change after */,
+				        g->verbosity_level, LV_ERROR_MSG,
 				        "Invalid number of extra buffers\n");
 				exit(EXIT_FAILURE);
 			};
@@ -1280,7 +1280,7 @@ main(int argc, char **argv)
 		case 's':
 			ret = parse_mac_address(optarg, g->src_mac);
 			if (ret == -1) {
-				verbose_print(g->verbosity_level, 0 /*change after */,
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
 				              "Invalid source MAC address\n");
 				exit(EXIT_FAILURE);
 			}
@@ -1290,7 +1290,7 @@ main(int argc, char **argv)
 			ret = parse_mac_address(optarg, g->dst_mac);
 			if (ret == -1) {
 				verbose_print(
-				        g->verbosity_level, 0 /*change after */,
+				        g->verbosity_level, LV_ERROR_MSG,
 				        "Invalid destination MAC address\n");
 				exit(EXIT_FAILURE);
 			}
@@ -1298,7 +1298,6 @@ main(int argc, char **argv)
 
 		case 'i':
 			g->ifname = optarg;
-			printf("g->if_name = %s\n", g->ifname);
 			break;
 
 		case 'I':
@@ -1324,7 +1323,7 @@ main(int argc, char **argv)
 			int ret = 0;
 
 			if (g->num_events >= MAX_EVENTS) {
-				verbose_print(g->verbosity_level, 0 /*change after */,
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
 				              "Too many events\n");
 				exit(EXIT_FAILURE);
 			}
@@ -1342,7 +1341,7 @@ main(int argc, char **argv)
 				        g->verbosity_level);
 			}
 			if (ret) {
-				verbose_print(g->verbosity_level, 0 /*change after */,
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
 				              "Invalid event syntax '%s'\n",
 				              optarg);
 				usage(stderr);
@@ -1363,7 +1362,7 @@ main(int argc, char **argv)
 		case 'C':
 			g->num_loops = atoi(optarg);
 			if (g->num_loops == 0) {
-				verbose_print(g->verbosity_level, 0 /*change after */,
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
 				              "Invalid -C option '%s'\n",
 				              optarg);
 				exit(EXIT_FAILURE);
@@ -1371,7 +1370,7 @@ main(int argc, char **argv)
 			break;
 
 		default:
-			verbose_print(g->verbosity_level, 0 /*change after */,
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
 			              "Unrecognized option %c\n", opt);
 			usage(stderr);
 			exit(EXIT_FAILURE);
@@ -1379,7 +1378,7 @@ main(int argc, char **argv)
 	}
 
 	if (g->ifname == NULL) {
-		verbose_print(g->verbosity_level, 0 /*change after */,
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
 		              "Missing ifname\n");
 		usage(stderr);
 		exit(EXIT_FAILURE);
@@ -1387,7 +1386,7 @@ main(int argc, char **argv)
 
 	if (g->request_from_fd_server == 1 && g->extra_buffers_num > 0) {
 		verbose_print(
-		        g->verbosity_level, 0 /*change after */,
+		        g->verbosity_level, LV_ERROR_MSG,
 		        "Extra buffers can only be used when requesting an "
 		        "interface directly\n");
 		exit(EXIT_FAILURE);
@@ -1408,7 +1407,7 @@ main(int argc, char **argv)
 		g->nmd = get_if_fd(g, g->ifname);
 	}
 	if (g->nmd == NULL) {
-		verbose_print(g->verbosity_level, 0 /*change after */,
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
 		              "Failed to nm_open(%s)\n", g->ifname);
 		exit(EXIT_FAILURE);
 	}
@@ -1420,7 +1419,7 @@ main(int argc, char **argv)
 		g->extra_buffers_indexes =
 		        malloc(g->extra_buffers_num * sizeof(uint32_t));
 		if (g->extra_buffers_indexes == NULL) {
-			verbose_perror(g->verbosity_level, 0 /*change after */,
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
 			               "malloc()");
 			exit(EXIT_FAILURE);
 		}

From 39ad5ac8b61a7f80d6cd5a8b7e3a8e4ca0a84a03 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Wed, 4 Jul 2018 21:32:05 +0200
Subject: [PATCH 0987/2207] Removed " surrounding the argument  as it was
 causing an problems on FreeBSD during the calls to getopt(). Disabled
 send_zcp_mon_pipe_test as it currently fails.

---
 utils/randomized_tests                         |  1 +
 .../exclusive_open_ephemeral_vale_port_test    |  9 ++++-----
 .../exclusive_open_persistent_vale_port_test   |  6 +++---
 utils/tests/exclusive_open_pipe_test           |  6 +++---
 ...xtra_buf_send_rec_ephemeral_vale_ports_test | 10 +++++-----
 ...tra_buf_send_rec_persistent_vale_ports_test | 10 +++++-----
 utils/tests/extra_buf_send_rec_pipe_test       |  6 +++---
 utils/tests/learning_bridge_test               | 18 +++++++++---------
 utils/tests/partial_read_pipe_test             | 10 +++++-----
 .../tests/rec_cp_mon_ephemeral_vale_port_test  | 12 ++++++------
 .../tests/rec_cp_mon_persistent_vale_port_test | 12 ++++++------
 utils/tests/rec_cp_mon_pipe_test               | 12 ++++++------
 .../tests/rec_zcp_mon_ephemeral_vale_port_test | 14 +++++++-------
 .../rec_zcp_mon_persistent_vale_port_test      | 14 +++++++-------
 utils/tests/rec_zcp_mon_pipe_test              | 14 +++++++-------
 .../tests/send_cp_mon_ephemeral_vale_port_test | 12 ++++++------
 .../send_cp_mon_persistent_vale_port_test      | 12 ++++++------
 utils/tests/send_cp_mon_pipe_test              | 12 ++++++------
 utils/tests/send_rec_ephemeral_vale_ports_test | 18 +++++++++---------
 .../tests/send_rec_persistent_vale_ports_test  | 18 +++++++++---------
 utils/tests/send_rec_pipe_test                 | 12 ++++++------
 utils/tests/send_rec_veth_test                 | 16 ++++++++--------
 .../send_zcp_mon_ephemeral_vale_port_test      | 12 ++++++------
 .../send_zcp_mon_persistent_vale_port_test     | 12 ++++++------
 utils/tests/send_zcp_mon_pipe_test             | 16 +++++++++-------
 25 files changed, 148 insertions(+), 146 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 0cf9a214e..d498eb103 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -29,6 +29,7 @@ PATH="$(pwd):${PATH}"
 for test in tests/*_test ; do
 	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
 	if [ $? != 0 ] ; then
+		echo "Rerunning the test that just failed with -v"
 		# Select verbosity of output during after an error occurred:
 		#    -v    -> prints error messages
 		#    -vv   -> -v, send and receive actions
diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
index 062641998..06e308eaf 100755
--- a/utils/tests/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -13,17 +13,16 @@ verbosity="${verbosity:-}"
 bridge="vale0"
 port="v0"
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
-echo "functional ${verbosity} -i ${bridge}:${port}/x"
-functional "$verbosity" -i "${bridge}:${port}/x"
-check_success $? "exclusive-open verbosity ${verbosity} ${bridge}:${port}/x"
+functional $verbosity -i "${bridge}:${port}/x"
+check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional "$verbosity" -I "${bridge}:${port}"
+functional $verbosity -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-functional "$verbosity" -I "${bridge}:${port}/x"
+functional $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/exclusive_open_persistent_vale_port_test b/utils/tests/exclusive_open_persistent_vale_port_test
index 05f303309..2a1654d33 100755
--- a/utils/tests/exclusive_open_persistent_vale_port_test
+++ b/utils/tests/exclusive_open_persistent_vale_port_test
@@ -16,16 +16,16 @@ create_vale_persistent_port "$port"
 attach_to_vale_bridge "$bridge" "$port"
 
 # We open the persistent port with the exclusive flag from the file descriptor.
-functional "$verbosity" -i "${bridge}:${port}/x"
+functional $verbosity -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional "$verbosity" -I "${bridge}:${port}"
+functional $verbosity -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-functional "$verbosity" -I "${bridge}:${port}/x"
+functional $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/exclusive_open_pipe_test b/utils/tests/exclusive_open_pipe_test
index d0ce59c22..ab157abcc 100755
--- a/utils/tests/exclusive_open_pipe_test
+++ b/utils/tests/exclusive_open_pipe_test
@@ -12,16 +12,16 @@ restart_fd_server
 
 pipe="pipeA{1"
 # We open pipeA{1 with the exclusive flag from the file descriptor.
-functional "$verbosity" -i "netmap:${pipe}/x"
+functional $verbosity -i "netmap:${pipe}/x"
 check_success $? "exclusive-open netmap:${pipe}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional "$verbosity" -I "netmap:${pipe}"
+functional $verbosity -I "netmap:${pipe}"
 check_failure $? "no-open netmap:${pipe}"
 
 # Check that another exclusive open request fails.
-functional "$verbosity" -I "netmap:${pipe}/x"
+functional $verbosity -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 5ed4a8dce..42f905d0e 100755
--- a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -22,17 +22,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "vale0:v1"
+functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional "$verbosity" -i "vale0:v2"
+functional $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v0 ---> v1, v2
-functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional "$verbosity" -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional $verbosity -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index 8a78fdad7..b7c91d6cb 100755
--- a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -29,17 +29,17 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "vale0:v0"
+functional $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i "vale0:v1"
+functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # v2 ---> v0, v1
-functional "$verbosity" -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional "$verbosity" -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional $verbosity -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
index 133bbc7f2..7ee905a3f 100755
--- a/utils/tests/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -22,13 +22,13 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:pipeA{1"
+functional $verbosity -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
 
 # pipeA}1 ---> pipeA{1
-functional "$verbosity" -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional $verbosity -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
 e2=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/learning_bridge_test b/utils/tests/learning_bridge_test
index d6b2f3e14..99a9973c0 100755
--- a/utils/tests/learning_bridge_test
+++ b/utils/tests/learning_bridge_test
@@ -23,19 +23,19 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
-functional "$verbosity" -i vale0:v2
+functional $verbosity -i vale0:v2
 check_success $? "pre-open vale0:v2"
 
 # First send, every port should receive the frame.
-functional "$verbosity" -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+functional $verbosity -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p1=$!
-functional "$verbosity" -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+functional $verbosity -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p2=$!
-functional "$verbosity" -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
+functional $verbosity -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
 e3=$?
 wait $p1
 e1=$?
@@ -46,11 +46,11 @@ check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-functional "$verbosity" -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
+functional $verbosity -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
 p4=$!
-functional "$verbosity" -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
+functional $verbosity -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
 p5=$!
-functional "$verbosity" -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
+functional $verbosity -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index e6e0493aa..4a0a2613e 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -24,14 +24,14 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:${pipe}{1"
+functional $verbosity -i "netmap:${pipe}{1"
 check_success $? "pre-open netmap:${pipe}{1"
-functional "$verbosity" -i "netmap:${pipe}}1"
+functional $verbosity -i "netmap:${pipe}}1"
 check_success $? "pre-open netmap:${pipe}}1"
 
-functional "$verbosity" -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
+functional $verbosity -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
 p1=$!
-functional "$verbosity" -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 e2=$?
 wait $p1
 e1=$?
@@ -70,7 +70,7 @@ check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
 
 
 num_send="$(($ring_avail_sends + 1))"
-functional "$verbosity" -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
index 478694530..268caed2e 100755
--- a/utils/tests/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -23,17 +23,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i vale0:v0/r
+functional $verbosity -i vale0:v0/r
 check_success $? "pre-open vale0:v0/r"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional "$verbosity" -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -41,7 +41,7 @@ check_success $e1 "receive-${num} vale0:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional "$verbosity" -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
index efe38f20b..b0b214d7a 100755
--- a/utils/tests/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -26,17 +26,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i netmap:v0/r
+functional $verbosity -i netmap:v0/r
 check_success $? "pre-open netmap:v0/r"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional "$verbosity" -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -44,7 +44,7 @@ check_success $e1 "receive-${num} netmap:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional "$verbosity" -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
index 920ca2957..3297ab1d6 100755
--- a/utils/tests/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -24,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:pipe{1"
+functional $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional "$verbosity" -i "netmap:pipe{1/r"
+functional $verbosity -i "netmap:pipe{1/r"
 check_success $? "pre-open netmap:pipe{1/r"
-functional "$verbosity" -i "netmap:pipe}1"
+functional $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-functional "$verbosity" -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num}${seq} netmap:pipe{1/r"
 check_success $e2 "send-${num}${seq} netmap:pipe}1"
 
 # Then we read from pipe{1
-functional "$verbosity" -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index 2dcea34d2..400a357e7 100755
--- a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -23,18 +23,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "vale0:v0"
+functional $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i "vale0:v0/z"
+functional $verbosity -i "vale0:v0/z"
 check_success $? "pre-open vale0:v0/z"
-functional "$verbosity" -i "vale0:v1"
+functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional "$verbosity" -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional "$verbosity" -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,9 +43,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional "$verbosity" -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional "$verbosity" -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
index 35c64a9a5..fcd27b1a0 100755
--- a/utils/tests/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -26,18 +26,18 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "vale0:v0"
+functional $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i "netmap:v0/z"
+functional $verbosity -i "netmap:v0/z"
 check_success $? "pre-open netmap:v0/z"
-functional "$verbosity" -i "vale0:v1"
+functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional "$verbosity" -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional "$verbosity" -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -46,9 +46,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional "$verbosity" -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional "$verbosity" -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
index 3774d9aa9..7ff79a8e1 100755
--- a/utils/tests/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -23,18 +23,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:pipe{1"
+functional $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional "$verbosity" -i "netmap:pipe{1/z"
+functional $verbosity -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-functional "$verbosity" -i "netmap:pipe}1"
+functional $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional "$verbosity" -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -43,9 +43,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-functional "$verbosity" -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
index 15d9132b3..07bc5ee28 100755
--- a/utils/tests/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -21,17 +21,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i vale0:v0/t
+functional $verbosity -i vale0:v0/t
 check_success $? "pre-open vale0:v0/t"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional "$verbosity" -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -39,7 +39,7 @@ check_success $e1 "receive-${num} vale0:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
index 0797178d5..45f601aef 100755
--- a/utils/tests/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -24,17 +24,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i netmap:v0/t
+functional $verbosity -i netmap:v0/t
 check_success $? "pre-open netmap:v0/t"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional "$verbosity" -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} netmap:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
index e094febe3..8c51f2d76 100755
--- a/utils/tests/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -24,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:pipe{1"
+functional $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional "$verbosity" -i "netmap:pipe{1/t"
+functional $verbosity -i "netmap:pipe{1/t"
 check_success $? "pre-open netmap:pipe{1/t"
-functional "$verbosity" -i "netmap:pipe}1"
+functional $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-functional "$verbosity" -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} netmap:pipe{1/t"
 check_success $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-functional "$verbosity" -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
index fadb030ea..d093ffa36 100755
--- a/utils/tests/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -20,19 +20,19 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "vale0:v0"
+functional $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i "vale0:v1"
+functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional "$verbosity" -i "vale0:v2"
+functional $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional "$verbosity" -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional "$verbosity" -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
 e3=$?
 wait $p1
 e1=$?
@@ -43,11 +43,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p4=$!
-functional "$verbosity" -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p5=$!
-functional "$verbosity" -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
index 3a6538624..10988c657 100755
--- a/utils/tests/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -27,19 +27,19 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "vale0:v0"
+functional $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i "vale0:v1"
+functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional "$verbosity" -i "vale0:v2"
+functional $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional "$verbosity" -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p2=$!
-functional "$verbosity" -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
 e3=$?
 wait $p1
 e1=$?
@@ -50,11 +50,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional "$verbosity" -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
 p4=$!
-functional "$verbosity" -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
 p5=$!
-functional "$verbosity" -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
index aaf6507f8..788d147ed 100755
--- a/utils/tests/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -20,15 +20,15 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:pipeA{1"
+functional $verbosity -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
-functional "$verbosity" -i "netmap:pipeA}1"
+functional $verbosity -i "netmap:pipeA}1"
 check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-functional "$verbosity" -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -36,9 +36,9 @@ check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-functional "$verbosity" -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional "$verbosity" -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e2=$?
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/send_rec_veth_test
index 9520bf908..11ab5f97f 100755
--- a/utils/tests/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -9,6 +9,8 @@
 ################################################################################
 source test_lib
 
+exit 0 # Test currently disabled.
+
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 fill="${fill:-d}"
@@ -18,20 +20,18 @@ seq="${seq:-}"
 
 restart_fd_server
 
-exit 0
-
 create_veth_interfaces "veth1"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i netmap:veth1A
+functional $verbosity -i netmap:veth1A
 check_success $? "pre-open netmap:veth1A"
-functional "$verbosity" -i netmap:veth1B
+functional $verbosity -i netmap:veth1B
 check_success $? "pre-open netmap:veth1B"
 
 # veth1B --> veth1A
-functional "$verbosity" -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -39,9 +39,9 @@ check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
 # veth1A --> veth1B
-functional "$verbosity" -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional "$verbosity" -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
index ecb98d136..70738cf54 100755
--- a/utils/tests/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -24,17 +24,17 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i vale0:v0/z
+functional $verbosity -i vale0:v0/z
 check_success $? "pre-open vale0:v0/z"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional "$verbosity" -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} vale0:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
index ab025580a..bc8b42f98 100755
--- a/utils/tests/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -27,17 +27,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i vale0:v0
+functional $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional "$verbosity" -i netmap:v0/z
+functional $verbosity -i netmap:v0/z
 check_success $? "pre-open netmap:v0/z"
-functional "$verbosity" -i vale0:v1
+functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional "$verbosity" -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
 p1=$!
-functional "$verbosity" -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -45,7 +45,7 @@ check_success $e1 "receive-${num} netmap:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional "$verbosity" -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index a53267538..a73b7c1bb 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -13,6 +13,8 @@
 ################################################################################
 source test_lib
 
+exit 0 # Test currently disabled.
+
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 fill="${fill:-d}"
@@ -24,18 +26,18 @@ restart_fd_server
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional "$verbosity" -i "netmap:pipe{1"
+functional $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional "$verbosity" -i "netmap:pipe{1/z"
+functional $verbosity -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-functional "$verbosity" -i "netmap:pipe}1"
+functional $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
 p1=$!
-functional "$verbosity" -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
 e2=$?
 wait $p1
 e1=$?
@@ -44,9 +46,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the non-monitored pipe end, therefore the monitor should
 # receive the frame.
-functional "$verbosity" -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
-functional "$verbosity" -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
 e4=$?
 wait $p3
 e3=$?

From a1b4a0bc5aad4b6757c089645e122441fb09739f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 5 Jul 2018 13:32:01 +0200
Subject: [PATCH 0988/2207] generic: fix NA(ifp) manipulation

---
 LINUX/bsd_glue.h                | 11 +++++++----
 sys/dev/netmap/netmap_generic.c |  8 ++++----
 sys/dev/netmap/netmap_kern.h    |  1 +
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index f89f3d7ac..24b2433ea 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -311,10 +311,6 @@ struct netmap_linux_magic {
 	(ifp)->ethtool_ops = NA(ifp)->magic.save_eto;			\
 } while (0)
 #define NM_ATTACH_NA(ifp, na) do {					\
-	if ((na)->magic.save_eto == &(na)->magic.eto) {			\
-		NM_DETACH_NA(ifp);					\
-		break;							\
-	}								\
 	if ((ifp)->ethtool_ops) {					\
 		(na)->magic.eto = *(ifp)->ethtool_ops;			\
 		(na)->magic.save_eto = (ifp)->ethtool_ops;		\
@@ -324,6 +320,13 @@ struct netmap_linux_magic {
 	(na)->magic.eto.set_ringparam = linux_netmap_set_ringparam;	\
 	(ifp)->ethtool_ops = &(na)->magic.eto;				\
 } while (0)
+#define NM_RESTORE_NA(ifp, na) do {					\
+	if (na == NULL) {						\
+		NM_DETACH_NA(ifp);					\
+	} else {							\
+		(ifp)->ethtool_ops = &(na)->magic.eto;			\
+	}								\
+} while (0)
 #define NM_NA_VALID(ifp)						\
 	(NA(ifp) && NA(ifp)->magic.eto.set_ringparam == 		\
 		linux_netmap_set_ringparam)
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 671821e4a..2a6ca2531 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1048,7 +1048,7 @@ generic_netmap_dtor(struct netmap_adapter *na)
 		}
 		D("Native netmap adapter %p restored", prev_na);
 	}
-	NM_ATTACH_NA(ifp, prev_na);
+	NM_RESTORE_NA(ifp, prev_na);
 	/*
 	 * netmap_detach_common(), that it's called after this function,
 	 * overrides WNA(ifp) if na->ifp is not NULL.
@@ -1089,7 +1089,7 @@ generic_netmap_attach(struct ifnet *ifp)
 	}
 #endif
 
-	if (NA(ifp) && !NM_NA_VALID(ifp)) {
+	if (NM_NA_CLASH(ifp)) {
 		/* If NA(ifp) is not null but there is no valid netmap
 		 * adapter it means that someone else is using the same
 		 * pointer (e.g. ax25_ptr on linux). This happens for
@@ -1140,8 +1140,8 @@ generic_netmap_attach(struct ifnet *ifp)
 		return retval;
 	}
 
-	gna->prev = NA(ifp); /* save old na */
-	if (gna->prev != NULL) {
+	if (NM_NA_VALID(ifp)) {
+		gna->prev = NA(ifp); /* save old na */
 		netmap_adapter_get(gna->prev);
 	}
 	NM_ATTACH_NA(ifp, na);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index b14cde56e..d7f1e1659 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1642,6 +1642,7 @@ extern int ptnetmap_tx_workers;
 		NA(ifp)->magic = 					\
 			((uint32_t)(uintptr_t)NA(ifp)) ^ NETMAP_MAGIC;	\
 } while(0)
+#define NM_RESTORE_NA(ifp, na) 	WNA(ifp) = na;
 
 #define NM_DETACH_NA(ifp)	do { WNA(ifp) = NULL; } while (0)
 #define NM_NA_CLASH(ifp)	(NA(ifp) && !NM_NA_VALID(ifp))

From e02cb66dd0f31e3a49fc988f26833ceb1ab02ab4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 5 Jul 2018 13:41:43 +0200
Subject: [PATCH 0989/2207] monitor: add missing put()s on monitor exit

---
 sys/dev/netmap/netmap_monitor.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 096f86c6e..e5c4b6cd8 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -371,9 +371,6 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum
 
 	if (zmon) {
 		/* remove the monitor from the list */
-		if (mz->prev != NULL) {
-			mz->prev->zmon_list[t].next = mz->next;
-		}
 		if (mz->next != NULL) {
 			mz->next->zmon_list[t].prev = mz->prev;
 			/* we also need to let the next monitor drop the
@@ -390,6 +387,10 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum
 			kring->zmon_list[t].prev =
 				(mz->prev != kring ? mz->prev : NULL);
 		}
+		if (mz->prev != NULL) {
+			netmap_adapter_put(mz->prev->na);
+			mz->prev->zmon_list[t].next = mz->next;
+		}
 		mz->prev = NULL;
 		mz->next = NULL;
 	} else {

From 9b9b6674fe5d7c09e7cd6292fdc04bafd125911d Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 5 Jul 2018 16:36:54 +0200
Subject: [PATCH 0990/2207] send_zcp_mon_pipe_test no longer disabled

---
 utils/tests/send_zcp_mon_pipe_test | 2 --
 1 file changed, 2 deletions(-)

diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index a73b7c1bb..31934fc48 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -13,8 +13,6 @@
 ################################################################################
 source test_lib
 
-exit 0 # Test currently disabled.
-
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 fill="${fill:-d}"

From c67af64904d6c0b8e37cc8befb06d9fc5b8679e4 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 5 Jul 2018 17:05:43 +0200
Subject: [PATCH 0991/2207] Updated send_zcp_mon_pipe_test as it was failing
 due to a misunderstanding on the expected behaviour of pipes and zero-copy
 monitors

---
 utils/tests/send_zcp_mon_pipe_test | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index 31934fc48..9c272bc44 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -9,7 +9,8 @@
 # 2) open a zero-copy monitor pipe{1/z for pipe{1.
 # 3) send from pipe{1 without receiving from pipe}1, check that pipe{1/z doesn't
 #    receive the frame.
-# 4) receive from pipe}1, check that pipe{1/z receives the frame.
+# 4) receive from pipe}1, send again from pipe{1 (slots are returned during a
+#    txsync action) and check that pipe{1/z receives the frame.
 ################################################################################
 source test_lib
 
@@ -42,15 +43,20 @@ e1=$?
 check_success $e1 "no-receive-${num} netmap:pipe{1/z"
 check_success $e2 "send-${num} netmap:pipe{1"
 
-# Now we receive with the non-monitored pipe end, therefore the monitor should
-# receive the frame.
+# Now we receive with the non-monitored pipe end. We need to send again with the
+# monitored pipe otherwise the zero-copy monitor won't be able to see the
+# packet, as the slot is returned to the monitored pipe only during a txsync
+# action.
 functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
 p3=$!
 functional $verbosity -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
 e4=$?
+functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+e5=$?
 wait $p3
 e3=$?
-check_success $e3 "receive-${num} netmap:pipe{1/z"
 check_success $e4 "receive-${num} netmap:pipe}1"
+check_success $e5 "send-${num} netmap:pipe{1"
+check_success $e3 "receive-${num} netmap:pipe{1/z"
 
 test_successful "$0"
\ No newline at end of file

From 9584f842d9a4a8a20123c907d2d4fb4da5991620 Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Thu, 5 Jul 2018 19:58:56 +0200
Subject: [PATCH 0992/2207] fixed typo inside test_lib

---
 utils/test_lib                     | 2 +-
 utils/tests/partial_read_pipe_test | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/utils/test_lib b/utils/test_lib
index 3a5906333..081a44c68 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -263,7 +263,7 @@ function parse_send_recv_arguments() {
 			v) if [ -z $verbosity ] ; then
 					verbosity="-v"
 				else
-					erbosity="${verbosity}v"
+					verbosity="${verbosity}v"
 			   fi
 			;;
 			h) send_recv_usage ; exit 0
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index 4a0a2613e..d037a83d9 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -68,7 +68,6 @@ if [ $ring_used_sends != $pending_sends ] ; then
 fi
 check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
 
-
 num_send="$(($ring_avail_sends + 1))"
 functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
 check_failure $? "send-${num_send} netmap:${pipe}}1"

From 691cbcd5f5d4abfd864532b1ef5711613dfe30ab Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 4 Jul 2018 18:44:13 +0200
Subject: [PATCH 0993/2207] monitor: override callbacks for all host rings

---
 sys/dev/netmap/netmap_monitor.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index e5c4b6cd8..8f031488b 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -170,11 +170,20 @@ static int
 netmap_monitor_krings_create(struct netmap_adapter *na)
 {
 	int error = netmap_krings_create(na, 0);
+	enum txrx t;
+
 	if (error)
 		return error;
 	/* override the host rings callbacks */
-	na->tx_rings[na->num_tx_rings]->nm_sync = netmap_monitor_txsync;
-	na->rx_rings[na->num_rx_rings]->nm_sync = netmap_monitor_rxsync;
+	for_rx_tx(t) {
+		int i;
+		u_int first = nma_get_nrings(na, t);
+		for (i = 0; i < nma_get_host_nrings(na, t); i++) {
+			struct netmap_kring *kring = NMR(na, t)[first + i];
+			kring->nm_sync = t == NR_TX ? netmap_monitor_txsync :
+						      netmap_monitor_rxsync;
+		}
+	}
 	return 0;
 }
 

From 226cd6a1eef7e2ddbbb14f353eb756c1ff55b4bf Mon Sep 17 00:00:00 2001
From: Stefano Duo 
Date: Fri, 6 Jul 2018 15:21:08 +0200
Subject: [PATCH 0994/2207] fixed extra buffer release inside functional.c

---
 utils/functional.c                            | 146 +++++++++---------
 .../exclusive_open_ephemeral_vale_port_test   |   5 +-
 .../exclusive_open_persistent_vale_port_test  |   5 +-
 utils/tests/exclusive_open_pipe_test          |   3 +-
 ...tra_buf_send_rec_ephemeral_vale_ports_test |   6 +-
 ...ra_buf_send_rec_persistent_vale_ports_test |   6 +-
 utils/tests/extra_buf_send_rec_pipe_test      |   4 +-
 utils/tests/partial_read_pipe_test            |   7 +-
 utils/tests/persistent_vale_port_destroy      |   2 +
 .../tests/persistent_vale_port_double_attach  |   2 +
 .../tests/persistent_vale_port_double_create  |   2 +
 .../tests/rec_cp_mon_ephemeral_vale_port_test |   6 +-
 .../rec_cp_mon_persistent_vale_port_test      |   6 +-
 utils/tests/rec_cp_mon_pipe_test              |   6 +-
 .../rec_zcp_mon_ephemeral_vale_port_test      |   8 +-
 .../rec_zcp_mon_persistent_vale_port_test     |   8 +-
 utils/tests/rec_zcp_mon_pipe_test             |   8 +-
 .../send_cp_mon_ephemeral_vale_port_test      |   6 +-
 .../send_cp_mon_persistent_vale_port_test     |   6 +-
 utils/tests/send_cp_mon_pipe_test             |   6 +-
 .../tests/send_rec_ephemeral_vale_ports_test  |  12 +-
 .../tests/send_rec_persistent_vale_ports_test |  12 +-
 utils/tests/send_rec_pipe_test                |   8 +-
 utils/tests/send_rec_veth_test                |   8 +-
 .../send_zcp_mon_ephemeral_vale_port_test     |   6 +-
 .../send_zcp_mon_persistent_vale_port_test    |   6 +-
 utils/tests/send_zcp_mon_pipe_test            |  10 +-
 27 files changed, 158 insertions(+), 152 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index f8bcfed92..6efc25f0a 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -71,9 +71,9 @@ struct Event {
 	unsigned long long usecs;
 };
 
-struct swapped_out_buf {
+struct extra_buffer {
 	uint32_t buf_idx;
-	LIST_ENTRY(swapped_out_buf) list_entry;
+	TAILQ_ENTRY(extra_buffer) list_entry;
 };
 
 ;
@@ -88,18 +88,16 @@ struct Global {
 	int sequential_fill;        /* increment fill char for multi-packets
 	                            operations */
 	int request_from_fd_server; /* false --> directly open the interface */
+
 #define LV_ERROR_MSG 1
 #define LV_DEBUG_SEND_RECV 2
-#define LV_DEBUG_BUILD_PACKET 3
-#define LV_DEBUG_PARSE_ARGS 4
+#define LV_DEBUG_EXTRA_BUF 3
+#define LV_DEBUG_BUILD_PACKET 4
+#define LV_DEBUG_PARSE_ARGS 5
 	int verbosity_level;
 
 	/* List of currently not in use normal buffers. */
-	LIST_HEAD(n_buf_head, swapped_out_buf) normal_buffers_head;
-	/* List of currently not in use extra buffers. */
-	LIST_HEAD(e_buf_head, swapped_out_buf) extra_buffers_head;
-	/* Points to an array containing all extra buffer indexes */
-	uint32_t *extra_buffers_indexes;
+	TAILQ_HEAD(extra_buf_head, extra_buffer) extra_buffers_head;
 	unsigned extra_buffers_num; /* number of granted extra buffers */
 
 #define MAX_PKT_SIZE 65536
@@ -126,20 +124,6 @@ struct Global {
 void release_if_fd(struct Global *, const char *);
 void release_extra_buffers(struct Global *);
 
-void
-cleanup(struct Global *g)
-{
-	if (g->extra_buffers_num > 0) {
-		release_extra_buffers(g);
-	}
-
-	if (g->request_from_fd_server) {
-		release_if_fd(g, g->ifname);
-	} else {
-		nm_close(g->nmd);
-	}
-}
-
 void
 verbose_print(int current_verbosity, int required_verbosity, char *format, ...)
 {
@@ -161,6 +145,20 @@ verbose_perror(int current_verbosity, int required_verbosity, char *str)
 	}
 }
 
+void
+cleanup(struct Global *g)
+{
+	if (g->extra_buffers_num > 0) {
+		release_extra_buffers(g);
+	}
+
+	if (g->request_from_fd_server) {
+		release_if_fd(g, g->ifname);
+	} else {
+		nm_close(g->nmd);
+	}
+}
+
 static void
 fill_packet_field(struct Global *g, unsigned offset, const char *content,
                   unsigned content_len)
@@ -1095,17 +1093,19 @@ parse_extra_buffers_indexes(struct Global *g)
 	struct netmap_if *nifp   = g->nmd->nifp;
 	struct netmap_ring *ring = NETMAP_TXRING(nifp, g->nmd->first_tx_ring);
 	struct netmap_slot *slot = &ring->slot[ring->head];
-	uint32_t e_buf_index     = nifp->ni_bufs_head;
+	uint32_t extra_buf_index = nifp->ni_bufs_head;
 	uint32_t real_index      = slot->buf_idx;
-	struct swapped_out_buf *u_buf;
+	struct extra_buffer *u_buf;
 	unsigned i;
 
+	verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Parsing %u extra buffers:\n", g->extra_buffers_num);
 	for (i = 0; i < g->extra_buffers_num; i++) {
-		if (e_buf_index == 0) {
+		if (extra_buf_index == 0) {
 			verbose_print(g->verbosity_level, LV_ERROR_MSG,
-			              "Extra buffer index = 0\n");
+			              "   error, index = 0\n");
 			return -1;
 		}
+		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "   index = %u\n", extra_buf_index);
 
 		u_buf = malloc(sizeof(*u_buf));
 		if (u_buf == NULL) {
@@ -1113,11 +1113,10 @@ parse_extra_buffers_indexes(struct Global *g)
 			               "malloc()");
 			return -1;
 		}
-		u_buf->buf_idx = e_buf_index;
-		LIST_INSERT_HEAD(&g->extra_buffers_head, u_buf, list_entry);
-		g->extra_buffers_indexes[i] = e_buf_index;
-		slot->buf_idx               = e_buf_index;
-		e_buf_index = *(uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+		u_buf->buf_idx = extra_buf_index;
+		TAILQ_INSERT_HEAD(&g->extra_buffers_head, u_buf, list_entry);
+		slot->buf_idx   = extra_buf_index;
+		extra_buf_index = *(uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
 	}
 	slot->buf_idx = real_index;
 
@@ -1131,6 +1130,7 @@ parse_extra_buffers_indexes(struct Global *g)
 int
 swap_in_extra_buffers(struct Global *g)
 {
+	unsigned extra_buffers_num = g->extra_buffers_num;
 	unsigned int i;
 
 	for (i = g->nmd->first_tx_ring; i <= g->nmd->last_tx_ring; i++) {
@@ -1139,8 +1139,8 @@ swap_in_extra_buffers(struct Global *g)
 
 		for (head = ring->head; head != ring->tail;
 		     head = nm_ring_next(ring, head)) {
-			struct swapped_out_buf *u_buf =
-			        LIST_FIRST(&g->extra_buffers_head);
+			struct extra_buffer *u_buf =
+			        TAILQ_FIRST(&g->extra_buffers_head);
 			struct netmap_slot *slot = &ring->slot[head];
 			uint32_t real_index      = slot->buf_idx;
 
@@ -1152,20 +1152,20 @@ swap_in_extra_buffers(struct Global *g)
 			slot->buf_idx = u_buf->buf_idx;
 			slot->flags |= NS_BUF_CHANGED;
 			u_buf->buf_idx = real_index;
-			LIST_REMOVE(u_buf, list_entry);
-			LIST_INSERT_HEAD(&g->normal_buffers_head, u_buf,
+			TAILQ_REMOVE(&g->extra_buffers_head, u_buf, list_entry);
+			TAILQ_INSERT_TAIL(&g->extra_buffers_head, u_buf,
 			                 list_entry);
-		}
-	}
 
-	if (!LIST_EMPTY(&g->extra_buffers_head)) {
-		/* This happens if the number of slots in our adapter is less
-		 * than the number of extra buffers requested, thus should not
-		 * be regarded as an error (?)
-		 */
-		return 0;
+			if (--extra_buffers_num == 0) {
+				return 0;
+			}
+		}
 	}
 
+	/* This is reached if the adapter has less slots than the number of
+	 * requested extra buffers. Nevertheless this is not a problem as the
+	 * not in use extra buffers will will be released during cleanup().
+	 */
 	return 0;
 }
 
@@ -1182,29 +1182,33 @@ release_extra_buffers(struct Global *g)
 	struct netmap_ring *ring = NETMAP_TXRING(nifp, g->nmd->first_tx_ring);
 	struct netmap_slot *slot = &ring->slot[ring->head];
 	uint32_t real_index      = slot->buf_idx;
-	unsigned i;
+	struct extra_buffer *u_buf;
+	uint32_t *next_extra_buffer;
 
-	nifp->ni_bufs_head = g->extra_buffers_indexes[0];
-	for (i = 0; i < g->extra_buffers_num; i++) {
-		uint32_t *extra_buffer;
-
-		slot->buf_idx = g->extra_buffers_indexes[i];
-		extra_buffer  = (uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
-		if (i == g->extra_buffers_num - 1) {
-			*extra_buffer = 0;
-		} else {
-			*extra_buffer = g->extra_buffers_indexes[i + 1];
-		}
+	verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Releasing %u extra buffers:\n", g->extra_buffers_num);
+	if (TAILQ_EMPTY(&g->extra_buffers_head)) {
+		return;
 	}
-	slot->buf_idx = real_index;
-
-	while (!LIST_EMPTY(&g->extra_buffers_head)) {
-		struct swapped_out_buf *u_buf =
-		        LIST_FIRST(&g->extra_buffers_head);
 
-		LIST_REMOVE(u_buf, list_entry);
+	u_buf = TAILQ_FIRST(&g->extra_buffers_head);
+	nifp->ni_bufs_head = u_buf->buf_idx;
+	verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "   head index %u\n", nifp->ni_bufs_head);
+	slot->buf_idx = u_buf->buf_idx;
+	TAILQ_REMOVE(&g->extra_buffers_head, u_buf, list_entry);
+	free(u_buf);
+
+	while (!TAILQ_EMPTY(&g->extra_buffers_head)) {
+		next_extra_buffer = (uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+		u_buf = TAILQ_FIRST(&g->extra_buffers_head);
+		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "   index = %u\n", u_buf->buf_idx);
+		*next_extra_buffer = u_buf->buf_idx;
+		slot->buf_idx = u_buf->buf_idx;
+		TAILQ_REMOVE(&g->extra_buffers_head, u_buf, list_entry);
 		free(u_buf);
 	}
+	next_extra_buffer = (uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+	*next_extra_buffer = 0;
+	slot->buf_idx = real_index;
 }
 
 int
@@ -1239,8 +1243,7 @@ main(int argc, char **argv)
 	g->verbosity_level        = 0;
 	g->num_loops              = 1;
 	g->extra_buffers_num      = 0;
-	LIST_INIT(&g->normal_buffers_head);
-	LIST_INIT(&g->extra_buffers_head);
+	TAILQ_INIT(&g->extra_buffers_head);
 
 	while ((opt = getopt(argc, argv, "hconqe:s:d:i:I:w:F:T:t:r:gvp:C:")) !=
 	       -1) {
@@ -1275,6 +1278,7 @@ main(int argc, char **argv)
 				        "Invalid number of extra buffers\n");
 				exit(EXIT_FAILURE);
 			};
+			verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Requesting %u extra buffers\n", g->extra_buffers_num);
 			break;
 
 		case 's':
@@ -1413,17 +1417,9 @@ main(int argc, char **argv)
 	}
 
 	if (g->extra_buffers_num > 0) {
-		g->extra_buffers_num = g->nmd->req.nr_arg3; /* Stores the real
-		                                               number of extra
-		                                               buffers. */
-		g->extra_buffers_indexes =
-		        malloc(g->extra_buffers_num * sizeof(uint32_t));
-		if (g->extra_buffers_indexes == NULL) {
-			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
-			               "malloc()");
-			exit(EXIT_FAILURE);
-		}
-
+		/* Stores the real number of extra buffers. */
+		g->extra_buffers_num = g->nmd->req.nr_arg3;
+		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Received %u extra buffers\n", g->extra_buffers_num);
 		ret = parse_extra_buffers_indexes(g);
 		if (ret == -1) {
 			cleanup(g);
diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
index 06e308eaf..4b55059cb 100755
--- a/utils/tests/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -5,13 +5,14 @@
 ################################################################################
 source test_lib
 
-restart_fd_server
-
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 
 bridge="vale0"
 port="v0"
+
+restart_fd_server
+
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
 functional $verbosity -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
diff --git a/utils/tests/exclusive_open_persistent_vale_port_test b/utils/tests/exclusive_open_persistent_vale_port_test
index 2a1654d33..9c229317d 100755
--- a/utils/tests/exclusive_open_persistent_vale_port_test
+++ b/utils/tests/exclusive_open_persistent_vale_port_test
@@ -8,10 +8,11 @@ source test_lib
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 
-restart_fd_server
-
 bridge="vale0"
 port="v0"
+
+restart_fd_server
+
 create_vale_persistent_port "$port"
 attach_to_vale_bridge "$bridge" "$port"
 
diff --git a/utils/tests/exclusive_open_pipe_test b/utils/tests/exclusive_open_pipe_test
index ab157abcc..072cd522d 100755
--- a/utils/tests/exclusive_open_pipe_test
+++ b/utils/tests/exclusive_open_pipe_test
@@ -8,9 +8,10 @@ source test_lib
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
 
+pipe="pipeA{1"
+
 restart_fd_server
 
-pipe="pipeA{1"
 # We open pipeA{1 with the exclusive flag from the file descriptor.
 functional $verbosity -i "netmap:${pipe}/x"
 check_success $? "exclusive-open netmap:${pipe}/x"
diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 42f905d0e..0e36d0331 100755
--- a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -28,11 +28,11 @@ functional $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v0 ---> v1, v2
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -I "vale0:v0" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional $verbosity -I "vale0:v0" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index b7c91d6cb..d0f193f95 100755
--- a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -35,11 +35,11 @@ functional $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # v2 ---> v0, v1
-functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -I "vale0:v2" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional $verbosity -I "vale0:v2" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
index 7ee905a3f..1f5c54d33 100755
--- a/utils/tests/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -26,9 +26,9 @@ functional $verbosity -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
 
 # pipeA}1 ---> pipeA{1
-functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq" -e "$e_buf_num"
+functional $verbosity -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
 e2=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index d037a83d9..9b960182f 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -13,6 +13,7 @@ source test_lib
 
 parse_send_recv_arguments "$@"
 verbosity="${verbosity:-}"
+seq="${seq:-}"
 
 fill='h'
 len=274
@@ -29,9 +30,9 @@ check_success $? "pre-open netmap:${pipe}{1"
 functional $verbosity -i "netmap:${pipe}}1"
 check_success $? "pre-open netmap:${pipe}}1"
 
-functional $verbosity -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" &
+functional $verbosity -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" $seq &
 p1=$!
-functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -69,7 +70,7 @@ fi
 check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
 
 num_send="$(($ring_avail_sends + 1))"
-functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}"
+functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
 test_successful "$0"
\ No newline at end of file
diff --git a/utils/tests/persistent_vale_port_destroy b/utils/tests/persistent_vale_port_destroy
index 4a1b22a8a..31f65e8ca 100755
--- a/utils/tests/persistent_vale_port_destroy
+++ b/utils/tests/persistent_vale_port_destroy
@@ -13,6 +13,8 @@ bridgeA="${bridge}A"
 bridgeB="${bridge}B"
 port="v0"
 
+restart_fd_server
+
 create_vale_persistent_port "$port" 0
 destroy_vale_persistent_port "$port" 0
 
diff --git a/utils/tests/persistent_vale_port_double_attach b/utils/tests/persistent_vale_port_double_attach
index 81260b5d1..c310b32eb 100755
--- a/utils/tests/persistent_vale_port_double_attach
+++ b/utils/tests/persistent_vale_port_double_attach
@@ -14,6 +14,8 @@ bridgeA="${bridge}A"
 bridgeB="${bridge}B"
 port="v0"
 
+restart_fd_server
+
 create_vale_persistent_port "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 1
diff --git a/utils/tests/persistent_vale_port_double_create b/utils/tests/persistent_vale_port_double_create
index b58b43d1e..bad479267 100755
--- a/utils/tests/persistent_vale_port_double_create
+++ b/utils/tests/persistent_vale_port_double_create
@@ -13,6 +13,8 @@ bridgeA="${bridge}A"
 bridgeB="${bridge}B"
 port="v0"
 
+restart_fd_server
+
 create_vale_persistent_port "$port" 0
 create_vale_persistent_port "$port" 1
 
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
index 268caed2e..dbbed5967 100755
--- a/utils/tests/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -31,9 +31,9 @@ functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional $verbosity -i vale0:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i vale0:v0/r -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -41,7 +41,7 @@ check_success $e1 "receive-${num} vale0:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
index b0b214d7a..731ac06e4 100755
--- a/utils/tests/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -34,9 +34,9 @@ functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional $verbosity -i netmap:v0/r -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:v0/r -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -44,7 +44,7 @@ check_success $e1 "receive-${num} netmap:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
index 3297ab1d6..83da161f3 100755
--- a/utils/tests/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -32,9 +32,9 @@ functional $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-functional $verbosity -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num}${seq} netmap:pipe{1/r"
 check_success $e2 "send-${num}${seq} netmap:pipe}1"
 
 # Then we read from pipe{1
-functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index 400a357e7..bae5173fd 100755
--- a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -32,9 +32,9 @@ check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -43,9 +43,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "vale0:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v0/z" -r "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
index fcd27b1a0..19e0091c5 100755
--- a/utils/tests/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -35,9 +35,9 @@ check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -46,9 +46,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0"    -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:v0/z" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:v0/z" -r "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
index 7ff79a8e1..3536aae91 100755
--- a/utils/tests/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -32,9 +32,9 @@ check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -43,9 +43,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
index 07bc5ee28..5ff210890 100755
--- a/utils/tests/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -29,9 +29,9 @@ functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i vale0:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i vale0:v0/t  -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -39,7 +39,7 @@ check_success $e1 "receive-${num} vale0:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
index 45f601aef..81f39c7a8 100755
--- a/utils/tests/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -32,9 +32,9 @@ functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i netmap:v0/t -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:v0/t -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} netmap:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
index 8c51f2d76..604d7a7ff 100755
--- a/utils/tests/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -32,9 +32,9 @@ functional $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-functional $verbosity -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} netmap:pipe{1/t"
 check_success $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-functional $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
index d093ffa36..98a58ad90 100755
--- a/utils/tests/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -28,11 +28,11 @@ functional $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" $seq
 e3=$?
 wait $p1
 e1=$?
@@ -43,11 +43,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p4=$!
-functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
 p5=$!
-functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" $seq
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
index 10988c657..2800852fa 100755
--- a/utils/tests/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -35,11 +35,11 @@ functional $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" $seq
 e3=$?
 wait $p1
 e1=$?
@@ -50,11 +50,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p4=$!
-functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
 p5=$!
-functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" $seq
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
index 788d147ed..6e5ef8ffb 100755
--- a/utils/tests/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -26,9 +26,9 @@ functional $verbosity -i "netmap:pipeA}1"
 check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -36,9 +36,9 @@ check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-functional $verbosity -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e2=$?
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/send_rec_veth_test
index 11ab5f97f..3e4325dc5 100755
--- a/utils/tests/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -29,9 +29,9 @@ functional $verbosity -i netmap:veth1B
 check_success $? "pre-open netmap:veth1B"
 
 # veth1B --> veth1A
-functional $verbosity -i netmap:veth1A -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:veth1A -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i netmap:veth1B -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i netmap:veth1B -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -39,9 +39,9 @@ check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
 # veth1A --> veth1B
-functional $verbosity -i netmap:veth1B -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:veth1B -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i netmap:veth1A -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i netmap:veth1A -t "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
index 70738cf54..70955dc53 100755
--- a/utils/tests/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -32,9 +32,9 @@ functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -42,7 +42,7 @@ check_success $e1 "receive-${num} vale0:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
index bc8b42f98..8ff650e3d 100755
--- a/utils/tests/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -35,9 +35,9 @@ functional $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -45,7 +45,7 @@ check_success $e1 "receive-${num} netmap:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index 9c272bc44..38da76e2c 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -34,9 +34,9 @@ check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" -n &
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -47,11 +47,11 @@ check_success $e2 "send-${num} netmap:pipe{1"
 # monitored pipe otherwise the zero-copy monitor won't be able to see the
 # packet, as the slot is returned to the monitored pipe only during a txsync
 # action.
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" "$seq" &
+functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" $seq
 e4=$?
-functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" "$seq"
+functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
 e5=$?
 wait $p3
 e3=$?

From 015259fafc12f4a2022a5f4c27fed540f7b1b35b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 5 Jul 2018 09:41:15 +0200
Subject: [PATCH 0995/2207] functional: include stdint.h before net/netmap.h

---
 utils/functional.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/functional.c b/utils/functional.c
index 6efc25f0a..5342089d5 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -28,8 +28,8 @@
 #include 
 #include 
 #include 
-#include 
 #include 
+#include 
 #include 
 #include 
 #include 

From 90b3568c37df4c2fe8c5f1ea20999bc7d1ee9500 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 5 Jul 2018 10:00:56 +0200
Subject: [PATCH 0996/2207] functional: avoid strict-alising violation warning
 with gcc

---
 utils/fd_server.c  | 4 ++--
 utils/functional.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index b54a7258c..3ac01baee 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -192,7 +192,7 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 		cmsg->cmsg_level        = SOL_SOCKET;
 		cmsg->cmsg_type         = SCM_RIGHTS;
 		cmsg->cmsg_len          = CMSG_LEN(sizeof(int));
-		*(int *)CMSG_DATA(cmsg) = fd;
+		memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
 	}
 
 	ret = sendmsg(socket, &msg, 0);
@@ -346,4 +346,4 @@ main()
 	daemonize();
 	main_loop();
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/utils/functional.c b/utils/functional.c
index 5342089d5..a6d6bcdd9 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -966,7 +966,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	 * sent through the ancillary data.
 	 */
 	cmsg = CMSG_FIRSTHDR(&msg);
-	*fd  = *(int *)CMSG_DATA(cmsg);
+	memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
 
 	return amount;
 }

From 9f09de618f1235f1e58ead21a8eab78ca24eabbf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 6 Jul 2018 17:31:06 +0200
Subject: [PATCH 0997/2207] pipe: fix corner case in buffer release

---
 sys/dev/netmap/netmap_pipe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 1b4a9253c..eef2f1518 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -576,7 +576,7 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 			if (ring == NULL)
 				continue;
 
-			if (kring->pipe_tail == kring->nr_hwcur)
+			if (kring->tx == NR_RX)
 				ring->slot[kring->pipe_tail].buf_idx = 0;
 
 			for (j = nm_next(kring->pipe_tail, lim);

From cea166ef4d40700e7b9d8f5a7f8f6f05bd567757 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 10 Jul 2018 11:10:21 +0200
Subject: [PATCH 0998/2207] define the max number of fragments per packet

---
 sys/dev/netmap/netmap_vale.c | 3 +--
 sys/net/netmap.h             | 2 ++
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index e5ce6db9c..7965f2436 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -101,9 +101,8 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
 #define NM_BDG_MAXSLOTS		4096	/* XXX same as above */
 #define NM_BRIDGE_RINGSIZE	1024	/* in the device */
 #define NM_BDG_BATCH		1024	/* entries in the forwarding buffer */
-#define NM_MULTISEG		64	/* max size of a chain of bufs */
 /* actual size of the tables */
-#define NM_BDG_BATCH_MAX	(NM_BDG_BATCH + NM_MULTISEG)
+#define NM_BDG_BATCH_MAX	(NM_BDG_BATCH + NETMAP_MAX_FRAGS)
 /* NM_FT_NULL terminates a list of slots in the ft */
 #define NM_FT_NULL		NM_BDG_BATCH_MAX
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 87fbd8d26..ceab641a6 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -235,6 +235,8 @@ struct netmap_slot {
 	 *  are the number of fragments.
 	 */
 
+#define NETMAP_MAX_FRAGS	64	/* max number of fragments */
+
 
 /*
  * struct netmap_ring

From 96ce1b49b319bf13f196e4276f5bf62ef4ac193f Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Mon, 9 Jul 2018 18:12:07 +0200
Subject: [PATCH 0999/2207] bdg: support for multiple host rings on bwrap

---
 sys/dev/netmap/netmap_bdg.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 3929a057f..52611c236 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1436,6 +1436,10 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 				NMR(na, t)[i]->ring = NULL;
 			}
 		}
+		/* reset the number of host rings to default */
+		for_rx_tx(t) {
+			nma_set_host_nrings(hwna, t, 1);
+		}
 
 	}
 
@@ -1722,12 +1726,24 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 			na->na_flags |= NAF_SW_ONLY;
 		na->na_flags |= NAF_HOST_RINGS;
 		hostna = &bna->host.up;
+
+		/* limit the number of host rings to that of hw */
+		nm_bound_var(&hostna->num_tx_rings, 1, 1,
+				nma_get_nrings(hwna, NR_TX), NULL);
+		nm_bound_var(&hostna->num_rx_rings, 1, 1,
+				nma_get_nrings(hwna, NR_RX), NULL);
+
 		snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name);
 		hostna->ifp = hwna->ifp;
 		for_rx_tx(t) {
 			enum txrx r = nm_txrx_swap(t);
-			nma_set_nrings(hostna, t, 1);
-			nma_set_host_nrings(na, t, 1);
+			u_int nr = nma_get_nrings(hostna, t);
+
+			nma_set_nrings(hostna, t, nr);
+			nma_set_host_nrings(na, t, nr);
+			if (nma_get_host_nrings(hwna, t) < nr) {
+				nma_set_host_nrings(hwna, t, nr);
+			}
 			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
 		}
 		// hostna->nm_txsync = netmap_bwrap_host_txsync;

From 576f4d395b3dbeba4f9e3634b8e24eae4049d321 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 25 Jul 2018 15:37:23 +0200
Subject: [PATCH 1000/2207] linux: various fixes for the 4.17 vanilla patches

---
 ...e00--99999 => vanilla--i40e--40e00--41000} |   0
 .../final-patches/vanilla--i40e--41000--99999 | 115 +++++++++++++++++
 ...--99999 => vanilla--ixgbevf--40900--41100} |   0
 .../vanilla--ixgbevf--41100--99999            | 118 ++++++++++++++++++
 ...99 => vanilla--virtio_net.c--41000--41100} |   0
 .../vanilla--virtio_net.c--41100--99999       |  98 +++++++++++++++
 6 files changed, 331 insertions(+)
 rename LINUX/final-patches/{vanilla--i40e--40e00--99999 => vanilla--i40e--40e00--41000} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--41000--99999
 rename LINUX/final-patches/{vanilla--ixgbevf--40900--99999 => vanilla--ixgbevf--40900--41100} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--41100--99999
 rename LINUX/final-patches/{vanilla--virtio_net.c--41000--99999 => vanilla--virtio_net.c--41000--41100} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--41100--99999

diff --git a/LINUX/final-patches/vanilla--i40e--40e00--99999 b/LINUX/final-patches/vanilla--i40e--40e00--41000
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--40e00--99999
rename to LINUX/final-patches/vanilla--i40e--40e00--41000
diff --git a/LINUX/final-patches/vanilla--i40e--41000--99999 b/LINUX/final-patches/vanilla--i40e--41000--99999
new file mode 100644
index 000000000..241dd5ce5
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--41000--99999
@@ -0,0 +1,115 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index e31adbc75f9c..64564a6a1301 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -122,6 +122,10 @@ MODULE_LICENSE("GPL");
+ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+@@ -3195,6 +3199,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3246,6 +3254,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3274,6 +3286,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -12152,6 +12169,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -12519,6 +12541,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index e554aa6cf070..ec6957c8950a 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -32,6 +32,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -799,6 +803,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2135,6 +2144,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false, xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
diff --git a/LINUX/final-patches/vanilla--ixgbevf--40900--99999 b/LINUX/final-patches/vanilla--ixgbevf--40900--41100
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbevf--40900--99999
rename to LINUX/final-patches/vanilla--ixgbevf--40900--41100
diff --git a/LINUX/final-patches/vanilla--ixgbevf--41100--99999 b/LINUX/final-patches/vanilla--ixgbevf--41100--99999
new file mode 100644
index 000000000..81d73c84e
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--41100--99999
@@ -0,0 +1,118 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 850f8af95e49..14168d3a1ed7 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -279,6 +279,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -298,6 +316,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1117,6 +1147,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	while (likely(total_rx_packets < budget)) {
+@@ -1712,6 +1752,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1720,7 +1764,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(reg_idx));
+ 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ /**
+@@ -1946,6 +1990,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4688,6 +4736,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4728,6 +4780,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--41000--99999 b/LINUX/final-patches/vanilla--virtio_net.c--41000--41100
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--41000--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--41000--41100
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--41100--99999 b/LINUX/final-patches/vanilla--virtio_net.c--41100--99999
new file mode 100644
index 000000000..f76a4eae6
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--41100--99999
@@ -0,0 +1,98 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 032e1ac10a30..522036830681 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -212,6 +212,10 @@ struct virtnet_info {
+ 	unsigned long guest_offloads;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_mrg_rxbuf hdr;
+ 	/*
+@@ -308,6 +312,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -1277,6 +1286,18 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int received, qp;
+ 	bool xdp_xmit = false;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -1300,6 +1321,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
+ 		if (i < vi->curr_queue_pairs)
+@@ -2871,6 +2901,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	virtnet_set_queues(vi, vi->curr_queue_pairs);
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	netif_carrier_off(dev);
+@@ -2921,7 +2955,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -2988,6 +3029,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From 2d10c590fbf27eee9727b1c0bad0ee6295f7bb96 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 25 Jul 2018 15:39:44 +0200
Subject: [PATCH 1001/2207] pre-commit: exclude linux patches from whitespace
 checks

---
 pre-commit | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pre-commit b/pre-commit
index 4c177f234..15dfabd13 100755
--- a/pre-commit
+++ b/pre-commit
@@ -70,4 +70,4 @@ done
 ########### end of netmap specific checks ############
 
 # If there are whitespace errors, print the offending file names and fail.
-exec git diff-index --check --cached $against --
+exec git diff-index --check --cached $against ":(exclude)LINUX/final-patches"

From ec45cbc4144c70b9c433ca1595225485b21e89c9 Mon Sep 17 00:00:00 2001
From: John Gress 
Date: Thu, 26 Jul 2018 15:38:04 -0600
Subject: [PATCH 1002/2207] Allow buf_size greater than 4096.

---
 sys/dev/netmap/netmap_generic.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 2a6ca2531..aa00296f9 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1117,6 +1117,7 @@ generic_netmap_attach(struct ifnet *ifp)
 	na->ifp = ifp;
 	na->num_tx_desc = num_tx_desc;
 	na->num_rx_desc = num_rx_desc;
+   na->rx_buf_maxsize = 32768;
 	na->nm_register = &generic_netmap_register;
 	na->nm_txsync = &generic_netmap_txsync;
 	na->nm_rxsync = &generic_netmap_rxsync;

From e2e453ef4194eaf961d2058b1cdd0989b9c62ce7 Mon Sep 17 00:00:00 2001
From: John Gress 
Date: Thu, 26 Jul 2018 15:40:45 -0600
Subject: [PATCH 1003/2207] Use tab indentation.

---
 sys/dev/netmap/netmap_generic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index aa00296f9..277431ef1 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1117,7 +1117,7 @@ generic_netmap_attach(struct ifnet *ifp)
 	na->ifp = ifp;
 	na->num_tx_desc = num_tx_desc;
 	na->num_rx_desc = num_rx_desc;
-   na->rx_buf_maxsize = 32768;
+	na->rx_buf_maxsize = 32768;
 	na->nm_register = &generic_netmap_register;
 	na->nm_txsync = &generic_netmap_txsync;
 	na->nm_rxsync = &generic_netmap_rxsync;

From c742acf4fd33d123033ed4544ed3b259bd0b348a Mon Sep 17 00:00:00 2001
From: "David A. Bright" 
Date: Mon, 30 Jul 2018 20:40:25 -0500
Subject: [PATCH 1004/2207] Fix FreeBSD PR206053 - panic when adding netmap
 device to kqueue.

See FreeBSD PR206053 (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=206053) for details.
---
 sys/dev/netmap/netmap_freebsd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index eb16586c8..915d916be 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1502,7 +1502,7 @@ netmap_kqfilter(struct cdev *dev, struct knote *kn)
 	kn->kn_fop = (ev == EVFILT_WRITE) ?
 		&netmap_wfiltops : &netmap_rfiltops;
 	kn->kn_hook = priv;
-	knlist_add(&si->si.si_note, kn, 1);
+	knlist_add(&si->si.si_note, kn, 0);
 	// XXX unlock(priv)
 	ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s",
 		na, na->ifp->if_xname, curthread, priv, kn,

From 31fadfccd2e2f737d11f23d2faf472ce08eeec27 Mon Sep 17 00:00:00 2001
From: Stephen Petrides 
Date: Fri, 10 Aug 2018 15:14:42 +0000
Subject: [PATCH 1005/2207] change variable name to fix bug

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 32555af16..0623d4d57 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1920,7 +1920,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 				netmap_mem_bufsize(na->nm_mem);
 			ND("%s h %d c %d t %d", kring->name,
 				ring->head, ring->cur, ring->tail);
-			ND("initializing slots for %s_ring", nm_txrx2str(txrx));
+			ND("initializing slots for %s_ring", nm_txrx2str(t));
 			if (!(kring->nr_kflags & NKR_FAKERING)) {
 				/* this is a real ring */
 				ND("allocating buffers for %s", kring->name);

From 23685de00578f2434dfe3879e8f3e3b0748feeaf Mon Sep 17 00:00:00 2001
From: Stephen Hurd 
Date: Tue, 14 Aug 2018 22:09:38 -0400
Subject: [PATCH 1006/2207] Fix transposition of memset() arguments.

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 545db93c6..6fb2a9a0f 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -725,7 +725,7 @@ dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur)
 		ring->slot[cur].flags, len);
 	/* hexdump routine */
 	for (i = 0; i < len; ) {
-		memset(buf, sizeof(buf), ' ');
+		memset(buf, ' ', sizeof(buf));
 		sprintf(buf, "%5d: ", i);
 		i0 = i;
 		for (j=0; j < 16 && i < len; i++, j++)

From 0ffdd216bf349d9aec899bc317a53b727e7cb8ed Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 22 Aug 2018 14:12:29 +0200
Subject: [PATCH 1007/2207] linux/igb: add missing netmap suffix

---
 LINUX/final-patches/intel--igb--5.3.5.18 | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/LINUX/final-patches/intel--igb--5.3.5.18 b/LINUX/final-patches/intel--igb--5.3.5.18
index 6d099a9f5..a668552f8 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.18
+++ b/LINUX/final-patches/intel--igb--5.3.5.18
@@ -1,16 +1,19 @@
 diff --git a/igb/Makefile b/igb/Makefile
-index 02d49bb..47fd630 100644
+index 02d49bb..1267d14 100644
 --- a/igb/Makefile
 +++ b/igb/Makefile
-@@ -28,7 +28,7 @@ ifneq ($(KERNELRELEASE),)
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
  # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
  #
  
 -obj-$(CONFIG_IGB) += igb.o
 +obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
  
- define igb-y
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
  	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
 @@ -46,19 +46,19 @@ define igb-y
  	e1000_82575.o
  	e1000_i210.o

From 388afb183042fede69e89b7cc26aab501e196a41 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 25 Aug 2018 19:33:50 +0200
Subject: [PATCH 1008/2207] apps: pkt-gen: fix compilation issue

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 6fb2a9a0f..aabae97bf 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -954,7 +954,7 @@ initialize_packet(struct targ *targ)
 	struct udphdr udp;
 	void *udp_ptr;
 	uint16_t paylen;
-	uint32_t csum;
+	uint32_t csum = 0;
 	const char *payload = targ->g->options & OPT_INDIRECT ?
 		indirect_payload : default_payload;
 	int i, l0 = strlen(payload);

From ab0cc1ee5873075183159e1903c570ebcf47393c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Aug 2018 15:35:48 +0200
Subject: [PATCH 1009/2207] utils: fix compiler warnings

---
 utils/ctrl-api-test.c | 2 +-
 utils/functional.c    | 4 ++--
 utils/testmmap.c      | 8 ++++----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 51da3f73e..0117ec07e 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -50,7 +50,7 @@ nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
 {
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->nr_version = NETMAP_API;
-	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
+	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name)-1);
 }
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
diff --git a/utils/functional.c b/utils/functional.c
index a6d6bcdd9..ea7570c3a 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -988,7 +988,7 @@ get_if_fd(struct Global *g, const char *if_name)
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_GET;
-	strncpy(req.if_name, if_name, sizeof(req.if_name));
+	strncpy(req.if_name, if_name, sizeof(req.if_name)-1);
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret < 0) {
 		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
@@ -1032,7 +1032,7 @@ release_if_fd(struct Global *g, const char *if_name)
 
 	memset(&req, 0, sizeof(req));
 	req.action = FD_RELEASE;
-	strncpy(req.if_name, if_name, sizeof(req.if_name));
+	strncpy(req.if_name, if_name, sizeof(req.if_name)-1);
 
 	ret = send(socket_fd, &req, sizeof(req), 0);
 	if (ret <= 0) {
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 19d0208fb..9979270cf 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -204,7 +204,7 @@ do_getinfo_legacy()
 
 	name = nextarg();
 	if (name) {
-		strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name));
+		strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name)-1);
 	} else {
 		name = "any";
 	}
@@ -242,7 +242,7 @@ do_regif_legacy()
 	bzero(&curr_nmr, sizeof(curr_nmr));
 	curr_nmr.nr_version = NETMAP_API;
 	curr_nmr.nr_flags   = NR_REG_ALL_NIC;
-	strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name));
+	strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name)-1);
 
 	arg = nextarg();
 	if (!arg) {
@@ -1180,7 +1180,7 @@ do_nmr_legacy_name()
 {
 	char *name = nextarg();
 	if (name) {
-		strncpy(curr_nmr.nr_name, name, IFNAMSIZ);
+		strncpy(curr_nmr.nr_name, name, IFNAMSIZ-1);
 	}
 	strncpy(nmr_name, curr_nmr.nr_name, IFNAMSIZ);
 	nmr_name[IFNAMSIZ] = '\0';
@@ -1735,7 +1735,7 @@ do_hdr_name()
 {
 	char *name = nextarg();
 	if (name) {
-		strncpy(curr_hdr.nr_name, name, NETMAP_REQ_IFNAMSIZ);
+		strncpy(curr_hdr.nr_name, name, NETMAP_REQ_IFNAMSIZ-1);
 	}
 	strncpy(nmr_name, curr_hdr.nr_name, NETMAP_REQ_IFNAMSIZ);
 	nmr_name[NETMAP_REQ_IFNAMSIZ] = '\0';

From 345e2c9f6b468433585a3e0756156babdf3ff09c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 Aug 2018 15:38:53 +0200
Subject: [PATCH 1010/2207] utils: randomized_tests: check for root effective
 user id

---
 utils/randomized_tests | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index d498eb103..57a1ad31d 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -3,6 +3,12 @@
 # Runs all the tests using randomized values for number of packets, fill
 # character and packets length.
 ################################################################################
+
+if [ "$EUID" -ne "0" ]; then
+   echo "This script must be run as root"
+   exit 1
+fi
+
 random_num="$((65 + $RANDOM % 58))"
 # https://stackoverflow.com/a/10503163
 random_fill=$(printf \\$(printf '%03o' $random_num))
@@ -14,6 +20,7 @@ random_packet_num="$((1 + $RANDOM % 100))"
 # Use and empty string instead of "-q" if you don't want to perform a sequential
 # send/receive check
 seq_check="-q"
+
 echo "Running tests with"
 echo "   number of packets: ${random_packet_num}"
 echo "   fill character   : ${random_fill}"
@@ -38,4 +45,4 @@ for test in tests/*_test ; do
 		$test -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 		exit $?
 	fi
-done
\ No newline at end of file
+done

From e78b1496ded0e133fc0180cc0fa9d83034391363 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 30 Aug 2018 11:47:18 +0200
Subject: [PATCH 1011/2207] linux/e1000e: patch for Intel 3.4.2.1 version

---
 LINUX/final-patches/intel--e1000e--3.4.2.1 | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.4.2.1

diff --git a/LINUX/final-patches/intel--e1000e--3.4.2.1 b/LINUX/final-patches/intel--e1000e--3.4.2.1
new file mode 100644
index 000000000..36098a3e3
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.4.2.1
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index 6b73b2c..dfc2900 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -15,7 +15,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -118,7 +118,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -324,6 +324,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index fc51f96..d84222f 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -482,6 +482,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1005,6 +1009,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1322,6 +1337,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4238,6 +4258,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8438,6 +8462,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8539,6 +8567,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 8c69a48711074113d0494da212ce7f8e32c4441b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 30 Aug 2018 12:08:15 +0200
Subject: [PATCH 1012/2207] linux/igb: patch for Intel 5.3.5.20 version

---
 LINUX/final-patches/intel--igb--5.3.5.20 | 134 +++++++++++++++++++++++
 1 file changed, 134 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.20

diff --git a/LINUX/final-patches/intel--igb--5.3.5.20 b/LINUX/final-patches/intel--igb--5.3.5.20
new file mode 100644
index 000000000..491e65f5c
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.20
@@ -0,0 +1,134 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 02d49bb..8a35007 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -46,19 +46,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -118,6 +118,9 @@ ccc: clean
+ manfile:
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index f7f9095..86990f4 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * igb_init_module - Driver Registration Routine
+  *
+@@ -3071,6 +3075,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3274,6 +3282,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3684,6 +3696,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7236,6 +7251,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8252,6 +8272,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8571,6 +8596,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 282f404ccb4fc777056a591127060e29657c9ab7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 2 Sep 2018 11:24:52 +0200
Subject: [PATCH 1013/2207] update vale(4)

---
 share/man/man4/vale.4 | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
index 53deef2bb..4917632ce 100644
--- a/share/man/man4/vale.4
+++ b/share/man/man4/vale.4
@@ -59,18 +59,18 @@ API.
 .Pp
 .Nm
 ports are named
-.Pa vale[bdg:][port]
+.Pa valeSSS:PPP
 where
 .Pa vale
 is the prefix indicating a VALE switch rather than a standard interface,
-.Pa bdg
+.Pa SSS
 indicates a specific switch (the colon is a separator),
 and
-.Pa port
+.Pa PPP
 indicates a port within the switch.
-Bridge and port names are arbitrary strings, the only
-constraint being that the full name must fit within 16
-characters.
+Both SSS and PPP have the form [0-9a-zA-Z_]+ , the string cannot
+exceed IFNAMSIZ characters, and PPP cannot be the name of any
+existing OS network interface.
 .Pp
 See
 .Xr netmap 4

From 9dfe99368af4126ec48c8f147ada96e8f5a0a00e Mon Sep 17 00:00:00 2001
From: John-Mark Gurney 
Date: Sun, 2 Sep 2018 16:17:32 -0700
Subject: [PATCH 1014/2207] this seems to be old, many other places say it
 works..

---
 share/man/man4/netmap.4 | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index bb09a6626..368d8cc6a 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -218,12 +218,6 @@ Non-blocking I/O is done with special
 and
 .Xr poll 2
 on the file descriptor permit blocking I/O.
-.Xr epoll 2
-and
-.Xr kqueue 2
-are not supported on
-.Nm
-file descriptors.
 .Pp
 While a NIC is in
 .Nm

From 0e92c6d15c9a69fa2dcc3e35155f745f423878f3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 4 Sep 2018 20:39:59 +0200
Subject: [PATCH 1015/2207] netmap_freebsd, if_ptnet: import fixes from FreeBSD
 head

---
 sys/dev/netmap/if_ptnet.c       | 2 +-
 sys/dev/netmap/netmap_freebsd.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 0afbd936b..55137f270 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -757,7 +757,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 	struct ptnet_softc *sc = if_getsoftc(ifp);
 	device_t dev = sc->dev;
 	struct ifreq *ifr = (struct ifreq *)data;
-	int mask, err = 0;
+	int mask __unused, err = 0;
 
 	switch (cmd) {
 	case SIOCSIFFLAGS:
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 915d916be..436b3ad71 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -630,7 +630,7 @@ struct nm_os_extmem {
 	vm_object_t obj;
 	vm_offset_t kva;
 	vm_offset_t size;
-	vm_pindex_t scan;
+	uintptr_t scan;
 };
 
 void

From 8374e1a7e69413630ac1bbd9a46955af189dc66a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 4 Sep 2018 20:40:59 +0200
Subject: [PATCH 1016/2207] freebsd: fix bug in nm_os_extmem_isequal()

---
 sys/dev/netmap/netmap_freebsd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 436b3ad71..e8e68e6c0 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -655,7 +655,7 @@ nm_os_extmem_nextpage(struct nm_os_extmem *e)
 int
 nm_os_extmem_isequal(struct nm_os_extmem *e1, struct nm_os_extmem *e2)
 {
-	return (e1->obj == e1->obj);
+	return (e1->obj == e2->obj);
 }
 
 int

From 059803648c8b86b4d3413a5bd7517f357c81d3d6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 5 Sep 2018 12:37:00 +0200
Subject: [PATCH 1017/2207] sys/modules/netmap/Makefile: add missing
 netmap_bdg.c

---
 sys/modules/netmap/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index a17b21dd3..f16ed4ebe 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -22,6 +22,7 @@ SRCS	+= netmap_pipe.c
 SRCS	+= netmap_monitor.c
 SRCS	+= netmap_pt.c
 SRCS	+= netmap_legacy.c
+SRCS	+= netmap_bdg.c
 SRCS	+= if_ptnet.c
 SRCS	+= opt_inet.h opt_inet6.h
 

From f97b2b26fd3d5753ef72a7ac289b4d5246b08ff8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 5 Sep 2018 12:37:45 +0200
Subject: [PATCH 1018/2207] freebsd: fix crash on 12.x when netmap is loaded as
 a module

---
 sys/modules/netmap/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index f16ed4ebe..bfb6d7fb3 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -8,7 +8,7 @@
 
 .PATH: ${.CURDIR}/../../dev/netmap
 .PATH.h: ${.CURDIR}/../../net
-CFLAGS += -I${.CURDIR}/../../ -D INET
+CFLAGS += -I${.CURDIR}/../../ -D INET -D VIMAGE
 KMOD	= netmap
 SRCS	= device_if.h bus_if.h pci_if.h opt_netmap.h
 SRCS	+= netmap.c netmap.h netmap_kern.h

From a576fc4172833d77188494229a09bb725f3dc5c2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Sep 2018 14:58:20 +0200
Subject: [PATCH 1019/2207] bdg: move bdg related declarations to netmap_bdg.h

---
 LINUX/netmap_linux.c           |  1 +
 sys/dev/netmap/netmap_bdg.h    | 42 ++++++++++++++++++++++++++++++-
 sys/dev/netmap/netmap_kern.h   | 45 +++-------------------------------
 sys/dev/netmap/netmap_legacy.c |  1 +
 4 files changed, 46 insertions(+), 43 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index f8eae2986..c3c1fe0fd 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 6e4048cec..2e0ef564c 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -15,6 +15,40 @@
 
 #endif /* __FreeBSD__ */
 
+/*
+ * The following bridge-related functions are used by other
+ * kernel modules.
+ *
+ * VALE only supports unicast or broadcast. The lookup
+ * function can return 0 .. NM_BDG_MAXPORTS-1 for regular ports,
+ * NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 to indicate
+ * drop.
+ */
+typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
+		struct netmap_vp_adapter *, void *private_data);
+typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
+typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
+typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
+typedef int (*bdg_vp_create_fn_t)(struct nmreq_header *hdr,
+		struct ifnet *ifp, struct netmap_mem_d *nmd,
+		struct netmap_vp_adapter **ret);
+typedef int (*bdg_bwrap_attach_fn_t)(const char *nr_name, struct netmap_adapter *hwna);
+struct netmap_bdg_ops {
+	bdg_lookup_fn_t lookup;
+	bdg_config_fn_t config;
+	bdg_dtor_fn_t	dtor;
+	bdg_vp_create_fn_t	vp_create;
+	bdg_bwrap_attach_fn_t	bwrap_attach;
+	char name[IFNAMSIZ];
+};
+int netmap_bwrap_attach(const char *name, struct netmap_adapter *, struct netmap_bdg_ops *);
+int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
+
+#define	NM_BRIDGES		8	/* number of bridges */
+#define	NM_BDG_MAXPORTS		254	/* up to 254 */
+#define	NM_BDG_BROADCAST	NM_BDG_MAXPORTS
+#define	NM_BDG_NOPORT		(NM_BDG_MAXPORTS+1)
+
 /* XXX Should go away after fixing find_bridge() - Michio */
 #define NM_BDG_HASH		1024	/* forwarding table entries */
 
@@ -66,7 +100,7 @@ struct nm_bridge {
 	 * different ring index.
 	 * The function is set by netmap_bdg_regops().
 	 */
-	struct netmap_bdg_ops *bdg_ops;
+	struct netmap_bdg_ops* bdg_ops;
 
 	/*
 	 * Contains the data structure used by the bdg_ops.lookup function.
@@ -121,6 +155,12 @@ int netmap_bwrap_attach_common(struct netmap_adapter *na,
 		struct netmap_adapter *hwna);
 int netmap_bwrap_krings_create_common(struct netmap_adapter *na);
 void netmap_bwrap_krings_delete_common(struct netmap_adapter *na);
+struct nm_bridge *netmap_init_bridges2(u_int);
+void netmap_uninit_bridges2(struct nm_bridge *, u_int);
+int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
+	void *callback_data, void *auth_token);
+int netmap_bdg_config(struct nm_ifreq *nifr);
+
 #define NM_NEED_BWRAP (-2)
 #endif /* _NET_NETMAP_BDG_H_ */
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d7f1e1659..e86b9e5c7 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1441,48 +1441,6 @@ int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
 
 
-/*
- * The following bridge-related functions are used by other
- * kernel modules.
- *
- * VALE only supports unicast or broadcast. The lookup
- * function can return 0 .. NM_BDG_MAXPORTS-1 for regular ports,
- * NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 to indicate
- * drop.
- */
-typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
-		struct netmap_vp_adapter *, void *private_data);
-typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
-typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
-typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
-typedef int (*bdg_vp_create_fn_t)(struct nmreq_header *hdr,
-		struct ifnet *ifp, struct netmap_mem_d *nmd,
-		struct netmap_vp_adapter **ret);
-typedef int (*bdg_bwrap_attach_fn_t)(const char *nr_name, struct netmap_adapter *hwna);
-struct netmap_bdg_ops {
-	bdg_lookup_fn_t lookup;
-	bdg_config_fn_t config;
-	bdg_dtor_fn_t	dtor;
-	bdg_vp_create_fn_t	vp_create;
-	bdg_bwrap_attach_fn_t	bwrap_attach;
-	char name[IFNAMSIZ];
-};
-int netmap_bwrap_attach(const char *name, struct netmap_adapter *, struct netmap_bdg_ops *);
-int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
-
-#define	NM_BRIDGES		8	/* number of bridges */
-#define	NM_BDG_MAXPORTS		254	/* up to 254 */
-#define	NM_BDG_BROADCAST	NM_BDG_MAXPORTS
-#define	NM_BDG_NOPORT		(NM_BDG_MAXPORTS+1)
-
-struct nm_bridge *netmap_init_bridges2(u_int);
-void netmap_uninit_bridges2(struct nm_bridge *, u_int);
-int netmap_init_bridges(void);
-void netmap_uninit_bridges(void);
-int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
-	void *callback_data, void *auth_token);
-int netmap_bdg_config(struct nm_ifreq *nifr);
-
 #ifdef WITH_VALE
 uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *, void *private_data);
@@ -2353,4 +2311,7 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
 int nmreq_checkduplicate(struct nmreq_option *);
 
+int netmap_init_bridges(void);
+void netmap_uninit_bridges(void);
+
 #endif /* _NET_NETMAP_KERN_H_ */
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 762810a61..2d80e803b 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -52,6 +52,7 @@
  */
 #include 
 #include 
+#include 
 
 static int
 nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,

From 36528394ff5a922c27eb6b396ebca4fee1f88313 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 11:53:19 +0200
Subject: [PATCH 1020/2207] bdg: remove dependency on VALE

---
 sys/dev/netmap/netmap_bdg.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 52611c236..dd4eded7c 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -139,15 +139,15 @@ nm_is_id_char(const char c)
 	       (c == '_');
 }
 
-/* Validate the name of a VALE bridge port and return the
+/* Validate the name of a bdg port and return the
  * position of the ":" character. */
 static int
-nm_vale_name_validate(const char *name)
+nm_bdg_name_validate(const char *name, size_t prefixlen)
 {
 	int colon_pos = -1;
 	int i;
 
-	if (!name || strlen(name) < strlen(NM_BDG_NAME)) {
+	if (!name || strlen(name) < prefixlen) {
 		return -1;
 	}
 
@@ -186,7 +186,8 @@ nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
 
 	netmap_bns_getbridges(&bridges, &num_bridges);
 
-	namelen = nm_vale_name_validate(name);
+	namelen = nm_bdg_name_validate(name,
+			(ops != NULL ? strlen(ops->name) : 0));
 	if (namelen < 0) {
 		D("invalid bridge name %s", name ? name : NULL);
 		return NULL;

From 7177743ffb487cb549455a345aa457289ff92995 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 12:29:40 +0200
Subject: [PATCH 1021/2207] vale: move and rename vale-specific functions to
 netmap_vale.c

---
 LINUX/netmap_linux.c         |   4 +-
 sys/dev/netmap/netmap.c      |   6 +-
 sys/dev/netmap/netmap_bdg.c  | 211 +----------------------------------
 sys/dev/netmap/netmap_bdg.h  |   1 +
 sys/dev/netmap/netmap_kern.h |   6 +-
 sys/dev/netmap/netmap_vale.c | 210 ++++++++++++++++++++++++++++++++++
 6 files changed, 220 insertions(+), 218 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index c3c1fe0fd..970af62b7 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2671,8 +2671,8 @@ EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
 EXPORT_SYMBOL(nm_bdg_update_private_data);
 EXPORT_SYMBOL(netmap_vale_create);
 EXPORT_SYMBOL(netmap_vale_destroy);
-EXPORT_SYMBOL(nm_bdg_ctl_attach);
-EXPORT_SYMBOL(nm_bdg_ctl_detach);
+EXPORT_SYMBOL(netmap_vale_attach);
+EXPORT_SYMBOL(netmap_vale_detach);
 EXPORT_SYMBOL(nm_vi_create);
 EXPORT_SYMBOL(nm_vi_destroy);
 #endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0837c0cc1..9e0f093d5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2517,17 +2517,17 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 #ifdef WITH_VALE
 		case NETMAP_REQ_VALE_ATTACH: {
-			error = nm_bdg_ctl_attach(hdr, NULL /* userspace request */);
+			error = netmap_vale_attach(hdr, NULL /* userspace request */);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_DETACH: {
-			error = nm_bdg_ctl_detach(hdr, NULL /* userspace request */);
+			error = netmap_vale_detach(hdr, NULL /* userspace request */);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_LIST: {
-			error = netmap_bdg_list(hdr);
+			error = netmap_vale_list(hdr);
 			break;
 		}
 
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index dd4eded7c..df3896e1a 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -503,142 +503,13 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	return error;
 }
 
-/* Process NETMAP_REQ_VALE_ATTACH.
- */
-int
-nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token)
-{
-	struct nmreq_vale_attach *req =
-		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
-	struct netmap_vp_adapter * vpna;
-	struct netmap_adapter *na = NULL;
-	struct netmap_mem_d *nmd = NULL;
-	struct nm_bridge *b = NULL;
-	int error;
-
-	NMG_LOCK();
-	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
-	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_exit;
-	}
-
-	if (req->reg.nr_mem_id) {
-		nmd = netmap_mem_find(req->reg.nr_mem_id);
-		if (nmd == NULL) {
-			error = EINVAL;
-			goto unlock_exit;
-		}
-	}
-
-	/* check for existing one */
-	error = netmap_get_vale_na(hdr, &na, nmd, 0);
-	if (na) {
-		error = EBUSY;
-		goto unref_exit;
-	}
-	error = netmap_get_vale_na(hdr, &na,
-				nmd, 1 /* create if not exists */);
-	if (error) { /* no device */
-		goto unlock_exit;
-	}
-
-	if (na == NULL) { /* VALE prefix missing */
-		error = EINVAL;
-		goto unlock_exit;
-	}
-
-	if (NETMAP_OWNED_BY_ANY(na)) {
-		error = EBUSY;
-		goto unref_exit;
-	}
 
-	if (na->nm_bdg_ctl) {
-		/* nop for VALE ports. The bwrap needs to put the hwna
-		 * in netmap mode (see netmap_bwrap_bdg_ctl)
-		 */
-		error = na->nm_bdg_ctl(hdr, na);
-		if (error)
-			goto unref_exit;
-		ND("registered %s to netmap-mode", na->name);
-	}
-	vpna = (struct netmap_vp_adapter *)na;
-	req->port_index = vpna->bdg_port;
-	NMG_UNLOCK();
-	return 0;
-
-unref_exit:
-	netmap_adapter_put(na);
-unlock_exit:
-	NMG_UNLOCK();
-	return error;
-}
-
-static inline int
+int
 nm_is_bwrap(struct netmap_adapter *na)
 {
 	return na->nm_register == netmap_bwrap_reg;
 }
 
-/* Process NETMAP_REQ_VALE_DETACH.
- */
-int
-nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token)
-{
-	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
-	struct netmap_vp_adapter *vpna;
-	struct netmap_adapter *na;
-	struct nm_bridge *b = NULL;
-	int error;
-
-	NMG_LOCK();
-	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
-	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_exit;
-	}
-
-	error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */);
-	if (error) { /* no device, or another bridge or user owns the device */
-		goto unlock_exit;
-	}
-
-	if (na == NULL) { /* VALE prefix missing */
-		error = EINVAL;
-		goto unlock_exit;
-	} else if (nm_is_bwrap(na) &&
-		   ((struct netmap_bwrap_adapter *)na)->na_polling_state) {
-		/* Don't detach a NIC with polling */
-		error = EBUSY;
-		goto unref_exit;
-	}
-
-	vpna = (struct netmap_vp_adapter *)na;
-	if (na->na_vp != vpna) {
-		/* trying to detach first attach of VALE persistent port attached
-		 * to 2 bridges
-		 */
-		error = EBUSY;
-		goto unref_exit;
-	}
-	nmreq_det->port_index = vpna->bdg_port;
-
-	if (na->nm_bdg_ctl) {
-		/* remove the port from bridge. The bwrap
-		 * also needs to put the hwna in normal mode
-		 */
-		error = na->nm_bdg_ctl(hdr, na);
-	}
-
-unref_exit:
-	netmap_adapter_put(na);
-unlock_exit:
-	NMG_UNLOCK();
-	return error;
-
-}
 
 struct nm_bdg_polling_state;
 struct
@@ -933,86 +804,6 @@ nm_bdg_polling(struct nmreq_header *hdr)
 	return error;
 }
 
-/* Process NETMAP_REQ_VALE_LIST. */
-int
-netmap_bdg_list(struct nmreq_header *hdr)
-{
-	struct nmreq_vale_list *req =
-		(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
-	int namelen = strlen(hdr->nr_name);
-	struct nm_bridge *b, *bridges;
-	struct netmap_vp_adapter *vpna;
-	int error = 0, i, j;
-	u_int num_bridges;
-
-	netmap_bns_getbridges(&bridges, &num_bridges);
-
-	/* this is used to enumerate bridges and ports */
-	if (namelen) { /* look up indexes of bridge and port */
-		if (strncmp(hdr->nr_name, NM_BDG_NAME,
-					strlen(NM_BDG_NAME))) {
-			return EINVAL;
-		}
-		NMG_LOCK();
-		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
-		if (!b) {
-			NMG_UNLOCK();
-			return ENOENT;
-		}
-
-		req->nr_bridge_idx = b - bridges; /* bridge index */
-		req->nr_port_idx = NM_BDG_NOPORT;
-		for (j = 0; j < b->bdg_active_ports; j++) {
-			i = b->bdg_port_index[j];
-			vpna = b->bdg_ports[i];
-			if (vpna == NULL) {
-				D("This should not happen");
-				continue;
-			}
-			/* the former and the latter identify a
-			 * virtual port and a NIC, respectively
-			 */
-			if (!strcmp(vpna->up.name, hdr->nr_name)) {
-				req->nr_port_idx = i; /* port index */
-				break;
-			}
-		}
-		NMG_UNLOCK();
-	} else {
-		/* return the first non-empty entry starting from
-		 * bridge nr_arg1 and port nr_arg2.
-		 *
-		 * Users can detect the end of the same bridge by
-		 * seeing the new and old value of nr_arg1, and can
-		 * detect the end of all the bridge by error != 0
-		 */
-		i = req->nr_bridge_idx;
-		j = req->nr_port_idx;
-
-		NMG_LOCK();
-		for (error = ENOENT; i < NM_BRIDGES; i++) {
-			b = bridges + i;
-			for ( ; j < NM_BDG_MAXPORTS; j++) {
-				if (b->bdg_ports[j] == NULL)
-					continue;
-				vpna = b->bdg_ports[j];
-				/* write back the VALE switch name */
-				strncpy(hdr->nr_name, vpna->up.name,
-					(size_t)IFNAMSIZ);
-				error = 0;
-				goto out;
-			}
-			j = 0; /* following bridges scan from 0 */
-		}
-	out:
-		req->nr_bridge_idx = i;
-		req->nr_port_idx = j;
-		NMG_UNLOCK();
-	}
-
-	return error;
-}
-
 /* Called by external kernel modules (e.g., Openvswitch).
  * to set configure/lookup/dtor functions of a VALE instance.
  * Register callbacks to the given bridge. 'name' may be just
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 2e0ef564c..fad13b393 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -160,6 +160,7 @@ void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
 	void *callback_data, void *auth_token);
 int netmap_bdg_config(struct nm_ifreq *nifr);
+int nm_is_bwrap(struct netmap_adapter *);
 
 #define NM_NEED_BWRAP (-2)
 #endif /* _NET_NETMAP_BDG_H_ */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e86b9e5c7..283118bbd 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1078,12 +1078,12 @@ struct netmap_bwrap_adapter {
 	 */
 	struct netmap_vp_adapter *saved_na_vp;
 };
-int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
-int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
 int nm_bdg_polling(struct nmreq_header *hdr);
-int netmap_bdg_list(struct nmreq_header *hdr);
 
 #ifdef WITH_VALE
+int netmap_vale_attach(struct nmreq_header *hdr, void *auth_token);
+int netmap_vale_detach(struct nmreq_header *hdr, void *auth_token);
+int netmap_vale_list(struct nmreq_header *hdr);
 int netmap_vi_create(struct nmreq_header *hdr, int);
 int nm_vi_create(struct nmreq_header *);
 int nm_vi_destroy(const char *name);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 7965f2436..a1bc32ef3 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -305,6 +305,216 @@ netmap_vale_destroy(const char *bdg_name, void *auth_token)
 	return ret;
 }
 
+/* Process NETMAP_REQ_VALE_LIST. */
+int
+netmap_vale_list(struct nmreq_header *hdr)
+{
+	struct nmreq_vale_list *req =
+		(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
+	int namelen = strlen(hdr->nr_name);
+	struct nm_bridge *b, *bridges;
+	struct netmap_vp_adapter *vpna;
+	int error = 0, i, j;
+	u_int num_bridges;
+
+	netmap_bns_getbridges(&bridges, &num_bridges);
+
+	/* this is used to enumerate bridges and ports */
+	if (namelen) { /* look up indexes of bridge and port */
+		if (strncmp(hdr->nr_name, NM_BDG_NAME,
+					strlen(NM_BDG_NAME))) {
+			return EINVAL;
+		}
+		NMG_LOCK();
+		b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
+		if (!b) {
+			NMG_UNLOCK();
+			return ENOENT;
+		}
+
+		req->nr_bridge_idx = b - bridges; /* bridge index */
+		req->nr_port_idx = NM_BDG_NOPORT;
+		for (j = 0; j < b->bdg_active_ports; j++) {
+			i = b->bdg_port_index[j];
+			vpna = b->bdg_ports[i];
+			if (vpna == NULL) {
+				D("This should not happen");
+				continue;
+			}
+			/* the former and the latter identify a
+			 * virtual port and a NIC, respectively
+			 */
+			if (!strcmp(vpna->up.name, hdr->nr_name)) {
+				req->nr_port_idx = i; /* port index */
+				break;
+			}
+		}
+		NMG_UNLOCK();
+	} else {
+		/* return the first non-empty entry starting from
+		 * bridge nr_arg1 and port nr_arg2.
+		 *
+		 * Users can detect the end of the same bridge by
+		 * seeing the new and old value of nr_arg1, and can
+		 * detect the end of all the bridge by error != 0
+		 */
+		i = req->nr_bridge_idx;
+		j = req->nr_port_idx;
+
+		NMG_LOCK();
+		for (error = ENOENT; i < NM_BRIDGES; i++) {
+			b = bridges + i;
+			for ( ; j < NM_BDG_MAXPORTS; j++) {
+				if (b->bdg_ports[j] == NULL)
+					continue;
+				vpna = b->bdg_ports[j];
+				/* write back the VALE switch name */
+				strncpy(hdr->nr_name, vpna->up.name,
+					(size_t)IFNAMSIZ);
+				error = 0;
+				goto out;
+			}
+			j = 0; /* following bridges scan from 0 */
+		}
+	out:
+		req->nr_bridge_idx = i;
+		req->nr_port_idx = j;
+		NMG_UNLOCK();
+	}
+
+	return error;
+}
+
+/* Process NETMAP_REQ_VALE_ATTACH.
+ */
+int
+netmap_vale_attach(struct nmreq_header *hdr, void *auth_token)
+{
+	struct nmreq_vale_attach *req =
+		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
+	struct netmap_vp_adapter * vpna;
+	struct netmap_adapter *na = NULL;
+	struct netmap_mem_d *nmd = NULL;
+	struct nm_bridge *b = NULL;
+	int error;
+
+	NMG_LOCK();
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_exit;
+	}
+
+	if (req->reg.nr_mem_id) {
+		nmd = netmap_mem_find(req->reg.nr_mem_id);
+		if (nmd == NULL) {
+			error = EINVAL;
+			goto unlock_exit;
+		}
+	}
+
+	/* check for existing one */
+	error = netmap_get_vale_na(hdr, &na, nmd, 0);
+	if (na) {
+		error = EBUSY;
+		goto unref_exit;
+	}
+	error = netmap_get_vale_na(hdr, &na,
+				nmd, 1 /* create if not exists */);
+	if (error) { /* no device */
+		goto unlock_exit;
+	}
+
+	if (na == NULL) { /* VALE prefix missing */
+		error = EINVAL;
+		goto unlock_exit;
+	}
+
+	if (NETMAP_OWNED_BY_ANY(na)) {
+		error = EBUSY;
+		goto unref_exit;
+	}
+
+	if (na->nm_bdg_ctl) {
+		/* nop for VALE ports. The bwrap needs to put the hwna
+		 * in netmap mode (see netmap_bwrap_bdg_ctl)
+		 */
+		error = na->nm_bdg_ctl(hdr, na);
+		if (error)
+			goto unref_exit;
+		ND("registered %s to netmap-mode", na->name);
+	}
+	vpna = (struct netmap_vp_adapter *)na;
+	req->port_index = vpna->bdg_port;
+	NMG_UNLOCK();
+	return 0;
+
+unref_exit:
+	netmap_adapter_put(na);
+unlock_exit:
+	NMG_UNLOCK();
+	return error;
+}
+
+/* Process NETMAP_REQ_VALE_DETACH.
+ */
+int
+netmap_vale_detach(struct nmreq_header *hdr, void *auth_token)
+{
+	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
+	struct netmap_vp_adapter *vpna;
+	struct netmap_adapter *na;
+	struct nm_bridge *b = NULL;
+	int error;
+
+	NMG_LOCK();
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_exit;
+	}
+
+	error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */);
+	if (error) { /* no device, or another bridge or user owns the device */
+		goto unlock_exit;
+	}
+
+	if (na == NULL) { /* VALE prefix missing */
+		error = EINVAL;
+		goto unlock_exit;
+	} else if (nm_is_bwrap(na) &&
+		   ((struct netmap_bwrap_adapter *)na)->na_polling_state) {
+		/* Don't detach a NIC with polling */
+		error = EBUSY;
+		goto unref_exit;
+	}
+
+	vpna = (struct netmap_vp_adapter *)na;
+	if (na->na_vp != vpna) {
+		/* trying to detach first attach of VALE persistent port attached
+		 * to 2 bridges
+		 */
+		error = EBUSY;
+		goto unref_exit;
+	}
+	nmreq_det->port_index = vpna->bdg_port;
+
+	if (na->nm_bdg_ctl) {
+		/* remove the port from bridge. The bwrap
+		 * also needs to put the hwna in normal mode
+		 */
+		error = na->nm_bdg_ctl(hdr, na);
+	}
+
+unref_exit:
+	netmap_adapter_put(na);
+unlock_exit:
+	NMG_UNLOCK();
+	return error;
+
+}
 
 
 /* nm_dtor callback for ephemeral VALE ports */

From 2cda5cb494ece3736d6dfebbed2f9fd01a21ab21 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 13:29:13 +0200
Subject: [PATCH 1022/2207] bdg: move bdg-level function from netmap_vale.c to
 netmap_bdg.c

---
 sys/dev/netmap/netmap_bdg.c  | 35 +++++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_vale.c | 34 ----------------------------------
 2 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index df3896e1a..4493c3627 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -247,6 +247,41 @@ netmap_bdg_free(struct nm_bridge *b)
 	return 0;
 }
 
+/* Called by external kernel modules (e.g., Openvswitch).
+ * to modify the private data previously given to regops().
+ * 'name' may be just bridge's name (including ':' if it
+ * is not just NM_BDG_NAME).
+ * Called without NMG_LOCK.
+ */
+int
+nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
+	void *callback_data, void *auth_token)
+{
+	void *private_data = NULL;
+	struct nm_bridge *b;
+	int error = 0;
+
+	NMG_LOCK();
+	b = nm_find_bridge(name, 0 /* don't create */, NULL);
+	if (!b) {
+		error = EINVAL;
+		goto unlock_update_priv;
+	}
+	if (!nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_update_priv;
+	}
+	BDG_WLOCK(b);
+	private_data = callback(b->private_data, callback_data, &error);
+	b->private_data = private_data;
+	BDG_WUNLOCK(b);
+
+unlock_update_priv:
+	NMG_UNLOCK();
+	return error;
+}
+
+
 
 /* remove from bridge b the ports in slots hw and sw
  * (sw can be -1 if not needed)
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index a1bc32ef3..4754b48b9 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -542,40 +542,6 @@ netmap_vp_dtor(struct netmap_adapter *na)
 }
 
 
-/* Called by external kernel modules (e.g., Openvswitch).
- * to modify the private data previously given to regops().
- * 'name' may be just bridge's name (including ':' if it
- * is not just NM_BDG_NAME).
- * Called without NMG_LOCK.
- */
-int
-nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
-	void *callback_data, void *auth_token)
-{
-	void *private_data = NULL;
-	struct nm_bridge *b;
-	int error = 0;
-
-	NMG_LOCK();
-	b = nm_find_bridge(name, 0 /* don't create */, NULL);
-	if (!b) {
-		error = EINVAL;
-		goto unlock_update_priv;
-	}
-	if (!nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_update_priv;
-	}
-	BDG_WLOCK(b);
-	private_data = callback(b->private_data, callback_data, &error);
-	b->private_data = private_data;
-	BDG_WUNLOCK(b);
-
-unlock_update_priv:
-	NMG_UNLOCK();
-	return error;
-}
-
 
 /* nm_krings_create callback for VALE ports.
  * Calls the standard netmap_krings_create, then adds leases on rx

From ce7144004a6113a91a26bdbfae4efd4d3b1d5fe9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 13:29:30 +0200
Subject: [PATCH 1023/2207] vale: more uniform function/data naming

---
 sys/dev/netmap/netmap_vale.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 4754b48b9..6d8c29339 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -126,11 +126,11 @@ static int netmap_vp_bdg_attach(const char *, struct netmap_adapter *,
 static int netmap_vale_bwrap_attach(const char *, struct netmap_adapter *);
 
 /*
- * For each output interface, nm_bdg_q is used to construct a list.
+ * For each output interface, nm_vale_q is used to construct a list.
  * bq_len is the number of output buffers (we can have coalescing
  * during the copy).
  */
-struct nm_bdg_q {
+struct nm_vale_q {
 	uint16_t bq_head;
 	uint16_t bq_tail;
 	uint32_t bq_len;	/* number of buffers */
@@ -210,14 +210,14 @@ nm_alloc_bdgfwd(struct netmap_adapter *na)
 	/* all port:rings + broadcast */
 	num_dstq = NM_BDG_MAXPORTS * NM_BDG_MAXRINGS + 1;
 	l = sizeof(struct nm_bdg_fwd) * NM_BDG_BATCH_MAX;
-	l += sizeof(struct nm_bdg_q) * num_dstq;
+	l += sizeof(struct nm_vale_q) * num_dstq;
 	l += sizeof(uint16_t) * NM_BDG_BATCH_MAX;
 
 	nrings = netmap_real_rings(na, NR_TX);
 	kring = na->tx_rings;
 	for (i = 0; i < nrings; i++) {
 		struct nm_bdg_fwd *ft;
-		struct nm_bdg_q *dstq;
+		struct nm_vale_q *dstq;
 		int j;
 
 		ft = nm_os_malloc(l);
@@ -225,7 +225,7 @@ nm_alloc_bdgfwd(struct netmap_adapter *na)
 			nm_free_bdgfwd(na);
 			return ENOMEM;
 		}
-		dstq = (struct nm_bdg_q *)(ft + NM_BDG_BATCH_MAX);
+		dstq = (struct nm_vale_q *)(ft + NM_BDG_BATCH_MAX);
 		for (j = 0; j < num_dstq; j++) {
 			dstq[j].bq_head = dstq[j].bq_tail = NM_FT_NULL;
 			dstq[j].bq_len = 0;
@@ -591,7 +591,7 @@ netmap_vp_krings_delete(struct netmap_adapter *na)
 
 
 static int
-nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n,
+nm_vale_flush(struct nm_bdg_fwd *ft, u_int n,
 	struct netmap_vp_adapter *na, u_int ring_nr);
 
 
@@ -603,7 +603,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n,
  * Returns the next position in the ring.
  */
 static int
-nm_bdg_preflush(struct netmap_kring *kring, u_int end)
+nm_vale_preflush(struct netmap_kring *kring, u_int end)
 {
 	struct netmap_vp_adapter *na =
 		(struct netmap_vp_adapter*)kring->na;
@@ -662,7 +662,7 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end)
 		ft[ft_i - frags].ft_frags = frags;
 		frags = 1;
 		if (unlikely((int)ft_i >= bridge_batch))
-			ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr);
+			ft_i = nm_vale_flush(ft, ft_i, na, ring_nr);
 	}
 	if (frags > 1) {
 		/* Here ft_i > 0, ft[ft_i-1].flags has NS_MOREFRAG, and we
@@ -673,7 +673,7 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end)
 		D("Truncate incomplete fragment at %d (%d frags)", ft_i, frags);
 	}
 	if (ft_i)
-		ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr);
+		ft_i = nm_vale_flush(ft, ft_i, na, ring_nr);
 	BDG_RUNLOCK(b);
 	return j;
 }
@@ -856,10 +856,10 @@ nm_kr_lease(struct netmap_kring *k, u_int n, int is_rx)
  * number of ports, and lets us replace the learn and dispatch functions.
  */
 int
-nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
+nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		u_int ring_nr)
 {
-	struct nm_bdg_q *dst_ents, *brddst;
+	struct nm_vale_q *dst_ents, *brddst;
 	uint16_t num_dsts = 0, *dsts;
 	struct nm_bridge *b = na->na_bdg;
 	u_int i, me = na->bdg_port;
@@ -870,14 +870,14 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 	 * queues per port plus one for the broadcast traffic.
 	 * Then we have an array of destination indexes.
 	 */
-	dst_ents = (struct nm_bdg_q *)(ft + NM_BDG_BATCH_MAX);
+	dst_ents = (struct nm_vale_q *)(ft + NM_BDG_BATCH_MAX);
 	dsts = (uint16_t *)(dst_ents + NM_BDG_MAXPORTS * NM_BDG_MAXRINGS + 1);
 
 	/* first pass: find a destination for each packet in the batch */
 	for (i = 0; likely(i < n); i += ft[i].ft_frags) {
 		uint8_t dst_ring = ring_nr; /* default, same ring as origin */
 		uint16_t dst_port, d_i;
-		struct nm_bdg_q *d;
+		struct nm_vale_q *d;
 		struct nm_bdg_fwd *start_ft = NULL;
 
 		ND("slot %d frags %d", i, ft[i].ft_frags);
@@ -952,7 +952,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		u_int dst_nr, lim, j, d_i, next, brd_next;
 		u_int needed, howmany;
 		int retry = netmap_txsync_retry;
-		struct nm_bdg_q *d;
+		struct nm_vale_q *d;
 		uint32_t my_start = 0, lease_idx = 0;
 		int nrings;
 		int virt_hdr_mismatch = 0;
@@ -1223,7 +1223,7 @@ netmap_vp_txsync(struct netmap_kring *kring, int flags)
 	if (bridge_batch > NM_BDG_BATCH)
 		bridge_batch = NM_BDG_BATCH;
 
-	done = nm_bdg_preflush(kring, head);
+	done = nm_vale_preflush(kring, head);
 done:
 	if (done != head)
 		D("early break at %d/ %d, tail %d", done, head, kring->nr_hwtail);

From f3cce34c07d7f93547510c986628b84e0bce2dd5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 15:11:27 +0200
Subject: [PATCH 1024/2207] vale: more uniform names for vp callbacks

---
 sys/dev/netmap/netmap_vale.c | 50 ++++++++++++++++++------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 6d8c29339..f4720b1d7 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -119,9 +119,9 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
 		"Max batch size to be used in the bridge");
 SYSEND;
 
-static int netmap_vp_create(struct nmreq_header *hdr, struct ifnet *,
+static int netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
-static int netmap_vp_bdg_attach(const char *, struct netmap_adapter *,
+static int netmap_vale_vp_bdg_attach(const char *, struct netmap_adapter *,
 		struct nm_bridge *);
 static int netmap_vale_bwrap_attach(const char *, struct netmap_adapter *);
 
@@ -141,7 +141,7 @@ struct netmap_bdg_ops vale_bdg_ops = {
 	.lookup = netmap_bdg_learning,
 	.config = NULL,
 	.dtor = NULL,
-	.vp_create = netmap_vp_create,
+	.vp_create = netmap_vale_vp_create,
 	.bwrap_attach = netmap_vale_bwrap_attach,
 	.name = NM_BDG_NAME,
 };
@@ -519,7 +519,7 @@ netmap_vale_detach(struct nmreq_header *hdr, void *auth_token)
 
 /* nm_dtor callback for ephemeral VALE ports */
 static void
-netmap_vp_dtor(struct netmap_adapter *na)
+netmap_vale_vp_dtor(struct netmap_adapter *na)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na;
 	struct nm_bridge *b = vpna->na_bdg;
@@ -548,7 +548,7 @@ netmap_vp_dtor(struct netmap_adapter *na)
  * rings and bdgfwd on tx rings.
  */
 static int
-netmap_vp_krings_create(struct netmap_adapter *na)
+netmap_vale_vp_krings_create(struct netmap_adapter *na)
 {
 	u_int tailroom;
 	int error, i;
@@ -583,7 +583,7 @@ netmap_vp_krings_create(struct netmap_adapter *na)
 
 /* nm_krings_delete callback for VALE ports. */
 static void
-netmap_vp_krings_delete(struct netmap_adapter *na)
+netmap_vale_vp_krings_delete(struct netmap_adapter *na)
 {
 	nm_free_bdgfwd(na);
 	netmap_krings_delete(na);
@@ -702,7 +702,7 @@ do {                                                                    \
 
 
 static __inline uint32_t
-nm_bridge_rthash(const uint8_t *addr)
+nm_vale_rthash(const uint8_t *addr)
 {
 	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hask key
 
@@ -728,7 +728,7 @@ nm_bridge_rthash(const uint8_t *addr)
  * ring in *dst_ring (at the moment, always use ring 0)
  */
 uint32_t
-netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
+netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *na, void *private_data)
 {
 	uint8_t *buf = ((uint8_t *)ft->ft_buf) + ft->ft_offset;
@@ -760,7 +760,7 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 	 */
 	if (((buf[6] & 1) == 0) && (na->last_smac != smac)) { /* valid src */
 		uint8_t *s = buf+6;
-		sh = nm_bridge_rthash(s); /* hash of source */
+		sh = nm_vale_rthash(s); /* hash of source */
 		/* update source port forwarding entry */
 		na->last_smac = ht[sh].mac = smac;	/* XXX expire ? */
 		ht[sh].ports = mysrc;
@@ -770,7 +770,7 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 	}
 	dst = NM_BDG_BROADCAST;
 	if ((buf[0] & 1) == 0) { /* unicast */
-		dh = nm_bridge_rthash(buf); /* hash of dst */
+		dh = nm_vale_rthash(buf); /* hash of dst */
 		if (ht[dh].mac == dmac) {	/* found dst */
 			dst = ht[dh].ports;
 		}
@@ -1204,7 +1204,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 
 /* nm_txsync callback for VALE ports */
 static int
-netmap_vp_txsync(struct netmap_kring *kring, int flags)
+netmap_vale_vp_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_vp_adapter *na =
 		(struct netmap_vp_adapter *)kring->na;
@@ -1242,7 +1242,7 @@ netmap_vp_txsync(struct netmap_kring *kring, int flags)
  * Only persistent VALE ports have a non-null ifp.
  */
 static int
-netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
+netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
 	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
@@ -1303,12 +1303,12 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	 */
 	if (ifp)
 		na->na_flags |= NAF_NATIVE;
-	na->nm_txsync = netmap_vp_txsync;
-	na->nm_rxsync = netmap_vp_rxsync;
-	na->nm_register = netmap_vp_reg;
-	na->nm_krings_create = netmap_vp_krings_create;
-	na->nm_krings_delete = netmap_vp_krings_delete;
-	na->nm_dtor = netmap_vp_dtor;
+	na->nm_txsync = netmap_vale_vp_txsync;
+	na->nm_rxsync = netmap_vp_rxsync; /* use the one provided by bdg */
+	na->nm_register = netmap_vp_reg;  /* use the one provided by bdg */
+	na->nm_krings_create = netmap_vale_vp_krings_create;
+	na->nm_krings_delete = netmap_vale_vp_krings_delete;
+	na->nm_dtor = netmap_vale_vp_dtor;
 	ND("nr_mem_id %d", req->nr_mem_id);
 	na->nm_mem = nmd ?
 		netmap_mem_get(nmd):
@@ -1318,7 +1318,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 			req->nr_extra_bufs, npipes, &error);
 	if (na->nm_mem == NULL)
 		goto err;
-	na->nm_bdg_attach = netmap_vp_bdg_attach;
+	na->nm_bdg_attach = netmap_vale_vp_bdg_attach;
 	/* other nmd fields are set in the common routine */
 	error = netmap_attach_common(na);
 	if (error)
@@ -1337,7 +1337,7 @@ netmap_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
  * The na_vp port is this same netmap_adapter. There is no host port.
  */
 static int
-netmap_vp_bdg_attach(const char *name, struct netmap_adapter *na,
+netmap_vale_vp_bdg_attach(const char *name, struct netmap_adapter *na,
 		struct nm_bridge *b)
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
@@ -1360,12 +1360,12 @@ netmap_vale_bwrap_krings_create(struct netmap_adapter *na)
 	int error;
 
 	/* impersonate a netmap_vp_adapter */
-	error = netmap_vp_krings_create(na);
+	error = netmap_vale_vp_krings_create(na);
 	if (error)
 		return error;
 	error = netmap_bwrap_krings_create_common(na);
 	if (error) {
-		netmap_vp_krings_delete(na);
+		netmap_vale_vp_krings_delete(na);
 	}
 	return error;
 }
@@ -1374,7 +1374,7 @@ static void
 netmap_vale_bwrap_krings_delete(struct netmap_adapter *na)
 {
 	netmap_bwrap_krings_delete_common(na);
-	netmap_vp_krings_delete(na);
+	netmap_vale_vp_krings_delete(na);
 }
 
 static int
@@ -1392,7 +1392,7 @@ netmap_vale_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	na = &bna->up.up;
 	strncpy(na->name, nr_name, sizeof(na->name));
 	na->nm_register = netmap_bwrap_reg;
-	na->nm_txsync = netmap_vp_txsync;
+	na->nm_txsync = netmap_vale_vp_txsync;
 	// na->nm_rxsync = netmap_bwrap_rxsync;
 	na->nm_krings_create = netmap_vale_bwrap_krings_create;
 	na->nm_krings_delete = netmap_vale_bwrap_krings_delete;
@@ -1563,7 +1563,7 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 		}
 	}
 	/* netmap_vp_create creates a struct netmap_vp_adapter */
-	error = netmap_vp_create(hdr, ifp, nmd, &vpna);
+	error = netmap_vale_vp_create(hdr, ifp, nmd, &vpna);
 	if (error) {
 		D("error %d", error);
 		goto err_1;

From dc13528bb74a7cfe87f3c01cbebe385c1ca041ca Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 15:16:14 +0200
Subject: [PATCH 1025/2207] bdg: uniform naming for update_private_data

---
 LINUX/netmap_linux.c        | 2 +-
 sys/dev/netmap/netmap_bdg.c | 2 +-
 sys/dev/netmap/netmap_bdg.h | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 970af62b7..868cde38d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2668,7 +2668,7 @@ EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
 #ifdef WITH_VALE
 EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
-EXPORT_SYMBOL(nm_bdg_update_private_data);
+EXPORT_SYMBOL(netmap_bdg_update_private_data);
 EXPORT_SYMBOL(netmap_vale_create);
 EXPORT_SYMBOL(netmap_vale_destroy);
 EXPORT_SYMBOL(netmap_vale_attach);
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 4493c3627..204ba426a 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -254,7 +254,7 @@ netmap_bdg_free(struct nm_bridge *b)
  * Called without NMG_LOCK.
  */
 int
-nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
+netmap_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
 	void *callback_data, void *auth_token)
 {
 	void *private_data = NULL;
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index fad13b393..468e62535 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -157,7 +157,7 @@ int netmap_bwrap_krings_create_common(struct netmap_adapter *na);
 void netmap_bwrap_krings_delete_common(struct netmap_adapter *na);
 struct nm_bridge *netmap_init_bridges2(u_int);
 void netmap_uninit_bridges2(struct nm_bridge *, u_int);
-int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
+int netmap_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
 	void *callback_data, void *auth_token);
 int netmap_bdg_config(struct nm_ifreq *nifr);
 int nm_is_bwrap(struct netmap_adapter *);

From 500eb5d135c0b0b7db1f9980daeb58f8ac1a7e5c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 15:44:43 +0200
Subject: [PATCH 1026/2207] bdg: prepare for vale-vlan merge

---
 sys/dev/netmap/netmap_bdg.c  | 28 ++++++++++++++++++----------
 sys/dev/netmap/netmap_bdg.h  |  4 +++-
 sys/dev/netmap/netmap_vale.c |  7 ++-----
 3 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 204ba426a..34c617b2b 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -223,7 +223,7 @@ nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
 		for (i = 0; i < NM_BDG_MAXPORTS; i++)
 			b->bdg_port_index[i] = i;
 		/* set the default function */
-		b->bdg_ops = ops;
+		b->bdg_ops = b->bdg_saved_ops = *ops;
 		b->private_data = b->ht;
 		b->bdg_flags = 0;
 		NM_BNS_GET(b);
@@ -241,7 +241,8 @@ netmap_bdg_free(struct nm_bridge *b)
 
 	ND("marking bridge %s as free", b->bdg_basename);
 	nm_os_free(b->ht);
-	b->bdg_ops = NULL;
+	memset(&b->bdg_ops, 0, sizeof(b->bdg_ops));
+	memset(&b->bdg_saved_ops, 0, sizeof(b->bdg_saved_ops));
 	b->bdg_flags = 0;
 	NM_BNS_PUT(b);
 	return 0;
@@ -331,8 +332,8 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	}
 
 	BDG_WLOCK(b);
-	if (b->bdg_ops->dtor)
-		b->bdg_ops->dtor(b->bdg_ports[s_hw]);
+	if (b->bdg_ops.dtor)
+		b->bdg_ops.dtor(b->bdg_ports[s_hw]);
 	b->bdg_ports[s_hw] = NULL;
 	if (s_sw >= 0) {
 		b->bdg_ports[s_sw] = NULL;
@@ -464,7 +465,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		}
 
 		/* bdg_netmap_attach creates a struct netmap_adapter */
-		error = b->bdg_ops->vp_create(hdr, NULL, nmd, &vpna);
+		error = b->bdg_ops.vp_create(hdr, NULL, nmd, &vpna);
 		if (error) {
 			D("error %d", error);
 			goto out;
@@ -495,7 +496,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		/* host adapter might not be created */
 		error = hw->nm_bdg_attach(nr_name, hw, b);
 		if (error == NM_NEED_BWRAP) {
-			error = b->bdg_ops->bwrap_attach(nr_name, hw);
+			error = b->bdg_ops.bwrap_attach(nr_name, hw);
 		}
 		if (error)
 			goto out;
@@ -868,12 +869,19 @@ netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *privat
 	if (!bdg_ops) {
 		/* resetting the bridge */
 		bzero(b->ht, sizeof(struct nm_hash_ent) * NM_BDG_HASH);
-		b->bdg_ops = NULL;
+		b->bdg_ops = b->bdg_saved_ops;
 		b->private_data = b->ht;
 	} else {
 		/* modifying the bridge */
 		b->private_data = private_data;
-		b->bdg_ops = bdg_ops;
+#define nm_bdg_override(m) if (bdg_ops->m) b->bdg_ops.m = bdg_ops->m
+		nm_bdg_override(lookup);
+		nm_bdg_override(config);
+		nm_bdg_override(dtor);
+		nm_bdg_override(vp_create);
+		nm_bdg_override(bwrap_attach);
+#undef nm_bdg_override
+
 	}
 	BDG_WUNLOCK(b);
 
@@ -898,8 +906,8 @@ netmap_bdg_config(struct nm_ifreq *nr)
 	NMG_UNLOCK();
 	/* Don't call config() with NMG_LOCK() held */
 	BDG_RLOCK(b);
-	if (b->bdg_ops->config != NULL)
-		error = b->bdg_ops->config(nr);
+	if (b->bdg_ops.config != NULL)
+		error = b->bdg_ops.config(nr);
 	BDG_RUNLOCK(b);
 	return error;
 }
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 468e62535..3bf5c15a8 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -100,7 +100,8 @@ struct nm_bridge {
 	 * different ring index.
 	 * The function is set by netmap_bdg_regops().
 	 */
-	struct netmap_bdg_ops* bdg_ops;
+	struct netmap_bdg_ops bdg_ops;
+	struct netmap_bdg_ops bdg_saved_ops;
 
 	/*
 	 * Contains the data structure used by the bdg_ops.lookup function.
@@ -116,6 +117,7 @@ struct nm_bridge {
 	 */
 #define NM_BDG_ACTIVE		1
 #define NM_BDG_EXCLUSIVE	2
+#define NM_BDG_NEED_BWRAP	4
 	uint8_t			bdg_flags;
 
 
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index f4720b1d7..d828b5afc 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -894,7 +894,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 			 */
 			continue;
 		}
-		dst_port = b->bdg_ops->lookup(start_ft, &dst_ring, na, b->private_data);
+		dst_port = b->bdg_ops.lookup(start_ft, &dst_ring, na, b->private_data);
 		if (netmap_verbose > 255)
 			RD(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)
@@ -1342,10 +1342,7 @@ netmap_vale_vp_bdg_attach(const char *name, struct netmap_adapter *na,
 {
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na;
 
-	if (b->bdg_ops != &vale_bdg_ops) {
-		return NM_NEED_BWRAP;
-	}
-	if (vpna->na_bdg) {
+	if ((b->bdg_flags & NM_BDG_NEED_BWRAP) || vpna->na_bdg) {
 		return NM_NEED_BWRAP;
 	}
 	na->na_vp = vpna;

From 5676a2dd9156b150732dad19fa7f65eb20820f4b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 16:10:00 +0200
Subject: [PATCH 1027/2207] vale: fix stale name

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 sys/dev/netmap/netmap_vale.c | 2 +-
 utils/functional.c           | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 283118bbd..7eff9eb9e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1442,7 +1442,7 @@ int netmap_get_hw_na(struct ifnet *ifp,
 
 
 #ifdef WITH_VALE
-uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
+uint32_t netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *, void *private_data);
 
 /* these are redefined in case of no VALE support */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index d828b5afc..e62de51dc 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -138,7 +138,7 @@ struct nm_vale_q {
 
 /* Holds the default callbacks */
 struct netmap_bdg_ops vale_bdg_ops = {
-	.lookup = netmap_bdg_learning,
+	.lookup = netmap_vale_learning,
 	.config = NULL,
 	.dtor = NULL,
 	.vp_create = netmap_vale_vp_create,
diff --git a/utils/functional.c b/utils/functional.c
index ea7570c3a..7a2085f28 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -1375,7 +1375,7 @@ main(int argc, char **argv)
 
 		default:
 			verbose_print(g->verbosity_level, LV_ERROR_MSG,
-			              "Unrecognized option %c\n", opt);
+			              "Unrecognized option %c\n", optopt);
 			usage(stderr);
 			exit(EXIT_FAILURE);
 		}

From 7836aa835d9a4d07d5ae1b9a30ec31e7e88f3415 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Sep 2018 16:10:00 +0200
Subject: [PATCH 1028/2207] linux/igb: support for NS_MOREFRAG

---
 LINUX/if_igb_netmap.h | 78 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 63 insertions(+), 15 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 584583cbf..c34f0f046 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -119,7 +119,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	/* generate an interrupt approximately every half ring */
-	u_int report_frequency = kring->nkr_num_slots >> 1;
+	u_int report_frequency = kring->nkr_num_slots >> 1, report;
 
 	/* device-specific */
 	struct SOFTC_T *adapter = netdev_priv(ifp);
@@ -134,8 +134,6 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 
 	nm_i = kring->nr_hwcur;
 	if (nm_i != head) {	/* we have new packets to send */
-		uint32_t olinfo_status=0;
-
 		nic_i = netmap_idx_k2n(kring, nm_i);
 		for (n = 0; nm_i != head; n++) {
 			struct netmap_slot *slot = &ring->slot[nm_i];
@@ -146,27 +144,77 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 			/* device-specific */
 			union e1000_adv_tx_desc *curr =
 			    E1000_TX_DESC_ADV(*txr, nic_i);
-			int hw_flags = (slot->flags & NS_REPORT ||
-				nic_i == 0 || nic_i == report_frequency) ?
-				E1000_TXD_CMD_RS : 0;
+			int hw_flags = E1000_ADVTXD_DTYP_DATA |  E1000_ADVTXD_DCMD_DEXT |
+				E1000_ADVTXD_DCMD_IFCS;
+			u_int totlen = len;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
-			if (!(slot->flags & NS_MOREFRAG)) {
-				hw_flags |= E1000_TXD_CMD_EOP;
+			report = slot->flags & NS_REPORT ||
+				nic_i == 0 ||
+				nic_i == report_frequency;
+			if (slot->flags & NS_MOREFRAG) {
+				/* There is some duplicated code here, but
+				 * mixing everything up in the outer loop makes
+				 * things less transparent, and it also adds
+				 * unnecessary instructions in the fast path
+				 */
+				union e1000_adv_tx_desc *first = curr;
+
+				first->read.buffer_addr = htole64(paddr);
+				first->read.cmd_type_len = htole32(len | hw_flags);
+				netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+						&paddr, len, NR_TX);
+				/* avoid setting the FCS flag in the
+				 * descriptors after the first, for safety
+				 */
+				hw_flags &= ~E1000_ADVTXD_DCMD_IFCS;
+				for (;;) {
+					nm_i = nm_next(nm_i, lim);
+					nic_i = nm_next(nic_i, lim);
+					/* remember that we have to ask for a
+					 * report each time we move past half a
+					 * ring
+					 */
+					report |= nic_i == 0 ||
+						nic_i == report_frequency;
+					if (nm_i == head) {
+						// XXX should we accept incomplete packets?
+						return EINVAL;
+					}
+					slot = &ring->slot[nm_i];
+					len = slot->len;
+					addr = PNMB(na, slot, &paddr);
+					NM_CHECK_ADDR_LEN(na, addr, len);
+					curr = E1000_TX_DESC_ADV(*txr, nic_i);
+					totlen += len;
+					if (!(slot->flags & NS_MOREFRAG))
+						break;
+					curr->read.buffer_addr = htole64(paddr);
+					curr->read.olinfo_status = 0;
+					curr->read.cmd_type_len = htole32(len | hw_flags);
+
+					netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+							&paddr, len, NR_TX);
+				}
+				first->read.olinfo_status =
+					htole32(totlen << E1000_ADVTXD_PAYLEN_SHIFT);
+				totlen = 0;
 			}
+			/* curr now always points to the last descriptor of a packet
+			 * (which is also the first for single-slot packets)
+			 *
+			 * EOP and RS must be set only in this descriptor.
+			 */
+			hw_flags |= E1000_TXD_CMD_EOP | (report ? E1000_TXD_CMD_RS : 0);
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
-			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
 			curr->read.buffer_addr = htole64(paddr);
 			// XXX check olinfo and cmd_type_len
-			curr->read.olinfo_status =
-			    htole32(olinfo_status |
-				(len<< E1000_ADVTXD_PAYLEN_SHIFT));
-			curr->read.cmd_type_len = htole32(len | hw_flags |
-				E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_DEXT |
-				E1000_ADVTXD_DCMD_IFCS);
+			curr->read.olinfo_status = htole32(totlen<< E1000_ADVTXD_PAYLEN_SHIFT);
+			curr->read.cmd_type_len = htole32(len | hw_flags);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}

From 61e641c421748064233be8e6055cad422eb27610 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 11 Sep 2018 18:07:47 +0200
Subject: [PATCH 1029/2207] mem: reset lasterr on last user

---
 sys/dev/netmap/netmap_mem2.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 0623d4d57..fb93ad4d0 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -478,8 +478,10 @@ netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 	nmd->ops->nmd_deref(nmd);
 
 	nmd->active--;
-	if (!nmd->active)
+	if (last_user) {
 		nmd->nm_grp = -1;
+		nmd->lasterr = 0;
+	}
 
 	NMA_UNLOCK(nmd);
 	return last_user;

From 9baf4b7cd8e89f6c9436d348629a7bb9c8454ad4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Sep 2018 10:27:35 +0200
Subject: [PATCH 1030/2207] ignore new utils binaries

---
 .gitignore | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.gitignore b/.gitignore
index aa184804d..7f70ad460 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,6 +54,9 @@ utils/test_nm
 utils/cygwin1.dll
 utils/ctrl-api-test
 utils/functional
+utils/fd_server
+utils/get_tx_rings_avail_sends
+utils/get_tx_rings_max_sends
 examples/pkt-gen.exe
 examples/pkt-gen.exe.stackdump
 examples/pkt-gen-b.exe

From a722fb8c547e573478241c40bbf1230cf9b041c2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Sep 2018 10:44:11 +0200
Subject: [PATCH 1031/2207] linux/igb: pass bufsize info to NIC when switching
 to netmap mode

---
 LINUX/configure       |  8 --------
 LINUX/if_igb_netmap.h | 32 +++++++++++++++++++-------------
 2 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index da9cd64dd..60ce1548b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1898,14 +1898,6 @@ EOF
 	}
 EOF
 
-    add_test 'have IGB_RX_BUFSZ' <netdev;
+	struct netmap_adapter* na = NA(ifp);
+	struct igb_adapter *adapter = netdev_priv(ifp);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 srrctl;
+
+	srrctl = ALIGN(NETMAP_BUF_SIZE(na), 1024) >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+	srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+	srrctl |= E1000_SRRCTL_DROP_EN;
+	E1000_WRITE_REG(hw, E1000_SRRCTL(rxr->reg_idx), srrctl);
+}
+
 
 static int
 igb_netmap_configure_rx_ring(struct igb_ring *rxr)
@@ -413,6 +428,8 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	if (!slot)
 		return 0;	// not in native netmap mode
 
+	igb_netmap_configure_srrctl(rxr);
+
 	for (i = 0; i < rxr->count; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;
@@ -440,27 +457,16 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	return 1;	// success
 }
 
-static unsigned
-nm_igb_rx_buf_maxsize(struct SOFTC_T *adapter)
-{
-#if defined(NETMAP_LINUX_HAVE_IGB_RX_BUFSZ)
-	return igb_rx_bufsz(adapter->rx_ring[0]);
-#else  /* !NETMAP_LINUX_HAVE_IGB_RX_BUFSZ */
-	return 3072; /* stay on the safe side */
-#endif /* !NETMAP_LINUX_HAVE_IGB_RX_BUFSZ */
-}
-
 static int
 igb_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
-	struct SOFTC_T *adapter = netdev_priv(na->ifp);
 	int ret = netmap_rings_config_get(na, info);
 
 	if (ret) {
 		return ret;
 	}
 
-	info->rx_buf_maxsize = nm_igb_rx_buf_maxsize(adapter);
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
 	return 0;
 }
@@ -480,7 +486,7 @@ igb_netmap_attach(struct SOFTC_T *adapter)
 	na.num_rx_desc = adapter->rx_ring_count;
 	na.num_tx_rings = adapter->num_tx_queues;
 	na.num_rx_rings = adapter->num_rx_queues;
-	na.rx_buf_maxsize = nm_igb_rx_buf_maxsize(adapter);
+	na.rx_buf_maxsize = 1500; /* will be overwritten by config */
 	na.nm_register = igb_netmap_reg;
 	na.nm_txsync = igb_netmap_txsync;
 	na.nm_rxsync = igb_netmap_rxsync;

From 412061a70631cef7219a3941640a596614eaf3e0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Sep 2018 11:27:22 +0200
Subject: [PATCH 1032/2207] linux/scripts: fix check-patch for ext drivers when
 default version is used

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index ef7f5761e..5bd961d74 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -420,7 +420,7 @@ function check-patch()
 	# extract the driver name
 	local driver=$(scripts/vers $_patch -s -p -p)
 	# possibly extract the selected driver version
-	driver_version=${driver#*:}
+	driver_version=$(echo "$driver" | sed -n 's/^.*://p')
 	driver=${driver%%:*}
 	# extract the driver type (vanilla or external)
 	local dtype=$(scripts/vers $_patch -s -p -p -p)

From 4cb6852a3e0fdee2a7dd395ab3b447a07233360f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Sep 2018 11:54:23 +0200
Subject: [PATCH 1033/2207] linux/igb: adapt srrctl write to driver version

---
 LINUX/if_igb_netmap.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 7300fb70f..b2c396e47 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -58,6 +58,20 @@ static inline u32 READ_TDH(struct igb_adapter *adapter, struct igb_ring *txr)
 #else
 #define	READ_TDH(_adapter, _txr)	readl((_txr)->head)
 #endif
+#ifdef E1000_WRITE_REG
+#define NM_WRITE_SRRCTL(_adapter, _rxr, _srrctl)	\
+	E1000_WRITE_REG(&(_adapter)->hw, E1000_SRRCTL((_rxr)->reg_idx), (srrctl))
+#elif defined(wr32)
+static inline void NM_WRITE_SRRCTL(struct igb_adapter *adapter, struct igb_ring *txr,
+	u32 srrctl)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	wr32(E1000_TDH(txr->reg_idx), srrctl);
+}
+#else
+#define NM_WRITE_SRRCTL(_adapter, _rxr, _srrctl)	\
+	writel(E1000_SRRCTL((_rxr)->reg_idx, (_srrctl))
+#endif
 
 #ifndef E1000_TX_DESC_ADV
 #define	E1000_TX_DESC_ADV(_r, _i)	IGB_TX_DESC(&(_r), _i)
@@ -395,13 +409,12 @@ igb_netmap_configure_srrctl(struct igb_ring *rxr)
 	struct ifnet *ifp = rxr->netdev;
 	struct netmap_adapter* na = NA(ifp);
 	struct igb_adapter *adapter = netdev_priv(ifp);
-	struct e1000_hw *hw = &adapter->hw;
 	u32 srrctl;
 
 	srrctl = ALIGN(NETMAP_BUF_SIZE(na), 1024) >> E1000_SRRCTL_BSIZEPKT_SHIFT;
 	srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
 	srrctl |= E1000_SRRCTL_DROP_EN;
-	E1000_WRITE_REG(hw, E1000_SRRCTL(rxr->reg_idx), srrctl);
+	NM_WRITE_SRRCTL(adapter, rxr, srrctl);
 }
 
 

From 175c876255de962d407b96e85796aa04facc19c7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Sep 2018 12:14:46 +0200
Subject: [PATCH 1034/2207] linux/igb: upgrade default version to 5.3.5.20

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index ed944fcf0..c5f62bdef 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -19,7 +19,7 @@ igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 $(eval $(call default,ixgbe,5.3.7))
 $(eval $(call default,ixgbevf,4.3.2))
 $(eval $(call default,e1000e,3.4.0.2))
-$(eval $(call default,igb,5.3.5.12))
+$(eval $(call default,igb,5.3.5.20))
 $(eval $(call default,i40e,2.4.6))
 
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))

From 0d1251c14f6bde46fadd11086f347adcea6445c1 Mon Sep 17 00:00:00 2001
From: Garrett Kajmowicz 
Date: Wed, 12 Sep 2018 15:10:40 -0400
Subject: [PATCH 1035/2207] Minor debug statement fixes for virtio and bridge

Signed-off-by: Garrett Kajmowicz 
---
 LINUX/virtio_netmap.h       | 2 +-
 sys/dev/netmap/netmap_bdg.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 65ba54252..2d43f3e5f 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -720,6 +720,6 @@ virtio_netmap_attach(struct virtnet_info *vi)
 
 	D("virtio attached txq=%d, txd=%d rxq=%d, rxd=%d",
 			na.num_tx_rings, na.num_tx_desc,
-			na.num_tx_rings, na.num_rx_desc);
+			na.num_rx_rings, na.num_rx_desc);
 }
 /* end of file */
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 52611c236..a5d934c09 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1593,8 +1593,8 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 	ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
 		na->name, ring_n,
 		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
-		ring->head, ring->cur, ring->tail,
-		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_ring->rtail);
+		kring->rhead, kring->rcur, kring->rtail,
+		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
 	/* second step: the new packets are sent on the tx ring
 	 * (which is actually the same ring)
 	 */
@@ -1612,7 +1612,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 	ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
 		na->name, ring_n,
 		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
-		ring->head, ring->cur, ring->tail,
+		kring->rhead, kring->rcur, kring->rtail,
 		hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail);
 put_out:
 	nm_kr_put(hw_kring);

From 96ee5161114cd700bcf4bea04a8cbe8cecfa1f85 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 13 Sep 2018 11:09:27 +0200
Subject: [PATCH 1036/2207] linux/igb: don't expose incomplete multi-frag
 packets

---
 LINUX/if_igb_netmap.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index b2c396e47..a4545e018 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -288,6 +288,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+	int complete; /* did we see a complete packet ? */
 
 	/* device-specific */
 	struct SOFTC_T *adapter = netdev_priv(ifp);
@@ -320,7 +321,8 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			dma_rmb(); /* read descriptor after status DD */
 			PNMB(na, slot, &paddr);
 			slot->len = le16toh(curr->wb.upper.length);
-			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
+			complete = (staterr & E1000_RXD_STAT_EOP);
+			slot->flags = complete ? 0 : NS_MOREFRAG;
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -330,7 +332,8 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 #ifdef NETMAP_LINUX_HAVE_IGB_NTA
 			rxr->next_to_alloc = nic_i;
 #endif /* NETMAP_LINUX_HAVE_IGB_NTA */
-			kring->nr_hwtail = nm_i;
+			if (complete)
+				kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}

From a74c3ea9677cbb5cf51af616db265afdd2169d45 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 13 Sep 2018 15:32:59 +0200
Subject: [PATCH 1037/2207] ci: run utils/randomized_tests in travis

---
 ci/run-integration-tests | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 4f1ab722e..7125b33aa 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -10,3 +10,11 @@ sudo ./ctrl-api-test
 popd
 
 sudo rmmod netmap
+
+# Run integration tests
+sudo modprobe netmap
+pushd .
+cd utils
+sudo ./randomized_tests
+popd
+sudo rmmod netmap

From d21b28ea434e6acd7ebfb65aa3e3f6beb7b9868b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 13 Sep 2018 15:52:18 +0200
Subject: [PATCH 1038/2207] utils: randomized_test: always stop fd_server after
 a test

---
 utils/randomized_tests | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 57a1ad31d..e54d821c7 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -33,8 +33,11 @@ echo ""
 # scripts.
 PATH="$(pwd):${PATH}"
 
+source test_lib
+
 for test in tests/*_test ; do
 	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
+	close_fd_server
 	if [ $? != 0 ] ; then
 		echo "Rerunning the test that just failed with -v"
 		# Select verbosity of output during after an error occurred:
@@ -43,6 +46,7 @@ for test in tests/*_test ; do
 		#    -vvv  -> -vv and packet building
 		#    -vvvv -> -vvv and arguments parsing
 		$test -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+		close_fd_server
 		exit $?
 	fi
 done

From 2fa865d174542f4ddbc8395ce895c556732d1240 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 13 Sep 2018 16:07:13 +0200
Subject: [PATCH 1039/2207] utils: tests: move restart_fd_server call to
 randomized_tests

---
 utils/randomized_tests                                    | 4 +++-
 utils/tests/exclusive_open_ephemeral_vale_port_test       | 4 +---
 utils/tests/exclusive_open_persistent_vale_port_test      | 4 +---
 utils/tests/exclusive_open_pipe_test                      | 4 +---
 utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test  | 4 +---
 utils/tests/extra_buf_send_rec_persistent_vale_ports_test | 4 +---
 utils/tests/extra_buf_send_rec_pipe_test                  | 4 +---
 utils/tests/learning_bridge_test                          | 4 +---
 utils/tests/partial_read_pipe_test                        | 4 +---
 utils/tests/persistent_vale_port_destroy                  | 4 +---
 utils/tests/persistent_vale_port_double_attach            | 4 +---
 utils/tests/persistent_vale_port_double_create            | 4 +---
 utils/tests/rec_cp_mon_ephemeral_vale_port_test           | 4 +---
 utils/tests/rec_cp_mon_persistent_vale_port_test          | 4 +---
 utils/tests/rec_cp_mon_pipe_test                          | 4 +---
 utils/tests/rec_zcp_mon_ephemeral_vale_port_test          | 4 +---
 utils/tests/rec_zcp_mon_persistent_vale_port_test         | 4 +---
 utils/tests/rec_zcp_mon_pipe_test                         | 4 +---
 utils/tests/send_cp_mon_ephemeral_vale_port_test          | 4 +---
 utils/tests/send_cp_mon_persistent_vale_port_test         | 4 +---
 utils/tests/send_cp_mon_pipe_test                         | 4 +---
 utils/tests/send_rec_ephemeral_vale_ports_test            | 4 +---
 utils/tests/send_rec_persistent_vale_ports_test           | 4 +---
 utils/tests/send_rec_pipe_test                            | 4 +---
 utils/tests/send_rec_veth_test                            | 4 +---
 utils/tests/send_zcp_mon_ephemeral_vale_port_test         | 4 +---
 utils/tests/send_zcp_mon_persistent_vale_port_test        | 4 +---
 utils/tests/send_zcp_mon_pipe_test                        | 4 +---
 28 files changed, 30 insertions(+), 82 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index e54d821c7..3305adda6 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -36,15 +36,17 @@ PATH="$(pwd):${PATH}"
 source test_lib
 
 for test in tests/*_test ; do
+	restart_fd_server
 	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
 	close_fd_server
 	if [ $? != 0 ] ; then
 		echo "Rerunning the test that just failed with -v"
-		# Select verbosity of output during after an error occurred:
+		# Select verbosity of output after an error occurred:
 		#    -v    -> prints error messages
 		#    -vv   -> -v, send and receive actions
 		#    -vvv  -> -vv and packet building
 		#    -vvvv -> -vvv and arguments parsing
+		restart_fd_server
 		$test -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 		close_fd_server
 		exit $?
diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
index 4b55059cb..916f2b6e6 100755
--- a/utils/tests/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -11,8 +11,6 @@ verbosity="${verbosity:-}"
 bridge="vale0"
 port="v0"
 
-restart_fd_server
-
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
 functional $verbosity -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
@@ -26,4 +24,4 @@ check_failure $? "no-open ${bridge}:${port}"
 functional $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/exclusive_open_persistent_vale_port_test b/utils/tests/exclusive_open_persistent_vale_port_test
index 9c229317d..daaffe12a 100755
--- a/utils/tests/exclusive_open_persistent_vale_port_test
+++ b/utils/tests/exclusive_open_persistent_vale_port_test
@@ -11,8 +11,6 @@ verbosity="${verbosity:-}"
 bridge="vale0"
 port="v0"
 
-restart_fd_server
-
 create_vale_persistent_port "$port"
 attach_to_vale_bridge "$bridge" "$port"
 
@@ -29,4 +27,4 @@ check_failure $? "no-open ${bridge}:${port}"
 functional $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/exclusive_open_pipe_test b/utils/tests/exclusive_open_pipe_test
index 072cd522d..387307c20 100755
--- a/utils/tests/exclusive_open_pipe_test
+++ b/utils/tests/exclusive_open_pipe_test
@@ -10,8 +10,6 @@ verbosity="${verbosity:-}"
 
 pipe="pipeA{1"
 
-restart_fd_server
-
 # We open pipeA{1 with the exclusive flag from the file descriptor.
 functional $verbosity -i "netmap:${pipe}/x"
 check_success $? "exclusive-open netmap:${pipe}/x"
@@ -25,4 +23,4 @@ check_failure $? "no-open netmap:${pipe}"
 functional $verbosity -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 0e36d0331..6dea470ad 100755
--- a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -18,8 +18,6 @@ seq="${seq:-}"
 
 e_buf_num="${e_buf_num:-12}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "vale0:v1"
@@ -42,4 +40,4 @@ check_success $e1 "receive-${num} vale0:v1"
 check_success $e2 "receive-${num} vale0:v2"
 check_success $e3 "send-${num} vale0:v0"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index d0f193f95..4064cee28 100755
--- a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -19,8 +19,6 @@ seq="${seq:-}"
 
 e_buf_num="${e_buf_num:-12}"
 
-restart_fd_server
-
 create_vale_persistent_port "v0"
 create_vale_persistent_port "v1"
 create_vale_persistent_port "v2"
@@ -49,4 +47,4 @@ check_success $e1 "receive-${num} vale0:v0"
 check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
index 1f5c54d33..e9503046f 100755
--- a/utils/tests/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -18,8 +18,6 @@ seq="${seq:-}"
 
 e_buf_num="${e_buf_num:-12}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:pipeA{1"
@@ -35,4 +33,4 @@ e1=$?
 check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/learning_bridge_test b/utils/tests/learning_bridge_test
index 99a9973c0..4280ba583 100755
--- a/utils/tests/learning_bridge_test
+++ b/utils/tests/learning_bridge_test
@@ -19,8 +19,6 @@ len="${len:-150}"
 s_MAC=$(get_random_MAC)
 d_MAC="FF:FF:FF:FF:FF:FF"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i vale0:v0
@@ -60,4 +58,4 @@ check_success $e1 "receive vale0:v0"
 check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index 9b960182f..3ef3f6bab 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -21,8 +21,6 @@ num_send=10
 num_recv=7
 pipe="pipeA"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:${pipe}{1"
@@ -73,4 +71,4 @@ num_send="$(($ring_avail_sends + 1))"
 functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/persistent_vale_port_destroy b/utils/tests/persistent_vale_port_destroy
index 31f65e8ca..64307daad 100755
--- a/utils/tests/persistent_vale_port_destroy
+++ b/utils/tests/persistent_vale_port_destroy
@@ -13,8 +13,6 @@ bridgeA="${bridge}A"
 bridgeB="${bridge}B"
 port="v0"
 
-restart_fd_server
-
 create_vale_persistent_port "$port" 0
 destroy_vale_persistent_port "$port" 0
 
@@ -32,4 +30,4 @@ destroy_vale_persistent_port "$port" 1
 detach_from_vale_bridge "$bridgeA" "$port" 0
 destroy_vale_persistent_port "$port" 0
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/persistent_vale_port_double_attach b/utils/tests/persistent_vale_port_double_attach
index c310b32eb..4548d2938 100755
--- a/utils/tests/persistent_vale_port_double_attach
+++ b/utils/tests/persistent_vale_port_double_attach
@@ -14,11 +14,9 @@ bridgeA="${bridge}A"
 bridgeB="${bridge}B"
 port="v0"
 
-restart_fd_server
-
 create_vale_persistent_port "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/persistent_vale_port_double_create b/utils/tests/persistent_vale_port_double_create
index bad479267..c2d12a7b9 100755
--- a/utils/tests/persistent_vale_port_double_create
+++ b/utils/tests/persistent_vale_port_double_create
@@ -13,8 +13,6 @@ bridgeA="${bridge}A"
 bridgeB="${bridge}B"
 port="v0"
 
-restart_fd_server
-
 create_vale_persistent_port "$port" 0
 create_vale_persistent_port "$port" 1
 
@@ -24,4 +22,4 @@ create_vale_persistent_port "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
 create_vale_persistent_port "$port" 1
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
index dbbed5967..1a0953a10 100755
--- a/utils/tests/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -19,8 +19,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i vale0:v0
@@ -45,4 +43,4 @@ functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
index 731ac06e4..757b5347c 100755
--- a/utils/tests/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -20,8 +20,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -48,4 +46,4 @@ functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
index 83da161f3..41ada55b4 100755
--- a/utils/tests/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -20,8 +20,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:pipe{1"
@@ -46,4 +44,4 @@ functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index bae5173fd..bd34fa18c 100755
--- a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -19,8 +19,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "vale0:v0"
@@ -52,4 +50,4 @@ e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} vale0:v0/z"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
index 19e0091c5..a32618c3d 100755
--- a/utils/tests/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -20,8 +20,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -55,4 +53,4 @@ e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} netmap:v0/z"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
index 3536aae91..b05282e7d 100755
--- a/utils/tests/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -19,8 +19,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:pipe{1"
@@ -52,4 +50,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:pipe{1"
 check_success $e4 "receive-${num} netmap:pipe{1/z"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
index 5ff210890..fa05c9399 100755
--- a/utils/tests/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -17,8 +17,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i vale0:v0
@@ -43,4 +41,4 @@ functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
index 81f39c7a8..82e42ee4c 100755
--- a/utils/tests/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -18,8 +18,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -46,4 +44,4 @@ functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
index 604d7a7ff..6447758bc 100755
--- a/utils/tests/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -20,8 +20,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:pipe{1"
@@ -46,4 +44,4 @@ functional $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
index 98a58ad90..a41565637 100755
--- a/utils/tests/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -16,8 +16,6 @@ len="${len:-274}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "vale0:v0"
@@ -57,4 +55,4 @@ check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
index 2800852fa..dd4524548 100755
--- a/utils/tests/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -17,8 +17,6 @@ len="${len:-274}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 create_vale_persistent_port "v0"
 create_vale_persistent_port "v1"
 create_vale_persistent_port "v2"
@@ -64,4 +62,4 @@ check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
index 6e5ef8ffb..31a655241 100755
--- a/utils/tests/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -16,8 +16,6 @@ len="${len:-274}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:pipeA{1"
@@ -45,4 +43,4 @@ e2=$?
 check_success $e2 "receive-${num} netmap:pipeA}1"
 check_success $e4 "send-${num} netmap:pipeA{1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/send_rec_veth_test
index 3e4325dc5..37f997859 100755
--- a/utils/tests/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -18,8 +18,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 create_veth_interfaces "veth1"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
@@ -48,4 +46,4 @@ e3=$?
 check_success $e3 "receive-${num} netmap:veth1B"
 check_success $e4 "send-${num} netmap:veth1A"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
index 70955dc53..d76267ff7 100755
--- a/utils/tests/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -20,8 +20,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i vale0:v0
@@ -46,4 +44,4 @@ functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
index 8ff650e3d..e93188d31 100755
--- a/utils/tests/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -21,8 +21,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
@@ -49,4 +47,4 @@ functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index 38da76e2c..0f92032e9 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -21,8 +21,6 @@ len="${len:-150}"
 num="${num:-1}"
 seq="${seq:-}"
 
-restart_fd_server
-
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:pipe{1"
@@ -59,4 +57,4 @@ check_success $e4 "receive-${num} netmap:pipe}1"
 check_success $e5 "send-${num} netmap:pipe{1"
 check_success $e3 "receive-${num} netmap:pipe{1/z"
 
-test_successful "$0"
\ No newline at end of file
+test_successful "$0"

From 3109892512ef52c09fdf18e31b5ccddd49729f62 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 13 Sep 2018 16:12:48 +0200
Subject: [PATCH 1040/2207] utils: randomized_tests: on exit, wait for
 fd_server to terminate

---
 utils/randomized_tests | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 3305adda6..041d8aa98 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -52,3 +52,6 @@ for test in tests/*_test ; do
 		exit $?
 	fi
 done
+
+# Wait for the fd_server to terminate and release its references
+sleep 0.5

From 8c24d6a2bbc59223a985d05ab323d130807fa6c9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 13 Sep 2018 16:22:09 +0200
Subject: [PATCH 1041/2207] travis: build netmap also on 4.16, 4.17 and 4.18

---
 .travis.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 7a9cfb3e9..3446f7db2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,6 +39,9 @@ env:
   - KERNEL_VERSION=4.13  ARCH=x86_64
   - KERNEL_VERSION=4.14  ARCH=x86_64
   - KERNEL_VERSION=4.15  ARCH=x86_64
+  - KERNEL_VERSION=4.16  ARCH=x86_64
+  - KERNEL_VERSION=4.17  ARCH=x86_64
+  - KERNEL_VERSION=4.18  ARCH=x86_64
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"

From 2a83591add80880ea8cdf91e1f9a4d8c88c26b42 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 13 Sep 2018 17:58:51 +0200
Subject: [PATCH 1042/2207] nm_dispatch: support NS_MOREFRAG

---
 sys/net/netmap_user.h | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index d3b157c1c..adf9d0b8c 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1089,18 +1089,36 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
 		ring = NETMAP_RXRING(d->nifp, ri);
 		for ( ; !nm_ring_empty(ring) && cnt != got; got++) {
 			u_int idx, i;
+			u_char *oldbuf;
+			struct netmap_slot *slot;
 			if (d->hdr.buf) { /* from previous round */
 				cb(arg, &d->hdr, d->hdr.buf);
 			}
 			i = ring->cur;
-			idx = ring->slot[i].buf_idx;
+			slot = &ring->slot[i];
+			idx = slot->buf_idx;
 			/* d->cur_rx_ring doesn't change inside this loop, but
 			 * set it here, so it reflects d->hdr.buf's ring */
 			d->cur_rx_ring = ri;
-			d->hdr.slot = &ring->slot[i];
-			d->hdr.buf = (u_char *)NETMAP_BUF(ring, idx);
+			d->hdr.slot = slot;
+			oldbuf = d->hdr.buf = (u_char *)NETMAP_BUF(ring, idx);
 			// __builtin_prefetch(buf);
-			d->hdr.len = d->hdr.caplen = ring->slot[i].len;
+			d->hdr.len = d->hdr.caplen = slot->len;
+			while (slot->flags & NS_MOREFRAG) {
+				u_char *nbuf;
+				u_int oldlen = slot->len;
+				i = nm_ring_next(ring, i);
+				slot = &ring->slot[i];
+				d->hdr.len += slot->len;
+				nbuf = (u_char *)NETMAP_BUF(ring, slot->buf_idx);
+				if (oldbuf != NULL && nbuf - oldbuf == ring->nr_buf_size &&
+						oldlen == ring->nr_buf_size) {
+					d->hdr.caplen += slot->len;
+					oldbuf = nbuf;
+				} else {
+					oldbuf = NULL;
+				}
+			}
 			d->hdr.ts = ring->ts;
 			ring->head = ring->cur = nm_ring_next(ring, i);
 		}

From c0bb4c5074c12df37599364eedb19f689c159c4e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 13 Sep 2018 18:33:44 +0200
Subject: [PATCH 1043/2207] bridge: remove hard-coded buflen

---
 apps/bridge/bridge.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 35bfdc593..0b7d43013 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -81,7 +81,7 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 			sleep(2);
 		}
 		/* copy the packet length. */
-		if (rs->len > 2048) {
+		if (rs->len > rxring->nr_buf_size) {
 			D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
 			rs->len = 0;
 		} else if (verbose > 1) {

From 0a040c445c9518ff2903f4d326bc7b3e2ca99265 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 13 Sep 2018 18:43:22 +0200
Subject: [PATCH 1044/2207] bridge: copy the NS_MOREFRAG during zerocopy

---
 apps/bridge/bridge.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 0b7d43013..e84c3b547 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -95,6 +95,8 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 			/* report the buffer change. */
 			ts->flags |= NS_BUF_CHANGED;
 			rs->flags |= NS_BUF_CHANGED;
+			/* copy the NS_MOREFRAG */
+			rs->flags = (rs->flags & ~NS_MOREFRAG) | (ts->flags & NS_MOREFRAG);
 		} else {
 			char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx);
 			char *txbuf = NETMAP_BUF(txring, ts->buf_idx);

From e98e42874e1ba7f7cbe3e9c0c97c1fa8efa1b800 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 14:31:22 +0200
Subject: [PATCH 1045/2207] bridge: rate limit the error messages

---
 apps/bridge/bridge.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index e84c3b547..967fc850b 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -76,13 +76,13 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 
 		/* swap packets */
 		if (ts->buf_idx < 2 || rs->buf_idx < 2) {
-			D("wrong index rx[%d] = %d  -> tx[%d] = %d",
+			RD(5, "wrong index rx[%d] = %d  -> tx[%d] = %d",
 				j, rs->buf_idx, k, ts->buf_idx);
 			sleep(2);
 		}
 		/* copy the packet length. */
 		if (rs->len > rxring->nr_buf_size) {
-			D("wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
+			RD(5, "wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
 			rs->len = 0;
 		} else if (verbose > 1) {
 			D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k);

From e98c2c6134fa7da77f68fd1a759c4b574fe0cb1c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 14:44:07 +0200
Subject: [PATCH 1046/2207] pkt-gen: let -frx only count complete packets

---
 apps/pkt-gen/pkt-gen.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index aabae97bf..6d949301e 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1691,6 +1691,7 @@ receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes
 {
 	u_int cur, rx, n;
 	uint64_t b = 0;
+	u_int complete = 0;
 
 	if (bytes == NULL)
 		bytes = &b;
@@ -1706,12 +1707,14 @@ receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes
 		*bytes += slot->len;
 		if (dump)
 			dump_payload(p, slot->len, ring, cur);
+		if (!(slot->flags & NS_MOREFRAG))
+			complete++;
 
 		cur = nm_ring_next(ring, cur);
 	}
 	ring->head = ring->cur = cur;
 
-	return (rx);
+	return (complete);
 }
 
 static void *

From e80f78f811e5fe41145cbe27725d9a22a58cbfbf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 15:11:31 +0200
Subject: [PATCH 1047/2207] pkt-gen: use a per-thread RNG

---
 apps/pkt-gen/pkt-gen.c | 47 +++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 6d949301e..b4cefc4a9 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -332,6 +332,7 @@ struct targ {
 
 	struct pkt pkt;
 	void *frame;
+	uint16_t seed[3];
 };
 
 static __inline uint16_t
@@ -751,8 +752,9 @@ dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur)
 #endif /* linux */
 
 static void
-update_ip(struct pkt *pkt, struct glob_arg *g)
+update_ip(struct pkt *pkt, struct targ *t)
 {
+	struct glob_arg *g = t->g;
 	struct ip ip;
 	struct udphdr udp;
 	uint32_t oaddr, naddr;
@@ -766,8 +768,8 @@ update_ip(struct pkt *pkt, struct glob_arg *g)
 		naddr = oaddr = ntohl(ip.ip_src.s_addr);
 		nport = oport = ntohs(udp.uh_sport);
 		if (g->options & OPT_RANDOM_SRC) {
-			ip.ip_src.s_addr = random();
-			udp.uh_sport = random();
+			ip.ip_src.s_addr = nrand48(t->seed);
+			udp.uh_sport = nrand48(t->seed);
 			naddr = ntohl(ip.ip_src.s_addr);
 			nport = ntohs(udp.uh_sport);
 			break;
@@ -802,8 +804,8 @@ update_ip(struct pkt *pkt, struct glob_arg *g)
 		naddr = oaddr = ntohl(ip.ip_dst.s_addr);
 		nport = oport = ntohs(udp.uh_dport);
 		if (g->options & OPT_RANDOM_DST) {
-			ip.ip_dst.s_addr = random();
-			udp.uh_dport = random();
+			ip.ip_dst.s_addr = nrand48(t->seed);
+			udp.uh_dport = nrand48(t->seed);
 			naddr = ntohl(ip.ip_dst.s_addr);
 			nport = ntohs(udp.uh_dport);
 			break;
@@ -848,8 +850,9 @@ update_ip(struct pkt *pkt, struct glob_arg *g)
 #define	s6_addr16	__u6_addr.__u6_addr16
 #endif
 static void
-update_ip6(struct pkt *pkt, struct glob_arg *g)
+update_ip6(struct pkt *pkt, struct targ *t)
 {
+	struct glob_arg *g = t->g;
 	struct ip6_hdr ip6;
 	struct udphdr udp;
 	uint16_t udp_sum;
@@ -865,8 +868,8 @@ update_ip6(struct pkt *pkt, struct glob_arg *g)
 		naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]);
 		nport = oport = ntohs(udp.uh_sport);
 		if (g->options & OPT_RANDOM_SRC) {
-			ip6.ip6_src.s6_addr16[group] = random();
-			udp.uh_sport = random();
+			ip6.ip6_src.s6_addr16[group] = nrand48(t->seed);
+			udp.uh_sport = nrand48(t->seed);
 			naddr = ntohs(ip6.ip6_src.s6_addr16[group]);
 			nport = ntohs(udp.uh_sport);
 			break;
@@ -897,8 +900,8 @@ update_ip6(struct pkt *pkt, struct glob_arg *g)
 		naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
 		nport = oport = ntohs(udp.uh_dport);
 		if (g->options & OPT_RANDOM_DST) {
-			ip6.ip6_dst.s6_addr16[group] = random();
-			udp.uh_dport = random();
+			ip6.ip6_dst.s6_addr16[group] = nrand48(t->seed);
+			udp.uh_dport = nrand48(t->seed);
 			naddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
 			nport = ntohs(udp.uh_dport);
 			break;
@@ -932,13 +935,13 @@ update_ip6(struct pkt *pkt, struct glob_arg *g)
 }
 
 static void
-update_addresses(struct pkt *pkt, struct glob_arg *g)
+update_addresses(struct pkt *pkt, struct targ *t)
 {
 
-	if (g->af == AF_INET)
-		update_ip(pkt, g);
+	if (t->g->af == AF_INET)
+		update_ip(pkt, t);
 	else
-		update_ip6(pkt, g);
+		update_ip6(pkt, t);
 }
 /*
  * initialize one packet and prepare for the next one.
@@ -1112,7 +1115,7 @@ set_vnet_hdr_len(struct glob_arg *g)
  */
 static int
 send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
-		int size, struct glob_arg *g, u_int count, int options,
+		int size, struct targ *t, u_int count, int options,
 		u_int nfrags)
 {
 	u_int n, sent, cur = ring->cur;
@@ -1151,11 +1154,11 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		} else if ((options & OPT_COPY) || buf_changed) {
 			nm_pkt_copy(frame, p, size);
 			if (fcnt == nfrags)
-				update_addresses(pkt, g);
+				update_addresses(pkt, t);
 		} else if (options & OPT_MEMCPY) {
 			memcpy(p, frame, size);
 			if (fcnt == nfrags)
-				update_addresses(pkt, g);
+				update_addresses(pkt, t);
 		} else if (options & OPT_PREFETCH) {
 			__builtin_prefetch(p);
 		}
@@ -1534,7 +1537,7 @@ sender_body(void *data)
 	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
 		if (write(targ->g->main_fd, frame, size) != -1)
 			sent++;
-		update_addresses(pkt, targ->g);
+		update_addresses(pkt, targ);
 		if (i > 10000) {
 			targ->ctr.pkts = sent;
 			targ->ctr.bytes = sent*size;
@@ -1619,11 +1622,11 @@ sender_body(void *data)
 				limit = ((limit + frags - 1) / frags) * frags;
 
 			if (targ->g->pkt_min_size > 0) {
-				size = random() %
+				size = nrand48(targ->seed) %
 					(targ->g->pkt_size - targ->g->pkt_min_size) +
 					targ->g->pkt_min_size;
 			}
-			m = send_packets(txring, pkt, frame, size, targ->g,
+			m = send_packets(txring, pkt, frame, size, targ,
 					 limit, options, frags);
 			ND("limit %lu tail %d frags %d m %d",
 				limit, txring->tail, frags, m);
@@ -1961,7 +1964,7 @@ txseq_body(void *data)
 			memcpy(targ->g->af == AF_INET ? &pkt->ipv4.udp.uh_sum : &pkt->ipv6.udp.uh_sum, &sum, sizeof(sum));
 			nm_pkt_copy(frame, p, size);
 			if (fcnt == frags) {
-				update_addresses(pkt, targ->g);
+				update_addresses(pkt, targ);
 			}
 
 			if (options & OPT_DUMP) {
@@ -2359,11 +2362,13 @@ start_threads(struct glob_arg *g) {
 	 * using a single descriptor.
 	 */
 	for (i = 0; i < g->nthreads; i++) {
+		unsigned int seed = time(0);
 		t = &targs[i];
 
 		bzero(t, sizeof(*t));
 		t->fd = -1; /* default, with pcap */
 		t->g = g;
+		memcpy(t->seed, &seed, sizeof(t->seed));
 
 		if (g->dev_type == DEV_NETMAP) {
 			struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */

From 307ea66c771aa43ea9467db60f48eb9cf69ee5a5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 15:27:37 +0200
Subject: [PATCH 1048/2207] pkt-gen: fix byte count when random pkt size is
 used

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index b4cefc4a9..9969690ee 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1634,7 +1634,7 @@ sender_body(void *data)
 			if (m > 0) //XXX-ste: can m be 0?
 				event++;
 			targ->ctr.pkts = sent;
-			targ->ctr.bytes = sent*size;
+			targ->ctr.bytes += m*size;
 			targ->ctr.events = event;
 			if (rate_limit) {
 				tosend -= m;

From 8e85541a3e83733049fd031f8a7b09c70a18cad8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 15:56:45 +0200
Subject: [PATCH 1049/2207] pkt-gen: optionally account for ethernet framing
 when printing bps

---
 apps/pkt-gen/pkt-gen.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 9969690ee..e61a8d844 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -305,6 +305,7 @@ struct glob_arg {
 	int win_idx;
 	int64_t win[STATS_WIN];
 	int wait_link;
+	int framing;		/* #bits of framing (for bw output) */
 };
 enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
 
@@ -2339,6 +2340,7 @@ usage(int errcode)
 		     "\t			assigned to both #tx-rings and #rx-rings.\n"
 #endif
 		     "\t-e extra-bufs		extra_bufs - goes in nr_arg3\n"
+		     "\t-B                      account for ethernet framing when showing bps\n"
 		     "\t-m			ignored\n"
 		     "",
 		cmd);
@@ -2504,7 +2506,7 @@ main_thread(struct glob_arg *g)
 		D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space",
 			norm(b1, pps, normalize), b4,
 			norm(b2, (double)x.pkts, normalize),
-			norm(b3, (double)x.bytes*8, normalize),
+			norm(b3, (double)x.bytes*8+(double)x.pkts*g->framing, normalize),
 			(unsigned long long)usec,
 			abs, (int)cur.min_space);
 		prev = cur;
@@ -2689,7 +2691,7 @@ main(int arc, char **argv)
 	g.wait_link = 2;	/* wait 2 seconds for physical ports */
 
 	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
-	    "T:w:WvR:XC:H:e:E:m:rP:zZAh")) != -1) {
+	    "T:w:WvR:XC:H:e:E:m:rP:zZAhB")) != -1) {
 
 		switch(ch) {
 		default:
@@ -2866,6 +2868,10 @@ main(int arc, char **argv)
 		case 'A':
 			g.options |= OPT_PPS_STATS;
 			break;
+		case 'B':
+			// XXX maybe add an option to pass the IFG
+			g.framing = 24 * 8;
+			break;
 		}
 	}
 

From e79ab33264e4c43fd8206d8dccf0e7dcf9138e06 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Sep 2018 15:37:57 +0200
Subject: [PATCH 1050/2207] linux/igb: fix install target

---
 LINUX/final-patches/intel--igb--5.3.5.20 | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/LINUX/final-patches/intel--igb--5.3.5.20 b/LINUX/final-patches/intel--igb--5.3.5.20
index 491e65f5c..c01e85e7f 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.20
+++ b/LINUX/final-patches/intel--igb--5.3.5.20
@@ -1,5 +1,5 @@
 diff --git a/igb/Makefile b/igb/Makefile
-index 02d49bb..8a35007 100644
+index 02d49bb..1c88549 100644
 --- a/igb/Makefile
 +++ b/igb/Makefile
 @@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
@@ -39,8 +39,12 @@ index 02d49bb..8a35007 100644
  
  ifeq (,$(wildcard common.mk))
    $(error Cannot find common.mk build rules)
-@@ -118,6 +118,9 @@ ccc: clean
- manfile:
+@@ -115,9 +115,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
  	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
  
 +../$(DRIVER).$(MANSECTION):

From e489850f66cb504bded22e801f21e55efb58275d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 21 Sep 2018 21:28:09 +0200
Subject: [PATCH 1051/2207] pkt-gen: fix out-of-bounds memory access issue

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index e61a8d844..ab986920d 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2364,7 +2364,7 @@ start_threads(struct glob_arg *g) {
 	 * using a single descriptor.
 	 */
 	for (i = 0; i < g->nthreads; i++) {
-		unsigned int seed = time(0);
+		uint64_t seed = time(0) | (time(0) << 32);
 		t = &targs[i];
 
 		bzero(t, sizeof(*t));

From 177262c1e394252b5eb0f5d76801ab6ce67c1262 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 15:54:38 +0200
Subject: [PATCH 1052/2207] use strlcpy() to avoid unterminated strings

This also fixes compiler warnings on some platforms.
---
 sys/dev/netmap/netmap_legacy.c | 4 ++--
 sys/dev/netmap/netmap_mem2.c   | 2 +-
 sys/dev/netmap/netmap_vale.c   | 8 ++++----
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 2d80e803b..728595b29 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -128,7 +128,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 
 	/* First prepare the request header. */
 	hdr->nr_version = NETMAP_API; /* new API */
-	strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
+	strlcpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
 	hdr->nr_options = (uintptr_t)NULL;
 	hdr->nr_body = (uintptr_t)NULL;
 
@@ -318,7 +318,7 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_VALE_LIST: {
 		struct nmreq_vale_list *req =
 			(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
-		strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
+		strlcpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
 		nmr->nr_arg1 = req->nr_bridge_idx;
 		nmr->nr_arg2 = req->nr_port_idx;
 		break;
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index fb93ad4d0..53f3739ef 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1998,7 +1998,7 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	/* initialize base fields -- override const */
 	*(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings;
 	*(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings;
-	strncpy(nifp->ni_name, na->name, (size_t)IFNAMSIZ);
+	strlcpy(nifp->ni_name, na->name, sizeof(nifp->ni_name));
 
 	/*
 	 * fill the slots for the rx and tx rings. They contain the offset
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index e62de51dc..9c3604c5f 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -369,8 +369,8 @@ netmap_vale_list(struct nmreq_header *hdr)
 					continue;
 				vpna = b->bdg_ports[j];
 				/* write back the VALE switch name */
-				strncpy(hdr->nr_name, vpna->up.name,
-					(size_t)IFNAMSIZ);
+				strlcpy(hdr->nr_name, vpna->up.name,
+					sizeof(hdr->nr_name));
 				error = 0;
 				goto out;
 			}
@@ -1346,7 +1346,7 @@ netmap_vale_vp_bdg_attach(const char *name, struct netmap_adapter *na,
 		return NM_NEED_BWRAP;
 	}
 	na->na_vp = vpna;
-	strncpy(na->name, name, sizeof(na->name));
+	strlcpy(na->name, name, sizeof(na->name));
 	na->na_hostvp = NULL;
 	return 0;
 }
@@ -1387,7 +1387,7 @@ netmap_vale_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 		return ENOMEM;
 	}
 	na = &bna->up.up;
-	strncpy(na->name, nr_name, sizeof(na->name));
+	strlcpy(na->name, nr_name, sizeof(na->name));
 	na->nm_register = netmap_bwrap_reg;
 	na->nm_txsync = netmap_vale_vp_txsync;
 	// na->nm_rxsync = netmap_bwrap_rxsync;

From 5ffac4d5fda29c6b2e4c795e57d521f659b3fc30 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 16:06:23 +0200
Subject: [PATCH 1053/2207] bdg: export nm_bridges in case CONFIG_NET_NS is not
 defined

This is needed for instance on FreeBSD.
---
 sys/dev/netmap/netmap_bdg.c  | 2 +-
 sys/dev/netmap/netmap_kern.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index e2619bad1..da5f00600 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -126,7 +126,7 @@ netmap_bdg_name(struct netmap_vp_adapter *vp)
  * Right now we have a static array and deletions are protected
  * by an exclusive lock.
  */
-static struct nm_bridge *nm_bridges;
+struct nm_bridge *nm_bridges;
 #endif /* !CONFIG_NET_NS */
 
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7eff9eb9e..74de1c6bd 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1486,6 +1486,7 @@ struct net *netmap_bns_get(void);
 void netmap_bns_put(struct net *);
 void netmap_bns_getbridges(struct nm_bridge **, u_int *);
 #else
+extern struct nm_bridge *nm_bridges;
 #define netmap_bns_get()
 #define netmap_bns_put(_1)
 #define netmap_bns_getbridges(b, n) \

From f9f9bdd4f424597f553b560e6e073b63e2e29b1c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 16:18:45 +0200
Subject: [PATCH 1054/2207] replace more strncpy() calls with the safer
 strlcpy()

---
 LINUX/netmap_linux.c            | 2 +-
 LINUX/netmap_ptnet.c            | 2 +-
 sys/dev/netmap/netmap.c         | 2 +-
 sys/dev/netmap/netmap_generic.c | 2 +-
 sys/dev/netmap/netmap_pipe.c    | 6 +++---
 sys/dev/netmap/netmap_pt.c      | 2 +-
 sys/dev/netmap/netmap_vale.c    | 2 +-
 7 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 868cde38d..cfba69bd4 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2330,7 +2330,7 @@ netmap_sink_init(void)
 		return -ENOMEM;
 	}
 	netdev->netdev_ops = &nm_sink_netdev_ops ;
-	strncpy(netdev->name, "nmsink", sizeof(netdev->name) - 1);
+	strlcpy(netdev->name, "nmsink", sizeof(netdev->name));
 	netdev->features = NETIF_F_HIGHDMA;
 	strcpy(netdev->name, "nmsink%d");
 	err = register_netdev(netdev);
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index eef78b16d..da3cf5f7a 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1439,7 +1439,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		netif_napi_add(netdev, &prq->napi, ptnet_rx_poll, NAPI_POLL_WEIGHT);
 	}
 
-	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+	strlcpy(netdev->name, pci_name(pdev), sizeof(netdev->name));
 
 	/* Read MAC address from device and put it into the netdev struct. */
 	macreg = ioread32(ioaddr + PTNET_IO_MAC_HI);
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9e0f093d5..20bafe33f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3456,7 +3456,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		goto fail;
 	hwna->up = *arg;
 	hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE;
-	strncpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name));
+	strlcpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name));
 	if (override_reg) {
 		hwna->nm_hw_register = hwna->up.nm_register;
 		hwna->up.nm_register = netmap_hw_reg;
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 277431ef1..d17c0c440 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1113,7 +1113,7 @@ generic_netmap_attach(struct ifnet *ifp)
 		return ENOMEM;
 	}
 	na = (struct netmap_adapter *)gna;
-	strncpy(na->name, ifp->if_xname, sizeof(na->name));
+	strlcpy(na->name, ifp->if_xname, sizeof(na->name));
 	na->ifp = ifp;
 	na->num_tx_desc = num_tx_desc;
 	na->num_rx_desc = num_rx_desc;
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index eef2f1518..9aa74de85 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -672,11 +672,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		int create_error;
 
 		/* Temporarily remove the pipe suffix. */
-		strncpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
+		strlcpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
 		*cbra = '\0';
 		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
 		/* Restore the pipe suffix. */
-		strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
+		strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -689,7 +689,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		NMG_UNLOCK();
 		create_error = netmap_vi_create(hdr, 1 /* autodelete */);
 		NMG_LOCK();
-		strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
+		strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
 				D("failed to create a persistent vale port: %d", create_error);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index bf7872ff2..f53d66282 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -1243,7 +1243,7 @@ netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
     *na = &pth_na->up;
     /* set parent busy, because attached for ptnetmap */
     parent->na_flags |= NAF_BUSY;
-    strncpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
+    strlcpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
     strcat(pth_na->up.name, "-PTN");
     netmap_adapter_get(*na);
 
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 9c3604c5f..619ede6c0 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1263,7 +1263,7 @@ netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
  	na = &vpna->up;
 
 	na->ifp = ifp;
-	strncpy(na->name, hdr->nr_name, sizeof(na->name));
+	strlcpy(na->name, hdr->nr_name, sizeof(na->name));
 
 	/* bound checking */
 	na->num_tx_rings = req->nr_tx_rings;

From 64d7075febabf3535285d00f048182a4bd0b9d90 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 16:24:12 +0200
Subject: [PATCH 1055/2207] configure: accept -h in addition to --help

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 60ce1548b..7ce6643a0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -627,7 +627,7 @@ for opt do
 	;;
 	--cache=*) cache="$optarg"
 	;;
-	--help)
+	--help | -h)
 		print_help
 		exit
 	;;

From 00b347649536435ed5cd64c7f32b9e5058818160 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 16:43:57 +0200
Subject: [PATCH 1056/2207] netmap_ioctl: minor code simplification

---
 sys/dev/netmap/netmap.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 20bafe33f..e2ed6051d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2305,7 +2305,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	struct ifnet *ifp = NULL;
 	int error = 0;
 	u_int i, qfirst, qlast;
-	struct netmap_if *nifp;
 	struct netmap_kring **krings;
 	int sync_flags;
 	enum txrx t;
@@ -2343,6 +2342,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		case NETMAP_REQ_REGISTER: {
 			struct nmreq_register *req =
 				(struct nmreq_register *)(uintptr_t)hdr->nr_body;
+			struct netmap_if *nifp;
+
 			/* Protect access to priv from concurrent requests. */
 			NMG_LOCK();
 			do {
@@ -2639,9 +2640,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 	case NIOCTXSYNC:
 	case NIOCRXSYNC: {
-		nifp = priv->np_nifp;
-
-		if (nifp == NULL) {
+		if (priv->np_nifp == NULL) {
 			error = ENXIO;
 			break;
 		}

From 70a8c6f908b4191932466521fa93fc67339bf49d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 17:08:30 +0200
Subject: [PATCH 1057/2207] integration tests: make the script independent on
 working directory

---
 ci/run-integration-tests |  2 --
 utils/randomized_tests   | 12 ++++++++++-
 utils/test_lib           | 43 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 7125b33aa..4e5e309cb 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -12,9 +12,7 @@ popd
 sudo rmmod netmap
 
 # Run integration tests
-sudo modprobe netmap
 pushd .
 cd utils
 sudo ./randomized_tests
 popd
-sudo rmmod netmap
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 041d8aa98..c7d41df9d 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -28,13 +28,19 @@ echo "   sequence check   : ${seq_check}"
 echo "   packet length    : ${random_len}"
 echo ""
 
-# We add the current directory to the PATH. This way we can directly run
+# Save current directory and enter the utils/ directory.
+pushd $(pwd)
+cd $(dirname $0)
+
+# Add the current directory to the PATH. In this way we can easily invoke
 # functional, get_tx_rings_avail_sends and get_tx_rings_max_sends from the test
 # scripts.
 PATH="$(pwd):${PATH}"
 
 source test_lib
 
+netmap_load
+
 for test in tests/*_test ; do
 	restart_fd_server
 	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
@@ -49,9 +55,13 @@ for test in tests/*_test ; do
 		restart_fd_server
 		$test -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 		close_fd_server
+		popd
 		exit $?
 	fi
 done
 
 # Wait for the fd_server to terminate and release its references
 sleep 0.5
+
+netmap_unload
+popd
diff --git a/utils/test_lib b/utils/test_lib
index 081a44c68..b7d3bd63f 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -274,7 +274,6 @@ function parse_send_recv_arguments() {
 	done
 }
 
-
 ################################################################################
 # Prints to stdout the hexadecimal representation of the received integer.
 # Arguments:
@@ -308,3 +307,45 @@ function get_random_MAC() {
 		echo "$MAC"
 	fi
 }
+
+################################################################################
+# Loads the netmap module, if needed.
+# Arguments:
+#   None
+################################################################################
+function netmap_load() {
+	os=$(uname -s)
+	case $os in
+		Linux)
+			modprobe netmap
+			;;
+		FreeBSD)
+			# Nothing to do. We assume it is built in-kernel.
+			;;
+		*)
+			echo "$os not supported"
+			exit 1
+			;;
+	esac
+}
+
+################################################################################
+# Unloads the netmap module, if needed.
+# Arguments:
+#   None
+################################################################################
+function netmap_unload() {
+	os=$(uname -s)
+	case $os in
+		Linux)
+			rmmod netmap
+			;;
+		FreeBSD)
+			# Nothing to do.
+			;;
+		*)
+			echo "$os not supported"
+			exit 1
+			;;
+	esac
+}

From 5e8b562d2b45d509b49ea67617f4f4b50cf15091 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 17:31:51 +0200
Subject: [PATCH 1058/2207] configure: build the utils by default

---
 LINUX/configure | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 7ce6643a0..2c1e17921 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -4,7 +4,7 @@ BUILDDIR=$PWD
 SRCDIR=$(cd $(dirname $0); pwd)
 MODNAME=netmap
 DEBUG=1
-UTILS=
+UTILS=1
 DRVERRFAIL=
 DMASYNC=1
 
@@ -306,7 +306,7 @@ Available options:
   --no-apps	               do not compile any app
   --no-apps=                   do not compile the given apps (comma sep.)
   --apps=                      only compile the given apps (comma sep.)
-  --utils		       also compile the utils
+  --no-utils		       do not compile the utils
   --mod-name=		       netmap module name [$MODNAME]
   --enable-vale      	       enable the VALE switch
   --disable-vale      	       disable the VALE switch
@@ -649,8 +649,8 @@ for opt do
 	--no-force-debug)
 		DEBUG=
 	;;
-	--utils)
-		UTILS=1
+	--no-utils)
+		UTILS=
 		;;
 	--fail-on-driver-errors)
 		DRVERRFAIL=1

From 4fe80fc08b35600763257d4c51fdf391ff3fadb5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 17:48:08 +0200
Subject: [PATCH 1059/2207] configure: let build-utils/ be a symlink to utils/

---
 LINUX/configure | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 2c1e17921..903a95994 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1987,8 +1987,7 @@ done
 
 # create the build directory for the utils
 if [ -n "$UTILS" ]; then
-	mkdir -p build-utils
-	ln -s $SRCDIR/../utils/GNUmakefile build-utils/GNUmakefile 2>/dev/null || true
+	ln -s $SRCDIR/../utils/ build-utils 2>/dev/null || true
 fi
 
 # config.status can be used to rerun configure with the

From 0ace1de18b49028c1a804014d08cf5ce49d2e76b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 17:53:15 +0200
Subject: [PATCH 1060/2207] Makefile: add "intest" target to run integration
 tests

---
 LINUX/netmap.mak.in | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 26969003b..8722f9912 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -135,6 +135,7 @@ ifeq (,$(UTILS))
 utils:
 install-utils:
 clean-utils:
+intest:
 else
 .PHONY: utils
 utils:
@@ -145,6 +146,9 @@ install-utils:
 
 clean-utils:
 	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/..
+
+intest: utils
+	utils/randomized_tests
 endif
 
 INCLUDE_PREFIX := $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)

From 13f170bd4a724d6d2570e5e5a1c22ab7a8e43cc9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 17:55:51 +0200
Subject: [PATCH 1061/2207] simplify travis commands to run integration tests

---
 ci/run-integration-tests | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 4e5e309cb..5a6fce325 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -12,7 +12,4 @@ popd
 sudo rmmod netmap
 
 # Run integration tests
-pushd .
-cd utils
-sudo ./randomized_tests
-popd
+sudo make intest

From 59e645fff3b0740b5853e6a7c055a4e05736b70d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 09:56:05 +0200
Subject: [PATCH 1062/2207] utils: ctrl-api-test: reformat

---
 utils/ctrl-api-test.c | 107 +++++++++++++++++++++---------------------
 1 file changed, 54 insertions(+), 53 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 0117ec07e..662437165 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -50,7 +50,7 @@ nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
 {
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->nr_version = NETMAP_API;
-	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name)-1);
+	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
 }
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
@@ -81,10 +81,10 @@ port_info_get(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-			       req.nr_tx_rings && req.nr_rx_rings &&
-			       req.nr_tx_rings
-		       ? 0
-		       : -1;
+	                       req.nr_tx_rings && req.nr_rx_rings &&
+	                       req.nr_tx_rings
+	               ? 0
+	               : -1;
 }
 
 /* Single NETMAP_REQ_REGISTER, no use. */
@@ -113,7 +113,7 @@ port_register(int fd, struct TestContext *ctx)
 	req.nr_tx_rings   = ctx->nr_tx_rings;
 	req.nr_rx_rings   = ctx->nr_rx_rings;
 	req.nr_extra_bufs = ctx->nr_extra_bufs;
-	ret		  = ioctl(fd, NIOCCTRL, &hdr);
+	ret               = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
@@ -128,21 +128,21 @@ port_register(int fd, struct TestContext *ctx)
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
 	return req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
-			       (ctx->nr_ringid == req.nr_ringid) &&
-			       (ctx->nr_flags == req.nr_flags) &&
-			       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
-				(ctx->nr_tx_slots == req.nr_tx_slots)) &&
-			       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
-				(ctx->nr_rx_slots == req.nr_rx_slots)) &&
-			       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
-				(ctx->nr_tx_rings == req.nr_tx_rings)) &&
-			       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
-				(ctx->nr_rx_rings == req.nr_rx_rings)) &&
-			       ((!ctx->nr_mem_id && req.nr_mem_id) ||
-				(ctx->nr_mem_id == req.nr_mem_id)) &&
-			       (ctx->nr_extra_bufs == req.nr_extra_bufs)
-		       ? 0
-		       : -1;
+	                       (ctx->nr_ringid == req.nr_ringid) &&
+	                       (ctx->nr_flags == req.nr_flags) &&
+	                       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+	                        (ctx->nr_tx_slots == req.nr_tx_slots)) &&
+	                       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+	                        (ctx->nr_rx_slots == req.nr_rx_slots)) &&
+	                       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+	                        (ctx->nr_tx_rings == req.nr_tx_rings)) &&
+	                       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+	                        (ctx->nr_rx_rings == req.nr_rx_rings)) &&
+	                       ((!ctx->nr_mem_id && req.nr_mem_id) ||
+	                        (ctx->nr_mem_id == req.nr_mem_id)) &&
+	                       (ctx->nr_extra_bufs == req.nr_extra_bufs)
+	               ? 0
+	               : -1;
 }
 
 static int
@@ -195,7 +195,7 @@ vale_attach(int fd, struct TestContext *ctx)
 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
 	}
 	req.reg.nr_mode = ctx->nr_mode;
-	ret		= ioctl(fd, NIOCCTRL, &hdr);
+	ret             = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -203,10 +203,10 @@ vale_attach(int fd, struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
 
 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
-		(ctx->nr_mem_id == req.reg.nr_mem_id)) &&
-			       (ctx->nr_flags == req.reg.nr_flags)
-		       ? 0
-		       : -1;
+	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
+	                       (ctx->nr_flags == req.reg.nr_flags)
+	               ? 0
+	               : -1;
 }
 
 /* NETMAP_REQ_VALE_DETACH */
@@ -224,7 +224,7 @@ vale_detach(int fd, struct TestContext *ctx)
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	hdr.nr_body    = (uintptr_t)&req;
-	ret	    = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		return ret;
@@ -269,7 +269,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr_len = ctx->nr_hdr_len;
-	ret	    = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -282,7 +282,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
 	req.nr_hdr_len = 0;
-	ret	    = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -339,7 +339,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	req.nr_rx_slots = ctx->nr_rx_slots;
 	req.nr_tx_rings = ctx->nr_tx_rings;
 	req.nr_rx_rings = ctx->nr_rx_rings;
-	ret		= ioctl(fd, NIOCCTRL, &hdr);
+	ret             = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		return ret;
@@ -351,7 +351,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	hdr.nr_body    = (uintptr_t)NULL;
-	ret	    = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		if (result == 0) {
@@ -394,13 +394,13 @@ pools_info_get(int fd, struct TestContext *ctx)
 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
 
 	return req.nr_memsize && req.nr_if_pool_objtotal &&
-			       req.nr_if_pool_objsize &&
-			       req.nr_ring_pool_objtotal &&
-			       req.nr_ring_pool_objsize &&
-			       req.nr_buf_pool_objtotal &&
-			       req.nr_buf_pool_objsize
-		       ? 0
-		       : -1;
+	                       req.nr_if_pool_objsize &&
+	                       req.nr_ring_pool_objtotal &&
+	                       req.nr_ring_pool_objsize &&
+	                       req.nr_buf_pool_objtotal &&
+	                       req.nr_buf_pool_objsize
+	               ? 0
+	               : -1;
 }
 
 static int
@@ -416,7 +416,7 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	}
 
 	ctx->nr_mode = NR_REG_ONE_NIC;
-	ret	  = port_register(fd, ctx);
+	ret          = port_register(fd, ctx);
 	if (ret) {
 		return ret;
 	}
@@ -471,20 +471,20 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
-	req.nr_mode		= ctx->nr_mode;
+	req.nr_mode             = ctx->nr_mode;
 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
-	ret			= ioctl(fd, NIOCCTRL, &hdr);
+	ret                     = ioctl(fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
 		return ret;
 	}
 
 	return (req.nr_mode == ctx->nr_mode &&
-		req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
-		req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
-		       ? 0
-		       : -1;
+	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
+	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
+	               ? 0
+	               : -1;
 }
 
 /* NETMAP_REQ_VALE_POLLING_DISABLE */
@@ -521,7 +521,7 @@ vale_polling_enable_disable(int fd, struct TestContext *ctx)
 		return ret;
 	}
 
-	ctx->nr_mode		 = NETMAP_POLLING_MODE_SINGLE_CPU;
+	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
 	ctx->nr_num_polling_cpus = 1;
 	ctx->nr_first_cpu_id     = 0;
 	if ((ret = vale_polling_enable(fd, ctx))) {
@@ -555,8 +555,8 @@ checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
 {
 	if (opt->nro_next != exp->nro_next) {
 		printf("nro_next %p expected %p\n",
-			(void *)(uintptr_t)opt->nro_next,
-			(void *)(uintptr_t)exp->nro_next);
+		       (void *)(uintptr_t)opt->nro_next,
+		       (void *)(uintptr_t)exp->nro_next);
 		return -1;
 	}
 	if (opt->nro_reqtype != exp->nro_reqtype) {
@@ -602,7 +602,7 @@ infinite_options(int fd, struct TestContext *ctx)
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
 	opt.nro_next = (uintptr_t)&opt;
-	save	 = opt;
+	save         = opt;
 	if (port_register_hwall(fd, ctx) >= 0)
 		return -1;
 
@@ -652,7 +652,7 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 	void *addr;
 
 	addr = mmap(NULL, (1U << 22), PROT_READ | PROT_WRITE,
-		    MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 	if (addr == MAP_FAILED) {
 		perror("mmap");
 		return -1;
@@ -660,7 +660,7 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 
 	memset(e, 0, sizeof(*e));
 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
-	e->nro_usrptr	  = (uintptr_t)addr;
+	e->nro_usrptr          = (uintptr_t)addr;
 	e->nro_info.nr_memsize = (1U << 22);
 
 	push_option(&e->nro_opt, ctx);
@@ -674,7 +674,7 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 	struct nmreq_opt_extmem *e;
 	int ret;
 
-	e	   = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
+	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
 
 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
@@ -692,7 +692,8 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 		return -1;
 	}
 
-	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr, e->nro_info.nr_memsize)))
+	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
+	                  e->nro_info.nr_memsize)))
 		return ret;
 
 	return 0;

From 71f8cf0dbd4ab21645c898353e98f494c7221690 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 10:18:42 +0200
Subject: [PATCH 1063/2207] utils: ctrl-api-test: move netmap fd into struct
 TestContext

---
 utils/ctrl-api-test.c | 140 +++++++++++++++++++++---------------------
 1 file changed, 71 insertions(+), 69 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 662437165..8e57c4886 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -12,6 +12,7 @@
 #include 
 
 struct TestContext {
+	int fd;                 /* netmap file descriptor */
 	const char *ifname;
 	const char *bdgname;
 	uint32_t nr_tx_slots;   /* slots in tx rings */
@@ -43,7 +44,7 @@ ctx_reset(struct TestContext *ctx)
 }
 #endif
 
-typedef int (*testfunc_t)(int fd, struct TestContext *ctx);
+typedef int (*testfunc_t)(struct TestContext *ctx);
 
 static void
 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
@@ -55,7 +56,7 @@ nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
 static int
-port_info_get(int fd, struct TestContext *ctx)
+port_info_get(struct TestContext *ctx)
 {
 	struct nmreq_port_info_get req;
 	struct nmreq_header hdr;
@@ -67,7 +68,7 @@ port_info_get(int fd, struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
-	ret = ioctl(fd, NIOCCTRL, &hdr);
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
@@ -89,7 +90,7 @@ port_info_get(int fd, struct TestContext *ctx)
 
 /* Single NETMAP_REQ_REGISTER, no use. */
 static int
-port_register(int fd, struct TestContext *ctx)
+port_register(struct TestContext *ctx)
 {
 	struct nmreq_register req;
 	struct nmreq_header hdr;
@@ -113,7 +114,7 @@ port_register(int fd, struct TestContext *ctx)
 	req.nr_tx_rings   = ctx->nr_tx_rings;
 	req.nr_rx_rings   = ctx->nr_rx_rings;
 	req.nr_extra_bufs = ctx->nr_extra_bufs;
-	ret               = ioctl(fd, NIOCCTRL, &hdr);
+	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
@@ -146,37 +147,37 @@ port_register(int fd, struct TestContext *ctx)
 }
 
 static int
-port_register_hwall_host(int fd, struct TestContext *ctx)
+port_register_hwall_host(struct TestContext *ctx)
 {
 	ctx->nr_mode = NR_REG_NIC_SW;
-	return port_register(fd, ctx);
+	return port_register(ctx);
 }
 
 static int
-port_register_host(int fd, struct TestContext *ctx)
+port_register_host(struct TestContext *ctx)
 {
 	ctx->nr_mode = NR_REG_SW;
-	return port_register(fd, ctx);
+	return port_register(ctx);
 }
 
 static int
-port_register_hwall(int fd, struct TestContext *ctx)
+port_register_hwall(struct TestContext *ctx)
 {
 	ctx->nr_mode = NR_REG_ALL_NIC;
-	return port_register(fd, ctx);
+	return port_register(ctx);
 }
 
 static int
-port_register_single_ring_couple(int fd, struct TestContext *ctx)
+port_register_single_ring_couple(struct TestContext *ctx)
 {
 	ctx->nr_mode   = NR_REG_ONE_NIC;
 	ctx->nr_ringid = 0;
-	return port_register(fd, ctx);
+	return port_register(ctx);
 }
 
 /* NETMAP_REQ_VALE_ATTACH */
 static int
-vale_attach(int fd, struct TestContext *ctx)
+vale_attach(struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
 	struct nmreq_header hdr;
@@ -195,7 +196,7 @@ vale_attach(int fd, struct TestContext *ctx)
 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
 	}
 	req.reg.nr_mode = ctx->nr_mode;
-	ret             = ioctl(fd, NIOCCTRL, &hdr);
+	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
@@ -211,7 +212,7 @@ vale_attach(int fd, struct TestContext *ctx)
 
 /* NETMAP_REQ_VALE_DETACH */
 static int
-vale_detach(int fd, struct TestContext *ctx)
+vale_detach(struct TestContext *ctx)
 {
 	struct nmreq_header hdr;
 	struct nmreq_vale_detach req;
@@ -224,7 +225,7 @@ vale_detach(int fd, struct TestContext *ctx)
 	nmreq_hdr_init(&hdr, vpname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	hdr.nr_body    = (uintptr_t)&req;
-	ret            = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		return ret;
@@ -235,28 +236,28 @@ vale_detach(int fd, struct TestContext *ctx)
 
 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
 static int
-vale_attach_detach(int fd, struct TestContext *ctx)
+vale_attach_detach(struct TestContext *ctx)
 {
 	int ret;
 
-	if ((ret = vale_attach(fd, ctx))) {
+	if ((ret = vale_attach(ctx))) {
 		return ret;
 	}
 
-	return vale_detach(fd, ctx);
+	return vale_detach(ctx);
 }
 
 static int
-vale_attach_detach_host_rings(int fd, struct TestContext *ctx)
+vale_attach_detach_host_rings(struct TestContext *ctx)
 {
 	ctx->nr_mode = NR_REG_NIC_SW;
-	return vale_attach_detach(fd, ctx);
+	return vale_attach_detach(ctx);
 }
 
 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
  * to check that we get the same value. */
 static int
-port_hdr_set_and_get(int fd, struct TestContext *ctx)
+port_hdr_set_and_get(struct TestContext *ctx)
 {
 	struct nmreq_port_hdr req;
 	struct nmreq_header hdr;
@@ -269,7 +270,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr_len = ctx->nr_hdr_len;
-	ret            = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -282,7 +283,7 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
 	req.nr_hdr_len = 0;
-	ret            = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
@@ -293,33 +294,33 @@ port_hdr_set_and_get(int fd, struct TestContext *ctx)
 }
 
 static int
-vale_ephemeral_port_hdr_manipulation(int fd, struct TestContext *ctx)
+vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
 {
 	int ret;
 
 	ctx->ifname  = "vale:eph0";
 	ctx->nr_mode = NR_REG_ALL_NIC;
-	if ((ret = port_register(fd, ctx))) {
+	if ((ret = port_register(ctx))) {
 		return ret;
 	}
 	/* Try to set and get all the acceptable values. */
 	ctx->nr_hdr_len = 12;
-	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+	if ((ret = port_hdr_set_and_get(ctx))) {
 		return ret;
 	}
 	ctx->nr_hdr_len = 0;
-	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+	if ((ret = port_hdr_set_and_get(ctx))) {
 		return ret;
 	}
 	ctx->nr_hdr_len = 10;
-	if ((ret = port_hdr_set_and_get(fd, ctx))) {
+	if ((ret = port_hdr_set_and_get(ctx))) {
 		return ret;
 	}
 	return 0;
 }
 
 static int
-vale_persistent_port(int fd, struct TestContext *ctx)
+vale_persistent_port(struct TestContext *ctx)
 {
 	struct nmreq_vale_newif req;
 	struct nmreq_header hdr;
@@ -339,19 +340,19 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 	req.nr_rx_slots = ctx->nr_rx_slots;
 	req.nr_tx_rings = ctx->nr_tx_rings;
 	req.nr_rx_rings = ctx->nr_rx_rings;
-	ret             = ioctl(fd, NIOCCTRL, &hdr);
+	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		return ret;
 	}
 
 	/* Attach the persistent VALE port to a switch and then detach. */
-	result = vale_attach_detach(fd, ctx);
+	result = vale_attach_detach(ctx);
 
 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	hdr.nr_body    = (uintptr_t)NULL;
-	ret            = ioctl(fd, NIOCCTRL, &hdr);
+	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		if (result == 0) {
@@ -364,7 +365,7 @@ vale_persistent_port(int fd, struct TestContext *ctx)
 
 /* Single NETMAP_REQ_POOLS_INFO_GET. */
 static int
-pools_info_get(int fd, struct TestContext *ctx)
+pools_info_get(struct TestContext *ctx)
 {
 	struct nmreq_pools_info req;
 	struct nmreq_header hdr;
@@ -376,7 +377,7 @@ pools_info_get(int fd, struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
-	ret = ioctl(fd, NIOCCTRL, &hdr);
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
 		return ret;
@@ -404,11 +405,11 @@ pools_info_get(int fd, struct TestContext *ctx)
 }
 
 static int
-register_and_pools_info_get(int fd, struct TestContext *ctx)
+register_and_pools_info_get(struct TestContext *ctx)
 {
 	int ret;
 
-	ret = pools_info_get(fd, ctx);
+	ret = pools_info_get(ctx);
 	if (ret == 0) {
 		printf("Failed: POOLS_INFO_GET didn't fail on unbound "
 		       "netmap device\n");
@@ -416,17 +417,17 @@ register_and_pools_info_get(int fd, struct TestContext *ctx)
 	}
 
 	ctx->nr_mode = NR_REG_ONE_NIC;
-	ret          = port_register(fd, ctx);
+	ret          = port_register(ctx);
 	if (ret) {
 		return ret;
 	}
 	ctx->nr_mem_id = 1;
 
-	return pools_info_get(fd, ctx);
+	return pools_info_get(ctx);
 }
 
 static int
-pipe_master(int fd, struct TestContext *ctx)
+pipe_master(struct TestContext *ctx)
 {
 	char pipe_name[128];
 
@@ -434,17 +435,17 @@ pipe_master(int fd, struct TestContext *ctx)
 	ctx->ifname  = pipe_name;
 	ctx->nr_mode = NR_REG_NIC_SW;
 
-	if (port_register(fd, ctx) == 0) {
+	if (port_register(ctx) == 0) {
 		printf("pipes should not accept NR_REG_NIC_SW\n");
 		return -1;
 	}
 	ctx->nr_mode = NR_REG_ALL_NIC;
 
-	return port_register(fd, ctx);
+	return port_register(ctx);
 }
 
 static int
-pipe_slave(int fd, struct TestContext *ctx)
+pipe_slave(struct TestContext *ctx)
 {
 	char pipe_name[128];
 
@@ -452,12 +453,12 @@ pipe_slave(int fd, struct TestContext *ctx)
 	ctx->ifname  = pipe_name;
 	ctx->nr_mode = NR_REG_ALL_NIC;
 
-	return port_register(fd, ctx);
+	return port_register(ctx);
 }
 
 /* NETMAP_REQ_VALE_POLLING_ENABLE */
 static int
-vale_polling_enable(int fd, struct TestContext *ctx)
+vale_polling_enable(struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
 	struct nmreq_header hdr;
@@ -474,7 +475,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 	req.nr_mode             = ctx->nr_mode;
 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
-	ret                     = ioctl(fd, NIOCCTRL, &hdr);
+	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
 		return ret;
@@ -489,7 +490,7 @@ vale_polling_enable(int fd, struct TestContext *ctx)
 
 /* NETMAP_REQ_VALE_POLLING_DISABLE */
 static int
-vale_polling_disable(int fd, struct TestContext *ctx)
+vale_polling_disable(struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
 	struct nmreq_header hdr;
@@ -503,7 +504,7 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
-	ret = ioctl(fd, NIOCCTRL, &hdr);
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
 		return ret;
@@ -513,28 +514,28 @@ vale_polling_disable(int fd, struct TestContext *ctx)
 }
 
 static int
-vale_polling_enable_disable(int fd, struct TestContext *ctx)
+vale_polling_enable_disable(struct TestContext *ctx)
 {
 	int ret = 0;
 
-	if ((ret = vale_attach(fd, ctx))) {
+	if ((ret = vale_attach(ctx))) {
 		return ret;
 	}
 
 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
 	ctx->nr_num_polling_cpus = 1;
 	ctx->nr_first_cpu_id     = 0;
-	if ((ret = vale_polling_enable(fd, ctx))) {
-		vale_detach(fd, ctx);
+	if ((ret = vale_polling_enable(ctx))) {
+		vale_detach(ctx);
 		return ret;
 	}
 
-	if ((ret = vale_polling_disable(fd, ctx))) {
-		vale_detach(fd, ctx);
+	if ((ret = vale_polling_disable(ctx))) {
+		vale_detach(ctx);
 		return ret;
 	}
 
-	return vale_detach(fd, ctx);
+	return vale_detach(ctx);
 }
 
 static void
@@ -573,7 +574,7 @@ checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
 }
 
 static int
-unsupported_option(int fd, struct TestContext *ctx)
+unsupported_option(struct TestContext *ctx)
 {
 	struct nmreq_option opt, save;
 
@@ -584,7 +585,7 @@ unsupported_option(int fd, struct TestContext *ctx)
 	push_option(&opt, ctx);
 	save = opt;
 
-	if (port_register_hwall(fd, ctx) >= 0)
+	if (port_register_hwall(ctx) >= 0)
 		return -1;
 
 	clear_options(ctx);
@@ -593,7 +594,7 @@ unsupported_option(int fd, struct TestContext *ctx)
 }
 
 static int
-infinite_options(int fd, struct TestContext *ctx)
+infinite_options(struct TestContext *ctx)
 {
 	struct nmreq_option opt, save;
 
@@ -603,7 +604,7 @@ infinite_options(int fd, struct TestContext *ctx)
 	push_option(&opt, ctx);
 	opt.nro_next = (uintptr_t)&opt;
 	save         = opt;
-	if (port_register_hwall(fd, ctx) >= 0)
+	if (port_register_hwall(ctx) >= 0)
 		return -1;
 
 	clear_options(ctx);
@@ -700,7 +701,7 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 }
 
 static int
-_extmem_option(int fd, struct TestContext *ctx, int new_rsz)
+_extmem_option(struct TestContext *ctx, int new_rsz)
 {
 	struct nmreq_opt_extmem e, save;
 	int ret;
@@ -718,7 +719,7 @@ _extmem_option(int fd, struct TestContext *ctx, int new_rsz)
 	if ((ret = change_param("priv_ring_size", new_rsz, &old_rsz)))
 		return ret;
 
-	if ((ret = port_register_hwall(fd, ctx)))
+	if ((ret = port_register_hwall(ctx)))
 		return ret;
 
 	ret = pop_extmem_option(ctx, &save);
@@ -730,23 +731,23 @@ _extmem_option(int fd, struct TestContext *ctx, int new_rsz)
 }
 
 static int
-extmem_option(int fd, struct TestContext *ctx)
+extmem_option(struct TestContext *ctx)
 {
 	printf("Testing extmem option on vale0:0\n");
 
-	return _extmem_option(fd, ctx, 512);
+	return _extmem_option(ctx, 512);
 }
 
 static int
-bad_extmem_option(int fd, struct TestContext *ctx)
+bad_extmem_option(struct TestContext *ctx)
 {
 	printf("Testing bad extmem option on vale0:0\n");
 
-	return _extmem_option(fd, ctx, (1 << 16)) < 0 ? 0 : -1;
+	return _extmem_option(ctx, (1 << 16)) < 0 ? 0 : -1;
 }
 
 static int
-duplicate_extmem_options(int fd, struct TestContext *ctx)
+duplicate_extmem_options(struct TestContext *ctx)
 {
 	struct nmreq_opt_extmem e1, save1, e2, save2;
 	int ret;
@@ -764,7 +765,7 @@ duplicate_extmem_options(int fd, struct TestContext *ctx)
 	save1 = e1;
 	save2 = e2;
 
-	ret = port_register_hwall(fd, ctx);
+	ret = port_register_hwall(ctx);
 	if (ret >= 0) {
 		printf("duplicate option not detected\n");
 		return -1;
@@ -890,7 +891,8 @@ main(int argc, char **argv)
 			goto out;
 		}
 		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
-		ret = tests[i].test(fd, &ctxcopy);
+		ctxcopy.fd = fd;
+		ret = tests[i].test(&ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 			goto out;

From ed07d7d8c4ebb9eed59f2ede183d0a81b0c14a99 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 12:30:53 +0200
Subject: [PATCH 1064/2207] utils: ctrl-api-test: run all the tests (last one
 included)

The last test (infinite options) was never run. And it fails.
---
 utils/ctrl-api-test.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8e57c4886..a3d8c1614 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -609,7 +609,13 @@ infinite_options(struct TestContext *ctx)
 
 	clear_options(ctx);
 	save.nro_status = EOPNOTSUPP;
+#if 0
 	return checkoption(&opt, &save);
+#else
+	/* TODO the checkoption above fails */
+	(void)save;
+	return 0;
+#endif
 }
 
 #ifdef CONFIG_NETMAP_EXTMEM
@@ -826,10 +832,11 @@ int
 main(int argc, char **argv)
 {
 	struct TestContext ctx;
-	unsigned int i;
 	int loopback_if;
+	int num_tests;
 	int ret = 0;
 	int j   = -1;
+	int i;
 	int opt;
 
 	memset(&ctx, 0, sizeof(ctx));
@@ -869,18 +876,20 @@ main(int argc, char **argv)
 		}
 	}
 
+	num_tests = sizeof(tests) / sizeof(tests[0]);
+
 	if (j >= 0) {
 		j--; /* one-based --> zero-based */
-		if (j >= (int)(sizeof(tests) / sizeof(tests[0]))) {
+		if (j >= num_tests) {
 			printf("Error: Test not in range\n");
 			ret = -1;
 			goto out;
 		}
 	}
-	for (i = 0; i < sizeof(tests) / sizeof(tests[0]) - 1; i++) {
+	for (i = 0; i < num_tests; i++) {
 		struct TestContext ctxcopy;
 		int fd;
-		if (j >= 0 && (unsigned)j != i) {
+		if (j >= 0 && j != i) {
 			continue;
 		}
 		printf("==> Start of Test #%d -- %s\n", i + 1, tests[i].name);

From c45b16b4de7f519533f3d21b0a842ea6cdb9ae70 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 12:53:07 +0200
Subject: [PATCH 1065/2207] utils: ctrl-api-test: port_register: write back
 info to TextContext

---
 utils/ctrl-api-test.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a3d8c1614..720be8ae8 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -94,6 +94,7 @@ port_register(struct TestContext *ctx)
 {
 	struct nmreq_register req;
 	struct nmreq_header hdr;
+	int success;
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
@@ -128,7 +129,7 @@ port_register(struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
-	return req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
+	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
 	                       (ctx->nr_ringid == req.nr_ringid) &&
 	                       (ctx->nr_flags == req.nr_flags) &&
 	                       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
@@ -141,9 +142,20 @@ port_register(struct TestContext *ctx)
 	                        (ctx->nr_rx_rings == req.nr_rx_rings)) &&
 	                       ((!ctx->nr_mem_id && req.nr_mem_id) ||
 	                        (ctx->nr_mem_id == req.nr_mem_id)) &&
-	                       (ctx->nr_extra_bufs == req.nr_extra_bufs)
-	               ? 0
-	               : -1;
+	                       (ctx->nr_extra_bufs == req.nr_extra_bufs);
+	if (!success) {
+		return -1;
+	}
+
+	/* Write back results to the context structure.*/
+	ctx->nr_tx_slots = req.nr_tx_slots;
+	ctx->nr_rx_slots = req.nr_rx_slots;
+	ctx->nr_tx_rings = req.nr_tx_rings;
+	ctx->nr_rx_rings = req.nr_rx_rings;
+	ctx->nr_mem_id = req.nr_mem_id;
+	ctx->nr_extra_bufs = req.nr_extra_bufs;
+
+	return -0;
 }
 
 static int

From a543102d217f25a31670b6779888a2ba822b6a63 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 16:07:39 +0200
Subject: [PATCH 1066/2207] Revert "configure: let build-utils/ be a symlink to
 utils/"

This reverts commit 4fe80fc08b35600763257d4c51fdf391ff3fadb5.
---
 LINUX/configure | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 903a95994..2c1e17921 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1987,7 +1987,8 @@ done
 
 # create the build directory for the utils
 if [ -n "$UTILS" ]; then
-	ln -s $SRCDIR/../utils/ build-utils 2>/dev/null || true
+	mkdir -p build-utils
+	ln -s $SRCDIR/../utils/GNUmakefile build-utils/GNUmakefile 2>/dev/null || true
 fi
 
 # config.status can be used to rerun configure with the

From f2a9381bfa45b615a86aa47366ac30dc801048e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 16:10:20 +0200
Subject: [PATCH 1067/2207] utils: functional: use execlp() rather than execl()

This is needed to search for "fd_server" in $PATH
---
 utils/functional.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/functional.c b/utils/functional.c
index 7a2085f28..efc753900 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -911,7 +911,7 @@ start_fd_server(struct Global *g)
 		return;
 	}
 
-	if (execl("fd_server", "fd_server", (char *)NULL)) {
+	if (execlp("fd_server", "fd_server", (char *)NULL)) {
 		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "exec()");
 		exit(EXIT_FAILURE);
 	}

From 7fc697724286e94bfa08ca236541320cfb84e853 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 16:16:41 +0200
Subject: [PATCH 1068/2207] utils: randomized_test: add build-utils to the PATH
 variable

---
 utils/randomized_tests | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index c7d41df9d..2d51c8ddb 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -32,10 +32,10 @@ echo ""
 pushd $(pwd)
 cd $(dirname $0)
 
-# Add the current directory to the PATH. In this way we can easily invoke
-# functional, get_tx_rings_avail_sends and get_tx_rings_max_sends from the test
-# scripts.
-PATH="$(pwd):${PATH}"
+# Add the current directory (and build-utils) to the PATH. In this way we can
+# easily invoke functional, get_tx_rings_avail_sends and the other executables
+# from the test scripts.
+PATH="$(pwd)/../build-utils:$(pwd):${PATH}"
 
 source test_lib
 

From 620cff3859e6c71d5096d35f1c7fba72b5cf3dcf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 16:23:56 +0200
Subject: [PATCH 1069/2207] Makefile: add "unitest" target to run unit tests

---
 LINUX/netmap.mak.in      | 3 +++
 ci/run-integration-tests | 9 +--------
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 8722f9912..b11f41fb7 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -136,6 +136,7 @@ utils:
 install-utils:
 clean-utils:
 intest:
+unitest:
 else
 .PHONY: utils
 utils:
@@ -149,6 +150,8 @@ clean-utils:
 
 intest: utils
 	utils/randomized_tests
+unitest: utils
+	build-utils/ctrl-api-test
 endif
 
 INCLUDE_PREFIX := $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)
diff --git a/ci/run-integration-tests b/ci/run-integration-tests
index 5a6fce325..e2ddf0e59 100755
--- a/ci/run-integration-tests
+++ b/ci/run-integration-tests
@@ -1,14 +1,7 @@
 #!/bin/bash -eu
 
 sudo modprobe netmap
-
-# Run control API tests
-pushd .
-cd utils
-make
-sudo ./ctrl-api-test
-popd
-
+sudo make unitest
 sudo rmmod netmap
 
 # Run integration tests

From 5b4278f5f460139e6d8a8117c71d0f322952bf93 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Sep 2018 10:04:03 +0200
Subject: [PATCH 1070/2207] Makefile: do not install the utils

---
 LINUX/netmap.mak.in | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index b11f41fb7..6f11adf71 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -143,7 +143,8 @@ utils:
 	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)" SUBSYS_FLAGS="$(SUBSYS_FLAGS)"
 
 install-utils:
-	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
+# Do not install the utils, because they are only used for testing.
+#	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
 
 clean-utils:
 	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/..

From 535fe2432e4c1b34d4ca6cc5a83fdf21a4843c14 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Sep 2018 10:27:44 +0200
Subject: [PATCH 1071/2207] Makefile: re-enable install-utils target

---
 LINUX/netmap.mak.in | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 6f11adf71..762cfe10b 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -89,7 +89,7 @@ $(foreach d,$(S_DRIVERS),$(eval $(call common_driver,$(d))))
 $(foreach d,$(E_DRIVERS),$(eval $(call external_driver,$(d))))
 
 .PHONY: install install-netmap install-apps install-headers install-docs
-install: install-netmap $(E_DRIVERS:%=install-%) install-apps install-headers install-docs install-utils
+install: install-netmap $(E_DRIVERS:%=install-%) install-apps install-headers install-docs
 
 install-netmap:
 	$(MAKE) -C $(KSRC) M=$(BUILDDIR) CONFIG_NETMAP=m $(MOD_LIST) \
@@ -143,8 +143,7 @@ utils:
 	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)" SUBSYS_FLAGS="$(SUBSYS_FLAGS)"
 
 install-utils:
-# Do not install the utils, because they are only used for testing.
-#	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
+	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
 
 clean-utils:
 	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/..

From 3c05ed1b63eb5396d59fff451c3568ec54b7aa94 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 25 Sep 2018 10:43:34 +0200
Subject: [PATCH 1072/2207] ctrl-api-test: check the expected error in the
 infinite_options test

---
 utils/ctrl-api-test.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 720be8ae8..85042426a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -608,26 +608,17 @@ unsupported_option(struct TestContext *ctx)
 static int
 infinite_options(struct TestContext *ctx)
 {
-	struct nmreq_option opt, save;
+	struct nmreq_option opt;
 
 	printf("Testing infinite list of options on %s\n", ctx->ifname);
 
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
 	opt.nro_next = (uintptr_t)&opt;
-	save         = opt;
 	if (port_register_hwall(ctx) >= 0)
 		return -1;
-
 	clear_options(ctx);
-	save.nro_status = EOPNOTSUPP;
-#if 0
-	return checkoption(&opt, &save);
-#else
-	/* TODO the checkoption above fails */
-	(void)save;
-	return 0;
-#endif
+	return (errno == EMSGSIZE ? 0 : -1);
 }
 
 #ifdef CONFIG_NETMAP_EXTMEM

From e9d0ea9c85e22d547b694e9a19beafeec5cd519a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 25 Sep 2018 11:08:49 +0200
Subject: [PATCH 1073/2207] tlem: fix indentation

---
 apps/tlem/tlem.c | 1378 +++++++++++++++++++++++-----------------------
 1 file changed, 689 insertions(+), 689 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 7b4b6a956..2e906de93 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -163,12 +163,12 @@ static int do_abort = 0;
 #define cpuset_t        uint64_t        // XXX
 static inline void CPU_ZERO(cpuset_t *p)
 {
-	*p = 0;
+    *p = 0;
 }
 
 static inline void CPU_SET(uint32_t i, cpuset_t *p)
 {
-	*p |= 1<< (i & 0x3f);
+    *p |= 1<< (i & 0x3f);
 }
 
 #define pthread_setaffinity_np(a, b, c) ((void)a, 0)
@@ -394,30 +394,30 @@ struct pipe_args {
 static int
 setaffinity(int i)
 {
-	cpuset_t cpumask;
-	struct sched_param p;
-	int error;
-
-	if (i == -1)
-		return 0;
-
-	/* Set thread affinity affinity.*/
-	CPU_ZERO(&cpumask);
-	CPU_SET(i, &cpumask);
-
-	if ( (error = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t), &cpumask)) != 0) {
-		ED("Unable to set affinity to cpu %d: %s", i, strerror(error));
-	}
-	if (setpriority(PRIO_PROCESS, 0, -10)) {; // XXX not meaningful
-		ED("Unable to set priority: %s", strerror(errno));
-	}
-	bzero(&p, sizeof(p));
-	p.sched_priority = 10; // 99 on linux ?
-	// use SCHED_RR or SCHED_FIFO
-	if (sched_setscheduler(0, SCHED_RR, &p)) {
-		ED("Unable to set scheduler: %s", strerror(errno));
-	}
-	return 0;
+    cpuset_t cpumask;
+    struct sched_param p;
+    int error;
+
+    if (i == -1)
+        return 0;
+
+    /* Set thread affinity affinity.*/
+    CPU_ZERO(&cpumask);
+    CPU_SET(i, &cpumask);
+
+    if ( (error = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t), &cpumask)) != 0) {
+        ED("Unable to set affinity to cpu %d: %s", i, strerror(error));
+    }
+    if (setpriority(PRIO_PROCESS, 0, -10)) {; // XXX not meaningful
+        ED("Unable to set priority: %s", strerror(errno));
+    }
+    bzero(&p, sizeof(p));
+    p.sched_priority = 10; // 99 on linux ?
+    // use SCHED_RR or SCHED_FIFO
+    if (sched_setscheduler(0, SCHED_RR, &p)) {
+        ED("Unable to set scheduler: %s", strerror(errno));
+    }
+    return 0;
 }
 
 
@@ -434,14 +434,14 @@ set_tns_now(uint64_t *now, uint64_t t0)
 
 static inline int pad(int x)
 {
-	return ((x) + PKT_PAD - 1) & ~(PKT_PAD - 1) ;
+    return ((x) + PKT_PAD - 1) & ~(PKT_PAD - 1) ;
 }
 
 /* compare two timestamps */
 static inline int64_t
 ts_cmp(uint64_t a, uint64_t b)
 {
-	return (int64_t)(a - b);
+    return (int64_t)(a - b);
 }
 
 /* create a packet descriptor */
@@ -459,17 +459,17 @@ pkt_at(struct _qs *q, uint64_t ofs)
 static int
 q_reclaim(struct _qs *q)
 {
-	struct q_pkt *p0, *p;
-
-	p = p0 = pkt_at(q, q->prod_tail_1);
-	/* always reclaim queued packets */
-	while (ts_cmp(p->pt_qout, q->prod_now) <= 0 && q->prod_queued > 0) {
-	    ND(1, "reclaim pkt at %ld len %d left %ld", q->prod_tail_1, p->pktlen, q->prod_queued);
-	    q->prod_queued -= p->pktlen;
-	    q->prod_tail_1 = p->next;
-	    p = pkt_at(q, q->prod_tail_1);
-	}
-	return p != p0;
+    struct q_pkt *p0, *p;
+
+    p = p0 = pkt_at(q, q->prod_tail_1);
+    /* always reclaim queued packets */
+    while (ts_cmp(p->pt_qout, q->prod_now) <= 0 && q->prod_queued > 0) {
+        ND(1, "reclaim pkt at %ld len %d left %ld", q->prod_tail_1, p->pktlen, q->prod_queued);
+        q->prod_queued -= p->pktlen;
+        q->prod_tail_1 = p->next;
+        p = pkt_at(q, q->prod_tail_1);
+    }
+    return p != p0;
 }
 
 /*
@@ -504,29 +504,29 @@ no_room(struct _qs *q)
     uint64_t new_t = t + need;
 
     if (q->buflen - new_t < MAX_PKT + sizeof(*p))
-	new_t = 0; /* further padding */
+        new_t = 0; /* further padding */
 
     /* XXX let the queue overflow once, otherwise it is complex
      * to deal with 0-sized queues
      */
     if (q->prod_queued > q->qsize) {
-	q_reclaim(q);
-	if (q->prod_queued > q->qsize) {
-	    q->prod_drop++;
-	    RD(1, "too many bytes queued %llu, drop %llu",
-		(unsigned long long)q->prod_queued, (unsigned long long)q->prod_drop);
-	    return 1;
-	}
+        q_reclaim(q);
+        if (q->prod_queued > q->qsize) {
+            q->prod_drop++;
+            RD(1, "too many bytes queued %llu, drop %llu",
+                    (unsigned long long)q->prod_queued, (unsigned long long)q->prod_drop);
+            return 1;
+        }
     }
 
     if ((h <= t && new_t == 0 && h == 0) || (h > t && (new_t == 0 || new_t >= h)) ) {
-	h = q->prod_head = q->head; /* re-read head, just in case */
-	/* repeat the test */
-	if ((h <= t && new_t == 0 && h == 0) || (h > t && (new_t == 0 || new_t >= h)) ) {
-	    ND(1, "no room for insert h %lld t %lld new_t %lld",
-		(long long)h, (long long)t, (long long)new_t);
-	    return 1; /* no room for insert */
-	}
+        h = q->prod_head = q->head; /* re-read head, just in case */
+        /* repeat the test */
+        if ((h <= t && new_t == 0 && h == 0) || (h > t && (new_t == 0 || new_t >= h)) ) {
+            ND(1, "no room for insert h %lld t %lld new_t %lld",
+                    (long long)h, (long long)t, (long long)new_t);
+            return 1; /* no room for insert */
+        }
     }
     p->next = new_t; /* prepare for queueing */
     p->pktlen = 0;
@@ -548,12 +548,12 @@ enq(struct _qs *q)
     p->pt_qout = q->qt_qout;
     p->pt_tx = q->qt_tx;
     ND(1, "enqueue len %d at %d new tail %ld qout %ld tx %ld",
-	q->cur_len, (int)q->prod_tail, p->next,
-	p->pt_qout, p->pt_tx);
+            q->cur_len, (int)q->prod_tail, p->next,
+            p->pt_qout, p->pt_tx);
     q->prod_tail = p->next;
     q->tx++;
     if (q->max_bps)
-	q->prod_queued += p->pktlen;
+        q->prod_queued += p->pktlen;
     /* XXX update timestamps ? */
     return 0;
 }
@@ -564,11 +564,11 @@ rx_queued(struct nm_desc *d)
 {
     u_int tot = 0, i;
     for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
-	struct netmap_ring *rxr = NETMAP_RXRING(d->nifp, i);
+        struct netmap_ring *rxr = NETMAP_RXRING(d->nifp, i);
 
-	ND(5, "ring %d h %d cur %d tail %d", i,
-		rxr->head, rxr->cur, rxr->tail);
-	tot += nm_ring_space(rxr);
+        ND(5, "ring %d h %d cur %d tail %d", i,
+                rxr->head, rxr->cur, rxr->tail);
+        tot += nm_ring_space(rxr);
     }
     return tot;
 }
@@ -585,52 +585,52 @@ wait_for_packets(struct _qs *q)
     ioctl(q->src_port->fd, NIOCRXSYNC, 0); /* forced */
     while (!do_abort) {
 
-	n0 = rx_queued(q->src_port);
-	if (n0 > (int)q->rx_qmax) {
-	    q->rx_qmax = n0;
-	}
-	if (n0)
-	    break;
-	prev = 0; /* we slept */
-	if (1) {
-	    usleep(5);
-	    ioctl(q->src_port->fd, NIOCRXSYNC, 0);
-	} else {
-	    struct pollfd pfd;
-	    struct netmap_ring *rx;
-	    int ret;
-
-	    pfd.fd = q->src_port->fd;
-	    pfd.revents = 0;
-	    pfd.events = POLLIN;
-	    ND(1, "prepare for poll on %s", q->prod_ifname);
-	    ret = poll(&pfd, 1, 10000);
-	    if (ret <= 0 || verbose) {
-		D("poll %s ev %x %x rx %d@%d",
-		    ret <= 0 ? "timeout" : "ok",
-		    pfd.events,
-		    pfd.revents,
-		    rx_queued(q->src_port),
-		    NETMAP_RXRING(q->src_port->nifp, q->src_port->first_rx_ring)->cur
-		);
-	    }
-	    if (pfd.revents & POLLERR) {
-		rx = NETMAP_RXRING(q->src_port->nifp, q->src_port->first_rx_ring);
-		D("error on fd0, rx [%d,%d,%d)",
-		    rx->head, rx->cur, rx->tail);
-		sleep(1);
-	    }
-	}
+        n0 = rx_queued(q->src_port);
+        if (n0 > (int)q->rx_qmax) {
+            q->rx_qmax = n0;
+        }
+        if (n0)
+            break;
+        prev = 0; /* we slept */
+        if (1) {
+            usleep(5);
+            ioctl(q->src_port->fd, NIOCRXSYNC, 0);
+        } else {
+            struct pollfd pfd;
+            struct netmap_ring *rx;
+            int ret;
+
+            pfd.fd = q->src_port->fd;
+            pfd.revents = 0;
+            pfd.events = POLLIN;
+            ND(1, "prepare for poll on %s", q->prod_ifname);
+            ret = poll(&pfd, 1, 10000);
+            if (ret <= 0 || verbose) {
+                D("poll %s ev %x %x rx %d@%d",
+                        ret <= 0 ? "timeout" : "ok",
+                        pfd.events,
+                        pfd.revents,
+                        rx_queued(q->src_port),
+                        NETMAP_RXRING(q->src_port->nifp, q->src_port->first_rx_ring)->cur
+                 );
+            }
+            if (pfd.revents & POLLERR) {
+                rx = NETMAP_RXRING(q->src_port->nifp, q->src_port->first_rx_ring);
+                D("error on fd0, rx [%d,%d,%d)",
+                        rx->head, rx->cur, rx->tail);
+                sleep(1);
+            }
+        }
     }
     set_tns_now(&q->prod_now, q->t0);
     if (ts_cmp(q->qt_qout, q->prod_now) < 0) {
-	q->qt_qout = q->prod_now;
+        q->qt_qout = q->prod_now;
     }
     if (prev > 0 && (prev = q->prod_now - prev) > q->prod_max_gap) {
-	q->prod_max_gap = prev;
+        q->prod_max_gap = prev;
     }
     ND(10, "%s %d queued packets at %ld ms",
-	q->prod_ifname, n0, (q->prod_now/1000000) % 10000);
+            q->prod_ifname, n0, (q->prod_now/1000000) % 10000);
 }
 
 /*
@@ -646,12 +646,12 @@ prefetch_packet(struct netmap_ring *rxr, int pos)
     const char *buf;
 
     if (ofs >= rxr->num_slots)
-	return;
+        return;
     rs = &rxr->slot[ofs];
     buf = NETMAP_BUF(rxr, rs->buf_idx);
     l = rs->len;
     for (i = 0; i < l; i += 64)
-	__builtin_prefetch(buf + i);
+        __builtin_prefetch(buf + i);
 }
 
 /*
@@ -666,36 +666,36 @@ scan_ring(struct _qs *q, int next /* bool */)
 
     /* fast path for the first two */
     if (likely(next != 0)) { /* current ring */
-	ND(10, "scan next");
-	/* advance */
-	rxr->head = rxr->cur = nm_ring_next(rxr, rxr->cur);
-	if (!nm_ring_empty(rxr)) /* good one */
-	    goto got_one;
-	q->si++;	/* otherwise update and fallthrough */
+        ND(10, "scan next");
+        /* advance */
+        rxr->head = rxr->cur = nm_ring_next(rxr, rxr->cur);
+        if (!nm_ring_empty(rxr)) /* good one */
+            goto got_one;
+        q->si++;	/* otherwise update and fallthrough */
     } else { /* scan from beginning */
-	q->si = pa->first_rx_ring;
-	ND(10, "scanning first ring %d", q->si);
+        q->si = pa->first_rx_ring;
+        ND(10, "scanning first ring %d", q->si);
     }
     while (q->si <= pa->last_rx_ring) {
-	q->rxring = rxr = NETMAP_RXRING(pa->nifp, q->si);
-	if (!nm_ring_empty(rxr))
-	    break;
-	q->si++;
-	continue;
+        q->rxring = rxr = NETMAP_RXRING(pa->nifp, q->si);
+        if (!nm_ring_empty(rxr))
+            break;
+        q->si++;
+        continue;
     }
     if (q->si > pa->last_rx_ring) { /* no data, cur == tail */
-	ND(5, "no more pkts on %s", q->prod_ifname);
-	return;
+        ND(5, "no more pkts on %s", q->prod_ifname);
+        return;
     }
 got_one:
     rs = &rxr->slot[rxr->cur];
     if (unlikely(rs->buf_idx < 2)) {
-	D("wrong index rx[%d] = %d", rxr->cur, rs->buf_idx);
-	sleep(2);
+        D("wrong index rx[%d] = %d", rxr->cur, rs->buf_idx);
+        sleep(2);
     }
     if (unlikely(rs->len > MAX_PKT)) { // XXX
-	D("wrong len rx[%d] len %d", rxr->cur, rs->len);
-	rs->len = 0;
+        D("wrong len rx[%d] len %d", rxr->cur, rs->len);
+        rs->len = 0;
     }
     q->cur_pkt = NETMAP_BUF(rxr, rs->buf_idx);
     q->cur_len = rs->len;
@@ -720,8 +720,8 @@ null_run_fn(struct _qs *q, struct _cfg *cfg)
 static int
 drop_after(struct _qs *q)
 {
-	(void)q; // XXX
-	return 0;
+    (void)q; // XXX
+    return 0;
 }
 
 
@@ -736,42 +736,42 @@ prod(void *_pa)
     q->qt_qout = q->qt_tx = q->prod_now;
     ND("start times %ld", q->prod_now);
     while (!do_abort) { /* producer, infinite */
-	int count;
-
-	wait_for_packets(q);	/* also updates prod_now */
-	// XXX optimize to flush frequently
-	for (count = 0, scan_ring(q, 0); count < q->burst && !nm_ring_empty(q->rxring);
-		count++, scan_ring(q, 1)) {
-	    // transmission time
-	    uint64_t t_tx, tt;	/* output and transmission time */
-
-	    if (q->cur_len < 60) {
-		RD(5, "short packet len %d", q->cur_len);
-		continue; // short frame
-	    }
-	    q->c_loss.run(q, &q->c_loss);
-	    if (q->cur_drop)
-		continue;
-	    if (no_room(q)) {
-		q->tail = q->prod_tail; /* notify */
-		usleep(1); // XXX give cons a chance to run ?
-		if (no_room(q)) /* try to run drop-free once */
-		    continue;
-	    }
-	    // XXX possibly implement c_tt for transmission time emulation
-	    q->c_bw.run(q, &q->c_bw);
-	    tt = q->cur_tt;
-	    q->qt_qout += tt;
-	    if (drop_after(q))
-		continue;
-	    q->c_delay.run(q, &q->c_delay); /* compute delay */
-	    t_tx = q->qt_qout + q->cur_delay;
-	    ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
-	    /* insure no reordering and spacing by transmission time */
-	    q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt;
-	    enq(q);
-	}
-	q->tail = q->prod_tail; /* notify */
+        int count;
+
+        wait_for_packets(q);	/* also updates prod_now */
+        // XXX optimize to flush frequently
+        for (count = 0, scan_ring(q, 0); count < q->burst && !nm_ring_empty(q->rxring);
+                count++, scan_ring(q, 1)) {
+            // transmission time
+            uint64_t t_tx, tt;	/* output and transmission time */
+
+            if (q->cur_len < 60) {
+                RD(5, "short packet len %d", q->cur_len);
+                continue; // short frame
+            }
+            q->c_loss.run(q, &q->c_loss);
+            if (q->cur_drop)
+                continue;
+            if (no_room(q)) {
+                q->tail = q->prod_tail; /* notify */
+                usleep(1); // XXX give cons a chance to run ?
+                if (no_room(q)) /* try to run drop-free once */
+                    continue;
+            }
+            // XXX possibly implement c_tt for transmission time emulation
+            q->c_bw.run(q, &q->c_bw);
+            tt = q->cur_tt;
+            q->qt_qout += tt;
+            if (drop_after(q))
+                continue;
+            q->c_delay.run(q, &q->c_delay); /* compute delay */
+            t_tx = q->qt_qout + q->cur_delay;
+            ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
+            /* insure no reordering and spacing by transmission time */
+            q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt;
+            enq(q);
+        }
+        q->tail = q->prod_tail; /* notify */
     }
     D("exiting on abort");
     return NULL;
@@ -800,53 +800,53 @@ cons(void *_pa)
     (void)cycles; // XXX disable warning
     set_tns_now(&q->cons_now, q->t0);
     while (!do_abort) { /* consumer, infinite */
-	struct q_pkt *p = (struct q_pkt *)(q->buf + q->head);
-	if (p->next < q->head) { /* wrap around prefetch */
-	    pre_start = q->buf + p->next;
-	}
-	pre_end = q->buf + p->next + 2048;
+        struct q_pkt *p = (struct q_pkt *)(q->buf + q->head);
+        if (p->next < q->head) { /* wrap around prefetch */
+            pre_start = q->buf + p->next;
+        }
+        pre_end = q->buf + p->next + 2048;
 #if 1
-	/* prefetch the first line saves 4ns */
-	(void)pre_end;//   __builtin_prefetch(pre_end - 2048);
+        /* prefetch the first line saves 4ns */
+        (void)pre_end;//   __builtin_prefetch(pre_end - 2048);
 #else
-	/* prefetch, ideally up to a full packet not just one line.
-	 * this does not seem to have a huge effect.
-	 * 4ns out of 198 on 1500 byte packets
-	 */
-	for (; pre_start < pre_end; pre_start += 64)
-	    __builtin_prefetch(pre_start);
+        /* prefetch, ideally up to a full packet not just one line.
+         * this does not seem to have a huge effect.
+         * 4ns out of 198 on 1500 byte packets
+         */
+        for (; pre_start < pre_end; pre_start += 64)
+            __builtin_prefetch(pre_start);
 #endif
 
-	if (q->head == q->tail || ts_cmp(p->pt_tx, q->cons_now) > 0) {
-	    ND(4, "                 >>>> TXSYNC, pkt not ready yet h %ld t %ld now %ld tx %ld",
-		q->head, q->tail, q->cons_now, p->pt_tx);
-	    q->rx_wait++;
-	    ioctl(pa->pb->fd, NIOCTXSYNC, 0); // XXX just in case
-	    pending = 0;
-	    usleep(5);
-	    set_tns_now(&q->cons_now, q->t0);
-	    continue;
-	}
-	ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
-		p->pktlen, q->cons_now, p->pt_tx, q->head, q->tail, p->next);
-	/* XXX inefficient but simple */
-	if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
-	    ND(5, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
-		(int)p->pktlen, q->cons_now, p->pt_tx, q->head, q->tail, p->next);
-	    ioctl(pa->pb->fd, NIOCTXSYNC, 0);
-	    pending = 0;
-	    continue;
-	}
-	pending++;
-	if (pending > q->burst) {
-	    ioctl(pa->pb->fd, NIOCTXSYNC, 0);
-	    pending = 0;
-	}
-
-	q->head = p->next;
-	/* drain packets from the queue */
-	q->rx++;
-	// XXX barrier
+        if (q->head == q->tail || ts_cmp(p->pt_tx, q->cons_now) > 0) {
+            ND(4, "                 >>>> TXSYNC, pkt not ready yet h %ld t %ld now %ld tx %ld",
+                    q->head, q->tail, q->cons_now, p->pt_tx);
+            q->rx_wait++;
+            ioctl(pa->pb->fd, NIOCTXSYNC, 0); // XXX just in case
+            pending = 0;
+            usleep(5);
+            set_tns_now(&q->cons_now, q->t0);
+            continue;
+        }
+        ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
+                p->pktlen, q->cons_now, p->pt_tx, q->head, q->tail, p->next);
+        /* XXX inefficient but simple */
+        if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
+            ND(5, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
+                    (int)p->pktlen, q->cons_now, p->pt_tx, q->head, q->tail, p->next);
+            ioctl(pa->pb->fd, NIOCTXSYNC, 0);
+            pending = 0;
+            continue;
+        }
+        pending++;
+        if (pending > q->burst) {
+            ioctl(pa->pb->fd, NIOCTXSYNC, 0);
+            pending = 0;
+        }
+
+        q->head = p->next;
+        /* drain packets from the queue */
+        q->rx++;
+        // XXX barrier
     }
     D("exiting on abort");
     return NULL;
@@ -870,15 +870,15 @@ tlem_main(void *_a)
 
     a->pa = nm_open(q->prod_ifname, NULL, NETMAP_NO_TX_POLL, NULL);
     if (a->pa == NULL) {
-	ED("cannot open %s", q->prod_ifname);
-	return NULL;
+        ED("cannot open %s", q->prod_ifname);
+        return NULL;
     }
     // XXX use a single mmap ?
     a->pb = nm_open(q->cons_ifname, NULL, NM_OPEN_NO_MMAP, a->pa);
     if (a->pb == NULL) {
-	ED("cannot open %s", q->cons_ifname);
-	nm_close(a->pa);
-	return NULL;
+        ED("cannot open %s", q->cons_ifname);
+        nm_close(a->pa);
+        return NULL;
     }
     a->zerocopy = a->zerocopy && (a->pa->mem == a->pb->mem);
     ND("------- zerocopy %ssupported", a->zerocopy ? "" : "NOT ");
@@ -906,17 +906,17 @@ tlem_main(void *_a)
 
     q->buf = calloc(1, need);
     if (q->buf == NULL) {
-	ED("alloc %lld bytes for queue failed, exiting", (long long)need);
-	nm_close(a->pa);
-	nm_close(a->pb);
-	return(NULL);
+        ED("alloc %lld bytes for queue failed, exiting", (long long)need);
+        nm_close(a->pa);
+        nm_close(a->pb);
+        return(NULL);
     }
     q->buflen = need;
     ED("----\n\t%s -> %s :  bps %lld delay %s loss %s queue %lld bytes"
-	"\n\tbuffer %llu bytes",
-	q->prod_ifname, q->cons_ifname,
-	(long long)q->max_bps, q->c_delay.optarg, q->c_loss.optarg,
-	(long long)q->qsize, (unsigned long long)q->buflen);
+            "\n\tbuffer %llu bytes",
+            q->prod_ifname, q->cons_ifname,
+            (long long)q->max_bps, q->c_delay.optarg, q->c_loss.optarg,
+            (long long)q->qsize, (unsigned long long)q->buflen);
 
     q->src_port = a->pa;
 
@@ -932,9 +932,9 @@ tlem_main(void *_a)
 static void
 sigint_h(int sig)
 {
-	(void)sig;	/* UNUSED */
-	do_abort = 1;
-	signal(SIGINT, SIG_DFL);
+    (void)sig;	/* UNUSED */
+    do_abort = 1;
+    signal(SIGINT, SIG_DFL);
 }
 
 
@@ -942,10 +942,10 @@ sigint_h(int sig)
 static void
 usage(void)
 {
-	fprintf(stderr,
-	    "usage: tlem [-v] [-D delay] [-B bps] [-L loss] [-Q qsize] \n"
-	    "\t[-b burst] [-w wait_time] -i ifa -i ifb\n");
-	exit(1);
+    fprintf(stderr,
+            "usage: tlem [-v] [-D delay] [-B bps] [-L loss] [-Q qsize] \n"
+            "\t[-b burst] [-w wait_time] -i ifa -i ifb\n");
+    exit(1);
 }
 
 
@@ -962,38 +962,38 @@ split_arg(const char *src, int *_ac)
     int l, i, ac; /* number of entries */
 
     if (!src)
-	return NULL;
+        return NULL;
     l = strlen(src);
     /* in the first pass we count fields, in the second pass
      * we allocate the av[] array and a copy of the string
      * and fill av[]. av[ac] = NULL, av[ac+1]
      */
     for (;;) {
-	i = ac = 0;
-	ND("start pass %d: <%s>", av ? 1 : 0, my);
-	while (i < l) {
-	    /* trim leading separator */
-	    while (i = l)
-		break;
-	    ND("   pass %d arg %d: <%s>", av ? 1 : 0, ac, src+i);
-	    if (av) /* in the second pass, set the result */
-		av[ac] = my+i;
-	    ac++;
-	    /* skip string */
-	    while (i ", av ? 1 : 0, my);
+        while (i < l) {
+            /* trim leading separator */
+            while (i = l)
+                break;
+            ND("   pass %d arg %d: <%s>", av ? 1 : 0, ac, src+i);
+            if (av) /* in the second pass, set the result */
+                av[ac] = my+i;
+            ac++;
+            /* skip string */
+            while (i \n", i, av[i]);
     av[i++] = NULL;
@@ -1010,42 +1010,42 @@ split_arg(const char *src, int *_ac)
 static int
 cmd_apply(const struct _cfg *a, const char *arg, struct _qs *q, struct _cfg *dst)
 {
-	int ac = 0;
-	char **av;
-	int i;
-
-	if (arg == NULL || *arg == '\0')
-		return 1; /* no argument may be ok */
-	if (a == NULL || dst == NULL) {
-		ED("program error - invalid arguments");
-		exit(1);
-	}
-	av = split_arg(arg, &ac);
-	if (av == NULL)
-		return 1; /* error */
-	for (i = 0; a[i].parse; i++) {
-		struct _cfg x = a[i];
-		const char *errmsg = x.optarg;
-		int ret;
-
-		x.arg = NULL;
-		x.arg_len = 0;
-		bzero(&x.d, sizeof(x.d));
-		ret = x.parse(q, &x, ac, av);
-		if (ret == 2) /* not recognised */
-			continue;
-		if (ret == 1) {
-			ED("invalid arguments: need '%s' have '%s'",
-				errmsg, arg);
-			break;
-		}
-		x.optarg = arg;
-		*dst = x;
-		return 0;
-	}
-	ED("arguments %s not recognised", arg);
-	free(av);
-	return 1;
+    int ac = 0;
+    char **av;
+    int i;
+
+    if (arg == NULL || *arg == '\0')
+        return 1; /* no argument may be ok */
+    if (a == NULL || dst == NULL) {
+        ED("program error - invalid arguments");
+        exit(1);
+    }
+    av = split_arg(arg, &ac);
+    if (av == NULL)
+        return 1; /* error */
+    for (i = 0; a[i].parse; i++) {
+        struct _cfg x = a[i];
+        const char *errmsg = x.optarg;
+        int ret;
+
+        x.arg = NULL;
+        x.arg_len = 0;
+        bzero(&x.d, sizeof(x.d));
+        ret = x.parse(q, &x, ac, av);
+        if (ret == 2) /* not recognised */
+            continue;
+        if (ret == 1) {
+            ED("invalid arguments: need '%s' have '%s'",
+                    errmsg, arg);
+            break;
+        }
+        x.optarg = arg;
+        *dst = x;
+        return 0;
+    }
+    ED("arguments %s not recognised", arg);
+    free(av);
+    return 1;
 }
 
 static struct _cfg delay_cfg[];
@@ -1064,219 +1064,219 @@ static uint64_t parse_qsize(const char *arg);
 static void
 add_to(const char ** v, int l, const char *arg, const char *msg)
 {
-	for (; l > 0 && *v != NULL ; l--, v++);
-	if (l == 0) {
-		ED("%s %s", msg, arg);
-		exit(1);
-	}
-	*v = arg;
+    for (; l > 0 && *v != NULL ; l--, v++);
+    if (l == 0) {
+        ED("%s %s", msg, arg);
+        exit(1);
+    }
+    *v = arg;
 }
 
 int
 main(int argc, char **argv)
 {
-	int ch, i, err=0;
+    int ch, i, err=0;
 
 #define	N_OPTS	2
-	struct pipe_args bp[N_OPTS];
-	const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS];
-	int cores[4] = { 2, 8, 4, 10 }; /* default values */
-
-	bzero(d, sizeof(d));
-	bzero(b, sizeof(b));
-	bzero(l, sizeof(l));
-	bzero(q, sizeof(q));
-	bzero(ifname, sizeof(ifname));
-
-	fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
-
-	bzero(&bp, sizeof(bp));	/* all data initially go here */
-
-	for (i = 0; i < N_OPTS; i++) {
-	    struct _qs *q = &bp[i].q;
-	    q->c_delay.optarg = "0";
-	    q->c_delay.run = null_run_fn;
-	    q->c_loss.optarg = "0";
-	    q->c_loss.run = null_run_fn;
-	    q->c_bw.optarg = "0";
-	    q->c_bw.run = null_run_fn;
-	}
-
-	// Options:
-	// B	bandwidth in bps
-	// D	delay in seconds
-	// Q	qsize in bytes
-	// L	loss probability
-	// i	interface name (two mandatory)
-	// v	verbose
-	// b	batch size
-
-	while ( (ch = getopt(argc, argv, "B:C:D:L:Q:b:ci:vw:")) != -1) {
-		switch (ch) {
-		default:
-			D("bad option %c %s", ch, optarg);
-			usage();
-			break;
-
-		case 'C': /* CPU placement, up to 4 arguments */
-			{
-				int ac = 0;
-				char **av = split_arg(optarg, &ac);
-				if (ac == 1) { /* sequential after the first */
-					cores[0] = atoi(av[0]);
-					cores[1] = cores[0] + 1;
-					cores[2] = cores[1] + 1;
-					cores[3] = cores[2] + 1;
-				} else if (ac == 2) { /* two sequential pairs */
-					cores[0] = atoi(av[0]);
-					cores[1] = cores[0] + 1;
-					cores[2] = atoi(av[1]);
-					cores[3] = cores[2] + 1;
-				} else if (ac == 4) { /* four values */
-					cores[0] = atoi(av[0]);
-					cores[1] = atoi(av[1]);
-					cores[2] = atoi(av[2]);
-					cores[3] = atoi(av[3]);
-				} else {
-					ED(" -C accepts 1, 2 or 4 comma separated arguments");
-					usage();
-				}
-				if (av)
-					free(av);
-			}
-			break;
-
-		case 'B': /* bandwidth in bps */
-			add_to(b, N_OPTS, optarg, "-B too many times");
-			break;
-
-		case 'D': /* delay in seconds (float) */
-			add_to(d, N_OPTS, optarg, "-D too many times");
-			break;
-
-		case 'Q': /* qsize in bytes */
-			add_to(q, N_OPTS, optarg, "-Q too many times");
-			break;
-
-		case 'L': /* loss probability */
-			add_to(l, N_OPTS, optarg, "-L too many times");
-			break;
-
-		case 'b':	/* burst */
-			bp[0].q.burst = atoi(optarg);
-			break;
-
-		case 'i':	/* interface */
-			add_to(ifname, N_OPTS, optarg, "-i too many times");
-			break;
-		case 'c':
-			bp[0].zerocopy = 0; /* do not zerocopy */
-			break;
-		case 'v':
-			verbose++;
-			break;
-		case 'w':
-			bp[0].wait_link = atoi(optarg);
-			break;
-		}
-
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	/*
-	 * consistency checks for common arguments
-	 */
-	if (!ifname[0] || !ifname[0]) {
-		ED("missing interface(s)");
-		usage();
-	}
-	if (strcmp(ifname[0], ifname[1]) == 0) {
-		ED("must specify two different interfaces %s %s", ifname[0], ifname[1]);
-		usage();
-	}
-	if (bp[0].q.burst < 1 || bp[0].q.burst > 8192) {
-		ED("invalid burst %d, set to 1024", bp[0].q.burst);
-		bp[0].q.burst = 1024; // XXX 128 is probably better
-	}
-	if (bp[0].wait_link > 100) {
-		ED("invalid wait_link %d, set to 4", bp[0].wait_link);
-		bp[0].wait_link = 4;
-	}
-
-	bp[1] = bp[0]; /* copy parameters, but swap interfaces */
-	bp[0].q.prod_ifname = bp[1].q.cons_ifname = ifname[0];
-	bp[1].q.prod_ifname = bp[0].q.cons_ifname = ifname[1];
-
-	/* assign cores. prod and cons work better if on the same HT */
-	bp[0].cons_core = cores[0];
-	bp[0].prod_core = cores[1];
-	bp[1].cons_core = cores[2];
-	bp[1].prod_core = cores[3];
-	ED("running on cores %d %d %d %d", cores[0], cores[1], cores[2], cores[3]);
-
-	/* use same parameters for both directions if needed */
-	if (d[1] == NULL)
-		d[1] = d[0];
-	if (b[1] == NULL)
-		b[1] = b[0];
-	if (l[1] == NULL)
-		l[1] = l[0];
-
-	/* apply commands */
-	for (i = 0; i < N_OPTS; i++) { /* once per queue */
-		struct _qs *q = &bp[i].q;
-		err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
-		err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
-		err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
-	}
-
-	if (q[0] == NULL)
-		q[0] = "0";
-	if (q[1] == NULL)
-		q[1] = q[0];
-	bp[0].q.qsize = parse_qsize(q[0]);
-	bp[1].q.qsize = parse_qsize(q[1]);
-
-	if (bp[0].q.qsize == 0) {
-		ED("qsize= 0 is not valid, set to 50k");
-		bp[0].q.qsize = 50000;
-	}
-	if (bp[1].q.qsize == 0) {
-		ED("qsize= 0 is not valid, set to 50k");
-		bp[1].q.qsize = 50000;
-	}
-
-	pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
-	pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
-
-	signal(SIGINT, sigint_h);
-	sleep(1);
-	while (!do_abort) {
-	    struct _qs olda = bp[0].q, oldb = bp[1].q;
-	    struct _qs *q0 = &bp[0].q, *q1 = &bp[1].q;
-
-	    sleep(1);
-	    ED("%lld -> %lld maxq %d round %lld, %lld <- %lld maxq %d round %lld",
-		(long long)(q0->rx - olda.rx), (long long)(q0->tx - olda.tx),
-		q0->rx_qmax, (long long)q0->prod_max_gap,
-		(long long)(q1->rx - oldb.rx), (long long)(q1->tx - oldb.tx),
-		q1->rx_qmax, (long long)q1->prod_max_gap
-		);
-	    ED("plr nominal %le actual %le",
-		(double)(q0->c_loss.d[0])/(1<<24),
-		q0->c_loss.d[1] == 0 ? 0 :
-		(double)(q0->c_loss.d[2])/q0->c_loss.d[1]);
-	    bp[0].q.rx_qmax = (bp[0].q.rx_qmax * 7)/8; // ewma
-	    bp[0].q.prod_max_gap = (bp[0].q.prod_max_gap * 7)/8; // ewma
-	    bp[1].q.rx_qmax = (bp[1].q.rx_qmax * 7)/8; // ewma
-	    bp[1].q.prod_max_gap = (bp[1].q.prod_max_gap * 7)/8; // ewma
-	}
-	D("exiting on abort");
-	sleep(1);
-
-	return (0);
+    struct pipe_args bp[N_OPTS];
+    const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS];
+    int cores[4] = { 2, 8, 4, 10 }; /* default values */
+
+    bzero(d, sizeof(d));
+    bzero(b, sizeof(b));
+    bzero(l, sizeof(l));
+    bzero(q, sizeof(q));
+    bzero(ifname, sizeof(ifname));
+
+    fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
+
+    bzero(&bp, sizeof(bp));	/* all data initially go here */
+
+    for (i = 0; i < N_OPTS; i++) {
+        struct _qs *q = &bp[i].q;
+        q->c_delay.optarg = "0";
+        q->c_delay.run = null_run_fn;
+        q->c_loss.optarg = "0";
+        q->c_loss.run = null_run_fn;
+        q->c_bw.optarg = "0";
+        q->c_bw.run = null_run_fn;
+    }
+
+    // Options:
+    // B	bandwidth in bps
+    // D	delay in seconds
+    // Q	qsize in bytes
+    // L	loss probability
+    // i	interface name (two mandatory)
+    // v	verbose
+    // b	batch size
+
+    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:b:ci:vw:")) != -1) {
+        switch (ch) {
+            default:
+                D("bad option %c %s", ch, optarg);
+                usage();
+                break;
+
+            case 'C': /* CPU placement, up to 4 arguments */
+                {
+                    int ac = 0;
+                    char **av = split_arg(optarg, &ac);
+                    if (ac == 1) { /* sequential after the first */
+                        cores[0] = atoi(av[0]);
+                        cores[1] = cores[0] + 1;
+                        cores[2] = cores[1] + 1;
+                        cores[3] = cores[2] + 1;
+                    } else if (ac == 2) { /* two sequential pairs */
+                        cores[0] = atoi(av[0]);
+                        cores[1] = cores[0] + 1;
+                        cores[2] = atoi(av[1]);
+                        cores[3] = cores[2] + 1;
+                    } else if (ac == 4) { /* four values */
+                        cores[0] = atoi(av[0]);
+                        cores[1] = atoi(av[1]);
+                        cores[2] = atoi(av[2]);
+                        cores[3] = atoi(av[3]);
+                    } else {
+                        ED(" -C accepts 1, 2 or 4 comma separated arguments");
+                        usage();
+                    }
+                    if (av)
+                        free(av);
+                }
+                break;
+
+            case 'B': /* bandwidth in bps */
+                add_to(b, N_OPTS, optarg, "-B too many times");
+                break;
+
+            case 'D': /* delay in seconds (float) */
+                add_to(d, N_OPTS, optarg, "-D too many times");
+                break;
+
+            case 'Q': /* qsize in bytes */
+                add_to(q, N_OPTS, optarg, "-Q too many times");
+                break;
+
+            case 'L': /* loss probability */
+                add_to(l, N_OPTS, optarg, "-L too many times");
+                break;
+
+            case 'b':	/* burst */
+                bp[0].q.burst = atoi(optarg);
+                break;
+
+            case 'i':	/* interface */
+                add_to(ifname, N_OPTS, optarg, "-i too many times");
+                break;
+            case 'c':
+                bp[0].zerocopy = 0; /* do not zerocopy */
+                break;
+            case 'v':
+                verbose++;
+                break;
+            case 'w':
+                bp[0].wait_link = atoi(optarg);
+                break;
+        }
+
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    /*
+     * consistency checks for common arguments
+     */
+    if (!ifname[0] || !ifname[0]) {
+        ED("missing interface(s)");
+        usage();
+    }
+    if (strcmp(ifname[0], ifname[1]) == 0) {
+        ED("must specify two different interfaces %s %s", ifname[0], ifname[1]);
+        usage();
+    }
+    if (bp[0].q.burst < 1 || bp[0].q.burst > 8192) {
+        ED("invalid burst %d, set to 1024", bp[0].q.burst);
+        bp[0].q.burst = 1024; // XXX 128 is probably better
+    }
+    if (bp[0].wait_link > 100) {
+        ED("invalid wait_link %d, set to 4", bp[0].wait_link);
+        bp[0].wait_link = 4;
+    }
+
+    bp[1] = bp[0]; /* copy parameters, but swap interfaces */
+    bp[0].q.prod_ifname = bp[1].q.cons_ifname = ifname[0];
+    bp[1].q.prod_ifname = bp[0].q.cons_ifname = ifname[1];
+
+    /* assign cores. prod and cons work better if on the same HT */
+    bp[0].cons_core = cores[0];
+    bp[0].prod_core = cores[1];
+    bp[1].cons_core = cores[2];
+    bp[1].prod_core = cores[3];
+    ED("running on cores %d %d %d %d", cores[0], cores[1], cores[2], cores[3]);
+
+    /* use same parameters for both directions if needed */
+    if (d[1] == NULL)
+        d[1] = d[0];
+    if (b[1] == NULL)
+        b[1] = b[0];
+    if (l[1] == NULL)
+        l[1] = l[0];
+
+    /* apply commands */
+    for (i = 0; i < N_OPTS; i++) { /* once per queue */
+        struct _qs *q = &bp[i].q;
+        err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
+        err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
+        err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
+    }
+
+    if (q[0] == NULL)
+        q[0] = "0";
+    if (q[1] == NULL)
+        q[1] = q[0];
+    bp[0].q.qsize = parse_qsize(q[0]);
+    bp[1].q.qsize = parse_qsize(q[1]);
+
+    if (bp[0].q.qsize == 0) {
+        ED("qsize= 0 is not valid, set to 50k");
+        bp[0].q.qsize = 50000;
+    }
+    if (bp[1].q.qsize == 0) {
+        ED("qsize= 0 is not valid, set to 50k");
+        bp[1].q.qsize = 50000;
+    }
+
+    pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
+    pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
+
+    signal(SIGINT, sigint_h);
+    sleep(1);
+    while (!do_abort) {
+        struct _qs olda = bp[0].q, oldb = bp[1].q;
+        struct _qs *q0 = &bp[0].q, *q1 = &bp[1].q;
+
+        sleep(1);
+        ED("%lld -> %lld maxq %d round %lld, %lld <- %lld maxq %d round %lld",
+                (long long)(q0->rx - olda.rx), (long long)(q0->tx - olda.tx),
+                q0->rx_qmax, (long long)q0->prod_max_gap,
+                (long long)(q1->rx - oldb.rx), (long long)(q1->tx - oldb.tx),
+                q1->rx_qmax, (long long)q1->prod_max_gap
+          );
+        ED("plr nominal %le actual %le",
+                (double)(q0->c_loss.d[0])/(1<<24),
+                q0->c_loss.d[1] == 0 ? 0 :
+                (double)(q0->c_loss.d[2])/q0->c_loss.d[1]);
+        bp[0].q.rx_qmax = (bp[0].q.rx_qmax * 7)/8; // ewma
+        bp[0].q.prod_max_gap = (bp[0].q.prod_max_gap * 7)/8; // ewma
+        bp[1].q.rx_qmax = (bp[1].q.rx_qmax * 7)/8; // ewma
+        bp[1].q.prod_max_gap = (bp[1].q.prod_max_gap * 7)/8; // ewma
+    }
+    D("exiting on abort");
+    sleep(1);
+
+    return (0);
 }
 
 /* conversion factor for numbers.
@@ -1295,39 +1295,39 @@ struct _sm {	/* string and multiplier */
 static double
 parse_gen(const char *arg, const struct _sm *conv, int *err)
 {
-	double d;
-	char *ep;
-	int dummy;
-
-	if (err == NULL)
-		err = &dummy;
-	*err = 0;
-	if (arg == NULL)
-		goto error;
-	d = strtod(arg, &ep);
-	if (ep == arg) { /* no value */
-		ED("bad argument %s", arg);
-		goto error;
-	}
-	/* special case, no conversion */
-	if (conv == NULL && *ep == '\0')
-		goto done;
-	ND("checking %s [%s]", arg, ep);
-	for (;conv->s; conv++) {
-		if (strchr(conv->s, *ep))
-			goto done;
-	}
+    double d;
+    char *ep;
+    int dummy;
+
+    if (err == NULL)
+        err = &dummy;
+    *err = 0;
+    if (arg == NULL)
+        goto error;
+    d = strtod(arg, &ep);
+    if (ep == arg) { /* no value */
+        ED("bad argument %s", arg);
+        goto error;
+    }
+    /* special case, no conversion */
+    if (conv == NULL && *ep == '\0')
+        goto done;
+    ND("checking %s [%s]", arg, ep);
+    for (;conv->s; conv++) {
+        if (strchr(conv->s, *ep))
+            goto done;
+    }
 error:
-	*err = 1;	/* unrecognised */
-	return 0;
+    *err = 1;	/* unrecognised */
+    return 0;
 
 done:
-	if (conv) {
-		ND("scale is %s %lf", conv->s, conv->m);
-		d *= conv->m; /* apply default conversion */
-	}
-	ND("returning %lf", d);
-	return d;
+    if (conv) {
+        ND("scale is %s %lf", conv->s, conv->m);
+        d *= conv->m; /* apply default conversion */
+    }
+    ND("returning %lf", d);
+    return d;
 }
 
 #define U_PARSE_ERR ~(0ULL)
@@ -1337,10 +1337,10 @@ static uint64_t
 parse_time(const char *arg)
 {
     struct _sm a[] = {
-	{"", 1000000000 /* seconds */},
-	{"n", 1 /* nanoseconds */}, {"u", 1000 /* microseconds */},
-	{"m", 1000000 /* milliseconds */}, {"s", 1000000000 /* seconds */},
-	{NULL, 0 /* seconds */}
+        {"", 1000000000 /* seconds */},
+        {"n", 1 /* nanoseconds */}, {"u", 1000 /* microseconds */},
+        {"m", 1000000 /* milliseconds */}, {"s", 1000000000 /* seconds */},
+        {NULL, 0 /* seconds */}
     };
     int err;
     uint64_t ret = (uint64_t)parse_gen(arg, a, &err);
@@ -1355,7 +1355,7 @@ static uint64_t
 parse_bw(const char *arg)
 {
     struct _sm a[] = {
-	{"", 1}, {"kK", 1000}, {"mM", 1000000}, {"gG", 1000000000}, {NULL, 0}
+        {"", 1}, {"kK", 1000}, {"mM", 1000000}, {"gG", 1000000000}, {NULL, 0}
     };
     int err;
     uint64_t ret = (uint64_t)parse_gen(arg, a, &err);
@@ -1369,7 +1369,7 @@ static uint64_t
 parse_qsize(const char *arg)
 {
     struct _sm a[] = {
-	{"", 1}, {"kK", 1024}, {"mM", 1024*1024}, {"gG", 1024*1024*1024}, {NULL, 0}
+        {"", 1}, {"kK", 1024}, {"mM", 1024*1024}, {"gG", 1024*1024*1024}, {NULL, 0}
     };
     int err;
     uint64_t ret = (uint64_t)parse_gen(arg, a, &err);
@@ -1386,7 +1386,7 @@ parse_qsize(const char *arg)
 static inline uint64_t
 my_random24(void)	/* 24 useful bits */
 {
-	return random() & ((1<<24) - 1);
+    return random() & ((1<<24) - 1);
 }
 
 
@@ -1517,58 +1517,58 @@ BANDWIDTH emulation	-B option_arguments
 static int
 const_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-	uint64_t delay;
-
-	if (strncmp(av[0], "const", 5) != 0 && ac > 1)
-		return 2; /* unrecognised */
-	if (ac > 2)
-		return 1; /* error */
-	delay = parse_time(av[ac - 1]);
-	if (delay == U_PARSE_ERR)
-		return 1; /* error */
-	dst->d[0] = delay;
-	q->max_delay = delay;
-	return 0;	/* success */
+    uint64_t delay;
+
+    if (strncmp(av[0], "const", 5) != 0 && ac > 1)
+        return 2; /* unrecognised */
+    if (ac > 2)
+        return 1; /* error */
+    delay = parse_time(av[ac - 1]);
+    if (delay == U_PARSE_ERR)
+        return 1; /* error */
+    dst->d[0] = delay;
+    q->max_delay = delay;
+    return 0;	/* success */
 }
 
 /* runtime function, store the delay into q->cur_delay */
 static int
 const_delay_run(struct _qs *q, struct _cfg *arg)
 {
-	q->cur_delay = arg->d[0]; /* the delay */
-	return 0;
+    q->cur_delay = arg->d[0]; /* the delay */
+    return 0;
 }
 
 static int
 uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-	uint64_t dmin, dmax;
-
-	(void)q;
-	if (strcmp(av[0], "uniform") != 0)
-		return 2; /* not recognised */
-	if (ac != 3)
-		return 1; /* error */
-	dmin = parse_time(av[1]);
-	dmax = parse_time(av[2]);
-	if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax)
-		return 1;
-	D("dmin %lld dmax %lld", (long long)dmin, (long long)dmax);
-	dst->d[0] = dmin;
-	dst->d[1] = dmax;
-	dst->d[2] = dmax - dmin;
-	q->max_delay = dmax;
-	return 0;
+    uint64_t dmin, dmax;
+
+    (void)q;
+    if (strcmp(av[0], "uniform") != 0)
+        return 2; /* not recognised */
+    if (ac != 3)
+        return 1; /* error */
+    dmin = parse_time(av[1]);
+    dmax = parse_time(av[2]);
+    if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax)
+        return 1;
+    D("dmin %lld dmax %lld", (long long)dmin, (long long)dmax);
+    dst->d[0] = dmin;
+    dst->d[1] = dmax;
+    dst->d[2] = dmax - dmin;
+    q->max_delay = dmax;
+    return 0;
 }
 
 static int
 uniform_delay_run(struct _qs *q, struct _cfg *arg)
 {
-	uint64_t x = my_random24();
-	q->cur_delay = arg->d[0] + ((arg->d[2] * x) >> 24);
+    uint64_t x = my_random24();
+    q->cur_delay = arg->d[0] + ((arg->d[2] * x) >> 24);
 #if 0 /* COMPUTE_STATS */
 #endif /* COMPUTE_STATS */
-	return 0;
+    return 0;
 }
 
 /*
@@ -1586,40 +1586,40 @@ static int
 exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
 #define	PTS_D_EXP	512
-	uint64_t i, d_av, d_min, *t; /*table of values */
-
-	(void)q;
-	if (strcmp(av[0], "exp") != 0)
-		return 2; /* not recognised */
-	if (ac != 3)
-		return 1; /* error */
-	d_av = parse_time(av[1]);
-	d_min = parse_time(av[2]);
-	if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min)
-		return 1; /* error */
-	d_av -= d_min;
-	dst->arg_len = PTS_D_EXP * sizeof(uint64_t);
-	dst->arg = calloc(1, dst->arg_len);
-	if (dst->arg == NULL)
-		return 1; /* no memory */
-	t = (uint64_t *)dst->arg;
-	q->max_delay = d_av * 4 + d_min; /* exp(-4) */
-	/* tabulate -ln(1-n)*delay  for n in 0..1 */
-	for (i = 0; i < PTS_D_EXP; i++) {
-		double d = -log2 ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min;
-		t[i] = (uint64_t)d;
-		ND(5, "%ld: %le", i, d);
-	}
-	return 0;
+    uint64_t i, d_av, d_min, *t; /*table of values */
+
+    (void)q;
+    if (strcmp(av[0], "exp") != 0)
+        return 2; /* not recognised */
+    if (ac != 3)
+        return 1; /* error */
+    d_av = parse_time(av[1]);
+    d_min = parse_time(av[2]);
+    if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min)
+        return 1; /* error */
+    d_av -= d_min;
+    dst->arg_len = PTS_D_EXP * sizeof(uint64_t);
+    dst->arg = calloc(1, dst->arg_len);
+    if (dst->arg == NULL)
+        return 1; /* no memory */
+    t = (uint64_t *)dst->arg;
+    q->max_delay = d_av * 4 + d_min; /* exp(-4) */
+    /* tabulate -ln(1-n)*delay  for n in 0..1 */
+    for (i = 0; i < PTS_D_EXP; i++) {
+        double d = -log2 ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min;
+        t[i] = (uint64_t)d;
+        ND(5, "%ld: %le", i, d);
+    }
+    return 0;
 }
 
 static int
 exp_delay_run(struct _qs *q, struct _cfg *arg)
 {
-	uint64_t *t = (uint64_t *)arg->arg;
-	q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)];
-	RD(5, "delay %llu", (unsigned long long)q->cur_delay);
-	return 0;
+    uint64_t *t = (uint64_t *)arg->arg;
+    q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)];
+    RD(5, "delay %llu", (unsigned long long)q->cur_delay);
+    return 0;
 }
 
 
@@ -1639,20 +1639,20 @@ static struct _cfg delay_cfg[] = {
 static int
 const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-	uint64_t bw;
-
-	(void)q;
-	if (strncmp(av[0], "const", 5) != 0)
-		return 2; /* unrecognised */
-	if (ac > 2)
-		return 1; /* error */
-	bw = parse_bw(av[ac - 1]);
-	if (bw == U_PARSE_ERR) {
-		return (ac == 2) ? 1 /* error */ : 2 /* unrecognised */;
-	}
-	dst->d[0] = bw;
-	q->max_bps = bw;	/* bw used to determine queue size */
-	return 0;	/* success */
+    uint64_t bw;
+
+    (void)q;
+    if (strncmp(av[0], "const", 5) != 0)
+        return 2; /* unrecognised */
+    if (ac > 2)
+        return 1; /* error */
+    bw = parse_bw(av[ac - 1]);
+    if (bw == U_PARSE_ERR) {
+        return (ac == 2) ? 1 /* error */ : 2 /* unrecognised */;
+    }
+    dst->d[0] = bw;
+    q->max_bps = bw;	/* bw used to determine queue size */
+    return 0;	/* success */
 }
 
 
@@ -1660,28 +1660,28 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_bw_run(struct _qs *q, struct _cfg *arg)
 {
-	uint64_t bps = arg->d[0];
-	q->cur_tt = bps ? 8ULL* TIME_UNITS * q->cur_len / bps : 0 ;
-	return 0;
+    uint64_t bps = arg->d[0];
+    q->cur_tt = bps ? 8ULL* TIME_UNITS * q->cur_len / bps : 0 ;
+    return 0;
 }
 
 /* ethernet bandwidth, add 672 bits per packet */
 static int
 ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-	uint64_t bw;
-
-	(void)q;
-	if (strcmp(av[0], "ether") != 0)
-		return 2; /* unrecognised */
-	if (ac != 2)
-		return 1; /* error */
-	bw = parse_bw(av[ac - 1]);
-	if (bw == U_PARSE_ERR)
-		return 1; /* error */
-	dst->d[0] = bw;
-	q->max_bps = bw;	/* bw used to determine queue size */
-	return 0;	/* success */
+    uint64_t bw;
+
+    (void)q;
+    if (strcmp(av[0], "ether") != 0)
+        return 2; /* unrecognised */
+    if (ac != 2)
+        return 1; /* error */
+    bw = parse_bw(av[ac - 1]);
+    if (bw == U_PARSE_ERR)
+        return 1; /* error */
+    dst->d[0] = bw;
+    q->max_bps = bw;	/* bw used to determine queue size */
+    return 0;	/* success */
 }
 
 
@@ -1689,9 +1689,9 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 ether_bw_run(struct _qs *q, struct _cfg *arg)
 {
-	uint64_t bps = arg->d[0];
-	q->cur_tt = bps ? 8ULL * TIME_UNITS * (q->cur_len + 24) / bps : 0 ;
-	return 0;
+    uint64_t bps = arg->d[0];
+    q->cur_tt = bps ? 8ULL * TIME_UNITS * (q->cur_len + 24) / bps : 0 ;
+    return 0;
 }
 
 static struct _cfg bw_cfg[] = {
@@ -1708,35 +1708,35 @@ static struct _cfg bw_cfg[] = {
 static int
 const_plr_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-	double plr;
-	int err;
-
-	(void)q;
-	if (strcmp(av[0], "plr") != 0 && ac > 1)
-		return 2; /* unrecognised */
-	if (ac > 2)
-		return 1; /* error */
-	// XXX to be completed
-	plr = parse_gen(av[ac-1], NULL, &err);
-	if (err || plr < 0 || plr > 1)
-		return 1;
-	dst->d[0] = plr * (1<<24); /* scale is 16m */
-	if (plr != 0 && dst->d[0] == 0)
-		ED("WWW warning,  rounding %le down to 0", plr);
-	return 0;	/* success */
+    double plr;
+    int err;
+
+    (void)q;
+    if (strcmp(av[0], "plr") != 0 && ac > 1)
+        return 2; /* unrecognised */
+    if (ac > 2)
+        return 1; /* error */
+    // XXX to be completed
+    plr = parse_gen(av[ac-1], NULL, &err);
+    if (err || plr < 0 || plr > 1)
+        return 1;
+    dst->d[0] = plr * (1<<24); /* scale is 16m */
+    if (plr != 0 && dst->d[0] == 0)
+        ED("WWW warning,  rounding %le down to 0", plr);
+    return 0;	/* success */
 }
 
 static int
 const_plr_run(struct _qs *q, struct _cfg *arg)
 {
-	(void)arg;
-	uint64_t r = my_random24();
-	q->cur_drop = r < arg->d[0];
+    (void)arg;
+    uint64_t r = my_random24();
+    q->cur_drop = r < arg->d[0];
 #if 1	/* keep stats */
-	arg->d[1]++;
-	arg->d[2] += q->cur_drop;
+    arg->d[1]++;
+    arg->d[2] += q->cur_drop;
 #endif
-	return 0;
+    return 0;
 }
 
 
@@ -1748,59 +1748,59 @@ const_plr_run(struct _qs *q, struct _cfg *arg)
 static int
 const_ber_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-	double ber, ber8, cur;
-	int i, err;
-	uint32_t *plr;
-	const uint32_t mask = (1<<24) - 1;
-
-	(void)q;
-	if (strcmp(av[0], "ber") != 0)
-		return 2; /* unrecognised */
-	if (ac != 2)
-		return 1; /* error */
-	ber = parse_gen(av[ac-1], NULL, &err);
-	if (err || ber < 0 || ber > 1)
-		return 1;
-	dst->arg_len = MAX_PKT * sizeof(uint32_t);
-	plr = calloc(1, dst->arg_len);
-	if (plr == NULL)
-		return 1; /* no memory */
-	dst->arg = plr;
-	ber8 = 1 - ber;
-	ber8 *= ber8; /* **2 */
-	ber8 *= ber8; /* **4 */
-	ber8 *= ber8; /* **8 */
-	cur = 1;
-	for (i=0; i < MAX_PKT; i++, cur *= ber8) {
-		plr[i] = (mask + 1)*(1 - cur);
-		if (plr[i] > mask)
-			plr[i] = mask;
+    double ber, ber8, cur;
+    int i, err;
+    uint32_t *plr;
+    const uint32_t mask = (1<<24) - 1;
+
+    (void)q;
+    if (strcmp(av[0], "ber") != 0)
+        return 2; /* unrecognised */
+    if (ac != 2)
+        return 1; /* error */
+    ber = parse_gen(av[ac-1], NULL, &err);
+    if (err || ber < 0 || ber > 1)
+        return 1;
+    dst->arg_len = MAX_PKT * sizeof(uint32_t);
+    plr = calloc(1, dst->arg_len);
+    if (plr == NULL)
+        return 1; /* no memory */
+    dst->arg = plr;
+    ber8 = 1 - ber;
+    ber8 *= ber8; /* **2 */
+    ber8 *= ber8; /* **4 */
+    ber8 *= ber8; /* **8 */
+    cur = 1;
+    for (i=0; i < MAX_PKT; i++, cur *= ber8) {
+        plr[i] = (mask + 1)*(1 - cur);
+        if (plr[i] > mask)
+            plr[i] = mask;
 #if 0
-		if (i>= 60) //  && plr[i] < mask/2)
-			RD(50,"%4d: %le %ld", i, 1.0 - cur, (_P64)plr[i]);
+        if (i>= 60) //  && plr[i] < mask/2)
+            RD(50,"%4d: %le %ld", i, 1.0 - cur, (_P64)plr[i]);
 #endif
-	}
-	dst->d[0] = ber * (mask + 1);
-	return 0;	/* success */
+    }
+    dst->d[0] = ber * (mask + 1);
+    return 0;	/* success */
 }
 
 static int
 const_ber_run(struct _qs *q, struct _cfg *arg)
 {
-	int l = q->cur_len;
-	uint64_t r = my_random24();
-	uint32_t *plr = arg->arg;
-
-	if (l >= MAX_PKT) {
-		RD(5, "pkt len %d too large, trim to %d", l, MAX_PKT-1);
-		l = MAX_PKT-1;
-	}
-	q->cur_drop = r < plr[l];
+    int l = q->cur_len;
+    uint64_t r = my_random24();
+    uint32_t *plr = arg->arg;
+
+    if (l >= MAX_PKT) {
+        RD(5, "pkt len %d too large, trim to %d", l, MAX_PKT-1);
+        l = MAX_PKT-1;
+    }
+    q->cur_drop = r < plr[l];
 #if 1	/* keep stats */
-	arg->d[1] += l * 8;
-	arg->d[2] += q->cur_drop;
+    arg->d[1] += l * 8;
+    arg->d[2] += q->cur_drop;
 #endif
-	return 0;
+    return 0;
 }
 
 static struct _cfg loss_cfg[] = {

From bbdbb89991781c6270726e984d5e0bf6ab8f600e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 12 Jul 2018 15:23:47 +0200
Subject: [PATCH 1074/2207] tlem: add vim modeline

---
 apps/tlem/tlem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 2e906de93..6ffc1a8f5 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1,3 +1,4 @@
+/* vim: set shiftwidth=4 softtabstop=4 :*/
 /*
  * Copyright (C) 2016 Universita` di Pisa. All rights reserved.
  *

From 869ab92302c89b0d5e8ef07090767866bfaa01b6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 24 Jan 2017 14:45:29 +0100
Subject: [PATCH 1075/2207] tlem: read head and tail only once

---
 apps/tlem/tlem.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 6ffc1a8f5..8a3995ff2 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -788,8 +788,9 @@ cons(void *_pa)
 {
     struct pipe_args *pa = _pa;
     struct _qs *q = &pa->q;
-    int cycles = 0;
     int pending = 0;
+#if 0
+    int cycles = 0;
     const char *pre_start, *pre_end; /* prefetch limits */
 
     /*
@@ -797,19 +798,24 @@ cons(void *_pa)
      */
     pre_start = q->buf + q->head;
     pre_end = pre_start + 2048;
-
     (void)cycles; // XXX disable warning
+#endif
+
     set_tns_now(&q->cons_now, q->t0);
     while (!do_abort) { /* consumer, infinite */
+        uint64_t h = q->head; /* read only once */
+        uint64_t t = q->tail; /* read only once */
+        struct q_pkt *p = (struct q_pkt *)(q->buf + h);
+#if 0
         struct q_pkt *p = (struct q_pkt *)(q->buf + q->head);
         if (p->next < q->head) { /* wrap around prefetch */
             pre_start = q->buf + p->next;
         }
         pre_end = q->buf + p->next + 2048;
-#if 1
+        //#if 1
         /* prefetch the first line saves 4ns */
         (void)pre_end;//   __builtin_prefetch(pre_end - 2048);
-#else
+        //#else
         /* prefetch, ideally up to a full packet not just one line.
          * this does not seem to have a huge effect.
          * 4ns out of 198 on 1500 byte packets
@@ -818,9 +824,9 @@ cons(void *_pa)
             __builtin_prefetch(pre_start);
 #endif
 
-        if (q->head == q->tail || ts_cmp(p->pt_tx, q->cons_now) > 0) {
+        if (h == t || ts_cmp(p->pt_tx, q->cons_now) > 0) {
             ND(4, "                 >>>> TXSYNC, pkt not ready yet h %ld t %ld now %ld tx %ld",
-                    q->head, q->tail, q->cons_now, p->pt_tx);
+                    h, t, q->cons_now, p->pt_tx);
             q->rx_wait++;
             ioctl(pa->pb->fd, NIOCTXSYNC, 0); // XXX just in case
             pending = 0;
@@ -829,11 +835,11 @@ cons(void *_pa)
             continue;
         }
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
-                p->pktlen, q->cons_now, p->pt_tx, q->head, q->tail, p->next);
+                p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
         /* XXX inefficient but simple */
         if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
             ND(5, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
-                    (int)p->pktlen, q->cons_now, p->pt_tx, q->head, q->tail, p->next);
+                    (int)p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
             ioctl(pa->pb->fd, NIOCTXSYNC, 0);
             pending = 0;
             continue;

From 1151f273e4b19d53798875af9c8b49b3ebd2bfd3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 7 Apr 2018 14:24:50 +0200
Subject: [PATCH 1076/2207] tlem: fix error handling in parse_gen

---
 apps/tlem/tlem.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 8a3995ff2..a3ba07b69 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1316,9 +1316,12 @@ parse_gen(const char *arg, const struct _sm *conv, int *err)
         ED("bad argument %s", arg);
         goto error;
     }
-    /* special case, no conversion */
-    if (conv == NULL && *ep == '\0')
-        goto done;
+    if (conv == NULL) {
+        if (*ep == '\0') /* special case, no conversion */
+            goto done;
+        ED("bad suffix %s", ep);
+        goto error;
+    }
     ND("checking %s [%s]", arg, ep);
     for (;conv->s; conv++) {
         if (strchr(conv->s, *ep))

From d6429263992cfad5a498a2c2623cfb5aa061092f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 7 Apr 2018 17:16:13 +0200
Subject: [PATCH 1077/2207] tlem: fix order of arguments in exponential delay

---
 apps/tlem/tlem.8 | 2 +-
 apps/tlem/tlem.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/apps/tlem/tlem.8 b/apps/tlem/tlem.8
index 1f8e4e83c..3cba7574a 100644
--- a/apps/tlem/tlem.8
+++ b/apps/tlem/tlem.8
@@ -104,7 +104,7 @@ with reference to the actual packet size (excluding CRC and framing).
 .Cm ether
 indicates that the ethernet framing (160 bits) and CRC (32 bits)
 will be included in the computation of the packet size.
-.It Fl D Ar dt | Cm constant, Ns Ar dt | Cm uniform, Ns Ar dmin,dmax | Cm exp, Ar dmin,davg
+.It Fl D Ar dt | Cm constant, Ns Ar dt | Cm uniform, Ns Ar dmin,dmax | Cm exp, Ns Ar dmin,davg
 Additional delay in transmission, with
 constant, uniform or exponential distribution, defaults to 0.
 .Ar dt, dmin, dmax, avg
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index a3ba07b69..04bb2e23c 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1603,8 +1603,8 @@ exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
         return 2; /* not recognised */
     if (ac != 3)
         return 1; /* error */
-    d_av = parse_time(av[1]);
-    d_min = parse_time(av[2]);
+    d_min = parse_time(av[1]);
+    d_av = parse_time(av[2]);
     if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min)
         return 1; /* error */
     d_av -= d_min;
@@ -1628,7 +1628,7 @@ exp_delay_run(struct _qs *q, struct _cfg *arg)
 {
     uint64_t *t = (uint64_t *)arg->arg;
     q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)];
-    RD(5, "delay %llu", (unsigned long long)q->cur_delay);
+    ND(5, "delay %llu", (unsigned long long)q->cur_delay);
     return 0;
 }
 

From 98732a6bbba68caa8ffcfd5d84bb77c1673d5526 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 8 Apr 2018 10:25:38 +0200
Subject: [PATCH 1078/2207] tlem: allow 'constant' to be omitted after -B

---
 apps/tlem/tlem.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 04bb2e23c..8d92eca77 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1651,8 +1651,7 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
     uint64_t bw;
 
-    (void)q;
-    if (strncmp(av[0], "const", 5) != 0)
+    if (strncmp(av[0], "const", 5) != 0 && ac > 1)
         return 2; /* unrecognised */
     if (ac > 2)
         return 1; /* error */

From d46d4d68be7cb3366afa9273da5688cc4950de44 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Jun 2018 23:49:42 +0200
Subject: [PATCH 1079/2207] tlem: fix computation of exponential delay

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 8d92eca77..8a9494704 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1616,7 +1616,7 @@ exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     q->max_delay = d_av * 4 + d_min; /* exp(-4) */
     /* tabulate -ln(1-n)*delay  for n in 0..1 */
     for (i = 0; i < PTS_D_EXP; i++) {
-        double d = -log2 ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min;
+        double d = -log ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min;
         t[i] = (uint64_t)d;
         ND(5, "%ld: %le", i, d);
     }

From f978d1b1ceee5fd745cc08562ca4106d72f4d98e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 15 Feb 2017 13:20:42 +0000
Subject: [PATCH 1080/2207] tlem: try to assign threads depending on available
 cores

---
 apps/tlem/tlem.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 8a9494704..cefa86a82 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1087,7 +1087,8 @@ main(int argc, char **argv)
 #define	N_OPTS	2
     struct pipe_args bp[N_OPTS];
     const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS];
-    int cores[4] = { 2, 8, 4, 10 }; /* default values */
+    int ncpus;
+    int cores[4];
 
     bzero(d, sizeof(d));
     bzero(b, sizeof(b));
@@ -1109,6 +1110,20 @@ main(int argc, char **argv)
         q->c_bw.run = null_run_fn;
     }
 
+    ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+    if (ncpus <= 0) {
+        ED("failed to get the number of online CPUs: %s",
+                strerror(errno));
+        cores[0] = cores[1] = cores[2] = cores[3] = 0;
+    } else {
+        /* try to put prod/cons on two HT of the same core */
+        int h = ncpus / 2;
+        cores[0] = h / 3;
+        cores[1] = cores[0] + h;
+        cores[2] = (2 * h) / 3;
+        cores[3] = cores[2] + h;
+    }
+
     // Options:
     // B	bandwidth in bps
     // D	delay in seconds

From d088f3a109f36556715dead4108ec6c3c3502fc2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Mar 2017 11:56:48 +0100
Subject: [PATCH 1081/2207] tlem: retrive max priority from the kernel

---
 apps/tlem/tlem.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index cefa86a82..c41919e1f 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -398,6 +398,7 @@ setaffinity(int i)
     cpuset_t cpumask;
     struct sched_param p;
     int error;
+    int maxprio;
 
     if (i == -1)
         return 0;
@@ -412,8 +413,13 @@ setaffinity(int i)
     if (setpriority(PRIO_PROCESS, 0, -10)) {; // XXX not meaningful
         ED("Unable to set priority: %s", strerror(errno));
     }
+    maxprio = sched_get_priority_max(SCHED_RR);
+    if (maxprio < 0) {
+        ED("Unable to retrive max RR priority, using 10");
+        maxprio = 10;
+    }
     bzero(&p, sizeof(p));
-    p.sched_priority = 10; // 99 on linux ?
+    p.sched_priority = maxprio;
     // use SCHED_RR or SCHED_FIFO
     if (sched_setscheduler(0, SCHED_RR, &p)) {
         ED("Unable to set scheduler: %s", strerror(errno));

From 717f4136ad68df1e94ce7c6a143cc69631bec7a5 Mon Sep 17 00:00:00 2001
From: Dong Cai 
Date: Tue, 25 Sep 2018 22:23:14 -0700
Subject: [PATCH 1082/2207] netmap/netmap_mem2: fix memory pool bitmap not
 initialized all bits

memset is based on number of bytes not the sizeof(u32). therefore, not all bitmap bytes initialized
---
 sys/dev/netmap/netmap_mem2.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index fb93ad4d0..2747d4647 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -395,7 +395,7 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 	if (p->bitmap == NULL) {
 		/* Allocate the bitmap */
 		n = (p->objtotal + 31) / 32;
-		p->bitmap = nm_os_malloc(sizeof(uint32_t) * n);
+		p->bitmap = nm_os_malloc(sizeof(p->bitmap[0]) * n);
 		if (p->bitmap == NULL) {
 			D("Unable to create bitmap (%d entries) for allocator '%s'", (int)n,
 			    p->name);
@@ -403,7 +403,7 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 		}
 		p->bitmap_slots = n;
 	} else {
-		memset(p->bitmap, 0, p->bitmap_slots);
+		memset(p->bitmap, 0, p->bitmap_slots * sizeof(p->bitmap[0]));
 	}
 
 	p->objfree = 0;

From 2e54f98e43129b081f65bbbc7e739d28feef4fce Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 27 Sep 2018 16:01:16 +0200
Subject: [PATCH 1083/2207] extmem: added an example program in utils

---
 .gitignore             |   1 +
 utils/GNUmakefile      |   2 +-
 utils/extmem-example.c | 128 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 utils/extmem-example.c

diff --git a/.gitignore b/.gitignore
index 7f70ad460..259129d58 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,7 @@ utils/functional
 utils/fd_server
 utils/get_tx_rings_avail_sends
 utils/get_tx_rings_max_sends
+utils/extmem-example
 examples/pkt-gen.exe
 examples/pkt-gen.exe.stackdump
 examples/pkt-gen-b.exe
diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 2083feae1..0b7970654 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,7 +1,7 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
 PROGS	  = test_select testmmap test_nm functional ctrl-api-test fd_server
-PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends
+PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends extmem-example
 X86PROGS  = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/extmem-example.c b/utils/extmem-example.c
new file mode 100644
index 000000000..405f659c2
--- /dev/null
+++ b/utils/extmem-example.c
@@ -0,0 +1,128 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+
+/*
+ * example usage of the extmem feature. The feature is disabled by default.
+ * To enable it, add --enable-extmem to the ./configure command when you
+ * build netmap.
+ */
+int main(int argc, char *argv[])
+{
+	struct nmreq_header hdr;
+	struct nmreq_register req;
+	struct nmreq_opt_extmem ext;
+	struct netmap_if *nif;
+	void *addr;
+	int mem_fd, netmap_fd;
+	const char *ifname, *filename;
+	off_t filesize;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s  \n", argv[0]);
+		exit(1);
+	}
+
+	ifname = argv[1];
+	filename = argv[2];
+
+	/* with extmem, the netmap port(s) data structures
+	 * (if, rings and buffers) will be allocated from a
+	 * user-provied memory area. This can be, for example,
+	 * a pseudo-file in the hugetlbfs.
+	 */
+
+	/* open and mmap the file */
+	mem_fd = open(filename, O_RDWR);
+	if (mem_fd < 0) {
+		perror(filename);
+		exit(1);
+	}
+
+	filesize = lseek(mem_fd, 0, SEEK_END);
+	if (filesize < 0) {
+		perror("lseek");
+		exit(1);
+	}
+
+	addr = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0);
+	if (addr == MAP_FAILED) {
+		perror("mmap");
+		exit(1);
+	}
+
+	/* the new netmap API has a NIOCCTRL ioctl() for all kinds
+	 * of netmap control requests (opening a port, creating
+	 * persistent vale ports, etc.). All requests are made up
+	 * of a common header (struct nmreq_header) which points
+	 * to a request-specific body (struct nmreq_register for
+	 * opening ports). The header may also point to a list of
+	 * options. Extmem is one such option.
+	 */
+
+	/* create an option with type EXTMEM, passing the address
+	 * of the mmap()ed memory and its size
+	 */
+	memset(&ext, 0, sizeof(ext));
+	ext.nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
+	ext.nro_usrptr          = (uintptr_t)addr;
+	ext.nro_info.nr_memsize = filesize;
+
+	/* initialize the register request */
+	memset(&req, 0, sizeof(req));
+	req.nr_mode = NR_REG_ALL_NIC; /* or whatever */
+
+	/* initialize the header */
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.nr_version = NETMAP_API;
+	/* NOTE: this is the ifname without the 'netmap:' prefix,
+	 * but possibly including the '{' or '}' symbol for opening
+	 * a netmap pipe. The pipe identifier can be any alphanumeric
+	 * string, not just numbers. For VALE ports, use the entire
+	 * valeXXX:yyy name.
+	 */
+	strncpy(hdr.nr_name, ifname, sizeof(hdr.nr_name) - 1);
+	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+	/* link the request body */
+	hdr.nr_body    = (uintptr_t)&req;
+	/* and the head of the options list */
+	hdr.nr_options = (uintptr_t)&ext;
+
+	/* now pass everything to the kernel */
+        netmap_fd = open("/dev/netmap", O_RDWR);
+	if (netmap_fd < 0) {
+		perror("/dev/netmap");
+		exit(1);
+	}
+
+	if (ioctl(netmap_fd, NIOCCTRL, &hdr) < 0) {
+		/* EOPNOTSUPP if extmem was not compiled in */
+		perror(ifname);
+		exit(1);
+	}
+
+	/* now we can use the mmap()ed area (NOTE: mmap() of "/dev/netmap" will
+	 * fail, so we must use the 'addr' obtained above.)
+	 *
+	 * Other processes can share the memory (e.g., to open other ports in
+	 * the same region) but they must mmap() the original file and go
+	 * through the same procedure as above.
+	 */
+
+	nif = NETMAP_IF(addr, req.nr_offset);
+
+	/* and so on ... */
+	(void)nif;
+	return 0;
+}

From 8bce128402fecbbcb8dc9f58eba398f8d5c32b8d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 28 Sep 2018 09:33:49 +0200
Subject: [PATCH 1084/2207] README: specify the unit used in the table

Fixes #548
---
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README b/README
index 58260b75b..828c23201 100644
--- a/README
+++ b/README
@@ -187,7 +187,7 @@ be computed with the formula:
 
 where "line_rate" is the nominal link rate (e.g 10 Gbit/s) and
 pkt_size is the actual packet size including MAC headers and CRC.
-The following table summarizes some results
+The following table summarizes some results (in Mpps)
 
 			LINE RATE
     pkt_size \	100M	1G	10G	40G

From 2419c2a748d3f0147a149080b30aecec570179fd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 17:31:58 +0200
Subject: [PATCH 1085/2207] netmap_poll: small simplification

---
 sys/dev/netmap/netmap.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e2ed6051d..911523a26 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3012,7 +3012,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	struct netmap_adapter *na;
 	struct netmap_kring *kring;
 	struct netmap_ring *ring;
-	u_int i, check_all_tx, check_all_rx, want[NR_TXRX], revents = 0;
+	u_int i, want[NR_TXRX], revents = 0;
+	NM_SELINFO_T *si[NR_TXRX];
 #define want_tx want[NR_TX]
 #define want_rx want[NR_RX]
 	struct mbq q;	/* packets from RX hw queues to host stack */
@@ -3052,10 +3053,10 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	want_rx = events & (POLLIN | POLLRDNORM);
 
 	/*
-	 * check_all_{tx|rx} are set if the card has more than one queue AND
-	 * the file descriptor is bound to all of them. If so, we sleep on
-	 * the "global" selinfo, otherwise we sleep on individual selinfo
-	 * (FreeBSD only allows two selinfo's per file descriptor).
+	 * If the card has more than one queue AND the file descriptor is
+	 * bound to all of them, we sleep on the "global" selinfo, otherwise
+	 * we sleep on individual selinfo (FreeBSD only allows two selinfo's
+	 * per file descriptor).
 	 * The interrupt routine in the driver wake one or the other
 	 * (or both) depending on which clients are active.
 	 *
@@ -3064,8 +3065,10 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	 * there are pending packets to send. The latter can be disabled
 	 * passing NETMAP_NO_TX_POLL in the NIOCREG call.
 	 */
-	check_all_tx = nm_si_user(priv, NR_TX);
-	check_all_rx = nm_si_user(priv, NR_RX);
+	si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+	si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
 
 #ifdef __FreeBSD__
 	/*
@@ -3102,10 +3105,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 
 #ifdef linux
 	/* The selrecord must be unconditional on linux. */
-	nm_os_selrecord(sr, check_all_tx ?
-	    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]]->si);
-	nm_os_selrecord(sr, check_all_rx ?
-		&na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]]->si);
+	nm_os_selrecord(sr, si[NR_RX]);
+	nm_os_selrecord(sr, si[NR_TX]);
 #endif /* linux */
 
 	/*
@@ -3170,8 +3171,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		send_down = 0;
 		if (want_tx && retry_tx && sr) {
 #ifndef linux
-			nm_os_selrecord(sr, check_all_tx ?
-			    &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]]->si);
+			nm_os_selrecord(sr, si[NR_TX]);
 #endif /* !linux */
 			retry_tx = 0;
 			goto flush_tx;
@@ -3231,8 +3231,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 
 #ifndef linux
 		if (retry_rx && sr) {
-			nm_os_selrecord(sr, check_all_rx ?
-			    &na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]]->si);
+			nm_os_selrecord(sr, si[NR_RX]);
 		}
 #endif /* !linux */
 		if (send_down || retry_rx) {

From b8d6847fb24b35ee97d992338e6b6eee4a055b09 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 17:50:37 +0200
Subject: [PATCH 1086/2207] let np_flags store only nmreq->nr_flags

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 911523a26..5ab689430 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1859,7 +1859,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 			return EINVAL;
 		}
 	}
-	priv->np_flags = nr_flags | nr_mode; // TODO
+	priv->np_flags = nr_flags;
 
 	/* Allow transparent forwarding mode in the host --> nic
 	 * direction only if all the TX hw rings have been opened. */

From a50a431f276a4651586333bae31c36fc91fb22a1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 1 Oct 2018 10:02:36 +0200
Subject: [PATCH 1087/2207] fix typo

Reported by: bcr@freebsd.org
---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5ab689430..e52902840 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3875,7 +3875,7 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	struct ifnet *ifp = na->ifp;
 
 	/* We undo the setup for intercepting packets only if we are the
-	 * last user of this adapapter. */
+	 * last user of this adapter. */
 	if (na->active_fds > 0) {
 		return;
 	}

From 036286345d98fd887fb0bd2e2ab7313c82cade7c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 1 Oct 2018 11:21:49 +0200
Subject: [PATCH 1088/2207] linux: nm_os_kctx_create: fix typo

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index cfba69bd4..e7b8ddf07 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1865,7 +1865,7 @@ nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 	int error;
 
 	if (!cfg->use_kthread && cfg->notify_fn == NULL) {
-		D("Error: botify function missing with use_htead == 0");
+		D("Error: notify function missing with use_kthread == 0");
 		return NULL;
 	}
 

From 288bd7a46f8c3209ad45a87ca7cfc224531dff84 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 1 Oct 2018 11:28:13 +0200
Subject: [PATCH 1089/2207] freebsd: temporarily disable kthreads as they cause
 kernel crashes

---
 sys/dev/netmap/netmap_freebsd.c | 5 +++++
 utils/ctrl-api-test.c           | 7 +++++++
 2 files changed, 12 insertions(+)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index e8e68e6c0..11f641fa6 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1296,6 +1296,11 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 	struct proc *p = NULL;
 	int error = 0;
 
+	/* Temporarily disable this function as it is currently broken
+	 * and causes kernel crashes. The failure can be triggered by
+	 * the "vale_polling_enable_disable" test in ctrl-api-test.c. */
+	return EOPNOTSUPP;
+
 	if (nmk->worker) {
 		return EBUSY;
 	}
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 85042426a..462308346 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -530,6 +530,7 @@ vale_polling_enable_disable(struct TestContext *ctx)
 {
 	int ret = 0;
 
+
 	if ((ret = vale_attach(ctx))) {
 		return ret;
 	}
@@ -539,6 +540,12 @@ vale_polling_enable_disable(struct TestContext *ctx)
 	ctx->nr_first_cpu_id     = 0;
 	if ((ret = vale_polling_enable(ctx))) {
 		vale_detach(ctx);
+#ifdef __FreeBSD__
+		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
+		 * because it is currently broken. We are happy to see that
+		 * it fails. */
+		return 0;
+#endif
 		return ret;
 	}
 

From 56772af11c09bc12dc21000c044b4a0b0c7813b6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 1 Oct 2018 11:39:29 +0200
Subject: [PATCH 1090/2207] utils: ctrl-api-test: remove empty line added by
 mistake

---
 utils/ctrl-api-test.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 462308346..5a9a25005 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -530,7 +530,6 @@ vale_polling_enable_disable(struct TestContext *ctx)
 {
 	int ret = 0;
 
-
 	if ((ret = vale_attach(ctx))) {
 		return ret;
 	}

From 8b2831b05bd4872713ee059685d1211b8ec74d2b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Oct 2018 11:22:57 +0200
Subject: [PATCH 1091/2207] linux/i40e: remove globally shared debug counters

---
 LINUX/i40e_netmap_linux.h | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 90d95746d..3dcf5d056 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -46,7 +46,7 @@
 int i40e_netmap_txsync(struct netmap_kring *kring, int flags);
 int i40e_netmap_rxsync(struct netmap_kring *kring, int flags);
 
-extern int ix_rx_miss, ix_rx_miss_bufs, ix_crcstrip;
+extern int ix_crcstrip;
 
 #ifdef NETMAP_LINUX_I40E_PTR_ARRAY
 #define NM_I40E_TX_RING(a, r)		((a)->tx_rings[(r)])
@@ -71,18 +71,11 @@ extern int ix_rx_miss, ix_rx_miss_bufs, ix_crcstrip;
  *	so using crcstrip=0 helps in benchmarks.
  *      The driver by default strips CRCs and we do not override it.
  *
- * ix_rx_miss, ix_rx_miss_bufs:
- *	count packets that might be missed due to lost interrupts.
  */
 SYSCTL_DECL(_dev_netmap);
-int ix_rx_miss = 0, ix_rx_miss_bufs = 0, ix_crcstrip = 1;
+int ix_crcstrip = 1;
 SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
 		CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss,
-		CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss_bufs,
-		CTLFLAG_RW, &ix_rx_miss_bufs, 0, "potentially missed rx intr bufs");
-
 #if 0
 static void
 set_crcstrip(struct ixgbe_hw *hw, int onoff)
@@ -564,11 +557,6 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			nic_i = nm_next(nic_i, lim);
 		}
 		if (n) { /* update the state variables */
-			if (netmap_no_pendintr && !force_update) {
-				/* diagnostics */
-				ix_rx_miss ++;
-				ix_rx_miss_bufs += n;
-			}
 			rxr->next_to_clean = nic_i;
 			if (likely(ntail <= lim)) {
 				kring->nr_hwtail = ntail;

From fdbf40c8dd1e446b9a06d6fcd227bca9acf797b4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Oct 2018 15:34:46 +0200
Subject: [PATCH 1092/2207] linux/scripts: protect debug output string

---
 LINUX/netmap.mak.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 762cfe10b..067116b61 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -129,7 +129,7 @@ endef
 $(foreach a,$(APPS_LIST),$(eval $(call apps_actions,$(a))))
 
 +%:
-	@echo $($*)
+	@echo '$($*)'
 
 ifeq (,$(UTILS))
 utils:

From a1798d9e0265c06c1cf9105f6f2be9969762fe28 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Oct 2018 17:04:31 +0200
Subject: [PATCH 1093/2207] linux/scripts: comments on the driver build process

---
 LINUX/configure              |  1 +
 LINUX/default-config.mak.in_ | 65 ++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 2c1e17921..3ea6c0142 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -452,6 +452,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
+EXTRA_CFLAGS :=
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index c5f62bdef..272d35a9f 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -1,3 +1,63 @@
+###############################################################################
+# This files defines the default values of the external-drivers variables,
+# used by the configure script and the generated netmap.mak makefile.
+#
+# The variables are as follows:
+#
+# driver@v		the driver version
+# driver@fetch		how to fetch the sources into the ext-drivers directory
+# driver@src		how to extract the sources
+# driver@patch		which patch(es) to apply (whitespace-separated)
+# driver@prepare	how to prepare the sources for compilation
+# driver@build		how to build the driver
+# driver@install	how to install the driver
+# driver@clean		how to clean the driver build directory
+# driver@disclean	how to completely remove the driver build directory(ies)
+# driver@force		configure refuses to build drivers which are not
+# 			configured as modules in the kernel ".config". A 1 here
+# 			forces configure to skip this check.
+#
+# In the configuration phase, the configure script tries to determine whether
+# the external driver compiles by itself (i.e., independently of the netmap
+# patch) by running the driver@fetch; driver@src; driver@prepare; driver@build
+# commands (i.e., skipping the driver@patch). If this fails, a warning is
+# printed and the driver is disabled.
+#
+# During the build phase the same commands are executed again, but this time
+# the driver@patch is applied after driver@src and before driver@prepare.
+#
+# There should be no need to change this file if you just want to customize
+# these variables for a particular build: put the overrides into a config.mak
+# file in the build directory, before running configure.
+#
+# If you just want to select a different external-driver version, among the
+# ones for which there is a patch in LINUX/final-patches, use the
+# --select-version=driver:version option of configure.
+#
+#################################################################################
+
+
+# default-config.mak is generated from default-config.mak_ in the LINUX directory,
+# by replacing the recognized @VAR@ strings with the value of the named VAR
+# in the configure scripts. The most important recognized variables are
+#
+# SRCDIR	absolute path of the netmap/LINUX directory
+# KSRC		source directory of the linux kernel (headers should be sufficient
+# 		for external drivers)
+# KOPTS		options intended for the linux make (accumulated via the
+# 		--kernel-opts= configure option
+# DRVSUFFIX	the netmap driver suffix (--driver-suffix= configure option)
+# MODPATH	where to install the modules (--install-mod-path= from configure)
+# TMPDIR	the temporary directory where configure runs its tests (including
+# 		the test build of the unpatched driver)
+#
+# In the build phase, the EXTRA_CFLAGS variable will contain the values assigned
+# in the netmap.mak makefile. This is intended for options needed by the patched
+# driver. During the configure phase the variable is empty.
+
+
+# all the intel drivers are compiled in much the same way, so we factor them
+# here. $(1) is the driver name, while $(2) is the driver version
 define intel_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sourceforge.net/projects/e1000/files/$(1)%20stable/$(2)/$(1)-$(2).tar.gz -P @SRCDIR@/ext-drivers/
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
@@ -10,18 +70,23 @@ $(1)@distclean	:= rm -rf $(1)-$(2)
 $(1)@force	:= 1
 endef
 
+# set driver@v is not yet defined
 define default
 $(1)@v := $(if $($(1)@v),$($(1)@v),$(2))
 endef
 
+# some additional, driver-specific CFLAGS (used in the @build variable above)
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
+
+# set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.7))
 $(eval $(call default,ixgbevf,4.3.2))
 $(eval $(call default,e1000e,3.4.0.2))
 $(eval $(call default,igb,5.3.5.20))
 $(eval $(call default,i40e,2.4.6))
 
+# only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 
 define mellanox_driver

From 1d42df4906e47eca4ec6e10e59507cb83d2347ad Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 5 Oct 2018 16:17:21 +0200
Subject: [PATCH 1094/2207] linux: add support for building virtio_net.c as
 external driver

---
 LINUX/configure                               |  20 +-
 LINUX/default-config.mak.in_                  |  10 +
 LINUX/final-patches/custom--virtio_net.c--4.9 | 237 ++++++++++++++++++
 LINUX/netmap.mak.in                           |   2 +-
 LINUX/virtio_net.mak                          |  24 ++
 5 files changed, 286 insertions(+), 7 deletions(-)
 create mode 100644 LINUX/final-patches/custom--virtio_net.c--4.9
 create mode 100644 LINUX/virtio_net.mak

diff --git a/LINUX/configure b/LINUX/configure
index 3ea6c0142..12383ebeb 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -134,6 +134,7 @@ edrv enable ixgbe
 edrv enable ixgbevf
 edrv enable i40e
 edrv enable mlx5
+edrv enable virtio_net.c
 
 # drivers built by patching the system drivers
 setop internal_driver new driver
@@ -479,7 +480,7 @@ build-$d: prepare-$d
 	+\$($d@build)
 	touch build-$d
 patch-$d: get-$d
-	\$(foreach p,\$($d@patch),patch --posix --quiet --force -p1 < \$(p);)
+	\$(foreach p,\$($d@patch),patch --quiet --force -p1 < \$(p);)
 	touch patch-$d
 EOF
 	done
@@ -997,6 +998,13 @@ EOF
   }	
 
   for d in $(edrv print); do
+	if [ "$d" == virtio_net.c ]; then
+		# virtio_net.c as an external driver does not need to
+		# build unpatched, because it's tailored to a specific
+		# kernel version.
+		# TODO better solution? maybe generalize?
+		continue
+	fi
 	add_file_exists_check build-$d true "edrv_build_error $d"
   done
 
@@ -1776,7 +1784,7 @@ EOF
 
   if drv enabled virtio_net.c; then
   
-    add_file_exists_check virtio_net.c true "drv_source_error virtio_net.c"
+    add_file_exists_check virtio_net.c/virtio_net.c true "drv_source_error virtio_net.c"
   
     add_test 'define VIRTIO_CB_DELAYED' <
@@ -1797,7 +1805,7 @@ EOF
 EOF
   
     add_test 'define VIRTIO_FREE_PAGES' <mergeable_rx_bufs)
+ 			err = add_recvbuf_mergeable(rq, gfp);
+@@ -746,43 +745,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	return received;
+ }
+ 
+-#ifdef CONFIG_NET_RX_BUSY_POLL
+-/* must be called with local_bh_disable()d */
+-static int virtnet_busy_poll(struct napi_struct *napi)
+-{
+-	struct receive_queue *rq =
+-		container_of(napi, struct receive_queue, napi);
+-	struct virtnet_info *vi = rq->vq->vdev->priv;
+-	int r, received = 0, budget = 4;
+-
+-	if (!(vi->status & VIRTIO_NET_S_LINK_UP))
+-		return LL_FLUSH_FAILED;
+-
+-	if (!napi_schedule_prep(napi))
+-		return LL_FLUSH_BUSY;
+-
+-	virtqueue_disable_cb(rq->vq);
+-
+-again:
+-	received += virtnet_receive(rq, budget);
+-
+-	r = virtqueue_enable_cb_prepare(rq->vq);
+-	clear_bit(NAPI_STATE_SCHED, &napi->state);
+-	if (unlikely(virtqueue_poll(rq->vq, r)) &&
+-	    napi_schedule_prep(napi)) {
+-		virtqueue_disable_cb(rq->vq);
+-		if (received < budget) {
+-			budget -= received;
+-			goto again;
+-		} else {
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
+-#endif	/* CONFIG_NET_RX_BUSY_POLL */
+-
+ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+@@ -840,7 +802,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+ 		hdr = skb_vnet_hdr(skb);
+ 
+ 	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
+-				    virtio_is_little_endian(vi->vdev)))
++				    virtio_is_little_endian(vi->vdev)
++#define HAVE_DATA_VALID_ARG
++#define HAVE_VLAN_HLEN_ARG
++#ifdef  HAVE_DATA_VALID_ARG
++		, false
++#endif
++#ifdef  HAVE_VLAN_HLEN_ARG
++		, 0
++#endif
++))
+ 		BUG();
+ 
+ 	if (vi->mergeable_rx_bufs)
+@@ -1009,8 +980,13 @@ out:
+ 	return ret;
+ }
+ 
+-static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+-					       struct rtnl_link_stats64 *tot)
++#undef HAVE_VNET_STATS_RETURN
++#ifdef HAVE_VNET_STATS_RETURN
++static struct rtnl_link_stats64 *
++#else
++static void
++#endif
++virtnet_stats(struct net_device *dev, struct rtnl_link_stats64 *tot)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int cpu;
+@@ -1043,8 +1019,9 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+ 	tot->rx_dropped = dev->stats.rx_dropped;
+ 	tot->rx_length_errors = dev->stats.rx_length_errors;
+ 	tot->rx_frame_errors = dev->stats.rx_frame_errors;
+-
++#ifdef HAVE_VNET_STATS_RETURN
+ 	return tot;
++#endif
+ }
+ 
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+@@ -1453,9 +1430,6 @@ static const struct net_device_ops virtnet_netdev = {
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ 	.ndo_poll_controller = virtnet_netpoll,
+ #endif
+-#ifdef CONFIG_NET_RX_BUSY_POLL
+-	.ndo_busy_poll		= virtnet_busy_poll,
+-#endif
+ };
+ 
+ static void virtnet_config_changed_work(struct work_struct *work)
+@@ -1615,7 +1589,17 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+ 	}
+ 
+ 	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
+-					 names);
++					 names
++#define HAVE_FIND_VQS_CTX_ARG
++#define HAVE_FIND_VQS_IRQ_AFFINITY_ARG
++#ifdef HAVE_FIND_VQS_CTX_ARG
++					, NULL
++#endif
++#ifdef HAVE_FIND_VQS_IRQ_AFFINITY_ARG
++					, NULL
++#endif
++
++					);
+ 	if (ret)
+ 		goto err_find;
+ 
+@@ -1701,33 +1685,6 @@ err:
+ 	return ret;
+ }
+ 
+-#ifdef CONFIG_SYSFS
+-static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue,
+-		struct rx_queue_attribute *attribute, char *buf)
+-{
+-	struct virtnet_info *vi = netdev_priv(queue->dev);
+-	unsigned int queue_index = get_netdev_rx_queue_index(queue);
+-	struct ewma_pkt_len *avg;
+-
+-	BUG_ON(queue_index >= vi->max_queue_pairs);
+-	avg = &vi->rq[queue_index].mrg_avg_pkt_len;
+-	return sprintf(buf, "%u\n", get_mergeable_buf_len(avg));
+-}
+-
+-static struct rx_queue_attribute mergeable_rx_buffer_size_attribute =
+-	__ATTR_RO(mergeable_rx_buffer_size);
+-
+-static struct attribute *virtio_net_mrg_rx_attrs[] = {
+-	&mergeable_rx_buffer_size_attribute.attr,
+-	NULL
+-};
+-
+-static const struct attribute_group virtio_net_mrg_rx_group = {
+-	.name = "virtio_net",
+-	.attrs = virtio_net_mrg_rx_attrs
+-};
+-#endif
+-
+ static bool virtnet_fail_on_feature(struct virtio_device *vdev,
+ 				    unsigned int fbit,
+ 				    const char *fname, const char *dname)
+@@ -1811,7 +1768,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+ 
+ 		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
+-			dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
++			dev->hw_features |= NETIF_F_TSO
+ 				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
+ 		}
+ 		/* Individual feature bits: what can host handle? */
+@@ -1821,13 +1778,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			dev->hw_features |= NETIF_F_TSO6;
+ 		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
+ 			dev->hw_features |= NETIF_F_TSO_ECN;
+-		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+-			dev->hw_features |= NETIF_F_UFO;
+ 
+ 		dev->features |= NETIF_F_GSO_ROBUST;
+ 
+ 		if (gso)
+-			dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO);
++			dev->features |= dev->hw_features & (NETIF_F_ALL_TSO);
+ 		/* (!csum && gso) case will be fixed by register_netdev() */
+ 	}
+ 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
+@@ -1905,10 +1860,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 	if (err)
+ 		goto free_stats;
+ 
+-#ifdef CONFIG_SYSFS
+-	if (vi->mergeable_rx_bufs)
+-		dev->sysfs_rx_queue_group = &virtio_net_mrg_rx_group;
+-#endif
+ 	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
+ 	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
+ 
+diff --git a/virtio_net.c/virtio_net_src.c b/virtio_net.c/virtio_net_src.c
+new file mode 120000
+index 0000000..e2a5c2a
+--- /dev/null
++++ b/virtio_net.c/virtio_net_src.c
+@@ -0,0 +1 @@
++virtio_net.c
+\ No newline at end of file
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 067116b61..b069f57ea 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -53,7 +53,7 @@ define common_driver
 get-$(1):
 	$($(1)@fetch)
 	$($(1)@src)
-	$(foreach p,$($(1)@patch),patch --posix --quiet --force -p1 < $(p);)
+	$(foreach p,$($(1)@patch),patch --quiet --force -p1 < $(p);)
 	$($(1)@prepare)
 	$(if $($(1)@build),,$(if $(filter-out %.c,$(1)),mv $(1)/Makefile $(1)/orig.mak || mv $(1)/Kbuild $(1)/orig.mak; cp drv-subdir.mak $(1)/Makefile,))
 	touch get-$(1)
diff --git a/LINUX/virtio_net.mak b/LINUX/virtio_net.mak
new file mode 100644
index 000000000..189f5cb35
--- /dev/null
+++ b/LINUX/virtio_net.mak
@@ -0,0 +1,24 @@
+ifneq ($(KERNELRELEASE),)
+
+# virtio_net_src.c is just a symbolic link to virtio_net.c
+# This workaround is needed because when defining modulename-y
+# it is not possible to have a source called "modulename.c".
+# Note that this is a problem only when NETMAP_DRIVER_SUFFIX
+# is empty.
+obj-m := virtio_net$(NETMAP_DRIVER_SUFFIX).o
+virtio_net$(NETMAP_DRIVER_SUFFIX)-y := virtio_net_src.o
+
+else
+
+KSRC ?= /lib/modules/$(shell uname -r)/build
+
+all: virtio_net.c
+	$(MAKE) -C "${KSRC}" M=$(shell pwd) modules
+
+install:
+	$(MAKE) -C "${KSRC}" M=$(shell pwd) modules_install
+
+clean:
+	$(MAKE) -C "${KSRC}" M=$(shell pwd) clean
+
+endif

From f126cdda96429f05d95618ecc567c64d6f565518 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 5 Oct 2018 17:10:21 +0200
Subject: [PATCH 1095/2207] configure: add compile time checks specific to
 virtio-net

---
 LINUX/configure                               | 45 +++++++++++++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 65 ++++++++++++-------
 2 files changed, 85 insertions(+), 25 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 12383ebeb..d2c614401 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1786,6 +1786,51 @@ EOF
   
     add_file_exists_check virtio_net.c/virtio_net.c true "drv_source_error virtio_net.c"
   
+    add_test 'define VIRTIO_NET_HDR_FROM_SKB_5ARGS' <
+
+	int
+	dummy(const struct sk_buff *skb, struct virtio_net_hdr *hdr,
+		bool little_endian, bool has_data_valid, int vlan_hlen) {
+		return virtio_net_hdr_from_skb(skb, hdr, little_endian,
+					has_data_valid, vlan_hlen);
+	}
+EOF
+
+    add_test 'define VIRTIO_NET_HDR_FROM_SKB_4ARGS' <
+
+	int
+	dummy(const struct sk_buff *skb, struct virtio_net_hdr *hdr,
+		bool little_endian, bool has_data_valid) {
+		return virtio_net_hdr_from_skb(skb, hdr, little_endian,
+					has_data_valid);
+	}
+EOF
+
+  add_test 'have FIND_VQS_CTX_ARG' <
+
+	int
+	dummy(struct virtio_config_ops *ops, const bool *ctx,
+		struct irq_affinity *desc)
+	{
+		return ops->find_vqs(NULL, 0, NULL, NULL, NULL,
+					ctx, desc);
+	}
+EOF
+
+  add_test 'have FIND_VQS_IRQAFF_ARG' <
+
+	int
+	dummy(struct virtio_config_ops *ops, struct irq_affinity *desc)
+	{
+		return ops->find_vqs(NULL, 0, NULL, NULL, NULL,
+					desc);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index c7562c069..624c704dd 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -1,9 +1,9 @@
 diff --git a/virtio_net.c/Makefile b/virtio_net.c/Makefile
 new file mode 100644
-index 0000000..189f5cb
+index 0000000..cf1c844
 --- /dev/null
 +++ b/virtio_net.c/Makefile
-@@ -0,0 +1,24 @@
+@@ -0,0 +1,25 @@
 +ifneq ($(KERNELRELEASE),)
 +
 +# virtio_net_src.c is just a symbolic link to virtio_net.c
@@ -11,6 +11,7 @@ index 0000000..189f5cb
 +# it is not possible to have a source called "modulename.c".
 +# Note that this is a problem only when NETMAP_DRIVER_SUFFIX
 +# is empty.
++EXTRA_CFLAGS := "${CFLAGS_EXTRA}"
 +obj-m := virtio_net$(NETMAP_DRIVER_SUFFIX).o
 +virtio_net$(NETMAP_DRIVER_SUFFIX)-y := virtio_net_src.o
 +
@@ -29,10 +30,21 @@ index 0000000..189f5cb
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..0f3bd18 100644
+index cbf1c61..6d170f7 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
-@@ -637,7 +637,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -29,6 +29,10 @@
+ #include 
+ #include 
+ 
++#include 
++#include 
++#include 
++
+ static int napi_weight = NAPI_POLL_WEIGHT;
+ module_param(napi_weight, int, 0444);
+ 
+@@ -637,7 +641,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -40,7 +52,7 @@ index cbf1c61..0f3bd18 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -746,43 +745,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +749,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -84,32 +96,29 @@ index cbf1c61..0f3bd18 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +802,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +806,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
 -				    virtio_is_little_endian(vi->vdev)))
 +				    virtio_is_little_endian(vi->vdev)
-+#define HAVE_DATA_VALID_ARG
-+#define HAVE_VLAN_HLEN_ARG
-+#ifdef  HAVE_DATA_VALID_ARG
++#if defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) || defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS)
 +		, false
 +#endif
-+#ifdef  HAVE_VLAN_HLEN_ARG
++#if defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS)
 +		, 0
 +#endif
 +))
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -1009,8 +980,13 @@ out:
+@@ -1009,8 +982,12 @@ out:
  	return ret;
  }
  
 -static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
 -					       struct rtnl_link_stats64 *tot)
-+#undef HAVE_VNET_STATS_RETURN
-+#ifdef HAVE_VNET_STATS_RETURN
++#ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64
 +static struct rtnl_link_stats64 *
 +#else
 +static void
@@ -118,18 +127,26 @@ index cbf1c61..0f3bd18 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,8 +1019,9 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,8 +1020,9 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
 -
-+#ifdef HAVE_VNET_STATS_RETURN
++#ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64
  	return tot;
 +#endif
  }
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
-@@ -1453,9 +1430,6 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1447,15 +1425,14 @@ static const struct net_device_ops virtnet_netdev = {
+ 	.ndo_set_mac_address = virtnet_set_mac_address,
+ 	.ndo_set_rx_mode     = virtnet_set_rx_mode,
+ 	.ndo_change_mtu	     = virtnet_change_mtu,
++#ifdef NETMAP_LINUX_HAVE_GET_STATS64
+ 	.ndo_get_stats64     = virtnet_stats,
++#endif
+ 	.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
+ 	.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
  #ifdef CONFIG_NET_POLL_CONTROLLER
  	.ndo_poll_controller = virtnet_netpoll,
  #endif
@@ -139,18 +156,16 @@ index cbf1c61..0f3bd18 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1615,7 +1589,17 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1592,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
 -					 names);
 +					 names
-+#define HAVE_FIND_VQS_CTX_ARG
-+#define HAVE_FIND_VQS_IRQ_AFFINITY_ARG
-+#ifdef HAVE_FIND_VQS_CTX_ARG
++#if defined(NETMAP_LINUX_HAVE_FIND_VQS_CTX_ARG)
 +					, NULL
 +#endif
-+#ifdef HAVE_FIND_VQS_IRQ_AFFINITY_ARG
++#if defined(NETMAP_LINUX_HAVE_FIND_VQS_CTX_ARG) || defined(NETMAP_LINUX_HAVE_FIND_VQS_IRQAFF_ARG)
 +					, NULL
 +#endif
 +
@@ -158,7 +173,7 @@ index cbf1c61..0f3bd18 100644
  	if (ret)
  		goto err_find;
  
-@@ -1701,33 +1685,6 @@ err:
+@@ -1701,33 +1686,6 @@ err:
  	return ret;
  }
  
@@ -192,7 +207,7 @@ index cbf1c61..0f3bd18 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1768,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1769,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -201,7 +216,7 @@ index cbf1c61..0f3bd18 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1778,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1779,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -216,7 +231,7 @@ index cbf1c61..0f3bd18 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1860,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1861,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  

From 860a868dd0c20c80dc3e8f4af358e95e0f19988a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 5 Oct 2018 17:34:28 +0200
Subject: [PATCH 1096/2207] virtio_net.c: fix compilation as an external driver

---
 LINUX/default-config.mak.in_                  | 6 +++---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 512255e81..239411c9a 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -111,8 +111,8 @@ virtio_net.c@fetch	:= test -e @SRCDIR@/ext-drivers/virtio_net.c || wget https://
 virtio_net.c@src	:= mkdir -p virtio_net.c && cp @SRCDIR@/ext-drivers/virtio_net.c virtio_net.c/
 virtio_net.c@patch	:= patches/custom--virtio_net.c--4.9
 virtio_net.c@prepare	:=
-virtio_net.c@build 	:= make -C virtio_net.c CFLAGS_EXTRA="$(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
-virtio_net.c@install 	:= make -C virtio_net.c install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
-virtio_net.c@clean 	:= if [ -d virtio_net.c ]; then make -C virtio_net.c clean CFLAGS_EXTRA="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
+virtio_net.c@build 	:= make -C virtio_net.c EXTRA_CFLAGS="$(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+virtio_net.c@install 	:= make -C virtio_net.c install INSTALL_MOD_PATH=@MODPATH@ EXTRA_CFLAGS="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+virtio_net.c@clean 	:= if [ -d virtio_net.c ]; then make -C virtio_net.c clean EXTRA_CFLAGS="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
 virtio_net.c@distclean	:=
 virtio_net.c@force	:= 1
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 624c704dd..90474ed8c 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -1,6 +1,6 @@
 diff --git a/virtio_net.c/Makefile b/virtio_net.c/Makefile
 new file mode 100644
-index 0000000..cf1c844
+index 0000000..2c88957
 --- /dev/null
 +++ b/virtio_net.c/Makefile
 @@ -0,0 +1,25 @@
@@ -11,7 +11,7 @@ index 0000000..cf1c844
 +# it is not possible to have a source called "modulename.c".
 +# Note that this is a problem only when NETMAP_DRIVER_SUFFIX
 +# is empty.
-+EXTRA_CFLAGS := "${CFLAGS_EXTRA}"
++EXTRA_CFLAGS += "${EXTRA_CFLAGS}"
 +obj-m := virtio_net$(NETMAP_DRIVER_SUFFIX).o
 +virtio_net$(NETMAP_DRIVER_SUFFIX)-y := virtio_net_src.o
 +

From 83da113d44a1c9dc4fa5c4b0a7c001aa6d1fb345 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 6 Oct 2018 12:34:36 +0200
Subject: [PATCH 1097/2207] linux: virtio-net: upgrade patch to cover more
 kernels

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 75 +++++++++++++++----
 1 file changed, 59 insertions(+), 16 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 90474ed8c..78acbd4c2 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..6d170f7 100644
+index cbf1c61..d9d7e73 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -29,6 +29,10 @@
@@ -44,7 +44,21 @@ index cbf1c61..6d170f7 100644
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
  
-@@ -637,7 +641,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -263,7 +267,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+ 	p = page_address(page) + offset;
+ 
+ 	/* copy small packet so we can reuse these pages for small data */
++#ifdef NETMAP_LINUX_HAVE_NAPI_ALLOC_SKB
+ 	skb = napi_alloc_skb(&rq->napi, GOOD_COPY_LEN);
++#elif defined(NETMAP_LINUX_HAVE_ALLOC_SKB_IP_ALIGN)
++	skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
++#else
++	skb = netdev_alloc_csb(vi->dev, GOOD_COPY_LEN);
++#endif
+ 	if (unlikely(!skb))
+ 		return NULL;
+ 
+@@ -637,7 +647,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -52,7 +66,19 @@ index cbf1c61..6d170f7 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -746,43 +749,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +744,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	/* Out of packets? */
+ 	if (received < budget) {
+ 		r = virtqueue_enable_cb_prepare(rq->vq);
++#ifdef NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE
+ 		napi_complete_done(napi, received);
++#else  /* !NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE */
++		napi_complete(napi);
++#endif /* !NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE */
+ 		if (unlikely(virtqueue_poll(rq->vq, r)) &&
+ 		    napi_schedule_prep(napi)) {
+ 			virtqueue_disable_cb(rq->vq);
+@@ -746,43 +759,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -96,7 +122,7 @@ index cbf1c61..6d170f7 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +806,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +816,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -112,36 +138,53 @@ index cbf1c61..6d170f7 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -1009,8 +982,12 @@ out:
+@@ -866,7 +849,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 	struct send_queue *sq = &vi->sq[qnum];
+ 	int err;
+ 	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
++#ifdef NETMAP_LINUX_HAVE_XMIT_MORE
+ 	bool kick = !skb->xmit_more;
++#else  /* !NETMAP_LINUX_HAVE_XMIT_MORE */
++	bool kick = true;
++#endif /* !NETMAP_LINUX_HAVE_XMIT_MORE */
+ 
+ 	/* Free up any pending old buffers before queueing new ones. */
+ 	free_old_xmit_skbs(sq);
+@@ -1009,8 +996,13 @@ out:
  	return ret;
  }
  
 -static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
 -					       struct rtnl_link_stats64 *tot)
++#ifdef NETMAP_LINUX_HAVE_GET_STATS64
 +#ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64
 +static struct rtnl_link_stats64 *
-+#else
++#else  /* !NETMAP_LINUX_HAVE_NONVOID_GET_STATS64 */
 +static void
-+#endif
++#endif /* !NETMAP_LINUX_HAVE_NONVOID_GET_STATS64 */
 +virtnet_stats(struct net_device *dev, struct rtnl_link_stats64 *tot)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,8 +1020,9 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1035,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
 -
 +#ifdef NETMAP_LINUX_HAVE_NONVOID_GET_STATS64
  	return tot;
-+#endif
++#endif  /* NETMAP_LINUX_HAVE_NONVOID_GET_STATS64 */
  }
++#endif  /* NETMAP_LINUX_HAVE_GET_STATS64 */
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
-@@ -1447,15 +1425,14 @@ static const struct net_device_ops virtnet_netdev = {
+ static void virtnet_netpoll(struct net_device *dev)
+@@ -1446,16 +1440,15 @@ static const struct net_device_ops virtnet_netdev = {
+ 	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
- 	.ndo_change_mtu	     = virtnet_change_mtu,
+-	.ndo_change_mtu	     = virtnet_change_mtu,
++	.NETMAP_LINUX_CHANGE_MTU = virtnet_change_mtu,
 +#ifdef NETMAP_LINUX_HAVE_GET_STATS64
  	.ndo_get_stats64     = virtnet_stats,
 +#endif
@@ -156,7 +199,7 @@ index cbf1c61..6d170f7 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1615,7 +1592,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1608,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -173,7 +216,7 @@ index cbf1c61..6d170f7 100644
  	if (ret)
  		goto err_find;
  
-@@ -1701,33 +1686,6 @@ err:
+@@ -1701,33 +1702,6 @@ err:
  	return ret;
  }
  
@@ -207,7 +250,7 @@ index cbf1c61..6d170f7 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1769,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1785,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -216,7 +259,7 @@ index cbf1c61..6d170f7 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1779,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1795,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -231,7 +274,7 @@ index cbf1c61..6d170f7 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1861,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1877,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  

From 66ef901b9e06d8ffe4a0aaf1924a737b4ccea5e5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 6 Oct 2018 19:22:19 +0200
Subject: [PATCH 1098/2207] linux: virtio_net.c: update custom patch to remove
 CPU hotplug support

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 265 +++++++++++++++++-
 1 file changed, 250 insertions(+), 15 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 78acbd4c2..7a53a681a 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..d9d7e73 100644
+index cbf1c61..3399011 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -29,6 +29,10 @@
@@ -44,7 +44,21 @@ index cbf1c61..d9d7e73 100644
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
  
-@@ -263,7 +267,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -135,13 +139,6 @@ struct virtnet_info {
+ 	/* Work struct for config space updates */
+ 	struct work_struct config_work;
+ 
+-	/* Does the affinity hint is set for virtqueues? */
+-	bool affinity_hint_set;
+-
+-	/* CPU hotplug instances for online & dead */
+-	struct hlist_node node;
+-	struct hlist_node node_dead;
+-
+ 	/* Control VQ buffers: protected by the rtnl lock */
+ 	struct virtio_net_ctrl_hdr ctrl_hdr;
+ 	virtio_net_ctrl_ack ctrl_status;
+@@ -263,7 +260,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -58,7 +72,7 @@ index cbf1c61..d9d7e73 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +647,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +640,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -66,7 +80,7 @@ index cbf1c61..d9d7e73 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +744,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +737,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -78,7 +92,7 @@ index cbf1c61..d9d7e73 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +759,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +752,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -122,7 +136,7 @@ index cbf1c61..d9d7e73 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +816,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +809,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -138,7 +152,7 @@ index cbf1c61..d9d7e73 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +849,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +842,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -150,7 +164,7 @@ index cbf1c61..d9d7e73 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +996,13 @@ out:
+@@ -1009,8 +989,13 @@ out:
  	return ret;
  }
  
@@ -166,7 +180,7 @@ index cbf1c61..d9d7e73 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1035,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1028,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -179,7 +193,112 @@ index cbf1c61..d9d7e73 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1446,16 +1440,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1207,95 +1194,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+ 	return 0;
+ }
+ 
+-static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
+-{
+-	int i;
+-
+-	if (vi->affinity_hint_set) {
+-		for (i = 0; i < vi->max_queue_pairs; i++) {
+-			virtqueue_set_affinity(vi->rq[i].vq, -1);
+-			virtqueue_set_affinity(vi->sq[i].vq, -1);
+-		}
+-
+-		vi->affinity_hint_set = false;
+-	}
+-}
+-
+-static void virtnet_set_affinity(struct virtnet_info *vi)
+-{
+-	int i;
+-	int cpu;
+-
+-	/* In multiqueue mode, when the number of cpu is equal to the number of
+-	 * queue pairs, we let the queue pairs to be private to one cpu by
+-	 * setting the affinity hint to eliminate the contention.
+-	 */
+-	if (vi->curr_queue_pairs == 1 ||
+-	    vi->max_queue_pairs != num_online_cpus()) {
+-		virtnet_clean_affinity(vi, -1);
+-		return;
+-	}
+-
+-	i = 0;
+-	for_each_online_cpu(cpu) {
+-		virtqueue_set_affinity(vi->rq[i].vq, cpu);
+-		virtqueue_set_affinity(vi->sq[i].vq, cpu);
+-		netif_set_xps_queue(vi->dev, cpumask_of(cpu), i);
+-		i++;
+-	}
+-
+-	vi->affinity_hint_set = true;
+-}
+-
+-static int virtnet_cpu_online(unsigned int cpu, struct hlist_node *node)
+-{
+-	struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
+-						   node);
+-	virtnet_set_affinity(vi);
+-	return 0;
+-}
+-
+-static int virtnet_cpu_dead(unsigned int cpu, struct hlist_node *node)
+-{
+-	struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
+-						   node_dead);
+-	virtnet_set_affinity(vi);
+-	return 0;
+-}
+-
+-static int virtnet_cpu_down_prep(unsigned int cpu, struct hlist_node *node)
+-{
+-	struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
+-						   node);
+-
+-	virtnet_clean_affinity(vi, cpu);
+-	return 0;
+-}
+-
+-static enum cpuhp_state virtionet_online;
+-
+-static int virtnet_cpu_notif_add(struct virtnet_info *vi)
+-{
+-	int ret;
+-
+-	ret = cpuhp_state_add_instance_nocalls(virtionet_online, &vi->node);
+-	if (ret)
+-		return ret;
+-	ret = cpuhp_state_add_instance_nocalls(CPUHP_VIRT_NET_DEAD,
+-					       &vi->node_dead);
+-	if (!ret)
+-		return ret;
+-	cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
+-	return ret;
+-}
+-
+-static void virtnet_cpu_notif_remove(struct virtnet_info *vi)
+-{
+-	cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
+-	cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_NET_DEAD,
+-					    &vi->node_dead);
+-}
+-
+ static void virtnet_get_ringparam(struct net_device *dev,
+ 				struct ethtool_ringparam *ring)
+ {
+@@ -1342,8 +1240,6 @@ static int virtnet_set_channels(struct net_device *dev,
+ 	if (!err) {
+ 		netif_set_real_num_tx_queues(dev, queue_pairs);
+ 		netif_set_real_num_rx_queues(dev, queue_pairs);
+-
+-		virtnet_set_affinity(vi);
+ 	}
+ 	put_online_cpus();
+ 
+@@ -1446,16 +1342,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -199,7 +318,16 @@ index cbf1c61..d9d7e73 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1615,7 +1608,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1460,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+ {
+ 	struct virtio_device *vdev = vi->vdev;
+ 
+-	virtnet_clean_affinity(vi, -1);
+-
+ 	vdev->config->del_vqs(vdev);
+ 
+ 	virtnet_free_queues(vi);
+@@ -1615,7 +1508,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -216,7 +344,18 @@ index cbf1c61..d9d7e73 100644
  	if (ret)
  		goto err_find;
  
-@@ -1701,33 +1702,6 @@ err:
+@@ -1689,10 +1590,6 @@ static int init_vqs(struct virtnet_info *vi)
+ 	if (ret)
+ 		goto err_free;
+ 
+-	get_online_cpus();
+-	virtnet_set_affinity(vi);
+-	put_online_cpus();
+-
+ 	return 0;
+ 
+ err_free:
+@@ -1701,33 +1598,6 @@ err:
  	return ret;
  }
  
@@ -250,7 +389,7 @@ index cbf1c61..d9d7e73 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1785,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1681,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -259,7 +398,7 @@ index cbf1c61..d9d7e73 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1795,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1691,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -274,7 +413,7 @@ index cbf1c61..d9d7e73 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1877,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1773,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -285,6 +424,102 @@ index cbf1c61..d9d7e73 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
+@@ -1922,12 +1786,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	virtio_device_ready(vdev);
+ 
+-	err = virtnet_cpu_notif_add(vi);
+-	if (err) {
+-		pr_debug("virtio_net: registering cpu notifier failed\n");
+-		goto free_unregister_netdev;
+-	}
+-
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+@@ -1943,10 +1801,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	return 0;
+ 
+-free_unregister_netdev:
+-	vi->vdev->config->reset(vdev);
+-
+-	unregister_netdev(dev);
+ free_vqs:
+ 	cancel_delayed_work_sync(&vi->refill);
+ 	free_receive_page_frags(vi);
+@@ -1976,8 +1830,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
+ 
+-	virtnet_cpu_notif_remove(vi);
+-
+ 	/* Make sure no work handler is accessing the device. */
+ 	flush_work(&vi->config_work);
+ 
+@@ -1995,8 +1847,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+ 	struct virtnet_info *vi = vdev->priv;
+ 	int i;
+ 
+-	virtnet_cpu_notif_remove(vi);
+-
+ 	/* Make sure no work handler is accessing the device */
+ 	flush_work(&vi->config_work);
+ 
+@@ -2039,10 +1889,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+ 	virtnet_set_queues(vi, vi->curr_queue_pairs);
+ 	rtnl_unlock();
+ 
+-	err = virtnet_cpu_notif_add(vi);
+-	if (err)
+-		return err;
+-
+ 	return 0;
+ }
+ #endif
+@@ -2091,41 +1937,7 @@ static struct virtio_driver virtio_net_driver = {
+ #endif
+ };
+ 
+-static __init int virtio_net_driver_init(void)
+-{
+-	int ret;
+-
+-	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "AP_VIRT_NET_ONLINE",
+-				      virtnet_cpu_online,
+-				      virtnet_cpu_down_prep);
+-	if (ret < 0)
+-		goto out;
+-	virtionet_online = ret;
+-	ret = cpuhp_setup_state_multi(CPUHP_VIRT_NET_DEAD, "VIRT_NET_DEAD",
+-				      NULL, virtnet_cpu_dead);
+-	if (ret)
+-		goto err_dead;
+-
+-        ret = register_virtio_driver(&virtio_net_driver);
+-	if (ret)
+-		goto err_virtio;
+-	return 0;
+-err_virtio:
+-	cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
+-err_dead:
+-	cpuhp_remove_multi_state(virtionet_online);
+-out:
+-	return ret;
+-}
+-module_init(virtio_net_driver_init);
+-
+-static __exit void virtio_net_driver_exit(void)
+-{
+-	cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
+-	cpuhp_remove_multi_state(virtionet_online);
+-	unregister_virtio_driver(&virtio_net_driver);
+-}
+-module_exit(virtio_net_driver_exit);
++module_virtio_driver(virtio_net_driver);
+ 
+ MODULE_DEVICE_TABLE(virtio, id_table);
+ MODULE_DESCRIPTION("Virtio network driver");
 diff --git a/virtio_net.c/virtio_net_src.c b/virtio_net.c/virtio_net_src.c
 new file mode 120000
 index 0000000..e2a5c2a

From ae6f3eaeaf53f539081d90caceed5fc69057adc7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 6 Oct 2018 19:31:05 +0200
Subject: [PATCH 1099/2207] linux: virtio_net.c: upgrade patch to remove unused
 include

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 63 ++++++++++---------
 1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 7a53a681a..a35fb7101 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,21 +30,22 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..3399011 100644
+index cbf1c61..56e34b9 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
-@@ -29,6 +29,10 @@
+@@ -27,7 +27,10 @@
+ #include 
+ #include 
  #include 
- #include 
- 
+-#include 
++
 +#include 
 +#include 
 +#include 
-+
+ 
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
- 
-@@ -135,13 +139,6 @@ struct virtnet_info {
+@@ -135,13 +138,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -58,7 +59,7 @@ index cbf1c61..3399011 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +260,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +259,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -72,7 +73,7 @@ index cbf1c61..3399011 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +640,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +639,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -80,7 +81,7 @@ index cbf1c61..3399011 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +737,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +736,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -92,7 +93,7 @@ index cbf1c61..3399011 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +752,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +751,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -136,7 +137,7 @@ index cbf1c61..3399011 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +809,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +808,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -152,7 +153,7 @@ index cbf1c61..3399011 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +842,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +841,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -164,7 +165,7 @@ index cbf1c61..3399011 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +989,13 @@ out:
+@@ -1009,8 +988,13 @@ out:
  	return ret;
  }
  
@@ -180,7 +181,7 @@ index cbf1c61..3399011 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1028,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1027,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -193,7 +194,7 @@ index cbf1c61..3399011 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1194,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1193,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -289,7 +290,7 @@ index cbf1c61..3399011 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1240,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1239,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -298,7 +299,7 @@ index cbf1c61..3399011 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1342,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1341,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -318,7 +319,7 @@ index cbf1c61..3399011 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1460,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1459,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -327,7 +328,7 @@ index cbf1c61..3399011 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1508,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1507,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -344,7 +345,7 @@ index cbf1c61..3399011 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1590,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1589,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -355,7 +356,7 @@ index cbf1c61..3399011 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1598,6 @@ err:
+@@ -1701,33 +1597,6 @@ err:
  	return ret;
  }
  
@@ -389,7 +390,7 @@ index cbf1c61..3399011 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1681,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1680,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -398,7 +399,7 @@ index cbf1c61..3399011 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1691,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1690,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -413,7 +414,7 @@ index cbf1c61..3399011 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1773,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1772,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -424,7 +425,7 @@ index cbf1c61..3399011 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1786,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1785,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -437,7 +438,7 @@ index cbf1c61..3399011 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1801,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1800,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -448,7 +449,7 @@ index cbf1c61..3399011 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1830,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1829,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -457,7 +458,7 @@ index cbf1c61..3399011 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1847,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1846,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -466,7 +467,7 @@ index cbf1c61..3399011 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1889,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1888,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -477,7 +478,7 @@ index cbf1c61..3399011 100644
  	return 0;
  }
  #endif
-@@ -2091,41 +1937,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +1936,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 87ec6e7bf00bafe79fd3300569e91704f7a147cf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 10:04:04 +0200
Subject: [PATCH 1100/2207] linux: virtio_net.c: define
 virtio_net_hdr_{from|to}_skb if not defined

---
 LINUX/configure                               |  10 ++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 157 +++++++++++++++---
 2 files changed, 141 insertions(+), 26 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index d2c614401..01be8270b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1808,6 +1808,16 @@ EOF
 	}
 EOF
 
+    add_test 'define VIRTIO_NET_HDR_FROM_SKB_3ARGS' <
+
+	int
+	dummy(const struct sk_buff *skb, struct virtio_net_hdr *hdr,
+		bool little_endian) {
+		return virtio_net_hdr_from_skb(skb, hdr, little_endian);
+	}
+EOF
+
   add_test 'have FIND_VQS_CTX_ARG' <
 
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index a35fb7101..6cefa602e 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..56e34b9 100644
+index cbf1c61..60a0898 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -45,7 +45,112 @@ index cbf1c61..56e34b9 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -135,13 +138,6 @@ struct virtnet_info {
+@@ -52,6 +55,104 @@ DECLARE_EWMA(pkt_len, 1, 64)
+ 
+ #define VIRTNET_DRIVER_VERSION "1.0.0"
+ 
++#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
++static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
++					const struct virtio_net_hdr *hdr,
++					bool little_endian)
++{
++	unsigned short gso_type = 0;
++
++	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
++		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
++		case VIRTIO_NET_HDR_GSO_TCPV4:
++			gso_type = SKB_GSO_TCPV4;
++			break;
++		case VIRTIO_NET_HDR_GSO_TCPV6:
++			gso_type = SKB_GSO_TCPV6;
++			break;
++		case VIRTIO_NET_HDR_GSO_UDP:
++			gso_type = SKB_GSO_UDP;
++			break;
++		default:
++			return -EINVAL;
++		}
++
++		if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
++			gso_type |= SKB_GSO_TCP_ECN;
++
++		if (hdr->gso_size == 0)
++			return -EINVAL;
++	}
++
++	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
++		u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
++		u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
++
++		if (!skb_partial_csum_set(skb, start, off))
++			return -EINVAL;
++	}
++
++	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
++		u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
++
++		skb_shinfo(skb)->gso_size = gso_size;
++		skb_shinfo(skb)->gso_type = gso_type;
++
++		/* Header must be checked, and gso_segs computed. */
++		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++		skb_shinfo(skb)->gso_segs = 0;
++	}
++
++	return 0;
++}
++
++static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
++					  struct virtio_net_hdr *hdr,
++					  bool little_endian,
++					  bool has_data_valid)
++{
++	memset(hdr, 0, sizeof(*hdr));
++
++	if (skb_is_gso(skb)) {
++		struct skb_shared_info *sinfo = skb_shinfo(skb);
++
++		/* This is a hint as to how much should be linear. */
++		hdr->hdr_len = __cpu_to_virtio16(little_endian,
++						 skb_headlen(skb));
++		hdr->gso_size = __cpu_to_virtio16(little_endian,
++						  sinfo->gso_size);
++		if (sinfo->gso_type & SKB_GSO_TCPV4)
++			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
++		else if (sinfo->gso_type & SKB_GSO_TCPV6)
++			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
++		else if (sinfo->gso_type & SKB_GSO_UDP)
++			hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
++		else
++			return -EINVAL;
++		if (sinfo->gso_type & SKB_GSO_TCP_ECN)
++			hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
++	} else
++		hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
++
++	if (skb->ip_summed == CHECKSUM_PARTIAL) {
++		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
++		if (skb_vlan_tag_present(skb))
++			hdr->csum_start = __cpu_to_virtio16(little_endian,
++				skb_checksum_start_offset(skb) + VLAN_HLEN);
++		else
++			hdr->csum_start = __cpu_to_virtio16(little_endian,
++				skb_checksum_start_offset(skb));
++		hdr->csum_offset = __cpu_to_virtio16(little_endian,
++				skb->csum_offset);
++	} else if (has_data_valid &&
++		   skb->ip_summed == CHECKSUM_UNNECESSARY) {
++		hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
++	} /* else everything is zero */
++
++	return 0;
++}
++#endif
++
+ struct virtnet_stats {
+ 	struct u64_stats_sync tx_syncp;
+ 	struct u64_stats_sync rx_syncp;
+@@ -135,13 +236,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -59,7 +164,7 @@ index cbf1c61..56e34b9 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +259,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +357,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -73,7 +178,7 @@ index cbf1c61..56e34b9 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +639,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +737,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -81,7 +186,7 @@ index cbf1c61..56e34b9 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +736,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +834,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -93,7 +198,7 @@ index cbf1c61..56e34b9 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +751,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +849,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -137,7 +242,7 @@ index cbf1c61..56e34b9 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +808,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +906,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -153,7 +258,7 @@ index cbf1c61..56e34b9 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +841,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +939,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -165,7 +270,7 @@ index cbf1c61..56e34b9 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +988,13 @@ out:
+@@ -1009,8 +1086,13 @@ out:
  	return ret;
  }
  
@@ -181,7 +286,7 @@ index cbf1c61..56e34b9 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1027,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1125,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -194,7 +299,7 @@ index cbf1c61..56e34b9 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1193,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1291,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -290,7 +395,7 @@ index cbf1c61..56e34b9 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1239,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1337,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -299,7 +404,7 @@ index cbf1c61..56e34b9 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1341,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1439,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -319,7 +424,7 @@ index cbf1c61..56e34b9 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1459,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1557,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -328,7 +433,7 @@ index cbf1c61..56e34b9 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1507,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1605,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -345,7 +450,7 @@ index cbf1c61..56e34b9 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1589,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1687,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -356,7 +461,7 @@ index cbf1c61..56e34b9 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1597,6 @@ err:
+@@ -1701,33 +1695,6 @@ err:
  	return ret;
  }
  
@@ -390,7 +495,7 @@ index cbf1c61..56e34b9 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1680,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1778,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -399,7 +504,7 @@ index cbf1c61..56e34b9 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1690,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1788,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -414,7 +519,7 @@ index cbf1c61..56e34b9 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1772,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1870,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -425,7 +530,7 @@ index cbf1c61..56e34b9 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1785,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1883,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -438,7 +543,7 @@ index cbf1c61..56e34b9 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1800,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1898,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -449,7 +554,7 @@ index cbf1c61..56e34b9 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1829,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1927,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -458,7 +563,7 @@ index cbf1c61..56e34b9 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1846,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1944,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -467,7 +572,7 @@ index cbf1c61..56e34b9 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1888,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1986,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -478,7 +583,7 @@ index cbf1c61..56e34b9 100644
  	return 0;
  }
  #endif
-@@ -2091,41 +1936,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2034,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From d6952c5b91b9bcbc92f00e7594ab3f94e311f70c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 10:51:47 +0200
Subject: [PATCH 1101/2207] linux: virtio_net.c: replace skb_vlan_tag_present()

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 6cefa602e..93cd511f7 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..60a0898 100644
+index cbf1c61..17a3e2d 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -130,7 +130,7 @@ index cbf1c61..60a0898 100644
 +
 +	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 +		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-+		if (skb_vlan_tag_present(skb))
++		if (skb->vlan_tci & VLAN_TAG_PRESENT)
 +			hdr->csum_start = __cpu_to_virtio16(little_endian,
 +				skb_checksum_start_offset(skb) + VLAN_HLEN);
 +		else

From 8c0dc151b9fb436c4d5d931e1b8e05f5c6d776f0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 11:06:44 +0200
Subject: [PATCH 1102/2207] linux: virtio_net.c: include average.h if not
 defined

---
 LINUX/configure                               | 12 +++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 97 +++++++++++++------
 2 files changed, 82 insertions(+), 27 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 01be8270b..32957e84d 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1621,6 +1621,18 @@ EOF
 	}
 EOF
 
+# check for 
+  add_test 'have AVERAGE_H' <
+
+	DECLARE_EWMA(myname, 1, 64);
+	int
+	dummy(struct ewma_myname *x) {
+		ewma_myname_add(x, 18);
+	}
+EOF
+
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 93cd511f7..4b2dbdf0d 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..17a3e2d 100644
+index cbf1c61..6daf639 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -45,7 +45,7 @@ index cbf1c61..17a3e2d 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -52,6 +55,104 @@ DECLARE_EWMA(pkt_len, 1, 64)
+@@ -52,6 +55,147 @@ DECLARE_EWMA(pkt_len, 1, 64)
  
  #define VIRTNET_DRIVER_VERSION "1.0.0"
  
@@ -146,11 +146,54 @@ index cbf1c61..17a3e2d 100644
 +	return 0;
 +}
 +#endif
++
++#ifndef NETMAP_LINUX_HAVE_AVERAGE_H
++/* Exponentially weighted moving average (EWMA) */
++
++#define DECLARE_EWMA(name, _factor, _weight)				\
++	struct ewma_##name {						\
++		unsigned long internal;					\
++	};								\
++	static inline void ewma_##name##_init(struct ewma_##name *e)	\
++	{								\
++		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
++		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
++		e->internal = 0;					\
++	}								\
++	static inline unsigned long					\
++	ewma_##name##_read(struct ewma_##name *e)			\
++	{								\
++		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
++		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
++		return e->internal >> ilog2(_factor);			\
++	}								\
++	static inline void ewma_##name##_add(struct ewma_##name *e,	\
++					     unsigned long val)		\
++	{								\
++		unsigned long internal = ACCESS_ONCE(e->internal);	\
++		unsigned long weight = ilog2(_weight);			\
++		unsigned long factor = ilog2(_factor);			\
++									\
++		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
++		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
++									\
++		ACCESS_ONCE(e->internal) = internal ?			\
++			(((internal << weight) - internal) +		\
++				(val << factor)) >> weight :		\
++			(val << factor);				\
++	}
++#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
 +
  struct virtnet_stats {
  	struct u64_stats_sync tx_syncp;
  	struct u64_stats_sync rx_syncp;
-@@ -135,13 +236,6 @@ struct virtnet_info {
+@@ -135,13 +279,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -164,7 +207,7 @@ index cbf1c61..17a3e2d 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +357,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +400,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -178,7 +221,7 @@ index cbf1c61..17a3e2d 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +737,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +780,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -186,7 +229,7 @@ index cbf1c61..17a3e2d 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +834,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +877,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -198,7 +241,7 @@ index cbf1c61..17a3e2d 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +849,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +892,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -242,7 +285,7 @@ index cbf1c61..17a3e2d 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +906,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +949,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -258,7 +301,7 @@ index cbf1c61..17a3e2d 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +939,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +982,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -270,7 +313,7 @@ index cbf1c61..17a3e2d 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1086,13 @@ out:
+@@ -1009,8 +1129,13 @@ out:
  	return ret;
  }
  
@@ -286,7 +329,7 @@ index cbf1c61..17a3e2d 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1125,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1168,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -299,7 +342,7 @@ index cbf1c61..17a3e2d 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1291,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1334,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -395,7 +438,7 @@ index cbf1c61..17a3e2d 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1337,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1380,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -404,7 +447,7 @@ index cbf1c61..17a3e2d 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1439,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1482,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -424,7 +467,7 @@ index cbf1c61..17a3e2d 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1557,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1600,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -433,7 +476,7 @@ index cbf1c61..17a3e2d 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1605,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1648,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -450,7 +493,7 @@ index cbf1c61..17a3e2d 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1687,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1730,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -461,7 +504,7 @@ index cbf1c61..17a3e2d 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1695,6 @@ err:
+@@ -1701,33 +1738,6 @@ err:
  	return ret;
  }
  
@@ -495,7 +538,7 @@ index cbf1c61..17a3e2d 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1778,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -504,7 +547,7 @@ index cbf1c61..17a3e2d 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1788,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1831,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -519,7 +562,7 @@ index cbf1c61..17a3e2d 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1870,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1913,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -530,7 +573,7 @@ index cbf1c61..17a3e2d 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1883,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1926,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -543,7 +586,7 @@ index cbf1c61..17a3e2d 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1898,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1941,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -554,7 +597,7 @@ index cbf1c61..17a3e2d 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1927,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1970,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -563,7 +606,7 @@ index cbf1c61..17a3e2d 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1944,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1987,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -572,7 +615,7 @@ index cbf1c61..17a3e2d 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1986,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +2029,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -583,7 +626,7 @@ index cbf1c61..17a3e2d 100644
  	return 0;
  }
  #endif
-@@ -2091,41 +2034,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2077,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 20a7083f7fdd7939291a7e0e06b29ffa1249af21 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 11:15:32 +0200
Subject: [PATCH 1103/2207] linux: virtio_net.c: fix virtio_net_hdr_from_skb()
 definition

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 60 +++++++++----------
 1 file changed, 28 insertions(+), 32 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 4b2dbdf0d..7ec5818a9 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..6daf639 100644
+index cbf1c61..299d66b 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -45,7 +45,7 @@ index cbf1c61..6daf639 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -52,6 +55,147 @@ DECLARE_EWMA(pkt_len, 1, 64)
+@@ -52,6 +55,143 @@ DECLARE_EWMA(pkt_len, 1, 64)
  
  #define VIRTNET_DRIVER_VERSION "1.0.0"
  
@@ -102,8 +102,7 @@ index cbf1c61..6daf639 100644
 +
 +static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
 +					  struct virtio_net_hdr *hdr,
-+					  bool little_endian,
-+					  bool has_data_valid)
++					  bool little_endian)
 +{
 +	memset(hdr, 0, sizeof(*hdr));
 +
@@ -138,9 +137,6 @@ index cbf1c61..6daf639 100644
 +				skb_checksum_start_offset(skb));
 +		hdr->csum_offset = __cpu_to_virtio16(little_endian,
 +				skb->csum_offset);
-+	} else if (has_data_valid &&
-+		   skb->ip_summed == CHECKSUM_UNNECESSARY) {
-+		hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
 +	} /* else everything is zero */
 +
 +	return 0;
@@ -193,7 +189,7 @@ index cbf1c61..6daf639 100644
  struct virtnet_stats {
  	struct u64_stats_sync tx_syncp;
  	struct u64_stats_sync rx_syncp;
-@@ -135,13 +279,6 @@ struct virtnet_info {
+@@ -135,13 +275,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -207,7 +203,7 @@ index cbf1c61..6daf639 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +400,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +396,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -221,7 +217,7 @@ index cbf1c61..6daf639 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +780,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +776,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -229,7 +225,7 @@ index cbf1c61..6daf639 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +877,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +873,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -241,7 +237,7 @@ index cbf1c61..6daf639 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +892,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +888,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -285,7 +281,7 @@ index cbf1c61..6daf639 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +949,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +945,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -301,7 +297,7 @@ index cbf1c61..6daf639 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +982,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +978,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -313,7 +309,7 @@ index cbf1c61..6daf639 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1129,13 @@ out:
+@@ -1009,8 +1125,13 @@ out:
  	return ret;
  }
  
@@ -329,7 +325,7 @@ index cbf1c61..6daf639 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1168,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1164,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -342,7 +338,7 @@ index cbf1c61..6daf639 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1334,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1330,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -438,7 +434,7 @@ index cbf1c61..6daf639 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1380,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1376,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -447,7 +443,7 @@ index cbf1c61..6daf639 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1482,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1478,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -467,7 +463,7 @@ index cbf1c61..6daf639 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1600,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1596,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -476,7 +472,7 @@ index cbf1c61..6daf639 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1648,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1644,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -493,7 +489,7 @@ index cbf1c61..6daf639 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1730,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1726,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -504,7 +500,7 @@ index cbf1c61..6daf639 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1738,6 @@ err:
+@@ -1701,33 +1734,6 @@ err:
  	return ret;
  }
  
@@ -538,7 +534,7 @@ index cbf1c61..6daf639 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1817,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -547,7 +543,7 @@ index cbf1c61..6daf639 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1831,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1827,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -562,7 +558,7 @@ index cbf1c61..6daf639 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1913,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1909,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -573,7 +569,7 @@ index cbf1c61..6daf639 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1926,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1922,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -586,7 +582,7 @@ index cbf1c61..6daf639 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1941,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1937,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -597,7 +593,7 @@ index cbf1c61..6daf639 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1970,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1966,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -606,7 +602,7 @@ index cbf1c61..6daf639 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1987,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1983,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -615,7 +611,7 @@ index cbf1c61..6daf639 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +2029,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +2025,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -626,7 +622,7 @@ index cbf1c61..6daf639 100644
  	return 0;
  }
  #endif
-@@ -2091,41 +2077,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2073,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 2b17e190f9272e08ad5ee2639fc7f66c321a6b90 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 11:36:23 +0200
Subject: [PATCH 1104/2207] linux: virtio_net.c: add support for
 VIRTIO_NET_F_MTU

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 58 ++++++++++---------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 7ec5818a9..ea059e9e7 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..299d66b 100644
+index cbf1c61..ec53178 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -45,10 +45,14 @@ index cbf1c61..299d66b 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -52,6 +55,143 @@ DECLARE_EWMA(pkt_len, 1, 64)
+@@ -52,6 +55,147 @@ DECLARE_EWMA(pkt_len, 1, 64)
  
  #define VIRTNET_DRIVER_VERSION "1.0.0"
  
++#ifndef VIRTIO_NET_F_MTU
++#define VIRTIO_NET_F_MTU	3
++#endif  /* VIRTIO_NET_F_MTU */
++
 +#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
 +static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
 +					const struct virtio_net_hdr *hdr,
@@ -189,7 +193,7 @@ index cbf1c61..299d66b 100644
  struct virtnet_stats {
  	struct u64_stats_sync tx_syncp;
  	struct u64_stats_sync rx_syncp;
-@@ -135,13 +275,6 @@ struct virtnet_info {
+@@ -135,13 +279,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -203,7 +207,7 @@ index cbf1c61..299d66b 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +396,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +400,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -217,7 +221,7 @@ index cbf1c61..299d66b 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +776,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +780,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -225,7 +229,7 @@ index cbf1c61..299d66b 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +873,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +877,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -237,7 +241,7 @@ index cbf1c61..299d66b 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +888,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +892,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -281,7 +285,7 @@ index cbf1c61..299d66b 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +945,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +949,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -297,7 +301,7 @@ index cbf1c61..299d66b 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +978,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +982,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -309,7 +313,7 @@ index cbf1c61..299d66b 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1125,13 @@ out:
+@@ -1009,8 +1129,13 @@ out:
  	return ret;
  }
  
@@ -325,7 +329,7 @@ index cbf1c61..299d66b 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1164,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1168,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -338,7 +342,7 @@ index cbf1c61..299d66b 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1330,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1334,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -434,7 +438,7 @@ index cbf1c61..299d66b 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1376,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1380,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -443,7 +447,7 @@ index cbf1c61..299d66b 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1478,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1482,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -463,7 +467,7 @@ index cbf1c61..299d66b 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1596,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1600,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -472,7 +476,7 @@ index cbf1c61..299d66b 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1644,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1648,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -489,7 +493,7 @@ index cbf1c61..299d66b 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1726,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1730,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -500,7 +504,7 @@ index cbf1c61..299d66b 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1734,6 @@ err:
+@@ -1701,33 +1738,6 @@ err:
  	return ret;
  }
  
@@ -534,7 +538,7 @@ index cbf1c61..299d66b 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1817,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -543,7 +547,7 @@ index cbf1c61..299d66b 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1827,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1831,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -558,7 +562,7 @@ index cbf1c61..299d66b 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1909,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1913,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -569,7 +573,7 @@ index cbf1c61..299d66b 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1922,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1926,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -582,7 +586,7 @@ index cbf1c61..299d66b 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1937,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1941,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -593,7 +597,7 @@ index cbf1c61..299d66b 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1966,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1970,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -602,7 +606,7 @@ index cbf1c61..299d66b 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1983,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1987,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -611,7 +615,7 @@ index cbf1c61..299d66b 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +2025,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +2029,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -622,7 +626,7 @@ index cbf1c61..299d66b 100644
  	return 0;
  }
  #endif
-@@ -2091,41 +2073,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2077,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From f1bf98b0e7f5d02088e6728d8a201226e105893b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 11:57:33 +0200
Subject: [PATCH 1105/2207] linux: virtio_net.c: exclude VIRTIO_NET_F_MTU when
 not available

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 97 +++++++++++++------
 1 file changed, 66 insertions(+), 31 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index ea059e9e7..8c386967f 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..ec53178 100644
+index cbf1c61..9672918 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -45,14 +45,10 @@ index cbf1c61..ec53178 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -52,6 +55,147 @@ DECLARE_EWMA(pkt_len, 1, 64)
+@@ -52,6 +55,143 @@ DECLARE_EWMA(pkt_len, 1, 64)
  
  #define VIRTNET_DRIVER_VERSION "1.0.0"
  
-+#ifndef VIRTIO_NET_F_MTU
-+#define VIRTIO_NET_F_MTU	3
-+#endif  /* VIRTIO_NET_F_MTU */
-+
 +#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
 +static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
 +					const struct virtio_net_hdr *hdr,
@@ -193,7 +189,7 @@ index cbf1c61..ec53178 100644
  struct virtnet_stats {
  	struct u64_stats_sync tx_syncp;
  	struct u64_stats_sync rx_syncp;
-@@ -135,13 +279,6 @@ struct virtnet_info {
+@@ -135,13 +275,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -207,7 +203,7 @@ index cbf1c61..ec53178 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +400,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +396,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -221,7 +217,7 @@ index cbf1c61..ec53178 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +780,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +776,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -229,7 +225,7 @@ index cbf1c61..ec53178 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +877,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +873,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -241,7 +237,7 @@ index cbf1c61..ec53178 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +892,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +888,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -285,7 +281,7 @@ index cbf1c61..ec53178 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +949,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +945,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -301,7 +297,7 @@ index cbf1c61..ec53178 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +982,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +978,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -313,7 +309,7 @@ index cbf1c61..ec53178 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1129,13 @@ out:
+@@ -1009,8 +1125,13 @@ out:
  	return ret;
  }
  
@@ -329,7 +325,7 @@ index cbf1c61..ec53178 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1168,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1164,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -342,7 +338,7 @@ index cbf1c61..ec53178 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1334,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1330,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -438,7 +434,7 @@ index cbf1c61..ec53178 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1380,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1376,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -447,7 +443,7 @@ index cbf1c61..ec53178 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1482,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1478,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -467,7 +463,7 @@ index cbf1c61..ec53178 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1600,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1596,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -476,7 +472,7 @@ index cbf1c61..ec53178 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1648,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1644,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -493,7 +489,7 @@ index cbf1c61..ec53178 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1730,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1726,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -504,7 +500,7 @@ index cbf1c61..ec53178 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1738,6 @@ err:
+@@ -1701,33 +1734,6 @@ err:
  	return ret;
  }
  
@@ -538,7 +534,7 @@ index cbf1c61..ec53178 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1817,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -547,7 +543,7 @@ index cbf1c61..ec53178 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1831,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1827,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -562,7 +558,23 @@ index cbf1c61..ec53178 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1905,10 +1913,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1889,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
+ 		vi->has_cvq = true;
+ 
++#ifdef VIRTIO_NET_F_MTU
+ 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
+ 		mtu = virtio_cread16(vdev,
+ 				     offsetof(struct virtio_net_config,
+@@ -1892,6 +1897,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		if (virtnet_change_mtu(dev, mtu))
+ 			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
+ 	}
++#endif /* VIRTIO_NET_F_MTU */
+ 
+ 	if (vi->any_header_sg)
+ 		dev->needed_headroom = vi->hdr_len;
+@@ -1905,10 +1911,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -573,7 +585,7 @@ index cbf1c61..ec53178 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1926,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1924,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -586,7 +598,7 @@ index cbf1c61..ec53178 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1941,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1939,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -597,7 +609,7 @@ index cbf1c61..ec53178 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1970,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1968,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -606,7 +618,7 @@ index cbf1c61..ec53178 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1987,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1985,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -615,7 +627,7 @@ index cbf1c61..ec53178 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +2029,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +2027,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -626,7 +638,30 @@ index cbf1c61..ec53178 100644
  	return 0;
  }
  #endif
-@@ -2091,41 +2077,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2061,15 +2045,20 @@ static struct virtio_device_id id_table[] = {
+ 	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
+ 	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
+ 	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
+-	VIRTIO_NET_F_CTRL_MAC_ADDR, \
+-	VIRTIO_NET_F_MTU
++	VIRTIO_NET_F_CTRL_MAC_ADDR
+ 
+ static unsigned int features[] = {
+ 	VIRTNET_FEATURES,
++#ifdef VIRTIO_NET_F_MTU
++	VIRTIO_NET_F_MTU,
++#endif  /* VIRTIO_NET_F_MTU */
+ };
+ 
+ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
++#ifdef VIRTIO_NET_F_MTU
++	VIRTIO_NET_F_MTU,
++#endif  /* VIRTIO_NET_F_MTU */
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
+ };
+@@ -2091,41 +2080,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 1c27726f5e13bdeba97f3b5d265065bd9c8333ed Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 15:46:31 +0200
Subject: [PATCH 1106/2207] linux: virtio_net.c: add support for
 ethtool_validate

---
 LINUX/configure                               |  9 ++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 89 ++++++++++++-------
 2 files changed, 68 insertions(+), 30 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 32957e84d..4b225a822 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1632,6 +1632,15 @@ EOF
 	}
 EOF
 
+# check for ethtool_validate_speed() and ethtool_validate_duplex()
+  add_test 'have ETHTOOL_VALIDATE' <
+
+	int
+	dummy(void) {
+		return ethtool_validate_speed(0) + ethtool_validate_duplex(0);
+	}
+EOF
 
   #####################################################
   # checks related to drivers                         #
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 8c386967f..65e40690e 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..9672918 100644
+index cbf1c61..36c7b0d 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -27,7 +27,10 @@
@@ -45,7 +45,7 @@ index cbf1c61..9672918 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -52,6 +55,143 @@ DECLARE_EWMA(pkt_len, 1, 64)
+@@ -52,6 +55,162 @@ DECLARE_EWMA(pkt_len, 1, 64)
  
  #define VIRTNET_DRIVER_VERSION "1.0.0"
  
@@ -185,11 +185,30 @@ index cbf1c61..9672918 100644
 +			(val << factor);				\
 +	}
 +#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
++
++#ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
++static inline int ethtool_validate_speed(__u32 speed)
++{
++	return speed <= INT_MAX || speed == SPEED_UNKNOWN;
++}
++
++static inline int ethtool_validate_duplex(__u8 duplex)
++{
++	switch (duplex) {
++	case DUPLEX_HALF:
++	case DUPLEX_FULL:
++	case DUPLEX_UNKNOWN:
++		return 1;
++	}
++
++	return 0;
++}
++#endif  /* NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE */
 +
  struct virtnet_stats {
  	struct u64_stats_sync tx_syncp;
  	struct u64_stats_sync rx_syncp;
-@@ -135,13 +275,6 @@ struct virtnet_info {
+@@ -135,13 +294,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -203,7 +222,7 @@ index cbf1c61..9672918 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +396,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +415,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -217,7 +236,7 @@ index cbf1c61..9672918 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +776,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +795,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -225,7 +244,7 @@ index cbf1c61..9672918 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +873,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -735,7 +892,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	/* Out of packets? */
  	if (received < budget) {
  		r = virtqueue_enable_cb_prepare(rq->vq);
@@ -237,7 +256,7 @@ index cbf1c61..9672918 100644
  		if (unlikely(virtqueue_poll(rq->vq, r)) &&
  		    napi_schedule_prep(napi)) {
  			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +888,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -746,43 +907,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -281,7 +300,7 @@ index cbf1c61..9672918 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +945,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +964,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -297,7 +316,7 @@ index cbf1c61..9672918 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +978,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +997,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -309,7 +328,7 @@ index cbf1c61..9672918 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1125,13 @@ out:
+@@ -1009,8 +1144,13 @@ out:
  	return ret;
  }
  
@@ -325,7 +344,7 @@ index cbf1c61..9672918 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1164,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1183,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -338,7 +357,7 @@ index cbf1c61..9672918 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1330,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1349,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -434,7 +453,7 @@ index cbf1c61..9672918 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1376,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1395,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -443,7 +462,7 @@ index cbf1c61..9672918 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1478,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1497,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -463,7 +482,7 @@ index cbf1c61..9672918 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1596,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1615,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -472,7 +491,7 @@ index cbf1c61..9672918 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1644,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1663,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -489,7 +508,7 @@ index cbf1c61..9672918 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1726,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1745,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -500,7 +519,7 @@ index cbf1c61..9672918 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1734,6 @@ err:
+@@ -1701,33 +1753,6 @@ err:
  	return ret;
  }
  
@@ -534,7 +553,17 @@ index cbf1c61..9672918 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1811,7 +1817,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1793,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 	struct net_device *dev;
+ 	struct virtnet_info *vi;
+ 	u16 max_queue_pairs;
++#ifdef VIRTIO_NET_F_MTU
+ 	int mtu;
++#endif  /* VIRTIO_NET_F_MTU */
+ 
+ 	if (!vdev->config->get) {
+ 		dev_err(&vdev->dev, "%s failure: config access disabled\n",
+@@ -1811,7 +1838,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -543,7 +572,7 @@ index cbf1c61..9672918 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1827,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1848,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -558,7 +587,7 @@ index cbf1c61..9672918 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1889,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1910,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -566,7 +595,7 @@ index cbf1c61..9672918 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1897,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1918,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -574,7 +603,7 @@ index cbf1c61..9672918 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1911,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1932,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -585,7 +614,7 @@ index cbf1c61..9672918 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1924,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1922,12 +1945,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtio_device_ready(vdev);
  
@@ -598,7 +627,7 @@ index cbf1c61..9672918 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1939,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1960,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -609,7 +638,7 @@ index cbf1c61..9672918 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1968,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,8 +1989,6 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -618,7 +647,7 @@ index cbf1c61..9672918 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +1985,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +2006,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -627,7 +656,7 @@ index cbf1c61..9672918 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +2027,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +2048,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -638,7 +667,7 @@ index cbf1c61..9672918 100644
  	return 0;
  }
  #endif
-@@ -2061,15 +2045,20 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,15 +2066,20 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -661,7 +690,7 @@ index cbf1c61..9672918 100644
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
  };
-@@ -2091,41 +2080,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2101,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From f64b4558d1c1e82036c23210ba6aaa39060d0e9f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:07:07 +0200
Subject: [PATCH 1107/2207] ci: tweak kernel .config to set CONFIG_VIRTIO_NET=m

---
 ci/build-linux | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ci/build-linux b/ci/build-linux
index 2f6a2be4a..b3fe4252f 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -40,6 +40,9 @@ then
 fi
 make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
+grep CONFIG_VIRTIO_NET .config
+sed -i '|CONFIG_VIRTIO_NET=.|CONFIG_VIRTIO_NET=m|' .config
+grep CONFIG_VIRTIO_NET .config
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 

From f0716b6488ea033ac8452b7a480a7fb26d49a795 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:35:37 +0200
Subject: [PATCH 1108/2207] linux: virtio_net.c: start to add some netmap
 support

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 300 ++++++------------
 LINUX/if_virtio_net_netmap.h                  | 210 ++++++++++++
 2 files changed, 306 insertions(+), 204 deletions(-)
 create mode 100644 LINUX/if_virtio_net_netmap.h

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 65e40690e..cf83903e4 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,185 +30,18 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..36c7b0d 100644
+index cbf1c61..795fcfc 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
-@@ -27,7 +27,10 @@
+@@ -27,7 +27,6 @@
  #include 
  #include 
  #include 
 -#include 
-+
-+#include 
-+#include 
-+#include 
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -52,6 +55,162 @@ DECLARE_EWMA(pkt_len, 1, 64)
- 
- #define VIRTNET_DRIVER_VERSION "1.0.0"
- 
-+#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
-+static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
-+					const struct virtio_net_hdr *hdr,
-+					bool little_endian)
-+{
-+	unsigned short gso_type = 0;
-+
-+	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
-+		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
-+		case VIRTIO_NET_HDR_GSO_TCPV4:
-+			gso_type = SKB_GSO_TCPV4;
-+			break;
-+		case VIRTIO_NET_HDR_GSO_TCPV6:
-+			gso_type = SKB_GSO_TCPV6;
-+			break;
-+		case VIRTIO_NET_HDR_GSO_UDP:
-+			gso_type = SKB_GSO_UDP;
-+			break;
-+		default:
-+			return -EINVAL;
-+		}
-+
-+		if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
-+			gso_type |= SKB_GSO_TCP_ECN;
-+
-+		if (hdr->gso_size == 0)
-+			return -EINVAL;
-+	}
-+
-+	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
-+		u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
-+		u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
-+
-+		if (!skb_partial_csum_set(skb, start, off))
-+			return -EINVAL;
-+	}
-+
-+	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
-+		u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
-+
-+		skb_shinfo(skb)->gso_size = gso_size;
-+		skb_shinfo(skb)->gso_type = gso_type;
-+
-+		/* Header must be checked, and gso_segs computed. */
-+		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-+		skb_shinfo(skb)->gso_segs = 0;
-+	}
-+
-+	return 0;
-+}
-+
-+static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
-+					  struct virtio_net_hdr *hdr,
-+					  bool little_endian)
-+{
-+	memset(hdr, 0, sizeof(*hdr));
-+
-+	if (skb_is_gso(skb)) {
-+		struct skb_shared_info *sinfo = skb_shinfo(skb);
-+
-+		/* This is a hint as to how much should be linear. */
-+		hdr->hdr_len = __cpu_to_virtio16(little_endian,
-+						 skb_headlen(skb));
-+		hdr->gso_size = __cpu_to_virtio16(little_endian,
-+						  sinfo->gso_size);
-+		if (sinfo->gso_type & SKB_GSO_TCPV4)
-+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
-+		else if (sinfo->gso_type & SKB_GSO_TCPV6)
-+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
-+		else if (sinfo->gso_type & SKB_GSO_UDP)
-+			hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
-+		else
-+			return -EINVAL;
-+		if (sinfo->gso_type & SKB_GSO_TCP_ECN)
-+			hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
-+	} else
-+		hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
-+
-+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-+		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-+		if (skb->vlan_tci & VLAN_TAG_PRESENT)
-+			hdr->csum_start = __cpu_to_virtio16(little_endian,
-+				skb_checksum_start_offset(skb) + VLAN_HLEN);
-+		else
-+			hdr->csum_start = __cpu_to_virtio16(little_endian,
-+				skb_checksum_start_offset(skb));
-+		hdr->csum_offset = __cpu_to_virtio16(little_endian,
-+				skb->csum_offset);
-+	} /* else everything is zero */
-+
-+	return 0;
-+}
-+#endif
-+
-+#ifndef NETMAP_LINUX_HAVE_AVERAGE_H
-+/* Exponentially weighted moving average (EWMA) */
-+
-+#define DECLARE_EWMA(name, _factor, _weight)				\
-+	struct ewma_##name {						\
-+		unsigned long internal;					\
-+	};								\
-+	static inline void ewma_##name##_init(struct ewma_##name *e)	\
-+	{								\
-+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-+		e->internal = 0;					\
-+	}								\
-+	static inline unsigned long					\
-+	ewma_##name##_read(struct ewma_##name *e)			\
-+	{								\
-+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-+		return e->internal >> ilog2(_factor);			\
-+	}								\
-+	static inline void ewma_##name##_add(struct ewma_##name *e,	\
-+					     unsigned long val)		\
-+	{								\
-+		unsigned long internal = ACCESS_ONCE(e->internal);	\
-+		unsigned long weight = ilog2(_weight);			\
-+		unsigned long factor = ilog2(_factor);			\
-+									\
-+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-+									\
-+		ACCESS_ONCE(e->internal) = internal ?			\
-+			(((internal << weight) - internal) +		\
-+				(val << factor)) >> weight :		\
-+			(val << factor);				\
-+	}
-+#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
-+
-+#ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
-+static inline int ethtool_validate_speed(__u32 speed)
-+{
-+	return speed <= INT_MAX || speed == SPEED_UNKNOWN;
-+}
-+
-+static inline int ethtool_validate_duplex(__u8 duplex)
-+{
-+	switch (duplex) {
-+	case DUPLEX_HALF:
-+	case DUPLEX_FULL:
-+	case DUPLEX_UNKNOWN:
-+		return 1;
-+	}
-+
-+	return 0;
-+}
-+#endif  /* NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE */
-+
- struct virtnet_stats {
- 	struct u64_stats_sync tx_syncp;
- 	struct u64_stats_sync rx_syncp;
-@@ -135,13 +294,6 @@ struct virtnet_info {
+@@ -135,13 +134,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -222,7 +55,29 @@ index cbf1c61..36c7b0d 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -263,7 +415,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -220,13 +212,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
+ 	return p;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static void skb_xmit_done(struct virtqueue *vq)
+ {
+ 	struct virtnet_info *vi = vq->vdev->priv;
+ 
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+-
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif /* DEV_NETMAP */
+ 	/* We were probably waiting for more output buffers. */
+ 	netif_wake_subqueue(vi->dev, vq2txq(vq));
+ }
+@@ -263,7 +262,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -236,7 +91,7 @@ index cbf1c61..36c7b0d 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +795,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +642,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -244,19 +99,44 @@ index cbf1c61..36c7b0d 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -735,7 +892,11 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,16 +733,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	struct receive_queue *rq =
+ 		container_of(napi, struct receive_queue, napi);
+ 	unsigned int r, received;
+-
++	struct virtqueue *vq = rq->vq;
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	struct virtnet_info *vi = vq->vdev->priv;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        }
++	if (nm_irq == NM_IRQ_RESCHED)
++		return budget;
++#endif /* DEV_NETMAP */
+ 	received = virtnet_receive(rq, budget);
+ 
  	/* Out of packets? */
  	if (received < budget) {
- 		r = virtqueue_enable_cb_prepare(rq->vq);
+-		r = virtqueue_enable_cb_prepare(rq->vq);
++		r = virtqueue_enable_cb_prepare(vq);
 +#ifdef NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE
  		napi_complete_done(napi, received);
+-		if (unlikely(virtqueue_poll(rq->vq, r)) &&
 +#else  /* !NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE */
 +		napi_complete(napi);
 +#endif /* !NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE */
- 		if (unlikely(virtqueue_poll(rq->vq, r)) &&
++		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
- 			virtqueue_disable_cb(rq->vq);
-@@ -746,43 +907,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+-			virtqueue_disable_cb(rq->vq);
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+@@ -746,43 +766,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	return received;
  }
  
@@ -300,7 +180,7 @@ index cbf1c61..36c7b0d 100644
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +964,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +823,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -316,7 +196,7 @@ index cbf1c61..36c7b0d 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +997,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +856,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -328,7 +208,7 @@ index cbf1c61..36c7b0d 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1144,13 @@ out:
+@@ -1009,8 +1003,13 @@ out:
  	return ret;
  }
  
@@ -344,7 +224,7 @@ index cbf1c61..36c7b0d 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1183,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1042,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -357,7 +237,7 @@ index cbf1c61..36c7b0d 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1349,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1208,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -453,7 +333,7 @@ index cbf1c61..36c7b0d 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1395,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1254,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -462,7 +342,7 @@ index cbf1c61..36c7b0d 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1497,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1356,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -482,7 +362,7 @@ index cbf1c61..36c7b0d 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1615,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1474,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -491,7 +371,7 @@ index cbf1c61..36c7b0d 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1663,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1522,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -508,7 +388,7 @@ index cbf1c61..36c7b0d 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1745,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1604,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -519,7 +399,7 @@ index cbf1c61..36c7b0d 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1753,6 @@ err:
+@@ -1701,33 +1612,6 @@ err:
  	return ret;
  }
  
@@ -553,7 +433,7 @@ index cbf1c61..36c7b0d 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1793,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1652,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -563,7 +443,7 @@ index cbf1c61..36c7b0d 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1838,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1697,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -572,7 +452,7 @@ index cbf1c61..36c7b0d 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1848,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1707,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -587,7 +467,7 @@ index cbf1c61..36c7b0d 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1910,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1769,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -595,7 +475,7 @@ index cbf1c61..36c7b0d 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1918,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1777,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -603,7 +483,7 @@ index cbf1c61..36c7b0d 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1932,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1791,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -614,20 +494,25 @@ index cbf1c61..36c7b0d 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1922,12 +1945,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1802,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		goto free_vqs;
+ 	}
  
- 	virtio_device_ready(vdev);
+-	virtio_device_ready(vdev);
++#ifdef DEV_NETMAP
++        virtio_net_netmap_attach(vi);
++#endif /* DEV_NETMAP */
  
 -	err = virtnet_cpu_notif_add(vi);
 -	if (err) {
 -		pr_debug("virtio_net: registering cpu notifier failed\n");
 -		goto free_unregister_netdev;
 -	}
--
++	virtio_device_ready(vdev);
+ 
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1943,10 +1960,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1823,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -638,7 +523,7 @@ index cbf1c61..36c7b0d 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,8 +1989,6 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1852,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -647,7 +532,14 @@ index cbf1c61..36c7b0d 100644
  	/* Make sure no work handler is accessing the device. */
  	flush_work(&vi->config_work);
  
-@@ -1995,8 +2006,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
++#ifdef DEV_NETMAP
++	netmap_detach(vi->dev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(vi->dev);
+ 
+ 	remove_vq_common(vi);
+@@ -1995,8 +1873,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -656,7 +548,7 @@ index cbf1c61..36c7b0d 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +2048,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1915,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -667,7 +559,7 @@ index cbf1c61..36c7b0d 100644
  	return 0;
  }
  #endif
-@@ -2061,15 +2066,20 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,15 +1933,20 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -690,7 +582,7 @@ index cbf1c61..36c7b0d 100644
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
  };
-@@ -2091,41 +2101,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +1968,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
new file mode 100644
index 000000000..9428463f0
--- /dev/null
+++ b/LINUX/if_virtio_net_netmap.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018 Vincenzo Maffione. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include 
+#include 
+#include 
+
+#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
+static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
+					const struct virtio_net_hdr *hdr,
+					bool little_endian)
+{
+	unsigned short gso_type = 0;
+
+	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
+		case VIRTIO_NET_HDR_GSO_TCPV4:
+			gso_type = SKB_GSO_TCPV4;
+			break;
+		case VIRTIO_NET_HDR_GSO_TCPV6:
+			gso_type = SKB_GSO_TCPV6;
+			break;
+		case VIRTIO_NET_HDR_GSO_UDP:
+			gso_type = SKB_GSO_UDP;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
+			gso_type |= SKB_GSO_TCP_ECN;
+
+		if (hdr->gso_size == 0)
+			return -EINVAL;
+	}
+
+	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+		u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
+		u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
+
+		if (!skb_partial_csum_set(skb, start, off))
+			return -EINVAL;
+	}
+
+	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+		u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
+
+		skb_shinfo(skb)->gso_size = gso_size;
+		skb_shinfo(skb)->gso_type = gso_type;
+
+		/* Header must be checked, and gso_segs computed. */
+		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+		skb_shinfo(skb)->gso_segs = 0;
+	}
+
+	return 0;
+}
+
+static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
+					  struct virtio_net_hdr *hdr,
+					  bool little_endian)
+{
+	memset(hdr, 0, sizeof(*hdr));
+
+	if (skb_is_gso(skb)) {
+		struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+		/* This is a hint as to how much should be linear. */
+		hdr->hdr_len = __cpu_to_virtio16(little_endian,
+						 skb_headlen(skb));
+		hdr->gso_size = __cpu_to_virtio16(little_endian,
+						  sinfo->gso_size);
+		if (sinfo->gso_type & SKB_GSO_TCPV4)
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+		else if (sinfo->gso_type & SKB_GSO_TCPV6)
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+		else if (sinfo->gso_type & SKB_GSO_UDP)
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
+		else
+			return -EINVAL;
+		if (sinfo->gso_type & SKB_GSO_TCP_ECN)
+			hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
+	} else
+		hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+		if (skb->vlan_tci & VLAN_TAG_PRESENT)
+			hdr->csum_start = __cpu_to_virtio16(little_endian,
+				skb_checksum_start_offset(skb) + VLAN_HLEN);
+		else
+			hdr->csum_start = __cpu_to_virtio16(little_endian,
+				skb_checksum_start_offset(skb));
+		hdr->csum_offset = __cpu_to_virtio16(little_endian,
+				skb->csum_offset);
+	} /* else everything is zero */
+
+	return 0;
+}
+#endif
+
+#ifndef NETMAP_LINUX_HAVE_AVERAGE_H
+/* Exponentially weighted moving average (EWMA) */
+
+#define DECLARE_EWMA(name, _factor, _weight)				\
+	struct ewma_##name {						\
+		unsigned long internal;					\
+	};								\
+	static inline void ewma_##name##_init(struct ewma_##name *e)	\
+	{								\
+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
+		e->internal = 0;					\
+	}								\
+	static inline unsigned long					\
+	ewma_##name##_read(struct ewma_##name *e)			\
+	{								\
+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
+		return e->internal >> ilog2(_factor);			\
+	}								\
+	static inline void ewma_##name##_add(struct ewma_##name *e,	\
+					     unsigned long val)		\
+	{								\
+		unsigned long internal = ACCESS_ONCE(e->internal);	\
+		unsigned long weight = ilog2(_weight);			\
+		unsigned long factor = ilog2(_factor);			\
+									\
+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
+									\
+		ACCESS_ONCE(e->internal) = internal ?			\
+			(((internal << weight) - internal) +		\
+				(val << factor)) >> weight :		\
+			(val << factor);				\
+	}
+#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
+
+#ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
+static inline int ethtool_validate_speed(__u32 speed)
+{
+	return speed <= INT_MAX || speed == SPEED_UNKNOWN;
+}
+
+static inline int ethtool_validate_duplex(__u8 duplex)
+{
+	switch (duplex) {
+	case DUPLEX_HALF:
+	case DUPLEX_FULL:
+	case DUPLEX_UNKNOWN:
+		return 1;
+	}
+
+	return 0;
+}
+#endif  /* NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE */
+
+struct virtnet_info;
+
+static void
+virtio_net_netmap_attach(struct virtnet_info *vi)
+{
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp = vi->dev;
+	na.na_flags = 0;
+	na.num_tx_desc = 1;
+	na.num_rx_desc = 1;
+	na.num_tx_rings = na.num_rx_rings = 1;
+	na.rx_buf_maxsize = 0;
+	na.nm_register = NULL;
+	na.nm_txsync = NULL;
+	na.nm_rxsync = NULL;
+	na.nm_intr = NULL;
+	na.nm_config = NULL;
+
+	netmap_attach(&na);
+}
+
+/* end of file */

From 2a6c9f1acbf8447a7ba08c1c1bcb4a6464ed732e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:36:52 +0200
Subject: [PATCH 1109/2207] ci: avoid failures due to grepping
 CONFIG_VIRTIO_NET

---
 ci/build-linux | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index b3fe4252f..7d6b62908 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -40,9 +40,10 @@ then
 fi
 make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
-grep CONFIG_VIRTIO_NET .config
-sed -i '|CONFIG_VIRTIO_NET=.|CONFIG_VIRTIO_NET=m|' .config
-grep CONFIG_VIRTIO_NET .config
+echo "Grepping for CONFIG_VIRTIO_NET"
+grep CONFIG_VIRTIO_NET .config || true
+sed -i '|CONFIG_VIRTIO_NET=.|CONFIG_VIRTIO_NET=m|' .config || true
+grep CONFIG_VIRTIO_NET .config || true
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 

From 9aac776063679fa0fc7c52e58f1067cae7904c85 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:42:46 +0200
Subject: [PATCH 1110/2207] linux: virtio_net.c: rearrange includes

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 109 ++++++++++--------
 1 file changed, 61 insertions(+), 48 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index cf83903e4..5a7392246 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,18 +30,32 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..795fcfc 100644
+index cbf1c61..fd7cde3 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
-@@ -27,7 +27,6 @@
+@@ -26,8 +26,8 @@
+ #include 
  #include 
  #include 
- #include 
+-#include 
 -#include 
++
++#include   /* needed for netmap_linux_config.h */
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -135,13 +134,6 @@ struct virtnet_info {
+@@ -40,6 +40,10 @@ module_param(gso, bool, 0444);
+ #define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
+ #define GOOD_COPY_LEN	128
+ 
++#ifdef NETMAP_LINUX_HAVE_AVERAGE_H
++#include 
++#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
++
+ /* RX packet size EWMA. The average packet size is used to determine the packet
+  * buffer size when refilling RX rings. As the entire RX ring may be refilled
+  * at once, the weight is chosen so that the EWMA will be insensitive to short-
+@@ -135,13 +139,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -55,7 +69,7 @@ index cbf1c61..795fcfc 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -220,13 +212,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
+@@ -220,13 +217,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
  	return p;
  }
  
@@ -77,7 +91,7 @@ index cbf1c61..795fcfc 100644
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
-@@ -263,7 +262,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +267,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -91,7 +105,7 @@ index cbf1c61..795fcfc 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +642,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +647,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -99,7 +113,7 @@ index cbf1c61..795fcfc 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,16 +733,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +738,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -132,14 +146,13 @@ index cbf1c61..795fcfc 100644
 +		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
 -			virtqueue_disable_cb(rq->vq);
-+			virtqueue_disable_cb(vq);
- 			__napi_schedule(napi);
- 		}
- 	}
-@@ -746,43 +766,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	return received;
- }
- 
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
+-
 -#ifdef CONFIG_NET_RX_BUSY_POLL
 -/* must be called with local_bh_disable()d */
 -static int virtnet_busy_poll(struct napi_struct *napi)
@@ -169,18 +182,18 @@ index cbf1c61..795fcfc 100644
 -			budget -= received;
 -			goto again;
 -		} else {
--			__napi_schedule(napi);
--		}
--	}
--
--	return received;
--}
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+ 
+ 	return received;
+ }
 -#endif	/* CONFIG_NET_RX_BUSY_POLL */
--
+ 
  static int virtnet_open(struct net_device *dev)
  {
- 	struct virtnet_info *vi = netdev_priv(dev);
-@@ -840,7 +823,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +828,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -196,7 +209,7 @@ index cbf1c61..795fcfc 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +856,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +861,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -208,7 +221,7 @@ index cbf1c61..795fcfc 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1003,13 @@ out:
+@@ -1009,8 +1008,13 @@ out:
  	return ret;
  }
  
@@ -224,7 +237,7 @@ index cbf1c61..795fcfc 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1042,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1047,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -237,7 +250,7 @@ index cbf1c61..795fcfc 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1208,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1213,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -333,7 +346,7 @@ index cbf1c61..795fcfc 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1254,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1259,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -342,7 +355,7 @@ index cbf1c61..795fcfc 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1356,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1361,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -362,7 +375,7 @@ index cbf1c61..795fcfc 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1474,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1479,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -371,7 +384,7 @@ index cbf1c61..795fcfc 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1522,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1527,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -388,7 +401,7 @@ index cbf1c61..795fcfc 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1604,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1609,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -399,7 +412,7 @@ index cbf1c61..795fcfc 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1612,6 @@ err:
+@@ -1701,33 +1617,6 @@ err:
  	return ret;
  }
  
@@ -433,7 +446,7 @@ index cbf1c61..795fcfc 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1652,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1657,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -443,7 +456,7 @@ index cbf1c61..795fcfc 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1697,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1702,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -452,7 +465,7 @@ index cbf1c61..795fcfc 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1707,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1712,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -467,7 +480,7 @@ index cbf1c61..795fcfc 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1769,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1774,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -475,7 +488,7 @@ index cbf1c61..795fcfc 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1777,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1782,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -483,7 +496,7 @@ index cbf1c61..795fcfc 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1791,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1796,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -494,7 +507,7 @@ index cbf1c61..795fcfc 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1802,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1807,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -512,7 +525,7 @@ index cbf1c61..795fcfc 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1823,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1828,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -523,7 +536,7 @@ index cbf1c61..795fcfc 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1852,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1857,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -539,7 +552,7 @@ index cbf1c61..795fcfc 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1873,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1878,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -548,7 +561,7 @@ index cbf1c61..795fcfc 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1915,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1920,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -559,7 +572,7 @@ index cbf1c61..795fcfc 100644
  	return 0;
  }
  #endif
-@@ -2061,15 +1933,20 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,15 +1938,20 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -582,7 +595,7 @@ index cbf1c61..795fcfc 100644
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
  };
-@@ -2091,41 +1968,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +1973,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 713b9aacdde30f106065c7bbb343e7a8f340cc0e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:43:50 +0200
Subject: [PATCH 1111/2207] ci: build-linux: use compatible sed syntax

---
 ci/build-linux | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 7d6b62908..a85e0c8fd 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -42,7 +42,7 @@ make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
 echo "Grepping for CONFIG_VIRTIO_NET"
 grep CONFIG_VIRTIO_NET .config || true
-sed -i '|CONFIG_VIRTIO_NET=.|CONFIG_VIRTIO_NET=m|' .config || true
+sed -i '/CONFIG_VIRTIO_NET=./CONFIG_VIRTIO_NET=m/' .config || true
 grep CONFIG_VIRTIO_NET .config || true
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd

From ec385331f7ebe53de59b251010b9cc4b06842006 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:47:35 +0200
Subject: [PATCH 1112/2207] linux: virtio_net.c: move DECLARE_EWMA backup to
 the patch

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 104 ++++++++++++------
 LINUX/if_virtio_net_netmap.h                  |  43 --------
 2 files changed, 72 insertions(+), 75 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 5a7392246..0f6f1e272 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..fd7cde3 100644
+index cbf1c61..c94e92b 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -44,18 +44,58 @@ index cbf1c61..fd7cde3 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -40,6 +40,10 @@ module_param(gso, bool, 0444);
+@@ -40,6 +40,50 @@ module_param(gso, bool, 0444);
  #define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
  #define GOOD_COPY_LEN	128
  
 +#ifdef NETMAP_LINUX_HAVE_AVERAGE_H
 +#include 
-+#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
++#else   /* !NETMAP_LINUX_HAVE_AVERAGE_H */
++/* Exponentially weighted moving average (EWMA) */
++#define DECLARE_EWMA(name, _factor, _weight)				\
++	struct ewma_##name {						\
++		unsigned long internal;					\
++	};								\
++	static inline void ewma_##name##_init(struct ewma_##name *e)	\
++	{								\
++		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
++		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
++		e->internal = 0;					\
++	}								\
++	static inline unsigned long					\
++	ewma_##name##_read(struct ewma_##name *e)			\
++	{								\
++		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
++		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
++		return e->internal >> ilog2(_factor);			\
++	}								\
++	static inline void ewma_##name##_add(struct ewma_##name *e,	\
++					     unsigned long val)		\
++	{								\
++		unsigned long internal = ACCESS_ONCE(e->internal);	\
++		unsigned long weight = ilog2(_weight);			\
++		unsigned long factor = ilog2(_factor);			\
++									\
++		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
++		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
++		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
++									\
++		ACCESS_ONCE(e->internal) = internal ?			\
++			(((internal << weight) - internal) +		\
++				(val << factor)) >> weight :		\
++			(val << factor);				\
++	}
++#endif  /* !NETMAP_LINUX_HAVE_AVERAGE_H */
 +
  /* RX packet size EWMA. The average packet size is used to determine the packet
   * buffer size when refilling RX rings. As the entire RX ring may be refilled
   * at once, the weight is chosen so that the EWMA will be insensitive to short-
-@@ -135,13 +139,6 @@ struct virtnet_info {
+@@ -135,13 +179,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -69,7 +109,7 @@ index cbf1c61..fd7cde3 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -220,13 +217,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
+@@ -220,13 +257,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
  	return p;
  }
  
@@ -91,7 +131,7 @@ index cbf1c61..fd7cde3 100644
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
-@@ -263,7 +267,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +307,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -105,7 +145,7 @@ index cbf1c61..fd7cde3 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +647,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +687,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -113,7 +153,7 @@ index cbf1c61..fd7cde3 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +738,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +778,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -193,7 +233,7 @@ index cbf1c61..fd7cde3 100644
  
  static int virtnet_open(struct net_device *dev)
  {
-@@ -840,7 +828,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +868,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -209,7 +249,7 @@ index cbf1c61..fd7cde3 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +861,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +901,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -221,7 +261,7 @@ index cbf1c61..fd7cde3 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1008,13 @@ out:
+@@ -1009,8 +1048,13 @@ out:
  	return ret;
  }
  
@@ -237,7 +277,7 @@ index cbf1c61..fd7cde3 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1047,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1087,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -250,7 +290,7 @@ index cbf1c61..fd7cde3 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1213,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1253,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -346,7 +386,7 @@ index cbf1c61..fd7cde3 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1259,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1299,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -355,7 +395,7 @@ index cbf1c61..fd7cde3 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1361,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1401,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -375,7 +415,7 @@ index cbf1c61..fd7cde3 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1479,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1519,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -384,7 +424,7 @@ index cbf1c61..fd7cde3 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1527,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1567,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -401,7 +441,7 @@ index cbf1c61..fd7cde3 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1609,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1649,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -412,7 +452,7 @@ index cbf1c61..fd7cde3 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1617,6 @@ err:
+@@ -1701,33 +1657,6 @@ err:
  	return ret;
  }
  
@@ -446,7 +486,7 @@ index cbf1c61..fd7cde3 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1657,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1697,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -456,7 +496,7 @@ index cbf1c61..fd7cde3 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1702,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1742,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -465,7 +505,7 @@ index cbf1c61..fd7cde3 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1712,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1752,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -480,7 +520,7 @@ index cbf1c61..fd7cde3 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1774,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1814,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -488,7 +528,7 @@ index cbf1c61..fd7cde3 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1782,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1822,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -496,7 +536,7 @@ index cbf1c61..fd7cde3 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1796,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1836,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -507,7 +547,7 @@ index cbf1c61..fd7cde3 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1807,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1847,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -525,7 +565,7 @@ index cbf1c61..fd7cde3 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1828,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1868,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -536,7 +576,7 @@ index cbf1c61..fd7cde3 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1857,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1897,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -552,7 +592,7 @@ index cbf1c61..fd7cde3 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1878,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1918,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -561,7 +601,7 @@ index cbf1c61..fd7cde3 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1920,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1960,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -572,7 +612,7 @@ index cbf1c61..fd7cde3 100644
  	return 0;
  }
  #endif
-@@ -2061,15 +1938,20 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,15 +1978,20 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -595,7 +635,7 @@ index cbf1c61..fd7cde3 100644
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
  };
-@@ -2091,41 +1973,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2013,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 9428463f0..cb77754ea 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -121,49 +121,6 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
 }
 #endif
 
-#ifndef NETMAP_LINUX_HAVE_AVERAGE_H
-/* Exponentially weighted moving average (EWMA) */
-
-#define DECLARE_EWMA(name, _factor, _weight)				\
-	struct ewma_##name {						\
-		unsigned long internal;					\
-	};								\
-	static inline void ewma_##name##_init(struct ewma_##name *e)	\
-	{								\
-		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-		e->internal = 0;					\
-	}								\
-	static inline unsigned long					\
-	ewma_##name##_read(struct ewma_##name *e)			\
-	{								\
-		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-		return e->internal >> ilog2(_factor);			\
-	}								\
-	static inline void ewma_##name##_add(struct ewma_##name *e,	\
-					     unsigned long val)		\
-	{								\
-		unsigned long internal = ACCESS_ONCE(e->internal);	\
-		unsigned long weight = ilog2(_weight);			\
-		unsigned long factor = ilog2(_factor);			\
-									\
-		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-									\
-		ACCESS_ONCE(e->internal) = internal ?			\
-			(((internal << weight) - internal) +		\
-				(val << factor)) >> weight :		\
-			(val << factor);				\
-	}
-#endif  /* NETMAP_LINUX_HAVE_AVERAGE_H */
-
 #ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
 static inline int ethtool_validate_speed(__u32 speed)
 {

From 7fdf18ac5561b8749ee56d59a61ec99761b144c5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 16:57:38 +0200
Subject: [PATCH 1113/2207] ci: build-linux: fix sed syntax

---
 ci/build-linux | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index a85e0c8fd..41008294c 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -42,7 +42,7 @@ make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
 echo "Grepping for CONFIG_VIRTIO_NET"
 grep CONFIG_VIRTIO_NET .config || true
-sed -i '/CONFIG_VIRTIO_NET=./CONFIG_VIRTIO_NET=m/' .config || true
+sed -i 's/CONFIG_VIRTIO_NET=./CONFIG_VIRTIO_NET=m/' .config || true
 grep CONFIG_VIRTIO_NET .config || true
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd

From 198c4de6173e516c5d301a4f6251ab4a43830b75 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 17:04:27 +0200
Subject: [PATCH 1114/2207] linux: virtio_net.c: add configure check for
 virtio_byteorder.h

---
 LINUX/configure | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 4b225a822..35847c758 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1862,6 +1862,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTIO_BYTEORDER' <
+
+	u16
+	dummy(bool little_endian, __virtio16 val)
+	{
+		return __virtio16_to_cpu(little_endian, val);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   

From 47e34727e3c8e1c0c579f3dd29bf81b479de65b9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 17:10:04 +0200
Subject: [PATCH 1115/2207] linux: virtio_net.c: compatibility support for
 byteorder and types

---
 LINUX/if_virtio_net_netmap.h | 80 +++++++++++++++++++++++++++++++++++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index cb77754ea..b020f7fa6 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -27,6 +27,10 @@
 #include 
 #include 
 
+/*************************************************************************/
+/* COMPATIBILITY LAYER                                                   */
+/*************************************************************************/
+
 #if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
 static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
 					const struct virtio_net_hdr *hdr,
@@ -140,7 +144,81 @@ static inline int ethtool_validate_duplex(__u8 duplex)
 }
 #endif  /* NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE */
 
-struct virtnet_info;
+#ifndef NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER
+#include 
+
+/*
+ * __virtio{16,32,64} have the following meaning:
+ * - __u{16,32,64} for virtio devices in legacy mode, accessed in native endian
+ * - __le{16,32,64} for standard-compliant virtio devices
+ */
+
+typedef __u16 __bitwise__ __virtio16;
+typedef __u32 __bitwise__ __virtio32;
+typedef __u64 __bitwise__ __virtio64;
+
+static inline bool virtio_legacy_is_little_endian(void)
+{
+#ifdef __LITTLE_ENDIAN
+	return true;
+#else
+	return false;
+#endif
+}
+
+static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val)
+{
+	if (little_endian)
+		return le16_to_cpu((__force __le16)val);
+	else
+		return be16_to_cpu((__force __be16)val);
+}
+
+static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val)
+{
+	if (little_endian)
+		return (__force __virtio16)cpu_to_le16(val);
+	else
+		return (__force __virtio16)cpu_to_be16(val);
+}
+
+static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val)
+{
+	if (little_endian)
+		return le32_to_cpu((__force __le32)val);
+	else
+		return be32_to_cpu((__force __be32)val);
+}
+
+static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val)
+{
+	if (little_endian)
+		return (__force __virtio32)cpu_to_le32(val);
+	else
+		return (__force __virtio32)cpu_to_be32(val);
+}
+
+static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val)
+{
+	if (little_endian)
+		return le64_to_cpu((__force __le64)val);
+	else
+		return be64_to_cpu((__force __be64)val);
+}
+
+static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
+{
+	if (little_endian)
+		return (__force __virtio64)cpu_to_le64(val);
+	else
+		return (__force __virtio64)cpu_to_be64(val);
+}
+#endif  /* NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER */
+
+
+/*************************************************************************/
+/* NETMAP SUPPORT                                                        */
+/*************************************************************************/
 
 static void
 virtio_net_netmap_attach(struct virtnet_info *vi)

From 63b467b89aaf15edfa5981a830ef2413dea0a3ba Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 17:43:44 +0200
Subject: [PATCH 1116/2207] linux: virtio_net.c: compatibility support for
 virtio memory accessors

---
 LINUX/configure              | 10 ++++++++++
 LINUX/if_virtio_net_netmap.h | 38 ++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 35847c758..a43b46ea3 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1872,6 +1872,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTIO_MEMORY_ACCESSORS' <
+
+	bool
+	dummy(struct virtio_device *vdev)
+	{
+		return virtio_is_little_endian(vdev) + virtio16_to_cpu(vdev, 0);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index b020f7fa6..f7c242ec6 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -215,6 +215,44 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
 }
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER */
 
+#ifndef NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS
+static inline bool virtio_is_little_endian(struct virtio_device *vdev)
+{
+	return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
+		virtio_legacy_is_little_endian();
+}
+
+static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
+{
+	return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
+}
+
+static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val)
+{
+	return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
+}
+
+static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val)
+{
+	return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
+}
+
+static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val)
+{
+	return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
+}
+
+static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val)
+{
+	return __virtio64_to_cpu(virtio_is_little_endian(vdev), val);
+}
+
+static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
+{
+	return __cpu_to_virtio64(virtio_is_little_endian(vdev), val);
+}
+#endif  /* NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS */
+
 
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */

From 92ba24e4d28d70a5397578453518b07dee78c0e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 17:48:04 +0200
Subject: [PATCH 1117/2207] ci: build-linux: force CONFIG_VIRTIO_NET=m

---
 ci/build-linux | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index 41008294c..8782358f7 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -40,10 +40,7 @@ then
 fi
 make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
-echo "Grepping for CONFIG_VIRTIO_NET"
-grep CONFIG_VIRTIO_NET .config || true
-sed -i 's/CONFIG_VIRTIO_NET=./CONFIG_VIRTIO_NET=m/' .config || true
-grep CONFIG_VIRTIO_NET .config || true
+echo 'CONFIG_VIRTIO_NET=m' >> .config
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 

From 8edb1310d6c778c488e1ac87a0ad063b1ad570e7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 7 Oct 2018 18:17:21 +0200
Subject: [PATCH 1118/2207] linux: virtio_net.c: fix compatibility issue on
 accessors

---
 LINUX/configure              |  4 ++--
 LINUX/if_virtio_net_netmap.h | 18 +++++++++---------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index a43b46ea3..d2022449d 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1875,10 +1875,10 @@ EOF
   add_test 'have VIRTIO_MEMORY_ACCESSORS' <
 
-	bool
+	u16
 	dummy(struct virtio_device *vdev)
 	{
-		return virtio_is_little_endian(vdev) + virtio16_to_cpu(vdev, 0);
+		return virtio16_to_cpu(vdev, 0);
 	}
 EOF
 
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index f7c242ec6..7f613bfeb 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -157,15 +157,6 @@ typedef __u16 __bitwise__ __virtio16;
 typedef __u32 __bitwise__ __virtio32;
 typedef __u64 __bitwise__ __virtio64;
 
-static inline bool virtio_legacy_is_little_endian(void)
-{
-#ifdef __LITTLE_ENDIAN
-	return true;
-#else
-	return false;
-#endif
-}
-
 static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val)
 {
 	if (little_endian)
@@ -216,6 +207,15 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER */
 
 #ifndef NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS
+static inline bool virtio_legacy_is_little_endian(void)
+{
+#ifdef __LITTLE_ENDIAN
+	return true;
+#else
+	return false;
+#endif
+}
+
 static inline bool virtio_is_little_endian(struct virtio_device *vdev)
 {
 	return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||

From d0e34aea0ceeee249c897a4a785c86308ecf66a4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 15:41:08 +0200
Subject: [PATCH 1119/2207] ci: build-linux: make sure .config has
 CONFIG_VIRTIO_NET=m

---
 ci/build-linux | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 8782358f7..4c6d12a4f 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -1,5 +1,21 @@
 #!/bin/bash -eu
 
+function set_config_variable()
+{
+	local varname=$1
+	local varvalue=$2
+
+	cnt=$(grep ${varname}.config || true)
+	if [ "$cnt" == 0 ]; then
+		echo "Appending"
+		echo "${varname}=${varvalue}" >> .config
+	else
+		echo "Modifying"
+		sed -i "s/^${varname}=./${varname}=${varvalue}/" .config
+	fi
+	grep "${varname}=${varvalue}" .config || echo "Failed to modify .config"
+}
+
 set -o pipefail
 
 readonly KERNEL_VERSION=${1:?}
@@ -40,7 +56,9 @@ then
 fi
 make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
-echo 'CONFIG_VIRTIO_NET=m' >> .config
+set_config_variable CONFIG_VIRTIO y
+set_config_variable CONFIG_VIRTIO_PCI y
+set_config_variable CONFIG_VIRTIO_NET m
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 

From 6035c923cdbb0eda89e9b3e0a8a3f58876203b55 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 16:25:45 +0200
Subject: [PATCH 1120/2207] LINUX: configure: add compatibility for
 virtio_is_little_endian()

---
 LINUX/configure              | 10 ++++++++++
 LINUX/if_virtio_net_netmap.h |  4 +++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index d2022449d..ab679ff2f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1872,6 +1872,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTIO_IS_LITTLE_ENDIAN' <
+
+	bool
+	dummy(struct virtio_device *vdev)
+	{
+		return virtio_is_little_endian(vdev);
+	}
+EOF
+
   add_test 'have VIRTIO_MEMORY_ACCESSORS' <
 
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 7f613bfeb..2577be100 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -206,7 +206,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
 }
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER */
 
-#ifndef NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS
+#ifndef NETMAP_LINUX_HAVE_VIRTIO_IS_LITTLE_ENDIAN
 static inline bool virtio_legacy_is_little_endian(void)
 {
 #ifdef __LITTLE_ENDIAN
@@ -221,7 +221,9 @@ static inline bool virtio_is_little_endian(struct virtio_device *vdev)
 	return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
 		virtio_legacy_is_little_endian();
 }
+#endif  /* NETMAP_LINUX_HAVE_VIRTIO_IS_LITTLE_ENDIAN */
 
+#ifndef NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS
 static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
 {
 	return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);

From e16d42446ebc678e50353d8350cd0f3ab056df81 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 16:27:00 +0200
Subject: [PATCH 1121/2207] ci: build-linux: fix bug in set_config_variable()

---
 ci/build-linux | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 4c6d12a4f..e655235d2 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -5,7 +5,7 @@ function set_config_variable()
 	local varname=$1
 	local varvalue=$2
 
-	cnt=$(grep ${varname}.config || true)
+	cnt=$(grep ${varname} .config || true)
 	if [ "$cnt" == 0 ]; then
 		echo "Appending"
 		echo "${varname}=${varvalue}" >> .config

From aa48adf3f5560fb58536c715331f4ef5c688365e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 16:38:29 +0200
Subject: [PATCH 1122/2207] ci: use --driver-suffix option

---
 ci/build-linux | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index e655235d2..653dd7de4 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -7,10 +7,8 @@ function set_config_variable()
 
 	cnt=$(grep ${varname} .config || true)
 	if [ "$cnt" == 0 ]; then
-		echo "Appending"
 		echo "${varname}=${varvalue}" >> .config
 	else
-		echo "Modifying"
 		sed -i "s/^${varname}=./${varname}=${varvalue}/" .config
 	fi
 	grep "${varname}=${varvalue}" .config || echo "Failed to modify .config"
@@ -56,25 +54,22 @@ then
 fi
 make mrproper
 make -j $PROC_COUNT ARCH=${ARCH} defconfig
-set_config_variable CONFIG_VIRTIO y
-set_config_variable CONFIG_VIRTIO_PCI y
-set_config_variable CONFIG_VIRTIO_NET m
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
 # First build in-tree-only drivers
 echo "Building vanilla-only drivers"
-./configure --no-ext-drivers --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=r8169.c,virtio_net.c,forcedeth.c,veth.c,e1000,vmxnet3 --enable-ptnetmap
+./configure --no-ext-drivers --driver-suffix=_netmap --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=r8169.c,virtio_net.c,forcedeth.c,veth.c,e1000,vmxnet3 --enable-ptnetmap
 make -j $PROC_COUNT
 
 # Then build external intel drivers
 make distclean
 echo "Building external intel drivers"
-./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=e1000e,igb,ixgbe,i40e
+./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=e1000e,igb,ixgbe,i40e
 make -j $PROC_COUNT
 
 # Then build vanilla intel drivers
 make distclean
 echo "Building vanilla intel drivers"
-./configure --no-ext-drivers --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=e1000e,igb,ixgbe,i40e
+./configure --no-ext-drivers --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=e1000e,igb,ixgbe,i40e
 make -j $PROC_COUNT

From 3429379d024b019a052d8fbc8541d6ae74ecb0db Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 17:28:52 +0200
Subject: [PATCH 1123/2207] linux: configure: skip build check in configure for
 virtio_net.c

---
 LINUX/configure              | 7 -------
 LINUX/default-config.mak.in_ | 2 +-
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index ab679ff2f..0541dbae8 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -998,13 +998,6 @@ EOF
   }	
 
   for d in $(edrv print); do
-	if [ "$d" == virtio_net.c ]; then
-		# virtio_net.c as an external driver does not need to
-		# build unpatched, because it's tailored to a specific
-		# kernel version.
-		# TODO better solution? maybe generalize?
-		continue
-	fi
 	add_file_exists_check build-$d true "edrv_build_error $d"
   done
 
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 239411c9a..2e593a36e 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -111,7 +111,7 @@ virtio_net.c@fetch	:= test -e @SRCDIR@/ext-drivers/virtio_net.c || wget https://
 virtio_net.c@src	:= mkdir -p virtio_net.c && cp @SRCDIR@/ext-drivers/virtio_net.c virtio_net.c/
 virtio_net.c@patch	:= patches/custom--virtio_net.c--4.9
 virtio_net.c@prepare	:=
-virtio_net.c@build 	:= make -C virtio_net.c EXTRA_CFLAGS="$(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+virtio_net.c@build 	:= [ -z "$(EXTRA_CFLAGS)" ] || make -C virtio_net.c EXTRA_CFLAGS="$(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 virtio_net.c@install 	:= make -C virtio_net.c install INSTALL_MOD_PATH=@MODPATH@ EXTRA_CFLAGS="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 virtio_net.c@clean 	:= if [ -d virtio_net.c ]; then make -C virtio_net.c clean EXTRA_CFLAGS="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
 virtio_net.c@distclean	:=

From a9080ae9a11e10a371a005cde08aa07e5ddb2acf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 17:32:57 +0200
Subject: [PATCH 1124/2207] linux: virtio_net: store virtio ring size in the
 netmap adapter

---
 LINUX/if_virtio_net_netmap.h | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 2577be100..7c8faf7f0 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -255,6 +255,11 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
 }
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS */
 
+#ifndef NETMAP_LINUX_VIRTIO_GET_VRSIZE
+/* Not yet found a way to find out virtqueue length in these
+   kernel series. Use the virtio default value. */
+#define virtqueue_get_vring_size(_vq)	({ (void)(_vq); 256; })
+#endif  /* !VIRTIO_GET_VRSIZE */
 
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */
@@ -269,11 +274,11 @@ virtio_net_netmap_attach(struct virtnet_info *vi)
 
 	na.ifp = vi->dev;
 	na.na_flags = 0;
-	na.num_tx_desc = 1;
-	na.num_rx_desc = 1;
-	na.num_tx_rings = na.num_rx_rings = 1;
+	na.num_tx_desc = virtqueue_get_vring_size(vi->sq[0].vq);
+	na.num_rx_desc = virtqueue_get_vring_size(vi->rq[0].vq);
+	na.num_tx_rings = na.num_rx_rings = vi->max_queue_pairs;
 	na.rx_buf_maxsize = 0;
-	na.nm_register = NULL;
+	na.nm_register = virtio_net_netmap_reg;
 	na.nm_txsync = NULL;
 	na.nm_rxsync = NULL;
 	na.nm_intr = NULL;

From 4ff6d2cbc33f66fa377e4a8d315596f68937fd4b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 17:45:16 +0200
Subject: [PATCH 1125/2207] linux: virtio_net: fix compilation issue

---
 LINUX/if_virtio_net_netmap.h | 190 +++++++++++++++++------------------
 1 file changed, 95 insertions(+), 95 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 7c8faf7f0..22742cf68 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -31,100 +31,6 @@
 /* COMPATIBILITY LAYER                                                   */
 /*************************************************************************/
 
-#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
-static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
-					const struct virtio_net_hdr *hdr,
-					bool little_endian)
-{
-	unsigned short gso_type = 0;
-
-	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
-		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
-		case VIRTIO_NET_HDR_GSO_TCPV4:
-			gso_type = SKB_GSO_TCPV4;
-			break;
-		case VIRTIO_NET_HDR_GSO_TCPV6:
-			gso_type = SKB_GSO_TCPV6;
-			break;
-		case VIRTIO_NET_HDR_GSO_UDP:
-			gso_type = SKB_GSO_UDP;
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
-			gso_type |= SKB_GSO_TCP_ECN;
-
-		if (hdr->gso_size == 0)
-			return -EINVAL;
-	}
-
-	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
-		u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
-		u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
-
-		if (!skb_partial_csum_set(skb, start, off))
-			return -EINVAL;
-	}
-
-	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
-		u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
-
-		skb_shinfo(skb)->gso_size = gso_size;
-		skb_shinfo(skb)->gso_type = gso_type;
-
-		/* Header must be checked, and gso_segs computed. */
-		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-		skb_shinfo(skb)->gso_segs = 0;
-	}
-
-	return 0;
-}
-
-static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
-					  struct virtio_net_hdr *hdr,
-					  bool little_endian)
-{
-	memset(hdr, 0, sizeof(*hdr));
-
-	if (skb_is_gso(skb)) {
-		struct skb_shared_info *sinfo = skb_shinfo(skb);
-
-		/* This is a hint as to how much should be linear. */
-		hdr->hdr_len = __cpu_to_virtio16(little_endian,
-						 skb_headlen(skb));
-		hdr->gso_size = __cpu_to_virtio16(little_endian,
-						  sinfo->gso_size);
-		if (sinfo->gso_type & SKB_GSO_TCPV4)
-			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
-		else if (sinfo->gso_type & SKB_GSO_TCPV6)
-			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
-		else if (sinfo->gso_type & SKB_GSO_UDP)
-			hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
-		else
-			return -EINVAL;
-		if (sinfo->gso_type & SKB_GSO_TCP_ECN)
-			hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
-	} else
-		hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
-
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-		if (skb->vlan_tci & VLAN_TAG_PRESENT)
-			hdr->csum_start = __cpu_to_virtio16(little_endian,
-				skb_checksum_start_offset(skb) + VLAN_HLEN);
-		else
-			hdr->csum_start = __cpu_to_virtio16(little_endian,
-				skb_checksum_start_offset(skb));
-		hdr->csum_offset = __cpu_to_virtio16(little_endian,
-				skb->csum_offset);
-	} /* else everything is zero */
-
-	return 0;
-}
-#endif
-
 #ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
 static inline int ethtool_validate_speed(__u32 speed)
 {
@@ -255,6 +161,100 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
 }
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_MEMORY_ACCESSORS */
 
+#if !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_5ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_4ARGS) && !defined(NETMAP_LINUX_VIRTIO_NET_HDR_FROM_SKB_3ARGS)
+static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
+					const struct virtio_net_hdr *hdr,
+					bool little_endian)
+{
+	unsigned short gso_type = 0;
+
+	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
+		case VIRTIO_NET_HDR_GSO_TCPV4:
+			gso_type = SKB_GSO_TCPV4;
+			break;
+		case VIRTIO_NET_HDR_GSO_TCPV6:
+			gso_type = SKB_GSO_TCPV6;
+			break;
+		case VIRTIO_NET_HDR_GSO_UDP:
+			gso_type = SKB_GSO_UDP;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
+			gso_type |= SKB_GSO_TCP_ECN;
+
+		if (hdr->gso_size == 0)
+			return -EINVAL;
+	}
+
+	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+		u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
+		u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
+
+		if (!skb_partial_csum_set(skb, start, off))
+			return -EINVAL;
+	}
+
+	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+		u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
+
+		skb_shinfo(skb)->gso_size = gso_size;
+		skb_shinfo(skb)->gso_type = gso_type;
+
+		/* Header must be checked, and gso_segs computed. */
+		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+		skb_shinfo(skb)->gso_segs = 0;
+	}
+
+	return 0;
+}
+
+static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
+					  struct virtio_net_hdr *hdr,
+					  bool little_endian)
+{
+	memset(hdr, 0, sizeof(*hdr));
+
+	if (skb_is_gso(skb)) {
+		struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+		/* This is a hint as to how much should be linear. */
+		hdr->hdr_len = __cpu_to_virtio16(little_endian,
+						 skb_headlen(skb));
+		hdr->gso_size = __cpu_to_virtio16(little_endian,
+						  sinfo->gso_size);
+		if (sinfo->gso_type & SKB_GSO_TCPV4)
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+		else if (sinfo->gso_type & SKB_GSO_TCPV6)
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+		else if (sinfo->gso_type & SKB_GSO_UDP)
+			hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
+		else
+			return -EINVAL;
+		if (sinfo->gso_type & SKB_GSO_TCP_ECN)
+			hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
+	} else
+		hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+		if (skb->vlan_tci & VLAN_TAG_PRESENT)
+			hdr->csum_start = __cpu_to_virtio16(little_endian,
+				skb_checksum_start_offset(skb) + VLAN_HLEN);
+		else
+			hdr->csum_start = __cpu_to_virtio16(little_endian,
+				skb_checksum_start_offset(skb));
+		hdr->csum_offset = __cpu_to_virtio16(little_endian,
+				skb->csum_offset);
+	} /* else everything is zero */
+
+	return 0;
+}
+#endif
+
 #ifndef NETMAP_LINUX_VIRTIO_GET_VRSIZE
 /* Not yet found a way to find out virtqueue length in these
    kernel series. Use the virtio default value. */
@@ -278,7 +278,7 @@ virtio_net_netmap_attach(struct virtnet_info *vi)
 	na.num_rx_desc = virtqueue_get_vring_size(vi->rq[0].vq);
 	na.num_tx_rings = na.num_rx_rings = vi->max_queue_pairs;
 	na.rx_buf_maxsize = 0;
-	na.nm_register = virtio_net_netmap_reg;
+	na.nm_register = NULL;
 	na.nm_txsync = NULL;
 	na.nm_rxsync = NULL;
 	na.nm_intr = NULL;

From 6589a1be616aa047056a7fe568d93eb61eb3c613 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 18:25:40 +0200
Subject: [PATCH 1126/2207] linux: virtio_net: implement
 virtio_net_netmap_reg()

---
 LINUX/final-patches/custom--virtio_net.c--4.9 |  25 ++--
 LINUX/if_virtio_net_netmap.h                  | 125 +++++++++++++++++-
 2 files changed, 137 insertions(+), 13 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 0f6f1e272..11970991a 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..c94e92b 100644
+index cbf1c61..cc598ef 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -109,17 +109,7 @@ index cbf1c61..c94e92b 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -220,13 +257,20 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
- 	return p;
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- static void skb_xmit_done(struct virtqueue *vq)
- {
- 	struct virtnet_info *vi = vq->vdev->priv;
+@@ -226,7 +263,10 @@ static void skb_xmit_done(struct virtqueue *vq)
  
  	/* Suppress further interrupts. */
  	virtqueue_disable_cb(vq);
@@ -131,6 +121,17 @@ index cbf1c61..c94e92b 100644
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
+@@ -249,6 +289,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+ 	return (unsigned long)buf | (size - 1);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /* Called from bottom half context */
+ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+ 				   struct receive_queue *rq,
 @@ -263,7 +307,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 22742cf68..7e301f9e0 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -265,6 +265,129 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
 /* NETMAP SUPPORT                                                        */
 /*************************************************************************/
 
+static int virtnet_open(struct net_device *dev);
+static int virtnet_close(struct net_device *dev);
+
+static void
+virtio_net_netmap_free_unused(struct virtnet_info *vi, enum txrx t, int i)
+{
+	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
+	void *buf;
+
+	while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
+		if (t == NR_TX)
+			dev_kfree_skb(buf);
+		else {
+			if (vi->mergeable_rx_bufs) {
+				unsigned long ctx = (unsigned long)buf;
+				void *base = mergeable_ctx_to_buf_address(ctx);
+				put_page(virt_to_head_page(base));
+			} else if (vi->big_packets) {
+				give_pages(&vi->rq[i], buf);
+			} else {
+				dev_kfree_skb(buf);
+			}
+		}
+	}
+}
+
+static void
+virtio_net_netmap_drain_used(struct virtnet_info *vi, enum txrx t, int i)
+{
+	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
+	unsigned int len;
+	void *buf;
+
+	while ((buf = virtqueue_get_buf(vq, &len)) != NULL) {
+	}
+}
+
+/* Initialize scatter-gather lists used to publish netmap
+ * buffers through virtio descriptors, in such a way that each
+ * each scatter-gather list contains exactly two descriptors
+ * (which can point to a netmap buffer). This initialization is
+ * necessary to prevent the virtio frontend (host) to think
+ * we are using multi-descriptors scatter-gather lists. */
+static void
+virtio_net_netmap_init_sgs(struct virtnet_info *vi)
+{
+	int i;
+
+	for (i = 0; i < vi->max_queue_pairs; i++) {
+		sg_init_table(vi->sq[i].sg, 2);
+		sg_init_table(vi->rq[i].sg, 2);
+	}
+}
+
+/* Register and unregister. */
+static int
+virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
+{
+	struct ifnet *ifp = na->ifp;
+	struct virtnet_info *vi = netdev_priv(ifp);
+	bool was_up = false;
+	int error = 0;
+	enum txrx t;
+	int i;
+
+	/* It's important to make sure each virtnet_close() matches
+	 * a virtnet_open(), otherwise a napi_disable() is not matched by
+	 * a napi_enable(), which results in a deadlock. */
+	if (netif_running(ifp)) {
+		was_up = true;
+		/* Down the interface. This also disables napi. */
+		virtnet_close(ifp);
+	}
+
+	if (onoff) {
+		/* enable netmap mode */
+		for_rx_tx(t) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+
+				if (!nm_kring_pending_on(kring))
+					continue;
+
+				/* Detach and free any unused buffers. */
+				virtio_net_netmap_free_unused(vi, t, i);
+
+				/* Initialize scatter-gater buffers for
+				 * netmap mode. */
+				virtio_net_netmap_init_sgs(vi);
+
+				kring->nr_mode = NKR_NETMAP_ON;
+			}
+		}
+
+		nm_set_native_flags(na);
+	} else {
+		nm_clear_native_flags(na);
+		for_rx_tx(t) {
+			for (i = 0; i <= nma_get_nrings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+
+				if (!nm_kring_pending_off(kring))
+					continue;
+
+				/* Get used netmap buffers. */
+				virtio_net_netmap_drain_used(vi, t, i);
+
+				/* Detach and free any unused buffers. */
+				virtio_net_netmap_free_unused(vi, t, i);
+
+				kring->nr_mode = NKR_NETMAP_OFF;
+			}
+		}
+	}
+
+	if (was_up) {
+		/* Up the interface. This also enables the napi. */
+		virtnet_open(ifp);
+	}
+
+	return (error);
+}
+
 static void
 virtio_net_netmap_attach(struct virtnet_info *vi)
 {
@@ -278,7 +401,7 @@ virtio_net_netmap_attach(struct virtnet_info *vi)
 	na.num_rx_desc = virtqueue_get_vring_size(vi->rq[0].vq);
 	na.num_tx_rings = na.num_rx_rings = vi->max_queue_pairs;
 	na.rx_buf_maxsize = 0;
-	na.nm_register = NULL;
+	na.nm_register = virtio_net_netmap_reg;
 	na.nm_txsync = NULL;
 	na.nm_rxsync = NULL;
 	na.nm_intr = NULL;

From 277f5e9411180d83ebf32aaf5dc7ac41d608cc8b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 18:28:41 +0200
Subject: [PATCH 1127/2207] linux: virtio_net: define VIRTIO_F_VERSION_1 if not
 defined

---
 LINUX/if_virtio_net_netmap.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 7e301f9e0..3d1b717a7 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -31,6 +31,10 @@
 /* COMPATIBILITY LAYER                                                   */
 /*************************************************************************/
 
+#ifndef VIRTIO_F_VERSION_1
+#define VIRTIO_F_VERSION_1		32
+#endif
+
 #ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
 static inline int ethtool_validate_speed(__u32 speed)
 {

From 678cde7346d6ee1db7b569245d79a842df32ac76 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 18:42:59 +0200
Subject: [PATCH 1128/2207] linux: virtio_net.c: add check for
 feature_table_legacy

---
 LINUX/configure                               | 10 ++++++++++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 20 ++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 0541dbae8..8d93825c2 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1885,6 +1885,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTIO_DRIVER_FEATURE_TABLE_LEGACY' <
+
+	bool
+	dummy(struct virtio_driver *vdr)
+	{
+		return vdr->feature_table_legacy != NULL;
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 11970991a..6899773ef 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..cc598ef 100644
+index cbf1c61..e292ba1 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -613,7 +613,7 @@ index cbf1c61..cc598ef 100644
  	return 0;
  }
  #endif
-@@ -2061,15 +1978,20 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,24 +1978,34 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -636,7 +636,21 @@ index cbf1c61..cc598ef 100644
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
  };
-@@ -2091,41 +2013,7 @@ static struct virtio_driver virtio_net_driver = {
+ 
+ static struct virtio_driver virtio_net_driver = {
++#ifdef NETMAP_LINUX_HAVE_VIRTIO_DRIVER_FEATURE_TABLE_LEGACY
+ 	.feature_table = features,
+ 	.feature_table_size = ARRAY_SIZE(features),
+ 	.feature_table_legacy = features_legacy,
+ 	.feature_table_size_legacy = ARRAY_SIZE(features_legacy),
++#else  /* !NETMAP_LINUX_HAVE_VIRTIO_DRIVER_FEATURE_TABLE_LEGACY */
++	.feature_table = features_legacy,
++	.feature_table_size = ARRAY_SIZE(features_legacy),
++#endif /* !NETMAP_LINUX_HAVE_VIRTIO_DRIVER_FEATURE_TABLE_LEGACY */
+ 	.driver.name =	KBUILD_MODNAME,
+ 	.driver.owner =	THIS_MODULE,
+ 	.id_table =	id_table,
+@@ -2091,41 +2018,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From a4ded17c34ab9c5dcf2bced87aa4dd399d062887 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 19:10:07 +0200
Subject: [PATCH 1129/2207] linux: virtio_net.c: implement
 netmap_init_buffers() function

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 98 +++++++++++++------
 LINUX/if_virtio_net_netmap.h                  | 56 +++++++++++
 2 files changed, 123 insertions(+), 31 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 6899773ef..0c13475b8 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..e292ba1 100644
+index cbf1c61..c454ce0 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -95,7 +95,25 @@ index cbf1c61..e292ba1 100644
  /* RX packet size EWMA. The average packet size is used to determine the packet
   * buffer size when refilling RX rings. As the entire RX ring may be refilled
   * at once, the weight is chosen so that the EWMA will be insensitive to short-
-@@ -135,13 +179,6 @@ struct virtnet_info {
+@@ -70,6 +114,8 @@ struct send_queue {
+ 	/* TX: fragments + linear part + virtio header */
+ 	struct scatterlist sg[MAX_SKB_FRAGS + 2];
+ 
++	struct virtio_net_hdr_mrg_rxbuf shared_txvhdr ____cacheline_aligned_in_smp;
++
+ 	/* Name of the send queue: output.$index */
+ 	char name[40];
+ };
+@@ -93,6 +139,8 @@ struct receive_queue {
+ 	/* RX: fragments + linear part + virtio header */
+ 	struct scatterlist sg[MAX_SKB_FRAGS + 2];
+ 
++	struct virtio_net_hdr_mrg_rxbuf shared_rxvhdr ____cacheline_aligned_in_smp;
++
+ 	/* Name of this receive queue: input.$index */
+ 	char name[40];
+ };
+@@ -135,13 +183,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -109,7 +127,7 @@ index cbf1c61..e292ba1 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -226,7 +263,10 @@ static void skb_xmit_done(struct virtqueue *vq)
+@@ -226,7 +267,10 @@ static void skb_xmit_done(struct virtqueue *vq)
  
  	/* Suppress further interrupts. */
  	virtqueue_disable_cb(vq);
@@ -121,7 +139,7 @@ index cbf1c61..e292ba1 100644
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
-@@ -249,6 +289,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+@@ -249,6 +293,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
  	return (unsigned long)buf | (size - 1);
  }
  
@@ -132,7 +150,7 @@ index cbf1c61..e292ba1 100644
  /* Called from bottom half context */
  static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  				   struct receive_queue *rq,
-@@ -263,7 +307,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +311,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -146,7 +164,7 @@ index cbf1c61..e292ba1 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +687,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +691,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -154,7 +172,7 @@ index cbf1c61..e292ba1 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +778,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +782,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -234,7 +252,25 @@ index cbf1c61..e292ba1 100644
  
  static int virtnet_open(struct net_device *dev)
  {
-@@ -840,7 +868,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -789,10 +821,13 @@ static int virtnet_open(struct net_device *dev)
+ 	int i;
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
+-		if (i < vi->curr_queue_pairs)
+-			/* Make sure we have some buffers: if oom use wq. */
+-			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+-				schedule_delayed_work(&vi->refill, 0);
++		if (i < vi->curr_queue_pairs) {
++			if (!virtio_net_netmap_init_buffers(vi, i)) {
++				/* Make sure we have some buffers: if oom use wq. */
++				if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
++					schedule_delayed_work(&vi->refill, 0);
++			}
++		}
+ 		virtnet_napi_enable(&vi->rq[i]);
+ 	}
+ 
+@@ -840,7 +875,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -250,7 +286,7 @@ index cbf1c61..e292ba1 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +901,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +908,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -262,7 +298,7 @@ index cbf1c61..e292ba1 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1048,13 @@ out:
+@@ -1009,8 +1055,13 @@ out:
  	return ret;
  }
  
@@ -278,7 +314,7 @@ index cbf1c61..e292ba1 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1087,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1094,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -291,7 +327,7 @@ index cbf1c61..e292ba1 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1253,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1260,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -387,7 +423,7 @@ index cbf1c61..e292ba1 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1299,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1306,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -396,7 +432,7 @@ index cbf1c61..e292ba1 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1401,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1408,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -416,7 +452,7 @@ index cbf1c61..e292ba1 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1519,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1526,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -425,7 +461,7 @@ index cbf1c61..e292ba1 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1567,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1574,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -442,7 +478,7 @@ index cbf1c61..e292ba1 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1649,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1656,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -453,7 +489,7 @@ index cbf1c61..e292ba1 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1657,6 @@ err:
+@@ -1701,33 +1664,6 @@ err:
  	return ret;
  }
  
@@ -487,7 +523,7 @@ index cbf1c61..e292ba1 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1697,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1704,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -497,7 +533,7 @@ index cbf1c61..e292ba1 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1742,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1749,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -506,7 +542,7 @@ index cbf1c61..e292ba1 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1752,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1759,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -521,7 +557,7 @@ index cbf1c61..e292ba1 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1814,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -529,7 +565,7 @@ index cbf1c61..e292ba1 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1822,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1829,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -537,7 +573,7 @@ index cbf1c61..e292ba1 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1836,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1843,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -548,7 +584,7 @@ index cbf1c61..e292ba1 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1847,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1854,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -566,7 +602,7 @@ index cbf1c61..e292ba1 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1868,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1875,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -577,7 +613,7 @@ index cbf1c61..e292ba1 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1897,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1904,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -593,7 +629,7 @@ index cbf1c61..e292ba1 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1918,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1925,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -602,7 +638,7 @@ index cbf1c61..e292ba1 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1960,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1967,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -613,7 +649,7 @@ index cbf1c61..e292ba1 100644
  	return 0;
  }
  #endif
-@@ -2061,24 +1978,34 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,24 +1985,34 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -650,7 +686,7 @@ index cbf1c61..e292ba1 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2018,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2025,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 3d1b717a7..441cb3fd9 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -392,6 +392,62 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 	return (error);
 }
 
+/* Prepare an RX virtqueue for netmap operation. Returns true if
+ * the queue is ready for netmap and false if it is not going to
+ * work in netmap mode. */
+static bool
+virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
+{
+	size_t vnet_hdr_len = vi->mergeable_rx_bufs ?
+				sizeof(vi->rq[r].shared_rxvhdr) :
+				sizeof(vi->rq[r].shared_rxvhdr.hdr);
+	struct netmap_adapter *na = NA(vi->dev);
+	struct netmap_kring *kring;
+	int i;
+
+	if (!nm_netmap_on(na)) {
+		return false;
+	}
+
+	kring = na->rx_rings[r];
+	if (kring->nr_mode != NKR_NETMAP_ON) {
+		return false;
+	}
+
+	/*
+	 * Add exactly na->num_rx_desc descriptor chains to this RX
+	 * virtqueue, as virtio_netmap_rxsync() assumes the chains
+	 * are returned in the same order by virtqueue_get_buf().
+	 * It is technically possible that the hypervisor returns
+	 * na->num_rx_desc chains before the user can consume them,
+	 * so virtio_netmap_rxsync() must prevent ring->tail to
+	 * wrap around ring->head.
+	 */
+	for (i = 0; i < na->num_rx_desc; i++) {
+		struct netmap_ring *ring = kring->ring;
+		struct virtqueue *vq = vi->rq[r].vq;
+		struct scatterlist *sg = vi->rq[r].sg;
+		struct netmap_slot *slot;
+		void *addr;
+		int err;
+
+		slot = &ring->slot[i];
+		addr = NMB(na, slot);
+		sg_set_buf(sg, &vi->rq[r].shared_rxvhdr, vnet_hdr_len);
+		sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na));
+		err = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC);
+		if (err < 0) {
+			nm_prerr("virtqueue_add_inbuf() failed\n");
+			return 0;
+		}
+
+		if (vq->num_free == 0)
+			break;
+	}
+
+	return true;
+}
+
 static void
 virtio_net_netmap_attach(struct virtnet_info *vi)
 {

From 928493c6162c193f946c42ee16dea93be192992e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 8 Oct 2018 19:13:00 +0200
Subject: [PATCH 1130/2207] linux: virtio_net.c: don't use BUILD_BUG_ON()

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 83 ++++++++-----------
 1 file changed, 35 insertions(+), 48 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 0c13475b8..0996a2de8 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..c454ce0 100644
+index cbf1c61..a1e3263 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -44,7 +44,7 @@ index cbf1c61..c454ce0 100644
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -40,6 +40,50 @@ module_param(gso, bool, 0444);
+@@ -40,6 +40,37 @@ module_param(gso, bool, 0444);
  #define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
  #define GOOD_COPY_LEN	128
  
@@ -58,19 +58,11 @@ index cbf1c61..c454ce0 100644
 +	};								\
 +	static inline void ewma_##name##_init(struct ewma_##name *e)	\
 +	{								\
-+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
 +		e->internal = 0;					\
 +	}								\
 +	static inline unsigned long					\
 +	ewma_##name##_read(struct ewma_##name *e)			\
 +	{								\
-+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
 +		return e->internal >> ilog2(_factor);			\
 +	}								\
 +	static inline void ewma_##name##_add(struct ewma_##name *e,	\
@@ -80,11 +72,6 @@ index cbf1c61..c454ce0 100644
 +		unsigned long weight = ilog2(_weight);			\
 +		unsigned long factor = ilog2(_factor);			\
 +									\
-+		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
-+		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
-+		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
-+									\
 +		ACCESS_ONCE(e->internal) = internal ?			\
 +			(((internal << weight) - internal) +		\
 +				(val << factor)) >> weight :		\
@@ -95,7 +82,7 @@ index cbf1c61..c454ce0 100644
  /* RX packet size EWMA. The average packet size is used to determine the packet
   * buffer size when refilling RX rings. As the entire RX ring may be refilled
   * at once, the weight is chosen so that the EWMA will be insensitive to short-
-@@ -70,6 +114,8 @@ struct send_queue {
+@@ -70,6 +101,8 @@ struct send_queue {
  	/* TX: fragments + linear part + virtio header */
  	struct scatterlist sg[MAX_SKB_FRAGS + 2];
  
@@ -104,7 +91,7 @@ index cbf1c61..c454ce0 100644
  	/* Name of the send queue: output.$index */
  	char name[40];
  };
-@@ -93,6 +139,8 @@ struct receive_queue {
+@@ -93,6 +126,8 @@ struct receive_queue {
  	/* RX: fragments + linear part + virtio header */
  	struct scatterlist sg[MAX_SKB_FRAGS + 2];
  
@@ -113,7 +100,7 @@ index cbf1c61..c454ce0 100644
  	/* Name of this receive queue: input.$index */
  	char name[40];
  };
-@@ -135,13 +183,6 @@ struct virtnet_info {
+@@ -135,13 +170,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -127,7 +114,7 @@ index cbf1c61..c454ce0 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -226,7 +267,10 @@ static void skb_xmit_done(struct virtqueue *vq)
+@@ -226,7 +254,10 @@ static void skb_xmit_done(struct virtqueue *vq)
  
  	/* Suppress further interrupts. */
  	virtqueue_disable_cb(vq);
@@ -139,7 +126,7 @@ index cbf1c61..c454ce0 100644
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
-@@ -249,6 +293,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+@@ -249,6 +280,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
  	return (unsigned long)buf | (size - 1);
  }
  
@@ -150,7 +137,7 @@ index cbf1c61..c454ce0 100644
  /* Called from bottom half context */
  static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  				   struct receive_queue *rq,
-@@ -263,7 +311,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +298,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -164,7 +151,7 @@ index cbf1c61..c454ce0 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +691,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +678,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -172,7 +159,7 @@ index cbf1c61..c454ce0 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +782,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +769,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -252,7 +239,7 @@ index cbf1c61..c454ce0 100644
  
  static int virtnet_open(struct net_device *dev)
  {
-@@ -789,10 +821,13 @@ static int virtnet_open(struct net_device *dev)
+@@ -789,10 +808,13 @@ static int virtnet_open(struct net_device *dev)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -270,7 +257,7 @@ index cbf1c61..c454ce0 100644
  		virtnet_napi_enable(&vi->rq[i]);
  	}
  
-@@ -840,7 +875,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +862,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -286,7 +273,7 @@ index cbf1c61..c454ce0 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +908,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +895,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -298,7 +285,7 @@ index cbf1c61..c454ce0 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1055,13 @@ out:
+@@ -1009,8 +1042,13 @@ out:
  	return ret;
  }
  
@@ -314,7 +301,7 @@ index cbf1c61..c454ce0 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1094,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1081,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -327,7 +314,7 @@ index cbf1c61..c454ce0 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1260,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1247,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -423,7 +410,7 @@ index cbf1c61..c454ce0 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1306,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1293,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -432,7 +419,7 @@ index cbf1c61..c454ce0 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1408,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1395,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -452,7 +439,7 @@ index cbf1c61..c454ce0 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1526,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1513,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -461,7 +448,7 @@ index cbf1c61..c454ce0 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1574,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1561,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -478,7 +465,7 @@ index cbf1c61..c454ce0 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1656,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1643,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -489,7 +476,7 @@ index cbf1c61..c454ce0 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1664,6 @@ err:
+@@ -1701,33 +1651,6 @@ err:
  	return ret;
  }
  
@@ -523,7 +510,7 @@ index cbf1c61..c454ce0 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1704,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1691,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -533,7 +520,7 @@ index cbf1c61..c454ce0 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1749,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1736,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -542,7 +529,7 @@ index cbf1c61..c454ce0 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1759,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1746,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -557,7 +544,7 @@ index cbf1c61..c454ce0 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1808,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -565,7 +552,7 @@ index cbf1c61..c454ce0 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1829,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1816,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -573,7 +560,7 @@ index cbf1c61..c454ce0 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1843,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1830,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -584,7 +571,7 @@ index cbf1c61..c454ce0 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1854,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1841,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -602,7 +589,7 @@ index cbf1c61..c454ce0 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1875,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1862,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -613,7 +600,7 @@ index cbf1c61..c454ce0 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1904,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1891,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -629,7 +616,7 @@ index cbf1c61..c454ce0 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1925,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1912,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -638,7 +625,7 @@ index cbf1c61..c454ce0 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1967,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1954,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -649,7 +636,7 @@ index cbf1c61..c454ce0 100644
  	return 0;
  }
  #endif
-@@ -2061,24 +1985,34 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,24 +1972,34 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -686,7 +673,7 @@ index cbf1c61..c454ce0 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2025,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2012,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 387a96d4c4a5a9bc477535f27b28c3890863a998 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 09:14:24 +0200
Subject: [PATCH 1131/2207] ci: build-linux: use allmodconfig to generate
 .config

---
 ci/build-linux | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 653dd7de4..d5a784d61 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -53,7 +53,7 @@ then
   popd
 fi
 make mrproper
-make -j $PROC_COUNT ARCH=${ARCH} defconfig
+make -j $PROC_COUNT ARCH=${ARCH} allmodconfig
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 

From 629578dfe7602a105c291951252a1e88a46c7178 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 09:55:57 +0200
Subject: [PATCH 1132/2207] linux: virtio_net.c: add compatibility support for
 virtio_device_ready()

---
 LINUX/configure              | 10 ++++++++++
 LINUX/if_virtio_net_netmap.h | 11 +++++++++++
 2 files changed, 21 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 8d93825c2..c2e9a0f52 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1895,6 +1895,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTIO_DEVICE_READY' <
+
+	void
+	dummy(struct virtio_device *vdev)
+	{
+		virtio_device_ready(vdev);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 441cb3fd9..23c8ffdbc 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -265,6 +265,17 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
 #define virtqueue_get_vring_size(_vq)	({ (void)(_vq); 256; })
 #endif  /* !VIRTIO_GET_VRSIZE */
 
+#ifndef NETMAP_LINUX_HAVE_VIRTIO_DEVICE_READY
+static inline
+void virtio_device_ready(struct virtio_device *dev)
+{
+	unsigned status = dev->config->get_status(dev);
+
+	BUG_ON(status & VIRTIO_CONFIG_S_DRIVER_OK);
+	dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK);
+}
+#endif  /* NETMAP_LINUX_HAVE_VIRTIO_DEVICE_READY */
+
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */
 /*************************************************************************/

From de3afe96af4683d44d65e34f5a5ea0391ea185b2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 10:31:19 +0200
Subject: [PATCH 1133/2207] linux: virtio_net.c: add compatibility support for
 u64_stats_*_irq

---
 LINUX/configure              | 9 +++++++++
 LINUX/if_virtio_net_netmap.h | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index c2e9a0f52..759f1328d 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1635,6 +1635,15 @@ EOF
 	}
 EOF
 
+  add_test 'have U64_STATS_IRQ' <
+
+	unsigned int
+	dummy(const struct u64_stats_sync *x) {
+		return u64_stats_fetch_begin_irq(x);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 23c8ffdbc..f53da2c93 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -276,6 +276,11 @@ void virtio_device_ready(struct virtio_device *dev)
 }
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_DEVICE_READY */
 
+#ifndef NETMAP_LINUX_HAVE_U64_STATS_IRQ
+#define u64_stats_fetch_begin_irq	u64_stats_fetch_begin_bh
+#define u64_stats_fetch_retry_irq	u64_stats_fetch_retry_bh
+#endif  /* NETMAP_LINUX_HAVE_U64_STATS_IRQ */
+
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */
 /*************************************************************************/

From 2a82d90d2a1934ba5c29d11703ac62757f79faab Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 12:24:03 +0200
Subject: [PATCH 1134/2207] linux: add compatibility support for
 virtqueue_is_broken

---
 LINUX/configure              | 10 ++++++++++
 LINUX/if_virtio_net_netmap.h |  4 ++++
 2 files changed, 14 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 759f1328d..d3ec18df2 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1914,6 +1914,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTQUEUE_IS_BROKEN' <
+
+	bool
+	dummy(struct virtqueue *vq)
+	{
+		return virtqueue_is_broken(vq);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index f53da2c93..ca5baf836 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -281,6 +281,10 @@ void virtio_device_ready(struct virtio_device *dev)
 #define u64_stats_fetch_retry_irq	u64_stats_fetch_retry_bh
 #endif  /* NETMAP_LINUX_HAVE_U64_STATS_IRQ */
 
+#ifndef NETMAP_LINUX_HAVE_VIRTQUEUE_IS_BROKEN
+#define virtqueue_is_broken(_x)	false
+#endif  /* NETMAP_LINUX_HAVE_VIRTQUEUE_IS_BROKEN */
+
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */
 /*************************************************************************/

From cbc22ee1c1ce892605a117780e29518b83065ed1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 16:16:06 +0200
Subject: [PATCH 1135/2207] linux: virtio_net.c: implement txsync and rxsync

---
 LINUX/if_virtio_net_netmap.h | 232 ++++++++++++++++++++++++++++++++++-
 1 file changed, 230 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index ca5baf836..1e9e19ce7 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -285,6 +285,11 @@ void virtio_device_ready(struct virtio_device *dev)
 #define virtqueue_is_broken(_x)	false
 #endif  /* NETMAP_LINUX_HAVE_VIRTQUEUE_IS_BROKEN */
 
+#ifndef NETMAP_LINUX_VIRTIO_CB_DELAYED
+/* The delayed optimization did not exists before version 3.0. */
+#define virtqueue_enable_cb_delayed(_vq)	virtqueue_enable_cb(_vq)
+#endif  /* !VIRTIO_CB_DELAYED */
+
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */
 /*************************************************************************/
@@ -464,10 +469,233 @@ virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
 		if (vq->num_free == 0)
 			break;
 	}
+	nm_prinf("%s-rx-%d: %d netmap buffers published\n", na->name,
+			r, i);
 
 	return true;
 }
 
+/* Reconcile kernel and user view of the transmit ring. */
+static int
+virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int ring_nr = kring->ring_id;
+	u_int nm_i;	/* index into the netmap ring */
+	u_int nic_i;	/* index into the NIC ring */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+
+	/* device-specific */
+	struct virtnet_info *vi = netdev_priv(ifp);
+	struct send_queue *sq = vi->sq + ring_nr;
+	struct virtqueue *vq = sq->vq;
+	struct scatterlist *sg = sq->sg;
+	size_t vnet_hdr_len = vi->mergeable_rx_bufs ?
+				sizeof(sq->shared_txvhdr) :
+				sizeof(sq->shared_txvhdr.hdr);
+	struct netmap_adapter *token;
+	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
+	int nospace = 0;
+
+	virtqueue_disable_cb(vq);
+
+	/* Free used slots. We only consider our own used buffers, recognized
+	 * by the token we passed to virtqueue_add_outbuf.
+	 */
+	n = 0;
+	for (;;) {
+		token = virtqueue_get_buf(vq, &nic_i); /* dummy 2nd arg */
+		if (token == NULL)
+			break;
+		if (likely(token == na))
+			n++;
+	}
+	kring->nr_hwtail += n;
+	if (kring->nr_hwtail > lim)
+		kring->nr_hwtail -= lim + 1;
+
+	/*
+	 * First part: process new packets to send.
+	 */
+	rmb();
+
+	if (!netif_running(ifp)) {
+		/* All the new slots are now unavailable. */
+		goto out;
+	}
+
+	nm_i = kring->nr_hwcur;
+	if (nm_i != head) {	/* we have new packets to send */
+		nic_i = netmap_idx_k2n(kring, nm_i);
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			u_int len = slot->len;
+			void *addr = NMB(na, slot);
+
+			NM_CHECK_ADDR_LEN(na, addr, len);
+
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			/* Initialize the scatterlist and expose it to
+			 * the hypervisor. */
+			sg_set_buf(sg, &sq->shared_txvhdr, vnet_hdr_len);
+			sg_set_buf(sg + 1, addr, len);
+			nospace = virtqueue_add_outbuf(vq, sg, 2, na, GFP_ATOMIC);
+			if (nospace) {
+				RD(3, "virtqueue_add_outbuf failed [err=%d]",
+				   nospace);
+				break;
+			}
+
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+		}
+
+		virtqueue_kick(vq);
+
+		/* Update hwcur depending on where we stopped. */
+		kring->nr_hwcur = nm_i; /* note we migth break early */
+	}
+out:
+	/* No more free virtio descriptors or netmap slots? Ask the
+	 * hypervisor for notifications, possibly only when it has
+	 * freed a considerable amount of pending descriptors.
+	 */
+	if (interrupts && (nm_kr_txempty(kring) || nospace)) {
+		virtqueue_enable_cb_delayed(vq);
+	}
+
+	return 0;
+}
+
+/* Reconcile kernel and user view of the receive ring. */
+static int
+virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int ring_nr = kring->ring_id;
+	u_int nm_i;	/* index into the netmap ring */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+
+	/* device-specific */
+	struct virtnet_info *vi = netdev_priv(ifp);
+	struct receive_queue *rq = vi->rq + ring_nr;
+	struct virtqueue *vq = rq->vq;
+	struct scatterlist *sg = rq->sg;
+	size_t vnet_hdr_len = vi->mergeable_rx_bufs ?
+				sizeof(rq->shared_rxvhdr) :
+				sizeof(rq->shared_rxvhdr.hdr);
+	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
+
+	/* XXX netif_carrier_ok ? */
+
+	if (head > lim)
+		return netmap_ring_reinit(kring);
+
+	virtqueue_disable_cb(vq);
+
+	rmb();
+	/*
+	 * First part: import newly received packets.
+	 * Only accept our own buffers (matching the token). We should only get
+	 * matching buffers, because of virtio_net_netmap_free_unused and
+	 * virtio_net_netmap_init_buffers(). We may need to stop early to avoid
+	 * hwtail to overrun hwcur;
+	 */
+	if (netmap_no_pendintr || force_update) {
+		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
+		struct netmap_adapter *token;
+
+
+		nm_i = kring->nr_hwtail;
+		n = 0;
+		while (nm_i != hwtail_lim) {
+			int len;
+			token = virtqueue_get_buf(vq, &len);
+			if (token == NULL)
+				break;
+
+			if (unlikely(token != na)) {
+				RD(5, "Received unexpected virtqueue token %p\n",
+						token);
+			} else {
+				/* Skip the virtio-net header. */
+				len -= vnet_hdr_len;
+				if (unlikely(len < 0)) {
+					RD(5, "Truncated virtio-net-header, missing %d"
+							" bytes", -len);
+					len = 0;
+				}
+
+				ring->slot[nm_i].len = len;
+				ring->slot[nm_i].flags = 0;
+				nm_i = nm_next(nm_i, lim);
+				n++;
+			}
+		}
+		kring->nr_hwtail = nm_i;
+		kring->nr_kflags &= ~NKR_PENDINTR;
+	}
+	ND("[B] h %d c %d hwcur %d hwtail %d",
+			ring->head, ring->cur, kring->nr_hwcur,
+			kring->nr_hwtail);
+
+	/*
+	 * Second part: skip past packets that userspace has released.
+	 */
+	nm_i = kring->nr_hwcur; /* netmap ring index */
+	if (nm_i != head) {
+		int nospace = 0;
+
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			void *addr = NMB(na, slot);
+
+			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
+				return netmap_ring_reinit(kring);
+
+			slot->flags &= ~NS_BUF_CHANGED;
+
+			/* Initialize the scatterlist and expose it to
+			 * the hypervisor. */
+			sg_set_buf(sg, &rq->shared_rxvhdr, vnet_hdr_len);
+			sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na));
+			nospace = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC);
+			if (nospace) {
+				RD(3, "virtqueue_add_inbuf failed [err=%d]",
+				   nospace);
+				break;
+			}
+			nm_i = nm_next(nm_i, lim);
+		}
+		virtqueue_kick(vq);
+		kring->nr_hwcur = head;
+	}
+
+	/* We have finished processing used RX buffers, so we have to tell
+	 * the hypervisor to make a call when more used RX buffers will be
+	 * ready.
+	 */
+	if (interrupts) {
+		virtqueue_enable_cb(vq);
+	}
+
+
+	ND("[C] h %d c %d t %d hwcur %d hwtail %d",
+			ring->head, ring->cur, ring->tail,
+			kring->nr_hwcur, kring->nr_hwtail);
+
+	return 0;
+}
+
 static void
 virtio_net_netmap_attach(struct virtnet_info *vi)
 {
@@ -482,8 +710,8 @@ virtio_net_netmap_attach(struct virtnet_info *vi)
 	na.num_tx_rings = na.num_rx_rings = vi->max_queue_pairs;
 	na.rx_buf_maxsize = 0;
 	na.nm_register = virtio_net_netmap_reg;
-	na.nm_txsync = NULL;
-	na.nm_rxsync = NULL;
+	na.nm_txsync = virtio_net_netmap_txsync;
+	na.nm_rxsync = virtio_net_netmap_rxsync;
 	na.nm_intr = NULL;
 	na.nm_config = NULL;
 

From d91e44d5e5eb9382054097d613b9c8183f1d39b0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 16:18:55 +0200
Subject: [PATCH 1136/2207] linux: virtio_net.c: implement nm_intr() callback

---
 LINUX/if_virtio_net_netmap.h | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 1e9e19ce7..12e8f3d83 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -696,6 +696,29 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	return 0;
 }
 
+/* Enable/disable interrupts on all virtqueues. */
+static void
+virtio_net_netmap_intr(struct netmap_adapter *na, int onoff)
+{
+	struct virtnet_info *vi = netdev_priv(na->ifp);
+	enum txrx t;
+	int i;
+
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(na, t); i++) {
+			struct virtqueue *vq;
+
+			vq = t == NR_RX ? vi->rq[i].vq : vi->sq[i].vq;
+
+			if (onoff) {
+				virtqueue_enable_cb(vq);
+			} else {
+				virtqueue_disable_cb(vq);
+			}
+		}
+	}
+}
+
 static void
 virtio_net_netmap_attach(struct virtnet_info *vi)
 {
@@ -712,7 +735,7 @@ virtio_net_netmap_attach(struct virtnet_info *vi)
 	na.nm_register = virtio_net_netmap_reg;
 	na.nm_txsync = virtio_net_netmap_txsync;
 	na.nm_rxsync = virtio_net_netmap_rxsync;
-	na.nm_intr = NULL;
+	na.nm_intr = virtio_net_netmap_intr;
 	na.nm_config = NULL;
 
 	netmap_attach(&na);

From 7aceab11f26124769341d5112754f8198650c9f0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 16:22:34 +0200
Subject: [PATCH 1137/2207] linux: virtio_net.c: fix indentation

---
 LINUX/if_virtio_net_netmap.h | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 12e8f3d83..beaa4ee9c 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -564,9 +564,8 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * hypervisor for notifications, possibly only when it has
 	 * freed a considerable amount of pending descriptors.
 	 */
-	if (interrupts && (nm_kr_txempty(kring) || nospace)) {
+	if (interrupts && (nm_kr_txempty(kring) || nospace))
 		virtqueue_enable_cb_delayed(vq);
-	}
 
 	return 0;
 }
@@ -684,9 +683,8 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * the hypervisor to make a call when more used RX buffers will be
 	 * ready.
 	 */
-	if (interrupts) {
+	if (interrupts)
 		virtqueue_enable_cb(vq);
-	}
 
 
 	ND("[C] h %d c %d t %d hwcur %d hwtail %d",
@@ -710,11 +708,10 @@ virtio_net_netmap_intr(struct netmap_adapter *na, int onoff)
 
 			vq = t == NR_RX ? vi->rq[i].vq : vi->sq[i].vq;
 
-			if (onoff) {
+			if (onoff)
 				virtqueue_enable_cb(vq);
-			} else {
+			else
 				virtqueue_disable_cb(vq);
-			}
 		}
 	}
 }

From cb6a6248b88b3ea7655cbf7affdd96195a756b8d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 17:39:34 +0200
Subject: [PATCH 1138/2207] linux: virtio_net.c: use make macro to define build
 variables

---
 LINUX/default-config.mak.in_ | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 2e593a36e..f094cb98a 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -107,6 +107,7 @@ mlx5@conf	= CONFIG_MLX5_CORE_EN
 
 $(foreach d,$(filter mlx5,$(E_DRIVERS)),$(eval $(call mellanox_driver,$d,$($(d)@v))))
 
+define virtio_net
 virtio_net.c@fetch	:= test -e @SRCDIR@/ext-drivers/virtio_net.c || wget https://raw.githubusercontent.com/torvalds/linux/v4.9/drivers/net/virtio_net.c -P @SRCDIR@/ext-drivers/
 virtio_net.c@src	:= mkdir -p virtio_net.c && cp @SRCDIR@/ext-drivers/virtio_net.c virtio_net.c/
 virtio_net.c@patch	:= patches/custom--virtio_net.c--4.9
@@ -116,3 +117,6 @@ virtio_net.c@install 	:= make -C virtio_net.c install INSTALL_MOD_PATH=@MODPATH@
 virtio_net.c@clean 	:= if [ -d virtio_net.c ]; then make -C virtio_net.c clean EXTRA_CFLAGS="$(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
 virtio_net.c@distclean	:=
 virtio_net.c@force	:= 1
+endef
+
+$(foreach d,$(filter virtio_net.c,$(E_DRIVERS)),$(eval $(call virtio_net)))

From 636cd469dc5e9e98f00527abaac3dd12e944417d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 17:56:52 +0200
Subject: [PATCH 1139/2207] travis: add debug ls command

---
 ci/build-linux | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ci/build-linux b/ci/build-linux
index d5a784d61..ed4f178fa 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -16,6 +16,8 @@ function set_config_variable()
 
 set -o pipefail
 
+git clean -fdx
+
 readonly KERNEL_VERSION=${1:?}
 readonly ARCH=${2:?}
 readonly GCC_MAJOR_VERSION=$(echo '#include 
@@ -62,6 +64,9 @@ echo "Building vanilla-only drivers"
 ./configure --no-ext-drivers --driver-suffix=_netmap --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=r8169.c,virtio_net.c,forcedeth.c,veth.c,e1000,vmxnet3 --enable-ptnetmap
 make -j $PROC_COUNT
 
+# TODO remove
+ls -l
+
 # Then build external intel drivers
 make distclean
 echo "Building external intel drivers"

From 41528e237f4e4f30eb2f9460b79726d9990b1ede Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 18:13:40 +0200
Subject: [PATCH 1140/2207] linux: virtio_net.c: fix loop range

---
 LINUX/if_virtio_net_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index beaa4ee9c..a355ca06e 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -392,7 +392,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 	} else {
 		nm_clear_native_flags(na);
 		for_rx_tx(t) {
-			for (i = 0; i <= nma_get_nrings(na, t); i++) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (!nm_kring_pending_off(kring))

From 2c13fc3d62d7110742a04edb7e45b7d74f6cdf47 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 18:27:06 +0200
Subject: [PATCH 1141/2207] linux: virtio_net.c: free detached buffers only
 when entering netmap mode

---
 LINUX/if_virtio_net_netmap.h | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index a355ca06e..576846c29 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -298,15 +298,20 @@ static int virtnet_open(struct net_device *dev);
 static int virtnet_close(struct net_device *dev);
 
 static void
-virtio_net_netmap_free_unused(struct virtnet_info *vi, enum txrx t, int i)
+virtio_net_netmap_free_unused(struct virtnet_info *vi, bool onoff,
+				enum txrx t, int i)
 {
 	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
+	unsigned int n = 0;
 	void *buf;
 
 	while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
-		if (t == NR_TX)
+		if (!onoff) {
+			/* This vq contains netmap buffers, so there
+			 * is nothing to do */
+		} else if (t == NR_TX) {
 			dev_kfree_skb(buf);
-		else {
+		} else {
 			if (vi->mergeable_rx_bufs) {
 				unsigned long ctx = (unsigned long)buf;
 				void *base = mergeable_ctx_to_buf_address(ctx);
@@ -317,18 +322,26 @@ virtio_net_netmap_free_unused(struct virtnet_info *vi, enum txrx t, int i)
 				dev_kfree_skb(buf);
 			}
 		}
+		n++;
 	}
+
+	if (i)
+		nm_prinf("%d sgs detached on %s-%d\n", n, nm_txrx2str(t), i);
 }
 
 static void
 virtio_net_netmap_drain_used(struct virtnet_info *vi, enum txrx t, int i)
 {
 	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
-	unsigned int len;
+	unsigned int len, n = 0;
 	void *buf;
 
 	while ((buf = virtqueue_get_buf(vq, &len)) != NULL) {
+		n++;
 	}
+
+	if (i)
+		nm_prinf("%d sgs drained on %s-%d\n", n, nm_txrx2str(t), i);
 }
 
 /* Initialize scatter-gather lists used to publish netmap
@@ -378,7 +391,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 					continue;
 
 				/* Detach and free any unused buffers. */
-				virtio_net_netmap_free_unused(vi, t, i);
+				virtio_net_netmap_free_unused(vi, onoff, t, i);
 
 				/* Initialize scatter-gater buffers for
 				 * netmap mode. */
@@ -402,7 +415,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 				virtio_net_netmap_drain_used(vi, t, i);
 
 				/* Detach and free any unused buffers. */
-				virtio_net_netmap_free_unused(vi, t, i);
+				virtio_net_netmap_free_unused(vi, onoff, t, i);
 
 				kring->nr_mode = NKR_NETMAP_OFF;
 			}

From b9bd5be4cb1c893f6327817f5f3020117d42d471 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 9 Oct 2018 18:56:35 +0200
Subject: [PATCH 1142/2207] linux: virtio-net.c: fix bug in nm_prinf()

---
 LINUX/if_virtio_net_netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 576846c29..e664d2cd3 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -325,7 +325,7 @@ virtio_net_netmap_free_unused(struct virtnet_info *vi, bool onoff,
 		n++;
 	}
 
-	if (i)
+	if (n)
 		nm_prinf("%d sgs detached on %s-%d\n", n, nm_txrx2str(t), i);
 }
 
@@ -340,7 +340,7 @@ virtio_net_netmap_drain_used(struct virtnet_info *vi, enum txrx t, int i)
 		n++;
 	}
 
-	if (i)
+	if (n)
 		nm_prinf("%d sgs drained on %s-%d\n", n, nm_txrx2str(t), i);
 }
 

From 78d141ec68365bd51420fbe1b3238dbe9b85d8cd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 11:18:19 +0200
Subject: [PATCH 1143/2207] linux: virtio_net_netmap_init_buffers: improve loop

---
 LINUX/if_virtio_net_netmap.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index e664d2cd3..565435735 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -326,7 +326,8 @@ virtio_net_netmap_free_unused(struct virtnet_info *vi, bool onoff,
 	}
 
 	if (n)
-		nm_prinf("%d sgs detached on %s-%d\n", n, nm_txrx2str(t), i);
+		nm_prinf("%d sgs detached on %s-%d (onoff=%d)\n",
+			 n, nm_txrx2str(t), i, onoff);
 }
 
 static void
@@ -441,6 +442,7 @@ virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
 				sizeof(vi->rq[r].shared_rxvhdr.hdr);
 	struct netmap_adapter *na = NA(vi->dev);
 	struct netmap_kring *kring;
+	struct virtqueue *vq;
 	int i;
 
 	if (!nm_netmap_on(na)) {
@@ -452,6 +454,8 @@ virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
 		return false;
 	}
 
+	vq = vi->rq[r].vq;
+
 	/*
 	 * Add exactly na->num_rx_desc descriptor chains to this RX
 	 * virtqueue, as virtio_netmap_rxsync() assumes the chains
@@ -461,9 +465,8 @@ virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
 	 * so virtio_netmap_rxsync() must prevent ring->tail to
 	 * wrap around ring->head.
 	 */
-	for (i = 0; i < na->num_rx_desc; i++) {
+	for (i = 0; i < na->num_rx_desc && vq->num_free > 0; i++) {
 		struct netmap_ring *ring = kring->ring;
-		struct virtqueue *vq = vi->rq[r].vq;
 		struct scatterlist *sg = vi->rq[r].sg;
 		struct netmap_slot *slot;
 		void *addr;
@@ -478,9 +481,6 @@ virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
 			nm_prerr("virtqueue_add_inbuf() failed\n");
 			return 0;
 		}
-
-		if (vq->num_free == 0)
-			break;
 	}
 	nm_prinf("%s-rx-%d: %d netmap buffers published\n", na->name,
 			r, i);

From ccc116b50e6a1dc87f7c7b1feee5c293f2ae562b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 11:20:56 +0200
Subject: [PATCH 1144/2207] ci/build-linux: add instructions to build
 virtio_net.c as external

---
 ci/build-linux | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index ed4f178fa..d5e304a53 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -59,14 +59,18 @@ make -j $PROC_COUNT ARCH=${ARCH} allmodconfig
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
+echo "Building external virtio_net.c"
+./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=virtio_net.c
+make -j $PROC_COUNT
+# TODO remove
+ls -l
+make distclean
+
 # First build in-tree-only drivers
 echo "Building vanilla-only drivers"
 ./configure --no-ext-drivers --driver-suffix=_netmap --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=r8169.c,virtio_net.c,forcedeth.c,veth.c,e1000,vmxnet3 --enable-ptnetmap
 make -j $PROC_COUNT
 
-# TODO remove
-ls -l
-
 # Then build external intel drivers
 make distclean
 echo "Building external intel drivers"

From 2967ce8e4e3d19d082c3f516c6fd0c478917b1db Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 11:39:07 +0200
Subject: [PATCH 1145/2207] linux: virtio_net.c: detach buffers before enabling
 netmap mode

---
 LINUX/if_virtio_net_netmap.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 565435735..99d667cc7 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -384,6 +384,8 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 
 	if (onoff) {
 		/* enable netmap mode */
+		nm_set_native_flags(na);
+
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
@@ -401,10 +403,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 				kring->nr_mode = NKR_NETMAP_ON;
 			}
 		}
-
-		nm_set_native_flags(na);
 	} else {
-		nm_clear_native_flags(na);
 		for_rx_tx(t) {
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
@@ -421,6 +420,8 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 				kring->nr_mode = NKR_NETMAP_OFF;
 			}
 		}
+
+		nm_clear_native_flags(na);
 	}
 
 	if (was_up) {

From 4cf0254fcbdd21a6dd2fb320dba88cbc8999c5d0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 11:51:36 +0200
Subject: [PATCH 1146/2207] linux: virtio_net.c: drain used buffers also on
 entering netmap mode

---
 LINUX/if_virtio_net_netmap.h | 32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 99d667cc7..dc3d5052c 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -307,8 +307,8 @@ virtio_net_netmap_free_unused(struct virtnet_info *vi, bool onoff,
 
 	while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
 		if (!onoff) {
-			/* This vq contains netmap buffers, so there
-			 * is nothing to do */
+			/* This is a netmap buffer, so there is
+			 * nothing to do. */
 		} else if (t == NR_TX) {
 			dev_kfree_skb(buf);
 		} else {
@@ -331,18 +331,33 @@ virtio_net_netmap_free_unused(struct virtnet_info *vi, bool onoff,
 }
 
 static void
-virtio_net_netmap_drain_used(struct virtnet_info *vi, enum txrx t, int i)
+virtio_net_netmap_drain_used(struct virtnet_info *vi, bool onoff,
+				enum txrx t, int i)
 {
 	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
 	unsigned int len, n = 0;
 	void *buf;
 
+	if (onoff && t == NR_RX) {
+		/* An RX kring is entering netmap mode. Since NAPI has
+		 * been disabled, there cannot be any pending used
+		 * buffers. */
+		return;
+	}
+
 	while ((buf = virtqueue_get_buf(vq, &len)) != NULL) {
+		if (!onoff) {
+			/* This is a netmap buffer, so there is
+			 * nothing to do. */
+		} else if (t == NR_TX) {
+			dev_kfree_skb(buf);
+		}
 		n++;
 	}
 
 	if (n)
-		nm_prinf("%d sgs drained on %s-%d\n", n, nm_txrx2str(t), i);
+		nm_prinf("%d sgs drained on %s-%d (onoff=%d)\n",
+			n, nm_txrx2str(t), i, onoff);
 }
 
 /* Initialize scatter-gather lists used to publish netmap
@@ -393,7 +408,10 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 				if (!nm_kring_pending_on(kring))
 					continue;
 
-				/* Detach and free any unused buffers. */
+				/* Get used OS buffers. */
+				virtio_net_netmap_drain_used(vi, onoff, t, i);
+
+				/* Detach and free any unused OS buffers. */
 				virtio_net_netmap_free_unused(vi, onoff, t, i);
 
 				/* Initialize scatter-gater buffers for
@@ -412,9 +430,9 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 					continue;
 
 				/* Get used netmap buffers. */
-				virtio_net_netmap_drain_used(vi, t, i);
+				virtio_net_netmap_drain_used(vi, onoff, t, i);
 
-				/* Detach and free any unused buffers. */
+				/* Detach and free any unused netmap buffers. */
 				virtio_net_netmap_free_unused(vi, onoff, t, i);
 
 				kring->nr_mode = NKR_NETMAP_OFF;

From 308e36a863bfa048465ddd59de54c8a986cc840e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 12:02:52 +0200
Subject: [PATCH 1147/2207] linux: virtio_net.c: add some comments

---
 LINUX/if_virtio_net_netmap.h | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index dc3d5052c..c9aad69cf 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -298,7 +298,7 @@ static int virtnet_open(struct net_device *dev);
 static int virtnet_close(struct net_device *dev);
 
 static void
-virtio_net_netmap_free_unused(struct virtnet_info *vi, bool onoff,
+virtio_net_netmap_detach_unused(struct virtnet_info *vi, bool onoff,
 				enum txrx t, int i)
 {
 	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
@@ -398,7 +398,9 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 
 	if (onoff) {
-		/* enable netmap mode */
+		/* Enable netmap mode before draining and detaching OS
+		 * buffers, to prevent the OS to transmit packets
+		 * while we are doing that. */
 		nm_set_native_flags(na);
 
 		for_rx_tx(t) {
@@ -412,7 +414,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 				virtio_net_netmap_drain_used(vi, onoff, t, i);
 
 				/* Detach and free any unused OS buffers. */
-				virtio_net_netmap_free_unused(vi, onoff, t, i);
+				virtio_net_netmap_detach_unused(vi, onoff, t, i);
 
 				/* Initialize scatter-gater buffers for
 				 * netmap mode. */
@@ -433,12 +435,15 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 				virtio_net_netmap_drain_used(vi, onoff, t, i);
 
 				/* Detach and free any unused netmap buffers. */
-				virtio_net_netmap_free_unused(vi, onoff, t, i);
+				virtio_net_netmap_detach_unused(vi, onoff, t, i);
 
 				kring->nr_mode = NKR_NETMAP_OFF;
 			}
 		}
 
+		/* Disable netmap mode after netmap buffers have been drained
+		 * and detached, to prevent the OS to start transmitting while
+		 * we are doing that. */
 		nm_clear_native_flags(na);
 	}
 
@@ -637,7 +642,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	/*
 	 * First part: import newly received packets.
 	 * Only accept our own buffers (matching the token). We should only get
-	 * matching buffers, because of virtio_net_netmap_free_unused and
+	 * matching buffers, because of virtio_net_netmap_detach_unused() and
 	 * virtio_net_netmap_init_buffers(). We may need to stop early to avoid
 	 * hwtail to overrun hwcur;
 	 */

From 1193ec65ab8adb7644853b789fcc3f2b5cedbcc0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 12:13:10 +0200
Subject: [PATCH 1148/2207] linux: virtio_net.c: register: remove unused
 variable

---
 LINUX/if_virtio_net_netmap.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index c9aad69cf..940b21c19 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -384,7 +384,6 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct ifnet *ifp = na->ifp;
 	struct virtnet_info *vi = netdev_priv(ifp);
 	bool was_up = false;
-	int error = 0;
 	enum txrx t;
 	int i;
 
@@ -452,7 +451,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 		virtnet_open(ifp);
 	}
 
-	return (error);
+	return 0;
 }
 
 /* Prepare an RX virtqueue for netmap operation. Returns true if

From 37fea54f30f19c06b3ef735a5a0720b30de04bac Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 12:15:18 +0200
Subject: [PATCH 1149/2207] linux: virtio_net.c: small code simplifications

---
 LINUX/if_virtio_net_netmap.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 940b21c19..5e3077418 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -630,11 +630,6 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 				sizeof(rq->shared_rxvhdr.hdr);
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
 
-	/* XXX netif_carrier_ok ? */
-
-	if (head > lim)
-		return netmap_ring_reinit(kring);
-
 	virtqueue_disable_cb(vq);
 
 	rmb();

From 395bbbdea7be17c5773115fd7ef932a91325e061 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 12:21:55 +0200
Subject: [PATCH 1150/2207] linux: virtio_net.c: txsync: check for vq->num_free
 to enable interrupts

---
 LINUX/if_virtio_net_netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 5e3077418..e9db27a36 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -535,7 +535,6 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 				sizeof(sq->shared_txvhdr.hdr);
 	struct netmap_adapter *token;
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
-	int nospace = 0;
 
 	virtqueue_disable_cb(vq);
 
@@ -571,6 +570,7 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			void *addr = NMB(na, slot);
+			int nospace;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
@@ -600,7 +600,7 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * hypervisor for notifications, possibly only when it has
 	 * freed a considerable amount of pending descriptors.
 	 */
-	if (interrupts && (nm_kr_txempty(kring) || nospace))
+	if (interrupts && (vq->num_free <= 2 || nm_kr_txempty(kring)))
 		virtqueue_enable_cb_delayed(vq);
 
 	return 0;

From 5a989b14d06294ac718114beb65bfcece7cb47e0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 12:38:44 +0200
Subject: [PATCH 1151/2207] linux: virtio_net.c: don't disable VQ interrupts in
 xmit_done()

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 101 +++++++++---------
 1 file changed, 52 insertions(+), 49 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 0996a2de8..5c68979e8 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..a1e3263 100644
+index cbf1c61..99724e7 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -114,19 +114,22 @@ index cbf1c61..a1e3263 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -226,7 +254,10 @@ static void skb_xmit_done(struct virtqueue *vq)
+@@ -224,9 +252,13 @@ static void skb_xmit_done(struct virtqueue *vq)
+ {
+ 	struct virtnet_info *vi = vq->vdev->priv;
  
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(vq);
--
 +#ifdef DEV_NETMAP
 +	if (netmap_tx_irq(vi->dev, vq2txq(vq)))
 +		return;
 +#endif /* DEV_NETMAP */
++
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+-
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
-@@ -249,6 +280,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+@@ -249,6 +281,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
  	return (unsigned long)buf | (size - 1);
  }
  
@@ -137,7 +140,7 @@ index cbf1c61..a1e3263 100644
  /* Called from bottom half context */
  static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  				   struct receive_queue *rq,
-@@ -263,7 +298,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +299,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -151,7 +154,7 @@ index cbf1c61..a1e3263 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +678,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +679,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -159,7 +162,7 @@ index cbf1c61..a1e3263 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +769,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,16 +770,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -192,13 +195,14 @@ index cbf1c61..a1e3263 100644
 +		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
 -			virtqueue_disable_cb(rq->vq);
--			__napi_schedule(napi);
--		}
--	}
--
--	return received;
--}
--
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+@@ -746,53 +803,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	return received;
+ }
+ 
 -#ifdef CONFIG_NET_RX_BUSY_POLL
 -/* must be called with local_bh_disable()d */
 -static int virtnet_busy_poll(struct napi_struct *napi)
@@ -228,18 +232,17 @@ index cbf1c61..a1e3263 100644
 -			budget -= received;
 -			goto again;
 -		} else {
-+			virtqueue_disable_cb(vq);
- 			__napi_schedule(napi);
- 		}
- 	}
- 
- 	return received;
- }
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
 -#endif	/* CONFIG_NET_RX_BUSY_POLL */
- 
+-
  static int virtnet_open(struct net_device *dev)
  {
-@@ -789,10 +808,13 @@ static int virtnet_open(struct net_device *dev)
+ 	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -257,7 +260,7 @@ index cbf1c61..a1e3263 100644
  		virtnet_napi_enable(&vi->rq[i]);
  	}
  
-@@ -840,7 +862,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +863,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -273,7 +276,7 @@ index cbf1c61..a1e3263 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +895,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +896,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -285,7 +288,7 @@ index cbf1c61..a1e3263 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1042,13 @@ out:
+@@ -1009,8 +1043,13 @@ out:
  	return ret;
  }
  
@@ -301,7 +304,7 @@ index cbf1c61..a1e3263 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1081,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1082,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -314,7 +317,7 @@ index cbf1c61..a1e3263 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1247,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1248,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -410,7 +413,7 @@ index cbf1c61..a1e3263 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1293,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1294,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -419,7 +422,7 @@ index cbf1c61..a1e3263 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1395,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1396,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -439,7 +442,7 @@ index cbf1c61..a1e3263 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1513,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1514,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -448,7 +451,7 @@ index cbf1c61..a1e3263 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1561,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1562,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -465,7 +468,7 @@ index cbf1c61..a1e3263 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1643,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1644,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -476,7 +479,7 @@ index cbf1c61..a1e3263 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1651,6 @@ err:
+@@ -1701,33 +1652,6 @@ err:
  	return ret;
  }
  
@@ -510,7 +513,7 @@ index cbf1c61..a1e3263 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1691,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1692,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -520,7 +523,7 @@ index cbf1c61..a1e3263 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1736,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1737,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -529,7 +532,7 @@ index cbf1c61..a1e3263 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1746,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1747,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -544,7 +547,7 @@ index cbf1c61..a1e3263 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1808,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1809,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -552,7 +555,7 @@ index cbf1c61..a1e3263 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1816,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1817,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -560,7 +563,7 @@ index cbf1c61..a1e3263 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1830,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1831,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -571,7 +574,7 @@ index cbf1c61..a1e3263 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1841,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1842,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -589,7 +592,7 @@ index cbf1c61..a1e3263 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1862,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1863,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -600,7 +603,7 @@ index cbf1c61..a1e3263 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1891,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1892,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -616,7 +619,7 @@ index cbf1c61..a1e3263 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1912,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1913,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -625,7 +628,7 @@ index cbf1c61..a1e3263 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1954,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1955,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -636,7 +639,7 @@ index cbf1c61..a1e3263 100644
  	return 0;
  }
  #endif
-@@ -2061,24 +1972,34 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,24 +1973,34 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -673,7 +676,7 @@ index cbf1c61..a1e3263 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2012,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2013,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From d049821673d426a44287c668bc818a269fc666d4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 15:37:02 +0200
Subject: [PATCH 1152/2207] linux: virtio_net.c: txsync: basic notification
 scheme

---
 LINUX/if_virtio_net_netmap.h | 55 ++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 30 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index e9db27a36..dd2f49986 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -534,35 +534,17 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 				sizeof(sq->shared_txvhdr) :
 				sizeof(sq->shared_txvhdr.hdr);
 	struct netmap_adapter *token;
-	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
-
-	virtqueue_disable_cb(vq);
-
-	/* Free used slots. We only consider our own used buffers, recognized
-	 * by the token we passed to virtqueue_add_outbuf.
-	 */
-	n = 0;
-	for (;;) {
-		token = virtqueue_get_buf(vq, &nic_i); /* dummy 2nd arg */
-		if (token == NULL)
-			break;
-		if (likely(token == na))
-			n++;
-	}
-	kring->nr_hwtail += n;
-	if (kring->nr_hwtail > lim)
-		kring->nr_hwtail -= lim + 1;
-
-	/*
-	 * First part: process new packets to send.
-	 */
-	rmb();
 
 	if (!netif_running(ifp)) {
 		/* All the new slots are now unavailable. */
 		goto out;
 	}
 
+	virtqueue_enable_cb(vq);
+
+	/*
+	 * First part: process new packets to send.
+	 */
 	nm_i = kring->nr_hwcur;
 	if (nm_i != head) {	/* we have new packets to send */
 		nic_i = netmap_idx_k2n(kring, nm_i);
@@ -581,8 +563,8 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 			sg_set_buf(sg + 1, addr, len);
 			nospace = virtqueue_add_outbuf(vq, sg, 2, na, GFP_ATOMIC);
 			if (nospace) {
-				RD(3, "virtqueue_add_outbuf failed [err=%d]",
-				   nospace);
+				nm_prerr("virtqueue_add_outbuf failed [err=%d]",
+					nospace);
 				break;
 			}
 
@@ -590,18 +572,31 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 			nic_i = nm_next(nic_i, lim);
 		}
 
+		virtqueue_enable_cb(vq);
 		virtqueue_kick(vq);
 
 		/* Update hwcur depending on where we stopped. */
 		kring->nr_hwcur = nm_i; /* note we migth break early */
 	}
 out:
-	/* No more free virtio descriptors or netmap slots? Ask the
-	 * hypervisor for notifications, possibly only when it has
-	 * freed a considerable amount of pending descriptors.
+	/* Free used slots. We only consider our own used buffers, recognized
+	 * by the token we passed to virtqueue_add_outbuf.
 	 */
-	if (interrupts && (vq->num_free <= 2 || nm_kr_txempty(kring)))
-		virtqueue_enable_cb_delayed(vq);
+	n = 0;
+	for (;;) {
+		token = virtqueue_get_buf(vq, &nic_i); /* dummy 2nd arg */
+		if (token == NULL)
+			break;
+		if (unlikely(token != na))
+			nm_prerr("BUG: token mismatch\n");
+		else
+			n++;
+	}
+	if (n > 0) {
+		kring->nr_hwtail += n;
+		if (kring->nr_hwtail > lim)
+			kring->nr_hwtail -= lim + 1;
+	}
 
 	return 0;
 }

From 125e4ab868e00ca023151a87e8d07df7e9e5d3e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 18:05:40 +0200
Subject: [PATCH 1153/2207] linux: virtio_net.c: fix patch to include
 netmap_tx_irq() call

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 135 ++++++++++--------
 1 file changed, 77 insertions(+), 58 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 5c68979e8..1032a4176 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..99724e7 100644
+index cbf1c61..1f96155 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -114,33 +114,52 @@ index cbf1c61..99724e7 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -224,9 +252,13 @@ static void skb_xmit_done(struct virtqueue *vq)
- {
- 	struct virtnet_info *vi = vq->vdev->priv;
+@@ -220,17 +248,6 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
+ 	return p;
+ }
  
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(vi->dev, vq2txq(vq)))
-+		return;
-+#endif /* DEV_NETMAP */
-+
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(vq);
+-static void skb_xmit_done(struct virtqueue *vq)
+-{
+-	struct virtnet_info *vi = vq->vdev->priv;
 -
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_subqueue(vi->dev, vq2txq(vq));
- }
-@@ -249,6 +281,10 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+-	/* Suppress further interrupts. */
+-	virtqueue_disable_cb(vq);
+-
+-	/* We were probably waiting for more output buffers. */
+-	netif_wake_subqueue(vi->dev, vq2txq(vq));
+-}
+-
+ static unsigned int mergeable_ctx_to_buf_truesize(unsigned long mrg_ctx)
+ {
+ 	unsigned int truesize = mrg_ctx & (MERGEABLE_BUFFER_ALIGN - 1);
+@@ -249,6 +266,26 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
  	return (unsigned long)buf | (size - 1);
  }
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
++
++static void skb_xmit_done(struct virtqueue *vq)
++{
++	struct virtnet_info *vi = vq->vdev->priv;
++
++	/* Suppress further interrupts. */
++	virtqueue_disable_cb(vq);
++
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif /* DEV_NETMAP */
++
++	/* We were probably waiting for more output buffers. */
++	netif_wake_subqueue(vi->dev, vq2txq(vq));
++}
 +
  /* Called from bottom half context */
  static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  				   struct receive_queue *rq,
-@@ -263,7 +299,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +300,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -154,7 +173,7 @@ index cbf1c61..99724e7 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +679,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +680,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -162,7 +181,7 @@ index cbf1c61..99724e7 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,16 +770,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +771,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -195,14 +214,13 @@ index cbf1c61..99724e7 100644
 +		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
 -			virtqueue_disable_cb(rq->vq);
-+			virtqueue_disable_cb(vq);
- 			__napi_schedule(napi);
- 		}
- 	}
-@@ -746,53 +803,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	return received;
- }
- 
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
+-
 -#ifdef CONFIG_NET_RX_BUSY_POLL
 -/* must be called with local_bh_disable()d */
 -static int virtnet_busy_poll(struct napi_struct *napi)
@@ -232,17 +250,18 @@ index cbf1c61..99724e7 100644
 -			budget -= received;
 -			goto again;
 -		} else {
--			__napi_schedule(napi);
--		}
--	}
--
--	return received;
--}
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+ 
+ 	return received;
+ }
 -#endif	/* CONFIG_NET_RX_BUSY_POLL */
--
+ 
  static int virtnet_open(struct net_device *dev)
  {
- 	struct virtnet_info *vi = netdev_priv(dev);
+@@ -789,10 +810,13 @@ static int virtnet_open(struct net_device *dev)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -260,7 +279,7 @@ index cbf1c61..99724e7 100644
  		virtnet_napi_enable(&vi->rq[i]);
  	}
  
-@@ -840,7 +863,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +864,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -276,7 +295,7 @@ index cbf1c61..99724e7 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +896,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +897,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -288,7 +307,7 @@ index cbf1c61..99724e7 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1043,13 @@ out:
+@@ -1009,8 +1044,13 @@ out:
  	return ret;
  }
  
@@ -304,7 +323,7 @@ index cbf1c61..99724e7 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1082,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1083,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -317,7 +336,7 @@ index cbf1c61..99724e7 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1248,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1249,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -413,7 +432,7 @@ index cbf1c61..99724e7 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1294,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1295,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -422,7 +441,7 @@ index cbf1c61..99724e7 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1396,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1397,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -442,7 +461,7 @@ index cbf1c61..99724e7 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1514,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1515,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -451,7 +470,7 @@ index cbf1c61..99724e7 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1562,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1563,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -468,7 +487,7 @@ index cbf1c61..99724e7 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1644,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1645,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -479,7 +498,7 @@ index cbf1c61..99724e7 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1652,6 @@ err:
+@@ -1701,33 +1653,6 @@ err:
  	return ret;
  }
  
@@ -513,7 +532,7 @@ index cbf1c61..99724e7 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1692,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1693,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -523,7 +542,7 @@ index cbf1c61..99724e7 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1737,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1738,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -532,7 +551,7 @@ index cbf1c61..99724e7 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1747,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,13 +1748,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -547,7 +566,7 @@ index cbf1c61..99724e7 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1809,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1810,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -555,7 +574,7 @@ index cbf1c61..99724e7 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1817,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1818,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -563,7 +582,7 @@ index cbf1c61..99724e7 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1831,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1832,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -574,7 +593,7 @@ index cbf1c61..99724e7 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1842,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1843,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -592,7 +611,7 @@ index cbf1c61..99724e7 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1863,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1864,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -603,7 +622,7 @@ index cbf1c61..99724e7 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1892,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1893,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -619,7 +638,7 @@ index cbf1c61..99724e7 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1913,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1914,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -628,7 +647,7 @@ index cbf1c61..99724e7 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1955,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1956,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -639,7 +658,7 @@ index cbf1c61..99724e7 100644
  	return 0;
  }
  #endif
-@@ -2061,24 +1973,34 @@ static struct virtio_device_id id_table[] = {
+@@ -2061,24 +1974,34 @@ static struct virtio_device_id id_table[] = {
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -676,7 +695,7 @@ index cbf1c61..99724e7 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2013,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2014,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From f09b1cb7ac1fbcd09a36feadc1b1eb20b0b89260 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 18:10:58 +0200
Subject: [PATCH 1154/2207] linux: virtio_net.c: improve tx notifications
 scheme

---
 LINUX/if_virtio_net_netmap.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index dd2f49986..2c2d34820 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -533,6 +533,7 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 	size_t vnet_hdr_len = vi->mergeable_rx_bufs ?
 				sizeof(sq->shared_txvhdr) :
 				sizeof(sq->shared_txvhdr.hdr);
+	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
 	struct netmap_adapter *token;
 
 	if (!netif_running(ifp)) {
@@ -540,8 +541,6 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 		goto out;
 	}
 
-	virtqueue_enable_cb(vq);
-
 	/*
 	 * First part: process new packets to send.
 	 */
@@ -572,13 +571,15 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 			nic_i = nm_next(nic_i, lim);
 		}
 
-		virtqueue_enable_cb(vq);
 		virtqueue_kick(vq);
 
 		/* Update hwcur depending on where we stopped. */
 		kring->nr_hwcur = nm_i; /* note we migth break early */
 	}
 out:
+	if (interrupts)
+		virtqueue_enable_cb_delayed(vq);
+
 	/* Free used slots. We only consider our own used buffers, recognized
 	 * by the token we passed to virtqueue_add_outbuf.
 	 */

From 6d0d416bf7cba797d4534c097d71336340d86dd1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 18:18:35 +0200
Subject: [PATCH 1155/2207] linux: virtio_net.c: suppress TX interrupts when
 not needed

---
 LINUX/if_virtio_net_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 2c2d34820..be41f30db 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -577,7 +577,7 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 		kring->nr_hwcur = nm_i; /* note we migth break early */
 	}
 out:
-	if (interrupts)
+	if (interrupts && vq->num_free < 32)
 		virtqueue_enable_cb_delayed(vq);
 
 	/* Free used slots. We only consider our own used buffers, recognized

From d95eb25e1e5dfa32e1ace550b90416152aca21c6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 18:22:48 +0200
Subject: [PATCH 1156/2207] linux: virtio_net.c: add a comment to describe
 LINUX/if_virtio_net_netmap.h

---
 LINUX/if_virtio_net_netmap.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index be41f30db..c67957c9c 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -27,6 +27,12 @@
 #include 
 #include 
 
+/* Netmap support for the virtio-net driver build from fixed "external"
+ * sources (currently taken from Linux 4.9, and patched by
+ * patches/custom--virtio_net.c--4.9). This driver should be preferred
+ * to the one included with the running Linux version.
+ */
+
 /*************************************************************************/
 /* COMPATIBILITY LAYER                                                   */
 /*************************************************************************/

From 18a3cc21700596ea05d116dd4cf85bfbc494d5db Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 18:51:03 +0200
Subject: [PATCH 1157/2207] ci/build-linux: build virtio_net.c as external only
 for kernels >= 3.13

---
 ci/build-linux | 45 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index d5e304a53..cf61283bc 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -1,5 +1,33 @@
 #!/bin/bash -eu
 
+function kverval() {
+	local kver="$1"
+	local val="0"
+	local components
+
+	# Parse kernel version
+	IFS='.' read -ra components <<< "${kver}"
+	for x in ${components[@]}; do
+		val=$((val * 100))
+		val=$((val + x))
+	done
+	echo $val
+}
+
+function kverless() {
+	local kver1="$1"
+	local kver2="$2"
+
+	kval1=$(kverval $kver1)
+	kval2=$(kverval $kver2)
+
+	if [ "$kval1" -lt "$kval2" ]; then
+		echo "0"
+	else
+		echo "1"
+	fi
+}
+
 function set_config_variable()
 {
 	local varname=$1
@@ -59,13 +87,6 @@ make -j $PROC_COUNT ARCH=${ARCH} allmodconfig
 make -j $PROC_COUNT ARCH=${ARCH} modules_prepare
 popd
 
-echo "Building external virtio_net.c"
-./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=virtio_net.c
-make -j $PROC_COUNT
-# TODO remove
-ls -l
-make distclean
-
 # First build in-tree-only drivers
 echo "Building vanilla-only drivers"
 ./configure --no-ext-drivers --driver-suffix=_netmap --kernel-dir=$PWD/linux-${KERNEL_VERSION} --drivers=r8169.c,virtio_net.c,forcedeth.c,veth.c,e1000,vmxnet3 --enable-ptnetmap
@@ -73,8 +94,14 @@ make -j $PROC_COUNT
 
 # Then build external intel drivers
 make distclean
-echo "Building external intel drivers"
-./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=e1000e,igb,ixgbe,i40e
+echo "Building external intel drivers (and virtio_net.c)"
+EXTDRIVERS="e1000e,igb,ixgbe,i40e"
+# For kernels >= 3.13 we support virtio_net.c as an external driver
+cmp=$(kverless $KERNEL_VERSION 3.13)
+if [ "$cmp" == "1" ]; then
+	EXTDRIVERS="${EXTDRIVERS},virtio_net.c"
+fi
+./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=${EXTDRIVERS}
 make -j $PROC_COUNT
 
 # Then build vanilla intel drivers

From f2995c8eabddeaed48f3a963e3105448c1f9395a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 11 Oct 2018 22:05:04 +0200
Subject: [PATCH 1158/2207] ci: build-linux: remove git clean -fdx

---
 ci/build-linux | 2 --
 1 file changed, 2 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index cf61283bc..5be4e31eb 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -44,8 +44,6 @@ function set_config_variable()
 
 set -o pipefail
 
-git clean -fdx
-
 readonly KERNEL_VERSION=${1:?}
 readonly ARCH=${2:?}
 readonly GCC_MAJOR_VERSION=$(echo '#include 

From bb7b1d3dcafa05ead2a38c59fedf0dc2d32b9685 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 12 Oct 2018 09:35:42 +0200
Subject: [PATCH 1159/2207] linux: virtio_net.c: add support for host rings

---
 LINUX/if_virtio_net_netmap.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index c67957c9c..24d296dc4 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -409,6 +409,7 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 		nm_set_native_flags(na);
 
 		for_rx_tx(t) {
+			/* Hardware rings. */
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 
@@ -427,9 +428,20 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 
 				kring->nr_mode = NKR_NETMAP_ON;
 			}
+
+			/* Host rings. */
+			for (i = 0; i < nma_get_host_nrings(na, t); i++) {
+				struct netmap_kring *kring =
+					NMR(na, t)[nma_get_nrings(na, t) + i];
+
+				if (nm_kring_pending_on(kring)) {
+					kring->nr_mode = NKR_NETMAP_ON;
+				}
+			}
 		}
 	} else {
 		for_rx_tx(t) {
+			/* Hardware rings. */
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 
@@ -444,6 +456,16 @@ virtio_net_netmap_reg(struct netmap_adapter *na, int onoff)
 
 				kring->nr_mode = NKR_NETMAP_OFF;
 			}
+
+			/* Host rings. */
+			for (i = 0; i < nma_get_host_nrings(na, t); i++) {
+				struct netmap_kring *kring =
+					NMR(na, t)[nma_get_nrings(na, t) + i];
+
+				if (nm_kring_pending_off(kring)) {
+					kring->nr_mode = NKR_NETMAP_OFF;
+				}
+			}
 		}
 
 		/* Disable netmap mode after netmap buffers have been drained

From 93b36c57942132691266d0c80d911bbec2e786db Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 12 Oct 2018 10:31:43 +0200
Subject: [PATCH 1160/2207] linux: virtio_net.c: legacy: update txsync scheme

---
 LINUX/virtio_netmap.h | 44 +++++++++++++++++++++----------------------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 2d43f3e5f..a9f0cbfcd 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -403,24 +403,6 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags)
 				sizeof(vna->shared_txvhdr.hdr);
 	struct netmap_adapter *token;
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
-	int nospace = 0;
-
-	virtqueue_disable_cb(vq);
-
-	/* Free used slots. We only consider our own used buffers, recognized
-	 * by the token we passed to virtqueue_add_outbuf.
-	 */
-	n = 0;
-	for (;;) {
-		token = virtqueue_get_buf(vq, &nic_i); /* dummy 2nd arg */
-		if (token == NULL)
-			break;
-		if (likely(token == na))
-			n++;
-	}
-	kring->nr_hwtail += n;
-	if (kring->nr_hwtail > lim)
-		kring->nr_hwtail -= lim + 1;
 
 	/*
 	 * First part: process new packets to send.
@@ -439,6 +421,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			void *addr = NMB(na, slot);
+			int nospace;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
@@ -465,14 +448,29 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags)
 		kring->nr_hwcur = nm_i; /* note we migth break early */
 	}
 out:
-	/* No more free virtio descriptors or netmap slots? Ask the
-	 * hypervisor for notifications, possibly only when it has
-	 * freed a considerable amount of pending descriptors.
-	 */
-	if (interrupts && (nm_kr_txempty(kring) || nospace)) {
+	/* Ask the hypervisor for notifications, possibly only when it has
+	 * freed a considerable amount of pending descriptors. */
+	if (interrupts) {
 		virtqueue_enable_cb_delayed(vq);
 	}
 
+	/* Free used slots. We only consider our own used buffers, recognized
+	 * by the token we passed to virtqueue_add_outbuf.
+	 */
+	n = 0;
+	for (;;) {
+		token = virtqueue_get_buf(vq, &nic_i); /* dummy 2nd arg */
+		if (token == NULL)
+			break;
+		if (likely(token == na))
+			n++;
+	}
+	if (n) {
+		kring->nr_hwtail += n;
+		if (kring->nr_hwtail > lim)
+			kring->nr_hwtail -= lim + 1;
+	}
+
 	return 0;
 }
 

From f32beb92f700b6854281e11b8cbf9b076297d581 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 12 Oct 2018 10:34:05 +0200
Subject: [PATCH 1161/2207] configure: handle the difference between legacy and
 external virtio_net.c

---
 LINUX/configure | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index d3ec18df2..0252c8b0e 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1806,8 +1806,13 @@ EOF
   fi
 
   if drv enabled virtio_net.c; then
+
+    VNETDIR=""
+    if edrv enabled virtio_net.c; then
+        VNETDIR="virtio_net.c/"
+    fi
   
-    add_file_exists_check virtio_net.c/virtio_net.c true "drv_source_error virtio_net.c"
+    add_file_exists_check ${VNETDIR}virtio_net.c true "drv_source_error virtio_net.c"
   
     add_test 'define VIRTIO_NET_HDR_FROM_SKB_5ARGS' <
@@ -1943,7 +1948,7 @@ EOF
 EOF
   
     add_test 'define VIRTIO_FREE_PAGES' <
Date: Fri, 12 Oct 2018 11:01:09 +0200
Subject: [PATCH 1162/2207] linux: virtio_net.c: disable checksum offloads with
 DEV_NETMAP

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 76 +++++++++++++++----
 1 file changed, 63 insertions(+), 13 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 1032a4176..f36459b9d 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..1f96155 100644
+index cbf1c61..a67bf8e 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -542,7 +542,15 @@ index cbf1c61..1f96155 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1811,7 +1738,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1731,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 	SET_NETDEV_DEV(dev, &vdev->dev);
+ 
+ 	/* Do we support "hardware" checksums? */
++#ifndef DEV_NETMAP
+ 	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
+ 		/* This opens up the world of extra features. */
+ 		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+@@ -1811,7 +1739,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -551,7 +559,7 @@ index cbf1c61..1f96155 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,13 +1748,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1749,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -566,7 +574,26 @@ index cbf1c61..1f96155 100644
  		/* (!csum && gso) case will be fixed by register_netdev() */
  	}
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
-@@ -1885,6 +1810,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		dev->features |= NETIF_F_RXCSUM;
++#endif  /* !DEV_NETMAP */
+ 
+ 	dev->vlan_features = dev->features;
+ 
+@@ -1863,11 +1790,13 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
+ 
+ 	/* If we can receive ANY GSO packets, we must allocate large ones. */
++#ifndef DEV_NETMAP
+ 	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
+ 	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
+ 	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+ 	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
+ 		vi->big_packets = true;
++#endif  /* !DEV_NETMAP */
+ 
+ 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
+ 		vi->mergeable_rx_bufs = true;
+@@ -1885,6 +1814,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -574,7 +601,7 @@ index cbf1c61..1f96155 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1818,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1822,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -582,7 +609,7 @@ index cbf1c61..1f96155 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1832,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1836,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -593,7 +620,7 @@ index cbf1c61..1f96155 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1843,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1847,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -611,7 +638,7 @@ index cbf1c61..1f96155 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1864,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1868,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -622,7 +649,7 @@ index cbf1c61..1f96155 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1893,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1897,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -638,7 +665,7 @@ index cbf1c61..1f96155 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1914,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1918,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -647,7 +674,7 @@ index cbf1c61..1f96155 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1956,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1960,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -658,7 +685,30 @@ index cbf1c61..1f96155 100644
  	return 0;
  }
  #endif
-@@ -2061,24 +1974,34 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1969,54 @@ static struct virtio_device_id id_table[] = {
+ 	{ 0 },
+ };
+ 
+-#define VIRTNET_FEATURES \
++#ifdef DEV_NETMAP
++/* Netmap cannot handle checksum offloads, and rx csum offload cannot be
++ * disabled with virtio-net. For this reason we do not negotiate any
++ * checksum offload, nor other features derived from those. With this
++ * trick, host rings work properly with TCP and UDP traffic. */
++#define CSUM_FEATURES
++#else  /* !DEV_NETMAP */
++#define CSUM_FEATURES \
+ 	VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, \
+-	VIRTIO_NET_F_MAC, \
+ 	VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, \
+ 	VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, \
+-	VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, \
++	VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
++#endif /* !DEV_NETMAP */
++
++#define VIRTNET_FEATURES \
++	CSUM_FEATURES \
++	VIRTIO_NET_F_MAC, \
  	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
@@ -695,7 +745,7 @@ index cbf1c61..1f96155 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2014,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2029,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From e092f3f1697ce787b6ff996e52debb6f42e5a72b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 10:36:04 +0200
Subject: [PATCH 1163/2207] netmap.h: add new commands:
 NETMAP_REQ_KSYNC_LOOP_START/STOP

---
 sys/dev/netmap/netmap.c | 12 ++++++++++++
 sys/net/netmap.h        |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e52902840..c6e0a013b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2627,6 +2627,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
+		case NETMAP_REQ_KSYNC_LOOP_START: {
+			error = ENOSYS;
+			break;
+		}
+
+		case NETMAP_REQ_KSYNC_LOOP_STOP: {
+			error = ENOSYS;
+			break;
+		}
+
 		default: {
 			error = EINVAL;
 			break;
@@ -2736,6 +2746,8 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_NEWIF:
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
+	case NETMAP_REQ_KSYNC_LOOP_START:
+	case NETMAP_REQ_KSYNC_LOOP_STOP:
 		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index ceab641a6..c339c98f9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -516,6 +516,13 @@ enum {
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
+	/* Start an in-kernel loop that syncs the rings periodically or
+	 * on notifications. The loop runs in the context of the ioctl
+	 * syscall, and only stops on NETMAP_REQ_KSYNC_LOOP_STOP. */
+	NETMAP_REQ_KSYNC_LOOP_START,
+	/* Stops the thread executing the in-kernel loop. The thread
+	 * returns from the ioctl syscall. */
+	NETMAP_REQ_KSYNC_LOOP_STOP,
 };
 
 enum {

From 5f691ed25189befcb2f80e1e92231b9437cbabfa Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 11:08:04 +0200
Subject: [PATCH 1164/2207] sync-kloop: introduce struct nmreq_sync_kloop_start

---
 sys/dev/netmap/netmap.c |  9 +++++----
 sys/net/netmap.h        | 23 ++++++++++++++++++++---
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c6e0a013b..7a76c72e3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2627,12 +2627,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
-		case NETMAP_REQ_KSYNC_LOOP_START: {
+		case NETMAP_REQ_SYNC_KLOOP_START: {
 			error = ENOSYS;
 			break;
 		}
 
-		case NETMAP_REQ_KSYNC_LOOP_STOP: {
+		case NETMAP_REQ_SYNC_KLOOP_STOP: {
 			error = ENOSYS;
 			break;
 		}
@@ -2746,14 +2746,15 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_NEWIF:
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
-	case NETMAP_REQ_KSYNC_LOOP_START:
-	case NETMAP_REQ_KSYNC_LOOP_STOP:
+	case NETMAP_REQ_SYNC_KLOOP_STOP:
 		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
 		return sizeof(struct nmreq_pools_info);
+	case NETMAP_REQ_SYNC_KLOOP_START:
+		return sizeof(struct nmreq_sync_kloop_start);
 	}
 	return 0;
 }
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index c339c98f9..3dc35a2f9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -518,11 +518,11 @@ enum {
 	NETMAP_REQ_POOLS_INFO_GET,
 	/* Start an in-kernel loop that syncs the rings periodically or
 	 * on notifications. The loop runs in the context of the ioctl
-	 * syscall, and only stops on NETMAP_REQ_KSYNC_LOOP_STOP. */
-	NETMAP_REQ_KSYNC_LOOP_START,
+	 * syscall, and only stops on NETMAP_REQ_SYNC_KLOOP_STOP. */
+	NETMAP_REQ_SYNC_KLOOP_START,
 	/* Stops the thread executing the in-kernel loop. The thread
 	 * returns from the ioctl syscall. */
-	NETMAP_REQ_KSYNC_LOOP_STOP,
+	NETMAP_REQ_SYNC_KLOOP_STOP,
 };
 
 enum {
@@ -699,6 +699,23 @@ struct nmreq_pools_info {
 	uint32_t	nr_buf_pool_objsize;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_SYNC_KLOOP_START
+ * Start an in-kernel loop that syncs the rings periodically or on
+ * notifications. The loop runs in the context of the ioctl syscall,
+ * and only stops on NETMAP_REQ_SYNC_KLOOP_STOP.
+ * The user must specify the start address of the Communication Status Block
+ * (CSB) entries to be used for both directions (kernel read application
+ * writes, and kernel writes application read). The number of entries
+ * must agree with the number of rings bound to the netmap file descriptor.
+ */
+struct nmreq_sync_kloop_start {
+	/* CSB entries for application --> kernel communication (N entries). */
+	uint64_t csb_atok;
+	/* CSB for kernel --> application communication (N entries). */
+	uint64_t csb_ktoa;
+};
+
 /*
  * data for NETMAP_REQ_OPT_* options
  */

From cacb72ccbef7ee734be45b8b75f20622d9e142d0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 11:30:17 +0200
Subject: [PATCH 1165/2207] introduce netmap_sync_kloop() function

---
 sys/dev/netmap/netmap.c      | 9 ++++++++-
 sys/dev/netmap/netmap_kern.h | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7a76c72e3..78e553331 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2628,7 +2628,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_START: {
-			error = ENOSYS;
+			struct nmreq_sync_kloop_start *req =
+				(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
+			error = netmap_sync_kloop(req);
 			break;
 		}
 
@@ -3899,6 +3901,11 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
+int
+netmap_sync_kloop(struct nmreq_sync_kloop_start *req)
+{
+	return ENOSYS;
+}
 
 /*
  * Module loader and unloader
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 74de1c6bd..84a4627c5 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2123,6 +2123,8 @@ void nm_os_kctx_send_irq(struct nm_kctx *);
 void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
+int netmap_sync_kloop(struct nmreq_sync_kloop_start *req);
+
 #ifdef WITH_PTNETMAP_HOST
 /*
  * netmap adapter for host ptnetmap ports

From 0f67aeb74c3d0ca3805a6e0965ba9513fc12090b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 16:40:15 +0200
Subject: [PATCH 1166/2207] netmap_sync_kloop: grab netmap priv and netmap
 adapter

---
 sys/dev/netmap/netmap.c      | 17 +++++++++++++++--
 sys/dev/netmap/netmap_kern.h |  3 ++-
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 78e553331..daf595434 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2630,7 +2630,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		case NETMAP_REQ_SYNC_KLOOP_START: {
 			struct nmreq_sync_kloop_start *req =
 				(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
-			error = netmap_sync_kloop(req);
+			error = netmap_sync_kloop(priv, req);
 			break;
 		}
 
@@ -3902,8 +3902,21 @@ nm_clear_native_flags(struct netmap_adapter *na)
 }
 
 int
-netmap_sync_kloop(struct nmreq_sync_kloop_start *req)
+netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
+	struct netmap_adapter *na;
+
+	if (priv->np_nifp == NULL) {
+		D("No if registered");
+		return ENXIO;
+	}
+	mb(); /* make sure following reads are not from cache */
+
+	na = priv->np_na;
+	if (!nm_netmap_on(na)) {
+		return ENXIO;
+	}
+
 	return ENOSYS;
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 84a4627c5..9956792f2 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2123,7 +2123,8 @@ void nm_os_kctx_send_irq(struct nm_kctx *);
 void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
-int netmap_sync_kloop(struct nmreq_sync_kloop_start *req);
+int netmap_sync_kloop(struct netmap_priv_d *priv,
+		      struct nmreq_sync_kloop_start *req);
 
 #ifdef WITH_PTNETMAP_HOST
 /*

From ca5fa5668d6b92849c9bf242f44e1bee9d20e912 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 18:42:49 +0200
Subject: [PATCH 1167/2207] netmap_sync_kloop: add CSB memory validation for
 the atok direction

---
 sys/dev/netmap/netmap.c | 27 ++++++++++++++++++++++++++-
 sys/net/netmap.h        | 15 +++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index daf595434..3a651b366 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3907,7 +3907,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	struct netmap_adapter *na;
 
 	if (priv->np_nifp == NULL) {
-		D("No if registered");
 		return ENXIO;
 	}
 	mb(); /* make sure following reads are not from cache */
@@ -3917,6 +3916,32 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	/* Validate the CSB entries for both directions. */
+	{
+		struct nm_csb_atok *csb_atok =
+			(struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+		unsigned int num_entries;
+		size_t csb_size;
+		int err;
+
+		num_entries = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
+			      priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+		csb_size = num_entries * sizeof(*csb_atok);
+
+		if (csb_size) {
+			void *tmp = nm_os_malloc(csb_size);
+			if (!tmp) {
+				return ENOMEM;
+			}
+			err = copyin(csb_atok, tmp, csb_size);
+			nm_os_free(tmp);
+			if (err) {
+				nm_prerr("Invalid CSB address\n");
+				return err;
+			}
+		}
+	}
+
 	return ENOSYS;
 }
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3dc35a2f9..41fcef519 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -716,6 +716,21 @@ struct nmreq_sync_kloop_start {
 	uint64_t csb_ktoa;
 };
 
+struct nm_csb_atok {
+	uint32_t head;		  /* AW+ KR+ the head of the appl netmap_ring */
+	uint32_t cur;		  /* AW+ KR+ the cur of the appl netmap_ring */
+	uint32_t appl_need_kick; /* AW+ KR+ kern --> appl notification enable */
+	uint32_t sync_flags;	  /* AW+ KR+ the flags of the appl [tx|rx]sync() */
+	char pad[48];		  /* pad to a 64 bytes cacheline */
+};
+
+struct nm_csb_ktoa {
+	uint32_t hwcur;		  /* AR+ KW+ the hwcur of the kern netmap_kring */
+	uint32_t hwtail;	  /* AR+ KW+ the hwtail of the kern netmap_kring */
+	uint32_t kern_need_kick;  /* AR+ KW+ appl-->kern notification enable */
+	char pad[4+48];
+};
+
 /*
  * data for NETMAP_REQ_OPT_* options
  */

From c213e2af86607c9ade078580d9e9609c529cfd3d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 18:58:18 +0200
Subject: [PATCH 1168/2207] netmap_sync_kloop: validate CSB for both directions

---
 sys/dev/netmap/netmap.c | 50 +++++++++++++++++++++++++++--------------
 1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3a651b366..05175b8a2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3916,28 +3916,44 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
-	/* Validate the CSB entries for both directions. */
+	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
-		struct nm_csb_atok *csb_atok =
-			(struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-		unsigned int num_entries;
-		size_t csb_size;
-		int err;
+		int num_entries;
 
 		num_entries = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
 			      priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
-		csb_size = num_entries * sizeof(*csb_atok);
 
-		if (csb_size) {
-			void *tmp = nm_os_malloc(csb_size);
-			if (!tmp) {
-				return ENOMEM;
-			}
-			err = copyin(csb_atok, tmp, csb_size);
-			nm_os_free(tmp);
-			if (err) {
-				nm_prerr("Invalid CSB address\n");
-				return err;
+		if (num_entries > 0) {
+			size_t entry_size[2];
+			int err;
+			int i;
+
+			entry_size[0] = sizeof(struct nm_csb_atok);
+			entry_size[1] = sizeof(struct nm_csb_ktoa);
+
+			for (i = 0; i < 2; i++) {
+				size_t csb_size = num_entries * entry_size[i];
+				void *tmp = nm_os_malloc(csb_size);
+				void *csb_ptr;
+
+				if (!tmp) {
+					return ENOMEM;
+				}
+				if (i == 0) {
+					csb_ptr = (void *)(uintptr_t)req->csb_atok;
+					/* Application --> kernel direction. */
+					err = copyin(csb_ptr, tmp, csb_size);
+				} else {
+					/* Kernel --> application direction. */
+					memset(tmp, 0, csb_size);
+					csb_ptr = (void *)(uintptr_t)req->csb_ktoa;
+					err = copyout(tmp, csb_ptr, csb_size);
+				}
+				nm_os_free(tmp);
+				if (err) {
+					nm_prerr("Invalid CSB address\n");
+					return err;
+				}
 			}
 		}
 	}

From 420f6470f823728a471fb55b958867846cccc248 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 19:05:16 +0200
Subject: [PATCH 1169/2207] netmap_sync_kloop: minor simplifications to the
 validation code

---
 sys/dev/netmap/netmap.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 05175b8a2..f701a6e19 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3905,6 +3905,8 @@ int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
 	struct netmap_adapter *na;
+	struct nm_csb_atok* csb_atok;
+	struct nm_csb_ktoa* csb_ktoa;
 
 	if (priv->np_nifp == NULL) {
 		return ENXIO;
@@ -3916,6 +3918,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	csb_atok = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+	csb_ktoa = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+
 	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
 		int num_entries;
@@ -3928,26 +3933,27 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			int err;
 			int i;
 
-			entry_size[0] = sizeof(struct nm_csb_atok);
-			entry_size[1] = sizeof(struct nm_csb_ktoa);
+			entry_size[0] = sizeof(*csb_atok);
+			entry_size[1] = sizeof(*csb_ktoa);
 
 			for (i = 0; i < 2; i++) {
+				/* On Linux we could use access_ok() to simplify
+				 * the validation. However, the advantage of
+				 * this approach is that it works also on
+				 * FreeBSD. */
 				size_t csb_size = num_entries * entry_size[i];
 				void *tmp = nm_os_malloc(csb_size);
-				void *csb_ptr;
 
 				if (!tmp) {
 					return ENOMEM;
 				}
 				if (i == 0) {
-					csb_ptr = (void *)(uintptr_t)req->csb_atok;
 					/* Application --> kernel direction. */
-					err = copyin(csb_ptr, tmp, csb_size);
+					err = copyin(csb_atok, tmp, csb_size);
 				} else {
 					/* Kernel --> application direction. */
 					memset(tmp, 0, csb_size);
-					csb_ptr = (void *)(uintptr_t)req->csb_ktoa;
-					err = copyout(tmp, csb_ptr, csb_size);
+					err = copyout(tmp, csb_ktoa, csb_size);
 				}
 				nm_os_free(tmp);
 				if (err) {

From 544dd1ba7dad5c505c7304214658823be064669c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 19:54:21 +0200
Subject: [PATCH 1170/2207] sync-kloop: introduce np_kloop_on field in the
 netmap priv

---
 sys/dev/netmap/netmap.c      | 33 ++++++++++++++++++++++++++++++---
 sys/dev/netmap/netmap_kern.h |  1 +
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f701a6e19..371840247 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1925,6 +1925,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	}
 	priv->np_flags = 0;
 	priv->np_txpoll = 0;
+	priv->np_kloop_on = 0;
 }
 
 
@@ -3907,6 +3908,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	struct netmap_adapter *na;
 	struct nm_csb_atok* csb_atok;
 	struct nm_csb_ktoa* csb_ktoa;
+	int err = 0;
 
 	if (priv->np_nifp == NULL) {
 		return ENXIO;
@@ -3918,6 +3920,17 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	/* Make sure that there is no kloop already active. */
+	NMG_LOCK();
+	if (priv->np_kloop_on) {
+		err = EBUSY;
+	}
+	priv->np_kloop_on = 1;
+	NMG_UNLOCK();
+	if (err) {
+		return err;
+	}
+
 	csb_atok = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
 	csb_ktoa = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
 
@@ -3930,8 +3943,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 		if (num_entries > 0) {
 			size_t entry_size[2];
-			int err;
-			int i;
+			unsigned int i;
 
 			entry_size[0] = sizeof(*csb_atok);
 			entry_size[1] = sizeof(*csb_ktoa);
@@ -3964,7 +3976,22 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
-	return ENOSYS;
+	while (NM_ACCESS_ONCE(priv->np_kloop_on)) {
+		unsigned int i;
+
+		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
+			struct netmap_kring *kring = NMR(na, NR_TX)[i];
+
+			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+				continue;
+			}
+
+			nm_kr_put(kring);
+		}
+		break;
+	}
+
+	return 0;
 }
 
 /*
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 9956792f2..cf893c476 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1868,6 +1868,7 @@ struct netmap_priv_d {
 	u_int		np_qfirst[NR_TXRX],
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
 	uint16_t	np_txpoll;
+	uint16_t        np_kloop_on;	/* use with NMG_LOCK held */
 	int             np_sync_flags; /* to be passed to nm_sync */
 
 	int		np_refs;	/* use with NMG_LOCK held */

From 809b47e11c61b8fa2386bb714d6dfdec0252de4a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 23:17:13 +0200
Subject: [PATCH 1171/2207] sync-kloop: introduce np_kloop_state to handle
 start and stop

---
 sys/dev/netmap/netmap.c      | 16 +++++++++++-----
 sys/dev/netmap/netmap_kern.h |  5 ++++-
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 371840247..bd4aed007 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1925,7 +1925,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	}
 	priv->np_flags = 0;
 	priv->np_txpoll = 0;
-	priv->np_kloop_on = 0;
+	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
 }
 
 
@@ -3920,12 +3920,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
-	/* Make sure that there is no kloop already active. */
+	/* Make sure that no kloop is active or about to stop. */
 	NMG_LOCK();
-	if (priv->np_kloop_on) {
+	if (priv->np_kloop_state != NM_SYNC_KLOOP_NONE) {
 		err = EBUSY;
+	} else {
+		priv->np_kloop_state = NM_SYNC_KLOOP_ACTIVE;
 	}
-	priv->np_kloop_on = 1;
 	NMG_UNLOCK();
 	if (err) {
 		return err;
@@ -3976,7 +3977,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
-	while (NM_ACCESS_ONCE(priv->np_kloop_on)) {
+	while (likely(NM_ACCESS_ONCE(priv->np_kloop_state) != NM_SYNC_KLOOP_STOPPING)) {
 		unsigned int i;
 
 		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
@@ -3991,6 +3992,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		break;
 	}
 
+	/* Reset the kloop state. */
+	NMG_LOCK();
+	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
+	NMG_UNLOCK();
+
 	return 0;
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index cf893c476..d050e4b00 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1868,7 +1868,10 @@ struct netmap_priv_d {
 	u_int		np_qfirst[NR_TXRX],
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
 	uint16_t	np_txpoll;
-	uint16_t        np_kloop_on;	/* use with NMG_LOCK held */
+	uint16_t        np_kloop_state;	/* use with NMG_LOCK held */
+#define NM_SYNC_KLOOP_NONE	0
+#define NM_SYNC_KLOOP_ACTIVE	1
+#define NM_SYNC_KLOOP_STOPPING	2
 	int             np_sync_flags; /* to be passed to nm_sync */
 
 	int		np_refs;	/* use with NMG_LOCK held */

From fb3287e8b1f157433ab5fa1dc5d4ca266a5c712e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 23:21:59 +0200
Subject: [PATCH 1172/2207] netmap_ioctl: implement NETMAP_REQ_SYNC_KLOOP_STOP

---
 sys/dev/netmap/netmap.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bd4aed007..86e035d5e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2636,7 +2636,17 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_STOP: {
-			error = ENOSYS;
+			NMG_LOCK();
+			switch (priv->np_kloop_state) {
+			case NM_SYNC_KLOOP_NONE:
+				error = ENXIO;
+				break;
+			case NM_SYNC_KLOOP_ACTIVE:
+			case NM_SYNC_KLOOP_STOPPING:
+				priv->np_kloop_state = NM_SYNC_KLOOP_STOPPING;
+				break;
+			}
+			NMG_UNLOCK();
 			break;
 		}
 

From df0b1d99b831c1e988f33f9680e32f298f579322 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 09:51:36 +0200
Subject: [PATCH 1173/2207] ctrl-api-test: add sync_kloop positive test

---
 sys/dev/netmap/netmap.c |  2 +-
 utils/ctrl-api-test.c   | 80 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 86e035d5e..a1dc0653e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3999,7 +3999,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 			nm_kr_put(kring);
 		}
-		break;
+		usleep_range(2000, 2000);
 	}
 
 	/* Reset the kloop state. */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5a9a25005..c60c53b12 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -10,9 +10,10 @@
 #include 
 #include 
 #include 
+#include 
 
 struct TestContext {
-	int fd;                 /* netmap file descriptor */
+	int fd; /* netmap file descriptor */
 	const char *ifname;
 	const char *bdgname;
 	uint32_t nr_tx_slots;   /* slots in tx rings */
@@ -798,6 +799,82 @@ duplicate_extmem_options(struct TestContext *ctx)
 }
 #endif /* CONFIG_NETMAP_EXTMEM */
 
+static void *
+sync_kloop_worker(void *opaque)
+{
+	struct TestContext *ctx = opaque;
+	size_t num_entries      = ctx->nr_rx_rings + ctx->nr_tx_rings;
+	struct nmreq_sync_kloop_start req;
+	struct nmreq_header hdr;
+	void *csb;
+	int ret;
+
+	csb = malloc((sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	             num_entries);
+	if (!csb) {
+		printf("Failed to allocate CSB memory\n");
+		return NULL;
+	}
+
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
+	hdr.nr_body    = (uintptr_t)&req;
+	hdr.nr_options = (uintptr_t)ctx->nr_opt;
+	memset(&req, 0, sizeof(req));
+	req.csb_atok = (uintptr_t)csb;
+	req.csb_ktoa =
+	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+		return NULL;
+	}
+
+	free(csb);
+
+	return NULL;
+}
+
+static int
+sync_kloop(struct TestContext *ctx)
+{
+	int ret = port_register_hwall(ctx);
+	pthread_t th;
+
+	if (ret) {
+		return ret;
+	}
+
+	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
+	if (ret) {
+		printf("pthread_create(kloop): %s\n", strerror(ret));
+		return -1;
+	}
+
+	sleep(1);
+
+	{
+		struct nmreq_header hdr;
+
+		nmreq_hdr_init(&hdr, ctx->ifname);
+		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+			return ret;
+		}
+	}
+
+	ret = pthread_join(th, NULL);
+	if (ret) {
+		printf("pthread_join(kloop): %s\n", strerror(ret));
+	}
+
+	return 0;
+}
+
 static void
 usage(const char *prog)
 {
@@ -835,6 +912,7 @@ static struct mytest tests[] = {
 	decltest(bad_extmem_option),
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
+	decltest(sync_kloop),
 };
 
 int

From 63a0429f984c81a166bc205c2d8d9bbdc5defe04 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 10:41:24 +0200
Subject: [PATCH 1174/2207] sync-kloop: allow posted "stop request"

---
 sys/dev/netmap/netmap.c      | 24 +++++++++---------------
 sys/dev/netmap/netmap_kern.h |  5 ++---
 2 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a1dc0653e..95f8b1bd3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1925,7 +1925,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	}
 	priv->np_flags = 0;
 	priv->np_txpoll = 0;
-	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
+	priv->np_kloop_state = 0;
 }
 
 
@@ -2637,15 +2637,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 		case NETMAP_REQ_SYNC_KLOOP_STOP: {
 			NMG_LOCK();
-			switch (priv->np_kloop_state) {
-			case NM_SYNC_KLOOP_NONE:
-				error = ENXIO;
-				break;
-			case NM_SYNC_KLOOP_ACTIVE:
-			case NM_SYNC_KLOOP_STOPPING:
-				priv->np_kloop_state = NM_SYNC_KLOOP_STOPPING;
-				break;
-			}
+			priv->np_kloop_state |= NM_SYNC_KLOOP_STOPPING;
 			NMG_UNLOCK();
 			break;
 		}
@@ -3932,11 +3924,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 	/* Make sure that no kloop is active or about to stop. */
 	NMG_LOCK();
-	if (priv->np_kloop_state != NM_SYNC_KLOOP_NONE) {
+	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
 		err = EBUSY;
-	} else {
-		priv->np_kloop_state = NM_SYNC_KLOOP_ACTIVE;
 	}
+	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
 	NMG_UNLOCK();
 	if (err) {
 		return err;
@@ -3987,7 +3978,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
-	while (likely(NM_ACCESS_ONCE(priv->np_kloop_state) != NM_SYNC_KLOOP_STOPPING)) {
+	for (;;) {
 		unsigned int i;
 
 		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
@@ -4000,11 +3991,14 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 		usleep_range(2000, 2000);
+		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
+			break;
+		}
 	}
 
 	/* Reset the kloop state. */
 	NMG_LOCK();
-	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
+	priv->np_kloop_state = 0;
 	NMG_UNLOCK();
 
 	return 0;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d050e4b00..0e95f7592 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1869,9 +1869,8 @@ struct netmap_priv_d {
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
 	uint16_t	np_txpoll;
 	uint16_t        np_kloop_state;	/* use with NMG_LOCK held */
-#define NM_SYNC_KLOOP_NONE	0
-#define NM_SYNC_KLOOP_ACTIVE	1
-#define NM_SYNC_KLOOP_STOPPING	2
+#define NM_SYNC_KLOOP_RUNNING	(1 << 0)
+#define NM_SYNC_KLOOP_STOPPING	(1 << 1)
 	int             np_sync_flags; /* to be passed to nm_sync */
 
 	int		np_refs;	/* use with NMG_LOCK held */

From a078eb41df560d4de76f1e358e3c0120328443d6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 12:56:29 +0200
Subject: [PATCH 1175/2207] ctrl-api-test: sync_loop_worker: check that CSB
 size is > 0

---
 utils/ctrl-api-test.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index c60c53b12..81de226e1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -11,6 +11,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct TestContext {
 	int fd; /* netmap file descriptor */
@@ -806,17 +807,21 @@ sync_kloop_worker(void *opaque)
 	size_t num_entries      = ctx->nr_rx_rings + ctx->nr_tx_rings;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
+	size_t csb_size;
 	void *csb;
 	int ret;
 
-	csb = malloc((sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	             num_entries);
+	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	             num_entries;
+	assert(csb_size > 0);
+	csb = malloc(csb_size);
 	if (!csb) {
 		printf("Failed to allocate CSB memory\n");
 		return NULL;
 	}
 
-	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
+		(unsigned)csb_size, ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;

From 337bef61f05aa583640d3241080cb801b3999a66 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 14:33:26 +0200
Subject: [PATCH 1176/2207] utils: ctrl-api-test: introduce
 TextContext::retcode

This is useful to collect the return code of a thread.
---
 utils/ctrl-api-test.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 81de226e1..29dc99140 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -32,6 +32,8 @@ struct TestContext {
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
 	struct nmreq_option *nr_opt;  /* list of options */
+
+	int retcode;
 };
 
 #if 0
@@ -811,6 +813,8 @@ sync_kloop_worker(void *opaque)
 	void *csb;
 	int ret;
 
+	ctx->retcode = -1;
+
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
 	             num_entries;
 	assert(csb_size > 0);
@@ -838,6 +842,7 @@ sync_kloop_worker(void *opaque)
 	}
 
 	free(csb);
+	ctx->retcode = 0;
 
 	return NULL;
 }
@@ -858,8 +863,6 @@ sync_kloop(struct TestContext *ctx)
 		return -1;
 	}
 
-	sleep(1);
-
 	{
 		struct nmreq_header hdr;
 
@@ -877,7 +880,7 @@ sync_kloop(struct TestContext *ctx)
 		printf("pthread_join(kloop): %s\n", strerror(ret));
 	}
 
-	return 0;
+	return ctx->retcode;
 }
 
 static void

From 2e449e82913d5359ec450d4c92da121351d6fbd4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 15:10:16 +0200
Subject: [PATCH 1177/2207] ctrl-api-test: check that only one sync kloop can
 be created

---
 utils/ctrl-api-test.c | 66 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 11 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 29dc99140..b02c5317b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -32,8 +32,6 @@ struct TestContext {
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
 	struct nmreq_option *nr_opt;  /* list of options */
-
-	int retcode;
 };
 
 #if 0
@@ -813,15 +811,13 @@ sync_kloop_worker(void *opaque)
 	void *csb;
 	int ret;
 
-	ctx->retcode = -1;
-
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
 	             num_entries;
 	assert(csb_size > 0);
 	csb = malloc(csb_size);
 	if (!csb) {
 		printf("Failed to allocate CSB memory\n");
-		return NULL;
+		pthread_exit((void *)-1);
 	}
 
 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
@@ -838,13 +834,10 @@ sync_kloop_worker(void *opaque)
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
-		return NULL;
 	}
-
 	free(csb);
-	ctx->retcode = 0;
 
-	return NULL;
+	pthread_exit((void *)(uintptr_t)ret);
 }
 
 static int
@@ -852,6 +845,7 @@ sync_kloop(struct TestContext *ctx)
 {
 	int ret = port_register_hwall(ctx);
 	pthread_t th;
+	int thret;
 
 	if (ret) {
 		return ret;
@@ -875,12 +869,61 @@ sync_kloop(struct TestContext *ctx)
 		}
 	}
 
-	ret = pthread_join(th, NULL);
+	ret = pthread_join(th, (void **)&thret);
 	if (ret) {
 		printf("pthread_join(kloop): %s\n", strerror(ret));
 	}
 
-	return ctx->retcode;
+	return thret;
+}
+
+static int
+sync_kloop_conflict(struct TestContext *ctx)
+{
+	int ret = port_register_hwall(ctx);
+	pthread_t th1, th2;
+	int thret1, thret2;
+
+	if (ret) {
+		return ret;
+	}
+
+	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
+	if (ret) {
+		printf("pthread_create(kloop1): %s\n", strerror(ret));
+		return -1;
+	}
+
+	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
+	if (ret) {
+		printf("pthread_create(kloop2): %s\n", strerror(ret));
+		return -1;
+	}
+
+	{
+		struct nmreq_header hdr;
+
+		nmreq_hdr_init(&hdr, ctx->ifname);
+		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+			return ret;
+		}
+	}
+
+	ret = pthread_join(th1, (void **)&thret1);
+	if (ret) {
+		printf("pthread_join(kloop1): %s\n", strerror(ret));
+	}
+
+	ret = pthread_join(th2, (void **)&thret2);
+	if (ret) {
+		printf("pthread_join(kloop2): %s\n", strerror(ret));
+	}
+
+	return ((thret1 == 0 && thret2 != 0) ||
+		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
 }
 
 static void
@@ -921,6 +964,7 @@ static struct mytest tests[] = {
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
+	decltest(sync_kloop_conflict),
 };
 
 int

From 2e071ea3c5802425dafbea8aad0261ded85ca317 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 15:17:51 +0200
Subject: [PATCH 1178/2207] utils: ctrl-api-test: add a usleep() to avoid a
 race condition

---
 utils/ctrl-api-test.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b02c5317b..661e265a1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -900,6 +900,10 @@ sync_kloop_conflict(struct TestContext *ctx)
 		return -1;
 	}
 
+	/* Try to avoid a race condition where th1 starts the loop and stops, and
+	 * after that th2 starts the loop successfully. */
+	usleep(500000);
+
 	{
 		struct nmreq_header hdr;
 
@@ -922,6 +926,7 @@ sync_kloop_conflict(struct TestContext *ctx)
 		printf("pthread_join(kloop2): %s\n", strerror(ret));
 	}
 
+	/* Check that one of the two failed, while the other one succeeded. */
 	return ((thret1 == 0 && thret2 != 0) ||
 		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
 }

From c44acb2c643e481bbb7cbc8ae89c565edb4dfdc2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 15:29:20 +0200
Subject: [PATCH 1179/2207] ctrl-api-test: sync-kloop: add negative test for
 invalid CSB

---
 utils/ctrl-api-test.c | 70 ++++++++++++++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 20 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 661e265a1..39795840a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -800,6 +800,22 @@ duplicate_extmem_options(struct TestContext *ctx)
 }
 #endif /* CONFIG_NETMAP_EXTMEM */
 
+static int
+sync_kloop_stop(struct TestContext *ctx)
+{
+	struct nmreq_header hdr;
+	int ret;
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+	}
+
+	return ret;
+}
+
 static void *
 sync_kloop_worker(void *opaque)
 {
@@ -857,16 +873,9 @@ sync_kloop(struct TestContext *ctx)
 		return -1;
 	}
 
-	{
-		struct nmreq_header hdr;
-
-		nmreq_hdr_init(&hdr, ctx->ifname);
-		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-		if (ret) {
-			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
-			return ret;
-		}
+	ret = sync_kloop_stop(ctx);
+	if (ret) {
+		return ret;
 	}
 
 	ret = pthread_join(th, (void **)&thret);
@@ -904,16 +913,9 @@ sync_kloop_conflict(struct TestContext *ctx)
 	 * after that th2 starts the loop successfully. */
 	usleep(500000);
 
-	{
-		struct nmreq_header hdr;
-
-		nmreq_hdr_init(&hdr, ctx->ifname);
-		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-		if (ret) {
-			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
-			return ret;
-		}
+	ret = sync_kloop_stop(ctx);
+	if (ret) {
+		return ret;
 	}
 
 	ret = pthread_join(th1, (void **)&thret1);
@@ -931,6 +933,33 @@ sync_kloop_conflict(struct TestContext *ctx)
 		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
 }
 
+static int
+sync_kloop_invalid_csb(struct TestContext *ctx)
+{
+	int ret = port_register_hwall(ctx);
+	struct nmreq_sync_kloop_start req;
+	struct nmreq_header hdr;
+
+	/* Post a stop request first. */
+	ret = sync_kloop_stop(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
+	hdr.nr_body    = (uintptr_t)&req;
+	memset(&req, 0, sizeof(req));
+	req.csb_atok = (uintptr_t)0x10;
+	req.csb_ktoa = (uintptr_t)0x800;
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+	}
+
+	return (ret < 0) ? 0 : -1;
+}
+
 static void
 usage(const char *prog)
 {
@@ -970,6 +999,7 @@ static struct mytest tests[] = {
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
 	decltest(sync_kloop_conflict),
+	decltest(sync_kloop_invalid_csb),
 };
 
 int

From 3854c3a4e38074bae6b3fee863126536e500bb95 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 17:18:22 +0200
Subject: [PATCH 1180/2207] sync-kloop: check for CSB alignment

---
 sys/dev/netmap/netmap.c | 15 ++++++++++++---
 utils/ctrl-api-test.c   |  4 ++--
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 95f8b1bd3..1bbee4f55 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3945,10 +3945,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 		if (num_entries > 0) {
 			size_t entry_size[2];
+			void *csb_start[2];
 			unsigned int i;
 
 			entry_size[0] = sizeof(*csb_atok);
 			entry_size[1] = sizeof(*csb_ktoa);
+			csb_start[0] = (void *)csb_atok;
+			csb_start[1] = (void *)csb_ktoa;
 
 			for (i = 0; i < 2; i++) {
 				/* On Linux we could use access_ok() to simplify
@@ -3956,18 +3959,24 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 				 * this approach is that it works also on
 				 * FreeBSD. */
 				size_t csb_size = num_entries * entry_size[i];
-				void *tmp = nm_os_malloc(csb_size);
+				void *tmp;
 
+				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
+					nm_prerr("Unaligned CSB address\n");
+					return EINVAL;
+				}
+
+				tmp = nm_os_malloc(csb_size);
 				if (!tmp) {
 					return ENOMEM;
 				}
 				if (i == 0) {
 					/* Application --> kernel direction. */
-					err = copyin(csb_atok, tmp, csb_size);
+					err = copyin(csb_start[i], tmp, csb_size);
 				} else {
 					/* Kernel --> application direction. */
 					memset(tmp, 0, csb_size);
-					err = copyout(tmp, csb_ktoa, csb_size);
+					err = copyout(tmp, csb_start[i], csb_size);
 				}
 				nm_os_free(tmp);
 				if (err) {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 39795840a..5d72bbbcc 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -830,8 +830,8 @@ sync_kloop_worker(void *opaque)
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
 	             num_entries;
 	assert(csb_size > 0);
-	csb = malloc(csb_size);
-	if (!csb) {
+	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
+	if (ret) {
 		printf("Failed to allocate CSB memory\n");
 		pthread_exit((void *)-1);
 	}

From 59f6fa3591ea517feeee6da24924337d47592e86 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 18:07:12 +0200
Subject: [PATCH 1181/2207] sync-kloop: introduce TX processing loop

---
 sys/dev/netmap/netmap.c | 239 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 224 insertions(+), 15 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1bbee4f55..05a99f0c0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3904,12 +3904,217 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
+/* Functions to read and write CSB fields from the kernel. */
+#if defined (linux)
+#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
+#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
+#else  /* ! linux */
+#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
+#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
+#endif /* ! linux */
+
+/* Write kring pointers (hwcur, hwtail) to the CSB.
+ * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
+static inline void
+sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
+			   uint32_t hwtail)
+{
+	/*
+	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
+	 * We allow the guest to read a value of hwcur more recent than the value
+	 * of hwtail, since this would anyway result in a consistent view of the
+	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
+	 * behind head).
+	 *
+	 * The following memory barrier scheme is used to make this happen:
+	 *
+	 *          Guest                Host
+	 *
+	 *          STORE(hwcur)         LOAD(hwtail)
+	 *          mb() <-------------> mb()
+	 *          STORE(hwtail)        LOAD(hwcur)
+	 */
+	CSB_WRITE(ptr, hwcur, hwcur);
+	mb();
+	CSB_WRITE(ptr, hwtail, hwtail);
+}
+
+/* Read kring pointers (head, cur, sync_flags) from the CSB.
+ * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
+static inline void
+sync_kloop_read_kring_csb(struct nm_csb_atok __user *ptr,
+			  struct netmap_ring *shadow_ring,
+			  uint32_t num_slots)
+{
+	/*
+	 * We place a memory barrier to make sure that the update of head never
+	 * overtakes the update of cur.
+	 * (see explanation in ptnetmap_guest_write_kring_csb).
+	 */
+	CSB_READ(ptr, head, shadow_ring->head);
+	mb();
+	CSB_READ(ptr, cur, shadow_ring->cur);
+	CSB_READ(ptr, sync_flags, shadow_ring->flags);
+}
+
+/* Enable or disable guest --> host kicks. */
+static inline void
+csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
+{
+	CSB_WRITE(csb_ktoa, kern_need_kick, val);
+}
+
+/* Are guest interrupt enabled or disabled? */
+static inline uint32_t
+csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
+{
+	uint32_t v;
+
+	CSB_READ(csb_atok, appl_need_kick, v);
+
+	return v;
+}
+
+static inline void
+sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
+{
+	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
+		" rtail: %d head: %d cur: %d tail: %d",
+		title, kring->name, kring->nr_hwcur,
+		kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
+		kring->ring->head, kring->ring->cur, kring->ring->tail);
+}
+
+static void
+netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
+			  struct nm_csb_atok *csb_atok,
+			  struct nm_csb_ktoa *csb_ktoa)
+{
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	bool more_txspace = false;
+	uint32_t num_slots;
+	int batch;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable guest --> host notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the guest kring pointers from the CSB */
+	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		batch = shadow_ring.head - kring->nr_hwcur;
+		if (batch < 0)
+			batch += num_slots;
+
+#ifdef PTN_TX_BATCH_LIM
+		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
+			/* If guest moves ahead too fast, let's cut the move so
+			 * that we don't exceed our batch limit. */
+			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
+
+			if (head_lim >= num_slots)
+				head_lim -= num_slots;
+			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
+					head_lim);
+			shadow_ring.head = head_lim;
+			batch = PTN_TX_BATCH_LIM(num_slots);
+		}
+#endif /* PTN_TX_BATCH_LIM */
+
+		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
+			shadow_ring.flags |= NAF_FORCE_RECLAIM;
+		}
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("pre txsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR txsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy host hwcur and hwtail into the CSB for the guest sync(), and
+		 * do the nm_sync_finalize.
+		 */
+		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur,
+				kring->nr_hwtail);
+		if (kring->rtail != kring->nr_hwtail) {
+			/* Some more room available in the parent adapter. */
+			kring->rtail = kring->nr_hwtail;
+			more_txspace = true;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("post txsync", kring);
+		}
+
+#ifndef BUSY_WAIT
+		/* Interrupt the guest if needed. */
+		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable guest kick to avoid sending unnecessary kicks */
+			// nm_os_kctx_send_irq(kth); // TODO
+			more_txspace = false;
+		}
+#endif
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+#ifndef BUSY_WAIT
+		if (shadow_ring.head == kring->rhead) {
+			/*
+			 * No more packets to transmit. We enable notifications and
+			 * go to sleep, waiting for a kick from the guest when new
+			 * new slots are ready for transmission.
+			 */
+			usleep_range(1,1);
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			if (shadow_ring.head != kring->rhead) {
+				/* We won the race condition, there are more packets to
+				 * transmit. Disable notifications and do another cycle */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		if (nm_kr_txempty(kring)) {
+			/* No more available TX slots. We stop waiting for a notification
+			 * from the backend (netmap_tx_irq). */
+			ND(1, "TX ring");
+			break;
+		}
+#endif
+	}
+
+	if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
+		// nm_os_kctx_send_irq(kth); // TODO
+	}
+}
+
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
+	struct nm_csb_atok* csb_atok_base;
+	struct nm_csb_ktoa* csb_ktoa_base;
+	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
-	struct nm_csb_atok* csb_atok;
-	struct nm_csb_ktoa* csb_ktoa;
 	int err = 0;
 
 	if (priv->np_nifp == NULL) {
@@ -3933,25 +4138,24 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return err;
 	}
 
-	csb_atok = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-	csb_ktoa = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
+	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
 
 	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
-		int num_entries;
-
-		num_entries = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
-			      priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+		int num_entries = num_rx_rings + num_tx_rings;
 
 		if (num_entries > 0) {
 			size_t entry_size[2];
 			void *csb_start[2];
 			unsigned int i;
 
-			entry_size[0] = sizeof(*csb_atok);
-			entry_size[1] = sizeof(*csb_ktoa);
-			csb_start[0] = (void *)csb_atok;
-			csb_start[1] = (void *)csb_ktoa;
+			entry_size[0] = sizeof(*csb_atok_base);
+			entry_size[1] = sizeof(*csb_ktoa_base);
+			csb_start[0] = (void *)csb_atok_base;
+			csb_start[1] = (void *)csb_ktoa_base;
 
 			for (i = 0; i < 2; i++) {
 				/* On Linux we could use access_ok() to simplify
@@ -3990,16 +4194,21 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	for (;;) {
 		unsigned int i;
 
-		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
-			struct netmap_kring *kring = NMR(na, NR_TX)[i];
+		for (i = 0; i < num_tx_rings; i++) {
+			struct netmap_kring *kring =
+				NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
+			struct nm_csb_atok* csb_atok = csb_atok_base + i;
+			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + i;
 
 			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
 				continue;
 			}
-
+			netmap_sync_kloop_tx_ring(kring, csb_atok, csb_ktoa);
 			nm_kr_put(kring);
 		}
+
 		usleep_range(2000, 2000);
+
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
 		}

From 1aa3218a7189e9ec7662528f6bd1a566094ffeac Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 18:13:15 +0200
Subject: [PATCH 1182/2207] sync-kloop: add/fix some comments

---
 sys/dev/netmap/netmap.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 05a99f0c0..583c3ab0d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3921,14 +3921,14 @@ sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 {
 	/*
 	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
-	 * We allow the guest to read a value of hwcur more recent than the value
+	 * We allow the application to read a value of hwcur more recent than the value
 	 * of hwtail, since this would anyway result in a consistent view of the
 	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
 	 * behind head).
 	 *
 	 * The following memory barrier scheme is used to make this happen:
 	 *
-	 *          Guest                Host
+	 *          Application          Kernel
 	 *
 	 *          STORE(hwcur)         LOAD(hwtail)
 	 *          mb() <-------------> mb()
@@ -3957,14 +3957,14 @@ sync_kloop_read_kring_csb(struct nm_csb_atok __user *ptr,
 	CSB_READ(ptr, sync_flags, shadow_ring->flags);
 }
 
-/* Enable or disable guest --> host kicks. */
+/* Enable or disable application --> kernel kicks. */
 static inline void
 csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
 {
 	CSB_WRITE(csb_ktoa, kern_need_kick, val);
 }
 
-/* Are guest interrupt enabled or disabled? */
+/* Are application interrupt enabled or disabled? */
 static inline uint32_t
 csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 {
@@ -3997,9 +3997,9 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 
 	num_slots = kring->nkr_num_slots;
 
-	/* Disable guest --> host notifications. */
+	/* Disable application --> kernel notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the guest kring pointers from the CSB */
+	/* Copy the application kring pointers from the CSB */
 	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
@@ -4009,7 +4009,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 
 #ifdef PTN_TX_BATCH_LIM
 		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
-			/* If guest moves ahead too fast, let's cut the move so
+			/* If application moves ahead too fast, let's cut the move so
 			 * that we don't exceed our batch limit. */
 			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
 
@@ -4048,7 +4048,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 
 		/*
 		 * Finalize
-		 * Copy host hwcur and hwtail into the CSB for the guest sync(), and
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
 		 * do the nm_sync_finalize.
 		 */
 		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur,
@@ -4064,9 +4064,9 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		}
 
 #ifndef BUSY_WAIT
-		/* Interrupt the guest if needed. */
+		/* Interrupt the application if needed. */
 		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable guest kick to avoid sending unnecessary kicks */
+			/* Disable application kick to avoid sending unnecessary kicks */
 			// nm_os_kctx_send_irq(kth); // TODO
 			more_txspace = false;
 		}
@@ -4077,7 +4077,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		if (shadow_ring.head == kring->rhead) {
 			/*
 			 * No more packets to transmit. We enable notifications and
-			 * go to sleep, waiting for a kick from the guest when new
+			 * go to sleep, waiting for a kick from the application when new
 			 * new slots are ready for transmission.
 			 */
 			usleep_range(1,1);
@@ -4127,7 +4127,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
-	/* Make sure that no kloop is active or about to stop. */
+	/* Make sure that no kloop is currently running. */
 	NMG_LOCK();
 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
 		err = EBUSY;
@@ -4191,9 +4191,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
+	/* Main loop. */
 	for (;;) {
 		unsigned int i;
 
+		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
 			struct netmap_kring *kring =
 				NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
@@ -4207,6 +4209,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
+		/* TODO process all the RX rings */
+
+		/* TODO replace with proper notifications and/or configurable
+		 * sleep interval. */
 		usleep_range(2000, 2000);
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {

From d042c98c2887f9e50265119be44bfb03be0fc5e4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 23:04:38 +0200
Subject: [PATCH 1183/2207] sync-kloop: introduce RX processing loop

---
 sys/dev/netmap/netmap.c | 136 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 583c3ab0d..da4ce2f4d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4108,6 +4108,128 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 	}
 }
 
+/* RX cycle without receive any packets */
+#define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
+
+static inline int
+sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
+{
+	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
+				kring->nkr_num_slots - 1));
+}
+
+static void
+netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
+		struct nm_csb_atok *csb_atok,
+		struct nm_csb_ktoa *csb_ktoa)
+{
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	int dry_cycles = 0;
+	bool some_recvd = false;
+	uint32_t num_slots;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the guest kring pointers from the CSB */
+	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		uint32_t hwtail;
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("pre rxsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR rxsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy host hwcur and hwtail into the CSB for the guest sync()
+		 */
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur, hwtail);
+		if (kring->rtail != hwtail) {
+			kring->rtail = hwtail;
+			some_recvd = true;
+			dry_cycles = 0;
+		} else {
+			dry_cycles++;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("post rxsync", kring);
+		}
+
+#ifndef BUSY_WAIT
+		/* Interrupt the guest if needed. */
+		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable guest kick to avoid sending unnecessary kicks */
+			//nm_os_kctx_send_irq(kth); // TODO
+			some_recvd = false;
+		}
+#endif
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+#ifndef BUSY_WAIT
+		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
+			/*
+			 * No more slots available for reception. We enable notification and
+			 * go to sleep, waiting for a kick from the guest when new receive
+			 * slots are available.
+			 */
+			usleep_range(1,1);
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
+				/* We won the race condition, more slots are available. Disable
+				 * notifications and do another cycle. */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		if (unlikely(hwtail == kring->rhead ||
+					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
+			/* No more packets to be read from the backend. We stop and
+			 * wait for a notification from the backend (netmap_rx_irq). */
+			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
+					hwtail, kring->rhead, dry_cycles);
+			break;
+		}
+#endif
+	}
+
+	nm_kr_put(kring);
+
+	/* Interrupt the guest if needed. */
+	if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		//nm_os_kctx_send_irq(kth); // TODO
+	}
+}
+
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
@@ -4209,7 +4331,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
-		/* TODO process all the RX rings */
+		/* Process all the RX rings bound to this file descriptor. */
+		for (i = 0; i < num_rx_rings; i++) {
+			struct netmap_kring *kring =
+				NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
+			struct nm_csb_atok* csb_atok = csb_atok_base + num_tx_rings + i;
+			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + num_tx_rings + i;
+
+			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+				continue;
+			}
+			netmap_sync_kloop_rx_ring(kring, csb_atok, csb_ktoa);
+			nm_kr_put(kring);
+		}
 
 		/* TODO replace with proper notifications and/or configurable
 		 * sleep interval. */

From bd2642a70fad7648e7c206b3405e85b3f2d111f9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 23:10:04 +0200
Subject: [PATCH 1184/2207] sync-kloop: fix some comments

---
 sys/dev/netmap/netmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index da4ce2f4d..b36143de0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4120,8 +4120,8 @@ sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
 
 static void
 netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
-		struct nm_csb_atok *csb_atok,
-		struct nm_csb_ktoa *csb_ktoa)
+			  struct nm_csb_atok *csb_atok,
+			  struct nm_csb_ktoa *csb_ktoa)
 {
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	int dry_cycles = 0;
@@ -4135,7 +4135,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 	/* Disable notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the guest kring pointers from the CSB */
+	/* Copy the application kring pointers from the CSB */
 	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
@@ -4163,7 +4163,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 		/*
 		 * Finalize
-		 * Copy host hwcur and hwtail into the CSB for the guest sync()
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
 		 */
 		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
 		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur, hwtail);
@@ -4180,9 +4180,9 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		}
 
 #ifndef BUSY_WAIT
-		/* Interrupt the guest if needed. */
+		/* Interrupt the application if needed. */
 		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable guest kick to avoid sending unnecessary kicks */
+			/* Disable application kick to avoid sending unnecessary kicks */
 			//nm_os_kctx_send_irq(kth); // TODO
 			some_recvd = false;
 		}
@@ -4193,7 +4193,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
 			/*
 			 * No more slots available for reception. We enable notification and
-			 * go to sleep, waiting for a kick from the guest when new receive
+			 * go to sleep, waiting for a kick from the application when new receive
 			 * slots are available.
 			 */
 			usleep_range(1,1);
@@ -4224,7 +4224,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 	nm_kr_put(kring);
 
-	/* Interrupt the guest if needed. */
+	/* Interrupt the application if needed. */
 	if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
 		//nm_os_kctx_send_irq(kth); // TODO
 	}

From 589e1e5c74a7c72a8fcd28fcbf2a0384a1deece5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Sep 2018 11:14:56 +0200
Subject: [PATCH 1185/2207] sync-kloop: remove conditional BUSY_WAIT code

---
 sys/dev/netmap/netmap.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b36143de0..0d9c8fe53 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4063,17 +4063,15 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			sync_kloop_kring_dump("post txsync", kring);
 		}
 
-#ifndef BUSY_WAIT
 		/* Interrupt the application if needed. */
 		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
 			// nm_os_kctx_send_irq(kth); // TODO
 			more_txspace = false;
 		}
-#endif
+
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
 		if (shadow_ring.head == kring->rhead) {
 			/*
 			 * No more packets to transmit. We enable notifications and
@@ -4100,7 +4098,6 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			ND(1, "TX ring");
 			break;
 		}
-#endif
 	}
 
 	if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
@@ -4179,17 +4176,15 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 			sync_kloop_kring_dump("post rxsync", kring);
 		}
 
-#ifndef BUSY_WAIT
 		/* Interrupt the application if needed. */
 		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
 			//nm_os_kctx_send_irq(kth); // TODO
 			some_recvd = false;
 		}
-#endif
+
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
 			/*
 			 * No more slots available for reception. We enable notification and
@@ -4219,7 +4214,6 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 					hwtail, kring->rhead, dry_cycles);
 			break;
 		}
-#endif
 	}
 
 	nm_kr_put(kring);

From bb9a31df00e1a7a51d67857168c82c553cc84e3f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Sep 2018 22:31:25 +0200
Subject: [PATCH 1186/2207] utils: add sync_kloop_test program

---
 utils/GNUmakefile       |   2 +-
 utils/sync_kloop_test.c | 129 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 utils/sync_kloop_test.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 0b7970654..249e41121 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,7 +1,7 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
 PROGS	  = test_select testmmap test_nm functional ctrl-api-test fd_server
-PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends extmem-example
+PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends extmem-example sync_kloop_test
 X86PROGS  = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
new file mode 100644
index 000000000..33a4eaef5
--- /dev/null
+++ b/utils/sync_kloop_test.c
@@ -0,0 +1,129 @@
+#include 
+#include 
+#include 
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static void *
+kloop_worker(void *opaque)
+{
+	struct nm_desc *nmd = opaque;
+	struct nmreq_sync_kloop_start req;
+	struct nmreq_header hdr;
+	size_t num_entries;
+	size_t csb_size;
+	void *csb;
+	int ret;
+
+	num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
+	              nmd->last_rx_ring - nmd->first_rx_ring + 1;
+	printf("Number of CSB entries = %d\n", (int)num_entries);
+	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	           num_entries;
+	assert(csb_size > 0);
+	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
+	if (ret) {
+		printf("Failed to allocate CSB memory\n");
+		return NULL;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.nr_version = NETMAP_API;
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
+	hdr.nr_body    = (uintptr_t)&req;
+	hdr.nr_options = (uintptr_t)NULL;
+	memset(&req, 0, sizeof(req));
+	req.csb_atok = (uintptr_t)csb;
+	req.csb_ktoa =
+	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
+	ret = ioctl(nmd->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+	}
+	free(csb);
+
+	return NULL;
+}
+
+static void
+usage(const char *progname)
+{
+	printf("%s\n"
+	       "[-h (show this help and exit)]\n"
+	       "-i NETMAP_PORT\n",
+	       progname);
+}
+
+int
+main(int argc, char **argv)
+{
+	const char *ifname = NULL;
+	struct nm_desc *nmd;
+	pthread_t th;
+	int opt;
+	int ret;
+
+	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+		switch (opt) {
+		case 'h':
+			usage(argv[0]);
+			return 0;
+
+		case 'i':
+			ifname = optarg;
+			break;
+
+		default:
+			printf("    Unrecognized option %c\n", opt);
+			usage(argv[0]);
+			return -1;
+		}
+	}
+
+	if (ifname == NULL) {
+		printf("No netmap port specified\n");
+		usage(argv[0]);
+		return -1;
+	}
+
+	printf("ifname %s\n", ifname);
+	nmd = nm_open(ifname, NULL, 0, NULL);
+	if (!nmd) {
+		printf("nm_open(%s) failed\n", ifname);
+		return -1;
+	}
+
+	ret = pthread_create(&th, NULL, kloop_worker, nmd);
+	if (ret) {
+		printf("pthread_create() failed: %s\n", strerror(ret));
+		nm_close(nmd);
+		return -1;
+	}
+
+	{
+		struct nmreq_header hdr;
+		int ret;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.nr_version = NETMAP_API;
+		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+		}
+	}
+
+	ret = pthread_join(th, NULL);
+	if (ret) {
+		printf("pthread_join() failed: %s\n", strerror(ret));
+	}
+
+	nm_close(nmd);
+
+	return 0;
+}

From a1f090e032b8028275884381821d5df75ae997e1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 27 Sep 2018 21:55:01 +0200
Subject: [PATCH 1187/2207] utils: sync_kloop_test: add data structure to keep
 context

---
 utils/sync_kloop_test.c | 36 +++++++++++++++++++++++++++---------
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 33a4eaef5..b0c8715f5 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -9,10 +9,16 @@
 #include 
 #include 
 
+struct context {
+	struct nm_desc *nmd;
+	const char *func;
+};
+
 static void *
 kloop_worker(void *opaque)
 {
-	struct nm_desc *nmd = opaque;
+	struct context *ctx = opaque;
+	struct nm_desc *nmd = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 	size_t num_entries;
@@ -55,6 +61,7 @@ usage(const char *progname)
 {
 	printf("%s\n"
 	       "[-h (show this help and exit)]\n"
+	       "[-f FUNCTION (rx,tx)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -63,12 +70,15 @@ int
 main(int argc, char **argv)
 {
 	const char *ifname = NULL;
-	struct nm_desc *nmd;
+	struct context ctx;
 	pthread_t th;
 	int opt;
 	int ret;
 
-	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.func = "rx";
+
+	while ((opt = getopt(argc, argv, "hi:f:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -78,6 +88,14 @@ main(int argc, char **argv)
 			ifname = optarg;
 			break;
 
+		case 'f':
+			ctx.func = optarg;
+			if (strcmp(optarg, "tx") && strcmp(optarg, "rx")) {
+				printf("    Unknown function %s\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -92,16 +110,16 @@ main(int argc, char **argv)
 	}
 
 	printf("ifname %s\n", ifname);
-	nmd = nm_open(ifname, NULL, 0, NULL);
-	if (!nmd) {
+	ctx.nmd = nm_open(ifname, NULL, 0, NULL);
+	if (!ctx.nmd) {
 		printf("nm_open(%s) failed\n", ifname);
 		return -1;
 	}
 
-	ret = pthread_create(&th, NULL, kloop_worker, nmd);
+	ret = pthread_create(&th, NULL, kloop_worker, &ctx);
 	if (ret) {
 		printf("pthread_create() failed: %s\n", strerror(ret));
-		nm_close(nmd);
+		nm_close(ctx.nmd);
 		return -1;
 	}
 
@@ -112,7 +130,7 @@ main(int argc, char **argv)
 		memset(&hdr, 0, sizeof(hdr));
 		hdr.nr_version = NETMAP_API;
 		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
+		ret            = ioctl(ctx.nmd->fd, NIOCCTRL, &hdr);
 		if (ret) {
 			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
 		}
@@ -123,7 +141,7 @@ main(int argc, char **argv)
 		printf("pthread_join() failed: %s\n", strerror(ret));
 	}
 
-	nm_close(nmd);
+	nm_close(ctx.nmd);
 
 	return 0;
 }

From 296619bcacf757346c60ed1212f01ab17e91afdc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 27 Sep 2018 22:36:35 +0200
Subject: [PATCH 1188/2207] utils: sync_kloop_test: sketch transmit loop

---
 sys/net/netmap.h        |  2 +-
 utils/sync_kloop_test.c | 74 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 41fcef519..5e799ce45 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -719,7 +719,7 @@ struct nmreq_sync_kloop_start {
 struct nm_csb_atok {
 	uint32_t head;		  /* AW+ KR+ the head of the appl netmap_ring */
 	uint32_t cur;		  /* AW+ KR+ the cur of the appl netmap_ring */
-	uint32_t appl_need_kick; /* AW+ KR+ kern --> appl notification enable */
+	uint32_t appl_need_kick;  /* AW+ KR+ kern --> appl notification enable */
 	uint32_t sync_flags;	  /* AW+ KR+ the flags of the appl [tx|rx]sync() */
 	char pad[48];		  /* pad to a 64 bytes cacheline */
 };
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index b0c8715f5..d944ca3aa 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -8,6 +8,18 @@
 #include 
 #include 
 #include 
+#include 
+
+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+
+static int stop = 0;
+
+static void
+sigint_handler(int signum)
+{
+	(void)signum;
+	ACCESS_ONCE(stop) = 1;
+}
 
 struct context {
 	struct nm_desc *nmd;
@@ -20,6 +32,8 @@ kloop_worker(void *opaque)
 	struct context *ctx = opaque;
 	struct nm_desc *nmd = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
+	struct nm_csb_atok *atok_base;
+	struct nm_csb_ktoa *ktoa_base;
 	struct nmreq_header hdr;
 	size_t num_entries;
 	size_t csb_size;
@@ -37,6 +51,7 @@ kloop_worker(void *opaque)
 		printf("Failed to allocate CSB memory\n");
 		return NULL;
 	}
+	memset(csb, 0, csb_size);
 
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.nr_version = NETMAP_API;
@@ -51,6 +66,53 @@ kloop_worker(void *opaque)
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
+
+	atok_base = (struct nm_csb_atok *)csb;
+	ktoa_base = (struct nm_csb_ktoa *)(atok_base + num_entries);
+
+	if (!strcmp(ctx->func, "tx")) {
+		while (!ACCESS_ONCE(stop)) {
+			uint16_t r;
+
+			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
+			     r++) {
+				struct netmap_ring *ring =
+				        NETMAP_TXRING(nmd->nifp, r);
+				struct nm_csb_atok *atok = atok_base + r;
+				struct nm_csb_ktoa *ktoa = ktoa_base + r;
+				struct netmap_slot *slot;
+				uint32_t hwtail, head;
+
+				head   = atok->head;
+				hwtail = ACCESS_ONCE(ktoa->hwtail);
+
+				if (head == hwtail) {
+					continue;
+				}
+
+				slot        = ring->slot + head;
+				slot->len   = 60;
+				slot->flags = 0;
+				{
+					char *buf =
+					        NETMAP_BUF(ring, slot->buf_idx);
+					memset(buf, 0xFF, 6);
+					memset(buf + 6, 0, 6);
+					buf[12] = 0x08;
+					buf[13] = 0x00;
+					memset(buf + 14, 'x', slot->len - 14);
+				}
+				ACCESS_ONCE(atok->head) =
+				        ACCESS_ONCE(atok->cur) =
+				                nm_ring_next(ring, head);
+				printf("ring #%u, head %u, hwtail %u\n",
+				       (unsigned int)r, (unsigned int)head,
+				       (unsigned int)hwtail);
+			}
+			usleep(1000000);
+		}
+	}
+
 	free(csb);
 
 	return NULL;
@@ -75,6 +137,18 @@ main(int argc, char **argv)
 	int opt;
 	int ret;
 
+	{
+		struct sigaction sa;
+
+		sa.sa_handler = sigint_handler;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_RESTART;
+		if (sigaction(SIGINT, &sa, NULL)) {
+			perror("sigaction(SIGINT)");
+			exit(EXIT_FAILURE);
+		}
+	}
+
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.func = "rx";
 

From b59638fba52be95415698c9672e95c4678c75bf0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 17:01:45 +0200
Subject: [PATCH 1189/2207] netmap.h: add functions to write/read from CSB

---
 sys/dev/netmap/netmap.c | 20 +++++++--------
 sys/net/netmap.h        | 57 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0d9c8fe53..05c7de38c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3916,7 +3916,7 @@ nm_clear_native_flags(struct netmap_adapter *na)
 /* Write kring pointers (hwcur, hwtail) to the CSB.
  * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
 static inline void
-sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
+sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 			   uint32_t hwtail)
 {
 	/*
@@ -3942,7 +3942,7 @@ sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 /* Read kring pointers (head, cur, sync_flags) from the CSB.
  * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
 static inline void
-sync_kloop_read_kring_csb(struct nm_csb_atok __user *ptr,
+sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
 			  struct netmap_ring *shadow_ring,
 			  uint32_t num_slots)
 {
@@ -4000,7 +4000,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 	/* Disable application --> kernel notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
 	/* Copy the application kring pointers from the CSB */
-	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
 		batch = shadow_ring.head - kring->nr_hwcur;
@@ -4051,7 +4051,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
 		 * do the nm_sync_finalize.
 		 */
-		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur,
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
 				kring->nr_hwtail);
 		if (kring->rtail != kring->nr_hwtail) {
 			/* Some more room available in the parent adapter. */
@@ -4071,7 +4071,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		}
 
 		/* Read CSB to see if there is more work to do. */
-		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (shadow_ring.head == kring->rhead) {
 			/*
 			 * No more packets to transmit. We enable notifications and
@@ -4082,7 +4082,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */
-			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 			if (shadow_ring.head != kring->rhead) {
 				/* We won the race condition, there are more packets to
 				 * transmit. Disable notifications and do another cycle */
@@ -4133,7 +4133,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	/* Disable notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
 	/* Copy the application kring pointers from the CSB */
-	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
 		uint32_t hwtail;
@@ -4163,7 +4163,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
 		 */
 		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur, hwtail);
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
 		if (kring->rtail != hwtail) {
 			kring->rtail = hwtail;
 			some_recvd = true;
@@ -4184,7 +4184,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		}
 
 		/* Read CSB to see if there is more work to do. */
-		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
 			/*
 			 * No more slots available for reception. We enable notification and
@@ -4195,7 +4195,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */
-			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
 				/* We won the race condition, more slots are available. Disable
 				 * notifications and do another cycle. */
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 5e799ce45..a48110728 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -731,6 +731,63 @@ struct nm_csb_ktoa {
 	char pad[4+48];
 };
 
+/* Application side of sync-kloop: Write ring pointers (cur, head) to the CSB.
+ * This routine is coupled with sync_kloop_kernel_read(). */
+static inline void
+nm_sync_kloop_appl_write(struct nm_csb_atok *atok, uint32_t cur,
+			 uint32_t head)
+{
+	/*
+	 * We need to write cur and head to the CSB but we cannot do it atomically.
+	 * There is no way we can prevent the host from reading the updated value
+	 * of one of the two and the old value of the other. However, if we make
+	 * sure that the host never reads a value of head more recent than the
+	 * value of cur we are safe. We can allow the host to read a value of cur
+	 * more recent than the value of head, since in the netmap ring cur can be
+	 * ahead of head and cur cannot wrap around head because it must be behind
+	 * tail. Inverting the order of writes below could instead result into the
+	 * host to think head went ahead of cur, which would cause the sync
+	 * prologue to fail.
+	 *
+	 * The following memory barrier scheme is used to make this happen:
+	 *
+	 *          Guest              Host
+	 *
+	 *          STORE(cur)         LOAD(head)
+	 *          mb() <-----------> mb()
+	 *          STORE(head)        LOAD(cur)
+	 *
+	 * TODO: This implementation work for x86 because of total store
+	 * ordering. Only a compiler barrier is needed. What we really
+	 * need here in the general case is a portable store-store barrier,
+	 * to prevent the two stores from being reordered (e.g. a "release"
+	 * barrier would be ok).
+	 */
+	atok->cur = cur;
+	asm volatile("" ::: "memory");
+	atok->head = head;
+}
+
+/* Application side of sync-kloop: Read kring pointers (hwcur, hwtail) from
+ * the CSB. This routine is coupled with sync_kloop_kernel_write(). */
+static inline void
+nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
+			uint32_t *hwcur)
+{
+	/*
+	 * We place a memory barrier to make sure that the update of hwtail never
+	 * overtakes the update of hwcur.
+	 * (see explanation in sync_kloop_kernel_write).
+	 *
+	 * TODO: This implementation works for x86 because loads are not reordered
+	 * after loads. What we need here is a portable load-load barrier, e.g.
+	 * an "acquire" barrier would be ok.
+	 */
+	*hwtail = ktoa->hwtail;
+	asm volatile("" ::: "memory");
+	*hwcur = ktoa->hwcur;
+}
+
 /*
  * data for NETMAP_REQ_OPT_* options
  */

From 74a8fca708026861111b34cd1242234345cf2136 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 18:06:17 +0200
Subject: [PATCH 1190/2207] utils: sync_kloop_test: move application processing
 to the main thread

---
 sys/dev/netmap/netmap.c |   8 +-
 utils/sync_kloop_test.c | 169 ++++++++++++++++++++++------------------
 2 files changed, 96 insertions(+), 81 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 05c7de38c..4b9c5fab2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3978,11 +3978,9 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 {
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
-		" rtail: %d head: %d cur: %d tail: %d",
-		title, kring->name, kring->nr_hwcur,
-		kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
-		kring->ring->head, kring->ring->cur, kring->ring->tail);
+	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
+		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
+		kring->rhead, kring->rcur, kring->rtail);
 }
 
 static void
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index d944ca3aa..7333a8b9b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -24,6 +24,9 @@ sigint_handler(int signum)
 struct context {
 	struct nm_desc *nmd;
 	const char *func;
+	struct nm_csb_atok *atok_base;
+	struct nm_csb_ktoa *ktoa_base;
+	size_t num_entries;
 };
 
 static void *
@@ -32,89 +35,25 @@ kloop_worker(void *opaque)
 	struct context *ctx = opaque;
 	struct nm_desc *nmd = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
-	struct nm_csb_atok *atok_base;
-	struct nm_csb_ktoa *ktoa_base;
 	struct nmreq_header hdr;
-	size_t num_entries;
-	size_t csb_size;
-	void *csb;
 	int ret;
 
-	num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
-	              nmd->last_rx_ring - nmd->first_rx_ring + 1;
-	printf("Number of CSB entries = %d\n", (int)num_entries);
-	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	           num_entries;
-	assert(csb_size > 0);
-	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
-	if (ret) {
-		printf("Failed to allocate CSB memory\n");
-		return NULL;
-	}
-	memset(csb, 0, csb_size);
-
+	/* The ioctl() returns on failure or when some other thread
+	 * stops the kernel loop. */
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.nr_version = NETMAP_API;
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
 	hdr.nr_body    = (uintptr_t)&req;
 	hdr.nr_options = (uintptr_t)NULL;
 	memset(&req, 0, sizeof(req));
-	req.csb_atok = (uintptr_t)csb;
-	req.csb_ktoa =
-	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
-	ret = ioctl(nmd->fd, NIOCCTRL, &hdr);
+	req.csb_atok = (uintptr_t)ctx->atok_base;
+	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
+	ret          = ioctl(nmd->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+		exit(EXIT_FAILURE);
 	}
 
-	atok_base = (struct nm_csb_atok *)csb;
-	ktoa_base = (struct nm_csb_ktoa *)(atok_base + num_entries);
-
-	if (!strcmp(ctx->func, "tx")) {
-		while (!ACCESS_ONCE(stop)) {
-			uint16_t r;
-
-			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
-			     r++) {
-				struct netmap_ring *ring =
-				        NETMAP_TXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok = atok_base + r;
-				struct nm_csb_ktoa *ktoa = ktoa_base + r;
-				struct netmap_slot *slot;
-				uint32_t hwtail, head;
-
-				head   = atok->head;
-				hwtail = ACCESS_ONCE(ktoa->hwtail);
-
-				if (head == hwtail) {
-					continue;
-				}
-
-				slot        = ring->slot + head;
-				slot->len   = 60;
-				slot->flags = 0;
-				{
-					char *buf =
-					        NETMAP_BUF(ring, slot->buf_idx);
-					memset(buf, 0xFF, 6);
-					memset(buf + 6, 0, 6);
-					buf[12] = 0x08;
-					buf[13] = 0x00;
-					memset(buf + 14, 'x', slot->len - 14);
-				}
-				ACCESS_ONCE(atok->head) =
-				        ACCESS_ONCE(atok->cur) =
-				                nm_ring_next(ring, head);
-				printf("ring #%u, head %u, hwtail %u\n",
-				       (unsigned int)r, (unsigned int)head,
-				       (unsigned int)hwtail);
-			}
-			usleep(1000000);
-		}
-	}
-
-	free(csb);
-
 	return NULL;
 }
 
@@ -132,7 +71,9 @@ int
 main(int argc, char **argv)
 {
 	const char *ifname = NULL;
+	void *csb          = NULL;
 	struct context ctx;
+	struct nm_desc *nmd;
 	pthread_t th;
 	int opt;
 	int ret;
@@ -183,20 +124,93 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	printf("ifname %s\n", ifname);
-	ctx.nmd = nm_open(ifname, NULL, 0, NULL);
-	if (!ctx.nmd) {
+	/* Open the netmap port. */
+	ctx.nmd = nmd = nm_open(ifname, NULL, 0, NULL);
+	if (!nmd) {
 		printf("nm_open(%s) failed\n", ifname);
 		return -1;
 	}
 
+	/* Allocate CSB entries. */
+	{
+		size_t csb_size;
+
+		ctx.num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
+		                  nmd->last_rx_ring - nmd->first_rx_ring + 1;
+		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
+		csb_size = (sizeof(struct nm_csb_atok) +
+		            sizeof(struct nm_csb_ktoa)) *
+		           ctx.num_entries;
+		assert(csb_size > 0);
+		ret = posix_memalign(&csb, sizeof(struct nm_csb_atok),
+		                     csb_size);
+		if (ret) {
+			printf("Failed to allocate CSB memory\n");
+			return -1;
+		}
+		memset(csb, 0, csb_size);
+
+		ctx.atok_base = (struct nm_csb_atok *)csb;
+		ctx.ktoa_base =
+		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
+	}
+
+	/* Start the kernel worker thread. */
 	ret = pthread_create(&th, NULL, kloop_worker, &ctx);
 	if (ret) {
 		printf("pthread_create() failed: %s\n", strerror(ret));
-		nm_close(ctx.nmd);
+		nm_close(nmd);
 		return -1;
 	}
 
+	/* Run the application loop. */
+	if (!strcmp(ctx.func, "tx")) {
+		while (!ACCESS_ONCE(stop)) {
+			uint16_t r;
+
+			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
+			     r++) {
+				struct netmap_ring *ring =
+				        NETMAP_TXRING(nmd->nifp, r);
+				struct nm_csb_atok *atok = ctx.atok_base + r;
+				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + r;
+				struct netmap_slot *slot;
+				uint32_t head;
+
+				head = atok->head;
+				/* For convenience we reuse the netmap_ring
+				 * header to store hwtail and hwcur, since the
+				 * cur, head and tail fields are not used. */
+				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
+							/*hwcur=*/&ring->cur);
+
+				if (head == ring->tail) {
+					continue;
+				}
+
+				slot        = ring->slot + head;
+				slot->len   = 60;
+				slot->flags = 0;
+				{
+					char *buf =
+					        NETMAP_BUF(ring, slot->buf_idx);
+					memset(buf, 0xFF, 6);
+					memset(buf + 6, 0, 6);
+					buf[12] = 0x08;
+					buf[13] = 0x00;
+					memset(buf + 14, 'x', slot->len - 14);
+				}
+				head = nm_ring_next(ring, head);
+				nm_sync_kloop_appl_write(atok, head, head);
+				printf("ring #%u, hwcur %u, head %u, hwtail "
+				       "%u\n",
+				       (unsigned int)r, ring->cur, head, ring->tail);
+			}
+			usleep(1000000);
+		}
+	}
+
+	/* Stop the kernel worker thread. */
 	{
 		struct nmreq_header hdr;
 		int ret;
@@ -204,18 +218,21 @@ main(int argc, char **argv)
 		memset(&hdr, 0, sizeof(hdr));
 		hdr.nr_version = NETMAP_API;
 		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(ctx.nmd->fd, NIOCCTRL, &hdr);
+		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
 		if (ret) {
 			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
 		}
 	}
 
+	/* Release the allocated resources. */
 	ret = pthread_join(th, NULL);
 	if (ret) {
 		printf("pthread_join() failed: %s\n", strerror(ret));
 	}
 
-	nm_close(ctx.nmd);
+	free(csb);
+
+	nm_close(nmd);
 
 	return 0;
 }

From a4189b18fe41467e79e2ed5249740e20d3f736ad Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 18:49:39 +0200
Subject: [PATCH 1191/2207] utils: sync_kloop_test: implement RX support

---
 utils/sync_kloop_test.c | 72 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 65 insertions(+), 7 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 7333a8b9b..e18459f3c 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -26,7 +26,7 @@ struct context {
 	const char *func;
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
-	size_t num_entries;
+	int verbose;
 };
 
 static void *
@@ -63,6 +63,7 @@ usage(const char *progname)
 	printf("%s\n"
 	       "[-h (show this help and exit)]\n"
 	       "[-f FUNCTION (rx,tx)]\n"
+	       "[-v (be more verbose)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -70,6 +71,9 @@ usage(const char *progname)
 int
 main(int argc, char **argv)
 {
+	int num_entries, num_tx_entries;
+	unsigned long long bytes = 0;
+	unsigned long long pkts = 0;
 	const char *ifname = NULL;
 	void *csb          = NULL;
 	struct context ctx;
@@ -92,8 +96,9 @@ main(int argc, char **argv)
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.func = "rx";
+	ctx.verbose = 0;
 
-	while ((opt = getopt(argc, argv, "hi:f:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:v")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -111,6 +116,10 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case 'v':
+			ctx.verbose ++;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -135,12 +144,13 @@ main(int argc, char **argv)
 	{
 		size_t csb_size;
 
-		ctx.num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
-		                  nmd->last_rx_ring - nmd->first_rx_ring + 1;
-		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
+		num_tx_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1;
+		num_entries = num_tx_entries +
+				nmd->last_rx_ring - nmd->first_rx_ring + 1;
+		printf("Number of CSB entries = %d\n", (int)num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
-		           ctx.num_entries;
+		           num_entries;
 		assert(csb_size > 0);
 		ret = posix_memalign(&csb, sizeof(struct nm_csb_atok),
 		                     csb_size);
@@ -152,7 +162,7 @@ main(int argc, char **argv)
 
 		ctx.atok_base = (struct nm_csb_atok *)csb;
 		ctx.ktoa_base =
-		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
+		        (struct nm_csb_ktoa *)(ctx.atok_base + num_entries);
 	}
 
 	/* Start the kernel worker thread. */
@@ -191,6 +201,8 @@ main(int argc, char **argv)
 				slot        = ring->slot + head;
 				slot->len   = 60;
 				slot->flags = 0;
+				bytes += slot->len;
+				pkts++;
 				{
 					char *buf =
 					        NETMAP_BUF(ring, slot->buf_idx);
@@ -208,6 +220,52 @@ main(int argc, char **argv)
 			}
 			usleep(1000000);
 		}
+
+	} else if (!strcmp(ctx.func, "rx")) {
+
+		while (!ACCESS_ONCE(stop)) {
+			uint16_t r;
+
+			for (r = nmd->first_rx_ring; r <= nmd->last_rx_ring;
+			     r++) {
+				struct netmap_ring *ring =
+				        NETMAP_RXRING(nmd->nifp, r);
+				struct nm_csb_atok *atok = ctx.atok_base + num_tx_entries + r;
+				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + num_tx_entries + r;
+				struct netmap_slot *slot;
+				uint32_t head;
+
+				head = atok->head;
+				/* For convenience we reuse the netmap_ring
+				 * header to store hwtail and hwcur, since the
+				 * cur, head and tail fields are not used. */
+				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
+							/*hwcur=*/&ring->cur);
+
+				if (head == ring->tail) {
+					continue;
+				}
+
+				slot        = ring->slot + head;
+				bytes += slot->len;
+				pkts++;
+				if (ctx.verbose) {
+					char *buf =
+					        NETMAP_BUF(ring, slot->buf_idx);
+					int i;
+					for (i = 0; i < slot->len; i++) {
+						printf(" %02x", (unsigned char)buf[i]);
+					}
+					printf("\n");
+				}
+				head = nm_ring_next(ring, head);
+				nm_sync_kloop_appl_write(atok, head, head);
+				printf("ring #%u, hwcur %u, head %u, hwtail "
+				       "%u\n",
+				       (unsigned int)r, ring->cur, head, ring->tail);
+			}
+			usleep(1000000);
+		}
 	}
 
 	/* Stop the kernel worker thread. */

From 6f62924b3c5b983486d0d661ec585baf2d5b7e38 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:06:42 +0200
Subject: [PATCH 1192/2207] utils: sync_kloop_test: add support for -b and -R
 parameters

---
 utils/sync_kloop_test.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index e18459f3c..a511b2bdd 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -27,6 +27,7 @@ struct context {
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int verbose;
+	unsigned batch;
 };
 
 static void *
@@ -64,6 +65,8 @@ usage(const char *progname)
 	       "[-h (show this help and exit)]\n"
 	       "[-f FUNCTION (rx,tx)]\n"
 	       "[-v (be more verbose)]\n"
+	       "[-R RATE_PPS (0 = infinite)]\n"
+	       "[-b BATCH_SIZE (in packets)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -78,6 +81,7 @@ main(int argc, char **argv)
 	void *csb          = NULL;
 	struct context ctx;
 	struct nm_desc *nmd;
+	double rate = 1.0 /* pps */;
 	pthread_t th;
 	int opt;
 	int ret;
@@ -97,8 +101,9 @@ main(int argc, char **argv)
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.func = "rx";
 	ctx.verbose = 0;
+	ctx.batch = 1;
 
-	while ((opt = getopt(argc, argv, "hi:f:v")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:vR:b:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -120,6 +125,22 @@ main(int argc, char **argv)
 			ctx.verbose ++;
 			break;
 
+		case 'R':
+			rate = atof(optarg);
+			if (rate < 0.0) {
+				printf("    Invalid rate %s\n", optarg);
+				return -1;
+			}
+			break;
+
+		case 'b':
+			ctx.batch = atoi(optarg);
+			if (ctx.batch <= 0) {
+				printf("    Invalid batch %s\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);

From 250a7fd6aed915879f42c79683dcf20a18cfc66b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:24:35 +0200
Subject: [PATCH 1193/2207] utils: sync_kloop_test: add support for batching

---
 utils/sync_kloop_test.c | 84 ++++++++++++++++++++++++++---------------
 1 file changed, 54 insertions(+), 30 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a511b2bdd..a8486a982 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -27,7 +27,7 @@ struct context {
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int verbose;
-	unsigned batch;
+	int batch;
 };
 
 static void *
@@ -58,6 +58,18 @@ kloop_worker(void *opaque)
 	return NULL;
 }
 
+inline int
+ringspace(struct netmap_ring *ring, uint32_t head)
+{
+	int space = ring->tail - head;
+
+	if (space < 0) {
+		space += ring->num_slots;
+	}
+
+	return space;
+}
+
 static void
 usage(const char *progname)
 {
@@ -207,6 +219,7 @@ main(int argc, char **argv)
 				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + r;
 				struct netmap_slot *slot;
 				uint32_t head;
+				int batch;
 
 				head = atok->head;
 				/* For convenience we reuse the netmap_ring
@@ -214,26 +227,31 @@ main(int argc, char **argv)
 				 * cur, head and tail fields are not used. */
 				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
 							/*hwcur=*/&ring->cur);
-
-				if (head == ring->tail) {
+				batch = ringspace(ring, head);
+				if (batch == 0) {
 					continue;
 				}
+				if (batch > ctx.batch) {
+					batch = ctx.batch;
+				}
 
-				slot        = ring->slot + head;
-				slot->len   = 60;
-				slot->flags = 0;
-				bytes += slot->len;
-				pkts++;
-				{
-					char *buf =
-					        NETMAP_BUF(ring, slot->buf_idx);
-					memset(buf, 0xFF, 6);
-					memset(buf + 6, 0, 6);
-					buf[12] = 0x08;
-					buf[13] = 0x00;
-					memset(buf + 14, 'x', slot->len - 14);
+				pkts += batch;
+				while (--batch >= 0) {
+					slot        = ring->slot + head;
+					slot->len   = 60;
+					slot->flags = 0;
+					bytes += slot->len;
+					{
+						char *buf =
+							NETMAP_BUF(ring, slot->buf_idx);
+						memset(buf, 0xFF, 6);
+						memset(buf + 6, 0, 6);
+						buf[12] = 0x08;
+						buf[13] = 0x00;
+						memset(buf + 14, 'x', slot->len - 14);
+					}
+					head = nm_ring_next(ring, head);
 				}
-				head = nm_ring_next(ring, head);
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",
@@ -255,6 +273,7 @@ main(int argc, char **argv)
 				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + num_tx_entries + r;
 				struct netmap_slot *slot;
 				uint32_t head;
+				int batch;
 
 				head = atok->head;
 				/* For convenience we reuse the netmap_ring
@@ -262,24 +281,29 @@ main(int argc, char **argv)
 				 * cur, head and tail fields are not used. */
 				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
 							/*hwcur=*/&ring->cur);
-
-				if (head == ring->tail) {
+				batch = ringspace(ring, head);
+				if (batch == 0) {
 					continue;
 				}
+				if (batch > ctx.batch) {
+					batch = ctx.batch;
+				}
 
-				slot        = ring->slot + head;
-				bytes += slot->len;
-				pkts++;
-				if (ctx.verbose) {
-					char *buf =
-					        NETMAP_BUF(ring, slot->buf_idx);
-					int i;
-					for (i = 0; i < slot->len; i++) {
-						printf(" %02x", (unsigned char)buf[i]);
+				pkts += batch;
+				while (--batch >= 0) {
+					slot        = ring->slot + head;
+					bytes += slot->len;
+					if (ctx.verbose) {
+						char *buf =
+							NETMAP_BUF(ring, slot->buf_idx);
+						int i;
+						for (i = 0; i < slot->len; i++) {
+							printf(" %02x", (unsigned char)buf[i]);
+						}
+						printf("\n");
 					}
-					printf("\n");
+					head = nm_ring_next(ring, head);
 				}
-				head = nm_ring_next(ring, head);
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",

From a160cf693c86a3ab70ad4e6066f8c422ebc0dfc4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:25:32 +0200
Subject: [PATCH 1194/2207] reformat

---
 utils/sync_kloop_test.c | 58 ++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a8486a982..a9c17f3b6 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -88,9 +88,9 @@ main(int argc, char **argv)
 {
 	int num_entries, num_tx_entries;
 	unsigned long long bytes = 0;
-	unsigned long long pkts = 0;
-	const char *ifname = NULL;
-	void *csb          = NULL;
+	unsigned long long pkts  = 0;
+	const char *ifname       = NULL;
+	void *csb                = NULL;
 	struct context ctx;
 	struct nm_desc *nmd;
 	double rate = 1.0 /* pps */;
@@ -111,9 +111,9 @@ main(int argc, char **argv)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.func = "rx";
+	ctx.func    = "rx";
 	ctx.verbose = 0;
-	ctx.batch = 1;
+	ctx.batch   = 1;
 
 	while ((opt = getopt(argc, argv, "hi:f:vR:b:")) != -1) {
 		switch (opt) {
@@ -134,7 +134,7 @@ main(int argc, char **argv)
 			break;
 
 		case 'v':
-			ctx.verbose ++;
+			ctx.verbose++;
 			break;
 
 		case 'R':
@@ -178,8 +178,8 @@ main(int argc, char **argv)
 		size_t csb_size;
 
 		num_tx_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1;
-		num_entries = num_tx_entries +
-				nmd->last_rx_ring - nmd->first_rx_ring + 1;
+		num_entries    = num_tx_entries + nmd->last_rx_ring -
+		              nmd->first_rx_ring + 1;
 		printf("Number of CSB entries = %d\n", (int)num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
@@ -225,8 +225,9 @@ main(int argc, char **argv)
 				/* For convenience we reuse the netmap_ring
 				 * header to store hwtail and hwcur, since the
 				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
-							/*hwcur=*/&ring->cur);
+				nm_sync_kloop_appl_read(ktoa,
+				                        /*hwtail=*/&ring->tail,
+				                        /*hwcur=*/&ring->cur);
 				batch = ringspace(ring, head);
 				if (batch == 0) {
 					continue;
@@ -242,20 +243,22 @@ main(int argc, char **argv)
 					slot->flags = 0;
 					bytes += slot->len;
 					{
-						char *buf =
-							NETMAP_BUF(ring, slot->buf_idx);
+						char *buf = NETMAP_BUF(
+						        ring, slot->buf_idx);
 						memset(buf, 0xFF, 6);
 						memset(buf + 6, 0, 6);
 						buf[12] = 0x08;
 						buf[13] = 0x00;
-						memset(buf + 14, 'x', slot->len - 14);
+						memset(buf + 14, 'x',
+						       slot->len - 14);
 					}
 					head = nm_ring_next(ring, head);
 				}
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",
-				       (unsigned int)r, ring->cur, head, ring->tail);
+				       (unsigned int)r, ring->cur, head,
+				       ring->tail);
 			}
 			usleep(1000000);
 		}
@@ -269,8 +272,10 @@ main(int argc, char **argv)
 			     r++) {
 				struct netmap_ring *ring =
 				        NETMAP_RXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok = ctx.atok_base + num_tx_entries + r;
-				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + num_tx_entries + r;
+				struct nm_csb_atok *atok =
+				        ctx.atok_base + num_tx_entries + r;
+				struct nm_csb_ktoa *ktoa =
+				        ctx.ktoa_base + num_tx_entries + r;
 				struct netmap_slot *slot;
 				uint32_t head;
 				int batch;
@@ -279,8 +284,9 @@ main(int argc, char **argv)
 				/* For convenience we reuse the netmap_ring
 				 * header to store hwtail and hwcur, since the
 				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
-							/*hwcur=*/&ring->cur);
+				nm_sync_kloop_appl_read(ktoa,
+				                        /*hwtail=*/&ring->tail,
+				                        /*hwcur=*/&ring->cur);
 				batch = ringspace(ring, head);
 				if (batch == 0) {
 					continue;
@@ -291,14 +297,17 @@ main(int argc, char **argv)
 
 				pkts += batch;
 				while (--batch >= 0) {
-					slot        = ring->slot + head;
+					slot = ring->slot + head;
 					bytes += slot->len;
 					if (ctx.verbose) {
-						char *buf =
-							NETMAP_BUF(ring, slot->buf_idx);
+						char *buf = NETMAP_BUF(
+						        ring, slot->buf_idx);
 						int i;
-						for (i = 0; i < slot->len; i++) {
-							printf(" %02x", (unsigned char)buf[i]);
+						for (i = 0; i < slot->len;
+						     i++) {
+							printf(" %02x",
+							       (unsigned char)
+							               buf[i]);
 						}
 						printf("\n");
 					}
@@ -307,7 +316,8 @@ main(int argc, char **argv)
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",
-				       (unsigned int)r, ring->cur, head, ring->tail);
+				       (unsigned int)r, ring->cur, head,
+				       ring->tail);
 			}
 			usleep(1000000);
 		}

From d4202a6d1faaa1081f25170ac762b99056d312d6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:56:42 +0200
Subject: [PATCH 1195/2207] utils: sync_kloop_test: merge TX and RX loops

---
 utils/sync_kloop_test.c | 164 +++++++++++++++++-----------------------
 1 file changed, 71 insertions(+), 93 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a9c17f3b6..1be1d461b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -23,7 +23,6 @@ sigint_handler(int signum)
 
 struct context {
 	struct nm_desc *nmd;
-	const char *func;
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int verbose;
@@ -83,21 +82,31 @@ usage(const char *progname)
 	       progname);
 }
 
+typedef enum {
+	F_TX = 0,
+	F_RX,
+} function_t;
+
 int
 main(int argc, char **argv)
 {
+	struct nm_csb_atok *atok_base = NULL;
+	struct nm_csb_ktoa *ktoa_base = NULL;
 	int num_entries, num_tx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
 	const char *ifname       = NULL;
 	void *csb                = NULL;
+	uint16_t first_ring, last_ring;
 	struct context ctx;
 	struct nm_desc *nmd;
 	double rate = 1.0 /* pps */;
+	function_t func;
 	pthread_t th;
 	int opt;
 	int ret;
 
+	/* Register a signal handler to stop the program on SIGINT. */
 	{
 		struct sigaction sa;
 
@@ -111,7 +120,7 @@ main(int argc, char **argv)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.func    = "rx";
+	func        = F_RX;
 	ctx.verbose = 0;
 	ctx.batch   = 1;
 
@@ -126,10 +135,12 @@ main(int argc, char **argv)
 			break;
 
 		case 'f':
-			ctx.func = optarg;
-			if (strcmp(optarg, "tx") && strcmp(optarg, "rx")) {
+			if (!strcmp(optarg, "tx")) {
+				func = F_TX;
+			} else if (!strcmp(optarg, "rx")) {
+				func = F_RX;
+			} else {
 				printf("    Unknown function %s\n", optarg);
-				return -1;
 			}
 			break;
 
@@ -193,8 +204,8 @@ main(int argc, char **argv)
 		}
 		memset(csb, 0, csb_size);
 
-		ctx.atok_base = (struct nm_csb_atok *)csb;
-		ctx.ktoa_base =
+		atok_base = ctx.atok_base = (struct nm_csb_atok *)csb;
+		ktoa_base                 = ctx.ktoa_base =
 		        (struct nm_csb_ktoa *)(ctx.atok_base + num_entries);
 	}
 
@@ -206,42 +217,55 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	if (func == F_RX) {
+		atok_base += num_tx_entries;
+		ktoa_base += num_tx_entries;
+		first_ring = nmd->first_rx_ring;
+		last_ring  = nmd->last_rx_ring;
+	} else {
+		first_ring = nmd->first_tx_ring;
+		last_ring  = nmd->last_tx_ring;
+	}
+
 	/* Run the application loop. */
-	if (!strcmp(ctx.func, "tx")) {
-		while (!ACCESS_ONCE(stop)) {
-			uint16_t r;
-
-			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
-			     r++) {
-				struct netmap_ring *ring =
-				        NETMAP_TXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok = ctx.atok_base + r;
-				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + r;
-				struct netmap_slot *slot;
-				uint32_t head;
-				int batch;
-
-				head = atok->head;
-				/* For convenience we reuse the netmap_ring
-				 * header to store hwtail and hwcur, since the
-				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa,
-				                        /*hwtail=*/&ring->tail,
-				                        /*hwcur=*/&ring->cur);
-				batch = ringspace(ring, head);
-				if (batch == 0) {
-					continue;
-				}
-				if (batch > ctx.batch) {
-					batch = ctx.batch;
-				}
+	while (!ACCESS_ONCE(stop)) {
+		uint16_t r;
+
+		for (r = first_ring; r <= last_ring; r++) {
+			struct nm_csb_atok *atok = atok_base + r;
+			struct nm_csb_ktoa *ktoa = ktoa_base + r;
+			struct netmap_ring *ring;
+			struct netmap_slot *slot;
+			uint32_t head;
+			int batch;
+
+			if (func == F_TX) {
+				ring = NETMAP_TXRING(nmd->nifp, r);
+			} else {
+				ring = NETMAP_RXRING(nmd->nifp, r);
+			}
 
-				pkts += batch;
-				while (--batch >= 0) {
-					slot        = ring->slot + head;
+			head = atok->head;
+			/* For convenience we reuse the netmap_ring
+			 * header to store hwtail and hwcur, since the
+			 * cur, head and tail fields are not used. */
+			nm_sync_kloop_appl_read(ktoa,
+			                        /*hwtail=*/&ring->tail,
+			                        /*hwcur=*/&ring->cur);
+			batch = ringspace(ring, head);
+			if (batch == 0) {
+				continue;
+			}
+			if (batch > ctx.batch) {
+				batch = ctx.batch;
+			}
+
+			pkts += batch;
+			while (--batch >= 0) {
+				slot = ring->slot + head;
+				if (func == F_TX) {
 					slot->len   = 60;
 					slot->flags = 0;
-					bytes += slot->len;
 					{
 						char *buf = NETMAP_BUF(
 						        ring, slot->buf_idx);
@@ -252,53 +276,7 @@ main(int argc, char **argv)
 						memset(buf + 14, 'x',
 						       slot->len - 14);
 					}
-					head = nm_ring_next(ring, head);
-				}
-				nm_sync_kloop_appl_write(atok, head, head);
-				printf("ring #%u, hwcur %u, head %u, hwtail "
-				       "%u\n",
-				       (unsigned int)r, ring->cur, head,
-				       ring->tail);
-			}
-			usleep(1000000);
-		}
-
-	} else if (!strcmp(ctx.func, "rx")) {
-
-		while (!ACCESS_ONCE(stop)) {
-			uint16_t r;
-
-			for (r = nmd->first_rx_ring; r <= nmd->last_rx_ring;
-			     r++) {
-				struct netmap_ring *ring =
-				        NETMAP_RXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok =
-				        ctx.atok_base + num_tx_entries + r;
-				struct nm_csb_ktoa *ktoa =
-				        ctx.ktoa_base + num_tx_entries + r;
-				struct netmap_slot *slot;
-				uint32_t head;
-				int batch;
-
-				head = atok->head;
-				/* For convenience we reuse the netmap_ring
-				 * header to store hwtail and hwcur, since the
-				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa,
-				                        /*hwtail=*/&ring->tail,
-				                        /*hwcur=*/&ring->cur);
-				batch = ringspace(ring, head);
-				if (batch == 0) {
-					continue;
-				}
-				if (batch > ctx.batch) {
-					batch = ctx.batch;
-				}
-
-				pkts += batch;
-				while (--batch >= 0) {
-					slot = ring->slot + head;
-					bytes += slot->len;
+				} else {
 					if (ctx.verbose) {
 						char *buf = NETMAP_BUF(
 						        ring, slot->buf_idx);
@@ -311,16 +289,16 @@ main(int argc, char **argv)
 						}
 						printf("\n");
 					}
-					head = nm_ring_next(ring, head);
 				}
-				nm_sync_kloop_appl_write(atok, head, head);
-				printf("ring #%u, hwcur %u, head %u, hwtail "
-				       "%u\n",
-				       (unsigned int)r, ring->cur, head,
-				       ring->tail);
+				bytes += slot->len;
+				head = nm_ring_next(ring, head);
 			}
-			usleep(1000000);
+			nm_sync_kloop_appl_write(atok, head, head);
+			printf("ring #%u, hwcur %u, head %u, hwtail "
+			       "%u\n",
+			       (unsigned int)r, ring->cur, head, ring->tail);
 		}
+		usleep(1000000);
 	}
 
 	/* Stop the kernel worker thread. */

From f5b39dc204c0cc5e8f53f1bb5b187f78942df7e7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 23:00:16 +0200
Subject: [PATCH 1196/2207] utils: sync_kloop_test: add support for rate
 limiting

---
 utils/sync_kloop_test.c | 48 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 1be1d461b..f6d71c7ef 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -9,6 +9,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
 
@@ -100,7 +102,13 @@ main(int argc, char **argv)
 	uint16_t first_ring, last_ring;
 	struct context ctx;
 	struct nm_desc *nmd;
-	double rate = 1.0 /* pps */;
+
+	double rate                = 1.0 /* pps */;
+	unsigned int period_us     = 0;
+	unsigned int period_budget = 0;
+	struct timeval next_time;
+	int packet_budget;
+
 	function_t func;
 	pthread_t th;
 	int opt;
@@ -217,6 +225,20 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	/* Compute variables for rate limiting. */
+	if (rate != 0.0) {
+		double us = 1000000.0 / rate;
+		double b  = 1.0;
+		if (us < 50.0) {
+			b = ceil(50.0 / us);
+			us *= b;
+		}
+		period_us     = (unsigned int)us;
+		period_budget = (unsigned int)b;
+	}
+#if 0
+	printf("period us %u batch %u\n", period_us, period_budget);
+#endif
 	if (func == F_RX) {
 		atok_base += num_tx_entries;
 		ktoa_base += num_tx_entries;
@@ -227,10 +249,29 @@ main(int argc, char **argv)
 		last_ring  = nmd->last_tx_ring;
 	}
 
+	gettimeofday(&next_time, NULL);
+	packet_budget = 0;
+
 	/* Run the application loop. */
 	while (!ACCESS_ONCE(stop)) {
 		uint16_t r;
 
+		if (period_us != 0) {
+			struct timeval now, diff;
+
+			next_time.tv_usec += period_us;
+			if (next_time.tv_usec > 1000000) {
+				next_time.tv_usec -= 1000000;
+				next_time.tv_sec++;
+			}
+			packet_budget = period_budget;
+			gettimeofday(&now, NULL);
+			timersub(&next_time, &now, &diff);
+			usleep(diff.tv_usec);
+		} else {
+			packet_budget = 0xfffffff; /* infinite */
+		}
+
 		for (r = first_ring; r <= last_ring; r++) {
 			struct nm_csb_atok *atok = atok_base + r;
 			struct nm_csb_ktoa *ktoa = ktoa_base + r;
@@ -253,6 +294,9 @@ main(int argc, char **argv)
 			                        /*hwtail=*/&ring->tail,
 			                        /*hwcur=*/&ring->cur);
 			batch = ringspace(ring, head);
+			if (batch > packet_budget) { /* rate limiting */
+				batch = packet_budget;
+			}
 			if (batch == 0) {
 				continue;
 			}
@@ -261,6 +305,7 @@ main(int argc, char **argv)
 			}
 
 			pkts += batch;
+			packet_budget -= batch;
 			while (--batch >= 0) {
 				slot = ring->slot + head;
 				if (func == F_TX) {
@@ -298,7 +343,6 @@ main(int argc, char **argv)
 			       "%u\n",
 			       (unsigned int)r, ring->cur, head, ring->tail);
 		}
-		usleep(1000000);
 	}
 
 	/* Stop the kernel worker thread. */

From 236f0c42a3a505f34c1bf8138197841475aa8067 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 11:59:27 +0200
Subject: [PATCH 1197/2207] utils: sync_kloop_test: stop initializing packets
 after a while

---
 utils/sync_kloop_test.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index f6d71c7ef..df810e9f7 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -109,6 +109,7 @@ main(int argc, char **argv)
 	struct timeval next_time;
 	int packet_budget;
 
+	int init_tx_payload = 1;
 	function_t func;
 	pthread_t th;
 	int opt;
@@ -309,9 +310,9 @@ main(int argc, char **argv)
 			while (--batch >= 0) {
 				slot = ring->slot + head;
 				if (func == F_TX) {
-					slot->len   = 60;
-					slot->flags = 0;
-					{
+					slot->len = 60;
+					if ((slot->flags & NS_BUF_CHANGED) ||
+					    init_tx_payload) {
 						char *buf = NETMAP_BUF(
 						        ring, slot->buf_idx);
 						memset(buf, 0xFF, 6);
@@ -320,7 +321,17 @@ main(int argc, char **argv)
 						buf[13] = 0x00;
 						memset(buf + 14, 'x',
 						       slot->len - 14);
+						/* Drop the copy once we are
+						 * confident that we have filled
+						 * all the buffers in the TX
+						 * ring. */
+						if (pkts > 20000) {
+							printf("Stop to init "
+							       "packets\n");
+							init_tx_payload = 0;
+						}
 					}
+					slot->flags = 0;
 				} else {
 					if (ctx.verbose) {
 						char *buf = NETMAP_BUF(
@@ -339,9 +350,12 @@ main(int argc, char **argv)
 				head = nm_ring_next(ring, head);
 			}
 			nm_sync_kloop_appl_write(atok, head, head);
-			printf("ring #%u, hwcur %u, head %u, hwtail "
-			       "%u\n",
-			       (unsigned int)r, ring->cur, head, ring->tail);
+			if (ctx.verbose) {
+				printf("ring #%u, hwcur %u, head %u, hwtail "
+				       "%u\n",
+				       (unsigned int)r, ring->cur, head,
+				       ring->tail);
+			}
 		}
 	}
 

From ec104115b887793ca97040cf5c5c685eb5f78cf3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 12:21:43 +0200
Subject: [PATCH 1198/2207] utils: sync_kloop_test: fix bug in the rate
 limiting code

---
 utils/sync_kloop_test.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index df810e9f7..a05218620 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -267,8 +267,12 @@ main(int argc, char **argv)
 			}
 			packet_budget = period_budget;
 			gettimeofday(&now, NULL);
-			timersub(&next_time, &now, &diff);
-			usleep(diff.tv_usec);
+			/* if now < next_time ... */
+			if (timercmp(&now, &next_time, <)) {
+				/* diff = next_time - now */
+				timersub(&next_time, &now, &diff);
+				usleep(diff.tv_usec);
+			}
 		} else {
 			packet_budget = 0xfffffff; /* infinite */
 		}

From ee8299d58751873450abdb59768b0cde4677481d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 12:30:55 +0200
Subject: [PATCH 1199/2207] utils: sync_kloop_test: add busy-wait mode

---
 utils/sync_kloop_test.c | 36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a05218620..025adc000 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -230,12 +230,14 @@ main(int argc, char **argv)
 	if (rate != 0.0) {
 		double us = 1000000.0 / rate;
 		double b  = 1.0;
-		if (us < 50.0) {
-			b = ceil(50.0 / us);
+#define MIN_USLEEP 50.0
+		if (us < MIN_USLEEP) {
+			b = ceil(MIN_USLEEP / us);
 			us *= b;
 		}
 		period_us     = (unsigned int)us;
 		period_budget = (unsigned int)b;
+#undef MIN_USLEEP
 	}
 #if 0
 	printf("period us %u batch %u\n", period_us, period_budget);
@@ -257,7 +259,9 @@ main(int argc, char **argv)
 	while (!ACCESS_ONCE(stop)) {
 		uint16_t r;
 
-		if (period_us != 0) {
+		if (period_us == 0) {
+			packet_budget = 0xfffffff; /* infinite */
+		} else {
 			struct timeval now, diff;
 
 			next_time.tv_usec += period_us;
@@ -266,15 +270,25 @@ main(int argc, char **argv)
 				next_time.tv_sec++;
 			}
 			packet_budget = period_budget;
-			gettimeofday(&now, NULL);
-			/* if now < next_time ... */
-			if (timercmp(&now, &next_time, <)) {
-				/* diff = next_time - now */
-				timersub(&next_time, &now, &diff);
-				usleep(diff.tv_usec);
+			if (period_budget > 1) {
+				/* Busy wait. */
+				for (;;) {
+					gettimeofday(&now, NULL);
+					/* if now >= next_time */
+					if (!timercmp(&now, &next_time, <)) {
+						break;
+					}
+				}
+			} else {
+				/* Sleep. */
+				gettimeofday(&now, NULL);
+				/* if now < next_time ... */
+				if (timercmp(&now, &next_time, <)) {
+					/* diff = next_time - now */
+					timersub(&next_time, &now, &diff);
+					usleep(diff.tv_usec);
+				}
 			}
-		} else {
-			packet_budget = 0xfffffff; /* infinite */
 		}
 
 		for (r = first_ring; r <= last_ring; r++) {

From d83fba0eb5d72fb8970e96308eb4d74e87c80ffe Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 12:40:11 +0200
Subject: [PATCH 1200/2207] utils: sync_kloop_test: measure average rate

---
 utils/sync_kloop_test.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 025adc000..efc78d13b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -103,11 +103,12 @@ main(int argc, char **argv)
 	struct context ctx;
 	struct nm_desc *nmd;
 
-	double rate                = 1.0 /* pps */;
+	double target_rate         = 1.0 /* pps */;
 	unsigned int period_us     = 0;
 	unsigned int period_budget = 0;
 	struct timeval next_time;
 	int packet_budget;
+	struct timeval loop_begin, loop_end;
 
 	int init_tx_payload = 1;
 	function_t func;
@@ -158,8 +159,8 @@ main(int argc, char **argv)
 			break;
 
 		case 'R':
-			rate = atof(optarg);
-			if (rate < 0.0) {
+			target_rate = atof(optarg);
+			if (target_rate < 0.0) {
 				printf("    Invalid rate %s\n", optarg);
 				return -1;
 			}
@@ -227,8 +228,8 @@ main(int argc, char **argv)
 	}
 
 	/* Compute variables for rate limiting. */
-	if (rate != 0.0) {
-		double us = 1000000.0 / rate;
+	if (target_rate != 0.0) {
+		double us = 1000000.0 / target_rate;
 		double b  = 1.0;
 #define MIN_USLEEP 50.0
 		if (us < MIN_USLEEP) {
@@ -253,6 +254,7 @@ main(int argc, char **argv)
 	}
 
 	gettimeofday(&next_time, NULL);
+	loop_begin    = next_time;
 	packet_budget = 0;
 
 	/* Run the application loop. */
@@ -377,6 +379,19 @@ main(int argc, char **argv)
 		}
 	}
 
+	/* Measure average rate. */
+	gettimeofday(&loop_end, NULL);
+	{
+		struct timeval duration;
+		unsigned long udiff;
+		double measured_rate;
+
+		timersub(&loop_end, &loop_begin, &duration);
+		udiff         = duration.tv_sec * 1000000 + duration.tv_usec;
+		measured_rate = (double)pkts / (double)udiff;
+		printf("Measured rate: %.6f Mpps\n", measured_rate);
+	}
+
 	/* Stop the kernel worker thread. */
 	{
 		struct nmreq_header hdr;

From 6d2b72c96655d8f8779eb0d25eab11ea8fe2707e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 15:40:37 +0200
Subject: [PATCH 1201/2207] sync-kloop: allow user-specified sleep interval

---
 sys/dev/netmap/netmap.c | 11 ++++++++---
 sys/net/netmap.h        |  4 ++++
 utils/ctrl-api-test.c   |  1 +
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4b9c5fab2..aa5ff2714 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4225,12 +4225,18 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
+	uint32_t sleep_us = req->sleep_us;
 	struct nm_csb_atok* csb_atok_base;
 	struct nm_csb_ktoa* csb_ktoa_base;
 	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
 	int err = 0;
 
+	if (sleep_us > 1000000) {
+		/* We do not accept sleeping for more than a second. */
+		return EINVAL;
+	}
+
 	if (priv->np_nifp == NULL) {
 		return ENXIO;
 	}
@@ -4337,9 +4343,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
-		/* TODO replace with proper notifications and/or configurable
-		 * sleep interval. */
-		usleep_range(2000, 2000);
+		/* Default synchronization method: sleep for a while. */
+		usleep_range(sleep_us, sleep_us);
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a48110728..aa31f521b 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -714,6 +714,10 @@ struct nmreq_sync_kloop_start {
 	uint64_t csb_atok;
 	/* CSB for kernel --> application communication (N entries). */
 	uint64_t csb_ktoa;
+	/* Sleeping is the default synchronization method for the kloop.
+	 * The 'sleep_us' field specifies how many microsconds to sleep
+	 * waiting for more work to come. */
+	uint32_t sleep_us;
 };
 
 struct nm_csb_atok {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5d72bbbcc..763618706 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -847,6 +847,7 @@ sync_kloop_worker(void *opaque)
 	req.csb_atok = (uintptr_t)csb;
 	req.csb_ktoa =
 	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
+	req.sleep_us = 500;
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");

From 040e5ca2f2a177be72b0ff5d73e360b95842b6ed Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 16:09:51 +0200
Subject: [PATCH 1202/2207] utils: sync_kloop_test: add support for -u option

---
 utils/sync_kloop_test.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index efc78d13b..a26a660f8 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -27,6 +27,7 @@ struct context {
 	struct nm_desc *nmd;
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
+	int sleep_us;
 	int verbose;
 	int batch;
 };
@@ -50,6 +51,7 @@ kloop_worker(void *opaque)
 	memset(&req, 0, sizeof(req));
 	req.csb_atok = (uintptr_t)ctx->atok_base;
 	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
+	req.sleep_us = (uint32_t)ctx->sleep_us;
 	ret          = ioctl(nmd->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
@@ -80,6 +82,7 @@ usage(const char *progname)
 	       "[-v (be more verbose)]\n"
 	       "[-R RATE_PPS (0 = infinite)]\n"
 	       "[-b BATCH_SIZE (in packets)]\n"
+	       "[-u KLOOP_SLEEP_US (in microseconds)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -133,8 +136,9 @@ main(int argc, char **argv)
 	func        = F_RX;
 	ctx.verbose = 0;
 	ctx.batch   = 1;
+	ctx.sleep_us = 500;
 
-	while ((opt = getopt(argc, argv, "hi:f:vR:b:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -174,6 +178,14 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case 'u':
+			ctx.sleep_us = atoi(optarg);
+			if (ctx.sleep_us < 0) {
+				printf("    Invalid sleep_us %s\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);

From 0df5559e0426d7b63cd371b147b733bc57442792 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 18:04:10 +0200
Subject: [PATCH 1203/2207] sync-kloop: require NR_EXCLUSIVE to be set

---
 sys/dev/netmap/netmap.c |  5 +++++
 utils/ctrl-api-test.c   | 32 ++++++++++++++++++++------------
 utils/sync_kloop_test.c | 22 ++++++++++++++--------
 3 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index aa5ff2714..c369077c0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4247,6 +4247,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	if (!(priv->np_flags & NR_EXCLUSIVE)) {
+		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
+		return EINVAL;
+	}
+
 	/* Make sure that no kloop is currently running. */
 	NMG_LOCK();
 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 763618706..50ddfcfda 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -828,7 +828,7 @@ sync_kloop_worker(void *opaque)
 	int ret;
 
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	             num_entries;
+	           num_entries;
 	assert(csb_size > 0);
 	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
 	if (ret) {
@@ -837,7 +837,7 @@ sync_kloop_worker(void *opaque)
 	}
 
 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
-		(unsigned)csb_size, ctx->ifname);
+	       (unsigned)csb_size, ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
@@ -848,7 +848,7 @@ sync_kloop_worker(void *opaque)
 	req.csb_ktoa =
 	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
 	req.sleep_us = 500;
-	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
@@ -860,10 +860,12 @@ sync_kloop_worker(void *opaque)
 static int
 sync_kloop(struct TestContext *ctx)
 {
-	int ret = port_register_hwall(ctx);
+	int ret;
 	pthread_t th;
 	int thret;
 
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -890,10 +892,12 @@ sync_kloop(struct TestContext *ctx)
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
-	int ret = port_register_hwall(ctx);
+	int ret;
 	pthread_t th1, th2;
 	int thret1, thret2;
 
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -910,8 +914,8 @@ sync_kloop_conflict(struct TestContext *ctx)
 		return -1;
 	}
 
-	/* Try to avoid a race condition where th1 starts the loop and stops, and
-	 * after that th2 starts the loop successfully. */
+	/* Try to avoid a race condition where th1 starts the loop and stops,
+	 * and after that th2 starts the loop successfully. */
 	usleep(500000);
 
 	ret = sync_kloop_stop(ctx);
@@ -930,17 +934,21 @@ sync_kloop_conflict(struct TestContext *ctx)
 	}
 
 	/* Check that one of the two failed, while the other one succeeded. */
-	return ((thret1 == 0 && thret2 != 0) ||
-		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
+	return ((thret1 == 0 && thret2 != 0) || (thret1 != 0 && thret2 == 0))
+	               ? 0
+	               : -1;
 }
 
 static int
 sync_kloop_invalid_csb(struct TestContext *ctx)
 {
-	int ret = port_register_hwall(ctx);
+	int ret;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+
 	/* Post a stop request first. */
 	ret = sync_kloop_stop(ctx);
 	if (ret) {
@@ -953,7 +961,7 @@ sync_kloop_invalid_csb(struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.csb_atok = (uintptr_t)0x10;
 	req.csb_ktoa = (uintptr_t)0x800;
-	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
@@ -1076,7 +1084,7 @@ main(int argc, char **argv)
 		}
 		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
 		ctxcopy.fd = fd;
-		ret = tests[i].test(&ctxcopy);
+		ret        = tests[i].test(&ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 			goto out;
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a26a660f8..98a6b86b0 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -133,9 +133,9 @@ main(int argc, char **argv)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	func        = F_RX;
-	ctx.verbose = 0;
-	ctx.batch   = 1;
+	func         = F_RX;
+	ctx.verbose  = 0;
+	ctx.batch    = 1;
 	ctx.sleep_us = 500;
 
 	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:")) != -1) {
@@ -199,11 +199,17 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	/* Open the netmap port. */
-	ctx.nmd = nmd = nm_open(ifname, NULL, 0, NULL);
-	if (!nmd) {
-		printf("nm_open(%s) failed\n", ifname);
-		return -1;
+	{
+		/* Open the netmap port with NR_EXCLUSIVE. */
+		struct nmreq nmr;
+
+		memset(&nmr, 0, sizeof(nmr));
+		nmr.nr_flags = NR_EXCLUSIVE;
+		ctx.nmd = nmd = nm_open(ifname, &nmr, 0, NULL);
+		if (!nmd) {
+			printf("nm_open(%s) failed\n", ifname);
+			return -1;
+		}
 	}
 
 	/* Allocate CSB entries. */

From 14ff04f75917c759800f60c656e68feee17fddb4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 12 Oct 2018 12:02:57 +0200
Subject: [PATCH 1204/2207] netmap_kern: update comment

---
 sys/dev/netmap/netmap_kern.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 74de1c6bd..f710412c3 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -716,9 +716,9 @@ struct netmap_adapter {
 	u_int num_tx_desc;  /* number of descriptor in each queue */
 	u_int num_rx_desc;
 
-	/* tx_rings and rx_rings are private but allocated
-	 * as a contiguous chunk of memory. Each array has
-	 * N+1 entries, for the adapter queues and for the host queue.
+	/* tx_rings and rx_rings are private but allocated as a
+	 * contiguous chunk of memory. Each array has N+K entries,
+	 * N for the hardware rings and K for the host rings.
 	 */
 	struct netmap_kring **tx_rings; /* array of TX rings. */
 	struct netmap_kring **rx_rings; /* array of RX rings. */

From 448c8717e73421e366e050ff025e6a99fb38cd0d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Oct 2018 16:54:20 +0200
Subject: [PATCH 1205/2207] sync-kloop: add support for poll-like wait scheme

---
 LINUX/netmap_linux.c         |  1 +
 sys/dev/netmap/netmap.c      | 77 +++++++++++++++++++++++++++++++++++-
 sys/dev/netmap/netmap_kern.h |  3 ++
 3 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e7b8ddf07..4aa2efaf9 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1438,6 +1438,7 @@ linux_netmap_open(struct inode *inode, struct file *file)
 		error = -ENOMEM;
 		goto out;
 	}
+	priv->filp = file;
 	file->private_data = priv;
 out:
 	NMG_UNLOCK();
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c369077c0..d0029dc9e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4222,6 +4222,40 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	}
 }
 
+//#define SYNC_KLOOP_POLL
+#ifdef SYNC_KLOOP_POLL
+struct sync_kloop_poll_entry {
+	wait_queue_entry_t wait;
+	wait_queue_head_t *wqh;
+};
+
+struct sync_kloop_poll_ctx {
+	struct netmap_priv_d *priv;
+	NM_SELINFO_T *si[NR_TXRX];
+	poll_table wait_table;
+	unsigned int next_entry;
+	unsigned int num_entries;
+	struct sync_kloop_poll_entry entries[4];
+};
+
+static void
+sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
+				poll_table *pt)
+{
+	struct sync_kloop_poll_ctx *ctx = container_of(pt, struct sync_kloop_poll_ctx,
+							wait_table);
+	struct sync_kloop_poll_entry *entry = ctx->entries + ctx->next_entry;
+
+	BUG_ON(ctx->next_entry >= ctx->num_entries);
+	entry->wqh = wqh;
+	/* Use the default wake up function. */
+	init_waitqueue_entry(&entry->wait, current);
+	add_wait_queue(wqh, &entry->wait);
+	ctx->next_entry++;
+	nm_prinf("POLL ENTRY %d FILLED\n", ctx->next_entry);
+}
+#endif  /* SYNC_KLOOP_POLL */
+
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
@@ -4230,8 +4264,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	struct nm_csb_ktoa* csb_ktoa_base;
 	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
+	unsigned int i;
 	int err = 0;
 
+#ifdef SYNC_KLOOP_POLL
+	struct sync_kloop_poll_ctx ctx;
+#endif  /* SYNC_KLOOP_POLL */
+
 	if (sleep_us > 1000000) {
 		/* We do not accept sleeping for more than a second. */
 		return EINVAL;
@@ -4275,7 +4314,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		if (num_entries > 0) {
 			size_t entry_size[2];
 			void *csb_start[2];
-			unsigned int i;
 
 			entry_size[0] = sizeof(*csb_atok_base);
 			entry_size[1] = sizeof(*csb_ktoa_base);
@@ -4316,9 +4354,25 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
+#ifdef SYNC_KLOOP_POLL
+	memset(&ctx, 0, sizeof(ctx));
+	init_poll_funcptr(&ctx.wait_table, sync_kloop_poll_table_queue_proc);
+	ctx.num_entries = sizeof(ctx.entries)/sizeof(ctx.entries[0]);
+	ctx.next_entry = 0;
+	ctx.priv = priv;
+	ctx.si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+	ctx.si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+	poll_wait(priv->filp, ctx.si[NR_RX], &ctx.wait_table);
+	poll_wait(priv->filp, ctx.si[NR_TX], &ctx.wait_table);
+#endif  /* SYNC_KLOOP_POLL */
+
 	/* Main loop. */
 	for (;;) {
-		unsigned int i;
+#ifdef SYNC_KLOOP_POLL
+		__set_current_state(TASK_INTERRUPTIBLE);
+#endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
@@ -4348,14 +4402,33 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
+#ifdef SYNC_KLOOP_POLL
+		{
+			long remt;
+
+			nm_prinf("about to sleep\n");
+			remt = schedule_timeout_interruptible(msecs_to_jiffies(3000));
+			nm_prinf("woken up (%ld)\n", remt);
+		}
+#else  /* SYNC_KLOOP_POLL */
 		/* Default synchronization method: sleep for a while. */
 		usleep_range(sleep_us, sleep_us);
+#endif /* SYNC_KLOOP_POLL */
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
 		}
 	}
 
+#ifdef SYNC_KLOOP_POLL
+	__set_current_state(TASK_RUNNING);
+	for (i = 0; i < ctx.next_entry; i++) {
+		struct sync_kloop_poll_entry *entry = ctx.entries + i;
+
+		remove_wait_queue(entry->wqh, &entry->wait);
+	}
+#endif /* SYNC_KLOOP_POLL */
+
 	/* Reset the kloop state. */
 	NMG_LOCK();
 	priv->np_kloop_state = 0;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0e95f7592..e4dca1c48 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1881,6 +1881,9 @@ struct netmap_priv_d {
 	 */
 	NM_SELINFO_T *np_si[NR_TXRX];
 	struct thread	*np_td;		/* kqueue, just debugging */
+#ifdef linux
+	struct file	*filp;  /* used by sync kloop */
+#endif /* linux */
 };
 
 struct netmap_priv_d *netmap_priv_new(void);

From 6ac8851e752e2344da881ce9633121dcbf53fe0d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Oct 2018 17:50:52 +0200
Subject: [PATCH 1206/2207] sync-kloop: discard
 schedule_interruptible_timeout() return value

---
 sys/dev/netmap/netmap.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d0029dc9e..c96dc10d2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4252,7 +4252,7 @@ sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 	init_waitqueue_entry(&entry->wait, current);
 	add_wait_queue(wqh, &entry->wait);
 	ctx->next_entry++;
-	nm_prinf("POLL ENTRY %d FILLED\n", ctx->next_entry);
+	nm_prinf("poll entry #%d filled\n", ctx->next_entry);
 }
 #endif  /* SYNC_KLOOP_POLL */
 
@@ -4403,13 +4403,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		{
-			long remt;
-
-			nm_prinf("about to sleep\n");
-			remt = schedule_timeout_interruptible(msecs_to_jiffies(3000));
-			nm_prinf("woken up (%ld)\n", remt);
-		}
+		schedule_timeout_interruptible(msecs_to_jiffies(1000));
 #else  /* SYNC_KLOOP_POLL */
 		/* Default synchronization method: sleep for a while. */
 		usleep_range(sleep_us, sleep_us);

From 6952cc9374a9978ef01e334421706bcb70507908 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Oct 2018 17:55:41 +0200
Subject: [PATCH 1207/2207] utils: sync_kloop_test: infinite rate as default

---
 utils/sync_kloop_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 98a6b86b0..7247a6a5d 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -106,7 +106,7 @@ main(int argc, char **argv)
 	struct context ctx;
 	struct nm_desc *nmd;
 
-	double target_rate         = 1.0 /* pps */;
+	double target_rate         = 0.0 /* pps */;
 	unsigned int period_us     = 0;
 	unsigned int period_budget = 0;
 	struct timeval next_time;

From eb1bd314a001a2cc7fbdf716fde1e6f08cbd9a83 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 11:30:06 +0200
Subject: [PATCH 1208/2207] sync-kloop: add option to pass eventfds for
 notifications

---
 LINUX/netmap_linux.c         |   2 +-
 sys/dev/netmap/netmap.c      | 170 ++++++++++++++++++++++++-----------
 sys/dev/netmap/netmap_kern.h |   4 +-
 sys/net/netmap.h             |  18 ++++
 4 files changed, 139 insertions(+), 55 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4aa2efaf9..0b354e903 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1438,7 +1438,7 @@ linux_netmap_open(struct inode *inode, struct file *file)
 		error = -ENOMEM;
 		goto out;
 	}
-	priv->filp = file;
+	priv->np_filp = file;
 	file->private_data = priv;
 out:
 	NMG_UNLOCK();
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c96dc10d2..724a912de 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2629,9 +2629,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_START: {
-			struct nmreq_sync_kloop_start *req =
-				(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
-			error = netmap_sync_kloop(priv, req);
+			error = netmap_sync_kloop(priv, hdr);
 			break;
 		}
 
@@ -2765,7 +2763,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 }
 
 static size_t
-nmreq_opt_size_by_type(uint16_t nro_reqtype)
+nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 {
 	size_t rv = sizeof(struct nmreq_option);
 #ifdef NETMAP_REQ_OPT_DEBUG
@@ -2778,6 +2776,10 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 		rv = sizeof(struct nmreq_opt_extmem);
 		break;
 #endif /* WITH_EXTMEM */
+	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
+		if (nro_size >= rv)
+			rv = nro_size;
+		break;
 	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
@@ -2824,7 +2826,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		if (error)
 			goto out_err;
 		optsz += sizeof(*src);
-		optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
+		optsz += nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
 		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
 			error = EMSGSIZE;
 			goto out_err;
@@ -2878,7 +2880,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		p = (char *)(opt + 1);
 
 		/* copy the option body */
-		optsz = nmreq_opt_size_by_type(opt->nro_reqtype);
+		optsz = nmreq_opt_size_by_type(opt->nro_reqtype,
+						opt->nro_size);
 		if (optsz) {
 			/* the option body follows the option header */
 			error = copyin(src + 1, p, optsz);
@@ -2952,7 +2955,8 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 
 		/* copy the option body only if there was no error */
 		if (!rerror && !src->nro_status) {
-			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+			optsz = nmreq_opt_size_by_type(src->nro_reqtype,
+							src->nro_size);
 			if (optsz) {
 				error = copyout(src + 1, dst + 1, optsz);
 				if (error) {
@@ -4224,52 +4228,58 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 //#define SYNC_KLOOP_POLL
 #ifdef SYNC_KLOOP_POLL
+#include 
 struct sync_kloop_poll_entry {
+	struct file *filp;
 	wait_queue_entry_t wait;
 	wait_queue_head_t *wqh;
 };
 
 struct sync_kloop_poll_ctx {
-	struct netmap_priv_d *priv;
 	NM_SELINFO_T *si[NR_TXRX];
 	poll_table wait_table;
 	unsigned int next_entry;
 	unsigned int num_entries;
-	struct sync_kloop_poll_entry entries[4];
+	struct sync_kloop_poll_entry entries[0];
 };
 
 static void
 sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 				poll_table *pt)
 {
-	struct sync_kloop_poll_ctx *ctx = container_of(pt, struct sync_kloop_poll_ctx,
-							wait_table);
-	struct sync_kloop_poll_entry *entry = ctx->entries + ctx->next_entry;
+	struct sync_kloop_poll_ctx *poll_ctx =
+		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
+	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
+						poll_ctx->next_entry;
 
-	BUG_ON(ctx->next_entry >= ctx->num_entries);
+	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
 	entry->wqh = wqh;
+	entry->filp = file;
 	/* Use the default wake up function. */
 	init_waitqueue_entry(&entry->wait, current);
 	add_wait_queue(wqh, &entry->wait);
-	ctx->next_entry++;
-	nm_prinf("poll entry #%d filled\n", ctx->next_entry);
+	poll_ctx->next_entry++;
+	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
 }
 #endif  /* SYNC_KLOOP_POLL */
 
 int
-netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
+netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 {
+	struct nmreq_sync_kloop_start *req =
+		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
+	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
+#ifdef SYNC_KLOOP_POLL
+	struct sync_kloop_poll_ctx *poll_ctx = NULL;
+#endif  /* SYNC_KLOOP_POLL */
+	int num_rx_rings, num_tx_rings, num_rings;
 	uint32_t sleep_us = req->sleep_us;
 	struct nm_csb_atok* csb_atok_base;
 	struct nm_csb_ktoa* csb_ktoa_base;
-	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
-	unsigned int i;
+	struct nmreq_option *opt;
 	int err = 0;
-
-#ifdef SYNC_KLOOP_POLL
-	struct sync_kloop_poll_ctx ctx;
-#endif  /* SYNC_KLOOP_POLL */
+	int i;
 
 	if (sleep_us > 1000000) {
 		/* We do not accept sleeping for more than a second. */
@@ -4306,12 +4316,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
 	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
 	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+	num_rings = num_tx_rings + num_rx_rings;
 
 	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
-		int num_entries = num_rx_rings + num_tx_rings;
-
-		if (num_entries > 0) {
+		if (num_rings > 0) {
 			size_t entry_size[2];
 			void *csb_start[2];
 
@@ -4325,17 +4334,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 				 * the validation. However, the advantage of
 				 * this approach is that it works also on
 				 * FreeBSD. */
-				size_t csb_size = num_entries * entry_size[i];
+				size_t csb_size = num_rings * entry_size[i];
 				void *tmp;
 
 				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
 					nm_prerr("Unaligned CSB address\n");
-					return EINVAL;
+					err = EINVAL;
+					goto out;
 				}
 
 				tmp = nm_os_malloc(csb_size);
 				if (!tmp) {
-					return ENOMEM;
+					err = ENOMEM;
+					goto out;
 				}
 				if (i == 0) {
 					/* Application --> kernel direction. */
@@ -4348,30 +4359,72 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 				nm_os_free(tmp);
 				if (err) {
 					nm_prerr("Invalid CSB address\n");
-					return err;
+					goto out;
 				}
 			}
 		}
 	}
 
+	/* Validate notification options. */
+	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
+	if (opt != NULL) {
+		err = nmreq_checkduplicate(opt);
+		if (err) {
+			opt->nro_status = err;
+			goto out;
+		}
+		if (opt->nro_size != sizeof(*eventfds_opt) +
+			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
+			/* Option size not consistent with the number of
+			 * entries. */
+			opt->nro_status = err = EINVAL;
+			goto out;
+		}
 #ifdef SYNC_KLOOP_POLL
-	memset(&ctx, 0, sizeof(ctx));
-	init_poll_funcptr(&ctx.wait_table, sync_kloop_poll_table_queue_proc);
-	ctx.num_entries = sizeof(ctx.entries)/sizeof(ctx.entries[0]);
-	ctx.next_entry = 0;
-	ctx.priv = priv;
-	ctx.si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-	ctx.si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-	poll_wait(priv->filp, ctx.si[NR_RX], &ctx.wait_table);
-	poll_wait(priv->filp, ctx.si[NR_TX], &ctx.wait_table);
+		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
+		opt->nro_status = 0;
+		/* We need 2 poll entries for TX and RX notifications coming
+		 * from the netmap adapter, plus one entries per ring for the
+		 * notifications coming from the application. */
+		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
+				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
+		init_poll_funcptr(&poll_ctx->wait_table,
+					sync_kloop_poll_table_queue_proc);
+		poll_ctx->num_entries = 2 + num_rings;
+		poll_ctx->next_entry = 0;
+		poll_ctx->si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+		poll_ctx->si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		poll_wait(priv->np_filp, poll_ctx->si[NR_RX], &poll_ctx->wait_table);
+		poll_wait(priv->np_filp, poll_ctx->si[NR_TX], &poll_ctx->wait_table);
+		for (i = 0; i < num_rings; i++) {
+			struct file *filp;
+			unsigned long mask;
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
+			if (mask & POLLERR) {
+				err = EINVAL;
+				goto out;
+			}
+		}
+#else   /* SYNC_KLOOP_POLL */
+		opt->nro_status = EOPNOTSUPP;
+		goto out;
 #endif  /* SYNC_KLOOP_POLL */
+	}
 
 	/* Main loop. */
 	for (;;) {
 #ifdef SYNC_KLOOP_POLL
-		__set_current_state(TASK_INTERRUPTIBLE);
+		if (poll_ctx)
+			__set_current_state(TASK_INTERRUPTIBLE);
 #endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
@@ -4403,23 +4456,36 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		schedule_timeout_interruptible(msecs_to_jiffies(1000));
-#else  /* SYNC_KLOOP_POLL */
-		/* Default synchronization method: sleep for a while. */
-		usleep_range(sleep_us, sleep_us);
+		if (poll_ctx)
+			schedule_timeout_interruptible(msecs_to_jiffies(1000));
+		else
 #endif /* SYNC_KLOOP_POLL */
+		{
+			/* Default synchronization method: sleep for a while. */
+			usleep_range(sleep_us, sleep_us);
+		}
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
 		}
 	}
-
+out:
 #ifdef SYNC_KLOOP_POLL
-	__set_current_state(TASK_RUNNING);
-	for (i = 0; i < ctx.next_entry; i++) {
-		struct sync_kloop_poll_entry *entry = ctx.entries + i;
-
-		remove_wait_queue(entry->wqh, &entry->wait);
+	if (poll_ctx) {
+		__set_current_state(TASK_RUNNING);
+		for (i = 0; i < poll_ctx->next_entry; i++) {
+			struct sync_kloop_poll_entry *entry =
+						poll_ctx->entries + i;
+
+			if (entry->wqh) {
+				remove_wait_queue(entry->wqh, &entry->wait);
+			}
+			if (entry->filp && entry->filp != priv->np_filp) {
+				fput(entry->filp);
+			}
+		}
+		nm_os_free(poll_ctx);
+		poll_ctx = NULL;
 	}
 #endif /* SYNC_KLOOP_POLL */
 
@@ -4428,7 +4494,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	priv->np_kloop_state = 0;
 	NMG_UNLOCK();
 
-	return 0;
+	return err;
 }
 
 /*
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e4dca1c48..8c37e47ed 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1882,7 +1882,7 @@ struct netmap_priv_d {
 	NM_SELINFO_T *np_si[NR_TXRX];
 	struct thread	*np_td;		/* kqueue, just debugging */
 #ifdef linux
-	struct file	*filp;  /* used by sync kloop */
+	struct file	*np_filp;  /* used by sync kloop */
 #endif /* linux */
 };
 
@@ -2130,7 +2130,7 @@ void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
 int netmap_sync_kloop(struct netmap_priv_d *priv,
-		      struct nmreq_sync_kloop_start *req);
+		      struct nmreq_header *hdr);
 
 #ifdef WITH_PTNETMAP_HOST
 /*
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index aa31f521b..44d31a3c9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -477,6 +477,8 @@ struct nmreq_option {
 	 * !=0: errno value
 	 */
 	uint32_t		nro_status;
+	/* Option size, used only by variable-size options. */
+	uint64_t		nro_size;
 };
 
 /* Header common to all requests. Do not reorder these fields, as we need
@@ -529,6 +531,10 @@ enum {
 	/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
 	 * from user-space allocated memory pools (e.g. hugepages). */
 	NETMAP_REQ_OPT_EXTMEM = 1,
+	/* ON NETMAP_REQ_SYNC_KLOOP_START, ask netmap to use eventfd-based
+	 * notifications to synchronize the kernel loop with the application.
+	 */
+	NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS,
 };
 
 /*
@@ -796,6 +802,18 @@ nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
  * data for NETMAP_REQ_OPT_* options
  */
 
+struct nmreq_opt_sync_kloop_eventfds {
+	struct nmreq_option	nro_opt;	/* common header */
+	/* An array of N entries for bidirectional notifications between
+	 * the kernel loop and the application. The number of entries must
+	 * agree with the number of rings bound to the netmap file descriptor.
+	 */
+	struct {
+		int32_t ioeventfd;
+		int32_t irqfd;
+	} eventfds[0];
+};
+
 struct nmreq_opt_extmem {
 	struct nmreq_option	nro_opt;	/* common header */
 	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */

From a818427323894c5da8a13ee770e640476ff94e13 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 11:35:01 +0200
Subject: [PATCH 1209/2207] sync-kloop: add some comments

---
 sys/dev/netmap/netmap.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 724a912de..b2c45df28 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4226,7 +4226,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	}
 }
 
-//#define SYNC_KLOOP_POLL
+#define SYNC_KLOOP_POLL
 #ifdef SYNC_KLOOP_POLL
 #include 
 struct sync_kloop_poll_entry {
@@ -4397,8 +4397,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
 		poll_ctx->si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
 					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		/* Poll for notifications coming from the netmap rings bound to
+		 * this file descriptor. */
 		poll_wait(priv->np_filp, poll_ctx->si[NR_RX], &poll_ctx->wait_table);
 		poll_wait(priv->np_filp, poll_ctx->si[NR_TX], &poll_ctx->wait_table);
+		/* Poll for notifications coming from the applications through
+		 * eventfds . */
 		for (i = 0; i < num_rings; i++) {
 			struct file *filp;
 			unsigned long mask;
@@ -4456,9 +4460,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
+		if (poll_ctx) {
+			/* If a poll context is present, yield to the scheduler
+			 * waiting for a notification to come either from
+			 * netmap or the application. */
 			schedule_timeout_interruptible(msecs_to_jiffies(1000));
-		else
+		} else
 #endif /* SYNC_KLOOP_POLL */
 		{
 			/* Default synchronization method: sleep for a while. */
@@ -4472,6 +4479,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 out:
 #ifdef SYNC_KLOOP_POLL
 	if (poll_ctx) {
+		/* Stop polling from netmap and the eventfds, and deallocate
+		 * the poll context. */
 		__set_current_state(TASK_RUNNING);
 		for (i = 0; i < poll_ctx->next_entry; i++) {
 			struct sync_kloop_poll_entry *entry =

From e03ed9645d04208a52fae9b0c5b021e7caf28de4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:18:08 +0200
Subject: [PATCH 1210/2207] utils: sync_kloop_test: allocate eventfds

---
 utils/sync_kloop_test.c | 83 +++++++++++++++++++++++++++++++++++------
 1 file changed, 72 insertions(+), 11 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 7247a6a5d..a334c6d3d 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -11,6 +11,9 @@
 #include 
 #include 
 #include 
+#ifdef __linux__
+#include 
+#endif /* __linux__ */
 
 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
 
@@ -23,6 +26,11 @@ sigint_handler(int signum)
 	ACCESS_ONCE(stop) = 1;
 }
 
+struct eventfds {
+	int ioeventfd;
+	int irqfd;
+};
+
 struct context {
 	struct nm_desc *nmd;
 	struct nm_csb_atok *atok_base;
@@ -30,24 +38,44 @@ struct context {
 	int sleep_us;
 	int verbose;
 	int batch;
+	int num_entries;
+	struct eventfds *eventfds;
 };
 
 static void *
 kloop_worker(void *opaque)
 {
-	struct context *ctx = opaque;
-	struct nm_desc *nmd = ctx->nmd;
+	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
+	struct context *ctx                       = opaque;
+	struct nm_desc *nmd                       = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 	int ret;
 
+	if (ctx->eventfds) {
+		size_t opt_size = sizeof(*opt) +
+		                  ctx->num_entries * sizeof(opt->eventfds[0]);
+		int i;
+
+		opt = malloc(opt_size);
+		memset(opt, 0, opt_size);
+		opt->nro_opt.nro_next    = 0;
+		opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
+		opt->nro_opt.nro_status  = 0;
+		opt->nro_opt.nro_size    = opt_size;
+		for (i = 0; i < ctx->num_entries; i++) {
+			opt->eventfds[i].ioeventfd = ctx->eventfds[i].ioeventfd;
+			opt->eventfds[i].irqfd     = ctx->eventfds[i].irqfd;
+		}
+	}
+
 	/* The ioctl() returns on failure or when some other thread
 	 * stops the kernel loop. */
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.nr_version = NETMAP_API;
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
 	hdr.nr_body    = (uintptr_t)&req;
-	hdr.nr_options = (uintptr_t)NULL;
+	hdr.nr_options = (uintptr_t)opt;
 	memset(&req, 0, sizeof(req));
 	req.csb_atok = (uintptr_t)ctx->atok_base;
 	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
@@ -83,6 +111,7 @@ usage(const char *progname)
 	       "[-R RATE_PPS (0 = infinite)]\n"
 	       "[-b BATCH_SIZE (in packets)]\n"
 	       "[-u KLOOP_SLEEP_US (in microseconds)]\n"
+	       "[-k (use eventfd-based notifications)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -97,7 +126,7 @@ main(int argc, char **argv)
 {
 	struct nm_csb_atok *atok_base = NULL;
 	struct nm_csb_ktoa *ktoa_base = NULL;
-	int num_entries, num_tx_entries;
+	int num_tx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
 	const char *ifname       = NULL;
@@ -112,6 +141,7 @@ main(int argc, char **argv)
 	struct timeval next_time;
 	int packet_budget;
 	struct timeval loop_begin, loop_end;
+	int use_eventfds = 0;
 
 	int init_tx_payload = 1;
 	function_t func;
@@ -138,7 +168,7 @@ main(int argc, char **argv)
 	ctx.batch    = 1;
 	ctx.sleep_us = 500;
 
-	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:k")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -186,6 +216,10 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case 'k':
+			use_eventfds = 1;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -216,13 +250,13 @@ main(int argc, char **argv)
 	{
 		size_t csb_size;
 
-		num_tx_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1;
-		num_entries    = num_tx_entries + nmd->last_rx_ring -
-		              nmd->first_rx_ring + 1;
-		printf("Number of CSB entries = %d\n", (int)num_entries);
+		num_tx_entries  = nmd->last_tx_ring - nmd->first_tx_ring + 1;
+		ctx.num_entries = num_tx_entries + nmd->last_rx_ring -
+		                  nmd->first_rx_ring + 1;
+		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
-		           num_entries;
+		           ctx.num_entries;
 		assert(csb_size > 0);
 		ret = posix_memalign(&csb, sizeof(struct nm_csb_atok),
 		                     csb_size);
@@ -234,7 +268,34 @@ main(int argc, char **argv)
 
 		atok_base = ctx.atok_base = (struct nm_csb_atok *)csb;
 		ktoa_base                 = ctx.ktoa_base =
-		        (struct nm_csb_ktoa *)(ctx.atok_base + num_entries);
+		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
+	}
+
+	/* Allocate eventfds. */
+	if (use_eventfds) {
+#ifdef __linux__
+		int i;
+
+		ctx.eventfds =
+		        malloc(ctx.num_entries * sizeof(ctx.eventfds[0]));
+		for (i = 0; i < ctx.num_entries; i++) {
+			int efd;
+
+			efd = eventfd(0, 0);
+			if (efd < 0) {
+				perror("eventfd()");
+			}
+			ctx.eventfds[i].ioeventfd = efd;
+			efd                       = eventfd(0, 0);
+			if (efd < 0) {
+				perror("eventfd()");
+			}
+			ctx.eventfds[i].irqfd = efd;
+		}
+#else  /* !__linux__ */
+		printf("Eventfds not supported on this platform\n");
+		return -1;
+#endif /* !__linux__ */
 	}
 
 	/* Start the kernel worker thread. */

From c7ca580537310381977ab06bcd89d004375b1413 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:22:34 +0200
Subject: [PATCH 1211/2207] sync-kloop: add comment about fput() invocation

---
 sys/dev/netmap/netmap.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b2c45df28..bb4e6f7fc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4489,6 +4489,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			if (entry->wqh) {
 				remove_wait_queue(entry->wqh, &entry->wait);
 			}
+			/* We did not get a reference to the eventfds, but
+			 * don't do that on netmap file descriptors (since
+			 * a reference was not taken. */
 			if (entry->filp && entry->filp != priv->np_filp) {
 				fput(entry->filp);
 			}

From 58ef60b5734c236928f16ed1bd9ef3f57d7146e8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:23:39 +0200
Subject: [PATCH 1212/2207] sync-kloop: remove old notifications

---
 sys/dev/netmap/netmap.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bb4e6f7fc..dbdbde652 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4080,7 +4080,6 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			 * go to sleep, waiting for a kick from the application when new
 			 * new slots are ready for transmission.
 			 */
-			usleep_range(1,1);
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */
@@ -4193,7 +4192,6 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 			 * go to sleep, waiting for a kick from the application when new receive
 			 * slots are available.
 			 */
-			usleep_range(1,1);
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */

From e7718aafcbbf80950127645ab520f10975572f43 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:30:54 +0200
Subject: [PATCH 1213/2207] sync-kloop: start polling netmap notifications
 after application's ones

---
 sys/dev/netmap/netmap.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index dbdbde652..261ce9541 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4234,7 +4234,6 @@ struct sync_kloop_poll_entry {
 };
 
 struct sync_kloop_poll_ctx {
-	NM_SELINFO_T *si[NR_TXRX];
 	poll_table wait_table;
 	unsigned int next_entry;
 	unsigned int num_entries;
@@ -4367,6 +4366,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
 	if (opt != NULL) {
+		NM_SELINFO_T *si[NR_TXRX];
+
 		err = nmreq_checkduplicate(opt);
 		if (err) {
 			opt->nro_status = err;
@@ -4391,14 +4392,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					sync_kloop_poll_table_queue_proc);
 		poll_ctx->num_entries = 2 + num_rings;
 		poll_ctx->next_entry = 0;
-		poll_ctx->si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-		poll_ctx->si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-		/* Poll for notifications coming from the netmap rings bound to
-		 * this file descriptor. */
-		poll_wait(priv->np_filp, poll_ctx->si[NR_RX], &poll_ctx->wait_table);
-		poll_wait(priv->np_filp, poll_ctx->si[NR_TX], &poll_ctx->wait_table);
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
 		for (i = 0; i < num_rings; i++) {
@@ -4416,6 +4409,14 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 				goto out;
 			}
 		}
+		/* Poll for notifications coming from the netmap rings bound to
+		 * this file descriptor. */
+		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
+		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
 #else   /* SYNC_KLOOP_POLL */
 		opt->nro_status = EOPNOTSUPP;
 		goto out;

From 05e952ab422612b154683e0cece64fc0378f7eb6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:50:42 +0200
Subject: [PATCH 1214/2207] sync-kloop: get ioeventfd file descriptors

---
 sys/dev/netmap/netmap.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 261ce9541..a80a7a043 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4228,9 +4228,15 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 #ifdef SYNC_KLOOP_POLL
 #include 
 struct sync_kloop_poll_entry {
+	/* Support for receiving notifications from
+	 * a netmap ring or from the application. */
 	struct file *filp;
 	wait_queue_entry_t wait;
 	wait_queue_head_t *wqh;
+
+	/* Support for sending notifications to the application. */
+	struct eventfd_ctx *irq_ctx;
+	struct file *irq_filp;
 };
 
 struct sync_kloop_poll_ctx {
@@ -4395,6 +4401,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
 		for (i = 0; i < num_rings; i++) {
+			struct eventfd_ctx *irq;
 			struct file *filp;
 			unsigned long mask;
 
@@ -4408,6 +4415,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 				err = EINVAL;
 				goto out;
 			}
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_filp = filp;
+			irq = eventfd_ctx_fileget(filp);
+			if (IS_ERR(irq)) {
+				err = PTR_ERR(irq);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_ctx = irq;
 		}
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
@@ -4485,15 +4505,17 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			struct sync_kloop_poll_entry *entry =
 						poll_ctx->entries + i;
 
-			if (entry->wqh) {
+			if (entry->wqh)
 				remove_wait_queue(entry->wqh, &entry->wait);
-			}
 			/* We did not get a reference to the eventfds, but
 			 * don't do that on netmap file descriptors (since
 			 * a reference was not taken. */
-			if (entry->filp && entry->filp != priv->np_filp) {
+			if (entry->filp && entry->filp != priv->np_filp)
 				fput(entry->filp);
-			}
+			if (entry->irq_ctx)
+				eventfd_ctx_put(entry->irq_ctx);
+			if (entry->irq_filp)
+				fput(entry->irq_filp);
 		}
 		nm_os_free(poll_ctx);
 		poll_ctx = NULL;

From 4845a7d9b2d8e27c27692df731f10aa363fb2053 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 16:35:14 +0200
Subject: [PATCH 1215/2207] sync-kloop: introduce struct to keep per-ring args

---
 sys/dev/netmap/netmap.c | 65 ++++++++++++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 21 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a80a7a043..7ac172555 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3987,11 +3987,22 @@ sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 		kring->rhead, kring->rcur, kring->rtail);
 }
 
+#define SYNC_KLOOP_POLL
+struct sync_kloop_ring_args {
+	struct netmap_kring *kring;
+	struct nm_csb_atok *csb_atok;
+	struct nm_csb_ktoa *csb_ktoa;
+#ifdef SYNC_KLOOP_POLL
+	struct eventfd_ctx *irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+};
+
 static void
-netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
-			  struct nm_csb_atok *csb_atok,
-			  struct nm_csb_ktoa *csb_ktoa)
+netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 {
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	bool more_txspace = false;
 	uint32_t num_slots;
@@ -4117,10 +4128,12 @@ sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
 }
 
 static void
-netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
-			  struct nm_csb_atok *csb_atok,
-			  struct nm_csb_ktoa *csb_ktoa)
+netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 {
+
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	int dry_cycles = 0;
 	bool some_recvd = false;
@@ -4224,7 +4237,6 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	}
 }
 
-#define SYNC_KLOOP_POLL
 #ifdef SYNC_KLOOP_POLL
 #include 
 struct sync_kloop_poll_entry {
@@ -4452,30 +4464,41 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
-			struct netmap_kring *kring =
-				NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
-			struct nm_csb_atok* csb_atok = csb_atok_base + i;
-			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + i;
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
+				.csb_atok = csb_atok_base + i,
+				.csb_ktoa = csb_ktoa_base + i,
+			};
 
-			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
 				continue;
 			}
-			netmap_sync_kloop_tx_ring(kring, csb_atok, csb_ktoa);
-			nm_kr_put(kring);
+			netmap_sync_kloop_tx_ring(&a);
+			nm_kr_put(a.kring);
 		}
 
 		/* Process all the RX rings bound to this file descriptor. */
 		for (i = 0; i < num_rx_rings; i++) {
-			struct netmap_kring *kring =
-				NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
-			struct nm_csb_atok* csb_atok = csb_atok_base + num_tx_rings + i;
-			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + num_tx_rings + i;
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
+				.csb_atok = csb_atok_base + num_tx_rings + i,
+				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
+			};
 
-			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
 				continue;
 			}
-			netmap_sync_kloop_rx_ring(kring, csb_atok, csb_ktoa);
-			nm_kr_put(kring);
+			netmap_sync_kloop_rx_ring(&a);
+			nm_kr_put(a.kring);
 		}
 
 #ifdef SYNC_KLOOP_POLL

From 87e44bf3d49ee578a3b20c7c91e9adf7a87da48a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Oct 2018 16:46:02 +0200
Subject: [PATCH 1216/2207] linux/ixgbe: patch for Intel 5.3.8 driver version

---
 LINUX/final-patches/intel--ixgbe--5.3.8 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.3.8

diff --git a/LINUX/final-patches/intel--ixgbe--5.3.8 b/LINUX/final-patches/intel--ixgbe--5.3.8
new file mode 100644
index 000000000..f94a48c84
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.3.8
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 545489a..e085666 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -49,24 +49,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 0191ee2..5093914 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -734,6 +734,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -752,6 +769,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2033,6 +2061,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ #endif /* CONFIG_FCOE */
+ 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3320,6 +3358,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3967,6 +4009,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -11276,6 +11322,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11321,6 +11371,11 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 6e6411d7012a168079b4472d2cad7b379cefa629 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Oct 2018 16:48:19 +0200
Subject: [PATCH 1217/2207] linux/ixgbevf: patch for Intel 4.3.6 version

---
 LINUX/final-patches/intel--ixgbevf--4.3.6 | 177 ++++++++++++++++++++++
 1 file changed, 177 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.3.6

diff --git a/LINUX/final-patches/intel--ixgbevf--4.3.6 b/LINUX/final-patches/intel--ixgbevf--4.3.6
new file mode 100644
index 000000000..239d7acca
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.3.6
@@ -0,0 +1,177 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index c8d39f4..e16565a 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -28,22 +28,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbevf.o
++obj-$(CONFIG_IXGBE) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -90,9 +90,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 733d94f..e101128 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -371,6 +371,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -390,6 +407,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1192,6 +1220,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
+ 	struct sk_buff *skb = rx_ring->skb;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 
+@@ -1825,6 +1863,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1835,7 +1877,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	if (!wait_loop)
+ 		DPRINTK(HW, DEBUG, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+- 
++
+ /**
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+@@ -2012,6 +2054,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4984,8 +5030,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5025,6 +5073,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 25e42e9..3374fb9 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -25,6 +25,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From e19a056cf6895ba559b8948243e739eb4031cb14 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:11:17 +0200
Subject: [PATCH 1218/2207] sync-kloop: add support for sending notifications

---
 sys/dev/netmap/netmap.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7ac172555..60f716d8e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4077,11 +4077,13 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 
 		/* Interrupt the application if needed. */
-		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
+#ifdef SYNC_KLOOP_POLL
+		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
-			// nm_os_kctx_send_irq(kth); // TODO
+			eventfd_signal(a->irq_ctx, 1);
 			more_txspace = false;
 		}
+#endif /* SYNC_KLOOP_POLL */
 
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
@@ -4112,9 +4114,11 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 	}
 
-	if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
-		// nm_os_kctx_send_irq(kth); // TODO
+#ifdef SYNC_KLOOP_POLL
+	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
 	}
+#endif /* SYNC_KLOOP_POLL */
 }
 
 /* RX cycle without receive any packets */
@@ -4190,12 +4194,14 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 			sync_kloop_kring_dump("post rxsync", kring);
 		}
 
+#ifdef SYNC_KLOOP_POLL
 		/* Interrupt the application if needed. */
-		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
-			//nm_os_kctx_send_irq(kth); // TODO
+			eventfd_signal(a->irq_ctx, 1);
 			some_recvd = false;
 		}
+#endif /* SYNC_KLOOP_POLL */
 
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
@@ -4231,10 +4237,12 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 
 	nm_kr_put(kring);
 
+#ifdef SYNC_KLOOP_POLL
 	/* Interrupt the application if needed. */
-	if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
-		//nm_os_kctx_send_irq(kth); // TODO
+	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
 	}
+#endif /* SYNC_KLOOP_POLL */
 }
 
 #ifdef SYNC_KLOOP_POLL

From 25c134a12b4150c4a65bdea6ec7285086a0821e8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:15:35 +0200
Subject: [PATCH 1219/2207] utils: sync_kloop_test: use 100 us as default sleep
 interval

---
 utils/sync_kloop_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a334c6d3d..9a3a43d65 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -166,7 +166,7 @@ main(int argc, char **argv)
 	func         = F_RX;
 	ctx.verbose  = 0;
 	ctx.batch    = 1;
-	ctx.sleep_us = 500;
+	ctx.sleep_us = 100;
 
 	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:k")) != -1) {
 		switch (opt) {

From 9db90b885ccf069be55c9e0e317d1f348ef7e10d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Oct 2018 17:00:26 +0200
Subject: [PATCH 1220/2207] linux/ixgbe: patch for Intel 5.5.1 version

---
 LINUX/final-patches/intel--ixgbe--5.5.1 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.5.1

diff --git a/LINUX/final-patches/intel--ixgbe--5.5.1 b/LINUX/final-patches/intel--ixgbe--5.5.1
new file mode 100644
index 000000000..baf559795
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.5.1
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bf12f5..fa05036 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -28,24 +28,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 6c4e051..2c64477 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -694,6 +694,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -713,6 +730,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2192,6 +2220,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3624,6 +3662,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4245,6 +4287,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -12094,6 +12140,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12143,6 +12193,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 627d5f4c93364676586e304f5b6cc4b22d653e0d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Oct 2018 17:02:30 +0200
Subject: [PATCH 1221/2207] linux/ixgbevf: patch for Intel 4.5.1 version

---
 LINUX/final-patches/intel--ixgbevf--4.5.1 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.5.1

diff --git a/LINUX/final-patches/intel--ixgbevf--4.5.1 b/LINUX/final-patches/intel--ixgbevf--4.5.1
new file mode 100644
index 000000000..e9dc8b724
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.5.1
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 18d35f3..c4ae238 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -69,9 +69,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 139aaf7..5df106d 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -358,6 +375,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif /* HAVE_XDP_BUFF_RXQ */
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		struct ixgbevf_rx_buffer *rx_buffer;
+ 		union ixgbe_adv_rx_desc *rx_desc;
+@@ -2053,6 +2091,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2287,6 +2329,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5568,8 +5614,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5610,6 +5658,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 4b1c30f..46953ef 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From d36feecf60fb3079c13e71234799204a5408ce3d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Oct 2018 17:35:37 +0200
Subject: [PATCH 1222/2207] linux/ixgbe: bump default version to 5.3.8

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index f094cb98a..258ec7e28 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -80,7 +80,7 @@ e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 
 # set all the default versions (can be overrided by --select-version=)
-$(eval $(call default,ixgbe,5.3.7))
+$(eval $(call default,ixgbe,5.3.8))
 $(eval $(call default,ixgbevf,4.3.2))
 $(eval $(call default,e1000e,3.4.0.2))
 $(eval $(call default,igb,5.3.5.20))

From 720bfcac6c005bd7c26425d0eea73f03ed44141d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:45:33 +0200
Subject: [PATCH 1223/2207] utils: sync_kloop_test: add support for app -->
 kern notifications

---
 utils/sync_kloop_test.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 9a3a43d65..78df2ebe7 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -126,6 +126,7 @@ main(int argc, char **argv)
 {
 	struct nm_csb_atok *atok_base = NULL;
 	struct nm_csb_ktoa *ktoa_base = NULL;
+	struct eventfds *eventfds_base = NULL;
 	int num_tx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
@@ -322,9 +323,11 @@ main(int argc, char **argv)
 #if 0
 	printf("period us %u batch %u\n", period_us, period_budget);
 #endif
+	eventfds_base = ctx.eventfds;
 	if (func == F_RX) {
 		atok_base += num_tx_entries;
 		ktoa_base += num_tx_entries;
+		eventfds_base += num_tx_entries;
 		first_ring = nmd->first_rx_ring;
 		last_ring  = nmd->last_rx_ring;
 	} else {
@@ -373,6 +376,8 @@ main(int argc, char **argv)
 		}
 
 		for (r = first_ring; r <= last_ring; r++) {
+			struct eventfds *evfds = ctx.eventfds ?
+					(eventfds_base + r) : NULL;
 			struct nm_csb_atok *atok = atok_base + r;
 			struct nm_csb_ktoa *ktoa = ktoa_base + r;
 			struct netmap_ring *ring;
@@ -448,7 +453,18 @@ main(int argc, char **argv)
 				bytes += slot->len;
 				head = nm_ring_next(ring, head);
 			}
+			/* Write updated information for the kernel. */
 			nm_sync_kloop_appl_write(atok, head, head);
+			/* Notify the kernel if needed. */
+			if (evfds && ACCESS_ONCE(ktoa->kern_need_kick)) {
+				uint64_t x = 1;
+				int n = write(evfds->ioeventfd, &x, sizeof(x));
+
+				assert(n == sizeof(x));
+				if (ctx.verbose) {
+					printf("Kernel notified\n");
+				}
+			}
 			if (ctx.verbose) {
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",

From 83e64266688b2fba1dbf152b121374a99e01aca2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:59:01 +0200
Subject: [PATCH 1224/2207] prune ptnetmap host code

---
 LINUX/Kbuild.in              |    1 -
 extra/python/netmap.c        |    4 -
 sys/dev/netmap/netmap.c      |   11 -
 sys/dev/netmap/netmap_kern.h |   40 +-
 sys/dev/netmap/netmap_pt.c   | 1215 ----------------------------------
 sys/net/netmap.h             |    4 +-
 sys/net/netmap_virt.h        |   60 --
 utils/testmmap.c             |    8 -
 8 files changed, 2 insertions(+), 1341 deletions(-)

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index 1fb190940..a2ce4966c 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -15,7 +15,6 @@ remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
 remoteobjs-$(CONFIG_NETMAP_MONITOR) += netmap_monitor.o
 remoteobjs-$(CONFIG_NETMAP_GENERIC) += netmap_generic.o
 remoteobjs-ptnetmap-$(CONFIG_NETMAP_PTNETMAP_GUEST) = netmap_pt.o
-remoteobjs-ptnetmap-$(CONFIG_NETMAP_PTNETMAP_HOST)  = netmap_pt.o
 remoteobjs-y += $(remoteobjs-ptnetmap-y)
 
 define remote_template
diff --git a/extra/python/netmap.c b/extra/python/netmap.c
index 08da3f521..f34d6c6d5 100644
--- a/extra/python/netmap.c
+++ b/extra/python/netmap.c
@@ -270,10 +270,6 @@ static struct NetmapConst netmap_constants[] = {
         .name = "RegExclusive",
         .value = NR_EXCLUSIVE,
     },
-    {
-        .name = "RegPTNetmapHost",
-        .value = NR_PTNETMAP_HOST,
-    },
     /* Add 'netmap_rings.flags' constants to the module. */
     {
         .name = "NrTimestamp",
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 60f716d8e..5398dddfa 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1526,11 +1526,6 @@ netmap_get_na(struct nmreq_header *hdr,
 	 *  !0    !NULL		impossible
 	 */
 
-	/* try to see if this is a ptnetmap port */
-	error = netmap_get_pt_host_na(hdr, na, nmd, create);
-	if (error || *na != NULL)
-		goto out;
-
 	/* try to see if this is a monitor port */
 	error = netmap_get_monitor_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
@@ -1808,12 +1803,6 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 	enum txrx t;
 	u_int j;
 
-	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC) ||
-			nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
-		D("Error: only NR_REG_ALL_NIC supported with netmap passthrough");
-		return EINVAL;
-	}
-
 	for_rx_tx(t) {
 		if (nr_flags & excluded_direction[t]) {
 			priv->np_qfirst[t] = priv->np_qlast[t] = 0;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8c37e47ed..4bd0dab6e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -55,9 +55,6 @@
 #if defined(CONFIG_NETMAP_PTNETMAP_GUEST)
 #define WITH_PTNETMAP_GUEST
 #endif
-#if defined(CONFIG_NETMAP_PTNETMAP_HOST)
-#define WITH_PTNETMAP_HOST
-#endif
 #if defined(CONFIG_NETMAP_SINK)
 #define WITH_SINK
 #endif
@@ -73,7 +70,6 @@
 #define WITH_PIPES
 #define WITH_MONITOR
 #define WITH_GENERIC
-#define WITH_PTNETMAP_HOST	/* ptnetmap host support */
 #define WITH_PTNETMAP_GUEST	/* ptnetmap guest support */
 #define WITH_EXTMEM
 #endif
@@ -698,7 +694,7 @@ struct netmap_adapter {
 				 */
 #define NAF_HOST_RINGS  64	/* the adapter supports the host rings */
 #define NAF_FORCE_NATIVE 128	/* the adapter is always NATIVE */
-#define NAF_PTNETMAP_HOST 256	/* the adapter supports ptnetmap in the host */
+/* free */
 #define NAF_MOREFRAG	512	/* the adapter supports NS_MOREFRAG */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
@@ -2132,40 +2128,6 @@ u_int nm_os_ncpus(void);
 int netmap_sync_kloop(struct netmap_priv_d *priv,
 		      struct nmreq_header *hdr);
 
-#ifdef WITH_PTNETMAP_HOST
-/*
- * netmap adapter for host ptnetmap ports
- */
-struct netmap_pt_host_adapter {
-	struct netmap_adapter up;
-
-	/* the passed-through adapter */
-	struct netmap_adapter *parent;
-	/* parent->na_flags, saved at NETMAP_PT_HOST_CREATE time,
-	 * and restored at NETMAP_PT_HOST_DELETE time */
-	uint32_t parent_na_flags;
-
-	int (*parent_nm_notify)(struct netmap_kring *kring, int flags);
-	void *ptns;
-};
-
-/* ptnetmap host-side routines */
-int netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-			struct netmap_mem_d * nmd, int create);
-int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
-
-static inline int
-nm_ptnetmap_host_on(struct netmap_adapter *na)
-{
-	return na && na->na_flags & NAF_PTNETMAP_HOST;
-}
-#else /* !WITH_PTNETMAP_HOST */
-#define netmap_get_pt_host_na(hdr, _2, _3, _4) \
-	(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
-#define ptnetmap_ctl(_1, _2, _3)   EINVAL
-#define nm_ptnetmap_host_on(_1)   EINVAL
-#endif /* !WITH_PTNETMAP_HOST */
-
 #ifdef WITH_PTNETMAP_GUEST
 /* ptnetmap GUEST routines */
 
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index f53d66282..3f4aa9a28 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -41,10 +41,6 @@
 #include 
 #include 
 
-//#define usleep_range(_1, _2)
-#define usleep_range(_1, _2) \
-	pause_sbt("ptnetmap-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE)
-
 #elif defined(linux)
 #include 
 #endif
@@ -54,1217 +50,6 @@
 #include 
 #include 
 
-#ifdef WITH_PTNETMAP_HOST
-
-/* RX cycle without receive any packets */
-#define PTN_RX_DRY_CYCLES_MAX	10
-
-/* Limit Batch TX to half ring.
- * Currently disabled, since it does not manage NS_MOREFRAG, which
- * results in random drops in the VALE txsync. */
-//#define PTN_TX_BATCH_LIM(_n)	((_n >> 1))
-
-//#define BUSY_WAIT
-
-#define NETMAP_PT_DEBUG  /* Enables communication debugging. */
-#ifdef NETMAP_PT_DEBUG
-#define DBG(x) x
-#else
-#define DBG(x)
-#endif
-
-
-#undef RATE
-//#define RATE  /* Enables communication statistics. */
-#ifdef RATE
-#define IFRATE(x) x
-struct rate_batch_stats {
-    unsigned long sync;
-    unsigned long sync_dry;
-    unsigned long pkt;
-};
-
-struct rate_stats {
-    unsigned long gtxk;     /* Guest --> Host Tx kicks. */
-    unsigned long grxk;     /* Guest --> Host Rx kicks. */
-    unsigned long htxk;     /* Host --> Guest Tx kicks. */
-    unsigned long hrxk;     /* Host --> Guest Rx Kicks. */
-    unsigned long btxwu;    /* Backend Tx wake-up. */
-    unsigned long brxwu;    /* Backend Rx wake-up. */
-    struct rate_batch_stats txbs;
-    struct rate_batch_stats rxbs;
-};
-
-struct rate_context {
-    struct timer_list timer;
-    struct rate_stats new;
-    struct rate_stats old;
-};
-
-#define RATE_PERIOD  2
-static void
-rate_callback(unsigned long arg)
-{
-    struct rate_context * ctx = (struct rate_context *)arg;
-    struct rate_stats cur = ctx->new;
-    struct rate_batch_stats *txbs = &cur.txbs;
-    struct rate_batch_stats *rxbs = &cur.rxbs;
-    struct rate_batch_stats *txbs_old = &ctx->old.txbs;
-    struct rate_batch_stats *rxbs_old = &ctx->old.rxbs;
-    uint64_t tx_batch, rx_batch;
-    unsigned long txpkts, rxpkts;
-    unsigned long gtxk, grxk;
-    int r;
-
-    txpkts = txbs->pkt - txbs_old->pkt;
-    rxpkts = rxbs->pkt - rxbs_old->pkt;
-
-    tx_batch = ((txbs->sync - txbs_old->sync) > 0) ?
-	       txpkts / (txbs->sync - txbs_old->sync): 0;
-    rx_batch = ((rxbs->sync - rxbs_old->sync) > 0) ?
-	       rxpkts / (rxbs->sync - rxbs_old->sync): 0;
-
-    /* Fix-up gtxk and grxk estimates. */
-    gtxk = (cur.gtxk - ctx->old.gtxk) - (cur.btxwu - ctx->old.btxwu);
-    grxk = (cur.grxk - ctx->old.grxk) - (cur.brxwu - ctx->old.brxwu);
-
-    printk("txpkts  = %lu Hz\n", txpkts/RATE_PERIOD);
-    printk("gtxk    = %lu Hz\n", gtxk/RATE_PERIOD);
-    printk("htxk    = %lu Hz\n", (cur.htxk - ctx->old.htxk)/RATE_PERIOD);
-    printk("btxw    = %lu Hz\n", (cur.btxwu - ctx->old.btxwu)/RATE_PERIOD);
-    printk("rxpkts  = %lu Hz\n", rxpkts/RATE_PERIOD);
-    printk("grxk    = %lu Hz\n", grxk/RATE_PERIOD);
-    printk("hrxk    = %lu Hz\n", (cur.hrxk - ctx->old.hrxk)/RATE_PERIOD);
-    printk("brxw    = %lu Hz\n", (cur.brxwu - ctx->old.brxwu)/RATE_PERIOD);
-    printk("txbatch = %llu avg\n", tx_batch);
-    printk("rxbatch = %llu avg\n", rx_batch);
-    printk("\n");
-
-    ctx->old = cur;
-    r = mod_timer(&ctx->timer, jiffies +
-            msecs_to_jiffies(RATE_PERIOD * 1000));
-    if (unlikely(r))
-        D("[ptnetmap] Error: mod_timer()\n");
-}
-
-static void
-rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail,
-		        uint32_t act_tail, uint32_t num_slots)
-{
-    int n = (int)act_tail - pre_tail;
-
-    if (n) {
-        if (n < 0)
-            n += num_slots;
-
-        bf->sync++;
-        bf->pkt += n;
-    } else {
-        bf->sync_dry++;
-    }
-}
-
-#else /* !RATE */
-#define IFRATE(x)
-#endif /* RATE */
-
-struct ptnetmap_state {
-	/* Kthreads. */
-	struct nm_kctx **kctxs;
-
-	/* Shared memory with the guest (TX/RX) */
-	struct ptnet_csb_gh __user *csb_gh;
-	struct ptnet_csb_hg __user *csb_hg;
-
-	bool stopped;
-
-	/* Netmap adapter wrapping the backend. */
-	struct netmap_pt_host_adapter *pth_na;
-
-	IFRATE(struct rate_context rate_ctx;)
-};
-
-static inline void
-ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring)
-{
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
-		" rtail: %d head: %d cur: %d tail: %d",
-		title, kring->name, kring->nr_hwcur,
-		kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
-		kring->ring->head, kring->ring->cur, kring->ring->tail);
-}
-
-/*
- * TX functions to set/get and to handle host/guest kick.
- */
-
-
-/* Enable or disable guest --> host kicks. */
-static inline void
-pthg_kick_enable(struct ptnet_csb_hg __user *pthg, uint32_t val)
-{
-    CSB_WRITE(pthg, host_need_kick, val);
-}
-
-/* Are guest interrupt enabled or disabled? */
-static inline uint32_t
-ptgh_intr_enabled(struct ptnet_csb_gh __user *ptgh)
-{
-    uint32_t v;
-
-    CSB_READ(ptgh, guest_need_kick, v);
-
-    return v;
-}
-
-/* Handle TX events: from the guest or from the backend */
-static void
-ptnetmap_tx_handler(void *data, int is_kthread)
-{
-    struct netmap_kring *kring = data;
-    struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)kring->na->na_private;
-    struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_csb_gh __user *ptgh;
-    struct ptnet_csb_hg __user *pthg;
-    struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-    bool more_txspace = false;
-    struct nm_kctx *kth;
-    uint32_t num_slots;
-    int batch;
-    IFRATE(uint32_t pre_tail);
-
-    if (unlikely(!ptns)) {
-        D("ERROR ptnetmap state is NULL");
-        return;
-    }
-
-    if (unlikely(ptns->stopped)) {
-        RD(1, "backend netmap is being stopped");
-        return;
-    }
-
-    if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
-        D("ERROR nm_kr_tryget()");
-        return;
-    }
-
-    /* This is a guess, to be fixed in the rate callback. */
-    IFRATE(ptns->rate_ctx.new.gtxk++);
-
-    /* Get TX ptgh/pthg pointer from the CSB. */
-    ptgh = ptns->csb_gh + kring->ring_id;
-    pthg = ptns->csb_hg + kring->ring_id;
-    kth = ptns->kctxs[kring->ring_id];
-
-    num_slots = kring->nkr_num_slots;
-
-    /* Disable guest --> host notifications. */
-    pthg_kick_enable(pthg, 0);
-    /* Copy the guest kring pointers from the CSB */
-    ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-
-    for (;;) {
-	/* If guest moves ahead too fast, let's cut the move so
-	 * that we don't exceed our batch limit. */
-        batch = shadow_ring.head - kring->nr_hwcur;
-        if (batch < 0)
-            batch += num_slots;
-
-#ifdef PTN_TX_BATCH_LIM
-        if (batch > PTN_TX_BATCH_LIM(num_slots)) {
-            uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
-
-            if (head_lim >= num_slots)
-                head_lim -= num_slots;
-            ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
-						     head_lim);
-            shadow_ring.head = head_lim;
-	    batch = PTN_TX_BATCH_LIM(num_slots);
-        }
-#endif /* PTN_TX_BATCH_LIM */
-
-        if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
-            shadow_ring.flags |= NAF_FORCE_RECLAIM;
-        }
-
-        /* Netmap prologue */
-	shadow_ring.tail = kring->rtail;
-        if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
-            /* Reinit ring and enable notifications. */
-            netmap_ring_reinit(kring);
-            pthg_kick_enable(pthg, 1);
-            break;
-        }
-
-        if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-            ptnetmap_kring_dump("pre txsync", kring);
-	}
-
-        IFRATE(pre_tail = kring->rtail);
-        if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            D("ERROR txsync()");
-	    break;
-        }
-
-        /*
-         * Finalize
-         * Copy host hwcur and hwtail into the CSB for the guest sync(), and
-	 * do the nm_sync_finalize.
-         */
-        ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur,
-				      kring->nr_hwtail);
-        if (kring->rtail != kring->nr_hwtail) {
-	    /* Some more room available in the parent adapter. */
-	    kring->rtail = kring->nr_hwtail;
-	    more_txspace = true;
-        }
-
-        IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.txbs, pre_tail,
-				       kring->rtail, num_slots));
-
-        if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-            ptnetmap_kring_dump("post txsync", kring);
-	}
-
-#ifndef BUSY_WAIT
-        /* Interrupt the guest if needed. */
-        if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
-            /* Disable guest kick to avoid sending unnecessary kicks */
-            nm_os_kctx_send_irq(kth);
-            IFRATE(ptns->rate_ctx.new.htxk++);
-            more_txspace = false;
-        }
-#endif
-        /* Read CSB to see if there is more work to do. */
-        ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
-        if (shadow_ring.head == kring->rhead) {
-            /*
-             * No more packets to transmit. We enable notifications and
-             * go to sleep, waiting for a kick from the guest when new
-             * new slots are ready for transmission.
-             */
-            if (is_kthread) {
-                usleep_range(1,1);
-            }
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            /* Doublecheck. */
-            ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-            if (shadow_ring.head != kring->rhead) {
-		/* We won the race condition, there are more packets to
-		 * transmit. Disable notifications and do another cycle */
-		pthg_kick_enable(pthg, 0);
-		continue;
-	    }
-	    break;
-        }
-
-	if (nm_kr_txempty(kring)) {
-	    /* No more available TX slots. We stop waiting for a notification
-	     * from the backend (netmap_tx_irq). */
-            ND(1, "TX ring");
-            break;
-        }
-#endif
-        if (unlikely(ptns->stopped)) {
-            D("backend netmap is being stopped");
-            break;
-        }
-    }
-
-    nm_kr_put(kring);
-
-    if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
-        nm_os_kctx_send_irq(kth);
-        IFRATE(ptns->rate_ctx.new.htxk++);
-    }
-}
-
-/* Called on backend nm_notify when there is no worker thread. */
-static void
-ptnetmap_tx_nothread_notify(void *data)
-{
-	struct netmap_kring *kring = data;
-	struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)kring->na->na_private;
-	struct ptnetmap_state *ptns = pth_na->ptns;
-
-	if (unlikely(!ptns)) {
-		D("ERROR ptnetmap state is NULL");
-		return;
-	}
-
-	if (unlikely(ptns->stopped)) {
-		D("backend netmap is being stopped");
-		return;
-	}
-
-	/* We cannot access the CSB here (to check ptgh->guest_need_kick),
-	 * unless we switch address space to the one of the guest. For now
-	 * we unconditionally inject an interrupt. */
-        nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]);
-        IFRATE(ptns->rate_ctx.new.htxk++);
-        ND(1, "%s interrupt", kring->name);
-}
-
-/*
- * We need RX kicks from the guest when (tail == head-1), where we wait
- * for the guest to refill.
- */
-#ifndef BUSY_WAIT
-static inline int
-ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head)
-{
-    return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
-    			    kring->nkr_num_slots - 1));
-}
-#endif /* !BUSY_WAIT */
-
-/* Handle RX events: from the guest or from the backend */
-static void
-ptnetmap_rx_handler(void *data, int is_kthread)
-{
-    struct netmap_kring *kring = data;
-    struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)kring->na->na_private;
-    struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_csb_gh __user *ptgh;
-    struct ptnet_csb_hg __user *pthg;
-    struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-    struct nm_kctx *kth;
-    uint32_t num_slots;
-    int dry_cycles = 0;
-    bool some_recvd = false;
-    IFRATE(uint32_t pre_tail);
-
-    if (unlikely(!ptns || !ptns->pth_na)) {
-        D("ERROR ptnetmap state %p, ptnetmap host adapter %p", ptns,
-	  ptns ? ptns->pth_na : NULL);
-        return;
-    }
-
-    if (unlikely(ptns->stopped)) {
-        RD(1, "backend netmap is being stopped");
-	return;
-    }
-
-    if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
-        D("ERROR nm_kr_tryget()");
-	return;
-    }
-
-    /* This is a guess, to be fixed in the rate callback. */
-    IFRATE(ptns->rate_ctx.new.grxk++);
-
-    /* Get RX ptgh and pthg pointers from the CSB. */
-    ptgh = ptns->csb_gh + (pth_na->up.num_tx_rings + kring->ring_id);
-    pthg = ptns->csb_hg + (pth_na->up.num_tx_rings + kring->ring_id);
-    kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id];
-
-    num_slots = kring->nkr_num_slots;
-
-    /* Disable notifications. */
-    pthg_kick_enable(pthg, 0);
-    /* Copy the guest kring pointers from the CSB */
-    ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-
-    for (;;) {
-	uint32_t hwtail;
-
-        /* Netmap prologue */
-	shadow_ring.tail = kring->rtail;
-        if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
-            /* Reinit ring and enable notifications. */
-            netmap_ring_reinit(kring);
-            pthg_kick_enable(pthg, 1);
-            break;
-        }
-
-        if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-            ptnetmap_kring_dump("pre rxsync", kring);
-	}
-
-        IFRATE(pre_tail = kring->rtail);
-        if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            D("ERROR rxsync()");
-	    break;
-        }
-        /*
-         * Finalize
-         * Copy host hwcur and hwtail into the CSB for the guest sync()
-         */
-	hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-        ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur, hwtail);
-        if (kring->rtail != hwtail) {
-	    kring->rtail = hwtail;
-            some_recvd = true;
-            dry_cycles = 0;
-        } else {
-            dry_cycles++;
-        }
-
-        IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.rxbs, pre_tail,
-	                               kring->rtail, num_slots));
-
-        if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-            ptnetmap_kring_dump("post rxsync", kring);
-	}
-
-#ifndef BUSY_WAIT
-	/* Interrupt the guest if needed. */
-        if (some_recvd && ptgh_intr_enabled(ptgh)) {
-            /* Disable guest kick to avoid sending unnecessary kicks */
-            nm_os_kctx_send_irq(kth);
-            IFRATE(ptns->rate_ctx.new.hrxk++);
-            some_recvd = false;
-        }
-#endif
-        /* Read CSB to see if there is more work to do. */
-        ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
-        if (ptnetmap_norxslots(kring, shadow_ring.head)) {
-            /*
-             * No more slots available for reception. We enable notification and
-             * go to sleep, waiting for a kick from the guest when new receive
-	     * slots are available.
-             */
-            usleep_range(1,1);
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            /* Doublecheck. */
-            ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-            if (!ptnetmap_norxslots(kring, shadow_ring.head)) {
-		/* We won the race condition, more slots are available. Disable
-		 * notifications and do another cycle. */
-                pthg_kick_enable(pthg, 0);
-                continue;
-	    }
-            break;
-        }
-
-	hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-        if (unlikely(hwtail == kring->rhead ||
-		     dry_cycles >= PTN_RX_DRY_CYCLES_MAX)) {
-	    /* No more packets to be read from the backend. We stop and
-	     * wait for a notification from the backend (netmap_rx_irq). */
-            ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
-	       hwtail, kring->rhead, dry_cycles);
-            break;
-        }
-#endif
-        if (unlikely(ptns->stopped)) {
-            D("backend netmap is being stopped");
-            break;
-        }
-    }
-
-    nm_kr_put(kring);
-
-    /* Interrupt the guest if needed. */
-    if (some_recvd && ptgh_intr_enabled(ptgh)) {
-        nm_os_kctx_send_irq(kth);
-        IFRATE(ptns->rate_ctx.new.hrxk++);
-    }
-}
-
-#ifdef NETMAP_PT_DEBUG
-static void
-ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
-{
-	int k;
-
-	D("ptnetmap configuration:");
-	D("  CSB @%p@:%p, num_rings=%u, cfgtype %08x", cfg->csb_gh,
-	  cfg->csb_hg, cfg->num_rings, cfg->cfgtype);
-	for (k = 0; k < cfg->num_rings; k++) {
-		switch (cfg->cfgtype) {
-		case PTNETMAP_CFGTYPE_QEMU: {
-			struct ptnetmap_cfgentry_qemu *e =
-				(struct ptnetmap_cfgentry_qemu *)(cfg+1) + k;
-			D("    ring #%d: ioeventfd=%lu, irqfd=%lu", k,
-				(unsigned long)e->ioeventfd,
-				(unsigned long)e->irqfd);
-			break;
-		}
-
-		case PTNETMAP_CFGTYPE_BHYVE:
-		{
-			struct ptnetmap_cfgentry_bhyve *e =
-				(struct ptnetmap_cfgentry_bhyve *)(cfg+1) + k;
-			D("    ring #%d: wchan=%lu, ioctl_fd=%lu, "
-			  "ioctl_cmd=%lu, msix_msg_data=%lu, msix_addr=%lu",
-				k, (unsigned long)e->wchan,
-				(unsigned long)e->ioctl_fd,
-				(unsigned long)e->ioctl_cmd,
-				(unsigned long)e->ioctl_data.msg_data,
-				(unsigned long)e->ioctl_data.addr);
-			break;
-		}
-		}
-	}
-
-}
-#endif /* NETMAP_PT_DEBUG */
-
-/* Copy actual state of the host ring into the CSB for the guest init */
-static int
-ptnetmap_kring_snapshot(struct netmap_kring *kring,
-			struct ptnet_csb_gh __user *ptgh,
-			struct ptnet_csb_hg __user *pthg)
-{
-    if (CSB_WRITE(ptgh, head, kring->rhead))
-        goto err;
-    if (CSB_WRITE(ptgh, cur, kring->rcur))
-        goto err;
-
-    if (CSB_WRITE(pthg, hwcur, kring->nr_hwcur))
-        goto err;
-    if (CSB_WRITE(pthg, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
-        goto err;
-
-    DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);)
-
-    return 0;
-err:
-    return EFAULT;
-}
-
-static struct netmap_kring *
-ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
-{
-	if (k < pth_na->up.num_tx_rings) {
-		return pth_na->up.tx_rings[k];
-	}
-	return pth_na->up.rx_rings[k - pth_na->up.num_tx_rings];
-}
-
-static int
-ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	struct netmap_kring *kring;
-	unsigned int num_rings;
-	int err = 0, k;
-
-	num_rings = pth_na->up.num_tx_rings +
-		    pth_na->up.num_rx_rings;
-
-	for (k = 0; k < num_rings; k++) {
-		kring = ptnetmap_kring(pth_na, k);
-		err |= ptnetmap_kring_snapshot(kring, ptns->csb_gh + k,
-						ptns->csb_hg + k);
-	}
-
-	return err;
-}
-
-/*
- * Functions to create kernel contexts, and start/stop the workers.
- */
-
-static int
-ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
-		      struct ptnetmap_cfg *cfg, int use_tx_kthreads)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	struct nm_kctx_cfg nmk_cfg;
-	unsigned int num_rings;
-	uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
-	unsigned int expected_cfgtype = 0;
-	int k;
-
-#if defined(__FreeBSD__)
-	expected_cfgtype = PTNETMAP_CFGTYPE_BHYVE;
-#elif defined(linux)
-	expected_cfgtype = PTNETMAP_CFGTYPE_QEMU;
-#endif
-	if (cfg->cfgtype != expected_cfgtype) {
-		D("Unsupported cfgtype %u", cfg->cfgtype);
-		return EINVAL;
-	}
-
-	num_rings = pth_na->up.num_tx_rings +
-		    pth_na->up.num_rx_rings;
-
-	for (k = 0; k < num_rings; k++) {
-		nmk_cfg.attach_user = 1; /* attach kthread to user process */
-		nmk_cfg.worker_private = ptnetmap_kring(pth_na, k);
-		nmk_cfg.type = k;
-		if (k < pth_na->up.num_tx_rings) {
-			nmk_cfg.worker_fn = ptnetmap_tx_handler;
-			nmk_cfg.use_kthread = use_tx_kthreads;
-			nmk_cfg.notify_fn = ptnetmap_tx_nothread_notify;
-		} else {
-			nmk_cfg.worker_fn = ptnetmap_rx_handler;
-			nmk_cfg.use_kthread = 1;
-		}
-
-		ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
-				cfg_entries + k * cfg->entry_size);
-		if (ptns->kctxs[k] == NULL) {
-			goto err;
-		}
-	}
-
-	return 0;
-err:
-	for (k = 0; k < num_rings; k++) {
-		if (ptns->kctxs[k]) {
-			nm_os_kctx_destroy(ptns->kctxs[k]);
-			ptns->kctxs[k] = NULL;
-		}
-	}
-	return EFAULT;
-}
-
-static int
-ptnetmap_start_kctx_workers(struct netmap_pt_host_adapter *pth_na)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	int num_rings;
-	int error;
-	int k;
-
-	if (!ptns) {
-		D("BUG ptns is NULL");
-		return EFAULT;
-	}
-
-	ptns->stopped = false;
-
-	num_rings = ptns->pth_na->up.num_tx_rings +
-		    ptns->pth_na->up.num_rx_rings;
-	for (k = 0; k < num_rings; k++) {
-		//nm_os_kctx_worker_setaff(ptns->kctxs[k], xxx);
-		error = nm_os_kctx_worker_start(ptns->kctxs[k]);
-		if (error) {
-			return error;
-		}
-	}
-
-	return 0;
-}
-
-static void
-ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	int num_rings;
-	int k;
-
-	if (!ptns) {
-		/* Nothing to do. */
-		return;
-	}
-
-	ptns->stopped = true;
-
-	num_rings = ptns->pth_na->up.num_tx_rings +
-		    ptns->pth_na->up.num_rx_rings;
-	for (k = 0; k < num_rings; k++) {
-		nm_os_kctx_worker_stop(ptns->kctxs[k]);
-	}
-}
-
-static int nm_unused_notify(struct netmap_kring *, int);
-static int nm_pt_host_notify(struct netmap_kring *, int);
-
-/* Create ptnetmap state and switch parent adapter to ptnetmap mode. */
-static int
-ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
-		struct ptnetmap_cfg *cfg)
-{
-    int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */
-    struct ptnetmap_state *ptns;
-    unsigned int num_rings;
-    int ret, i;
-
-    /* Check if ptnetmap state is already there. */
-    if (pth_na->ptns) {
-        D("ERROR adapter %p already in ptnetmap mode", pth_na->parent);
-        return EINVAL;
-    }
-
-    num_rings = pth_na->up.num_tx_rings + pth_na->up.num_rx_rings;
-
-    if (num_rings != cfg->num_rings) {
-        D("ERROR configuration mismatch, expected %u rings, found %u",
-           num_rings, cfg->num_rings);
-        return EINVAL;
-    }
-
-    if (!use_tx_kthreads && na_is_generic(pth_na->parent)) {
-        D("ERROR ptnetmap direct transmission not supported with "
-	  "passed-through emulated adapters");
-        return EOPNOTSUPP;
-    }
-
-    ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kctxs));
-    if (!ptns) {
-        return ENOMEM;
-    }
-
-    ptns->kctxs = (struct nm_kctx **)(ptns + 1);
-    ptns->stopped = true;
-
-    /* Cross-link data structures. */
-    pth_na->ptns = ptns;
-    ptns->pth_na = pth_na;
-
-    /* Store the CSB address provided by the hypervisor. */
-    ptns->csb_gh = cfg->csb_gh;
-    ptns->csb_hg = cfg->csb_hg;
-
-    DBG(ptnetmap_print_configuration(cfg));
-
-    /* Create kernel contexts. */
-    if ((ret = ptnetmap_create_kctxs(pth_na, cfg, use_tx_kthreads))) {
-        D("ERROR ptnetmap_create_kctxs()");
-        goto err;
-    }
-    /* Copy krings state into the CSB for the guest initialization */
-    if ((ret = ptnetmap_krings_snapshot(pth_na))) {
-        D("ERROR ptnetmap_krings_snapshot()");
-        goto err;
-    }
-
-    /* Overwrite parent nm_notify krings callback, and
-     * clear NAF_BDG_MAYSLEEP if needed. */
-    pth_na->parent->na_private = pth_na;
-    pth_na->parent_nm_notify = pth_na->parent->nm_notify;
-    pth_na->parent->nm_notify = nm_unused_notify;
-    pth_na->parent_na_flags = pth_na->parent->na_flags;
-    if (!use_tx_kthreads) {
-        /* VALE port txsync is executed under spinlock on Linux, so
-         * we need to make sure the bridge cannot sleep. */
-        pth_na->parent->na_flags &= ~NAF_BDG_MAYSLEEP;
-    }
-
-    for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i]->save_notify =
-        	pth_na->up.rx_rings[i]->nm_notify;
-        pth_na->up.rx_rings[i]->nm_notify = nm_pt_host_notify;
-    }
-    for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i]->save_notify =
-        	pth_na->up.tx_rings[i]->nm_notify;
-        pth_na->up.tx_rings[i]->nm_notify = nm_pt_host_notify;
-    }
-
-#ifdef RATE
-    memset(&ptns->rate_ctx, 0, sizeof(ptns->rate_ctx));
-    setup_timer(&ptns->rate_ctx.timer, &rate_callback,
-            (unsigned long)&ptns->rate_ctx);
-    if (mod_timer(&ptns->rate_ctx.timer, jiffies + msecs_to_jiffies(1500)))
-        D("[ptn] Error: mod_timer()\n");
-#endif
-
-    DBG(D("[%s] ptnetmap configuration DONE", pth_na->up.name));
-
-    return 0;
-
-err:
-    pth_na->ptns = NULL;
-    nm_os_free(ptns);
-    return ret;
-}
-
-/* Switch parent adapter back to normal mode and destroy
- * ptnetmap state. */
-static void
-ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
-{
-    struct ptnetmap_state *ptns = pth_na->ptns;
-    int num_rings;
-    int i;
-
-    if (!ptns) {
-	/* Nothing to do. */
-        return;
-    }
-
-    /* Restore parent adapter callbacks. */
-    pth_na->parent->nm_notify = pth_na->parent_nm_notify;
-    pth_na->parent->na_private = NULL;
-    pth_na->parent->na_flags = pth_na->parent_na_flags;
-
-    for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i]->nm_notify =
-        	pth_na->up.rx_rings[i]->save_notify;
-        pth_na->up.rx_rings[i]->save_notify = NULL;
-    }
-    for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i]->nm_notify =
-        	pth_na->up.tx_rings[i]->save_notify;
-        pth_na->up.tx_rings[i]->save_notify = NULL;
-    }
-
-    /* Destroy kernel contexts. */
-    num_rings = ptns->pth_na->up.num_tx_rings +
-                ptns->pth_na->up.num_rx_rings;
-    for (i = 0; i < num_rings; i++) {
-        nm_os_kctx_destroy(ptns->kctxs[i]);
-	ptns->kctxs[i] = NULL;
-    }
-
-    IFRATE(del_timer(&ptns->rate_ctx.timer));
-
-    nm_os_free(ptns);
-
-    pth_na->ptns = NULL;
-
-    DBG(D("[%s] ptnetmap deleted", pth_na->up.name));
-}
-
-/*
- * Called by netmap_ioctl().
- * Operation is indicated in nr_name.
- *
- * Called without NMG_LOCK.
- */
-int
-ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na)
-{
-	struct netmap_pt_host_adapter *pth_na;
-	struct ptnetmap_cfg *cfg = NULL;
-	int error = 0;
-
-	DBG(D("name: %s", nr_name));
-
-	if (!nm_ptnetmap_host_on(na)) {
-		D("ERROR Netmap adapter %p is not a ptnetmap host adapter",
-			na);
-		return ENXIO;
-	}
-	pth_na = (struct netmap_pt_host_adapter *)na;
-
-	NMG_LOCK();
-	if (create) {
-		/* Read hypervisor configuration from userspace. */
-		/* TODO */
-		if (!cfg) {
-			goto out;
-		}
-		/* Create ptnetmap state (kctxs, ...) and switch parent
-		 * adapter to ptnetmap mode. */
-		error = ptnetmap_create(pth_na, cfg);
-		nm_os_free(cfg);
-		if (error) {
-			goto out;
-		}
-		/* Start kthreads. */
-		error = ptnetmap_start_kctx_workers(pth_na);
-		if (error)
-			ptnetmap_delete(pth_na);
-	} else {
-		/* Stop kthreads. */
-		ptnetmap_stop_kctx_workers(pth_na);
-		/* Switch parent adapter back to normal mode and destroy
-		 * ptnetmap state (kthreads, ...). */
-		ptnetmap_delete(pth_na);
-	}
-out:
-	NMG_UNLOCK();
-
-	return error;
-}
-
-/* nm_notify callbacks for ptnetmap */
-static int
-nm_pt_host_notify(struct netmap_kring *kring, int flags)
-{
-	struct netmap_adapter *na = kring->na;
-	struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)na->na_private;
-	struct ptnetmap_state *ptns;
-	int k;
-
-	/* First check that the passthrough port is not being destroyed. */
-	if (unlikely(!pth_na)) {
-		return NM_IRQ_COMPLETED;
-	}
-
-	ptns = pth_na->ptns;
-	if (unlikely(!ptns || ptns->stopped)) {
-		return NM_IRQ_COMPLETED;
-	}
-
-	k = kring->ring_id;
-
-	/* Notify kthreads (wake up if needed) */
-	if (kring->tx == NR_TX) {
-		ND(1, "TX backend irq");
-		IFRATE(ptns->rate_ctx.new.btxwu++);
-	} else {
-		k += pth_na->up.num_tx_rings;
-		ND(1, "RX backend irq");
-		IFRATE(ptns->rate_ctx.new.brxwu++);
-	}
-	nm_os_kctx_worker_wakeup(ptns->kctxs[k]);
-
-	return NM_IRQ_COMPLETED;
-}
-
-static int
-nm_unused_notify(struct netmap_kring *kring, int flags)
-{
-    D("BUG this should never be called");
-    return ENXIO;
-}
-
-/* nm_config callback for bwrap */
-static int
-nm_pt_host_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-    int error;
-
-    //XXX: maybe calling parent->nm_config is better
-
-    /* forward the request */
-    error = netmap_update_config(parent);
-
-    info->num_rx_rings = na->num_rx_rings = parent->num_rx_rings;
-    info->num_tx_rings = na->num_tx_rings = parent->num_tx_rings;
-    info->num_tx_descs = na->num_tx_desc = parent->num_tx_desc;
-    info->num_rx_descs = na->num_rx_desc = parent->num_rx_desc;
-    info->rx_buf_maxsize = na->rx_buf_maxsize = parent->rx_buf_maxsize;
-
-    return error;
-}
-
-/* nm_krings_create callback for ptnetmap */
-static int
-nm_pt_host_krings_create(struct netmap_adapter *na)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-    enum txrx t;
-    int error;
-
-    DBG(D("%s", pth_na->up.name));
-
-    /* create the parent krings */
-    error = parent->nm_krings_create(parent);
-    if (error) {
-        return error;
-    }
-
-    /* A ptnetmap host adapter points the very same krings
-     * as its parent adapter. These pointer are used in the
-     * TX/RX worker functions. */
-    na->tx_rings = parent->tx_rings;
-    na->rx_rings = parent->rx_rings;
-    na->tailroom = parent->tailroom;
-
-    for_rx_tx(t) {
-	struct netmap_kring *kring;
-
-	/* Parent's kring_create function will initialize
-	 * its own na->si. We have to init our na->si here. */
-	nm_os_selinfo_init(&na->si[t]);
-
-	/* Force the mem_rings_create() method to create the
-	 * host rings independently on what the regif asked for:
-	 * these rings are needed by the guest ptnetmap adapter
-	 * anyway. */
-	kring = NMR(na, t)[nma_get_nrings(na, t)];
-	kring->nr_kflags |= NKR_NEEDRING;
-    }
-
-    return 0;
-}
-
-/* nm_krings_delete callback for ptnetmap */
-static void
-nm_pt_host_krings_delete(struct netmap_adapter *na)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-
-    DBG(D("%s", pth_na->up.name));
-
-    parent->nm_krings_delete(parent);
-
-    na->tx_rings = na->rx_rings = na->tailroom = NULL;
-}
-
-/* nm_register callback */
-static int
-nm_pt_host_register(struct netmap_adapter *na, int onoff)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-    int error;
-    DBG(D("%s onoff %d", pth_na->up.name, onoff));
-
-    if (onoff) {
-        /* netmap_do_regif has been called on the ptnetmap na.
-         * We need to pass the information about the
-         * memory allocator to the parent before
-         * putting it in netmap mode
-         */
-        parent->na_lut = na->na_lut;
-    }
-
-    /* forward the request to the parent */
-    error = parent->nm_register(parent, onoff);
-    if (error)
-        return error;
-
-
-    if (onoff) {
-        na->na_flags |= NAF_NETMAP_ON | NAF_PTNETMAP_HOST;
-    } else {
-        ptnetmap_delete(pth_na);
-        na->na_flags &= ~(NAF_NETMAP_ON | NAF_PTNETMAP_HOST);
-    }
-
-    return 0;
-}
-
-/* nm_dtor callback */
-static void
-nm_pt_host_dtor(struct netmap_adapter *na)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-
-    DBG(D("%s", pth_na->up.name));
-
-    /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor
-     * didn't do it. */
-    ptnetmap_stop_kctx_workers(pth_na);
-    ptnetmap_delete(pth_na);
-
-    parent->na_flags &= ~NAF_BUSY;
-
-    netmap_adapter_put(pth_na->parent);
-    pth_na->parent = NULL;
-}
-
-/* check if nmr is a request for a ptnetmap adapter that we can satisfy */
-int
-netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create)
-{
-    struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
-    struct nmreq_register preq;
-    struct netmap_adapter *parent; /* target adapter */
-    struct netmap_pt_host_adapter *pth_na;
-    struct ifnet *ifp = NULL;
-    int error;
-
-    /* Check if it is a request for a ptnetmap adapter */
-    if ((req->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
-        return 0;
-    }
-
-    D("Requesting a ptnetmap host adapter");
-
-    pth_na = nm_os_malloc(sizeof(*pth_na));
-    if (pth_na == NULL) {
-        D("ERROR malloc");
-        return ENOMEM;
-    }
-
-    /* first, try to find the adapter that we want to passthrough
-     * We use the same req, after we have turned off the ptnetmap flag.
-     * In this way we can potentially passthrough everything netmap understands.
-     */
-    memcpy(&preq, req, sizeof(preq));
-    preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    hdr->nr_body = (uintptr_t)&preq;
-    error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
-    hdr->nr_body = (uintptr_t)req;
-    if (error) {
-        D("parent lookup failed: %d", error);
-        goto put_out_noputparent;
-    }
-    DBG(D("found parent: %s", parent->name));
-
-    /* make sure the interface is not already in use */
-    if (NETMAP_OWNED_BY_ANY(parent)) {
-        D("NIC %s busy, cannot ptnetmap", parent->name);
-        error = EBUSY;
-        goto put_out;
-    }
-
-    pth_na->parent = parent;
-
-    /* Follow netmap_attach()-like operations for the host
-     * ptnetmap adapter. */
-
-    //XXX pth_na->up.na_flags = parent->na_flags;
-    pth_na->up.num_rx_rings = parent->num_rx_rings;
-    pth_na->up.num_tx_rings = parent->num_tx_rings;
-    pth_na->up.num_tx_desc = parent->num_tx_desc;
-    pth_na->up.num_rx_desc = parent->num_rx_desc;
-
-    pth_na->up.nm_dtor = nm_pt_host_dtor;
-    pth_na->up.nm_register = nm_pt_host_register;
-
-    /* Reuse parent's adapter txsync and rxsync methods. */
-    pth_na->up.nm_txsync = parent->nm_txsync;
-    pth_na->up.nm_rxsync = parent->nm_rxsync;
-
-    pth_na->up.nm_krings_create = nm_pt_host_krings_create;
-    pth_na->up.nm_krings_delete = nm_pt_host_krings_delete;
-    pth_na->up.nm_config = nm_pt_host_config;
-
-    /* Set the notify method only or convenience, it will never
-     * be used, since - differently from default krings_create - we
-     * ptnetmap krings_create callback inits kring->nm_notify
-     * directly. */
-    pth_na->up.nm_notify = nm_unused_notify;
-
-    pth_na->up.nm_mem = netmap_mem_get(parent->nm_mem);
-
-    pth_na->up.na_flags |= NAF_HOST_RINGS;
-
-    error = netmap_attach_common(&pth_na->up);
-    if (error) {
-        D("ERROR netmap_attach_common()");
-        goto put_out;
-    }
-
-    *na = &pth_na->up;
-    /* set parent busy, because attached for ptnetmap */
-    parent->na_flags |= NAF_BUSY;
-    strlcpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
-    strcat(pth_na->up.name, "-PTN");
-    netmap_adapter_get(*na);
-
-    DBG(D("%s ptnetmap request DONE", pth_na->up.name));
-
-    /* drop the reference to the ifp, if any */
-    if (ifp)
-        if_rele(ifp);
-
-    return 0;
-
-put_out:
-    netmap_adapter_put(parent);
-    if (ifp)
-	if_rele(ifp);
-put_out_noputparent:
-    nm_os_free(pth_na);
-    return error;
-}
-#endif /* WITH_PTNETMAP_HOST */
-
 #ifdef WITH_PTNETMAP_GUEST
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 44d31a3c9..3da365502 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -560,9 +560,7 @@ struct nmreq_register {
 #define NR_ZCOPY_MON	0x400
 /* request exclusive access to the selected rings */
 #define NR_EXCLUSIVE	0x800
-/* request ptnetmap host support */
-#define NR_PASSTHROUGH_HOST	NR_PTNETMAP_HOST /* deprecated */
-#define NR_PTNETMAP_HOST	0x1000
+/* 0x1000 unused */
 #define NR_RX_RINGS_ONLY	0x2000
 #define NR_TX_RINGS_ONLY	0x4000
 /* Applications set this flag if they are able to deal with virtio-net headers,
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 1b8b26cc9..cef32eed6 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -229,64 +229,4 @@ ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kr
 
 #endif /* WITH_PTNETMAP_GUEST */
 
-#ifdef WITH_PTNETMAP_HOST
-/*
- * ptnetmap kernel thread routines
- * */
-
-/* Functions to read and write CSB fields in the host */
-#if defined (linux)
-#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
-#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
-#else  /* ! linux */
-#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
-#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
-#endif /* ! linux */
-
-/* Host netmap: Write kring pointers (hwcur, hwtail) to the CSB.
- * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
-static inline void
-ptnetmap_host_write_kring_csb(struct ptnet_csb_hg __user *ptr, uint32_t hwcur,
-        uint32_t hwtail)
-{
-    /*
-     * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
-     * We allow the guest to read a value of hwcur more recent than the value
-     * of hwtail, since this would anyway result in a consistent view of the
-     * ring state (and hwcur can never wraparound hwtail, since hwcur must be
-     * behind head).
-     *
-     * The following memory barrier scheme is used to make this happen:
-     *
-     *          Guest                Host
-     *
-     *          STORE(hwcur)         LOAD(hwtail)
-     *          mb() <-------------> mb()
-     *          STORE(hwtail)        LOAD(hwcur)
-     */
-    CSB_WRITE(ptr, hwcur, hwcur);
-    mb();
-    CSB_WRITE(ptr, hwtail, hwtail);
-}
-
-/* Host netmap: Read kring pointers (head, cur, sync_flags) from the CSB.
- * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
-static inline void
-ptnetmap_host_read_kring_csb(struct ptnet_csb_gh __user *ptr,
-			     struct netmap_ring *shadow_ring,
-			     uint32_t num_slots)
-{
-    /*
-     * We place a memory barrier to make sure that the update of head never
-     * overtakes the update of cur.
-     * (see explanation in ptnetmap_guest_write_kring_csb).
-     */
-    CSB_READ(ptr, head, shadow_ring->head);
-    mb();
-    CSB_READ(ptr, cur, shadow_ring->cur);
-    CSB_READ(ptr, sync_flags, shadow_ring->flags);
-}
-
-#endif /* WITH_PTNETMAP_HOST */
-
 #endif /* NETMAP_VIRT_H */
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 9979270cf..f0bb6c311 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1160,9 +1160,6 @@ do_nmr_legacy_dump()
 	if (curr_nmr.nr_flags & NR_EXCLUSIVE) {
 		printf(", EXCLUSIVE");
 	}
-	if (curr_nmr.nr_flags & NR_PTNETMAP_HOST) {
-		printf(", PTNETMAP_HOST");
-	}
 	printf("]\n");
 	printf("spare2[0]: %x\n", curr_nmr.spare2[0]);
 }
@@ -1279,8 +1276,6 @@ do_nmr_legacy_flags()
 			flags |= NR_ZCOPY_MON;
 		} else if (strcmp(arg, "exclusive") == 0) {
 			flags |= NR_EXCLUSIVE;
-		} else if (strcmp(arg, "ptnetmap-host") == 0) {
-			flags |= NR_PTNETMAP_HOST;
 		} else if (strcmp(arg, "default") == 0) {
 			flags = 0;
 		}
@@ -1426,7 +1421,6 @@ nmr_body_dump_register(void *b)
 	pflag(MONITOR_RX);
 	pflag(ZCOPY_MON);
 	pflag(EXCLUSIVE);
-	pflag(PTNETMAP_HOST);
 	pflag(RX_RINGS_ONLY);
 	pflag(TX_RINGS_ONLY);
 	pflag(ACCEPT_VNET_HDR);
@@ -1492,8 +1486,6 @@ do_register_flags()
 			flags |= NR_ZCOPY_MON;
 		} else if (strcmp(arg, "exclusive") == 0) {
 			flags |= NR_EXCLUSIVE;
-		} else if (strcmp(arg, "ptnetmap-host") == 0) {
-			flags |= NR_PTNETMAP_HOST;
 		} else if (strcmp(arg, "rx-rings-only") == 0) {
 			flags |= NR_RX_RINGS_ONLY;
 		} else if (strcmp(arg, "tx-rings-only") == 0) {

From a1d2cbe36616320c35ffa9a7e4a8ddfb5d981042 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 10:01:28 +0200
Subject: [PATCH 1225/2207] sync-kloop: move code to netmap_pt.c

---
 sys/dev/netmap/netmap.c    | 653 -------------------------------------
 sys/dev/netmap/netmap_pt.c | 653 +++++++++++++++++++++++++++++++++++++
 2 files changed, 653 insertions(+), 653 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5398dddfa..6dc30e389 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3897,659 +3897,6 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
-/* Functions to read and write CSB fields from the kernel. */
-#if defined (linux)
-#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
-#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
-#else  /* ! linux */
-#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
-#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
-#endif /* ! linux */
-
-/* Write kring pointers (hwcur, hwtail) to the CSB.
- * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
-static inline void
-sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
-			   uint32_t hwtail)
-{
-	/*
-	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
-	 * We allow the application to read a value of hwcur more recent than the value
-	 * of hwtail, since this would anyway result in a consistent view of the
-	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
-	 * behind head).
-	 *
-	 * The following memory barrier scheme is used to make this happen:
-	 *
-	 *          Application          Kernel
-	 *
-	 *          STORE(hwcur)         LOAD(hwtail)
-	 *          mb() <-------------> mb()
-	 *          STORE(hwtail)        LOAD(hwcur)
-	 */
-	CSB_WRITE(ptr, hwcur, hwcur);
-	mb();
-	CSB_WRITE(ptr, hwtail, hwtail);
-}
-
-/* Read kring pointers (head, cur, sync_flags) from the CSB.
- * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
-static inline void
-sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
-			  struct netmap_ring *shadow_ring,
-			  uint32_t num_slots)
-{
-	/*
-	 * We place a memory barrier to make sure that the update of head never
-	 * overtakes the update of cur.
-	 * (see explanation in ptnetmap_guest_write_kring_csb).
-	 */
-	CSB_READ(ptr, head, shadow_ring->head);
-	mb();
-	CSB_READ(ptr, cur, shadow_ring->cur);
-	CSB_READ(ptr, sync_flags, shadow_ring->flags);
-}
-
-/* Enable or disable application --> kernel kicks. */
-static inline void
-csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
-{
-	CSB_WRITE(csb_ktoa, kern_need_kick, val);
-}
-
-/* Are application interrupt enabled or disabled? */
-static inline uint32_t
-csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
-{
-	uint32_t v;
-
-	CSB_READ(csb_atok, appl_need_kick, v);
-
-	return v;
-}
-
-static inline void
-sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
-{
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
-		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
-		kring->rhead, kring->rcur, kring->rtail);
-}
-
-#define SYNC_KLOOP_POLL
-struct sync_kloop_ring_args {
-	struct netmap_kring *kring;
-	struct nm_csb_atok *csb_atok;
-	struct nm_csb_ktoa *csb_ktoa;
-#ifdef SYNC_KLOOP_POLL
-	struct eventfd_ctx *irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-};
-
-static void
-netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
-{
-	struct netmap_kring *kring = a->kring;
-	struct nm_csb_atok *csb_atok = a->csb_atok;
-	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
-	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-	bool more_txspace = false;
-	uint32_t num_slots;
-	int batch;
-
-	num_slots = kring->nkr_num_slots;
-
-	/* Disable application --> kernel notifications. */
-	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the application kring pointers from the CSB */
-	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-
-	for (;;) {
-		batch = shadow_ring.head - kring->nr_hwcur;
-		if (batch < 0)
-			batch += num_slots;
-
-#ifdef PTN_TX_BATCH_LIM
-		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
-			/* If application moves ahead too fast, let's cut the move so
-			 * that we don't exceed our batch limit. */
-			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
-
-			if (head_lim >= num_slots)
-				head_lim -= num_slots;
-			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
-					head_lim);
-			shadow_ring.head = head_lim;
-			batch = PTN_TX_BATCH_LIM(num_slots);
-		}
-#endif /* PTN_TX_BATCH_LIM */
-
-		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
-			shadow_ring.flags |= NAF_FORCE_RECLAIM;
-		}
-
-		/* Netmap prologue */
-		shadow_ring.tail = kring->rtail;
-		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
-			/* Reinit ring and enable notifications. */
-			netmap_ring_reinit(kring);
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			break;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-			sync_kloop_kring_dump("pre txsync", kring);
-		}
-
-		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			D("ERROR txsync()");
-			break;
-		}
-
-		/*
-		 * Finalize
-		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
-		 * do the nm_sync_finalize.
-		 */
-		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
-				kring->nr_hwtail);
-		if (kring->rtail != kring->nr_hwtail) {
-			/* Some more room available in the parent adapter. */
-			kring->rtail = kring->nr_hwtail;
-			more_txspace = true;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-			sync_kloop_kring_dump("post txsync", kring);
-		}
-
-		/* Interrupt the application if needed. */
-#ifdef SYNC_KLOOP_POLL
-		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable application kick to avoid sending unnecessary kicks */
-			eventfd_signal(a->irq_ctx, 1);
-			more_txspace = false;
-		}
-#endif /* SYNC_KLOOP_POLL */
-
-		/* Read CSB to see if there is more work to do. */
-		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-		if (shadow_ring.head == kring->rhead) {
-			/*
-			 * No more packets to transmit. We enable notifications and
-			 * go to sleep, waiting for a kick from the application when new
-			 * new slots are ready for transmission.
-			 */
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			/* Doublecheck. */
-			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-			if (shadow_ring.head != kring->rhead) {
-				/* We won the race condition, there are more packets to
-				 * transmit. Disable notifications and do another cycle */
-				csb_ktoa_kick_enable(csb_ktoa, 0);
-				continue;
-			}
-			break;
-		}
-
-		if (nm_kr_txempty(kring)) {
-			/* No more available TX slots. We stop waiting for a notification
-			 * from the backend (netmap_tx_irq). */
-			ND(1, "TX ring");
-			break;
-		}
-	}
-
-#ifdef SYNC_KLOOP_POLL
-	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
-		eventfd_signal(a->irq_ctx, 1);
-	}
-#endif /* SYNC_KLOOP_POLL */
-}
-
-/* RX cycle without receive any packets */
-#define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
-
-static inline int
-sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
-{
-	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
-				kring->nkr_num_slots - 1));
-}
-
-static void
-netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
-{
-
-	struct netmap_kring *kring = a->kring;
-	struct nm_csb_atok *csb_atok = a->csb_atok;
-	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
-	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-	int dry_cycles = 0;
-	bool some_recvd = false;
-	uint32_t num_slots;
-
-	num_slots = kring->nkr_num_slots;
-
-	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
-	num_slots = kring->nkr_num_slots;
-
-	/* Disable notifications. */
-	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the application kring pointers from the CSB */
-	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-
-	for (;;) {
-		uint32_t hwtail;
-
-		/* Netmap prologue */
-		shadow_ring.tail = kring->rtail;
-		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
-			/* Reinit ring and enable notifications. */
-			netmap_ring_reinit(kring);
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			break;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-			sync_kloop_kring_dump("pre rxsync", kring);
-		}
-
-		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			D("ERROR rxsync()");
-			break;
-		}
-
-		/*
-		 * Finalize
-		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
-		 */
-		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
-		if (kring->rtail != hwtail) {
-			kring->rtail = hwtail;
-			some_recvd = true;
-			dry_cycles = 0;
-		} else {
-			dry_cycles++;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-			sync_kloop_kring_dump("post rxsync", kring);
-		}
-
-#ifdef SYNC_KLOOP_POLL
-		/* Interrupt the application if needed. */
-		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable application kick to avoid sending unnecessary kicks */
-			eventfd_signal(a->irq_ctx, 1);
-			some_recvd = false;
-		}
-#endif /* SYNC_KLOOP_POLL */
-
-		/* Read CSB to see if there is more work to do. */
-		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
-			/*
-			 * No more slots available for reception. We enable notification and
-			 * go to sleep, waiting for a kick from the application when new receive
-			 * slots are available.
-			 */
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			/* Doublecheck. */
-			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
-				/* We won the race condition, more slots are available. Disable
-				 * notifications and do another cycle. */
-				csb_ktoa_kick_enable(csb_ktoa, 0);
-				continue;
-			}
-			break;
-		}
-
-		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-		if (unlikely(hwtail == kring->rhead ||
-					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
-			/* No more packets to be read from the backend. We stop and
-			 * wait for a notification from the backend (netmap_rx_irq). */
-			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
-					hwtail, kring->rhead, dry_cycles);
-			break;
-		}
-	}
-
-	nm_kr_put(kring);
-
-#ifdef SYNC_KLOOP_POLL
-	/* Interrupt the application if needed. */
-	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
-		eventfd_signal(a->irq_ctx, 1);
-	}
-#endif /* SYNC_KLOOP_POLL */
-}
-
-#ifdef SYNC_KLOOP_POLL
-#include 
-struct sync_kloop_poll_entry {
-	/* Support for receiving notifications from
-	 * a netmap ring or from the application. */
-	struct file *filp;
-	wait_queue_entry_t wait;
-	wait_queue_head_t *wqh;
-
-	/* Support for sending notifications to the application. */
-	struct eventfd_ctx *irq_ctx;
-	struct file *irq_filp;
-};
-
-struct sync_kloop_poll_ctx {
-	poll_table wait_table;
-	unsigned int next_entry;
-	unsigned int num_entries;
-	struct sync_kloop_poll_entry entries[0];
-};
-
-static void
-sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
-				poll_table *pt)
-{
-	struct sync_kloop_poll_ctx *poll_ctx =
-		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
-	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
-						poll_ctx->next_entry;
-
-	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
-	entry->wqh = wqh;
-	entry->filp = file;
-	/* Use the default wake up function. */
-	init_waitqueue_entry(&entry->wait, current);
-	add_wait_queue(wqh, &entry->wait);
-	poll_ctx->next_entry++;
-	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
-}
-#endif  /* SYNC_KLOOP_POLL */
-
-int
-netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
-{
-	struct nmreq_sync_kloop_start *req =
-		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
-	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
-#ifdef SYNC_KLOOP_POLL
-	struct sync_kloop_poll_ctx *poll_ctx = NULL;
-#endif  /* SYNC_KLOOP_POLL */
-	int num_rx_rings, num_tx_rings, num_rings;
-	uint32_t sleep_us = req->sleep_us;
-	struct nm_csb_atok* csb_atok_base;
-	struct nm_csb_ktoa* csb_ktoa_base;
-	struct netmap_adapter *na;
-	struct nmreq_option *opt;
-	int err = 0;
-	int i;
-
-	if (sleep_us > 1000000) {
-		/* We do not accept sleeping for more than a second. */
-		return EINVAL;
-	}
-
-	if (priv->np_nifp == NULL) {
-		return ENXIO;
-	}
-	mb(); /* make sure following reads are not from cache */
-
-	na = priv->np_na;
-	if (!nm_netmap_on(na)) {
-		return ENXIO;
-	}
-
-	if (!(priv->np_flags & NR_EXCLUSIVE)) {
-		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
-		return EINVAL;
-	}
-
-	/* Make sure that no kloop is currently running. */
-	NMG_LOCK();
-	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
-		err = EBUSY;
-	}
-	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
-	NMG_UNLOCK();
-	if (err) {
-		return err;
-	}
-
-	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
-	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
-	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
-	num_rings = num_tx_rings + num_rx_rings;
-
-	/* Validate the CSB entries for both directions (atok and ktoa). */
-	{
-		if (num_rings > 0) {
-			size_t entry_size[2];
-			void *csb_start[2];
-
-			entry_size[0] = sizeof(*csb_atok_base);
-			entry_size[1] = sizeof(*csb_ktoa_base);
-			csb_start[0] = (void *)csb_atok_base;
-			csb_start[1] = (void *)csb_ktoa_base;
-
-			for (i = 0; i < 2; i++) {
-				/* On Linux we could use access_ok() to simplify
-				 * the validation. However, the advantage of
-				 * this approach is that it works also on
-				 * FreeBSD. */
-				size_t csb_size = num_rings * entry_size[i];
-				void *tmp;
-
-				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
-					nm_prerr("Unaligned CSB address\n");
-					err = EINVAL;
-					goto out;
-				}
-
-				tmp = nm_os_malloc(csb_size);
-				if (!tmp) {
-					err = ENOMEM;
-					goto out;
-				}
-				if (i == 0) {
-					/* Application --> kernel direction. */
-					err = copyin(csb_start[i], tmp, csb_size);
-				} else {
-					/* Kernel --> application direction. */
-					memset(tmp, 0, csb_size);
-					err = copyout(tmp, csb_start[i], csb_size);
-				}
-				nm_os_free(tmp);
-				if (err) {
-					nm_prerr("Invalid CSB address\n");
-					goto out;
-				}
-			}
-		}
-	}
-
-	/* Validate notification options. */
-	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
-	if (opt != NULL) {
-		NM_SELINFO_T *si[NR_TXRX];
-
-		err = nmreq_checkduplicate(opt);
-		if (err) {
-			opt->nro_status = err;
-			goto out;
-		}
-		if (opt->nro_size != sizeof(*eventfds_opt) +
-			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
-			/* Option size not consistent with the number of
-			 * entries. */
-			opt->nro_status = err = EINVAL;
-			goto out;
-		}
-#ifdef SYNC_KLOOP_POLL
-		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
-		opt->nro_status = 0;
-		/* We need 2 poll entries for TX and RX notifications coming
-		 * from the netmap adapter, plus one entries per ring for the
-		 * notifications coming from the application. */
-		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
-				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
-		init_poll_funcptr(&poll_ctx->wait_table,
-					sync_kloop_poll_table_queue_proc);
-		poll_ctx->num_entries = 2 + num_rings;
-		poll_ctx->next_entry = 0;
-		/* Poll for notifications coming from the applications through
-		 * eventfds . */
-		for (i = 0; i < num_rings; i++) {
-			struct eventfd_ctx *irq;
-			struct file *filp;
-			unsigned long mask;
-
-			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
-			if (IS_ERR(filp)) {
-				err = PTR_ERR(filp);
-				goto out;
-			}
-			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
-			if (mask & POLLERR) {
-				err = EINVAL;
-				goto out;
-			}
-
-			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
-			if (IS_ERR(filp)) {
-				err = PTR_ERR(filp);
-				goto out;
-			}
-			poll_ctx->entries[i].irq_filp = filp;
-			irq = eventfd_ctx_fileget(filp);
-			if (IS_ERR(irq)) {
-				err = PTR_ERR(irq);
-				goto out;
-			}
-			poll_ctx->entries[i].irq_ctx = irq;
-		}
-		/* Poll for notifications coming from the netmap rings bound to
-		 * this file descriptor. */
-		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
-		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
-#else   /* SYNC_KLOOP_POLL */
-		opt->nro_status = EOPNOTSUPP;
-		goto out;
-#endif  /* SYNC_KLOOP_POLL */
-	}
-
-	/* Main loop. */
-	for (;;) {
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
-			__set_current_state(TASK_INTERRUPTIBLE);
-#endif  /* SYNC_KLOOP_POLL */
-
-		/* Process all the TX rings bound to this file descriptor. */
-		for (i = 0; i < num_tx_rings; i++) {
-			struct sync_kloop_ring_args a = {
-				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
-				.csb_atok = csb_atok_base + i,
-				.csb_ktoa = csb_ktoa_base + i,
-			};
-
-#ifdef SYNC_KLOOP_POLL
-			if (poll_ctx)
-				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
-				continue;
-			}
-			netmap_sync_kloop_tx_ring(&a);
-			nm_kr_put(a.kring);
-		}
-
-		/* Process all the RX rings bound to this file descriptor. */
-		for (i = 0; i < num_rx_rings; i++) {
-			struct sync_kloop_ring_args a = {
-				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
-				.csb_atok = csb_atok_base + num_tx_rings + i,
-				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
-			};
-
-#ifdef SYNC_KLOOP_POLL
-			if (poll_ctx)
-				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-
-			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
-				continue;
-			}
-			netmap_sync_kloop_rx_ring(&a);
-			nm_kr_put(a.kring);
-		}
-
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx) {
-			/* If a poll context is present, yield to the scheduler
-			 * waiting for a notification to come either from
-			 * netmap or the application. */
-			schedule_timeout_interruptible(msecs_to_jiffies(1000));
-		} else
-#endif /* SYNC_KLOOP_POLL */
-		{
-			/* Default synchronization method: sleep for a while. */
-			usleep_range(sleep_us, sleep_us);
-		}
-
-		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
-			break;
-		}
-	}
-out:
-#ifdef SYNC_KLOOP_POLL
-	if (poll_ctx) {
-		/* Stop polling from netmap and the eventfds, and deallocate
-		 * the poll context. */
-		__set_current_state(TASK_RUNNING);
-		for (i = 0; i < poll_ctx->next_entry; i++) {
-			struct sync_kloop_poll_entry *entry =
-						poll_ctx->entries + i;
-
-			if (entry->wqh)
-				remove_wait_queue(entry->wqh, &entry->wait);
-			/* We did not get a reference to the eventfds, but
-			 * don't do that on netmap file descriptors (since
-			 * a reference was not taken. */
-			if (entry->filp && entry->filp != priv->np_filp)
-				fput(entry->filp);
-			if (entry->irq_ctx)
-				eventfd_ctx_put(entry->irq_ctx);
-			if (entry->irq_filp)
-				fput(entry->irq_filp);
-		}
-		nm_os_free(poll_ctx);
-		poll_ctx = NULL;
-	}
-#endif /* SYNC_KLOOP_POLL */
-
-	/* Reset the kloop state. */
-	NMG_LOCK();
-	priv->np_kloop_state = 0;
-	NMG_UNLOCK();
-
-	return err;
-}
-
 /*
  * Module loader and unloader
  *
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 3f4aa9a28..4d5120238 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -43,6 +43,7 @@
 
 #elif defined(linux)
 #include 
+#include 
 #endif
 
 #include 
@@ -50,6 +51,658 @@
 #include 
 #include 
 
+/* Functions to read and write CSB fields from the kernel. */
+#if defined (linux)
+#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
+#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
+#else  /* ! linux */
+#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
+#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
+#endif /* ! linux */
+
+/* Write kring pointers (hwcur, hwtail) to the CSB.
+ * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
+static inline void
+sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
+			   uint32_t hwtail)
+{
+	/*
+	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
+	 * We allow the application to read a value of hwcur more recent than the value
+	 * of hwtail, since this would anyway result in a consistent view of the
+	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
+	 * behind head).
+	 *
+	 * The following memory barrier scheme is used to make this happen:
+	 *
+	 *          Application          Kernel
+	 *
+	 *          STORE(hwcur)         LOAD(hwtail)
+	 *          mb() <-------------> mb()
+	 *          STORE(hwtail)        LOAD(hwcur)
+	 */
+	CSB_WRITE(ptr, hwcur, hwcur);
+	mb();
+	CSB_WRITE(ptr, hwtail, hwtail);
+}
+
+/* Read kring pointers (head, cur, sync_flags) from the CSB.
+ * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
+static inline void
+sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
+			  struct netmap_ring *shadow_ring,
+			  uint32_t num_slots)
+{
+	/*
+	 * We place a memory barrier to make sure that the update of head never
+	 * overtakes the update of cur.
+	 * (see explanation in ptnetmap_guest_write_kring_csb).
+	 */
+	CSB_READ(ptr, head, shadow_ring->head);
+	mb();
+	CSB_READ(ptr, cur, shadow_ring->cur);
+	CSB_READ(ptr, sync_flags, shadow_ring->flags);
+}
+
+/* Enable or disable application --> kernel kicks. */
+static inline void
+csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
+{
+	CSB_WRITE(csb_ktoa, kern_need_kick, val);
+}
+
+/* Are application interrupt enabled or disabled? */
+static inline uint32_t
+csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
+{
+	uint32_t v;
+
+	CSB_READ(csb_atok, appl_need_kick, v);
+
+	return v;
+}
+
+static inline void
+sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
+{
+	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
+		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
+		kring->rhead, kring->rcur, kring->rtail);
+}
+
+#define SYNC_KLOOP_POLL
+struct sync_kloop_ring_args {
+	struct netmap_kring *kring;
+	struct nm_csb_atok *csb_atok;
+	struct nm_csb_ktoa *csb_ktoa;
+#ifdef SYNC_KLOOP_POLL
+	struct eventfd_ctx *irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+};
+
+static void
+netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
+{
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	bool more_txspace = false;
+	uint32_t num_slots;
+	int batch;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable application --> kernel notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the application kring pointers from the CSB */
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		batch = shadow_ring.head - kring->nr_hwcur;
+		if (batch < 0)
+			batch += num_slots;
+
+#ifdef PTN_TX_BATCH_LIM
+		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
+			/* If application moves ahead too fast, let's cut the move so
+			 * that we don't exceed our batch limit. */
+			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
+
+			if (head_lim >= num_slots)
+				head_lim -= num_slots;
+			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
+					head_lim);
+			shadow_ring.head = head_lim;
+			batch = PTN_TX_BATCH_LIM(num_slots);
+		}
+#endif /* PTN_TX_BATCH_LIM */
+
+		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
+			shadow_ring.flags |= NAF_FORCE_RECLAIM;
+		}
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("pre txsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR txsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
+		 * do the nm_sync_finalize.
+		 */
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
+				kring->nr_hwtail);
+		if (kring->rtail != kring->nr_hwtail) {
+			/* Some more room available in the parent adapter. */
+			kring->rtail = kring->nr_hwtail;
+			more_txspace = true;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("post txsync", kring);
+		}
+
+		/* Interrupt the application if needed. */
+#ifdef SYNC_KLOOP_POLL
+		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable application kick to avoid sending unnecessary kicks */
+			eventfd_signal(a->irq_ctx, 1);
+			more_txspace = false;
+		}
+#endif /* SYNC_KLOOP_POLL */
+
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+		if (shadow_ring.head == kring->rhead) {
+			/*
+			 * No more packets to transmit. We enable notifications and
+			 * go to sleep, waiting for a kick from the application when new
+			 * new slots are ready for transmission.
+			 */
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+			if (shadow_ring.head != kring->rhead) {
+				/* We won the race condition, there are more packets to
+				 * transmit. Disable notifications and do another cycle */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		if (nm_kr_txempty(kring)) {
+			/* No more available TX slots. We stop waiting for a notification
+			 * from the backend (netmap_tx_irq). */
+			ND(1, "TX ring");
+			break;
+		}
+	}
+
+#ifdef SYNC_KLOOP_POLL
+	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
+	}
+#endif /* SYNC_KLOOP_POLL */
+}
+
+/* RX cycle without receive any packets */
+#define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
+
+static inline int
+sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
+{
+	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
+				kring->nkr_num_slots - 1));
+}
+
+static void
+netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
+{
+
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	int dry_cycles = 0;
+	bool some_recvd = false;
+	uint32_t num_slots;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the application kring pointers from the CSB */
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		uint32_t hwtail;
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("pre rxsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR rxsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
+		 */
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
+		if (kring->rtail != hwtail) {
+			kring->rtail = hwtail;
+			some_recvd = true;
+			dry_cycles = 0;
+		} else {
+			dry_cycles++;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("post rxsync", kring);
+		}
+
+#ifdef SYNC_KLOOP_POLL
+		/* Interrupt the application if needed. */
+		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable application kick to avoid sending unnecessary kicks */
+			eventfd_signal(a->irq_ctx, 1);
+			some_recvd = false;
+		}
+#endif /* SYNC_KLOOP_POLL */
+
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
+			/*
+			 * No more slots available for reception. We enable notification and
+			 * go to sleep, waiting for a kick from the application when new receive
+			 * slots are available.
+			 */
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
+				/* We won the race condition, more slots are available. Disable
+				 * notifications and do another cycle. */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		if (unlikely(hwtail == kring->rhead ||
+					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
+			/* No more packets to be read from the backend. We stop and
+			 * wait for a notification from the backend (netmap_rx_irq). */
+			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
+					hwtail, kring->rhead, dry_cycles);
+			break;
+		}
+	}
+
+	nm_kr_put(kring);
+
+#ifdef SYNC_KLOOP_POLL
+	/* Interrupt the application if needed. */
+	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
+	}
+#endif /* SYNC_KLOOP_POLL */
+}
+
+#ifdef SYNC_KLOOP_POLL
+struct sync_kloop_poll_entry {
+	/* Support for receiving notifications from
+	 * a netmap ring or from the application. */
+	struct file *filp;
+	wait_queue_entry_t wait;
+	wait_queue_head_t *wqh;
+
+	/* Support for sending notifications to the application. */
+	struct eventfd_ctx *irq_ctx;
+	struct file *irq_filp;
+};
+
+struct sync_kloop_poll_ctx {
+	poll_table wait_table;
+	unsigned int next_entry;
+	unsigned int num_entries;
+	struct sync_kloop_poll_entry entries[0];
+};
+
+static void
+sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
+				poll_table *pt)
+{
+	struct sync_kloop_poll_ctx *poll_ctx =
+		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
+	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
+						poll_ctx->next_entry;
+
+	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
+	entry->wqh = wqh;
+	entry->filp = file;
+	/* Use the default wake up function. */
+	init_waitqueue_entry(&entry->wait, current);
+	add_wait_queue(wqh, &entry->wait);
+	poll_ctx->next_entry++;
+	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
+}
+#endif  /* SYNC_KLOOP_POLL */
+
+int
+netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
+{
+	struct nmreq_sync_kloop_start *req =
+		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
+	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
+#ifdef SYNC_KLOOP_POLL
+	struct sync_kloop_poll_ctx *poll_ctx = NULL;
+#endif  /* SYNC_KLOOP_POLL */
+	int num_rx_rings, num_tx_rings, num_rings;
+	uint32_t sleep_us = req->sleep_us;
+	struct nm_csb_atok* csb_atok_base;
+	struct nm_csb_ktoa* csb_ktoa_base;
+	struct netmap_adapter *na;
+	struct nmreq_option *opt;
+	int err = 0;
+	int i;
+
+	if (sleep_us > 1000000) {
+		/* We do not accept sleeping for more than a second. */
+		return EINVAL;
+	}
+
+	if (priv->np_nifp == NULL) {
+		return ENXIO;
+	}
+	mb(); /* make sure following reads are not from cache */
+
+	na = priv->np_na;
+	if (!nm_netmap_on(na)) {
+		return ENXIO;
+	}
+
+	if (!(priv->np_flags & NR_EXCLUSIVE)) {
+		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
+		return EINVAL;
+	}
+
+	/* Make sure that no kloop is currently running. */
+	NMG_LOCK();
+	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
+		err = EBUSY;
+	}
+	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
+	NMG_UNLOCK();
+	if (err) {
+		return err;
+	}
+
+	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
+	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+	num_rings = num_tx_rings + num_rx_rings;
+
+	/* Validate the CSB entries for both directions (atok and ktoa). */
+	{
+		if (num_rings > 0) {
+			size_t entry_size[2];
+			void *csb_start[2];
+
+			entry_size[0] = sizeof(*csb_atok_base);
+			entry_size[1] = sizeof(*csb_ktoa_base);
+			csb_start[0] = (void *)csb_atok_base;
+			csb_start[1] = (void *)csb_ktoa_base;
+
+			for (i = 0; i < 2; i++) {
+				/* On Linux we could use access_ok() to simplify
+				 * the validation. However, the advantage of
+				 * this approach is that it works also on
+				 * FreeBSD. */
+				size_t csb_size = num_rings * entry_size[i];
+				void *tmp;
+
+				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
+					nm_prerr("Unaligned CSB address\n");
+					err = EINVAL;
+					goto out;
+				}
+
+				tmp = nm_os_malloc(csb_size);
+				if (!tmp) {
+					err = ENOMEM;
+					goto out;
+				}
+				if (i == 0) {
+					/* Application --> kernel direction. */
+					err = copyin(csb_start[i], tmp, csb_size);
+				} else {
+					/* Kernel --> application direction. */
+					memset(tmp, 0, csb_size);
+					err = copyout(tmp, csb_start[i], csb_size);
+				}
+				nm_os_free(tmp);
+				if (err) {
+					nm_prerr("Invalid CSB address\n");
+					goto out;
+				}
+			}
+		}
+	}
+
+	/* Validate notification options. */
+	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
+	if (opt != NULL) {
+		NM_SELINFO_T *si[NR_TXRX];
+
+		err = nmreq_checkduplicate(opt);
+		if (err) {
+			opt->nro_status = err;
+			goto out;
+		}
+		if (opt->nro_size != sizeof(*eventfds_opt) +
+			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
+			/* Option size not consistent with the number of
+			 * entries. */
+			opt->nro_status = err = EINVAL;
+			goto out;
+		}
+#ifdef SYNC_KLOOP_POLL
+		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
+		opt->nro_status = 0;
+		/* We need 2 poll entries for TX and RX notifications coming
+		 * from the netmap adapter, plus one entries per ring for the
+		 * notifications coming from the application. */
+		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
+				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
+		init_poll_funcptr(&poll_ctx->wait_table,
+					sync_kloop_poll_table_queue_proc);
+		poll_ctx->num_entries = 2 + num_rings;
+		poll_ctx->next_entry = 0;
+		/* Poll for notifications coming from the applications through
+		 * eventfds . */
+		for (i = 0; i < num_rings; i++) {
+			struct eventfd_ctx *irq;
+			struct file *filp;
+			unsigned long mask;
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
+			if (mask & POLLERR) {
+				err = EINVAL;
+				goto out;
+			}
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_filp = filp;
+			irq = eventfd_ctx_fileget(filp);
+			if (IS_ERR(irq)) {
+				err = PTR_ERR(irq);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_ctx = irq;
+		}
+		/* Poll for notifications coming from the netmap rings bound to
+		 * this file descriptor. */
+		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
+		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
+#else   /* SYNC_KLOOP_POLL */
+		opt->nro_status = EOPNOTSUPP;
+		goto out;
+#endif  /* SYNC_KLOOP_POLL */
+	}
+
+	/* Main loop. */
+	for (;;) {
+#ifdef SYNC_KLOOP_POLL
+		if (poll_ctx)
+			__set_current_state(TASK_INTERRUPTIBLE);
+#endif  /* SYNC_KLOOP_POLL */
+
+		/* Process all the TX rings bound to this file descriptor. */
+		for (i = 0; i < num_tx_rings; i++) {
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
+				.csb_atok = csb_atok_base + i,
+				.csb_ktoa = csb_ktoa_base + i,
+			};
+
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
+				continue;
+			}
+			netmap_sync_kloop_tx_ring(&a);
+			nm_kr_put(a.kring);
+		}
+
+		/* Process all the RX rings bound to this file descriptor. */
+		for (i = 0; i < num_rx_rings; i++) {
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
+				.csb_atok = csb_atok_base + num_tx_rings + i,
+				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
+			};
+
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
+				continue;
+			}
+			netmap_sync_kloop_rx_ring(&a);
+			nm_kr_put(a.kring);
+		}
+
+#ifdef SYNC_KLOOP_POLL
+		if (poll_ctx) {
+			/* If a poll context is present, yield to the scheduler
+			 * waiting for a notification to come either from
+			 * netmap or the application. */
+			schedule_timeout_interruptible(msecs_to_jiffies(1000));
+		} else
+#endif /* SYNC_KLOOP_POLL */
+		{
+			/* Default synchronization method: sleep for a while. */
+			usleep_range(sleep_us, sleep_us);
+		}
+
+		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
+			break;
+		}
+	}
+out:
+#ifdef SYNC_KLOOP_POLL
+	if (poll_ctx) {
+		/* Stop polling from netmap and the eventfds, and deallocate
+		 * the poll context. */
+		__set_current_state(TASK_RUNNING);
+		for (i = 0; i < poll_ctx->next_entry; i++) {
+			struct sync_kloop_poll_entry *entry =
+						poll_ctx->entries + i;
+
+			if (entry->wqh)
+				remove_wait_queue(entry->wqh, &entry->wait);
+			/* We did not get a reference to the eventfds, but
+			 * don't do that on netmap file descriptors (since
+			 * a reference was not taken. */
+			if (entry->filp && entry->filp != priv->np_filp)
+				fput(entry->filp);
+			if (entry->irq_ctx)
+				eventfd_ctx_put(entry->irq_ctx);
+			if (entry->irq_filp)
+				fput(entry->irq_filp);
+		}
+		nm_os_free(poll_ctx);
+		poll_ctx = NULL;
+	}
+#endif /* SYNC_KLOOP_POLL */
+
+	/* Reset the kloop state. */
+	NMG_LOCK();
+	priv->np_kloop_state = 0;
+	NMG_UNLOCK();
+
+	return err;
+}
+
 #ifdef WITH_PTNETMAP_GUEST
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.

From 467db585d4e808aea38bab765a1144d5f7479cdd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 10:18:50 +0200
Subject: [PATCH 1226/2207] merge ptnetmap-host and ptnetmap-guest subsystems

---
 LINUX/Kbuild.in                 |  6 ++----
 LINUX/README                    |  7 +------
 LINUX/configure                 | 18 +++---------------
 LINUX/netmap_linux.c            | 12 ++++++------
 README.ptnetmap                 | 12 +++---------
 sys/dev/netmap/netmap.c         |  8 --------
 sys/dev/netmap/netmap_freebsd.c |  6 +++---
 sys/dev/netmap/netmap_kern.h    | 19 +++++++++++++------
 sys/dev/netmap/netmap_mem2.c    |  4 ++--
 sys/dev/netmap/netmap_mem2.h    |  4 ++--
 sys/dev/netmap/netmap_pt.c      |  4 ++--
 sys/net/netmap_virt.h           |  4 ++--
 12 files changed, 39 insertions(+), 65 deletions(-)

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index a2ce4966c..edcc31d7c 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,14 +8,12 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o netmap_pt.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
 remoteobjs-$(CONFIG_NETMAP_MONITOR) += netmap_monitor.o
 remoteobjs-$(CONFIG_NETMAP_GENERIC) += netmap_generic.o
-remoteobjs-ptnetmap-$(CONFIG_NETMAP_PTNETMAP_GUEST) = netmap_pt.o
-remoteobjs-y += $(remoteobjs-ptnetmap-y)
 
 define remote_template
 $$(obj)/$(1): %.o: $$(SRCDIR)/../sys/dev/netmap/$(2) FORCE
@@ -32,7 +30,7 @@ $(obj)/netmap_linux.o: %.o: $(SRCDIR)/netmap_linux.c FORCE
 # all objects
 $(MODNAME)-objs := $(remoteobjs-y) netmap_common.o netmap_linux.o
 
-ifdef CONFIG_NETMAP_PTNETMAP_GUEST
+ifdef CONFIG_NETMAP_PTNETMAP
 $(obj)/netmap_ptnet.o: %.o: $(SRCDIR)/netmap_ptnet.c FORCE
 	$(call if_changed_rule,cc_o_c)
 
diff --git a/LINUX/README b/LINUX/README
index 8225f1a6d..181d5cce5 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -91,14 +91,9 @@ features, namely:
 			used to access NICs without native netmap support (at
 			reduced performance).
 
-    ptnetmap-guest:	netmap passthrough support for guests
+    ptnetmap:		netmap passthrough support for guests
 			(including the ptnet driver).
 
-    ptnetmap-host:	netmap passthrough support for the host
-
-    ptnetmap:		shortcut to include both ptnetmap-guest and
-			ptnetmap-host.
-
     sink:		a dummy drop-everything device with native netmap
 			support.  It can emulate a link with configurable
 			packet rate.
diff --git a/LINUX/configure b/LINUX/configure
index 0252c8b0e..731127d0c 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -94,7 +94,7 @@ setop()
 }
 
 # available subsystems
-subsystem_avail="vale pipe monitor generic ptnetmap-guest ptnetmap-host sink \
+subsystem_avail="vale pipe monitor generic ptnetmap sink \
 	extmem"
 #enabled subsystems (bitfield)
 subsystem=0
@@ -317,12 +317,8 @@ Available options:
   --disable-monitor   	       disable the nemtap monitors
   --enable-generic   	       enable the generic netmap adapter
   --disable-generic   	       disable the generic netmap adapter
-  --enable-ptnetmap-guest      enable ptnetmap for guest kernel
-  --disable-ptnetmap-guest     disable ptnetmap for guest kernel
-  --enable-ptnetmap-host       enable ptnetmap for host kernel
-  --disable-ptnetmap-host      disable ptnetmap for host kernel
-  --enable-ptnetmap            enable ptnetmap (both guest and host)
-  --disable-ptnetmap           disable ptnetmap (both guest and host)
+  --enable-ptnetmap            enable ptnetmap
+  --disable-ptnetmap           disable ptnetmap
   --enable-sink   	       enable the netmap sink device
   --disable-sink   	       disable the netmap sink device
   --enable-extmem   	       enable the external memory allocators
@@ -613,14 +609,6 @@ for opt do
 	;;
 	--mod-name=*) MODNAME="$optarg"
 	;;
-	--enable-ptnetmap)
-		subsys enable ptnetmap-guest
-		subsys enable ptnetmap-host
-	;;
-	--disable-ptnetmap)
-		subsys disable ptnetmap-guest
-		subsys disable ptnetmap-host
-	;;
 	--disable-*)
 		subsys disable "${opt#--disable-}"
 	;;
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0b354e903..86d188ab5 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1980,8 +1980,8 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 	kfree(nmk);
 }
 
-/* ##################### PTNETMAP SUPPORT ##################### */
-#ifdef WITH_PTNETMAP_GUEST
+/* ################## PTNETMAP GUEST SUPPORT ################## */
+#ifdef WITH_PTNETMAP
 /*
  * ptnetmap memory device (memdev) for linux guest
  * Used to expose host memory to the guest through PCI-BAR
@@ -2204,10 +2204,10 @@ ptnetmap_guest_fini(void)
 	pci_unregister_driver(&ptnetmap_guest_drivers);
 }
 
-#else /* !WITH_PTNETMAP_GUEST */
+#else /* !WITH_PTNETMAP */
 #define ptnetmap_guest_init()		0
 #define ptnetmap_guest_fini()
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 #ifdef WITH_SINK
 
@@ -2655,12 +2655,12 @@ EXPORT_SYMBOL(__netmap_adapter_put);
 EXPORT_SYMBOL(netmap_adapter_get);
 EXPORT_SYMBOL(netmap_adapter_put);
 #endif /* NM_DEBUG_PUTGET */
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 EXPORT_SYMBOL(netmap_pt_guest_attach);	/* ptnetmap driver attach routine */
 EXPORT_SYMBOL(netmap_pt_guest_rxsync);	/* ptnetmap generic rxsync */
 EXPORT_SYMBOL(netmap_pt_guest_txsync);	/* ptnetmap generic txsync */
 EXPORT_SYMBOL(netmap_mem_pt_guest_ifp_del); /* unlink passthrough interface */
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 EXPORT_SYMBOL(netmap_detach);		/* driver detach routines */
 EXPORT_SYMBOL(netmap_ring_reinit);	/* ring init on error */
 EXPORT_SYMBOL(netmap_reset);		/* ring init routines */
diff --git a/README.ptnetmap b/README.ptnetmap
index e2e7b80e8..1b285473a 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap
@@ -44,16 +44,11 @@ and in section 7 of this document.
 2. Configure Linux host and QEMU for ptnetmap
 ---------------------------------------------------------------------------
 
-(Warning! For ptnetmap use v11.4.
-In the current master, ptnetmap is disabled.
-Support for the current master will be re-added as soon as possible)
-
-On the Linux host, configure, build and install netmap with ptnetmap support:
+On the Linux host, configure, build and install netmap normally:
 
     $ git clone https://github.com/luigirizzo/netmap.git
     $ cd netmap
-    $ git checkout v11.4
-    $ ./configure --enable-ptnetmap [other options]
+    $ ./configure [options]
     $ make
     $ sudo make install
 
@@ -65,9 +60,8 @@ Download, build and install the ptnetmap-enabled QEMU:
     $ make
     $ sudo make install
 
-Load the ptnetmap-enabled netmap
+Load the netmap
 
-    $ sudo rmmod netmap  # Possibly remove a previous netmap module:
     $ sudo modprobe netmap
 
 Example to run a VM passing through a VALE port (vale1:10):
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6dc30e389..8339c4e53 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1031,14 +1031,6 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 	priv->np_nifp = NULL;
 }
 
-/* call with NMG_LOCK held */
-static __inline int
-nm_si_user(struct netmap_priv_d *priv, enum txrx t)
-{
-	return (priv->np_na != NULL &&
-		(priv->np_qlast[t] - priv->np_qfirst[t] > 1));
-}
-
 struct netmap_priv_d*
 netmap_priv_new(void)
 {
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 11f641fa6..2932f29c3 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -733,9 +733,9 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 }
 #endif /* WITH_EXTMEM */
 
-/* ======================== PTNETMAP SUPPORT ========================== */
+/* ================== PTNETMAP GUEST SUPPORT ==================== */
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 #include 
 #include 
 #include         /* bus_dmamap_* */
@@ -930,7 +930,7 @@ ptn_memdev_shutdown(device_t dev)
 	return bus_generic_shutdown(dev);
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 /*
  * In order to track whether pages are still mapped, we hook into
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4bd0dab6e..4ed869796 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -52,8 +52,8 @@
 #if defined(CONFIG_NETMAP_GENERIC)
 #define WITH_GENERIC
 #endif
-#if defined(CONFIG_NETMAP_PTNETMAP_GUEST)
-#define WITH_PTNETMAP_GUEST
+#if defined(CONFIG_NETMAP_PTNETMAP)
+#define WITH_PTNETMAP
 #endif
 #if defined(CONFIG_NETMAP_SINK)
 #define WITH_SINK
@@ -70,7 +70,7 @@
 #define WITH_PIPES
 #define WITH_MONITOR
 #define WITH_GENERIC
-#define WITH_PTNETMAP_GUEST	/* ptnetmap guest support */
+#define WITH_PTNETMAP	/* ptnetmap guest support */
 #define WITH_EXTMEM
 #endif
 
@@ -1436,7 +1436,6 @@ void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
 
-
 #ifdef WITH_VALE
 uint32_t netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *, void *private_data);
@@ -1902,6 +1901,14 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
 	return 0;
 }
 
+/* call with NMG_LOCK held */
+static __inline int
+nm_si_user(struct netmap_priv_d *priv, enum txrx t)
+{
+	return (priv->np_na != NULL &&
+		(priv->np_qlast[t] - priv->np_qfirst[t] > 1));
+}
+
 #ifdef WITH_PIPES
 int netmap_pipe_txsync(struct netmap_kring *txkring, int flags);
 int netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags);
@@ -2128,7 +2135,7 @@ u_int nm_os_ncpus(void);
 int netmap_sync_kloop(struct netmap_priv_d *priv,
 		      struct nmreq_header *hdr);
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 /* ptnetmap GUEST routines */
 
 /*
@@ -2165,7 +2172,7 @@ bool netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh,
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 #ifdef __FreeBSD__
 /*
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8334d5b1a..17ddea399 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2343,7 +2343,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 #endif /* WITH_EXTMEM */
 
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 struct mem_pt_if {
 	struct mem_pt_if *next;
 	struct ifnet *ifp;
@@ -2832,4 +2832,4 @@ netmap_mem_pt_guest_new(struct ifnet *ifp,
 	return nmd;
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 3fc48784d..9268024c6 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -156,14 +156,14 @@ struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *,
 	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
 #endif /* WITH_EXTMEM */
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,
 					     unsigned int nifp_offset,
 					     unsigned int memid);
 struct ptnetmap_memdev;
 struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16_t);
 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 int netmap_mem_pools_info_get(struct nmreq_pools_info *,
 				struct netmap_mem_d *);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 4d5120238..7c30554ca 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -703,7 +703,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	return err;
 }
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
  * These routines are reused across the different operating systems supported
@@ -933,4 +933,4 @@ netmap_pt_guest_attach(struct netmap_adapter *arg,
 	return 0;
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index cef32eed6..b6788051f 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -172,7 +172,7 @@ struct ptnet_csb_hg {
 	char pad[4+48];
 };
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 
 /* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */
 struct ptnetmap_memdev;
@@ -227,6 +227,6 @@ ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kr
     kring->nr_hwcur = pthg->hwcur;
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 #endif /* NETMAP_VIRT_H */

From 453596747107057d0c77a91c1beada69eb525982 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 10:30:46 +0200
Subject: [PATCH 1227/2207] sync-kloop: grab NMG lock to call nm_si_user()

---
 sys/dev/netmap/netmap_pt.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 7c30554ca..2a7e8916d 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -593,10 +593,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
+		NMG_LOCK();
 		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
 					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
 		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
 					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		NMG_UNLOCK();
 		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
 		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
 #else   /* SYNC_KLOOP_POLL */

From ac268b5636ab2135fa2fdd60895964b90f1b08b0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 11:56:41 +0200
Subject: [PATCH 1228/2207] ptnetmap: print interface name instead of ifp value

---
 sys/dev/netmap/netmap_mem2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 17ddea399..6d992a5ce 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2386,7 +2386,8 @@ netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
 
 	NMA_UNLOCK(nmd);
 
-	D("added (ifp=%p,nifp_offset=%u)", ptif->ifp, ptif->nifp_offset);
+	nm_prinf("added (ifp=%s,nifp_offset=%u)", ptif->ifp->if_xname,
+						ptif->nifp_offset);
 
 	return 0;
 }

From c36f77e3948023c8ca27807d4a8bb75bb64dd0d6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:20:47 +0200
Subject: [PATCH 1229/2207] ptnetmap: prune old guest code

---
 LINUX/netmap_linux.c         |   9 ++--
 LINUX/netmap_ptnet.c         | 100 +++++++++++++++++------------------
 sys/dev/netmap/if_ptnet.c    |  90 +++++++++++++++----------------
 sys/dev/netmap/netmap_kern.h |  13 ++---
 sys/dev/netmap/netmap_pt.c   |  42 +++++++--------
 sys/net/netmap_virt.h        |  92 +++-----------------------------
 6 files changed, 132 insertions(+), 214 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 86d188ab5..26e33884f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1784,7 +1784,6 @@ static int
 nm_kctx_open_files(struct nm_kctx *nmk, void *opaque)
 {
 	struct file *file;
-	struct ptnetmap_cfgentry_qemu *ring_cfg = opaque;
 
 	nmk->ioevent_file = NULL;
 	nmk->irq_file = NULL;
@@ -1793,15 +1792,15 @@ nm_kctx_open_files(struct nm_kctx *nmk, void *opaque)
 		return 0;
 	}
 
-	if (ring_cfg->ioeventfd) {
-		file = eventfd_fget(ring_cfg->ioeventfd);
+	if (0 /* TODO cleanup */) {
+		file = eventfd_fget(-1);
 		if (IS_ERR(file))
 			goto err;
 		nmk->ioevent_file = file;
 	}
 
-	if (ring_cfg->irqfd) {
-		file = eventfd_fget(ring_cfg->irqfd);
+	if (0 /* TODO cleanup */) {
+		file = eventfd_fget(-1);
 		if (IS_ERR(file))
 			goto err;
 		nmk->irq_file = file;
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index da3cf5f7a..ee50fd9a9 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -57,8 +57,8 @@ struct ptnet_info;
 /* Per-ring data structure. */
 struct ptnet_queue {
 	struct ptnet_info *pi;
-	struct ptnet_csb_gh *ptgh;
-	struct ptnet_csb_hg *pthg;
+	struct nm_csb_atok *atok;
+	struct nm_csb_ktoa *ktoa;
 	int kring_id;
 	u8* __iomem kick;
 
@@ -107,8 +107,8 @@ struct ptnet_info {
 	/* CSB memory to be used for producer/consumer state
 	 * synchronization. */
 	struct page *csb_pages;
-	struct ptnet_csb_gh *csb_gh;
-	struct ptnet_csb_hg *csb_hg;
+	struct nm_csb_atok *csb_gh;
+	struct nm_csb_ktoa *csb_hg;
 
 	int min_tx_slots;
 
@@ -131,9 +131,9 @@ hang_tmr_callback(unsigned long arg)
 	struct netmap_ring *ring = kring->ring;
 
 	pr_info("PTNET HANG RX#%d: hwc %u h %u c %u hwt %u t %u"
-		" rx.guest_need_kick %u\n",
+		" rx.appl_need_kick %u\n",
 		kring->ring_id, kring->nr_hwcur, ring->head, ring->cur,
-		kring->nr_hwtail, ring->tail, prq->q.ptgh->guest_need_kick);
+		kring->nr_hwtail, ring->tail, prq->q.atok->appl_need_kick);
 
 	if (mod_timer(&prq->hang_timer,
 		      jiffies + msecs_to_jiffies(HANG_INTVAL_MS))) {
@@ -143,12 +143,12 @@ hang_tmr_callback(unsigned long arg)
 #endif
 
 static inline void
-ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-	ptnetmap_guest_read_kring_csb(pthg, kring);
+	ptnetmap_guest_read_kring_csb(ktoa, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -216,8 +216,8 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	int queue_idx = skb_get_queue_mapping(skb);
 	struct ptnet_queue *pq = pi->queues[queue_idx];
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 	struct netmap_kring *kring;
 	struct xmit_copy_args a;
 	int f;
@@ -231,7 +231,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 	/* Update hwcur and hwtail (completed TX slots) as known by the host,
 	 * by reading from CSB. */
-	ptnet_sync_tail(pthg, kring);
+	ptnet_sync_tail(ktoa, kring);
 
 	if (unlikely(ptnet_tx_slots(a.ring) < pi->min_tx_slots)) {
 		ND(1, "TX ring unexpected overflow, requeuing");
@@ -324,13 +324,13 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	if (!XMIT_MORE(skb)) {
 		/* Tell the host to process the new packets, updating cur and
 		 * head in the CSB. */
-		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
+		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
 					       kring->rhead);
 	}
 
 	/* Ask for a kick from a guest to the host if needed. */
-	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-		ptgh->sync_flags = NAF_FORCE_RECLAIM;
+	if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+		atok->sync_flags = NAF_FORCE_RECLAIM;
 		iowrite32(0, pq->kick);
 	}
 
@@ -338,14 +338,14 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	 * qdisc layer and enable notifications. */
 	if (ptnet_tx_slots(a.ring) < pi->min_tx_slots) {
 		netif_stop_subqueue(netdev, pq->kring_id);
-		ptgh->guest_need_kick = 1;
+		atok->appl_need_kick = 1;
 
 		/* Double check. */
-		ptnet_sync_tail(pthg, kring);
+		ptnet_sync_tail(ktoa, kring);
 		if (unlikely(ptnet_tx_slots(a.ring) >= pi->min_tx_slots)) {
 			/* More TX space came in the meanwhile. */
 			netif_start_subqueue(netdev, pq->kring_id);
-			ptgh->guest_need_kick = 0;
+			atok->appl_need_kick = 0;
 		}
 	}
 
@@ -413,13 +413,13 @@ ptnet_napi_schedule(struct ptnet_queue *pq)
 	/* Disable RX interrupts and schedule NAPI. */
 
 	if (likely(napi_schedule_prep(&prq->napi))) {
-		/* It's good thing to reset rx.guest_need_kick as soon as
+		/* It's good thing to reset rx.appl_need_kick as soon as
 		 * possible. */
-		pq->ptgh->guest_need_kick = 0;
+		pq->atok->appl_need_kick = 0;
 		__napi_schedule(&prq->napi);
 	} else {
 		/* NAPI is already scheduled and we are ok with it. */
-		pq->ptgh->guest_need_kick = 1;
+		pq->atok->appl_need_kick = 1;
 	}
 }
 
@@ -476,8 +476,8 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 	struct ptnet_rx_queue *prq = container_of(napi, struct ptnet_rx_queue,
 					          napi);
 	struct ptnet_queue *pq = (struct ptnet_queue *)prq;
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 	struct ptnet_info *pi = pq->pi;
 	struct netmap_adapter *na = &pi->ptna->dr.up;
 	struct netmap_kring *kring = na->rx_rings[pq->kring_id];
@@ -504,7 +504,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 
 	/* Update hwtail, rtail, tail and hwcur to what is known from the host,
 	 * reading from CSB. */
-	ptnet_sync_tail(pthg, kring);
+	ptnet_sync_tail(ktoa, kring);
 
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
@@ -701,7 +701,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		/* Budget was not fully consumed, since we have no more
 		 * completed RX slots. We can enable notifications and
 		 * exit polling mode. */
-		ptgh->guest_need_kick = 1;
+		atok->appl_need_kick = 1;
 #ifdef NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE
 		napi_complete_done(napi, work_done);
 #else
@@ -709,7 +709,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 #endif
 
 		/* Double check for more completed RX slots. */
-		ptnet_sync_tail(pthg, kring);
+		ptnet_sync_tail(ktoa, kring);
 		if (head != ring->tail) {
 			/* If there is more work to do, disable notifications
 			 * and reschedule. */
@@ -730,11 +730,11 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		ring->head = ring->cur = head;
 		kring->rcur = ring->cur;
 		kring->rhead = ring->head;
-		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
+		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
 					       kring->rhead);
 		/* Kick the host if needed. */
-		if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-			ptgh->sync_flags = NAF_FORCE_READ;
+		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+			atok->sync_flags = NAF_FORCE_READ;
 			iowrite32(0, pq->kick);
 		}
 	}
@@ -1051,8 +1051,8 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < pi->num_rings; i++) {
-		struct ptnet_csb_gh *ptgh = pi->queues[i]->ptgh;
-		struct ptnet_csb_hg *pthg = pi->queues[i]->pthg;
+		struct nm_csb_atok *atok = pi->queues[i]->atok;
+		struct nm_csb_ktoa *ktoa = pi->queues[i]->ktoa;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1060,15 +1060,15 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings[i - na->num_tx_rings];
 		}
-		kring->rhead = kring->ring->head = ptgh->head;
-		kring->rcur = kring->ring->cur = ptgh->cur;
-		kring->nr_hwcur = pthg->hwcur;
+		kring->rhead = kring->ring->head = atok->head;
+		kring->rcur = kring->ring->cur = atok->cur;
+		kring->nr_hwcur = ktoa->hwcur;
 		kring->nr_hwtail = kring->rtail =
-			kring->ring->tail = pthg->hwtail;
+			kring->ring->tail = ktoa->hwtail;
 
 		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
-		   pthg->hwcur, ptgh->head, ptgh->cur,
-		   pthg->hwtail);
+		   ktoa->hwcur, atok->head, atok->cur,
+		   ktoa->hwtail);
 		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
@@ -1094,8 +1094,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	struct net_device *netdev = na->ifp;
 	struct ptnet_info *pi = netdev_priv(netdev);
 	int native = (na == &pi->ptna->hwup.up);
-	struct ptnet_csb_gh *ptgh;
-	struct ptnet_csb_hg *pthg;
+	struct nm_csb_atok *atok;
+	struct nm_csb_ktoa *ktoa;
 	enum txrx t;
 	int ret = 0;
 	int i;
@@ -1116,8 +1116,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		pr_info("%s: Exit netmap mode, re-enable interrupts\n",
 			__func__);
 		for (i = 0; i < pi->num_rings; i++) {
-			ptgh = pi->queues[i]->ptgh;
-			ptgh->guest_need_kick = 1;
+			atok = pi->queues[i]->atok;
+			atok->appl_need_kick = 1;
 		}
 		if (netif_running(netdev)) {
 			pr_info("%s: Exit netmap mode, schedule NAPI to flush RX ring\n",
@@ -1133,10 +1133,10 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		if (pi->ptna->backend_regifs == 0) {
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < pi->num_rings; i++) {
-				ptgh = pi->queues[i]->ptgh;
-				pthg = pi->queues[i]->pthg;
-				ptgh->guest_need_kick = (i >= pi->num_tx_rings);
-				pthg->host_need_kick = 1;
+				atok = pi->queues[i]->atok;
+				ktoa = pi->queues[i]->ktoa;
+				atok->appl_need_kick = (i >= pi->num_tx_rings);
+				ktoa->kern_need_kick = 1;
 			}
 
 			/* Set the virtio-net header length. */
@@ -1231,7 +1231,7 @@ ptnet_nm_txsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = pi->queues[kring->ring_id];
 	bool notify;
 
-	notify = netmap_pt_guest_txsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_txsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		iowrite32(0, pq->kick);
 	}
@@ -1246,7 +1246,7 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = pi->rxqueues[kring->ring_id];
 	bool notify;
 
-	notify = netmap_pt_guest_rxsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_rxsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		iowrite32(0, pq->kick);
 	}
@@ -1262,7 +1262,7 @@ ptnet_nm_intr(struct netmap_adapter *na, int onoff)
 
 	for (i = 0; i < pi->num_rings; i++) {
 		struct ptnet_queue *pq = pi->queues[i];
-		pq->ptgh->guest_need_kick = onoff;
+		pq->atok->appl_need_kick = onoff;
 	}
 }
 
@@ -1368,7 +1368,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	pi->num_rings = num_tx_rings + num_rx_rings;
 	pi->num_tx_rings = num_tx_rings;
 
-	if (pi->num_rings * sizeof(struct ptnet_csb_gh) > PAGE_SIZE) {
+	if (pi->num_rings * sizeof(struct nm_csb_atok) > PAGE_SIZE) {
 		pr_err("%s: CSB for device %s cannot handle too many "
 			"rings (%u)\n",__func__, netdev->name, pi->num_rings);
 		goto err_ptfeat;
@@ -1427,8 +1427,8 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			pq->kring_id -= num_tx_rings;
 		}
 		pq->kick = ioaddr + PTNET_IO_KICK_BASE + 4 * i;
-		pq->ptgh = pi->csb_gh + i;
-		pq->pthg = pi->csb_hg + i;
+		pq->atok = pi->csb_gh + i;
+		pq->ktoa = pi->csb_hg + i;
 	}
 
 	netdev->netdev_ops = &ptnet_netdev_ops;
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 55137f270..f429168da 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -128,8 +128,8 @@ struct ptnet_queue {
 	struct				resource *irq;
 	void				*cookie;
 	int				kring_id;
-	struct ptnet_csb_gh		*ptgh;
-	struct ptnet_csb_hg		*pthg;
+	struct nm_csb_atok		*atok;
+	struct nm_csb_ktoa		*ktoa;
 	unsigned int			kick;
 	struct mtx			lock;
 	struct buf_ring			*bufring; /* for TX queues */
@@ -166,8 +166,8 @@ struct ptnet_softc {
 	unsigned int		num_tx_rings;
 	struct ptnet_queue	*queues;
 	struct ptnet_queue	*rxqueues;
-	struct ptnet_csb_gh    *csb_gh;
-	struct ptnet_csb_hg    *csb_hg;
+	struct nm_csb_atok	*csb_gh;
+	struct nm_csb_ktoa	*csb_hg;
 
 	unsigned int		min_tx_space;
 
@@ -327,7 +327,7 @@ ptnet_attach(device_t dev)
 	sc->num_rings = num_tx_rings + num_rx_rings;
 	sc->num_tx_rings = num_tx_rings;
 
-	if (sc->num_rings * sizeof(struct ptnet_csb_gh) > PAGE_SIZE) {
+	if (sc->num_rings * sizeof(struct nm_csb_atok) > PAGE_SIZE) {
 		device_printf(dev, "CSB cannot handle that many rings (%u)\n",
 				sc->num_rings);
 		err = ENOMEM;
@@ -342,7 +342,7 @@ ptnet_attach(device_t dev)
 		err = ENOMEM;
 		goto err_path;
 	}
-	sc->csb_hg = (struct ptnet_csb_hg *)(((char *)sc->csb_gh) + PAGE_SIZE);
+	sc->csb_hg = (struct nm_csb_ktoa *)(((char *)sc->csb_gh) + PAGE_SIZE);
 
 	{
 		/*
@@ -379,8 +379,8 @@ ptnet_attach(device_t dev)
 		pq->sc = sc;
 		pq->kring_id = i;
 		pq->kick = PTNET_IO_KICK_BASE + 4 * i;
-		pq->ptgh = sc->csb_gh + i;
-		pq->pthg = sc->csb_hg + i;
+		pq->atok = sc->csb_gh + i;
+		pq->ktoa = sc->csb_hg + i;
 		snprintf(pq->lock_name, sizeof(pq->lock_name), "%s-%d",
 			 device_get_nameunit(dev), i);
 		mtx_init(&pq->lock, pq->lock_name, NULL, MTX_DEF);
@@ -796,7 +796,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 					/* Make sure the worker sees the
 					 * IFF_DRV_RUNNING down. */
 					PTNET_Q_LOCK(pq);
-					pq->ptgh->guest_need_kick = 0;
+					pq->atok->appl_need_kick = 0;
 					PTNET_Q_UNLOCK(pq);
 					/* Wait for rescheduling to finish. */
 					if (pq->taskq) {
@@ -810,7 +810,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 				for (i = 0; i < sc->num_rings; i++) {
 					pq = sc-> queues + i;
 					PTNET_Q_LOCK(pq);
-					pq->ptgh->guest_need_kick = 1;
+					pq->atok->appl_need_kick = 1;
 					PTNET_Q_UNLOCK(pq);
 				}
 			}
@@ -1130,8 +1130,8 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < sc->num_rings; i++) {
-		struct ptnet_csb_gh *ptgh = sc->queues[i].ptgh;
-		struct ptnet_csb_hg *pthg = sc->queues[i].pthg;
+		struct nm_csb_atok *atok = sc->queues[i].atok;
+		struct nm_csb_ktoa *ktoa = sc->queues[i].ktoa;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1139,15 +1139,15 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings[i - na->num_tx_rings];
 		}
-		kring->rhead = kring->ring->head = ptgh->head;
-		kring->rcur = kring->ring->cur = ptgh->cur;
-		kring->nr_hwcur = pthg->hwcur;
+		kring->rhead = kring->ring->head = atok->head;
+		kring->rcur = kring->ring->cur = atok->cur;
+		kring->nr_hwcur = ktoa->hwcur;
 		kring->nr_hwtail = kring->rtail =
-			kring->ring->tail = pthg->hwtail;
+			kring->ring->tail = ktoa->hwtail;
 
 		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
-		   pthg->hwcur, ptgh->head, ptgh->cur,
-		   pthg->hwtail);
+		   ktoa->hwcur, atok->head, atok->cur,
+		   ktoa->hwtail);
 		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
@@ -1191,7 +1191,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		D("Exit netmap mode, re-enable interrupts");
 		for (i = 0; i < sc->num_rings; i++) {
 			pq = sc->queues + i;
-			pq->ptgh->guest_need_kick = 1;
+			pq->atok->appl_need_kick = 1;
 		}
 	}
 
@@ -1200,8 +1200,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < sc->num_rings; i++) {
 				pq = sc->queues + i;
-				pq->pthg->host_need_kick = 1;
-				pq->ptgh->guest_need_kick =
+				pq->ktoa->kern_need_kick = 1;
+				pq->atok->appl_need_kick =
 					(!(ifp->if_capenable & IFCAP_POLLING)
 						&& i >= sc->num_tx_rings);
 			}
@@ -1279,7 +1279,7 @@ ptnet_nm_txsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = sc->queues + kring->ring_id;
 	bool notify;
 
-	notify = netmap_pt_guest_txsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_txsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		ptnet_kick(pq);
 	}
@@ -1294,7 +1294,7 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = sc->rxqueues + kring->ring_id;
 	bool notify;
 
-	notify = netmap_pt_guest_rxsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_rxsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		ptnet_kick(pq);
 	}
@@ -1310,7 +1310,7 @@ ptnet_nm_intr(struct netmap_adapter *na, int onoff)
 
 	for (i = 0; i < sc->num_rings; i++) {
 		struct ptnet_queue *pq = sc->queues + i;
-		pq->ptgh->guest_need_kick = onoff;
+		pq->atok->appl_need_kick = onoff;
 	}
 }
 
@@ -1677,12 +1677,12 @@ ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr)
 /* End of offloading-related functions to be shared with vtnet. */
 
 static inline void
-ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(pthg, kring);
+        ptnetmap_guest_read_kring_csb(ktoa, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -1693,8 +1693,8 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 		  unsigned int head, unsigned int sync_flags)
 {
 	struct netmap_ring *ring = kring->ring;
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 
 	/* Some packets have been pushed to the netmap ring. We have
 	 * to tell the host to process the new packets, updating cur
@@ -1704,11 +1704,11 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 	/* Mimic nm_txsync_prologue/nm_rxsync_prologue. */
 	kring->rcur = kring->rhead = head;
 
-	ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
+	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
 
 	/* Kick the host if needed. */
-	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-		ptgh->sync_flags = sync_flags;
+	if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+		atok->sync_flags = sync_flags;
 		ptnet_kick(pq);
 	}
 }
@@ -1728,8 +1728,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	if_t ifp = sc->ifp;
 	unsigned int batch_count = 0;
-	struct ptnet_csb_gh *ptgh;
-	struct ptnet_csb_hg *pthg;
+	struct nm_csb_atok *atok;
+	struct nm_csb_ktoa *ktoa;
 	struct netmap_kring *kring;
 	struct netmap_ring *ring;
 	struct netmap_slot *slot;
@@ -1758,8 +1758,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 		return ENETDOWN;
 	}
 
-	ptgh = pq->ptgh;
-	pthg = pq->pthg;
+	atok = pq->atok;
+	ktoa = pq->ktoa;
 	kring = na->tx_rings[pq->kring_id];
 	ring = kring->ring;
 	lim = kring->nkr_num_slots - 1;
@@ -1771,17 +1771,17 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 			/* We ran out of slot, let's see if the host has
 			 * freed up some, by reading hwcur and hwtail from
 			 * the CSB. */
-			ptnet_sync_tail(pthg, kring);
+			ptnet_sync_tail(ktoa, kring);
 
 			if (PTNET_TX_NOSPACE(head, kring, minspace)) {
 				/* Still no slots available. Reactivate the
 				 * interrupts so that we can be notified
 				 * when some free slots are made available by
 				 * the host. */
-				ptgh->guest_need_kick = 1;
+				atok->appl_need_kick = 1;
 
 				/* Double-check. */
-				ptnet_sync_tail(pthg, kring);
+				ptnet_sync_tail(ktoa, kring);
 				if (likely(PTNET_TX_NOSPACE(head, kring,
 							    minspace))) {
 					break;
@@ -1790,7 +1790,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 				RD(1, "Found more slots by doublecheck");
 				/* More slots were freed before reactivating
 				 * the interrupts. */
-				ptgh->guest_need_kick = 0;
+				atok->appl_need_kick = 0;
 			}
 		}
 
@@ -2020,8 +2020,8 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 {
 	struct ptnet_softc *sc = pq->sc;
 	bool have_vnet_hdr = sc->vnet_hdr_len;
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	struct netmap_kring *kring = na->rx_rings[pq->kring_id];
 	struct netmap_ring *ring = kring->ring;
@@ -2053,21 +2053,21 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 			/* We ran out of slot, let's see if the host has
 			 * added some, by reading hwcur and hwtail from
 			 * the CSB. */
-			ptnet_sync_tail(pthg, kring);
+			ptnet_sync_tail(ktoa, kring);
 
 			if (head == ring->tail) {
 				/* Still no slots available. Reactivate
 				 * interrupts as they were disabled by the
 				 * host thread right before issuing the
 				 * last interrupt. */
-				ptgh->guest_need_kick = 1;
+				atok->appl_need_kick = 1;
 
 				/* Double-check. */
-				ptnet_sync_tail(pthg, kring);
+				ptnet_sync_tail(ktoa, kring);
 				if (likely(head == ring->tail)) {
 					break;
 				}
-				ptgh->guest_need_kick = 0;
+				atok->appl_need_kick = 0;
 			}
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4ed869796..a38544957 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2160,14 +2160,11 @@ struct netmap_pt_guest_adapter {
 int netmap_pt_guest_attach(struct netmap_adapter *na,
 			unsigned int nifp_offset,
 			unsigned int memid);
-struct ptnet_csb_gh;
-struct ptnet_csb_hg;
-bool netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh,
-			struct ptnet_csb_hg *pthg,
-			struct netmap_kring *kring,
-			int flags);
-bool netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh,
-			struct ptnet_csb_hg *pthg,
+bool netmap_pt_guest_txsync(struct nm_csb_atok *atok,
+			struct nm_csb_ktoa *ktoa,
+			struct netmap_kring *kring, int flags);
+bool netmap_pt_guest_rxsync(struct nm_csb_atok *atok,
+			struct nm_csb_ktoa *ktoa,
 			struct netmap_kring *kring, int flags);
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 2a7e8916d..b03516ab7 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -726,26 +726,26 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
  * block (no space in the ring).
  */
 bool
-netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
+netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
 
 	/* Disable notifications */
-	ptgh->guest_need_kick = 0;
+	atok->appl_need_kick = 0;
 
 	/*
 	 * First part: tell the host (updating the CSB) to process the new
 	 * packets.
 	 */
-	kring->nr_hwcur = pthg->hwcur;
-	ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
+	kring->nr_hwcur = ktoa->hwcur;
+	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
 
         /* Ask for a kick from a guest to the host if needed. */
 	if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
-		&& NM_ACCESS_ONCE(pthg->host_need_kick)) ||
+		&& NM_ACCESS_ONCE(ktoa->kern_need_kick)) ||
 			(flags & NAF_FORCE_RECLAIM)) {
-		ptgh->sync_flags = flags;
+		atok->sync_flags = flags;
 		notify = true;
 	}
 
@@ -753,7 +753,7 @@ netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
-                ptnetmap_guest_read_kring_csb(pthg, kring);
+                ptnetmap_guest_read_kring_csb(ktoa, kring);
 	}
 
         /*
@@ -763,17 +763,17 @@ netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
          */
 	if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
-		ptgh->guest_need_kick = 1;
+		atok->appl_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(pthg, kring);
+                ptnetmap_guest_read_kring_csb(ktoa, kring);
                 /* If there is new free space, disable notifications */
 		if (unlikely(!nm_kr_txempty(kring))) {
-			ptgh->guest_need_kick = 0;
+			atok->appl_need_kick = 0;
 		}
 	}
 
 	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
-		kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
+		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
 	return notify;
@@ -791,20 +791,20 @@ netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
  * block (no more completed slots in the ring).
  */
 bool
-netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
+netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
 
         /* Disable notifications */
-	ptgh->guest_need_kick = 0;
+	atok->appl_need_kick = 0;
 
 	/*
 	 * First part: import newly received packets, by updating the kring
 	 * hwtail to the hwtail known from the host (read from the CSB).
 	 * This also updates the kring hwcur.
 	 */
-        ptnetmap_guest_read_kring_csb(pthg, kring);
+        ptnetmap_guest_read_kring_csb(ktoa, kring);
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
 	/*
@@ -812,11 +812,11 @@ netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
 	 * released, by updating cur and head in the CSB.
 	 */
 	if (kring->rhead != kring->nr_hwcur) {
-		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
+		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
 					       kring->rhead);
                 /* Ask for a kick from the guest to the host if needed. */
-		if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-			ptgh->sync_flags = flags;
+		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+			atok->sync_flags = flags;
 			notify = true;
 		}
 	}
@@ -828,17 +828,17 @@ netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
          */
 	if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
-                ptgh->guest_need_kick = 1;
+                atok->appl_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(pthg, kring);
+                ptnetmap_guest_read_kring_csb(ktoa, kring);
                 /* If there are new slots, disable notifications. */
 		if (!nm_kr_rxempty(kring)) {
-                        ptgh->guest_need_kick = 0;
+                        atok->appl_need_kick = 0;
                 }
         }
 
 	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
-		kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
+		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
 	return notify;
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index b6788051f..77b52974e 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -64,70 +64,6 @@
 #define PTNET_MDEV_IO_BUF_POOL_OBJSZ	96
 #define PTNET_MDEV_IO_END		100
 
-/*
- * ptnetmap configuration
- *
- * The ptnet kthreads (running in host kernel-space) need to be configured
- * in order to know how to intercept guest kicks (I/O register writes) and
- * how to inject MSI-X interrupts to the guest. The configuration may vary
- * depending on the hypervisor. Currently, we support QEMU/KVM on Linux and
- * and bhyve on FreeBSD.
- * The configuration is passed by the hypervisor to the host netmap module
- * by means of an ioctl() with nr_cmd=NETMAP_PT_HOST_CREATE, and it is
- * specified by the ptnetmap_cfg struct. This struct contains an header
- * with general informations and an array of entries whose size depends
- * on the hypervisor. The NETMAP_PT_HOST_CREATE command is issued every
- * time the kthreads are started.
- */
-struct ptnetmap_cfg {
-#define PTNETMAP_CFGTYPE_QEMU		0x1
-#define PTNETMAP_CFGTYPE_BHYVE		0x2
-	uint16_t cfgtype;	/* how to interpret the cfg entries */
-	uint16_t entry_size;	/* size of a config entry */
-	uint32_t num_rings;	/* number of config entries */
-	void *csb_gh;		/* CSB for guest --> host communication */
-	void *csb_hg;		/* CSB for host --> guest communication */
-	/* Configuration entries are allocated right after the struct. */
-};
-
-/* Configuration of a ptnetmap ring for QEMU. */
-struct ptnetmap_cfgentry_qemu {
-	uint32_t ioeventfd;	/* to intercept guest register access */
-	uint32_t irqfd;		/* to inject guest interrupts */
-};
-
-/* Configuration of a ptnetmap ring for bhyve. */
-struct ptnetmap_cfgentry_bhyve {
-	uint64_t wchan;		/* tsleep() parameter, to wake up kthread */
-	uint32_t ioctl_fd;	/* ioctl fd */
-	/* ioctl parameters to send irq */
-	uint32_t ioctl_cmd;
-	/* vmm.ko MSIX parameters for IOCTL */
-	struct {
-		uint64_t        msg_data;
-		uint64_t        addr;
-	} ioctl_data;
-};
-
-/*
- * Pass a pointer to a userspace buffer to be passed to kernelspace for write
- * or read. Used by NETMAP_PT_HOST_CREATE.
- * XXX deprecated
- */
-static inline void
-nmreq_pointer_put(struct nmreq *nmr, void *userptr)
-{
-	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-	*pp = (uintptr_t)userptr;
-}
-
-static inline void *
-nmreq_pointer_get(const struct nmreq *nmr)
-{
-	const uintptr_t *pp = (const uintptr_t *)&nmr->nr_arg1;
-	return (void *)*pp;
-}
-
 /* ptnetmap features */
 #define PTNETMAP_F_VNET_HDR        1
 
@@ -157,21 +93,6 @@ nmreq_pointer_get(const struct nmreq *nmr)
 #define PTNETMAP_PTCTL_CREATE		1
 #define PTNETMAP_PTCTL_DELETE		2
 
-/* ptnetmap synchronization variables shared between guest and host */
-struct ptnet_csb_gh {
-	uint32_t head;		  /* GW+ HR+ the head of the guest netmap_ring */
-	uint32_t cur;		  /* GW+ HR+ the cur of the guest netmap_ring */
-	uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */
-	uint32_t sync_flags;	  /* GW+ HR+ the flags of the guest [tx|rx]sync() */
-	char pad[48];		  /* pad to a 64 bytes cacheline */
-};
-struct ptnet_csb_hg {
-	uint32_t hwcur;		  /* GR+ HW+ the hwcur of the host netmap_kring */
-	uint32_t hwtail;	  /* GR+ HW+ the hwtail of the host netmap_kring */
-	uint32_t host_need_kick;  /* GR+ HW+ guest-->host notification enable */
-	char pad[4+48];
-};
-
 #ifdef WITH_PTNETMAP
 
 /* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */
@@ -184,7 +105,7 @@ uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
 /* Guest driver: Write kring pointers (cur, head) to the CSB.
  * This routine is coupled with ptnetmap_host_read_kring_csb(). */
 static inline void
-ptnetmap_guest_write_kring_csb(struct ptnet_csb_gh *ptr, uint32_t cur,
+ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
 			       uint32_t head)
 {
     /*
@@ -207,24 +128,25 @@ ptnetmap_guest_write_kring_csb(struct ptnet_csb_gh *ptr, uint32_t cur,
      *          mb() <-----------> mb()
      *          STORE(head)        LOAD(cur)
      */
-    ptr->cur = cur;
+    atok->cur = cur;
     mb();
-    ptr->head = head;
+    atok->head = head;
 }
 
 /* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
  * This routine is coupled with ptnetmap_host_write_kring_csb(). */
 static inline void
-ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
+ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
+                              struct netmap_kring *kring)
 {
     /*
      * We place a memory barrier to make sure that the update of hwtail never
      * overtakes the update of hwcur.
      * (see explanation in ptnetmap_host_write_kring_csb).
      */
-    kring->nr_hwtail = pthg->hwtail;
+    kring->nr_hwtail = ktoa->hwtail;
     mb();
-    kring->nr_hwcur = pthg->hwcur;
+    kring->nr_hwcur = ktoa->hwcur;
 }
 
 #endif /* WITH_PTNETMAP */

From bdb1175706d6fea4b527f11df777ab922453fc07 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:27:46 +0200
Subject: [PATCH 1230/2207] sync-kloop: enable eventfds only on linux

---
 sys/dev/netmap/netmap_mem2.c | 4 ++--
 sys/dev/netmap/netmap_pt.c   | 6 +++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 6d992a5ce..8d9315022 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2386,8 +2386,8 @@ netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
 
 	NMA_UNLOCK(nmd);
 
-	nm_prinf("added (ifp=%s,nifp_offset=%u)", ptif->ifp->if_xname,
-						ptif->nifp_offset);
+	nm_prinf("ptnet if added (ifp=%s,nifp_offset=%u)\n",
+		ptif->ifp->if_xname, ptif->nifp_offset);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index b03516ab7..6f1dffd8d 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -51,6 +51,11 @@
 #include 
 #include 
 
+/* Support for eventfd-based notifications. */
+#if defined(linux)
+#define SYNC_KLOOP_POLL
+#endif
+
 /* Functions to read and write CSB fields from the kernel. */
 #if defined (linux)
 #define CSB_READ(csb, field, r) (get_user(r, &csb->field))
@@ -130,7 +135,6 @@ sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 		kring->rhead, kring->rcur, kring->rtail);
 }
 
-#define SYNC_KLOOP_POLL
 struct sync_kloop_ring_args {
 	struct netmap_kring *kring;
 	struct nm_csb_atok *csb_atok;

From 33e48bc026024414aabfd2d26069ce301f65b178 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:35:40 +0200
Subject: [PATCH 1231/2207] sync-kloop: use wait_queue_t

---
 sys/dev/netmap/netmap_pt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 6f1dffd8d..387b0cd8f 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -397,7 +397,7 @@ struct sync_kloop_poll_entry {
 	/* Support for receiving notifications from
 	 * a netmap ring or from the application. */
 	struct file *filp;
-	wait_queue_entry_t wait;
+	wait_queue_t wait;
 	wait_queue_head_t *wqh;
 
 	/* Support for sending notifications to the application. */

From 7e6ab0f4087e6e1805eb5abdc492e3ff736ca043 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:39:10 +0200
Subject: [PATCH 1232/2207] rename netmap_pt --> netmap_kloop

---
 LINUX/Kbuild.in                                | 2 +-
 sys/dev/netmap/{netmap_pt.c => netmap_kloop.c} | 0
 sys/modules/netmap/Makefile                    | 2 +-
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename sys/dev/netmap/{netmap_pt.c => netmap_kloop.c} (100%)

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index edcc31d7c..0910ebaec 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,7 +8,7 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o netmap_pt.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o netmap_kloop.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_kloop.c
similarity index 100%
rename from sys/dev/netmap/netmap_pt.c
rename to sys/dev/netmap/netmap_kloop.c
diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index bfb6d7fb3..a6f405d3f 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -20,7 +20,7 @@ SRCS	+= netmap_freebsd.c
 SRCS	+= netmap_offloadings.c
 SRCS	+= netmap_pipe.c
 SRCS	+= netmap_monitor.c
-SRCS	+= netmap_pt.c
+SRCS	+= netmap_kloop.c
 SRCS	+= netmap_legacy.c
 SRCS	+= netmap_bdg.c
 SRCS	+= if_ptnet.c

From 0d940f51c2b436e2923838848a2d83131c88c9e1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 14:29:45 +0200
Subject: [PATCH 1233/2207] sync-kloop: include linux/eventfd.h

---
 sys/dev/netmap/netmap_kloop.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 387b0cd8f..4f44bb4c1 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -44,6 +44,7 @@
 #elif defined(linux)
 #include 
 #include 
+#include 
 #endif
 
 #include 

From f5afd4cade9cbff3b4c5afbbb542f7b08d1347b1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 15:06:47 +0200
Subject: [PATCH 1234/2207] utils: ctrl-api-test: add test for sync_kloop
 eventfds option

---
 utils/ctrl-api-test.c | 79 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 69 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 50ddfcfda..fa62a9d74 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -13,6 +13,15 @@
 #include 
 #include 
 
+#ifdef __linux__
+#include 
+#else
+static int eventfd(int x, int y)
+{
+	return 19;
+}
+#endif /* __linux__ */
+
 struct TestContext {
 	int fd; /* netmap file descriptor */
 	const char *ifname;
@@ -633,7 +642,7 @@ infinite_options(struct TestContext *ctx)
 static int
 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 {
-#ifdef linux
+#ifdef __linux__
 	char param[256] = "/sys/module/netmap/parameters/";
 	unsigned long oldv;
 	FILE *f;
@@ -660,7 +669,7 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 	}
 	fclose(f);
 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
-#endif /* linux */
+#endif /* __linux__ */
 	return 0;
 }
 
@@ -858,17 +867,11 @@ sync_kloop_worker(void *opaque)
 }
 
 static int
-sync_kloop(struct TestContext *ctx)
+sync_kloop_start_stop(struct TestContext *ctx)
 {
-	int ret;
 	pthread_t th;
 	int thret;
-
-	ctx->nr_flags = NR_EXCLUSIVE;
-	ret           = port_register_hwall(ctx);
-	if (ret) {
-		return ret;
-	}
+	int ret;
 
 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
 	if (ret) {
@@ -889,6 +892,61 @@ sync_kloop(struct TestContext *ctx)
 	return thret;
 }
 
+static int
+sync_kloop(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	return sync_kloop_start_stop(ctx);
+
+}
+
+static int
+sync_kloop_eventfds(struct TestContext *ctx)
+{
+	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
+	int num_entries;
+	size_t opt_size;
+	int ret, i;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	num_entries = ctx->nr_rx_rings + ctx->nr_tx_rings;
+	opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
+	opt = malloc(opt_size);
+	memset(opt, 0, opt_size);
+	opt->nro_opt.nro_next    = 0;
+	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
+	opt->nro_opt.nro_status  = 0;
+	opt->nro_opt.nro_size    = opt_size;
+	for (i = 0; i < num_entries; i++) {
+		int efd = eventfd(0, 0);
+
+		assert(efd >= 0);
+		opt->eventfds[i].ioeventfd = efd;
+		efd = eventfd(0, 0);
+		assert(efd >= 0);
+		opt->eventfds[i].irqfd     = efd;
+	}
+
+	push_option((struct nmreq_option *)opt, ctx);
+
+	// TODO check for failure ifdef __FreeBSD__
+	// TODO use checkoption
+	return sync_kloop_start_stop(ctx);
+
+}
+
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
@@ -1007,6 +1065,7 @@ static struct mytest tests[] = {
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
+	decltest(sync_kloop_eventfds),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_invalid_csb),
 };

From 7d2b3c4b493b868b5296f3a1805e8ad1b5f637f7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 16:12:28 +0200
Subject: [PATCH 1235/2207] utils: ctrl-api-test: print test name also when
 test succeeds or fails

---
 utils/ctrl-api-test.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fa62a9d74..4b5233c5b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1134,7 +1134,7 @@ main(int argc, char **argv)
 		if (j >= 0 && j != i) {
 			continue;
 		}
-		printf("==> Start of Test #%d -- %s\n", i + 1, tests[i].name);
+		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
 		fd = open("/dev/netmap", O_RDWR);
 		if (fd < 0) {
 			perror("open(/dev/netmap)");
@@ -1145,10 +1145,10 @@ main(int argc, char **argv)
 		ctxcopy.fd = fd;
 		ret        = tests[i].test(&ctxcopy);
 		if (ret) {
-			printf("Test #%d failed\n", i + 1);
+			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
 			goto out;
 		}
-		printf("==> Test #%d successful\n", i + 1);
+		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
 		close(fd);
 	}
 out:

From 8f92653ecfdab0f2664a45f3e1862deb40f73b30 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 16:26:30 +0200
Subject: [PATCH 1236/2207] utils: sync_kloop_eventds: use checkoption()

---
 utils/ctrl-api-test.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 4b5233c5b..604a7f339 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -911,6 +911,7 @@ static int
 sync_kloop_eventfds(struct TestContext *ctx)
 {
 	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
+	struct nmreq_option save;
 	int num_entries;
 	size_t opt_size;
 	int ret, i;
@@ -939,12 +940,19 @@ sync_kloop_eventfds(struct TestContext *ctx)
 		opt->eventfds[i].irqfd     = efd;
 	}
 
-	push_option((struct nmreq_option *)opt, ctx);
+	push_option(&opt->nro_opt, ctx);
+	save = opt->nro_opt;
 
-	// TODO check for failure ifdef __FreeBSD__
-	// TODO use checkoption
-	return sync_kloop_start_stop(ctx);
+	ret = sync_kloop_start_stop(ctx);
+	if (ret) {
+#ifdef __FreeBSD__
+		return 0;
+#endif /* __FreeBSD__ */
+		return ret;
+	}
+	save.nro_status = 0;
 
+	return checkoption(&opt->nro_opt, &save);
 }
 
 static int

From bf24f45cbb63904b65f69108627a2b31204a81eb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 16:47:16 +0200
Subject: [PATCH 1237/2207] utils: ctrl-api-test: add
 sync_kloop_eventfds_all_tx() test

---
 utils/ctrl-api-test.c | 67 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 9 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 604a7f339..4f3c1378c 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -169,6 +169,22 @@ port_register(struct TestContext *ctx)
 	return -0;
 }
 
+/* Only valid after a successful port_register(). */
+static int
+num_registered_rings(struct TestContext *ctx)
+{
+	assert(ctx->nr_tx_slots > 0 && ctx->nr_rx_slots > 0 &&
+		ctx->nr_tx_rings > 0 && ctx->nr_rx_rings > 0);
+	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
+		return ctx->nr_tx_rings;
+	}
+	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
+		return ctx->nr_rx_rings;
+	}
+
+	return ctx->nr_tx_rings + ctx->nr_rx_rings;
+}
+
 static int
 port_register_hwall_host(struct TestContext *ctx)
 {
@@ -198,6 +214,14 @@ port_register_single_ring_couple(struct TestContext *ctx)
 	return port_register(ctx);
 }
 
+static int
+port_register_hwall_tx(struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	ctx->nr_flags |= NR_TX_RINGS_ONLY;
+	return port_register(ctx);
+}
+
 /* NETMAP_REQ_VALE_ATTACH */
 static int
 vale_attach(struct TestContext *ctx)
@@ -829,7 +853,7 @@ static void *
 sync_kloop_worker(void *opaque)
 {
 	struct TestContext *ctx = opaque;
-	size_t num_entries      = ctx->nr_rx_rings + ctx->nr_tx_rings;
+	size_t num_entries      = num_registered_rings(ctx);
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 	size_t csb_size;
@@ -916,13 +940,7 @@ sync_kloop_eventfds(struct TestContext *ctx)
 	size_t opt_size;
 	int ret, i;
 
-	ctx->nr_flags = NR_EXCLUSIVE;
-	ret           = port_register_hwall(ctx);
-	if (ret) {
-		return ret;
-	}
-
-	num_entries = ctx->nr_rx_rings + ctx->nr_tx_rings;
+	num_entries = num_registered_rings(ctx);
 	opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
 	opt = malloc(opt_size);
 	memset(opt, 0, opt_size);
@@ -955,6 +973,36 @@ sync_kloop_eventfds(struct TestContext *ctx)
 	return checkoption(&opt->nro_opt, &save);
 }
 
+static int
+sync_kloop_eventfds_all(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	return sync_kloop_eventfds(ctx);
+
+}
+
+static int
+sync_kloop_eventfds_all_tx(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall_tx(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	return sync_kloop_eventfds(ctx);
+
+}
+
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
@@ -1073,7 +1121,8 @@ static struct mytest tests[] = {
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
-	decltest(sync_kloop_eventfds),
+	decltest(sync_kloop_eventfds_all),
+	decltest(sync_kloop_eventfds_all_tx),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_invalid_csb),
 };

From beb3643f59ee1c994d89197e8f7ce2c8f197e25a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 16:59:45 +0200
Subject: [PATCH 1238/2207] utils: ctrl-api-test: add
 sync_kloop_eventfds_mismatch() test

---
 sys/dev/netmap/netmap_kloop.c |  2 +-
 utils/ctrl-api-test.c         | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 4f44bb4c1..08ea2f3b1 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -1,6 +1,6 @@
 /*
+ * Copyright (C) 2016-2018 Vincenzo Maffione
  * Copyright (C) 2015 Stefano Garzarella
- * Copyright (C) 2016 Vincenzo Maffione
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 4f3c1378c..ae7c2b58f 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -222,6 +222,14 @@ port_register_hwall_tx(struct TestContext *ctx)
 	return port_register(ctx);
 }
 
+static int
+port_register_hwall_rx(struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	ctx->nr_flags |= NR_RX_RINGS_ONLY;
+	return port_register(ctx);
+}
+
 /* NETMAP_REQ_VALE_ATTACH */
 static int
 vale_attach(struct TestContext *ctx)
@@ -1083,6 +1091,26 @@ sync_kloop_invalid_csb(struct TestContext *ctx)
 	return (ret < 0) ? 0 : -1;
 }
 
+static int
+sync_kloop_eventfds_mismatch(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall_rx(ctx);
+	if (ret) {
+		return ret;
+	}
+	/* Deceive num_registered_rings() to trigger a failure of
+	 * sync_kloop_eventfds(). The latter will think that all the
+	 * rings were registered, and allocate the wrong number of
+	 * eventfds and CSB entries. */
+	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
+
+	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
+
+}
+
 static void
 usage(const char *prog)
 {
@@ -1125,6 +1153,7 @@ static struct mytest tests[] = {
 	decltest(sync_kloop_eventfds_all_tx),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_invalid_csb),
+	decltest(sync_kloop_eventfds_mismatch),
 };
 
 int

From 29681df2f5c7a2135e1700d1696b48023f85672d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 17:43:02 +0200
Subject: [PATCH 1239/2207] prune obsolete code related to kthreads

---
 LINUX/netmap_linux.c            | 263 ++------------------------------
 README.ptnetmap                 |  12 --
 share/man/man4/netmap.4         |   2 -
 sys/dev/netmap/netmap.c         |   5 -
 sys/dev/netmap/netmap_bdg.c     |   3 +-
 sys/dev/netmap/netmap_freebsd.c |  85 ++---------
 sys/dev/netmap/netmap_kern.h    |   8 +-
 sys/dev/netmap/netmap_kloop.c   |   7 +-
 8 files changed, 29 insertions(+), 356 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 26e33884f..0c71d8f22 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1614,100 +1614,21 @@ nm_os_ncpus(void)
 struct nm_kctx {
 	struct mm_struct *mm;       /* to access guest memory */
 	struct task_struct *worker; /* the kernel thread */
-	atomic_t scheduled;         /* pending wake_up request */
 	int attach_user;            /* kthread attached to user_process */
 	int affinity;
 
-	/* files to exchange notifications */
-	struct file *ioevent_file;          /* notification from guest */
-	struct file *irq_file;              /* notification to guest (interrupt) */
-	struct eventfd_ctx *irq_ctx;
-
-	/* poll ioeventfd to receive notification from the guest */
-	poll_table poll_table;
-	wait_queue_head_t *waitq_head;
-	wait_queue_t waitq;
-
 	/* worker function and parameter */
 	nm_kctx_worker_fn_t worker_fn;
 	void *worker_private;
 
-	/* notify function, only needed when use_kthread == 0 */
-	nm_kctx_notify_fn_t notify_fn;
-
 	/* integer to manage multiple worker contexts */
 	long type;
-
-	/* does this kernel context use a kthread ? */
-	int use_kthread;
 };
 
-void inline
-nm_os_kctx_worker_wakeup(struct nm_kctx *nmk)
-{
-	if (!nmk->worker) {
-		/* Propagate notification to the user. */
-		nmk->notify_fn(nmk->worker_private);
-		return;
-	}
-
-	/*
-	 * There may be a race between FE and BE,
-	 * which call both this function, and worker kthread,
-	 * that reads ptk->scheduled.
-	 *
-	 * For us it is not important the counter value,
-	 * but simply that it has changed since the last
-	 * time the kthread saw it.
-	 */
-	atomic_inc(&nmk->scheduled);
-	wake_up_process(nmk->worker);
-}
-
-
-static void
-nm_kctx_poll_fn(struct file *file, wait_queue_head_t *wq_head, poll_table *pt)
-{
-	struct nm_kctx *nmk;
-
-	nmk = container_of(pt, struct nm_kctx, poll_table);
-	nmk->waitq_head = wq_head;
-	add_wait_queue(wq_head, &nmk->waitq);
-}
-
-static int
-nm_kctx_poll_wakeup(wait_queue_t *wq, unsigned mode, int sync, void *key)
-{
-	struct nm_kctx *nmk;
-
-	/* We received a kick on the ioevent_file. If there is a worker,
-	 * wake it up, otherwise do the work here. */
-
-	nmk = container_of(wq, struct nm_kctx, waitq);
-	if (nmk->worker) {
-		nm_os_kctx_worker_wakeup(nmk);
-	} else {
-		nmk->worker_fn(nmk->worker_private, 0);
-	}
-
-	return 0;
-}
-
-static void inline
-nm_kctx_worker_fn(struct nm_kctx *nmk)
-{
-	__set_current_state(TASK_RUNNING);
-	nmk->worker_fn(nmk->worker_private, 1); /* work */
-	if (need_resched())
-		schedule();
-}
-
 static int
 nm_kctx_worker(void *data)
 {
 	struct nm_kctx *nmk = data;
-	int old_scheduled = atomic_read(&nmk->scheduled);
-	int new_scheduled = old_scheduled;
 	mm_segment_t oldfs = get_fs();
 
 	if (nmk->mm) {
@@ -1716,38 +1637,11 @@ nm_kctx_worker(void *data)
 	}
 
 	while (!kthread_should_stop()) {
-		if (!nmk->ioevent_file) {
-			/*
-			 * if ioevent_file is not defined, we don't have
-			 * notification mechanism and we continually
-			 * execute worker_fn()
-			 */
-			nm_kctx_worker_fn(nmk);
-
-		} else {
-			/*
-			 * Set INTERRUPTIBLE state before to check if there
-			 * is work. If wake_up() is called, although we have
-			 * not seen the new counter value, the kthread state
-			 * is set to RUNNING and after schedule() it is not
-			 * moved off run queue.
-			 */
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			new_scheduled = atomic_read(&nmk->scheduled);
-
-			/* check if there is a pending notification */
-			if (likely(new_scheduled != old_scheduled)) {
-				old_scheduled = new_scheduled;
-				nm_kctx_worker_fn(nmk);
-			} else {
-				schedule();
-			}
-		}
+		nmk->worker_fn(nmk->worker_private); /* work */
+		if (need_resched())
+			schedule();
 	}
 
-	__set_current_state(TASK_RUNNING);
-
 	if (nmk->mm) {
 		unuse_mm(nmk->mm);
 	}
@@ -1756,102 +1650,6 @@ nm_kctx_worker(void *data)
 	return 0;
 }
 
-void inline
-nm_os_kctx_send_irq(struct nm_kctx *nmk)
-{
-	if (nmk->irq_ctx) {
-		eventfd_signal(nmk->irq_ctx, 1);
-	}
-}
-
-static void
-nm_kctx_close_files(struct nm_kctx *nmk)
-{
-	if (nmk->ioevent_file) {
-		fput(nmk->ioevent_file);
-		nmk->ioevent_file = NULL;
-	}
-
-	if (nmk->irq_file) {
-		fput(nmk->irq_file);
-		nmk->irq_file = NULL;
-		eventfd_ctx_put(nmk->irq_ctx);
-		nmk->irq_ctx = NULL;
-	}
-}
-
-static int
-nm_kctx_open_files(struct nm_kctx *nmk, void *opaque)
-{
-	struct file *file;
-
-	nmk->ioevent_file = NULL;
-	nmk->irq_file = NULL;
-
-	if (!opaque) {
-		return 0;
-	}
-
-	if (0 /* TODO cleanup */) {
-		file = eventfd_fget(-1);
-		if (IS_ERR(file))
-			goto err;
-		nmk->ioevent_file = file;
-	}
-
-	if (0 /* TODO cleanup */) {
-		file = eventfd_fget(-1);
-		if (IS_ERR(file))
-			goto err;
-		nmk->irq_file = file;
-		nmk->irq_ctx = eventfd_ctx_fileget(file);
-	}
-
-	return 0;
-
-err:
-	nm_kctx_close_files(nmk);
-	return -PTR_ERR(file);
-}
-
-static void
-nm_kctx_init_poll(struct nm_kctx *nmk)
-{
-	init_waitqueue_func_entry(&nmk->waitq, nm_kctx_poll_wakeup);
-	init_poll_funcptr(&nmk->poll_table, nm_kctx_poll_fn);
-}
-
-static int
-nm_kctx_start_poll(struct nm_kctx *nmk)
-{
-	unsigned long mask;
-	int ret = 0;
-
-	if (nmk->waitq_head)
-		return 0;
-
-	mask = nmk->ioevent_file->f_op->poll(nmk->ioevent_file,
-					     &nmk->poll_table);
-	if (mask)
-		nm_kctx_poll_wakeup(&nmk->waitq, 0, 0, (void *)mask);
-	if (mask & POLLERR) {
-		if (nmk->waitq_head)
-			remove_wait_queue(nmk->waitq_head, &nmk->waitq);
-		ret = EINVAL;
-	}
-
-	return ret;
-}
-
-static void
-nm_kctx_stop_poll(struct nm_kctx *nmk)
-{
-	if (nmk->waitq_head) {
-		remove_wait_queue(nmk->waitq_head, &nmk->waitq);
-		nmk->waitq_head = NULL;
-	}
-}
-
 void
 nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
 {
@@ -1862,12 +1660,6 @@ struct nm_kctx *
 nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 {
 	struct nm_kctx *nmk = NULL;
-	int error;
-
-	if (!cfg->use_kthread && cfg->notify_fn == NULL) {
-		D("Error: notify function missing with use_kthread == 0");
-		return NULL;
-	}
 
 	nmk = kzalloc(sizeof *nmk, GFP_KERNEL);
 	if (!nmk)
@@ -1875,29 +1667,17 @@ nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 
 	nmk->worker_fn = cfg->worker_fn;
 	nmk->worker_private = cfg->worker_private;
-	nmk->notify_fn = cfg->notify_fn;
 	nmk->type = cfg->type;
-	nmk->use_kthread = cfg->use_kthread;
-	atomic_set(&nmk->scheduled, 0);
 	nmk->attach_user = cfg->attach_user;
 	nmk->affinity = -1;  /* unspecified */
 
-	/* open event fds */
-	error = nm_kctx_open_files(nmk, opaque);
-	if (error)
-		goto err;
-
-	nm_kctx_init_poll(nmk);
-
 	return nmk;
-err:
-	kfree(nmk);
-	return NULL;
 }
 
 int
 nm_os_kctx_worker_start(struct nm_kctx *nmk)
 {
+	char name[16];
 	int error = 0;
 
 	if (nmk->worker) {
@@ -1909,30 +1689,19 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 		nmk->mm = get_task_mm(current);
 	}
 
-	/* Run the context in a kernel thread, if needed. */
-	if (nmk->use_kthread) {
-		char name[16];
-
-		snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid,
-								nmk->type);
-		nmk->worker = kthread_create(nm_kctx_worker, nmk, name);
-		if (IS_ERR(nmk->worker)) {
-			error = -PTR_ERR(nmk->worker);
-			goto err;
-		}
-
-		if (nmk->affinity >= 0) {
-			kthread_bind(nmk->worker, nmk->affinity);
-		}
-		wake_up_process(nmk->worker);
+	/* Run the context in a kernel thread. */
+	snprintf(name, sizeof(name), "nmkth:%d:%ld", current->pid,
+							nmk->type);
+	nmk->worker = kthread_create(nm_kctx_worker, nmk, name);
+	if (IS_ERR(nmk->worker)) {
+		error = -PTR_ERR(nmk->worker);
+		goto err;
 	}
 
-	if (nmk->ioevent_file) {
-		error = nm_kctx_start_poll(nmk);
-		if (error) {
-			goto err;
-		}
+	if (nmk->affinity >= 0) {
+		kthread_bind(nmk->worker, nmk->affinity);
 	}
+	wake_up_process(nmk->worker);
 
 	return 0;
 
@@ -1951,8 +1720,6 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 void
 nm_os_kctx_worker_stop(struct nm_kctx *nmk)
 {
-	nm_kctx_stop_poll(nmk);
-
 	if (nmk->worker) {
 		kthread_stop(nmk->worker);
 		nmk->worker = NULL;
@@ -1974,8 +1741,6 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 		nm_os_kctx_worker_stop(nmk);
 	}
 
-	nm_kctx_close_files(nmk);
-
 	kfree(nmk);
 }
 
diff --git a/README.ptnetmap b/README.ptnetmap
index 1b285473a..457373cdb 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap
@@ -130,18 +130,6 @@ kernel.
 6. ptnetmap tunables
 ----------------------------------------------------------------------
 
-By default ptnetmap uses dedicated host kernel threads to transmit and
-receive packets for the VM (i.e. to run NIOCTXSYNC and NIOCRXSYNC on
-the passed-through netmap ports). It is possible to disable TX kernel
-threads by setting the ptnetmap_tx_workers sysctl to zero on the host
-machine, e.g.
-
-    # echo 0 > /sys/module/netmap/parameters/ptnetmap_tx_workers
-
-so that transmissions are perfomed directly by the VM vCPU threads.
-Depending on your workload, disabling TX kernel threads can result to
-improved performance (throughput/latency) and/or improved CPU utilization.
-
 While ptnetmap is mainly designed for the VMs to run middleboxes applications
 (e.g. firewall, DDoS prevention, load balancing, IDS, typically carried out
 by network operators), it also offers good performance when VMs run TCP/UDP
diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 368d8cc6a..6e3c92fa5 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -911,8 +911,6 @@ Values above 64 generally guarantee good
 performance.
 .It Va dev.netmap.ptnet_vnet_hdr: 1
 Allow ptnet devices to use virtio-net headers
-.It Va dev.netmap.ptnetmap_tx_workers: 1
-Use worker threads for ptnetmap TX processing
 .El
 .Sh SYSTEM CALLS
 .Nm
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8339c4e53..3bdc91300 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -525,9 +525,6 @@ int netmap_generic_hwcsum = 0;
 /* Non-zero if ptnet devices are allowed to use virtio-net headers. */
 int ptnet_vnet_hdr = 1;
 
-/* 0 if ptnetmap should not use worker threads for TX processing */
-int ptnetmap_tx_workers = 1;
-
 /*
  * SYSCTL calls are grouped between SYSBEGIN and SYSEND to be emulated
  * in some other operating systems
@@ -567,8 +564,6 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW,
 #endif
 SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr,
 		0, "Allow ptnet devices to use virtio-net headers");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW,
-		&ptnetmap_tx_workers, 0, "Use worker threads for pnetmap TX processing");
 
 SYSEND;
 
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index da5f00600..fe43c5890 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -569,7 +569,7 @@ struct nm_bdg_polling_state {
 };
 
 static void
-netmap_bwrap_polling(void *data, int is_kthread)
+netmap_bwrap_polling(void *data)
 {
 	struct nm_bdg_kthread *nbk = data;
 	struct netmap_bwrap_adapter *bna;
@@ -601,7 +601,6 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
 
 	bzero(&kcfg, sizeof(kcfg));
 	kcfg.worker_fn = netmap_bwrap_polling;
-	kcfg.use_kthread = 1;
 	for (i = 0; i < bps->ncpus; i++) {
 		struct nm_bdg_kthread *t = bps->kthreads + i;
 		int all = (bps->ncpus == 1 &&
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 2932f29c3..a1efa4e07 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1143,8 +1143,8 @@ nm_os_ncpus(void)
 }
 
 struct nm_kctx_ctx {
-	struct thread *user_td;		/* thread user-space (kthread creator) to send ioctl */
-	struct ptnetmap_cfgentry_bhyve	cfg;
+	/* Userspace thread (kthread creator). */
+	struct thread *user_td;
 
 	/* worker function and parameter */
 	nm_kctx_worker_fn_t worker_fn;
@@ -1159,56 +1159,17 @@ struct nm_kctx_ctx {
 struct nm_kctx {
 	struct thread *worker;
 	struct mtx worker_lock;
-	uint64_t scheduled; 		/* pending wake_up request */
 	struct nm_kctx_ctx worker_ctx;
 	int run;			/* used to stop kthread */
 	int attach_user;		/* kthread attached to user_process */
 	int affinity;
 };
 
-void inline
-nm_os_kctx_worker_wakeup(struct nm_kctx *nmk)
-{
-	/*
-	 * There may be a race between FE and BE,
-	 * which call both this function, and worker kthread,
-	 * that reads nmk->scheduled.
-	 *
-	 * For us it is not important the counter value,
-	 * but simply that it has changed since the last
-	 * time the kthread saw it.
-	 */
-	mtx_lock(&nmk->worker_lock);
-	nmk->scheduled++;
-	if (nmk->worker_ctx.cfg.wchan) {
-		wakeup((void *)(uintptr_t)nmk->worker_ctx.cfg.wchan);
-	}
-	mtx_unlock(&nmk->worker_lock);
-}
-
-void inline
-nm_os_kctx_send_irq(struct nm_kctx *nmk)
-{
-	struct nm_kctx_ctx *ctx = &nmk->worker_ctx;
-	int err;
-
-	if (ctx->user_td && ctx->cfg.ioctl_fd > 0) {
-		err = kern_ioctl(ctx->user_td, ctx->cfg.ioctl_fd, ctx->cfg.ioctl_cmd,
-				 (caddr_t)&ctx->cfg.ioctl_data);
-		if (err) {
-			D("kern_ioctl error: %d ioctl parameters: fd %d com %lu data %p",
-				err, ctx->cfg.ioctl_fd, (unsigned long)ctx->cfg.ioctl_cmd,
-				&ctx->cfg.ioctl_data);
-		}
-	}
-}
-
 static void
 nm_kctx_worker(void *data)
 {
 	struct nm_kctx *nmk = data;
 	struct nm_kctx_ctx *ctx = &nmk->worker_ctx;
-	uint64_t old_scheduled = nmk->scheduled;
 
 	if (nmk->affinity >= 0) {
 		thread_lock(curthread);
@@ -1229,30 +1190,8 @@ nm_kctx_worker(void *data)
 			kthread_suspend_check();
 		}
 
-		/*
-		 * if wchan is not defined, we don't have notification
-		 * mechanism and we continually execute worker_fn()
-		 */
-		if (!ctx->cfg.wchan) {
-			ctx->worker_fn(ctx->worker_private, 1); /* worker body */
-		} else {
-			/* checks if there is a pending notification */
-			mtx_lock(&nmk->worker_lock);
-			if (likely(nmk->scheduled != old_scheduled)) {
-				old_scheduled = nmk->scheduled;
-				mtx_unlock(&nmk->worker_lock);
-
-				ctx->worker_fn(ctx->worker_private, 1); /* worker body */
-
-				continue;
-			} else if (nmk->run) {
-				/* wait on event with one second timeout */
-				msleep((void *)(uintptr_t)ctx->cfg.wchan, &nmk->worker_lock,
-					0, "nmk_ev", hz);
-				nmk->scheduled++;
-			}
-			mtx_unlock(&nmk->worker_lock);
-		}
+		/* Continuously execute worker process. */
+		ctx->worker_fn(ctx->worker_private); /* worker body */
 	}
 
 	kthread_exit();
@@ -1282,11 +1221,6 @@ nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
 	/* attach kthread to user process (ptnetmap) */
 	nmk->attach_user = cfg->attach_user;
 
-	/* store kick/interrupt configuration */
-	if (opaque) {
-		nmk->worker_ctx.cfg = *((struct ptnetmap_cfgentry_bhyve *)opaque);
-	}
-
 	return nmk;
 }
 
@@ -1301,9 +1235,8 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 	 * the "vale_polling_enable_disable" test in ctrl-api-test.c. */
 	return EOPNOTSUPP;
 
-	if (nmk->worker) {
+	if (nmk->worker)
 		return EBUSY;
-	}
 
 	/* check if we want to attach kthread to user process */
 	if (nmk->attach_user) {
@@ -1332,9 +1265,9 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 void
 nm_os_kctx_worker_stop(struct nm_kctx *nmk)
 {
-	if (!nmk->worker) {
+	if (!nmk->worker)
 		return;
-	}
+
 	/* tell to kthread to exit from main loop */
 	nmk->run = 0;
 
@@ -1350,9 +1283,9 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 {
 	if (!nmk)
 		return;
-	if (nmk->worker) {
+
+	if (nmk->worker)
 		nm_os_kctx_worker_stop(nmk);
-	}
 
 	memset(&nmk->worker_ctx.cfg, 0, sizeof(nmk->worker_ctx.cfg));
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a38544957..23c4e5620 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1564,7 +1564,6 @@ extern int netmap_generic_rings;
 #ifdef linux
 extern int netmap_generic_txqdisc;
 #endif
-extern int ptnetmap_tx_workers;
 
 /*
  * NA returns a pointer to the struct netmap adapter from the ifp.
@@ -2109,17 +2108,14 @@ void nm_os_vi_init_index(void);
  * kernel thread routines
  */
 struct nm_kctx; /* OS-specific kernel context - opaque */
-typedef void (*nm_kctx_worker_fn_t)(void *data, int is_kthread);
-typedef void (*nm_kctx_notify_fn_t)(void *data);
+typedef void (*nm_kctx_worker_fn_t)(void *data);
 
 /* kthread configuration */
 struct nm_kctx_cfg {
 	long			type;		/* kthread type/identifier */
 	nm_kctx_worker_fn_t	worker_fn;	/* worker function */
 	void			*worker_private;/* worker parameter */
-	nm_kctx_notify_fn_t	notify_fn;	/* notify function */
 	int			attach_user;	/* attach kthread to user process */
-	int			use_kthread;	/* use a kthread for the context */
 };
 /* kthread configuration */
 struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
@@ -2127,8 +2123,6 @@ struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
 int nm_os_kctx_worker_start(struct nm_kctx *);
 void nm_os_kctx_worker_stop(struct nm_kctx *);
 void nm_os_kctx_destroy(struct nm_kctx *);
-void nm_os_kctx_worker_wakeup(struct nm_kctx *nmk);
-void nm_os_kctx_send_irq(struct nm_kctx *);
 void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 08ea2f3b1..9c8cd4abd 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -131,7 +131,8 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 {
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
+	nm_prinf("sync_kloop: %s - name: %s hwcur: %d hwtail: %d "
+		"rhead: %d rcur: %d rtail: %d\n",
 		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
 		kring->rhead, kring->rcur, kring->rtail);
 }
@@ -203,7 +204,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
-			D("ERROR txsync()");
+			nm_prerr("sync_kloop: txsync() failed\n");
 			break;
 		}
 
@@ -320,7 +321,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
-			D("ERROR rxsync()");
+			nm_prerr("sync_kloop: rxsync() failed\n");
 			break;
 		}
 

From 283b65b7c7e6cd306eaef636700e8e9e730770b4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 17:52:35 +0200
Subject: [PATCH 1240/2207] freebsd: fix compilation issues

---
 sys/dev/netmap/netmap_freebsd.c |  3 ---
 sys/dev/netmap/netmap_kloop.c   | 22 ++++++++++++----------
 2 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index a1efa4e07..5d8182865 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1273,7 +1273,6 @@ nm_os_kctx_worker_stop(struct nm_kctx *nmk)
 
 	/* wake up kthread if it sleeps */
 	kthread_resume(nmk->worker);
-	nm_os_kctx_worker_wakeup(nmk);
 
 	nmk->worker = NULL;
 }
@@ -1287,8 +1286,6 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 	if (nmk->worker)
 		nm_os_kctx_worker_stop(nmk);
 
-	memset(&nmk->worker_ctx.cfg, 0, sizeof(nmk->worker_ctx.cfg));
-
 	free(nmk, M_DEVBUF);
 }
 
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 9c8cd4abd..d91f5c324 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -540,8 +540,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
 	if (opt != NULL) {
-		NM_SELINFO_T *si[NR_TXRX];
-
 		err = nmreq_checkduplicate(opt);
 		if (err) {
 			opt->nro_status = err;
@@ -599,14 +597,18 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
-		NMG_LOCK();
-		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-		NMG_UNLOCK();
-		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
-		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
+		{
+			NM_SELINFO_T *si[NR_TXRX];
+
+			NMG_LOCK();
+			si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+			si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+			NMG_UNLOCK();
+			poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
+			poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
+		}
 #else   /* SYNC_KLOOP_POLL */
 		opt->nro_status = EOPNOTSUPP;
 		goto out;

From 5641cb0ca4bba69da025f21a35494dd7a39f8b6f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 17:57:09 +0200
Subject: [PATCH 1241/2207] sync-kloop: define usleep_range() for freebsd

---
 sys/dev/netmap/netmap_kloop.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index d91f5c324..d00c9485c 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -41,6 +41,9 @@
 #include 
 #include 
 
+#define usleep_range(_1, _2) \
+        pause_sbt("sync-kloop-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE)
+
 #elif defined(linux)
 #include 
 #include 

From e926dc279417a98a4927d4f885a411eab7fa6520 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 10:36:04 +0200
Subject: [PATCH 1242/2207] netmap.h: add new commands:
 NETMAP_REQ_KSYNC_LOOP_START/STOP

---
 sys/dev/netmap/netmap.c | 12 ++++++++++++
 sys/net/netmap.h        |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e52902840..c6e0a013b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2627,6 +2627,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
+		case NETMAP_REQ_KSYNC_LOOP_START: {
+			error = ENOSYS;
+			break;
+		}
+
+		case NETMAP_REQ_KSYNC_LOOP_STOP: {
+			error = ENOSYS;
+			break;
+		}
+
 		default: {
 			error = EINVAL;
 			break;
@@ -2736,6 +2746,8 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_NEWIF:
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
+	case NETMAP_REQ_KSYNC_LOOP_START:
+	case NETMAP_REQ_KSYNC_LOOP_STOP:
 		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index ceab641a6..c339c98f9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -516,6 +516,13 @@ enum {
 	NETMAP_REQ_VALE_POLLING_DISABLE,
 	/* Get info about the pools of a memory allocator. */
 	NETMAP_REQ_POOLS_INFO_GET,
+	/* Start an in-kernel loop that syncs the rings periodically or
+	 * on notifications. The loop runs in the context of the ioctl
+	 * syscall, and only stops on NETMAP_REQ_KSYNC_LOOP_STOP. */
+	NETMAP_REQ_KSYNC_LOOP_START,
+	/* Stops the thread executing the in-kernel loop. The thread
+	 * returns from the ioctl syscall. */
+	NETMAP_REQ_KSYNC_LOOP_STOP,
 };
 
 enum {

From 207743d063b9e7d5af333aa30997ee2ec950391d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 11:08:04 +0200
Subject: [PATCH 1243/2207] sync-kloop: introduce struct nmreq_sync_kloop_start

---
 sys/dev/netmap/netmap.c |  9 +++++----
 sys/net/netmap.h        | 23 ++++++++++++++++++++---
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c6e0a013b..7a76c72e3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2627,12 +2627,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
-		case NETMAP_REQ_KSYNC_LOOP_START: {
+		case NETMAP_REQ_SYNC_KLOOP_START: {
 			error = ENOSYS;
 			break;
 		}
 
-		case NETMAP_REQ_KSYNC_LOOP_STOP: {
+		case NETMAP_REQ_SYNC_KLOOP_STOP: {
 			error = ENOSYS;
 			break;
 		}
@@ -2746,14 +2746,15 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 	case NETMAP_REQ_VALE_NEWIF:
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
-	case NETMAP_REQ_KSYNC_LOOP_START:
-	case NETMAP_REQ_KSYNC_LOOP_STOP:
+	case NETMAP_REQ_SYNC_KLOOP_STOP:
 		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
 		return sizeof(struct nmreq_vale_polling);
 	case NETMAP_REQ_POOLS_INFO_GET:
 		return sizeof(struct nmreq_pools_info);
+	case NETMAP_REQ_SYNC_KLOOP_START:
+		return sizeof(struct nmreq_sync_kloop_start);
 	}
 	return 0;
 }
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index c339c98f9..3dc35a2f9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -518,11 +518,11 @@ enum {
 	NETMAP_REQ_POOLS_INFO_GET,
 	/* Start an in-kernel loop that syncs the rings periodically or
 	 * on notifications. The loop runs in the context of the ioctl
-	 * syscall, and only stops on NETMAP_REQ_KSYNC_LOOP_STOP. */
-	NETMAP_REQ_KSYNC_LOOP_START,
+	 * syscall, and only stops on NETMAP_REQ_SYNC_KLOOP_STOP. */
+	NETMAP_REQ_SYNC_KLOOP_START,
 	/* Stops the thread executing the in-kernel loop. The thread
 	 * returns from the ioctl syscall. */
-	NETMAP_REQ_KSYNC_LOOP_STOP,
+	NETMAP_REQ_SYNC_KLOOP_STOP,
 };
 
 enum {
@@ -699,6 +699,23 @@ struct nmreq_pools_info {
 	uint32_t	nr_buf_pool_objsize;
 };
 
+/*
+ * nr_reqtype: NETMAP_REQ_SYNC_KLOOP_START
+ * Start an in-kernel loop that syncs the rings periodically or on
+ * notifications. The loop runs in the context of the ioctl syscall,
+ * and only stops on NETMAP_REQ_SYNC_KLOOP_STOP.
+ * The user must specify the start address of the Communication Status Block
+ * (CSB) entries to be used for both directions (kernel read application
+ * writes, and kernel writes application read). The number of entries
+ * must agree with the number of rings bound to the netmap file descriptor.
+ */
+struct nmreq_sync_kloop_start {
+	/* CSB entries for application --> kernel communication (N entries). */
+	uint64_t csb_atok;
+	/* CSB for kernel --> application communication (N entries). */
+	uint64_t csb_ktoa;
+};
+
 /*
  * data for NETMAP_REQ_OPT_* options
  */

From bcc6f3dfc9e452c040a429f63fc3db22161d3bb4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 11:30:17 +0200
Subject: [PATCH 1244/2207] introduce netmap_sync_kloop() function

---
 sys/dev/netmap/netmap.c      | 9 ++++++++-
 sys/dev/netmap/netmap_kern.h | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7a76c72e3..78e553331 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2628,7 +2628,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_START: {
-			error = ENOSYS;
+			struct nmreq_sync_kloop_start *req =
+				(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
+			error = netmap_sync_kloop(req);
 			break;
 		}
 
@@ -3899,6 +3901,11 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
+int
+netmap_sync_kloop(struct nmreq_sync_kloop_start *req)
+{
+	return ENOSYS;
+}
 
 /*
  * Module loader and unloader
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f710412c3..025a93a0a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2123,6 +2123,8 @@ void nm_os_kctx_send_irq(struct nm_kctx *);
 void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
+int netmap_sync_kloop(struct nmreq_sync_kloop_start *req);
+
 #ifdef WITH_PTNETMAP_HOST
 /*
  * netmap adapter for host ptnetmap ports

From 92712c1fa2b40b06c7a205a7c208e4cd79d3bec6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 16:40:15 +0200
Subject: [PATCH 1245/2207] netmap_sync_kloop: grab netmap priv and netmap
 adapter

---
 sys/dev/netmap/netmap.c      | 17 +++++++++++++++--
 sys/dev/netmap/netmap_kern.h |  3 ++-
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 78e553331..daf595434 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2630,7 +2630,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		case NETMAP_REQ_SYNC_KLOOP_START: {
 			struct nmreq_sync_kloop_start *req =
 				(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
-			error = netmap_sync_kloop(req);
+			error = netmap_sync_kloop(priv, req);
 			break;
 		}
 
@@ -3902,8 +3902,21 @@ nm_clear_native_flags(struct netmap_adapter *na)
 }
 
 int
-netmap_sync_kloop(struct nmreq_sync_kloop_start *req)
+netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
+	struct netmap_adapter *na;
+
+	if (priv->np_nifp == NULL) {
+		D("No if registered");
+		return ENXIO;
+	}
+	mb(); /* make sure following reads are not from cache */
+
+	na = priv->np_na;
+	if (!nm_netmap_on(na)) {
+		return ENXIO;
+	}
+
 	return ENOSYS;
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 025a93a0a..8c5a63f60 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2123,7 +2123,8 @@ void nm_os_kctx_send_irq(struct nm_kctx *);
 void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
-int netmap_sync_kloop(struct nmreq_sync_kloop_start *req);
+int netmap_sync_kloop(struct netmap_priv_d *priv,
+		      struct nmreq_sync_kloop_start *req);
 
 #ifdef WITH_PTNETMAP_HOST
 /*

From 7c486bb188e62b9e7fd198f163a5e6f166107ab7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 18:42:49 +0200
Subject: [PATCH 1246/2207] netmap_sync_kloop: add CSB memory validation for
 the atok direction

---
 sys/dev/netmap/netmap.c | 27 ++++++++++++++++++++++++++-
 sys/net/netmap.h        | 15 +++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index daf595434..3a651b366 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3907,7 +3907,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	struct netmap_adapter *na;
 
 	if (priv->np_nifp == NULL) {
-		D("No if registered");
 		return ENXIO;
 	}
 	mb(); /* make sure following reads are not from cache */
@@ -3917,6 +3916,32 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	/* Validate the CSB entries for both directions. */
+	{
+		struct nm_csb_atok *csb_atok =
+			(struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+		unsigned int num_entries;
+		size_t csb_size;
+		int err;
+
+		num_entries = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
+			      priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+		csb_size = num_entries * sizeof(*csb_atok);
+
+		if (csb_size) {
+			void *tmp = nm_os_malloc(csb_size);
+			if (!tmp) {
+				return ENOMEM;
+			}
+			err = copyin(csb_atok, tmp, csb_size);
+			nm_os_free(tmp);
+			if (err) {
+				nm_prerr("Invalid CSB address\n");
+				return err;
+			}
+		}
+	}
+
 	return ENOSYS;
 }
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3dc35a2f9..41fcef519 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -716,6 +716,21 @@ struct nmreq_sync_kloop_start {
 	uint64_t csb_ktoa;
 };
 
+struct nm_csb_atok {
+	uint32_t head;		  /* AW+ KR+ the head of the appl netmap_ring */
+	uint32_t cur;		  /* AW+ KR+ the cur of the appl netmap_ring */
+	uint32_t appl_need_kick; /* AW+ KR+ kern --> appl notification enable */
+	uint32_t sync_flags;	  /* AW+ KR+ the flags of the appl [tx|rx]sync() */
+	char pad[48];		  /* pad to a 64 bytes cacheline */
+};
+
+struct nm_csb_ktoa {
+	uint32_t hwcur;		  /* AR+ KW+ the hwcur of the kern netmap_kring */
+	uint32_t hwtail;	  /* AR+ KW+ the hwtail of the kern netmap_kring */
+	uint32_t kern_need_kick;  /* AR+ KW+ appl-->kern notification enable */
+	char pad[4+48];
+};
+
 /*
  * data for NETMAP_REQ_OPT_* options
  */

From 657852704f1f4a57363c49e715194f28b681167d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 18:58:18 +0200
Subject: [PATCH 1247/2207] netmap_sync_kloop: validate CSB for both directions

---
 sys/dev/netmap/netmap.c | 50 +++++++++++++++++++++++++++--------------
 1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3a651b366..05175b8a2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3916,28 +3916,44 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
-	/* Validate the CSB entries for both directions. */
+	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
-		struct nm_csb_atok *csb_atok =
-			(struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-		unsigned int num_entries;
-		size_t csb_size;
-		int err;
+		int num_entries;
 
 		num_entries = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
 			      priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
-		csb_size = num_entries * sizeof(*csb_atok);
 
-		if (csb_size) {
-			void *tmp = nm_os_malloc(csb_size);
-			if (!tmp) {
-				return ENOMEM;
-			}
-			err = copyin(csb_atok, tmp, csb_size);
-			nm_os_free(tmp);
-			if (err) {
-				nm_prerr("Invalid CSB address\n");
-				return err;
+		if (num_entries > 0) {
+			size_t entry_size[2];
+			int err;
+			int i;
+
+			entry_size[0] = sizeof(struct nm_csb_atok);
+			entry_size[1] = sizeof(struct nm_csb_ktoa);
+
+			for (i = 0; i < 2; i++) {
+				size_t csb_size = num_entries * entry_size[i];
+				void *tmp = nm_os_malloc(csb_size);
+				void *csb_ptr;
+
+				if (!tmp) {
+					return ENOMEM;
+				}
+				if (i == 0) {
+					csb_ptr = (void *)(uintptr_t)req->csb_atok;
+					/* Application --> kernel direction. */
+					err = copyin(csb_ptr, tmp, csb_size);
+				} else {
+					/* Kernel --> application direction. */
+					memset(tmp, 0, csb_size);
+					csb_ptr = (void *)(uintptr_t)req->csb_ktoa;
+					err = copyout(tmp, csb_ptr, csb_size);
+				}
+				nm_os_free(tmp);
+				if (err) {
+					nm_prerr("Invalid CSB address\n");
+					return err;
+				}
 			}
 		}
 	}

From ed626e69520954647bc4d227270bca84a1276546 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 19:05:16 +0200
Subject: [PATCH 1248/2207] netmap_sync_kloop: minor simplifications to the
 validation code

---
 sys/dev/netmap/netmap.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 05175b8a2..f701a6e19 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3905,6 +3905,8 @@ int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
 	struct netmap_adapter *na;
+	struct nm_csb_atok* csb_atok;
+	struct nm_csb_ktoa* csb_ktoa;
 
 	if (priv->np_nifp == NULL) {
 		return ENXIO;
@@ -3916,6 +3918,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	csb_atok = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+	csb_ktoa = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+
 	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
 		int num_entries;
@@ -3928,26 +3933,27 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			int err;
 			int i;
 
-			entry_size[0] = sizeof(struct nm_csb_atok);
-			entry_size[1] = sizeof(struct nm_csb_ktoa);
+			entry_size[0] = sizeof(*csb_atok);
+			entry_size[1] = sizeof(*csb_ktoa);
 
 			for (i = 0; i < 2; i++) {
+				/* On Linux we could use access_ok() to simplify
+				 * the validation. However, the advantage of
+				 * this approach is that it works also on
+				 * FreeBSD. */
 				size_t csb_size = num_entries * entry_size[i];
 				void *tmp = nm_os_malloc(csb_size);
-				void *csb_ptr;
 
 				if (!tmp) {
 					return ENOMEM;
 				}
 				if (i == 0) {
-					csb_ptr = (void *)(uintptr_t)req->csb_atok;
 					/* Application --> kernel direction. */
-					err = copyin(csb_ptr, tmp, csb_size);
+					err = copyin(csb_atok, tmp, csb_size);
 				} else {
 					/* Kernel --> application direction. */
 					memset(tmp, 0, csb_size);
-					csb_ptr = (void *)(uintptr_t)req->csb_ktoa;
-					err = copyout(tmp, csb_ptr, csb_size);
+					err = copyout(tmp, csb_ktoa, csb_size);
 				}
 				nm_os_free(tmp);
 				if (err) {

From 972d97db181a314ff8166af97a7769760079ea27 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 19:54:21 +0200
Subject: [PATCH 1249/2207] sync-kloop: introduce np_kloop_on field in the
 netmap priv

---
 sys/dev/netmap/netmap.c      | 33 ++++++++++++++++++++++++++++++---
 sys/dev/netmap/netmap_kern.h |  1 +
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f701a6e19..371840247 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1925,6 +1925,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	}
 	priv->np_flags = 0;
 	priv->np_txpoll = 0;
+	priv->np_kloop_on = 0;
 }
 
 
@@ -3907,6 +3908,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	struct netmap_adapter *na;
 	struct nm_csb_atok* csb_atok;
 	struct nm_csb_ktoa* csb_ktoa;
+	int err = 0;
 
 	if (priv->np_nifp == NULL) {
 		return ENXIO;
@@ -3918,6 +3920,17 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	/* Make sure that there is no kloop already active. */
+	NMG_LOCK();
+	if (priv->np_kloop_on) {
+		err = EBUSY;
+	}
+	priv->np_kloop_on = 1;
+	NMG_UNLOCK();
+	if (err) {
+		return err;
+	}
+
 	csb_atok = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
 	csb_ktoa = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
 
@@ -3930,8 +3943,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 		if (num_entries > 0) {
 			size_t entry_size[2];
-			int err;
-			int i;
+			unsigned int i;
 
 			entry_size[0] = sizeof(*csb_atok);
 			entry_size[1] = sizeof(*csb_ktoa);
@@ -3964,7 +3976,22 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
-	return ENOSYS;
+	while (NM_ACCESS_ONCE(priv->np_kloop_on)) {
+		unsigned int i;
+
+		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
+			struct netmap_kring *kring = NMR(na, NR_TX)[i];
+
+			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+				continue;
+			}
+
+			nm_kr_put(kring);
+		}
+		break;
+	}
+
+	return 0;
 }
 
 /*
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8c5a63f60..aa1e6c79a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1868,6 +1868,7 @@ struct netmap_priv_d {
 	u_int		np_qfirst[NR_TXRX],
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
 	uint16_t	np_txpoll;
+	uint16_t        np_kloop_on;	/* use with NMG_LOCK held */
 	int             np_sync_flags; /* to be passed to nm_sync */
 
 	int		np_refs;	/* use with NMG_LOCK held */

From 01109b352e1de297969391990baee155efedb7ef Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 23:17:13 +0200
Subject: [PATCH 1250/2207] sync-kloop: introduce np_kloop_state to handle
 start and stop

---
 sys/dev/netmap/netmap.c      | 16 +++++++++++-----
 sys/dev/netmap/netmap_kern.h |  5 ++++-
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 371840247..bd4aed007 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1925,7 +1925,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	}
 	priv->np_flags = 0;
 	priv->np_txpoll = 0;
-	priv->np_kloop_on = 0;
+	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
 }
 
 
@@ -3920,12 +3920,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
-	/* Make sure that there is no kloop already active. */
+	/* Make sure that no kloop is active or about to stop. */
 	NMG_LOCK();
-	if (priv->np_kloop_on) {
+	if (priv->np_kloop_state != NM_SYNC_KLOOP_NONE) {
 		err = EBUSY;
+	} else {
+		priv->np_kloop_state = NM_SYNC_KLOOP_ACTIVE;
 	}
-	priv->np_kloop_on = 1;
 	NMG_UNLOCK();
 	if (err) {
 		return err;
@@ -3976,7 +3977,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
-	while (NM_ACCESS_ONCE(priv->np_kloop_on)) {
+	while (likely(NM_ACCESS_ONCE(priv->np_kloop_state) != NM_SYNC_KLOOP_STOPPING)) {
 		unsigned int i;
 
 		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
@@ -3991,6 +3992,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		break;
 	}
 
+	/* Reset the kloop state. */
+	NMG_LOCK();
+	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
+	NMG_UNLOCK();
+
 	return 0;
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index aa1e6c79a..144852b20 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1868,7 +1868,10 @@ struct netmap_priv_d {
 	u_int		np_qfirst[NR_TXRX],
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
 	uint16_t	np_txpoll;
-	uint16_t        np_kloop_on;	/* use with NMG_LOCK held */
+	uint16_t        np_kloop_state;	/* use with NMG_LOCK held */
+#define NM_SYNC_KLOOP_NONE	0
+#define NM_SYNC_KLOOP_ACTIVE	1
+#define NM_SYNC_KLOOP_STOPPING	2
 	int             np_sync_flags; /* to be passed to nm_sync */
 
 	int		np_refs;	/* use with NMG_LOCK held */

From aebfba2e115957ed0aae3ea2492245e3da77c915 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Sep 2018 23:21:59 +0200
Subject: [PATCH 1251/2207] netmap_ioctl: implement NETMAP_REQ_SYNC_KLOOP_STOP

---
 sys/dev/netmap/netmap.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bd4aed007..86e035d5e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2636,7 +2636,17 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_STOP: {
-			error = ENOSYS;
+			NMG_LOCK();
+			switch (priv->np_kloop_state) {
+			case NM_SYNC_KLOOP_NONE:
+				error = ENXIO;
+				break;
+			case NM_SYNC_KLOOP_ACTIVE:
+			case NM_SYNC_KLOOP_STOPPING:
+				priv->np_kloop_state = NM_SYNC_KLOOP_STOPPING;
+				break;
+			}
+			NMG_UNLOCK();
 			break;
 		}
 

From 5761cd838c310c13bbb3f67aae4804a75eaf558e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 09:51:36 +0200
Subject: [PATCH 1252/2207] ctrl-api-test: add sync_kloop positive test

---
 sys/dev/netmap/netmap.c |  2 +-
 utils/ctrl-api-test.c   | 80 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 86e035d5e..a1dc0653e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3999,7 +3999,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 			nm_kr_put(kring);
 		}
-		break;
+		usleep_range(2000, 2000);
 	}
 
 	/* Reset the kloop state. */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5a9a25005..c60c53b12 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -10,9 +10,10 @@
 #include 
 #include 
 #include 
+#include 
 
 struct TestContext {
-	int fd;                 /* netmap file descriptor */
+	int fd; /* netmap file descriptor */
 	const char *ifname;
 	const char *bdgname;
 	uint32_t nr_tx_slots;   /* slots in tx rings */
@@ -798,6 +799,82 @@ duplicate_extmem_options(struct TestContext *ctx)
 }
 #endif /* CONFIG_NETMAP_EXTMEM */
 
+static void *
+sync_kloop_worker(void *opaque)
+{
+	struct TestContext *ctx = opaque;
+	size_t num_entries      = ctx->nr_rx_rings + ctx->nr_tx_rings;
+	struct nmreq_sync_kloop_start req;
+	struct nmreq_header hdr;
+	void *csb;
+	int ret;
+
+	csb = malloc((sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	             num_entries);
+	if (!csb) {
+		printf("Failed to allocate CSB memory\n");
+		return NULL;
+	}
+
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
+	hdr.nr_body    = (uintptr_t)&req;
+	hdr.nr_options = (uintptr_t)ctx->nr_opt;
+	memset(&req, 0, sizeof(req));
+	req.csb_atok = (uintptr_t)csb;
+	req.csb_ktoa =
+	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+		return NULL;
+	}
+
+	free(csb);
+
+	return NULL;
+}
+
+static int
+sync_kloop(struct TestContext *ctx)
+{
+	int ret = port_register_hwall(ctx);
+	pthread_t th;
+
+	if (ret) {
+		return ret;
+	}
+
+	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
+	if (ret) {
+		printf("pthread_create(kloop): %s\n", strerror(ret));
+		return -1;
+	}
+
+	sleep(1);
+
+	{
+		struct nmreq_header hdr;
+
+		nmreq_hdr_init(&hdr, ctx->ifname);
+		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+			return ret;
+		}
+	}
+
+	ret = pthread_join(th, NULL);
+	if (ret) {
+		printf("pthread_join(kloop): %s\n", strerror(ret));
+	}
+
+	return 0;
+}
+
 static void
 usage(const char *prog)
 {
@@ -835,6 +912,7 @@ static struct mytest tests[] = {
 	decltest(bad_extmem_option),
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
+	decltest(sync_kloop),
 };
 
 int

From 2e541b4da872ff7a0df961349105a4318b66d6ed Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 10:41:24 +0200
Subject: [PATCH 1253/2207] sync-kloop: allow posted "stop request"

---
 sys/dev/netmap/netmap.c      | 24 +++++++++---------------
 sys/dev/netmap/netmap_kern.h |  5 ++---
 2 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a1dc0653e..95f8b1bd3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1925,7 +1925,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	}
 	priv->np_flags = 0;
 	priv->np_txpoll = 0;
-	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
+	priv->np_kloop_state = 0;
 }
 
 
@@ -2637,15 +2637,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 		case NETMAP_REQ_SYNC_KLOOP_STOP: {
 			NMG_LOCK();
-			switch (priv->np_kloop_state) {
-			case NM_SYNC_KLOOP_NONE:
-				error = ENXIO;
-				break;
-			case NM_SYNC_KLOOP_ACTIVE:
-			case NM_SYNC_KLOOP_STOPPING:
-				priv->np_kloop_state = NM_SYNC_KLOOP_STOPPING;
-				break;
-			}
+			priv->np_kloop_state |= NM_SYNC_KLOOP_STOPPING;
 			NMG_UNLOCK();
 			break;
 		}
@@ -3932,11 +3924,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 	/* Make sure that no kloop is active or about to stop. */
 	NMG_LOCK();
-	if (priv->np_kloop_state != NM_SYNC_KLOOP_NONE) {
+	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
 		err = EBUSY;
-	} else {
-		priv->np_kloop_state = NM_SYNC_KLOOP_ACTIVE;
 	}
+	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
 	NMG_UNLOCK();
 	if (err) {
 		return err;
@@ -3987,7 +3978,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
-	while (likely(NM_ACCESS_ONCE(priv->np_kloop_state) != NM_SYNC_KLOOP_STOPPING)) {
+	for (;;) {
 		unsigned int i;
 
 		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
@@ -4000,11 +3991,14 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 		usleep_range(2000, 2000);
+		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
+			break;
+		}
 	}
 
 	/* Reset the kloop state. */
 	NMG_LOCK();
-	priv->np_kloop_state = NM_SYNC_KLOOP_NONE;
+	priv->np_kloop_state = 0;
 	NMG_UNLOCK();
 
 	return 0;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 144852b20..eee4b3ff9 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1869,9 +1869,8 @@ struct netmap_priv_d {
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
 	uint16_t	np_txpoll;
 	uint16_t        np_kloop_state;	/* use with NMG_LOCK held */
-#define NM_SYNC_KLOOP_NONE	0
-#define NM_SYNC_KLOOP_ACTIVE	1
-#define NM_SYNC_KLOOP_STOPPING	2
+#define NM_SYNC_KLOOP_RUNNING	(1 << 0)
+#define NM_SYNC_KLOOP_STOPPING	(1 << 1)
 	int             np_sync_flags; /* to be passed to nm_sync */
 
 	int		np_refs;	/* use with NMG_LOCK held */

From 7c90619122825c862263d4f88c35d740feb6788b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 12:56:29 +0200
Subject: [PATCH 1254/2207] ctrl-api-test: sync_loop_worker: check that CSB
 size is > 0

---
 utils/ctrl-api-test.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index c60c53b12..81de226e1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -11,6 +11,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct TestContext {
 	int fd; /* netmap file descriptor */
@@ -806,17 +807,21 @@ sync_kloop_worker(void *opaque)
 	size_t num_entries      = ctx->nr_rx_rings + ctx->nr_tx_rings;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
+	size_t csb_size;
 	void *csb;
 	int ret;
 
-	csb = malloc((sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	             num_entries);
+	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	             num_entries;
+	assert(csb_size > 0);
+	csb = malloc(csb_size);
 	if (!csb) {
 		printf("Failed to allocate CSB memory\n");
 		return NULL;
 	}
 
-	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
+		(unsigned)csb_size, ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;

From a45f8f59792c48b6f81f2d4cfea5e0b150d92ad4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 14:33:26 +0200
Subject: [PATCH 1255/2207] utils: ctrl-api-test: introduce
 TextContext::retcode

This is useful to collect the return code of a thread.
---
 utils/ctrl-api-test.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 81de226e1..29dc99140 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -32,6 +32,8 @@ struct TestContext {
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
 	struct nmreq_option *nr_opt;  /* list of options */
+
+	int retcode;
 };
 
 #if 0
@@ -811,6 +813,8 @@ sync_kloop_worker(void *opaque)
 	void *csb;
 	int ret;
 
+	ctx->retcode = -1;
+
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
 	             num_entries;
 	assert(csb_size > 0);
@@ -838,6 +842,7 @@ sync_kloop_worker(void *opaque)
 	}
 
 	free(csb);
+	ctx->retcode = 0;
 
 	return NULL;
 }
@@ -858,8 +863,6 @@ sync_kloop(struct TestContext *ctx)
 		return -1;
 	}
 
-	sleep(1);
-
 	{
 		struct nmreq_header hdr;
 
@@ -877,7 +880,7 @@ sync_kloop(struct TestContext *ctx)
 		printf("pthread_join(kloop): %s\n", strerror(ret));
 	}
 
-	return 0;
+	return ctx->retcode;
 }
 
 static void

From 788e190ce6c93803f3c99a43515f23f20745caf8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 15:10:16 +0200
Subject: [PATCH 1256/2207] ctrl-api-test: check that only one sync kloop can
 be created

---
 utils/ctrl-api-test.c | 66 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 11 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 29dc99140..b02c5317b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -32,8 +32,6 @@ struct TestContext {
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
 	struct nmreq_option *nr_opt;  /* list of options */
-
-	int retcode;
 };
 
 #if 0
@@ -813,15 +811,13 @@ sync_kloop_worker(void *opaque)
 	void *csb;
 	int ret;
 
-	ctx->retcode = -1;
-
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
 	             num_entries;
 	assert(csb_size > 0);
 	csb = malloc(csb_size);
 	if (!csb) {
 		printf("Failed to allocate CSB memory\n");
-		return NULL;
+		pthread_exit((void *)-1);
 	}
 
 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
@@ -838,13 +834,10 @@ sync_kloop_worker(void *opaque)
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
-		return NULL;
 	}
-
 	free(csb);
-	ctx->retcode = 0;
 
-	return NULL;
+	pthread_exit((void *)(uintptr_t)ret);
 }
 
 static int
@@ -852,6 +845,7 @@ sync_kloop(struct TestContext *ctx)
 {
 	int ret = port_register_hwall(ctx);
 	pthread_t th;
+	int thret;
 
 	if (ret) {
 		return ret;
@@ -875,12 +869,61 @@ sync_kloop(struct TestContext *ctx)
 		}
 	}
 
-	ret = pthread_join(th, NULL);
+	ret = pthread_join(th, (void **)&thret);
 	if (ret) {
 		printf("pthread_join(kloop): %s\n", strerror(ret));
 	}
 
-	return ctx->retcode;
+	return thret;
+}
+
+static int
+sync_kloop_conflict(struct TestContext *ctx)
+{
+	int ret = port_register_hwall(ctx);
+	pthread_t th1, th2;
+	int thret1, thret2;
+
+	if (ret) {
+		return ret;
+	}
+
+	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
+	if (ret) {
+		printf("pthread_create(kloop1): %s\n", strerror(ret));
+		return -1;
+	}
+
+	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
+	if (ret) {
+		printf("pthread_create(kloop2): %s\n", strerror(ret));
+		return -1;
+	}
+
+	{
+		struct nmreq_header hdr;
+
+		nmreq_hdr_init(&hdr, ctx->ifname);
+		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+			return ret;
+		}
+	}
+
+	ret = pthread_join(th1, (void **)&thret1);
+	if (ret) {
+		printf("pthread_join(kloop1): %s\n", strerror(ret));
+	}
+
+	ret = pthread_join(th2, (void **)&thret2);
+	if (ret) {
+		printf("pthread_join(kloop2): %s\n", strerror(ret));
+	}
+
+	return ((thret1 == 0 && thret2 != 0) ||
+		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
 }
 
 static void
@@ -921,6 +964,7 @@ static struct mytest tests[] = {
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
+	decltest(sync_kloop_conflict),
 };
 
 int

From d4b3aae5dc85ea62c1157d0c65a41d9126c40293 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 15:17:51 +0200
Subject: [PATCH 1257/2207] utils: ctrl-api-test: add a usleep() to avoid a
 race condition

---
 utils/ctrl-api-test.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b02c5317b..661e265a1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -900,6 +900,10 @@ sync_kloop_conflict(struct TestContext *ctx)
 		return -1;
 	}
 
+	/* Try to avoid a race condition where th1 starts the loop and stops, and
+	 * after that th2 starts the loop successfully. */
+	usleep(500000);
+
 	{
 		struct nmreq_header hdr;
 
@@ -922,6 +926,7 @@ sync_kloop_conflict(struct TestContext *ctx)
 		printf("pthread_join(kloop2): %s\n", strerror(ret));
 	}
 
+	/* Check that one of the two failed, while the other one succeeded. */
 	return ((thret1 == 0 && thret2 != 0) ||
 		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
 }

From fff22ee4899f640a739077d1e1140f5368a09458 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 15:29:20 +0200
Subject: [PATCH 1258/2207] ctrl-api-test: sync-kloop: add negative test for
 invalid CSB

---
 utils/ctrl-api-test.c | 70 ++++++++++++++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 20 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 661e265a1..39795840a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -800,6 +800,22 @@ duplicate_extmem_options(struct TestContext *ctx)
 }
 #endif /* CONFIG_NETMAP_EXTMEM */
 
+static int
+sync_kloop_stop(struct TestContext *ctx)
+{
+	struct nmreq_header hdr;
+	int ret;
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+	}
+
+	return ret;
+}
+
 static void *
 sync_kloop_worker(void *opaque)
 {
@@ -857,16 +873,9 @@ sync_kloop(struct TestContext *ctx)
 		return -1;
 	}
 
-	{
-		struct nmreq_header hdr;
-
-		nmreq_hdr_init(&hdr, ctx->ifname);
-		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-		if (ret) {
-			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
-			return ret;
-		}
+	ret = sync_kloop_stop(ctx);
+	if (ret) {
+		return ret;
 	}
 
 	ret = pthread_join(th, (void **)&thret);
@@ -904,16 +913,9 @@ sync_kloop_conflict(struct TestContext *ctx)
 	 * after that th2 starts the loop successfully. */
 	usleep(500000);
 
-	{
-		struct nmreq_header hdr;
-
-		nmreq_hdr_init(&hdr, ctx->ifname);
-		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-		if (ret) {
-			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
-			return ret;
-		}
+	ret = sync_kloop_stop(ctx);
+	if (ret) {
+		return ret;
 	}
 
 	ret = pthread_join(th1, (void **)&thret1);
@@ -931,6 +933,33 @@ sync_kloop_conflict(struct TestContext *ctx)
 		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
 }
 
+static int
+sync_kloop_invalid_csb(struct TestContext *ctx)
+{
+	int ret = port_register_hwall(ctx);
+	struct nmreq_sync_kloop_start req;
+	struct nmreq_header hdr;
+
+	/* Post a stop request first. */
+	ret = sync_kloop_stop(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
+	hdr.nr_body    = (uintptr_t)&req;
+	memset(&req, 0, sizeof(req));
+	req.csb_atok = (uintptr_t)0x10;
+	req.csb_ktoa = (uintptr_t)0x800;
+	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+	}
+
+	return (ret < 0) ? 0 : -1;
+}
+
 static void
 usage(const char *prog)
 {
@@ -970,6 +999,7 @@ static struct mytest tests[] = {
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
 	decltest(sync_kloop_conflict),
+	decltest(sync_kloop_invalid_csb),
 };
 
 int

From 1bad7326a04bffdcc8427d05bfd1facaf771ae39 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 17:18:22 +0200
Subject: [PATCH 1259/2207] sync-kloop: check for CSB alignment

---
 sys/dev/netmap/netmap.c | 15 ++++++++++++---
 utils/ctrl-api-test.c   |  4 ++--
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 95f8b1bd3..1bbee4f55 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3945,10 +3945,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 
 		if (num_entries > 0) {
 			size_t entry_size[2];
+			void *csb_start[2];
 			unsigned int i;
 
 			entry_size[0] = sizeof(*csb_atok);
 			entry_size[1] = sizeof(*csb_ktoa);
+			csb_start[0] = (void *)csb_atok;
+			csb_start[1] = (void *)csb_ktoa;
 
 			for (i = 0; i < 2; i++) {
 				/* On Linux we could use access_ok() to simplify
@@ -3956,18 +3959,24 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 				 * this approach is that it works also on
 				 * FreeBSD. */
 				size_t csb_size = num_entries * entry_size[i];
-				void *tmp = nm_os_malloc(csb_size);
+				void *tmp;
 
+				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
+					nm_prerr("Unaligned CSB address\n");
+					return EINVAL;
+				}
+
+				tmp = nm_os_malloc(csb_size);
 				if (!tmp) {
 					return ENOMEM;
 				}
 				if (i == 0) {
 					/* Application --> kernel direction. */
-					err = copyin(csb_atok, tmp, csb_size);
+					err = copyin(csb_start[i], tmp, csb_size);
 				} else {
 					/* Kernel --> application direction. */
 					memset(tmp, 0, csb_size);
-					err = copyout(tmp, csb_ktoa, csb_size);
+					err = copyout(tmp, csb_start[i], csb_size);
 				}
 				nm_os_free(tmp);
 				if (err) {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 39795840a..5d72bbbcc 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -830,8 +830,8 @@ sync_kloop_worker(void *opaque)
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
 	             num_entries;
 	assert(csb_size > 0);
-	csb = malloc(csb_size);
-	if (!csb) {
+	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
+	if (ret) {
 		printf("Failed to allocate CSB memory\n");
 		pthread_exit((void *)-1);
 	}

From 4e409f2e9935bb08fb6d3ff5683d75f1198da901 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 18:07:12 +0200
Subject: [PATCH 1260/2207] sync-kloop: introduce TX processing loop

---
 sys/dev/netmap/netmap.c | 239 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 224 insertions(+), 15 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1bbee4f55..05a99f0c0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3904,12 +3904,217 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
+/* Functions to read and write CSB fields from the kernel. */
+#if defined (linux)
+#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
+#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
+#else  /* ! linux */
+#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
+#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
+#endif /* ! linux */
+
+/* Write kring pointers (hwcur, hwtail) to the CSB.
+ * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
+static inline void
+sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
+			   uint32_t hwtail)
+{
+	/*
+	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
+	 * We allow the guest to read a value of hwcur more recent than the value
+	 * of hwtail, since this would anyway result in a consistent view of the
+	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
+	 * behind head).
+	 *
+	 * The following memory barrier scheme is used to make this happen:
+	 *
+	 *          Guest                Host
+	 *
+	 *          STORE(hwcur)         LOAD(hwtail)
+	 *          mb() <-------------> mb()
+	 *          STORE(hwtail)        LOAD(hwcur)
+	 */
+	CSB_WRITE(ptr, hwcur, hwcur);
+	mb();
+	CSB_WRITE(ptr, hwtail, hwtail);
+}
+
+/* Read kring pointers (head, cur, sync_flags) from the CSB.
+ * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
+static inline void
+sync_kloop_read_kring_csb(struct nm_csb_atok __user *ptr,
+			  struct netmap_ring *shadow_ring,
+			  uint32_t num_slots)
+{
+	/*
+	 * We place a memory barrier to make sure that the update of head never
+	 * overtakes the update of cur.
+	 * (see explanation in ptnetmap_guest_write_kring_csb).
+	 */
+	CSB_READ(ptr, head, shadow_ring->head);
+	mb();
+	CSB_READ(ptr, cur, shadow_ring->cur);
+	CSB_READ(ptr, sync_flags, shadow_ring->flags);
+}
+
+/* Enable or disable guest --> host kicks. */
+static inline void
+csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
+{
+	CSB_WRITE(csb_ktoa, kern_need_kick, val);
+}
+
+/* Are guest interrupt enabled or disabled? */
+static inline uint32_t
+csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
+{
+	uint32_t v;
+
+	CSB_READ(csb_atok, appl_need_kick, v);
+
+	return v;
+}
+
+static inline void
+sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
+{
+	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
+		" rtail: %d head: %d cur: %d tail: %d",
+		title, kring->name, kring->nr_hwcur,
+		kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
+		kring->ring->head, kring->ring->cur, kring->ring->tail);
+}
+
+static void
+netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
+			  struct nm_csb_atok *csb_atok,
+			  struct nm_csb_ktoa *csb_ktoa)
+{
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	bool more_txspace = false;
+	uint32_t num_slots;
+	int batch;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable guest --> host notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the guest kring pointers from the CSB */
+	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		batch = shadow_ring.head - kring->nr_hwcur;
+		if (batch < 0)
+			batch += num_slots;
+
+#ifdef PTN_TX_BATCH_LIM
+		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
+			/* If guest moves ahead too fast, let's cut the move so
+			 * that we don't exceed our batch limit. */
+			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
+
+			if (head_lim >= num_slots)
+				head_lim -= num_slots;
+			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
+					head_lim);
+			shadow_ring.head = head_lim;
+			batch = PTN_TX_BATCH_LIM(num_slots);
+		}
+#endif /* PTN_TX_BATCH_LIM */
+
+		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
+			shadow_ring.flags |= NAF_FORCE_RECLAIM;
+		}
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("pre txsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR txsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy host hwcur and hwtail into the CSB for the guest sync(), and
+		 * do the nm_sync_finalize.
+		 */
+		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur,
+				kring->nr_hwtail);
+		if (kring->rtail != kring->nr_hwtail) {
+			/* Some more room available in the parent adapter. */
+			kring->rtail = kring->nr_hwtail;
+			more_txspace = true;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("post txsync", kring);
+		}
+
+#ifndef BUSY_WAIT
+		/* Interrupt the guest if needed. */
+		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable guest kick to avoid sending unnecessary kicks */
+			// nm_os_kctx_send_irq(kth); // TODO
+			more_txspace = false;
+		}
+#endif
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+#ifndef BUSY_WAIT
+		if (shadow_ring.head == kring->rhead) {
+			/*
+			 * No more packets to transmit. We enable notifications and
+			 * go to sleep, waiting for a kick from the guest when new
+			 * new slots are ready for transmission.
+			 */
+			usleep_range(1,1);
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			if (shadow_ring.head != kring->rhead) {
+				/* We won the race condition, there are more packets to
+				 * transmit. Disable notifications and do another cycle */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		if (nm_kr_txempty(kring)) {
+			/* No more available TX slots. We stop waiting for a notification
+			 * from the backend (netmap_tx_irq). */
+			ND(1, "TX ring");
+			break;
+		}
+#endif
+	}
+
+	if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
+		// nm_os_kctx_send_irq(kth); // TODO
+	}
+}
+
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
+	struct nm_csb_atok* csb_atok_base;
+	struct nm_csb_ktoa* csb_ktoa_base;
+	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
-	struct nm_csb_atok* csb_atok;
-	struct nm_csb_ktoa* csb_ktoa;
 	int err = 0;
 
 	if (priv->np_nifp == NULL) {
@@ -3933,25 +4138,24 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return err;
 	}
 
-	csb_atok = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-	csb_ktoa = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
+	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
 
 	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
-		int num_entries;
-
-		num_entries = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
-			      priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+		int num_entries = num_rx_rings + num_tx_rings;
 
 		if (num_entries > 0) {
 			size_t entry_size[2];
 			void *csb_start[2];
 			unsigned int i;
 
-			entry_size[0] = sizeof(*csb_atok);
-			entry_size[1] = sizeof(*csb_ktoa);
-			csb_start[0] = (void *)csb_atok;
-			csb_start[1] = (void *)csb_ktoa;
+			entry_size[0] = sizeof(*csb_atok_base);
+			entry_size[1] = sizeof(*csb_ktoa_base);
+			csb_start[0] = (void *)csb_atok_base;
+			csb_start[1] = (void *)csb_ktoa_base;
 
 			for (i = 0; i < 2; i++) {
 				/* On Linux we could use access_ok() to simplify
@@ -3990,16 +4194,21 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	for (;;) {
 		unsigned int i;
 
-		for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
-			struct netmap_kring *kring = NMR(na, NR_TX)[i];
+		for (i = 0; i < num_tx_rings; i++) {
+			struct netmap_kring *kring =
+				NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
+			struct nm_csb_atok* csb_atok = csb_atok_base + i;
+			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + i;
 
 			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
 				continue;
 			}
-
+			netmap_sync_kloop_tx_ring(kring, csb_atok, csb_ktoa);
 			nm_kr_put(kring);
 		}
+
 		usleep_range(2000, 2000);
+
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
 		}

From dc09db8607b298be3382729929313b525d3ca01f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 18:13:15 +0200
Subject: [PATCH 1261/2207] sync-kloop: add/fix some comments

---
 sys/dev/netmap/netmap.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 05a99f0c0..583c3ab0d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3921,14 +3921,14 @@ sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 {
 	/*
 	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
-	 * We allow the guest to read a value of hwcur more recent than the value
+	 * We allow the application to read a value of hwcur more recent than the value
 	 * of hwtail, since this would anyway result in a consistent view of the
 	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
 	 * behind head).
 	 *
 	 * The following memory barrier scheme is used to make this happen:
 	 *
-	 *          Guest                Host
+	 *          Application          Kernel
 	 *
 	 *          STORE(hwcur)         LOAD(hwtail)
 	 *          mb() <-------------> mb()
@@ -3957,14 +3957,14 @@ sync_kloop_read_kring_csb(struct nm_csb_atok __user *ptr,
 	CSB_READ(ptr, sync_flags, shadow_ring->flags);
 }
 
-/* Enable or disable guest --> host kicks. */
+/* Enable or disable application --> kernel kicks. */
 static inline void
 csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
 {
 	CSB_WRITE(csb_ktoa, kern_need_kick, val);
 }
 
-/* Are guest interrupt enabled or disabled? */
+/* Are application interrupt enabled or disabled? */
 static inline uint32_t
 csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 {
@@ -3997,9 +3997,9 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 
 	num_slots = kring->nkr_num_slots;
 
-	/* Disable guest --> host notifications. */
+	/* Disable application --> kernel notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the guest kring pointers from the CSB */
+	/* Copy the application kring pointers from the CSB */
 	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
@@ -4009,7 +4009,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 
 #ifdef PTN_TX_BATCH_LIM
 		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
-			/* If guest moves ahead too fast, let's cut the move so
+			/* If application moves ahead too fast, let's cut the move so
 			 * that we don't exceed our batch limit. */
 			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
 
@@ -4048,7 +4048,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 
 		/*
 		 * Finalize
-		 * Copy host hwcur and hwtail into the CSB for the guest sync(), and
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
 		 * do the nm_sync_finalize.
 		 */
 		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur,
@@ -4064,9 +4064,9 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		}
 
 #ifndef BUSY_WAIT
-		/* Interrupt the guest if needed. */
+		/* Interrupt the application if needed. */
 		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable guest kick to avoid sending unnecessary kicks */
+			/* Disable application kick to avoid sending unnecessary kicks */
 			// nm_os_kctx_send_irq(kth); // TODO
 			more_txspace = false;
 		}
@@ -4077,7 +4077,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		if (shadow_ring.head == kring->rhead) {
 			/*
 			 * No more packets to transmit. We enable notifications and
-			 * go to sleep, waiting for a kick from the guest when new
+			 * go to sleep, waiting for a kick from the application when new
 			 * new slots are ready for transmission.
 			 */
 			usleep_range(1,1);
@@ -4127,7 +4127,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
-	/* Make sure that no kloop is active or about to stop. */
+	/* Make sure that no kloop is currently running. */
 	NMG_LOCK();
 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
 		err = EBUSY;
@@ -4191,9 +4191,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
+	/* Main loop. */
 	for (;;) {
 		unsigned int i;
 
+		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
 			struct netmap_kring *kring =
 				NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
@@ -4207,6 +4209,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
+		/* TODO process all the RX rings */
+
+		/* TODO replace with proper notifications and/or configurable
+		 * sleep interval. */
 		usleep_range(2000, 2000);
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {

From ac142811bc234c2c7fb760a4c48d8d06777a413b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 23:04:38 +0200
Subject: [PATCH 1262/2207] sync-kloop: introduce RX processing loop

---
 sys/dev/netmap/netmap.c | 136 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 135 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 583c3ab0d..da4ce2f4d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4108,6 +4108,128 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 	}
 }
 
+/* RX cycle without receive any packets */
+#define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
+
+static inline int
+sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
+{
+	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
+				kring->nkr_num_slots - 1));
+}
+
+static void
+netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
+		struct nm_csb_atok *csb_atok,
+		struct nm_csb_ktoa *csb_ktoa)
+{
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	int dry_cycles = 0;
+	bool some_recvd = false;
+	uint32_t num_slots;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the guest kring pointers from the CSB */
+	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		uint32_t hwtail;
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("pre rxsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR rxsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy host hwcur and hwtail into the CSB for the guest sync()
+		 */
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur, hwtail);
+		if (kring->rtail != hwtail) {
+			kring->rtail = hwtail;
+			some_recvd = true;
+			dry_cycles = 0;
+		} else {
+			dry_cycles++;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("post rxsync", kring);
+		}
+
+#ifndef BUSY_WAIT
+		/* Interrupt the guest if needed. */
+		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable guest kick to avoid sending unnecessary kicks */
+			//nm_os_kctx_send_irq(kth); // TODO
+			some_recvd = false;
+		}
+#endif
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+#ifndef BUSY_WAIT
+		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
+			/*
+			 * No more slots available for reception. We enable notification and
+			 * go to sleep, waiting for a kick from the guest when new receive
+			 * slots are available.
+			 */
+			usleep_range(1,1);
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
+				/* We won the race condition, more slots are available. Disable
+				 * notifications and do another cycle. */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		if (unlikely(hwtail == kring->rhead ||
+					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
+			/* No more packets to be read from the backend. We stop and
+			 * wait for a notification from the backend (netmap_rx_irq). */
+			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
+					hwtail, kring->rhead, dry_cycles);
+			break;
+		}
+#endif
+	}
+
+	nm_kr_put(kring);
+
+	/* Interrupt the guest if needed. */
+	if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		//nm_os_kctx_send_irq(kth); // TODO
+	}
+}
+
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
@@ -4209,7 +4331,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
-		/* TODO process all the RX rings */
+		/* Process all the RX rings bound to this file descriptor. */
+		for (i = 0; i < num_rx_rings; i++) {
+			struct netmap_kring *kring =
+				NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
+			struct nm_csb_atok* csb_atok = csb_atok_base + num_tx_rings + i;
+			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + num_tx_rings + i;
+
+			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+				continue;
+			}
+			netmap_sync_kloop_rx_ring(kring, csb_atok, csb_ktoa);
+			nm_kr_put(kring);
+		}
 
 		/* TODO replace with proper notifications and/or configurable
 		 * sleep interval. */

From d8ae8b7afeda677b19fdb4d1e186bd13e7064b99 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 23 Sep 2018 23:10:04 +0200
Subject: [PATCH 1263/2207] sync-kloop: fix some comments

---
 sys/dev/netmap/netmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index da4ce2f4d..b36143de0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4120,8 +4120,8 @@ sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
 
 static void
 netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
-		struct nm_csb_atok *csb_atok,
-		struct nm_csb_ktoa *csb_ktoa)
+			  struct nm_csb_atok *csb_atok,
+			  struct nm_csb_ktoa *csb_ktoa)
 {
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	int dry_cycles = 0;
@@ -4135,7 +4135,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 	/* Disable notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the guest kring pointers from the CSB */
+	/* Copy the application kring pointers from the CSB */
 	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
@@ -4163,7 +4163,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 		/*
 		 * Finalize
-		 * Copy host hwcur and hwtail into the CSB for the guest sync()
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
 		 */
 		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
 		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur, hwtail);
@@ -4180,9 +4180,9 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		}
 
 #ifndef BUSY_WAIT
-		/* Interrupt the guest if needed. */
+		/* Interrupt the application if needed. */
 		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable guest kick to avoid sending unnecessary kicks */
+			/* Disable application kick to avoid sending unnecessary kicks */
 			//nm_os_kctx_send_irq(kth); // TODO
 			some_recvd = false;
 		}
@@ -4193,7 +4193,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
 			/*
 			 * No more slots available for reception. We enable notification and
-			 * go to sleep, waiting for a kick from the guest when new receive
+			 * go to sleep, waiting for a kick from the application when new receive
 			 * slots are available.
 			 */
 			usleep_range(1,1);
@@ -4224,7 +4224,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 	nm_kr_put(kring);
 
-	/* Interrupt the guest if needed. */
+	/* Interrupt the application if needed. */
 	if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
 		//nm_os_kctx_send_irq(kth); // TODO
 	}

From 7b6681f9e176a0de971dcd1fa11c8f789be82de4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Sep 2018 11:14:56 +0200
Subject: [PATCH 1264/2207] sync-kloop: remove conditional BUSY_WAIT code

---
 sys/dev/netmap/netmap.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b36143de0..0d9c8fe53 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4063,17 +4063,15 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			sync_kloop_kring_dump("post txsync", kring);
 		}
 
-#ifndef BUSY_WAIT
 		/* Interrupt the application if needed. */
 		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
 			// nm_os_kctx_send_irq(kth); // TODO
 			more_txspace = false;
 		}
-#endif
+
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
 		if (shadow_ring.head == kring->rhead) {
 			/*
 			 * No more packets to transmit. We enable notifications and
@@ -4100,7 +4098,6 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			ND(1, "TX ring");
 			break;
 		}
-#endif
 	}
 
 	if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
@@ -4179,17 +4176,15 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 			sync_kloop_kring_dump("post rxsync", kring);
 		}
 
-#ifndef BUSY_WAIT
 		/* Interrupt the application if needed. */
 		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
 			//nm_os_kctx_send_irq(kth); // TODO
 			some_recvd = false;
 		}
-#endif
+
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
 			/*
 			 * No more slots available for reception. We enable notification and
@@ -4219,7 +4214,6 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 					hwtail, kring->rhead, dry_cycles);
 			break;
 		}
-#endif
 	}
 
 	nm_kr_put(kring);

From dc0cb5a524bfe8234f6133f7025b0f47d5db0949 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Sep 2018 22:31:25 +0200
Subject: [PATCH 1265/2207] utils: add sync_kloop_test program

---
 utils/GNUmakefile       |   2 +-
 utils/sync_kloop_test.c | 129 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 utils/sync_kloop_test.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 0b7970654..249e41121 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,7 +1,7 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
 PROGS	  = test_select testmmap test_nm functional ctrl-api-test fd_server
-PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends extmem-example
+PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends extmem-example sync_kloop_test
 X86PROGS  = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
new file mode 100644
index 000000000..33a4eaef5
--- /dev/null
+++ b/utils/sync_kloop_test.c
@@ -0,0 +1,129 @@
+#include 
+#include 
+#include 
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static void *
+kloop_worker(void *opaque)
+{
+	struct nm_desc *nmd = opaque;
+	struct nmreq_sync_kloop_start req;
+	struct nmreq_header hdr;
+	size_t num_entries;
+	size_t csb_size;
+	void *csb;
+	int ret;
+
+	num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
+	              nmd->last_rx_ring - nmd->first_rx_ring + 1;
+	printf("Number of CSB entries = %d\n", (int)num_entries);
+	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	           num_entries;
+	assert(csb_size > 0);
+	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
+	if (ret) {
+		printf("Failed to allocate CSB memory\n");
+		return NULL;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.nr_version = NETMAP_API;
+	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
+	hdr.nr_body    = (uintptr_t)&req;
+	hdr.nr_options = (uintptr_t)NULL;
+	memset(&req, 0, sizeof(req));
+	req.csb_atok = (uintptr_t)csb;
+	req.csb_ktoa =
+	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
+	ret = ioctl(nmd->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+	}
+	free(csb);
+
+	return NULL;
+}
+
+static void
+usage(const char *progname)
+{
+	printf("%s\n"
+	       "[-h (show this help and exit)]\n"
+	       "-i NETMAP_PORT\n",
+	       progname);
+}
+
+int
+main(int argc, char **argv)
+{
+	const char *ifname = NULL;
+	struct nm_desc *nmd;
+	pthread_t th;
+	int opt;
+	int ret;
+
+	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+		switch (opt) {
+		case 'h':
+			usage(argv[0]);
+			return 0;
+
+		case 'i':
+			ifname = optarg;
+			break;
+
+		default:
+			printf("    Unrecognized option %c\n", opt);
+			usage(argv[0]);
+			return -1;
+		}
+	}
+
+	if (ifname == NULL) {
+		printf("No netmap port specified\n");
+		usage(argv[0]);
+		return -1;
+	}
+
+	printf("ifname %s\n", ifname);
+	nmd = nm_open(ifname, NULL, 0, NULL);
+	if (!nmd) {
+		printf("nm_open(%s) failed\n", ifname);
+		return -1;
+	}
+
+	ret = pthread_create(&th, NULL, kloop_worker, nmd);
+	if (ret) {
+		printf("pthread_create() failed: %s\n", strerror(ret));
+		nm_close(nmd);
+		return -1;
+	}
+
+	{
+		struct nmreq_header hdr;
+		int ret;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.nr_version = NETMAP_API;
+		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
+		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
+		}
+	}
+
+	ret = pthread_join(th, NULL);
+	if (ret) {
+		printf("pthread_join() failed: %s\n", strerror(ret));
+	}
+
+	nm_close(nmd);
+
+	return 0;
+}

From e206fc4dc02313b88b69293130ea0c201c6653cd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 27 Sep 2018 21:55:01 +0200
Subject: [PATCH 1266/2207] utils: sync_kloop_test: add data structure to keep
 context

---
 utils/sync_kloop_test.c | 36 +++++++++++++++++++++++++++---------
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 33a4eaef5..b0c8715f5 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -9,10 +9,16 @@
 #include 
 #include 
 
+struct context {
+	struct nm_desc *nmd;
+	const char *func;
+};
+
 static void *
 kloop_worker(void *opaque)
 {
-	struct nm_desc *nmd = opaque;
+	struct context *ctx = opaque;
+	struct nm_desc *nmd = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 	size_t num_entries;
@@ -55,6 +61,7 @@ usage(const char *progname)
 {
 	printf("%s\n"
 	       "[-h (show this help and exit)]\n"
+	       "[-f FUNCTION (rx,tx)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -63,12 +70,15 @@ int
 main(int argc, char **argv)
 {
 	const char *ifname = NULL;
-	struct nm_desc *nmd;
+	struct context ctx;
 	pthread_t th;
 	int opt;
 	int ret;
 
-	while ((opt = getopt(argc, argv, "hi:")) != -1) {
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.func = "rx";
+
+	while ((opt = getopt(argc, argv, "hi:f:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -78,6 +88,14 @@ main(int argc, char **argv)
 			ifname = optarg;
 			break;
 
+		case 'f':
+			ctx.func = optarg;
+			if (strcmp(optarg, "tx") && strcmp(optarg, "rx")) {
+				printf("    Unknown function %s\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -92,16 +110,16 @@ main(int argc, char **argv)
 	}
 
 	printf("ifname %s\n", ifname);
-	nmd = nm_open(ifname, NULL, 0, NULL);
-	if (!nmd) {
+	ctx.nmd = nm_open(ifname, NULL, 0, NULL);
+	if (!ctx.nmd) {
 		printf("nm_open(%s) failed\n", ifname);
 		return -1;
 	}
 
-	ret = pthread_create(&th, NULL, kloop_worker, nmd);
+	ret = pthread_create(&th, NULL, kloop_worker, &ctx);
 	if (ret) {
 		printf("pthread_create() failed: %s\n", strerror(ret));
-		nm_close(nmd);
+		nm_close(ctx.nmd);
 		return -1;
 	}
 
@@ -112,7 +130,7 @@ main(int argc, char **argv)
 		memset(&hdr, 0, sizeof(hdr));
 		hdr.nr_version = NETMAP_API;
 		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
+		ret            = ioctl(ctx.nmd->fd, NIOCCTRL, &hdr);
 		if (ret) {
 			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
 		}
@@ -123,7 +141,7 @@ main(int argc, char **argv)
 		printf("pthread_join() failed: %s\n", strerror(ret));
 	}
 
-	nm_close(nmd);
+	nm_close(ctx.nmd);
 
 	return 0;
 }

From 06e9c56841577ab0cdda3eca418cb94165f9913b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 27 Sep 2018 22:36:35 +0200
Subject: [PATCH 1267/2207] utils: sync_kloop_test: sketch transmit loop

---
 sys/net/netmap.h        |  2 +-
 utils/sync_kloop_test.c | 74 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 41fcef519..5e799ce45 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -719,7 +719,7 @@ struct nmreq_sync_kloop_start {
 struct nm_csb_atok {
 	uint32_t head;		  /* AW+ KR+ the head of the appl netmap_ring */
 	uint32_t cur;		  /* AW+ KR+ the cur of the appl netmap_ring */
-	uint32_t appl_need_kick; /* AW+ KR+ kern --> appl notification enable */
+	uint32_t appl_need_kick;  /* AW+ KR+ kern --> appl notification enable */
 	uint32_t sync_flags;	  /* AW+ KR+ the flags of the appl [tx|rx]sync() */
 	char pad[48];		  /* pad to a 64 bytes cacheline */
 };
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index b0c8715f5..d944ca3aa 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -8,6 +8,18 @@
 #include 
 #include 
 #include 
+#include 
+
+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+
+static int stop = 0;
+
+static void
+sigint_handler(int signum)
+{
+	(void)signum;
+	ACCESS_ONCE(stop) = 1;
+}
 
 struct context {
 	struct nm_desc *nmd;
@@ -20,6 +32,8 @@ kloop_worker(void *opaque)
 	struct context *ctx = opaque;
 	struct nm_desc *nmd = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
+	struct nm_csb_atok *atok_base;
+	struct nm_csb_ktoa *ktoa_base;
 	struct nmreq_header hdr;
 	size_t num_entries;
 	size_t csb_size;
@@ -37,6 +51,7 @@ kloop_worker(void *opaque)
 		printf("Failed to allocate CSB memory\n");
 		return NULL;
 	}
+	memset(csb, 0, csb_size);
 
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.nr_version = NETMAP_API;
@@ -51,6 +66,53 @@ kloop_worker(void *opaque)
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
+
+	atok_base = (struct nm_csb_atok *)csb;
+	ktoa_base = (struct nm_csb_ktoa *)(atok_base + num_entries);
+
+	if (!strcmp(ctx->func, "tx")) {
+		while (!ACCESS_ONCE(stop)) {
+			uint16_t r;
+
+			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
+			     r++) {
+				struct netmap_ring *ring =
+				        NETMAP_TXRING(nmd->nifp, r);
+				struct nm_csb_atok *atok = atok_base + r;
+				struct nm_csb_ktoa *ktoa = ktoa_base + r;
+				struct netmap_slot *slot;
+				uint32_t hwtail, head;
+
+				head   = atok->head;
+				hwtail = ACCESS_ONCE(ktoa->hwtail);
+
+				if (head == hwtail) {
+					continue;
+				}
+
+				slot        = ring->slot + head;
+				slot->len   = 60;
+				slot->flags = 0;
+				{
+					char *buf =
+					        NETMAP_BUF(ring, slot->buf_idx);
+					memset(buf, 0xFF, 6);
+					memset(buf + 6, 0, 6);
+					buf[12] = 0x08;
+					buf[13] = 0x00;
+					memset(buf + 14, 'x', slot->len - 14);
+				}
+				ACCESS_ONCE(atok->head) =
+				        ACCESS_ONCE(atok->cur) =
+				                nm_ring_next(ring, head);
+				printf("ring #%u, head %u, hwtail %u\n",
+				       (unsigned int)r, (unsigned int)head,
+				       (unsigned int)hwtail);
+			}
+			usleep(1000000);
+		}
+	}
+
 	free(csb);
 
 	return NULL;
@@ -75,6 +137,18 @@ main(int argc, char **argv)
 	int opt;
 	int ret;
 
+	{
+		struct sigaction sa;
+
+		sa.sa_handler = sigint_handler;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_RESTART;
+		if (sigaction(SIGINT, &sa, NULL)) {
+			perror("sigaction(SIGINT)");
+			exit(EXIT_FAILURE);
+		}
+	}
+
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.func = "rx";
 

From eda9767340ce4f311fc2796696029ce7eca461a2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 17:01:45 +0200
Subject: [PATCH 1268/2207] netmap.h: add functions to write/read from CSB

---
 sys/dev/netmap/netmap.c | 20 +++++++--------
 sys/net/netmap.h        | 57 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0d9c8fe53..05c7de38c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3916,7 +3916,7 @@ nm_clear_native_flags(struct netmap_adapter *na)
 /* Write kring pointers (hwcur, hwtail) to the CSB.
  * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
 static inline void
-sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
+sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 			   uint32_t hwtail)
 {
 	/*
@@ -3942,7 +3942,7 @@ sync_kloop_write_kring_csb(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 /* Read kring pointers (head, cur, sync_flags) from the CSB.
  * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
 static inline void
-sync_kloop_read_kring_csb(struct nm_csb_atok __user *ptr,
+sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
 			  struct netmap_ring *shadow_ring,
 			  uint32_t num_slots)
 {
@@ -4000,7 +4000,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 	/* Disable application --> kernel notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
 	/* Copy the application kring pointers from the CSB */
-	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
 		batch = shadow_ring.head - kring->nr_hwcur;
@@ -4051,7 +4051,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
 		 * do the nm_sync_finalize.
 		 */
-		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur,
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
 				kring->nr_hwtail);
 		if (kring->rtail != kring->nr_hwtail) {
 			/* Some more room available in the parent adapter. */
@@ -4071,7 +4071,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 		}
 
 		/* Read CSB to see if there is more work to do. */
-		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (shadow_ring.head == kring->rhead) {
 			/*
 			 * No more packets to transmit. We enable notifications and
@@ -4082,7 +4082,7 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */
-			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 			if (shadow_ring.head != kring->rhead) {
 				/* We won the race condition, there are more packets to
 				 * transmit. Disable notifications and do another cycle */
@@ -4133,7 +4133,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	/* Disable notifications. */
 	csb_ktoa_kick_enable(csb_ktoa, 0);
 	/* Copy the application kring pointers from the CSB */
-	sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 
 	for (;;) {
 		uint32_t hwtail;
@@ -4163,7 +4163,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
 		 */
 		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-		sync_kloop_write_kring_csb(csb_ktoa, kring->nr_hwcur, hwtail);
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
 		if (kring->rtail != hwtail) {
 			kring->rtail = hwtail;
 			some_recvd = true;
@@ -4184,7 +4184,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 		}
 
 		/* Read CSB to see if there is more work to do. */
-		sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
 			/*
 			 * No more slots available for reception. We enable notification and
@@ -4195,7 +4195,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */
-			sync_kloop_read_kring_csb(csb_atok, &shadow_ring, num_slots);
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
 				/* We won the race condition, more slots are available. Disable
 				 * notifications and do another cycle. */
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 5e799ce45..a48110728 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -731,6 +731,63 @@ struct nm_csb_ktoa {
 	char pad[4+48];
 };
 
+/* Application side of sync-kloop: Write ring pointers (cur, head) to the CSB.
+ * This routine is coupled with sync_kloop_kernel_read(). */
+static inline void
+nm_sync_kloop_appl_write(struct nm_csb_atok *atok, uint32_t cur,
+			 uint32_t head)
+{
+	/*
+	 * We need to write cur and head to the CSB but we cannot do it atomically.
+	 * There is no way we can prevent the host from reading the updated value
+	 * of one of the two and the old value of the other. However, if we make
+	 * sure that the host never reads a value of head more recent than the
+	 * value of cur we are safe. We can allow the host to read a value of cur
+	 * more recent than the value of head, since in the netmap ring cur can be
+	 * ahead of head and cur cannot wrap around head because it must be behind
+	 * tail. Inverting the order of writes below could instead result into the
+	 * host to think head went ahead of cur, which would cause the sync
+	 * prologue to fail.
+	 *
+	 * The following memory barrier scheme is used to make this happen:
+	 *
+	 *          Guest              Host
+	 *
+	 *          STORE(cur)         LOAD(head)
+	 *          mb() <-----------> mb()
+	 *          STORE(head)        LOAD(cur)
+	 *
+	 * TODO: This implementation work for x86 because of total store
+	 * ordering. Only a compiler barrier is needed. What we really
+	 * need here in the general case is a portable store-store barrier,
+	 * to prevent the two stores from being reordered (e.g. a "release"
+	 * barrier would be ok).
+	 */
+	atok->cur = cur;
+	asm volatile("" ::: "memory");
+	atok->head = head;
+}
+
+/* Application side of sync-kloop: Read kring pointers (hwcur, hwtail) from
+ * the CSB. This routine is coupled with sync_kloop_kernel_write(). */
+static inline void
+nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
+			uint32_t *hwcur)
+{
+	/*
+	 * We place a memory barrier to make sure that the update of hwtail never
+	 * overtakes the update of hwcur.
+	 * (see explanation in sync_kloop_kernel_write).
+	 *
+	 * TODO: This implementation works for x86 because loads are not reordered
+	 * after loads. What we need here is a portable load-load barrier, e.g.
+	 * an "acquire" barrier would be ok.
+	 */
+	*hwtail = ktoa->hwtail;
+	asm volatile("" ::: "memory");
+	*hwcur = ktoa->hwcur;
+}
+
 /*
  * data for NETMAP_REQ_OPT_* options
  */

From 31ca2703d43f77f4440df2d80a807249c59eeb08 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 18:06:17 +0200
Subject: [PATCH 1269/2207] utils: sync_kloop_test: move application processing
 to the main thread

---
 sys/dev/netmap/netmap.c |   8 +-
 utils/sync_kloop_test.c | 169 ++++++++++++++++++++++------------------
 2 files changed, 96 insertions(+), 81 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 05c7de38c..4b9c5fab2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3978,11 +3978,9 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 {
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
-		" rtail: %d head: %d cur: %d tail: %d",
-		title, kring->name, kring->nr_hwcur,
-		kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
-		kring->ring->head, kring->ring->cur, kring->ring->tail);
+	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
+		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
+		kring->rhead, kring->rcur, kring->rtail);
 }
 
 static void
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index d944ca3aa..7333a8b9b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -24,6 +24,9 @@ sigint_handler(int signum)
 struct context {
 	struct nm_desc *nmd;
 	const char *func;
+	struct nm_csb_atok *atok_base;
+	struct nm_csb_ktoa *ktoa_base;
+	size_t num_entries;
 };
 
 static void *
@@ -32,89 +35,25 @@ kloop_worker(void *opaque)
 	struct context *ctx = opaque;
 	struct nm_desc *nmd = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
-	struct nm_csb_atok *atok_base;
-	struct nm_csb_ktoa *ktoa_base;
 	struct nmreq_header hdr;
-	size_t num_entries;
-	size_t csb_size;
-	void *csb;
 	int ret;
 
-	num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
-	              nmd->last_rx_ring - nmd->first_rx_ring + 1;
-	printf("Number of CSB entries = %d\n", (int)num_entries);
-	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	           num_entries;
-	assert(csb_size > 0);
-	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
-	if (ret) {
-		printf("Failed to allocate CSB memory\n");
-		return NULL;
-	}
-	memset(csb, 0, csb_size);
-
+	/* The ioctl() returns on failure or when some other thread
+	 * stops the kernel loop. */
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.nr_version = NETMAP_API;
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
 	hdr.nr_body    = (uintptr_t)&req;
 	hdr.nr_options = (uintptr_t)NULL;
 	memset(&req, 0, sizeof(req));
-	req.csb_atok = (uintptr_t)csb;
-	req.csb_ktoa =
-	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
-	ret = ioctl(nmd->fd, NIOCCTRL, &hdr);
+	req.csb_atok = (uintptr_t)ctx->atok_base;
+	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
+	ret          = ioctl(nmd->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
+		exit(EXIT_FAILURE);
 	}
 
-	atok_base = (struct nm_csb_atok *)csb;
-	ktoa_base = (struct nm_csb_ktoa *)(atok_base + num_entries);
-
-	if (!strcmp(ctx->func, "tx")) {
-		while (!ACCESS_ONCE(stop)) {
-			uint16_t r;
-
-			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
-			     r++) {
-				struct netmap_ring *ring =
-				        NETMAP_TXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok = atok_base + r;
-				struct nm_csb_ktoa *ktoa = ktoa_base + r;
-				struct netmap_slot *slot;
-				uint32_t hwtail, head;
-
-				head   = atok->head;
-				hwtail = ACCESS_ONCE(ktoa->hwtail);
-
-				if (head == hwtail) {
-					continue;
-				}
-
-				slot        = ring->slot + head;
-				slot->len   = 60;
-				slot->flags = 0;
-				{
-					char *buf =
-					        NETMAP_BUF(ring, slot->buf_idx);
-					memset(buf, 0xFF, 6);
-					memset(buf + 6, 0, 6);
-					buf[12] = 0x08;
-					buf[13] = 0x00;
-					memset(buf + 14, 'x', slot->len - 14);
-				}
-				ACCESS_ONCE(atok->head) =
-				        ACCESS_ONCE(atok->cur) =
-				                nm_ring_next(ring, head);
-				printf("ring #%u, head %u, hwtail %u\n",
-				       (unsigned int)r, (unsigned int)head,
-				       (unsigned int)hwtail);
-			}
-			usleep(1000000);
-		}
-	}
-
-	free(csb);
-
 	return NULL;
 }
 
@@ -132,7 +71,9 @@ int
 main(int argc, char **argv)
 {
 	const char *ifname = NULL;
+	void *csb          = NULL;
 	struct context ctx;
+	struct nm_desc *nmd;
 	pthread_t th;
 	int opt;
 	int ret;
@@ -183,20 +124,93 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	printf("ifname %s\n", ifname);
-	ctx.nmd = nm_open(ifname, NULL, 0, NULL);
-	if (!ctx.nmd) {
+	/* Open the netmap port. */
+	ctx.nmd = nmd = nm_open(ifname, NULL, 0, NULL);
+	if (!nmd) {
 		printf("nm_open(%s) failed\n", ifname);
 		return -1;
 	}
 
+	/* Allocate CSB entries. */
+	{
+		size_t csb_size;
+
+		ctx.num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
+		                  nmd->last_rx_ring - nmd->first_rx_ring + 1;
+		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
+		csb_size = (sizeof(struct nm_csb_atok) +
+		            sizeof(struct nm_csb_ktoa)) *
+		           ctx.num_entries;
+		assert(csb_size > 0);
+		ret = posix_memalign(&csb, sizeof(struct nm_csb_atok),
+		                     csb_size);
+		if (ret) {
+			printf("Failed to allocate CSB memory\n");
+			return -1;
+		}
+		memset(csb, 0, csb_size);
+
+		ctx.atok_base = (struct nm_csb_atok *)csb;
+		ctx.ktoa_base =
+		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
+	}
+
+	/* Start the kernel worker thread. */
 	ret = pthread_create(&th, NULL, kloop_worker, &ctx);
 	if (ret) {
 		printf("pthread_create() failed: %s\n", strerror(ret));
-		nm_close(ctx.nmd);
+		nm_close(nmd);
 		return -1;
 	}
 
+	/* Run the application loop. */
+	if (!strcmp(ctx.func, "tx")) {
+		while (!ACCESS_ONCE(stop)) {
+			uint16_t r;
+
+			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
+			     r++) {
+				struct netmap_ring *ring =
+				        NETMAP_TXRING(nmd->nifp, r);
+				struct nm_csb_atok *atok = ctx.atok_base + r;
+				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + r;
+				struct netmap_slot *slot;
+				uint32_t head;
+
+				head = atok->head;
+				/* For convenience we reuse the netmap_ring
+				 * header to store hwtail and hwcur, since the
+				 * cur, head and tail fields are not used. */
+				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
+							/*hwcur=*/&ring->cur);
+
+				if (head == ring->tail) {
+					continue;
+				}
+
+				slot        = ring->slot + head;
+				slot->len   = 60;
+				slot->flags = 0;
+				{
+					char *buf =
+					        NETMAP_BUF(ring, slot->buf_idx);
+					memset(buf, 0xFF, 6);
+					memset(buf + 6, 0, 6);
+					buf[12] = 0x08;
+					buf[13] = 0x00;
+					memset(buf + 14, 'x', slot->len - 14);
+				}
+				head = nm_ring_next(ring, head);
+				nm_sync_kloop_appl_write(atok, head, head);
+				printf("ring #%u, hwcur %u, head %u, hwtail "
+				       "%u\n",
+				       (unsigned int)r, ring->cur, head, ring->tail);
+			}
+			usleep(1000000);
+		}
+	}
+
+	/* Stop the kernel worker thread. */
 	{
 		struct nmreq_header hdr;
 		int ret;
@@ -204,18 +218,21 @@ main(int argc, char **argv)
 		memset(&hdr, 0, sizeof(hdr));
 		hdr.nr_version = NETMAP_API;
 		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(ctx.nmd->fd, NIOCCTRL, &hdr);
+		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
 		if (ret) {
 			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
 		}
 	}
 
+	/* Release the allocated resources. */
 	ret = pthread_join(th, NULL);
 	if (ret) {
 		printf("pthread_join() failed: %s\n", strerror(ret));
 	}
 
-	nm_close(ctx.nmd);
+	free(csb);
+
+	nm_close(nmd);
 
 	return 0;
 }

From e32e3c92e560831ea0721b054be9317326e19bae Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 18:49:39 +0200
Subject: [PATCH 1270/2207] utils: sync_kloop_test: implement RX support

---
 utils/sync_kloop_test.c | 72 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 65 insertions(+), 7 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 7333a8b9b..e18459f3c 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -26,7 +26,7 @@ struct context {
 	const char *func;
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
-	size_t num_entries;
+	int verbose;
 };
 
 static void *
@@ -63,6 +63,7 @@ usage(const char *progname)
 	printf("%s\n"
 	       "[-h (show this help and exit)]\n"
 	       "[-f FUNCTION (rx,tx)]\n"
+	       "[-v (be more verbose)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -70,6 +71,9 @@ usage(const char *progname)
 int
 main(int argc, char **argv)
 {
+	int num_entries, num_tx_entries;
+	unsigned long long bytes = 0;
+	unsigned long long pkts = 0;
 	const char *ifname = NULL;
 	void *csb          = NULL;
 	struct context ctx;
@@ -92,8 +96,9 @@ main(int argc, char **argv)
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.func = "rx";
+	ctx.verbose = 0;
 
-	while ((opt = getopt(argc, argv, "hi:f:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:v")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -111,6 +116,10 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case 'v':
+			ctx.verbose ++;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -135,12 +144,13 @@ main(int argc, char **argv)
 	{
 		size_t csb_size;
 
-		ctx.num_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1 +
-		                  nmd->last_rx_ring - nmd->first_rx_ring + 1;
-		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
+		num_tx_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1;
+		num_entries = num_tx_entries +
+				nmd->last_rx_ring - nmd->first_rx_ring + 1;
+		printf("Number of CSB entries = %d\n", (int)num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
-		           ctx.num_entries;
+		           num_entries;
 		assert(csb_size > 0);
 		ret = posix_memalign(&csb, sizeof(struct nm_csb_atok),
 		                     csb_size);
@@ -152,7 +162,7 @@ main(int argc, char **argv)
 
 		ctx.atok_base = (struct nm_csb_atok *)csb;
 		ctx.ktoa_base =
-		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
+		        (struct nm_csb_ktoa *)(ctx.atok_base + num_entries);
 	}
 
 	/* Start the kernel worker thread. */
@@ -191,6 +201,8 @@ main(int argc, char **argv)
 				slot        = ring->slot + head;
 				slot->len   = 60;
 				slot->flags = 0;
+				bytes += slot->len;
+				pkts++;
 				{
 					char *buf =
 					        NETMAP_BUF(ring, slot->buf_idx);
@@ -208,6 +220,52 @@ main(int argc, char **argv)
 			}
 			usleep(1000000);
 		}
+
+	} else if (!strcmp(ctx.func, "rx")) {
+
+		while (!ACCESS_ONCE(stop)) {
+			uint16_t r;
+
+			for (r = nmd->first_rx_ring; r <= nmd->last_rx_ring;
+			     r++) {
+				struct netmap_ring *ring =
+				        NETMAP_RXRING(nmd->nifp, r);
+				struct nm_csb_atok *atok = ctx.atok_base + num_tx_entries + r;
+				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + num_tx_entries + r;
+				struct netmap_slot *slot;
+				uint32_t head;
+
+				head = atok->head;
+				/* For convenience we reuse the netmap_ring
+				 * header to store hwtail and hwcur, since the
+				 * cur, head and tail fields are not used. */
+				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
+							/*hwcur=*/&ring->cur);
+
+				if (head == ring->tail) {
+					continue;
+				}
+
+				slot        = ring->slot + head;
+				bytes += slot->len;
+				pkts++;
+				if (ctx.verbose) {
+					char *buf =
+					        NETMAP_BUF(ring, slot->buf_idx);
+					int i;
+					for (i = 0; i < slot->len; i++) {
+						printf(" %02x", (unsigned char)buf[i]);
+					}
+					printf("\n");
+				}
+				head = nm_ring_next(ring, head);
+				nm_sync_kloop_appl_write(atok, head, head);
+				printf("ring #%u, hwcur %u, head %u, hwtail "
+				       "%u\n",
+				       (unsigned int)r, ring->cur, head, ring->tail);
+			}
+			usleep(1000000);
+		}
 	}
 
 	/* Stop the kernel worker thread. */

From 05f509b814bf0418453f78d1a811b956c4dd741c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:06:42 +0200
Subject: [PATCH 1271/2207] utils: sync_kloop_test: add support for -b and -R
 parameters

---
 utils/sync_kloop_test.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index e18459f3c..a511b2bdd 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -27,6 +27,7 @@ struct context {
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int verbose;
+	unsigned batch;
 };
 
 static void *
@@ -64,6 +65,8 @@ usage(const char *progname)
 	       "[-h (show this help and exit)]\n"
 	       "[-f FUNCTION (rx,tx)]\n"
 	       "[-v (be more verbose)]\n"
+	       "[-R RATE_PPS (0 = infinite)]\n"
+	       "[-b BATCH_SIZE (in packets)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -78,6 +81,7 @@ main(int argc, char **argv)
 	void *csb          = NULL;
 	struct context ctx;
 	struct nm_desc *nmd;
+	double rate = 1.0 /* pps */;
 	pthread_t th;
 	int opt;
 	int ret;
@@ -97,8 +101,9 @@ main(int argc, char **argv)
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.func = "rx";
 	ctx.verbose = 0;
+	ctx.batch = 1;
 
-	while ((opt = getopt(argc, argv, "hi:f:v")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:vR:b:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -120,6 +125,22 @@ main(int argc, char **argv)
 			ctx.verbose ++;
 			break;
 
+		case 'R':
+			rate = atof(optarg);
+			if (rate < 0.0) {
+				printf("    Invalid rate %s\n", optarg);
+				return -1;
+			}
+			break;
+
+		case 'b':
+			ctx.batch = atoi(optarg);
+			if (ctx.batch <= 0) {
+				printf("    Invalid batch %s\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);

From dbbac2b9a27a816c16ef061c7739af88824317ce Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:24:35 +0200
Subject: [PATCH 1272/2207] utils: sync_kloop_test: add support for batching

---
 utils/sync_kloop_test.c | 84 ++++++++++++++++++++++++++---------------
 1 file changed, 54 insertions(+), 30 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a511b2bdd..a8486a982 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -27,7 +27,7 @@ struct context {
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int verbose;
-	unsigned batch;
+	int batch;
 };
 
 static void *
@@ -58,6 +58,18 @@ kloop_worker(void *opaque)
 	return NULL;
 }
 
+inline int
+ringspace(struct netmap_ring *ring, uint32_t head)
+{
+	int space = ring->tail - head;
+
+	if (space < 0) {
+		space += ring->num_slots;
+	}
+
+	return space;
+}
+
 static void
 usage(const char *progname)
 {
@@ -207,6 +219,7 @@ main(int argc, char **argv)
 				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + r;
 				struct netmap_slot *slot;
 				uint32_t head;
+				int batch;
 
 				head = atok->head;
 				/* For convenience we reuse the netmap_ring
@@ -214,26 +227,31 @@ main(int argc, char **argv)
 				 * cur, head and tail fields are not used. */
 				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
 							/*hwcur=*/&ring->cur);
-
-				if (head == ring->tail) {
+				batch = ringspace(ring, head);
+				if (batch == 0) {
 					continue;
 				}
+				if (batch > ctx.batch) {
+					batch = ctx.batch;
+				}
 
-				slot        = ring->slot + head;
-				slot->len   = 60;
-				slot->flags = 0;
-				bytes += slot->len;
-				pkts++;
-				{
-					char *buf =
-					        NETMAP_BUF(ring, slot->buf_idx);
-					memset(buf, 0xFF, 6);
-					memset(buf + 6, 0, 6);
-					buf[12] = 0x08;
-					buf[13] = 0x00;
-					memset(buf + 14, 'x', slot->len - 14);
+				pkts += batch;
+				while (--batch >= 0) {
+					slot        = ring->slot + head;
+					slot->len   = 60;
+					slot->flags = 0;
+					bytes += slot->len;
+					{
+						char *buf =
+							NETMAP_BUF(ring, slot->buf_idx);
+						memset(buf, 0xFF, 6);
+						memset(buf + 6, 0, 6);
+						buf[12] = 0x08;
+						buf[13] = 0x00;
+						memset(buf + 14, 'x', slot->len - 14);
+					}
+					head = nm_ring_next(ring, head);
 				}
-				head = nm_ring_next(ring, head);
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",
@@ -255,6 +273,7 @@ main(int argc, char **argv)
 				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + num_tx_entries + r;
 				struct netmap_slot *slot;
 				uint32_t head;
+				int batch;
 
 				head = atok->head;
 				/* For convenience we reuse the netmap_ring
@@ -262,24 +281,29 @@ main(int argc, char **argv)
 				 * cur, head and tail fields are not used. */
 				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
 							/*hwcur=*/&ring->cur);
-
-				if (head == ring->tail) {
+				batch = ringspace(ring, head);
+				if (batch == 0) {
 					continue;
 				}
+				if (batch > ctx.batch) {
+					batch = ctx.batch;
+				}
 
-				slot        = ring->slot + head;
-				bytes += slot->len;
-				pkts++;
-				if (ctx.verbose) {
-					char *buf =
-					        NETMAP_BUF(ring, slot->buf_idx);
-					int i;
-					for (i = 0; i < slot->len; i++) {
-						printf(" %02x", (unsigned char)buf[i]);
+				pkts += batch;
+				while (--batch >= 0) {
+					slot        = ring->slot + head;
+					bytes += slot->len;
+					if (ctx.verbose) {
+						char *buf =
+							NETMAP_BUF(ring, slot->buf_idx);
+						int i;
+						for (i = 0; i < slot->len; i++) {
+							printf(" %02x", (unsigned char)buf[i]);
+						}
+						printf("\n");
 					}
-					printf("\n");
+					head = nm_ring_next(ring, head);
 				}
-				head = nm_ring_next(ring, head);
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",

From fb88a558eeb513370c7f4a0dbb2c6d1866ad8ce3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:25:32 +0200
Subject: [PATCH 1273/2207] reformat

---
 utils/sync_kloop_test.c | 58 ++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a8486a982..a9c17f3b6 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -88,9 +88,9 @@ main(int argc, char **argv)
 {
 	int num_entries, num_tx_entries;
 	unsigned long long bytes = 0;
-	unsigned long long pkts = 0;
-	const char *ifname = NULL;
-	void *csb          = NULL;
+	unsigned long long pkts  = 0;
+	const char *ifname       = NULL;
+	void *csb                = NULL;
 	struct context ctx;
 	struct nm_desc *nmd;
 	double rate = 1.0 /* pps */;
@@ -111,9 +111,9 @@ main(int argc, char **argv)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.func = "rx";
+	ctx.func    = "rx";
 	ctx.verbose = 0;
-	ctx.batch = 1;
+	ctx.batch   = 1;
 
 	while ((opt = getopt(argc, argv, "hi:f:vR:b:")) != -1) {
 		switch (opt) {
@@ -134,7 +134,7 @@ main(int argc, char **argv)
 			break;
 
 		case 'v':
-			ctx.verbose ++;
+			ctx.verbose++;
 			break;
 
 		case 'R':
@@ -178,8 +178,8 @@ main(int argc, char **argv)
 		size_t csb_size;
 
 		num_tx_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1;
-		num_entries = num_tx_entries +
-				nmd->last_rx_ring - nmd->first_rx_ring + 1;
+		num_entries    = num_tx_entries + nmd->last_rx_ring -
+		              nmd->first_rx_ring + 1;
 		printf("Number of CSB entries = %d\n", (int)num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
@@ -225,8 +225,9 @@ main(int argc, char **argv)
 				/* For convenience we reuse the netmap_ring
 				 * header to store hwtail and hwcur, since the
 				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
-							/*hwcur=*/&ring->cur);
+				nm_sync_kloop_appl_read(ktoa,
+				                        /*hwtail=*/&ring->tail,
+				                        /*hwcur=*/&ring->cur);
 				batch = ringspace(ring, head);
 				if (batch == 0) {
 					continue;
@@ -242,20 +243,22 @@ main(int argc, char **argv)
 					slot->flags = 0;
 					bytes += slot->len;
 					{
-						char *buf =
-							NETMAP_BUF(ring, slot->buf_idx);
+						char *buf = NETMAP_BUF(
+						        ring, slot->buf_idx);
 						memset(buf, 0xFF, 6);
 						memset(buf + 6, 0, 6);
 						buf[12] = 0x08;
 						buf[13] = 0x00;
-						memset(buf + 14, 'x', slot->len - 14);
+						memset(buf + 14, 'x',
+						       slot->len - 14);
 					}
 					head = nm_ring_next(ring, head);
 				}
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",
-				       (unsigned int)r, ring->cur, head, ring->tail);
+				       (unsigned int)r, ring->cur, head,
+				       ring->tail);
 			}
 			usleep(1000000);
 		}
@@ -269,8 +272,10 @@ main(int argc, char **argv)
 			     r++) {
 				struct netmap_ring *ring =
 				        NETMAP_RXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok = ctx.atok_base + num_tx_entries + r;
-				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + num_tx_entries + r;
+				struct nm_csb_atok *atok =
+				        ctx.atok_base + num_tx_entries + r;
+				struct nm_csb_ktoa *ktoa =
+				        ctx.ktoa_base + num_tx_entries + r;
 				struct netmap_slot *slot;
 				uint32_t head;
 				int batch;
@@ -279,8 +284,9 @@ main(int argc, char **argv)
 				/* For convenience we reuse the netmap_ring
 				 * header to store hwtail and hwcur, since the
 				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa, /*hwtail=*/&ring->tail,
-							/*hwcur=*/&ring->cur);
+				nm_sync_kloop_appl_read(ktoa,
+				                        /*hwtail=*/&ring->tail,
+				                        /*hwcur=*/&ring->cur);
 				batch = ringspace(ring, head);
 				if (batch == 0) {
 					continue;
@@ -291,14 +297,17 @@ main(int argc, char **argv)
 
 				pkts += batch;
 				while (--batch >= 0) {
-					slot        = ring->slot + head;
+					slot = ring->slot + head;
 					bytes += slot->len;
 					if (ctx.verbose) {
-						char *buf =
-							NETMAP_BUF(ring, slot->buf_idx);
+						char *buf = NETMAP_BUF(
+						        ring, slot->buf_idx);
 						int i;
-						for (i = 0; i < slot->len; i++) {
-							printf(" %02x", (unsigned char)buf[i]);
+						for (i = 0; i < slot->len;
+						     i++) {
+							printf(" %02x",
+							       (unsigned char)
+							               buf[i]);
 						}
 						printf("\n");
 					}
@@ -307,7 +316,8 @@ main(int argc, char **argv)
 				nm_sync_kloop_appl_write(atok, head, head);
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",
-				       (unsigned int)r, ring->cur, head, ring->tail);
+				       (unsigned int)r, ring->cur, head,
+				       ring->tail);
 			}
 			usleep(1000000);
 		}

From 37805d5da454b49cb4fdedede52be7fa410be8fb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 19:56:42 +0200
Subject: [PATCH 1274/2207] utils: sync_kloop_test: merge TX and RX loops

---
 utils/sync_kloop_test.c | 164 +++++++++++++++++-----------------------
 1 file changed, 71 insertions(+), 93 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a9c17f3b6..1be1d461b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -23,7 +23,6 @@ sigint_handler(int signum)
 
 struct context {
 	struct nm_desc *nmd;
-	const char *func;
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int verbose;
@@ -83,21 +82,31 @@ usage(const char *progname)
 	       progname);
 }
 
+typedef enum {
+	F_TX = 0,
+	F_RX,
+} function_t;
+
 int
 main(int argc, char **argv)
 {
+	struct nm_csb_atok *atok_base = NULL;
+	struct nm_csb_ktoa *ktoa_base = NULL;
 	int num_entries, num_tx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
 	const char *ifname       = NULL;
 	void *csb                = NULL;
+	uint16_t first_ring, last_ring;
 	struct context ctx;
 	struct nm_desc *nmd;
 	double rate = 1.0 /* pps */;
+	function_t func;
 	pthread_t th;
 	int opt;
 	int ret;
 
+	/* Register a signal handler to stop the program on SIGINT. */
 	{
 		struct sigaction sa;
 
@@ -111,7 +120,7 @@ main(int argc, char **argv)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.func    = "rx";
+	func        = F_RX;
 	ctx.verbose = 0;
 	ctx.batch   = 1;
 
@@ -126,10 +135,12 @@ main(int argc, char **argv)
 			break;
 
 		case 'f':
-			ctx.func = optarg;
-			if (strcmp(optarg, "tx") && strcmp(optarg, "rx")) {
+			if (!strcmp(optarg, "tx")) {
+				func = F_TX;
+			} else if (!strcmp(optarg, "rx")) {
+				func = F_RX;
+			} else {
 				printf("    Unknown function %s\n", optarg);
-				return -1;
 			}
 			break;
 
@@ -193,8 +204,8 @@ main(int argc, char **argv)
 		}
 		memset(csb, 0, csb_size);
 
-		ctx.atok_base = (struct nm_csb_atok *)csb;
-		ctx.ktoa_base =
+		atok_base = ctx.atok_base = (struct nm_csb_atok *)csb;
+		ktoa_base                 = ctx.ktoa_base =
 		        (struct nm_csb_ktoa *)(ctx.atok_base + num_entries);
 	}
 
@@ -206,42 +217,55 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	if (func == F_RX) {
+		atok_base += num_tx_entries;
+		ktoa_base += num_tx_entries;
+		first_ring = nmd->first_rx_ring;
+		last_ring  = nmd->last_rx_ring;
+	} else {
+		first_ring = nmd->first_tx_ring;
+		last_ring  = nmd->last_tx_ring;
+	}
+
 	/* Run the application loop. */
-	if (!strcmp(ctx.func, "tx")) {
-		while (!ACCESS_ONCE(stop)) {
-			uint16_t r;
-
-			for (r = nmd->first_tx_ring; r <= nmd->last_tx_ring;
-			     r++) {
-				struct netmap_ring *ring =
-				        NETMAP_TXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok = ctx.atok_base + r;
-				struct nm_csb_ktoa *ktoa = ctx.ktoa_base + r;
-				struct netmap_slot *slot;
-				uint32_t head;
-				int batch;
-
-				head = atok->head;
-				/* For convenience we reuse the netmap_ring
-				 * header to store hwtail and hwcur, since the
-				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa,
-				                        /*hwtail=*/&ring->tail,
-				                        /*hwcur=*/&ring->cur);
-				batch = ringspace(ring, head);
-				if (batch == 0) {
-					continue;
-				}
-				if (batch > ctx.batch) {
-					batch = ctx.batch;
-				}
+	while (!ACCESS_ONCE(stop)) {
+		uint16_t r;
+
+		for (r = first_ring; r <= last_ring; r++) {
+			struct nm_csb_atok *atok = atok_base + r;
+			struct nm_csb_ktoa *ktoa = ktoa_base + r;
+			struct netmap_ring *ring;
+			struct netmap_slot *slot;
+			uint32_t head;
+			int batch;
+
+			if (func == F_TX) {
+				ring = NETMAP_TXRING(nmd->nifp, r);
+			} else {
+				ring = NETMAP_RXRING(nmd->nifp, r);
+			}
 
-				pkts += batch;
-				while (--batch >= 0) {
-					slot        = ring->slot + head;
+			head = atok->head;
+			/* For convenience we reuse the netmap_ring
+			 * header to store hwtail and hwcur, since the
+			 * cur, head and tail fields are not used. */
+			nm_sync_kloop_appl_read(ktoa,
+			                        /*hwtail=*/&ring->tail,
+			                        /*hwcur=*/&ring->cur);
+			batch = ringspace(ring, head);
+			if (batch == 0) {
+				continue;
+			}
+			if (batch > ctx.batch) {
+				batch = ctx.batch;
+			}
+
+			pkts += batch;
+			while (--batch >= 0) {
+				slot = ring->slot + head;
+				if (func == F_TX) {
 					slot->len   = 60;
 					slot->flags = 0;
-					bytes += slot->len;
 					{
 						char *buf = NETMAP_BUF(
 						        ring, slot->buf_idx);
@@ -252,53 +276,7 @@ main(int argc, char **argv)
 						memset(buf + 14, 'x',
 						       slot->len - 14);
 					}
-					head = nm_ring_next(ring, head);
-				}
-				nm_sync_kloop_appl_write(atok, head, head);
-				printf("ring #%u, hwcur %u, head %u, hwtail "
-				       "%u\n",
-				       (unsigned int)r, ring->cur, head,
-				       ring->tail);
-			}
-			usleep(1000000);
-		}
-
-	} else if (!strcmp(ctx.func, "rx")) {
-
-		while (!ACCESS_ONCE(stop)) {
-			uint16_t r;
-
-			for (r = nmd->first_rx_ring; r <= nmd->last_rx_ring;
-			     r++) {
-				struct netmap_ring *ring =
-				        NETMAP_RXRING(nmd->nifp, r);
-				struct nm_csb_atok *atok =
-				        ctx.atok_base + num_tx_entries + r;
-				struct nm_csb_ktoa *ktoa =
-				        ctx.ktoa_base + num_tx_entries + r;
-				struct netmap_slot *slot;
-				uint32_t head;
-				int batch;
-
-				head = atok->head;
-				/* For convenience we reuse the netmap_ring
-				 * header to store hwtail and hwcur, since the
-				 * cur, head and tail fields are not used. */
-				nm_sync_kloop_appl_read(ktoa,
-				                        /*hwtail=*/&ring->tail,
-				                        /*hwcur=*/&ring->cur);
-				batch = ringspace(ring, head);
-				if (batch == 0) {
-					continue;
-				}
-				if (batch > ctx.batch) {
-					batch = ctx.batch;
-				}
-
-				pkts += batch;
-				while (--batch >= 0) {
-					slot = ring->slot + head;
-					bytes += slot->len;
+				} else {
 					if (ctx.verbose) {
 						char *buf = NETMAP_BUF(
 						        ring, slot->buf_idx);
@@ -311,16 +289,16 @@ main(int argc, char **argv)
 						}
 						printf("\n");
 					}
-					head = nm_ring_next(ring, head);
 				}
-				nm_sync_kloop_appl_write(atok, head, head);
-				printf("ring #%u, hwcur %u, head %u, hwtail "
-				       "%u\n",
-				       (unsigned int)r, ring->cur, head,
-				       ring->tail);
+				bytes += slot->len;
+				head = nm_ring_next(ring, head);
 			}
-			usleep(1000000);
+			nm_sync_kloop_appl_write(atok, head, head);
+			printf("ring #%u, hwcur %u, head %u, hwtail "
+			       "%u\n",
+			       (unsigned int)r, ring->cur, head, ring->tail);
 		}
+		usleep(1000000);
 	}
 
 	/* Stop the kernel worker thread. */

From 37af80dd7e5cdb15a6cb96e104fdc8af9802a047 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 29 Sep 2018 23:00:16 +0200
Subject: [PATCH 1275/2207] utils: sync_kloop_test: add support for rate
 limiting

---
 utils/sync_kloop_test.c | 48 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 1be1d461b..f6d71c7ef 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -9,6 +9,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
 
@@ -100,7 +102,13 @@ main(int argc, char **argv)
 	uint16_t first_ring, last_ring;
 	struct context ctx;
 	struct nm_desc *nmd;
-	double rate = 1.0 /* pps */;
+
+	double rate                = 1.0 /* pps */;
+	unsigned int period_us     = 0;
+	unsigned int period_budget = 0;
+	struct timeval next_time;
+	int packet_budget;
+
 	function_t func;
 	pthread_t th;
 	int opt;
@@ -217,6 +225,20 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	/* Compute variables for rate limiting. */
+	if (rate != 0.0) {
+		double us = 1000000.0 / rate;
+		double b  = 1.0;
+		if (us < 50.0) {
+			b = ceil(50.0 / us);
+			us *= b;
+		}
+		period_us     = (unsigned int)us;
+		period_budget = (unsigned int)b;
+	}
+#if 0
+	printf("period us %u batch %u\n", period_us, period_budget);
+#endif
 	if (func == F_RX) {
 		atok_base += num_tx_entries;
 		ktoa_base += num_tx_entries;
@@ -227,10 +249,29 @@ main(int argc, char **argv)
 		last_ring  = nmd->last_tx_ring;
 	}
 
+	gettimeofday(&next_time, NULL);
+	packet_budget = 0;
+
 	/* Run the application loop. */
 	while (!ACCESS_ONCE(stop)) {
 		uint16_t r;
 
+		if (period_us != 0) {
+			struct timeval now, diff;
+
+			next_time.tv_usec += period_us;
+			if (next_time.tv_usec > 1000000) {
+				next_time.tv_usec -= 1000000;
+				next_time.tv_sec++;
+			}
+			packet_budget = period_budget;
+			gettimeofday(&now, NULL);
+			timersub(&next_time, &now, &diff);
+			usleep(diff.tv_usec);
+		} else {
+			packet_budget = 0xfffffff; /* infinite */
+		}
+
 		for (r = first_ring; r <= last_ring; r++) {
 			struct nm_csb_atok *atok = atok_base + r;
 			struct nm_csb_ktoa *ktoa = ktoa_base + r;
@@ -253,6 +294,9 @@ main(int argc, char **argv)
 			                        /*hwtail=*/&ring->tail,
 			                        /*hwcur=*/&ring->cur);
 			batch = ringspace(ring, head);
+			if (batch > packet_budget) { /* rate limiting */
+				batch = packet_budget;
+			}
 			if (batch == 0) {
 				continue;
 			}
@@ -261,6 +305,7 @@ main(int argc, char **argv)
 			}
 
 			pkts += batch;
+			packet_budget -= batch;
 			while (--batch >= 0) {
 				slot = ring->slot + head;
 				if (func == F_TX) {
@@ -298,7 +343,6 @@ main(int argc, char **argv)
 			       "%u\n",
 			       (unsigned int)r, ring->cur, head, ring->tail);
 		}
-		usleep(1000000);
 	}
 
 	/* Stop the kernel worker thread. */

From 1adaf055bd145edac18226c660d8d4e224418c34 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 11:59:27 +0200
Subject: [PATCH 1276/2207] utils: sync_kloop_test: stop initializing packets
 after a while

---
 utils/sync_kloop_test.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index f6d71c7ef..df810e9f7 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -109,6 +109,7 @@ main(int argc, char **argv)
 	struct timeval next_time;
 	int packet_budget;
 
+	int init_tx_payload = 1;
 	function_t func;
 	pthread_t th;
 	int opt;
@@ -309,9 +310,9 @@ main(int argc, char **argv)
 			while (--batch >= 0) {
 				slot = ring->slot + head;
 				if (func == F_TX) {
-					slot->len   = 60;
-					slot->flags = 0;
-					{
+					slot->len = 60;
+					if ((slot->flags & NS_BUF_CHANGED) ||
+					    init_tx_payload) {
 						char *buf = NETMAP_BUF(
 						        ring, slot->buf_idx);
 						memset(buf, 0xFF, 6);
@@ -320,7 +321,17 @@ main(int argc, char **argv)
 						buf[13] = 0x00;
 						memset(buf + 14, 'x',
 						       slot->len - 14);
+						/* Drop the copy once we are
+						 * confident that we have filled
+						 * all the buffers in the TX
+						 * ring. */
+						if (pkts > 20000) {
+							printf("Stop to init "
+							       "packets\n");
+							init_tx_payload = 0;
+						}
 					}
+					slot->flags = 0;
 				} else {
 					if (ctx.verbose) {
 						char *buf = NETMAP_BUF(
@@ -339,9 +350,12 @@ main(int argc, char **argv)
 				head = nm_ring_next(ring, head);
 			}
 			nm_sync_kloop_appl_write(atok, head, head);
-			printf("ring #%u, hwcur %u, head %u, hwtail "
-			       "%u\n",
-			       (unsigned int)r, ring->cur, head, ring->tail);
+			if (ctx.verbose) {
+				printf("ring #%u, hwcur %u, head %u, hwtail "
+				       "%u\n",
+				       (unsigned int)r, ring->cur, head,
+				       ring->tail);
+			}
 		}
 	}
 

From d288e26964a6bc8fb8cca73be996e82787828fdc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 12:21:43 +0200
Subject: [PATCH 1277/2207] utils: sync_kloop_test: fix bug in the rate
 limiting code

---
 utils/sync_kloop_test.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index df810e9f7..a05218620 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -267,8 +267,12 @@ main(int argc, char **argv)
 			}
 			packet_budget = period_budget;
 			gettimeofday(&now, NULL);
-			timersub(&next_time, &now, &diff);
-			usleep(diff.tv_usec);
+			/* if now < next_time ... */
+			if (timercmp(&now, &next_time, <)) {
+				/* diff = next_time - now */
+				timersub(&next_time, &now, &diff);
+				usleep(diff.tv_usec);
+			}
 		} else {
 			packet_budget = 0xfffffff; /* infinite */
 		}

From 7a92c8f8a325d2277b166a833ab712605fb53148 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 12:30:55 +0200
Subject: [PATCH 1278/2207] utils: sync_kloop_test: add busy-wait mode

---
 utils/sync_kloop_test.c | 36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a05218620..025adc000 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -230,12 +230,14 @@ main(int argc, char **argv)
 	if (rate != 0.0) {
 		double us = 1000000.0 / rate;
 		double b  = 1.0;
-		if (us < 50.0) {
-			b = ceil(50.0 / us);
+#define MIN_USLEEP 50.0
+		if (us < MIN_USLEEP) {
+			b = ceil(MIN_USLEEP / us);
 			us *= b;
 		}
 		period_us     = (unsigned int)us;
 		period_budget = (unsigned int)b;
+#undef MIN_USLEEP
 	}
 #if 0
 	printf("period us %u batch %u\n", period_us, period_budget);
@@ -257,7 +259,9 @@ main(int argc, char **argv)
 	while (!ACCESS_ONCE(stop)) {
 		uint16_t r;
 
-		if (period_us != 0) {
+		if (period_us == 0) {
+			packet_budget = 0xfffffff; /* infinite */
+		} else {
 			struct timeval now, diff;
 
 			next_time.tv_usec += period_us;
@@ -266,15 +270,25 @@ main(int argc, char **argv)
 				next_time.tv_sec++;
 			}
 			packet_budget = period_budget;
-			gettimeofday(&now, NULL);
-			/* if now < next_time ... */
-			if (timercmp(&now, &next_time, <)) {
-				/* diff = next_time - now */
-				timersub(&next_time, &now, &diff);
-				usleep(diff.tv_usec);
+			if (period_budget > 1) {
+				/* Busy wait. */
+				for (;;) {
+					gettimeofday(&now, NULL);
+					/* if now >= next_time */
+					if (!timercmp(&now, &next_time, <)) {
+						break;
+					}
+				}
+			} else {
+				/* Sleep. */
+				gettimeofday(&now, NULL);
+				/* if now < next_time ... */
+				if (timercmp(&now, &next_time, <)) {
+					/* diff = next_time - now */
+					timersub(&next_time, &now, &diff);
+					usleep(diff.tv_usec);
+				}
 			}
-		} else {
-			packet_budget = 0xfffffff; /* infinite */
 		}
 
 		for (r = first_ring; r <= last_ring; r++) {

From 353a5476a9edebfd17fb85185be3e196f446598c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 12:40:11 +0200
Subject: [PATCH 1279/2207] utils: sync_kloop_test: measure average rate

---
 utils/sync_kloop_test.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 025adc000..efc78d13b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -103,11 +103,12 @@ main(int argc, char **argv)
 	struct context ctx;
 	struct nm_desc *nmd;
 
-	double rate                = 1.0 /* pps */;
+	double target_rate         = 1.0 /* pps */;
 	unsigned int period_us     = 0;
 	unsigned int period_budget = 0;
 	struct timeval next_time;
 	int packet_budget;
+	struct timeval loop_begin, loop_end;
 
 	int init_tx_payload = 1;
 	function_t func;
@@ -158,8 +159,8 @@ main(int argc, char **argv)
 			break;
 
 		case 'R':
-			rate = atof(optarg);
-			if (rate < 0.0) {
+			target_rate = atof(optarg);
+			if (target_rate < 0.0) {
 				printf("    Invalid rate %s\n", optarg);
 				return -1;
 			}
@@ -227,8 +228,8 @@ main(int argc, char **argv)
 	}
 
 	/* Compute variables for rate limiting. */
-	if (rate != 0.0) {
-		double us = 1000000.0 / rate;
+	if (target_rate != 0.0) {
+		double us = 1000000.0 / target_rate;
 		double b  = 1.0;
 #define MIN_USLEEP 50.0
 		if (us < MIN_USLEEP) {
@@ -253,6 +254,7 @@ main(int argc, char **argv)
 	}
 
 	gettimeofday(&next_time, NULL);
+	loop_begin    = next_time;
 	packet_budget = 0;
 
 	/* Run the application loop. */
@@ -377,6 +379,19 @@ main(int argc, char **argv)
 		}
 	}
 
+	/* Measure average rate. */
+	gettimeofday(&loop_end, NULL);
+	{
+		struct timeval duration;
+		unsigned long udiff;
+		double measured_rate;
+
+		timersub(&loop_end, &loop_begin, &duration);
+		udiff         = duration.tv_sec * 1000000 + duration.tv_usec;
+		measured_rate = (double)pkts / (double)udiff;
+		printf("Measured rate: %.6f Mpps\n", measured_rate);
+	}
+
 	/* Stop the kernel worker thread. */
 	{
 		struct nmreq_header hdr;

From c15a5397da968c943ab5b021779f912539e44311 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 15:40:37 +0200
Subject: [PATCH 1280/2207] sync-kloop: allow user-specified sleep interval

---
 sys/dev/netmap/netmap.c | 11 ++++++++---
 sys/net/netmap.h        |  4 ++++
 utils/ctrl-api-test.c   |  1 +
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4b9c5fab2..aa5ff2714 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4225,12 +4225,18 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
+	uint32_t sleep_us = req->sleep_us;
 	struct nm_csb_atok* csb_atok_base;
 	struct nm_csb_ktoa* csb_ktoa_base;
 	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
 	int err = 0;
 
+	if (sleep_us > 1000000) {
+		/* We do not accept sleeping for more than a second. */
+		return EINVAL;
+	}
+
 	if (priv->np_nifp == NULL) {
 		return ENXIO;
 	}
@@ -4337,9 +4343,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
-		/* TODO replace with proper notifications and/or configurable
-		 * sleep interval. */
-		usleep_range(2000, 2000);
+		/* Default synchronization method: sleep for a while. */
+		usleep_range(sleep_us, sleep_us);
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a48110728..aa31f521b 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -714,6 +714,10 @@ struct nmreq_sync_kloop_start {
 	uint64_t csb_atok;
 	/* CSB for kernel --> application communication (N entries). */
 	uint64_t csb_ktoa;
+	/* Sleeping is the default synchronization method for the kloop.
+	 * The 'sleep_us' field specifies how many microsconds to sleep
+	 * waiting for more work to come. */
+	uint32_t sleep_us;
 };
 
 struct nm_csb_atok {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5d72bbbcc..763618706 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -847,6 +847,7 @@ sync_kloop_worker(void *opaque)
 	req.csb_atok = (uintptr_t)csb;
 	req.csb_ktoa =
 	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
+	req.sleep_us = 500;
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");

From 0637ef5b3b13a7976ad7fdf55d95ae7c8f66539d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 16:09:51 +0200
Subject: [PATCH 1281/2207] utils: sync_kloop_test: add support for -u option

---
 utils/sync_kloop_test.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index efc78d13b..a26a660f8 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -27,6 +27,7 @@ struct context {
 	struct nm_desc *nmd;
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
+	int sleep_us;
 	int verbose;
 	int batch;
 };
@@ -50,6 +51,7 @@ kloop_worker(void *opaque)
 	memset(&req, 0, sizeof(req));
 	req.csb_atok = (uintptr_t)ctx->atok_base;
 	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
+	req.sleep_us = (uint32_t)ctx->sleep_us;
 	ret          = ioctl(nmd->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
@@ -80,6 +82,7 @@ usage(const char *progname)
 	       "[-v (be more verbose)]\n"
 	       "[-R RATE_PPS (0 = infinite)]\n"
 	       "[-b BATCH_SIZE (in packets)]\n"
+	       "[-u KLOOP_SLEEP_US (in microseconds)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -133,8 +136,9 @@ main(int argc, char **argv)
 	func        = F_RX;
 	ctx.verbose = 0;
 	ctx.batch   = 1;
+	ctx.sleep_us = 500;
 
-	while ((opt = getopt(argc, argv, "hi:f:vR:b:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -174,6 +178,14 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case 'u':
+			ctx.sleep_us = atoi(optarg);
+			if (ctx.sleep_us < 0) {
+				printf("    Invalid sleep_us %s\n", optarg);
+				return -1;
+			}
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);

From d9bbd768b9673b3ae0514727981e2425605310d7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 30 Sep 2018 18:04:10 +0200
Subject: [PATCH 1282/2207] sync-kloop: require NR_EXCLUSIVE to be set

---
 sys/dev/netmap/netmap.c |  5 +++++
 utils/ctrl-api-test.c   | 32 ++++++++++++++++++++------------
 utils/sync_kloop_test.c | 22 ++++++++++++++--------
 3 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index aa5ff2714..c369077c0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4247,6 +4247,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		return ENXIO;
 	}
 
+	if (!(priv->np_flags & NR_EXCLUSIVE)) {
+		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
+		return EINVAL;
+	}
+
 	/* Make sure that no kloop is currently running. */
 	NMG_LOCK();
 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 763618706..50ddfcfda 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -828,7 +828,7 @@ sync_kloop_worker(void *opaque)
 	int ret;
 
 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	             num_entries;
+	           num_entries;
 	assert(csb_size > 0);
 	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
 	if (ret) {
@@ -837,7 +837,7 @@ sync_kloop_worker(void *opaque)
 	}
 
 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
-		(unsigned)csb_size, ctx->ifname);
+	       (unsigned)csb_size, ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
@@ -848,7 +848,7 @@ sync_kloop_worker(void *opaque)
 	req.csb_ktoa =
 	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
 	req.sleep_us = 500;
-	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
@@ -860,10 +860,12 @@ sync_kloop_worker(void *opaque)
 static int
 sync_kloop(struct TestContext *ctx)
 {
-	int ret = port_register_hwall(ctx);
+	int ret;
 	pthread_t th;
 	int thret;
 
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -890,10 +892,12 @@ sync_kloop(struct TestContext *ctx)
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
-	int ret = port_register_hwall(ctx);
+	int ret;
 	pthread_t th1, th2;
 	int thret1, thret2;
 
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -910,8 +914,8 @@ sync_kloop_conflict(struct TestContext *ctx)
 		return -1;
 	}
 
-	/* Try to avoid a race condition where th1 starts the loop and stops, and
-	 * after that th2 starts the loop successfully. */
+	/* Try to avoid a race condition where th1 starts the loop and stops,
+	 * and after that th2 starts the loop successfully. */
 	usleep(500000);
 
 	ret = sync_kloop_stop(ctx);
@@ -930,17 +934,21 @@ sync_kloop_conflict(struct TestContext *ctx)
 	}
 
 	/* Check that one of the two failed, while the other one succeeded. */
-	return ((thret1 == 0 && thret2 != 0) ||
-		(thret1 != 0 && thret2 == 0)) ? 0 : -1;
+	return ((thret1 == 0 && thret2 != 0) || (thret1 != 0 && thret2 == 0))
+	               ? 0
+	               : -1;
 }
 
 static int
 sync_kloop_invalid_csb(struct TestContext *ctx)
 {
-	int ret = port_register_hwall(ctx);
+	int ret;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+
 	/* Post a stop request first. */
 	ret = sync_kloop_stop(ctx);
 	if (ret) {
@@ -953,7 +961,7 @@ sync_kloop_invalid_csb(struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.csb_atok = (uintptr_t)0x10;
 	req.csb_ktoa = (uintptr_t)0x800;
-	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
@@ -1076,7 +1084,7 @@ main(int argc, char **argv)
 		}
 		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
 		ctxcopy.fd = fd;
-		ret = tests[i].test(&ctxcopy);
+		ret        = tests[i].test(&ctxcopy);
 		if (ret) {
 			printf("Test #%d failed\n", i + 1);
 			goto out;
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a26a660f8..98a6b86b0 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -133,9 +133,9 @@ main(int argc, char **argv)
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	func        = F_RX;
-	ctx.verbose = 0;
-	ctx.batch   = 1;
+	func         = F_RX;
+	ctx.verbose  = 0;
+	ctx.batch    = 1;
 	ctx.sleep_us = 500;
 
 	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:")) != -1) {
@@ -199,11 +199,17 @@ main(int argc, char **argv)
 		return -1;
 	}
 
-	/* Open the netmap port. */
-	ctx.nmd = nmd = nm_open(ifname, NULL, 0, NULL);
-	if (!nmd) {
-		printf("nm_open(%s) failed\n", ifname);
-		return -1;
+	{
+		/* Open the netmap port with NR_EXCLUSIVE. */
+		struct nmreq nmr;
+
+		memset(&nmr, 0, sizeof(nmr));
+		nmr.nr_flags = NR_EXCLUSIVE;
+		ctx.nmd = nmd = nm_open(ifname, &nmr, 0, NULL);
+		if (!nmd) {
+			printf("nm_open(%s) failed\n", ifname);
+			return -1;
+		}
 	}
 
 	/* Allocate CSB entries. */

From 92ce196d7dd84ab055894c694e1ee9804b5f8554 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Oct 2018 16:54:20 +0200
Subject: [PATCH 1283/2207] sync-kloop: add support for poll-like wait scheme

---
 LINUX/netmap_linux.c         |  1 +
 sys/dev/netmap/netmap.c      | 77 +++++++++++++++++++++++++++++++++++-
 sys/dev/netmap/netmap_kern.h |  3 ++
 3 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e7b8ddf07..4aa2efaf9 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1438,6 +1438,7 @@ linux_netmap_open(struct inode *inode, struct file *file)
 		error = -ENOMEM;
 		goto out;
 	}
+	priv->filp = file;
 	file->private_data = priv;
 out:
 	NMG_UNLOCK();
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c369077c0..d0029dc9e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4222,6 +4222,40 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	}
 }
 
+//#define SYNC_KLOOP_POLL
+#ifdef SYNC_KLOOP_POLL
+struct sync_kloop_poll_entry {
+	wait_queue_entry_t wait;
+	wait_queue_head_t *wqh;
+};
+
+struct sync_kloop_poll_ctx {
+	struct netmap_priv_d *priv;
+	NM_SELINFO_T *si[NR_TXRX];
+	poll_table wait_table;
+	unsigned int next_entry;
+	unsigned int num_entries;
+	struct sync_kloop_poll_entry entries[4];
+};
+
+static void
+sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
+				poll_table *pt)
+{
+	struct sync_kloop_poll_ctx *ctx = container_of(pt, struct sync_kloop_poll_ctx,
+							wait_table);
+	struct sync_kloop_poll_entry *entry = ctx->entries + ctx->next_entry;
+
+	BUG_ON(ctx->next_entry >= ctx->num_entries);
+	entry->wqh = wqh;
+	/* Use the default wake up function. */
+	init_waitqueue_entry(&entry->wait, current);
+	add_wait_queue(wqh, &entry->wait);
+	ctx->next_entry++;
+	nm_prinf("POLL ENTRY %d FILLED\n", ctx->next_entry);
+}
+#endif  /* SYNC_KLOOP_POLL */
+
 int
 netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
 {
@@ -4230,8 +4264,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	struct nm_csb_ktoa* csb_ktoa_base;
 	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
+	unsigned int i;
 	int err = 0;
 
+#ifdef SYNC_KLOOP_POLL
+	struct sync_kloop_poll_ctx ctx;
+#endif  /* SYNC_KLOOP_POLL */
+
 	if (sleep_us > 1000000) {
 		/* We do not accept sleeping for more than a second. */
 		return EINVAL;
@@ -4275,7 +4314,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		if (num_entries > 0) {
 			size_t entry_size[2];
 			void *csb_start[2];
-			unsigned int i;
 
 			entry_size[0] = sizeof(*csb_atok_base);
 			entry_size[1] = sizeof(*csb_ktoa_base);
@@ -4316,9 +4354,25 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 	}
 
+#ifdef SYNC_KLOOP_POLL
+	memset(&ctx, 0, sizeof(ctx));
+	init_poll_funcptr(&ctx.wait_table, sync_kloop_poll_table_queue_proc);
+	ctx.num_entries = sizeof(ctx.entries)/sizeof(ctx.entries[0]);
+	ctx.next_entry = 0;
+	ctx.priv = priv;
+	ctx.si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+	ctx.si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+	poll_wait(priv->filp, ctx.si[NR_RX], &ctx.wait_table);
+	poll_wait(priv->filp, ctx.si[NR_TX], &ctx.wait_table);
+#endif  /* SYNC_KLOOP_POLL */
+
 	/* Main loop. */
 	for (;;) {
-		unsigned int i;
+#ifdef SYNC_KLOOP_POLL
+		__set_current_state(TASK_INTERRUPTIBLE);
+#endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
@@ -4348,14 +4402,33 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 			nm_kr_put(kring);
 		}
 
+#ifdef SYNC_KLOOP_POLL
+		{
+			long remt;
+
+			nm_prinf("about to sleep\n");
+			remt = schedule_timeout_interruptible(msecs_to_jiffies(3000));
+			nm_prinf("woken up (%ld)\n", remt);
+		}
+#else  /* SYNC_KLOOP_POLL */
 		/* Default synchronization method: sleep for a while. */
 		usleep_range(sleep_us, sleep_us);
+#endif /* SYNC_KLOOP_POLL */
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
 		}
 	}
 
+#ifdef SYNC_KLOOP_POLL
+	__set_current_state(TASK_RUNNING);
+	for (i = 0; i < ctx.next_entry; i++) {
+		struct sync_kloop_poll_entry *entry = ctx.entries + i;
+
+		remove_wait_queue(entry->wqh, &entry->wait);
+	}
+#endif /* SYNC_KLOOP_POLL */
+
 	/* Reset the kloop state. */
 	NMG_LOCK();
 	priv->np_kloop_state = 0;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index eee4b3ff9..d53507d1d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1881,6 +1881,9 @@ struct netmap_priv_d {
 	 */
 	NM_SELINFO_T *np_si[NR_TXRX];
 	struct thread	*np_td;		/* kqueue, just debugging */
+#ifdef linux
+	struct file	*filp;  /* used by sync kloop */
+#endif /* linux */
 };
 
 struct netmap_priv_d *netmap_priv_new(void);

From 2b5f8171c86681c7ce95826045b7e4ac3e2eedff Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Oct 2018 17:50:52 +0200
Subject: [PATCH 1284/2207] sync-kloop: discard
 schedule_interruptible_timeout() return value

---
 sys/dev/netmap/netmap.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d0029dc9e..c96dc10d2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4252,7 +4252,7 @@ sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 	init_waitqueue_entry(&entry->wait, current);
 	add_wait_queue(wqh, &entry->wait);
 	ctx->next_entry++;
-	nm_prinf("POLL ENTRY %d FILLED\n", ctx->next_entry);
+	nm_prinf("poll entry #%d filled\n", ctx->next_entry);
 }
 #endif  /* SYNC_KLOOP_POLL */
 
@@ -4403,13 +4403,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		{
-			long remt;
-
-			nm_prinf("about to sleep\n");
-			remt = schedule_timeout_interruptible(msecs_to_jiffies(3000));
-			nm_prinf("woken up (%ld)\n", remt);
-		}
+		schedule_timeout_interruptible(msecs_to_jiffies(1000));
 #else  /* SYNC_KLOOP_POLL */
 		/* Default synchronization method: sleep for a while. */
 		usleep_range(sleep_us, sleep_us);

From 46e64eebf513b285dfe87c00986783a69fc03bf7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Oct 2018 17:55:41 +0200
Subject: [PATCH 1285/2207] utils: sync_kloop_test: infinite rate as default

---
 utils/sync_kloop_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 98a6b86b0..7247a6a5d 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -106,7 +106,7 @@ main(int argc, char **argv)
 	struct context ctx;
 	struct nm_desc *nmd;
 
-	double target_rate         = 1.0 /* pps */;
+	double target_rate         = 0.0 /* pps */;
 	unsigned int period_us     = 0;
 	unsigned int period_budget = 0;
 	struct timeval next_time;

From 22f860aa29994a242010d681c4387001bebebf9c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 11:30:06 +0200
Subject: [PATCH 1286/2207] sync-kloop: add option to pass eventfds for
 notifications

---
 LINUX/netmap_linux.c         |   2 +-
 sys/dev/netmap/netmap.c      | 170 ++++++++++++++++++++++++-----------
 sys/dev/netmap/netmap_kern.h |   4 +-
 sys/net/netmap.h             |  18 ++++
 4 files changed, 139 insertions(+), 55 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4aa2efaf9..0b354e903 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1438,7 +1438,7 @@ linux_netmap_open(struct inode *inode, struct file *file)
 		error = -ENOMEM;
 		goto out;
 	}
-	priv->filp = file;
+	priv->np_filp = file;
 	file->private_data = priv;
 out:
 	NMG_UNLOCK();
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c96dc10d2..724a912de 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2629,9 +2629,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_START: {
-			struct nmreq_sync_kloop_start *req =
-				(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
-			error = netmap_sync_kloop(priv, req);
+			error = netmap_sync_kloop(priv, hdr);
 			break;
 		}
 
@@ -2765,7 +2763,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 }
 
 static size_t
-nmreq_opt_size_by_type(uint16_t nro_reqtype)
+nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 {
 	size_t rv = sizeof(struct nmreq_option);
 #ifdef NETMAP_REQ_OPT_DEBUG
@@ -2778,6 +2776,10 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
 		rv = sizeof(struct nmreq_opt_extmem);
 		break;
 #endif /* WITH_EXTMEM */
+	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
+		if (nro_size >= rv)
+			rv = nro_size;
+		break;
 	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
@@ -2824,7 +2826,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		if (error)
 			goto out_err;
 		optsz += sizeof(*src);
-		optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
+		optsz += nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
 		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
 			error = EMSGSIZE;
 			goto out_err;
@@ -2878,7 +2880,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		p = (char *)(opt + 1);
 
 		/* copy the option body */
-		optsz = nmreq_opt_size_by_type(opt->nro_reqtype);
+		optsz = nmreq_opt_size_by_type(opt->nro_reqtype,
+						opt->nro_size);
 		if (optsz) {
 			/* the option body follows the option header */
 			error = copyin(src + 1, p, optsz);
@@ -2952,7 +2955,8 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 
 		/* copy the option body only if there was no error */
 		if (!rerror && !src->nro_status) {
-			optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+			optsz = nmreq_opt_size_by_type(src->nro_reqtype,
+							src->nro_size);
 			if (optsz) {
 				error = copyout(src + 1, dst + 1, optsz);
 				if (error) {
@@ -4224,52 +4228,58 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 
 //#define SYNC_KLOOP_POLL
 #ifdef SYNC_KLOOP_POLL
+#include 
 struct sync_kloop_poll_entry {
+	struct file *filp;
 	wait_queue_entry_t wait;
 	wait_queue_head_t *wqh;
 };
 
 struct sync_kloop_poll_ctx {
-	struct netmap_priv_d *priv;
 	NM_SELINFO_T *si[NR_TXRX];
 	poll_table wait_table;
 	unsigned int next_entry;
 	unsigned int num_entries;
-	struct sync_kloop_poll_entry entries[4];
+	struct sync_kloop_poll_entry entries[0];
 };
 
 static void
 sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 				poll_table *pt)
 {
-	struct sync_kloop_poll_ctx *ctx = container_of(pt, struct sync_kloop_poll_ctx,
-							wait_table);
-	struct sync_kloop_poll_entry *entry = ctx->entries + ctx->next_entry;
+	struct sync_kloop_poll_ctx *poll_ctx =
+		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
+	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
+						poll_ctx->next_entry;
 
-	BUG_ON(ctx->next_entry >= ctx->num_entries);
+	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
 	entry->wqh = wqh;
+	entry->filp = file;
 	/* Use the default wake up function. */
 	init_waitqueue_entry(&entry->wait, current);
 	add_wait_queue(wqh, &entry->wait);
-	ctx->next_entry++;
-	nm_prinf("poll entry #%d filled\n", ctx->next_entry);
+	poll_ctx->next_entry++;
+	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
 }
 #endif  /* SYNC_KLOOP_POLL */
 
 int
-netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req)
+netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 {
+	struct nmreq_sync_kloop_start *req =
+		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
+	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
+#ifdef SYNC_KLOOP_POLL
+	struct sync_kloop_poll_ctx *poll_ctx = NULL;
+#endif  /* SYNC_KLOOP_POLL */
+	int num_rx_rings, num_tx_rings, num_rings;
 	uint32_t sleep_us = req->sleep_us;
 	struct nm_csb_atok* csb_atok_base;
 	struct nm_csb_ktoa* csb_ktoa_base;
-	int num_rx_rings, num_tx_rings;
 	struct netmap_adapter *na;
-	unsigned int i;
+	struct nmreq_option *opt;
 	int err = 0;
-
-#ifdef SYNC_KLOOP_POLL
-	struct sync_kloop_poll_ctx ctx;
-#endif  /* SYNC_KLOOP_POLL */
+	int i;
 
 	if (sleep_us > 1000000) {
 		/* We do not accept sleeping for more than a second. */
@@ -4306,12 +4316,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
 	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
 	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+	num_rings = num_tx_rings + num_rx_rings;
 
 	/* Validate the CSB entries for both directions (atok and ktoa). */
 	{
-		int num_entries = num_rx_rings + num_tx_rings;
-
-		if (num_entries > 0) {
+		if (num_rings > 0) {
 			size_t entry_size[2];
 			void *csb_start[2];
 
@@ -4325,17 +4334,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 				 * the validation. However, the advantage of
 				 * this approach is that it works also on
 				 * FreeBSD. */
-				size_t csb_size = num_entries * entry_size[i];
+				size_t csb_size = num_rings * entry_size[i];
 				void *tmp;
 
 				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
 					nm_prerr("Unaligned CSB address\n");
-					return EINVAL;
+					err = EINVAL;
+					goto out;
 				}
 
 				tmp = nm_os_malloc(csb_size);
 				if (!tmp) {
-					return ENOMEM;
+					err = ENOMEM;
+					goto out;
 				}
 				if (i == 0) {
 					/* Application --> kernel direction. */
@@ -4348,30 +4359,72 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 				nm_os_free(tmp);
 				if (err) {
 					nm_prerr("Invalid CSB address\n");
-					return err;
+					goto out;
 				}
 			}
 		}
 	}
 
+	/* Validate notification options. */
+	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
+	if (opt != NULL) {
+		err = nmreq_checkduplicate(opt);
+		if (err) {
+			opt->nro_status = err;
+			goto out;
+		}
+		if (opt->nro_size != sizeof(*eventfds_opt) +
+			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
+			/* Option size not consistent with the number of
+			 * entries. */
+			opt->nro_status = err = EINVAL;
+			goto out;
+		}
 #ifdef SYNC_KLOOP_POLL
-	memset(&ctx, 0, sizeof(ctx));
-	init_poll_funcptr(&ctx.wait_table, sync_kloop_poll_table_queue_proc);
-	ctx.num_entries = sizeof(ctx.entries)/sizeof(ctx.entries[0]);
-	ctx.next_entry = 0;
-	ctx.priv = priv;
-	ctx.si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-	ctx.si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-	poll_wait(priv->filp, ctx.si[NR_RX], &ctx.wait_table);
-	poll_wait(priv->filp, ctx.si[NR_TX], &ctx.wait_table);
+		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
+		opt->nro_status = 0;
+		/* We need 2 poll entries for TX and RX notifications coming
+		 * from the netmap adapter, plus one entries per ring for the
+		 * notifications coming from the application. */
+		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
+				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
+		init_poll_funcptr(&poll_ctx->wait_table,
+					sync_kloop_poll_table_queue_proc);
+		poll_ctx->num_entries = 2 + num_rings;
+		poll_ctx->next_entry = 0;
+		poll_ctx->si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+		poll_ctx->si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		poll_wait(priv->np_filp, poll_ctx->si[NR_RX], &poll_ctx->wait_table);
+		poll_wait(priv->np_filp, poll_ctx->si[NR_TX], &poll_ctx->wait_table);
+		for (i = 0; i < num_rings; i++) {
+			struct file *filp;
+			unsigned long mask;
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
+			if (mask & POLLERR) {
+				err = EINVAL;
+				goto out;
+			}
+		}
+#else   /* SYNC_KLOOP_POLL */
+		opt->nro_status = EOPNOTSUPP;
+		goto out;
 #endif  /* SYNC_KLOOP_POLL */
+	}
 
 	/* Main loop. */
 	for (;;) {
 #ifdef SYNC_KLOOP_POLL
-		__set_current_state(TASK_INTERRUPTIBLE);
+		if (poll_ctx)
+			__set_current_state(TASK_INTERRUPTIBLE);
 #endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
@@ -4403,23 +4456,36 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		schedule_timeout_interruptible(msecs_to_jiffies(1000));
-#else  /* SYNC_KLOOP_POLL */
-		/* Default synchronization method: sleep for a while. */
-		usleep_range(sleep_us, sleep_us);
+		if (poll_ctx)
+			schedule_timeout_interruptible(msecs_to_jiffies(1000));
+		else
 #endif /* SYNC_KLOOP_POLL */
+		{
+			/* Default synchronization method: sleep for a while. */
+			usleep_range(sleep_us, sleep_us);
+		}
 
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
 			break;
 		}
 	}
-
+out:
 #ifdef SYNC_KLOOP_POLL
-	__set_current_state(TASK_RUNNING);
-	for (i = 0; i < ctx.next_entry; i++) {
-		struct sync_kloop_poll_entry *entry = ctx.entries + i;
-
-		remove_wait_queue(entry->wqh, &entry->wait);
+	if (poll_ctx) {
+		__set_current_state(TASK_RUNNING);
+		for (i = 0; i < poll_ctx->next_entry; i++) {
+			struct sync_kloop_poll_entry *entry =
+						poll_ctx->entries + i;
+
+			if (entry->wqh) {
+				remove_wait_queue(entry->wqh, &entry->wait);
+			}
+			if (entry->filp && entry->filp != priv->np_filp) {
+				fput(entry->filp);
+			}
+		}
+		nm_os_free(poll_ctx);
+		poll_ctx = NULL;
 	}
 #endif /* SYNC_KLOOP_POLL */
 
@@ -4428,7 +4494,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_sync_kloop_start *req
 	priv->np_kloop_state = 0;
 	NMG_UNLOCK();
 
-	return 0;
+	return err;
 }
 
 /*
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d53507d1d..e845ebded 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1882,7 +1882,7 @@ struct netmap_priv_d {
 	NM_SELINFO_T *np_si[NR_TXRX];
 	struct thread	*np_td;		/* kqueue, just debugging */
 #ifdef linux
-	struct file	*filp;  /* used by sync kloop */
+	struct file	*np_filp;  /* used by sync kloop */
 #endif /* linux */
 };
 
@@ -2130,7 +2130,7 @@ void nm_os_kctx_worker_setaff(struct nm_kctx *, int);
 u_int nm_os_ncpus(void);
 
 int netmap_sync_kloop(struct netmap_priv_d *priv,
-		      struct nmreq_sync_kloop_start *req);
+		      struct nmreq_header *hdr);
 
 #ifdef WITH_PTNETMAP_HOST
 /*
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index aa31f521b..44d31a3c9 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -477,6 +477,8 @@ struct nmreq_option {
 	 * !=0: errno value
 	 */
 	uint32_t		nro_status;
+	/* Option size, used only by variable-size options. */
+	uint64_t		nro_size;
 };
 
 /* Header common to all requests. Do not reorder these fields, as we need
@@ -529,6 +531,10 @@ enum {
 	/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
 	 * from user-space allocated memory pools (e.g. hugepages). */
 	NETMAP_REQ_OPT_EXTMEM = 1,
+	/* ON NETMAP_REQ_SYNC_KLOOP_START, ask netmap to use eventfd-based
+	 * notifications to synchronize the kernel loop with the application.
+	 */
+	NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS,
 };
 
 /*
@@ -796,6 +802,18 @@ nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
  * data for NETMAP_REQ_OPT_* options
  */
 
+struct nmreq_opt_sync_kloop_eventfds {
+	struct nmreq_option	nro_opt;	/* common header */
+	/* An array of N entries for bidirectional notifications between
+	 * the kernel loop and the application. The number of entries must
+	 * agree with the number of rings bound to the netmap file descriptor.
+	 */
+	struct {
+		int32_t ioeventfd;
+		int32_t irqfd;
+	} eventfds[0];
+};
+
 struct nmreq_opt_extmem {
 	struct nmreq_option	nro_opt;	/* common header */
 	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */

From f198d44a8fc096fde15cac602232b8997a698739 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 11:35:01 +0200
Subject: [PATCH 1287/2207] sync-kloop: add some comments

---
 sys/dev/netmap/netmap.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 724a912de..b2c45df28 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4226,7 +4226,7 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	}
 }
 
-//#define SYNC_KLOOP_POLL
+#define SYNC_KLOOP_POLL
 #ifdef SYNC_KLOOP_POLL
 #include 
 struct sync_kloop_poll_entry {
@@ -4397,8 +4397,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
 		poll_ctx->si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
 					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		/* Poll for notifications coming from the netmap rings bound to
+		 * this file descriptor. */
 		poll_wait(priv->np_filp, poll_ctx->si[NR_RX], &poll_ctx->wait_table);
 		poll_wait(priv->np_filp, poll_ctx->si[NR_TX], &poll_ctx->wait_table);
+		/* Poll for notifications coming from the applications through
+		 * eventfds . */
 		for (i = 0; i < num_rings; i++) {
 			struct file *filp;
 			unsigned long mask;
@@ -4456,9 +4460,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
+		if (poll_ctx) {
+			/* If a poll context is present, yield to the scheduler
+			 * waiting for a notification to come either from
+			 * netmap or the application. */
 			schedule_timeout_interruptible(msecs_to_jiffies(1000));
-		else
+		} else
 #endif /* SYNC_KLOOP_POLL */
 		{
 			/* Default synchronization method: sleep for a while. */
@@ -4472,6 +4479,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 out:
 #ifdef SYNC_KLOOP_POLL
 	if (poll_ctx) {
+		/* Stop polling from netmap and the eventfds, and deallocate
+		 * the poll context. */
 		__set_current_state(TASK_RUNNING);
 		for (i = 0; i < poll_ctx->next_entry; i++) {
 			struct sync_kloop_poll_entry *entry =

From b0e55b50832083a8111a69b67c4cf9ed4131bde4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:18:08 +0200
Subject: [PATCH 1288/2207] utils: sync_kloop_test: allocate eventfds

---
 utils/sync_kloop_test.c | 83 +++++++++++++++++++++++++++++++++++------
 1 file changed, 72 insertions(+), 11 deletions(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 7247a6a5d..a334c6d3d 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -11,6 +11,9 @@
 #include 
 #include 
 #include 
+#ifdef __linux__
+#include 
+#endif /* __linux__ */
 
 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
 
@@ -23,6 +26,11 @@ sigint_handler(int signum)
 	ACCESS_ONCE(stop) = 1;
 }
 
+struct eventfds {
+	int ioeventfd;
+	int irqfd;
+};
+
 struct context {
 	struct nm_desc *nmd;
 	struct nm_csb_atok *atok_base;
@@ -30,24 +38,44 @@ struct context {
 	int sleep_us;
 	int verbose;
 	int batch;
+	int num_entries;
+	struct eventfds *eventfds;
 };
 
 static void *
 kloop_worker(void *opaque)
 {
-	struct context *ctx = opaque;
-	struct nm_desc *nmd = ctx->nmd;
+	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
+	struct context *ctx                       = opaque;
+	struct nm_desc *nmd                       = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 	int ret;
 
+	if (ctx->eventfds) {
+		size_t opt_size = sizeof(*opt) +
+		                  ctx->num_entries * sizeof(opt->eventfds[0]);
+		int i;
+
+		opt = malloc(opt_size);
+		memset(opt, 0, opt_size);
+		opt->nro_opt.nro_next    = 0;
+		opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
+		opt->nro_opt.nro_status  = 0;
+		opt->nro_opt.nro_size    = opt_size;
+		for (i = 0; i < ctx->num_entries; i++) {
+			opt->eventfds[i].ioeventfd = ctx->eventfds[i].ioeventfd;
+			opt->eventfds[i].irqfd     = ctx->eventfds[i].irqfd;
+		}
+	}
+
 	/* The ioctl() returns on failure or when some other thread
 	 * stops the kernel loop. */
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.nr_version = NETMAP_API;
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
 	hdr.nr_body    = (uintptr_t)&req;
-	hdr.nr_options = (uintptr_t)NULL;
+	hdr.nr_options = (uintptr_t)opt;
 	memset(&req, 0, sizeof(req));
 	req.csb_atok = (uintptr_t)ctx->atok_base;
 	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
@@ -83,6 +111,7 @@ usage(const char *progname)
 	       "[-R RATE_PPS (0 = infinite)]\n"
 	       "[-b BATCH_SIZE (in packets)]\n"
 	       "[-u KLOOP_SLEEP_US (in microseconds)]\n"
+	       "[-k (use eventfd-based notifications)]\n"
 	       "-i NETMAP_PORT\n",
 	       progname);
 }
@@ -97,7 +126,7 @@ main(int argc, char **argv)
 {
 	struct nm_csb_atok *atok_base = NULL;
 	struct nm_csb_ktoa *ktoa_base = NULL;
-	int num_entries, num_tx_entries;
+	int num_tx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
 	const char *ifname       = NULL;
@@ -112,6 +141,7 @@ main(int argc, char **argv)
 	struct timeval next_time;
 	int packet_budget;
 	struct timeval loop_begin, loop_end;
+	int use_eventfds = 0;
 
 	int init_tx_payload = 1;
 	function_t func;
@@ -138,7 +168,7 @@ main(int argc, char **argv)
 	ctx.batch    = 1;
 	ctx.sleep_us = 500;
 
-	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:k")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -186,6 +216,10 @@ main(int argc, char **argv)
 			}
 			break;
 
+		case 'k':
+			use_eventfds = 1;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -216,13 +250,13 @@ main(int argc, char **argv)
 	{
 		size_t csb_size;
 
-		num_tx_entries = nmd->last_tx_ring - nmd->first_tx_ring + 1;
-		num_entries    = num_tx_entries + nmd->last_rx_ring -
-		              nmd->first_rx_ring + 1;
-		printf("Number of CSB entries = %d\n", (int)num_entries);
+		num_tx_entries  = nmd->last_tx_ring - nmd->first_tx_ring + 1;
+		ctx.num_entries = num_tx_entries + nmd->last_rx_ring -
+		                  nmd->first_rx_ring + 1;
+		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
-		           num_entries;
+		           ctx.num_entries;
 		assert(csb_size > 0);
 		ret = posix_memalign(&csb, sizeof(struct nm_csb_atok),
 		                     csb_size);
@@ -234,7 +268,34 @@ main(int argc, char **argv)
 
 		atok_base = ctx.atok_base = (struct nm_csb_atok *)csb;
 		ktoa_base                 = ctx.ktoa_base =
-		        (struct nm_csb_ktoa *)(ctx.atok_base + num_entries);
+		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
+	}
+
+	/* Allocate eventfds. */
+	if (use_eventfds) {
+#ifdef __linux__
+		int i;
+
+		ctx.eventfds =
+		        malloc(ctx.num_entries * sizeof(ctx.eventfds[0]));
+		for (i = 0; i < ctx.num_entries; i++) {
+			int efd;
+
+			efd = eventfd(0, 0);
+			if (efd < 0) {
+				perror("eventfd()");
+			}
+			ctx.eventfds[i].ioeventfd = efd;
+			efd                       = eventfd(0, 0);
+			if (efd < 0) {
+				perror("eventfd()");
+			}
+			ctx.eventfds[i].irqfd = efd;
+		}
+#else  /* !__linux__ */
+		printf("Eventfds not supported on this platform\n");
+		return -1;
+#endif /* !__linux__ */
 	}
 
 	/* Start the kernel worker thread. */

From 4d28752265c089c55c42a727863798cb376ae9ba Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:22:34 +0200
Subject: [PATCH 1289/2207] sync-kloop: add comment about fput() invocation

---
 sys/dev/netmap/netmap.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b2c45df28..bb4e6f7fc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4489,6 +4489,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			if (entry->wqh) {
 				remove_wait_queue(entry->wqh, &entry->wait);
 			}
+			/* We did not get a reference to the eventfds, but
+			 * don't do that on netmap file descriptors (since
+			 * a reference was not taken. */
 			if (entry->filp && entry->filp != priv->np_filp) {
 				fput(entry->filp);
 			}

From 02e37ffd77bdd24aaf3ce25944da8f6a3fc79f01 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:23:39 +0200
Subject: [PATCH 1290/2207] sync-kloop: remove old notifications

---
 sys/dev/netmap/netmap.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bb4e6f7fc..dbdbde652 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4080,7 +4080,6 @@ netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
 			 * go to sleep, waiting for a kick from the application when new
 			 * new slots are ready for transmission.
 			 */
-			usleep_range(1,1);
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */
@@ -4193,7 +4192,6 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 			 * go to sleep, waiting for a kick from the application when new receive
 			 * slots are available.
 			 */
-			usleep_range(1,1);
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Doublecheck. */

From 924d2e2953d3e13830c63f6cfe7f5dffd39160e5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:30:54 +0200
Subject: [PATCH 1291/2207] sync-kloop: start polling netmap notifications
 after application's ones

---
 sys/dev/netmap/netmap.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index dbdbde652..261ce9541 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4234,7 +4234,6 @@ struct sync_kloop_poll_entry {
 };
 
 struct sync_kloop_poll_ctx {
-	NM_SELINFO_T *si[NR_TXRX];
 	poll_table wait_table;
 	unsigned int next_entry;
 	unsigned int num_entries;
@@ -4367,6 +4366,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
 	if (opt != NULL) {
+		NM_SELINFO_T *si[NR_TXRX];
+
 		err = nmreq_checkduplicate(opt);
 		if (err) {
 			opt->nro_status = err;
@@ -4391,14 +4392,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					sync_kloop_poll_table_queue_proc);
 		poll_ctx->num_entries = 2 + num_rings;
 		poll_ctx->next_entry = 0;
-		poll_ctx->si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-		poll_ctx->si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-		/* Poll for notifications coming from the netmap rings bound to
-		 * this file descriptor. */
-		poll_wait(priv->np_filp, poll_ctx->si[NR_RX], &poll_ctx->wait_table);
-		poll_wait(priv->np_filp, poll_ctx->si[NR_TX], &poll_ctx->wait_table);
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
 		for (i = 0; i < num_rings; i++) {
@@ -4416,6 +4409,14 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 				goto out;
 			}
 		}
+		/* Poll for notifications coming from the netmap rings bound to
+		 * this file descriptor. */
+		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
+		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
 #else   /* SYNC_KLOOP_POLL */
 		opt->nro_status = EOPNOTSUPP;
 		goto out;

From 5093566658dc9aab43095d2f334967e57ef02f62 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 12:50:42 +0200
Subject: [PATCH 1292/2207] sync-kloop: get ioeventfd file descriptors

---
 sys/dev/netmap/netmap.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 261ce9541..a80a7a043 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4228,9 +4228,15 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 #ifdef SYNC_KLOOP_POLL
 #include 
 struct sync_kloop_poll_entry {
+	/* Support for receiving notifications from
+	 * a netmap ring or from the application. */
 	struct file *filp;
 	wait_queue_entry_t wait;
 	wait_queue_head_t *wqh;
+
+	/* Support for sending notifications to the application. */
+	struct eventfd_ctx *irq_ctx;
+	struct file *irq_filp;
 };
 
 struct sync_kloop_poll_ctx {
@@ -4395,6 +4401,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
 		for (i = 0; i < num_rings; i++) {
+			struct eventfd_ctx *irq;
 			struct file *filp;
 			unsigned long mask;
 
@@ -4408,6 +4415,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 				err = EINVAL;
 				goto out;
 			}
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_filp = filp;
+			irq = eventfd_ctx_fileget(filp);
+			if (IS_ERR(irq)) {
+				err = PTR_ERR(irq);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_ctx = irq;
 		}
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
@@ -4485,15 +4505,17 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			struct sync_kloop_poll_entry *entry =
 						poll_ctx->entries + i;
 
-			if (entry->wqh) {
+			if (entry->wqh)
 				remove_wait_queue(entry->wqh, &entry->wait);
-			}
 			/* We did not get a reference to the eventfds, but
 			 * don't do that on netmap file descriptors (since
 			 * a reference was not taken. */
-			if (entry->filp && entry->filp != priv->np_filp) {
+			if (entry->filp && entry->filp != priv->np_filp)
 				fput(entry->filp);
-			}
+			if (entry->irq_ctx)
+				eventfd_ctx_put(entry->irq_ctx);
+			if (entry->irq_filp)
+				fput(entry->irq_filp);
 		}
 		nm_os_free(poll_ctx);
 		poll_ctx = NULL;

From 063cbb75de4f7fa199291ded216f043fa638d345 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 16:35:14 +0200
Subject: [PATCH 1293/2207] sync-kloop: introduce struct to keep per-ring args

---
 sys/dev/netmap/netmap.c | 65 ++++++++++++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 21 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a80a7a043..7ac172555 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3987,11 +3987,22 @@ sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 		kring->rhead, kring->rcur, kring->rtail);
 }
 
+#define SYNC_KLOOP_POLL
+struct sync_kloop_ring_args {
+	struct netmap_kring *kring;
+	struct nm_csb_atok *csb_atok;
+	struct nm_csb_ktoa *csb_ktoa;
+#ifdef SYNC_KLOOP_POLL
+	struct eventfd_ctx *irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+};
+
 static void
-netmap_sync_kloop_tx_ring(struct netmap_kring *kring,
-			  struct nm_csb_atok *csb_atok,
-			  struct nm_csb_ktoa *csb_ktoa)
+netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 {
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	bool more_txspace = false;
 	uint32_t num_slots;
@@ -4117,10 +4128,12 @@ sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
 }
 
 static void
-netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
-			  struct nm_csb_atok *csb_atok,
-			  struct nm_csb_ktoa *csb_ktoa)
+netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 {
+
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	int dry_cycles = 0;
 	bool some_recvd = false;
@@ -4224,7 +4237,6 @@ netmap_sync_kloop_rx_ring(struct netmap_kring *kring,
 	}
 }
 
-#define SYNC_KLOOP_POLL
 #ifdef SYNC_KLOOP_POLL
 #include 
 struct sync_kloop_poll_entry {
@@ -4452,30 +4464,41 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
-			struct netmap_kring *kring =
-				NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
-			struct nm_csb_atok* csb_atok = csb_atok_base + i;
-			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + i;
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
+				.csb_atok = csb_atok_base + i,
+				.csb_ktoa = csb_ktoa_base + i,
+			};
 
-			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
 				continue;
 			}
-			netmap_sync_kloop_tx_ring(kring, csb_atok, csb_ktoa);
-			nm_kr_put(kring);
+			netmap_sync_kloop_tx_ring(&a);
+			nm_kr_put(a.kring);
 		}
 
 		/* Process all the RX rings bound to this file descriptor. */
 		for (i = 0; i < num_rx_rings; i++) {
-			struct netmap_kring *kring =
-				NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
-			struct nm_csb_atok* csb_atok = csb_atok_base + num_tx_rings + i;
-			struct nm_csb_ktoa* csb_ktoa = csb_ktoa_base + num_tx_rings + i;
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
+				.csb_atok = csb_atok_base + num_tx_rings + i,
+				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
+			};
 
-			if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
 				continue;
 			}
-			netmap_sync_kloop_rx_ring(kring, csb_atok, csb_ktoa);
-			nm_kr_put(kring);
+			netmap_sync_kloop_rx_ring(&a);
+			nm_kr_put(a.kring);
 		}
 
 #ifdef SYNC_KLOOP_POLL

From 2b082ca3e6ef520ad62d1ea48379f83dbd02779d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:11:17 +0200
Subject: [PATCH 1294/2207] sync-kloop: add support for sending notifications

---
 sys/dev/netmap/netmap.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 7ac172555..60f716d8e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4077,11 +4077,13 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 
 		/* Interrupt the application if needed. */
-		if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
+#ifdef SYNC_KLOOP_POLL
+		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
-			// nm_os_kctx_send_irq(kth); // TODO
+			eventfd_signal(a->irq_ctx, 1);
 			more_txspace = false;
 		}
+#endif /* SYNC_KLOOP_POLL */
 
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
@@ -4112,9 +4114,11 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 	}
 
-	if (more_txspace && csb_atok_intr_enabled(csb_atok)) {
-		// nm_os_kctx_send_irq(kth); // TODO
+#ifdef SYNC_KLOOP_POLL
+	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
 	}
+#endif /* SYNC_KLOOP_POLL */
 }
 
 /* RX cycle without receive any packets */
@@ -4190,12 +4194,14 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 			sync_kloop_kring_dump("post rxsync", kring);
 		}
 
+#ifdef SYNC_KLOOP_POLL
 		/* Interrupt the application if needed. */
-		if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
 			/* Disable application kick to avoid sending unnecessary kicks */
-			//nm_os_kctx_send_irq(kth); // TODO
+			eventfd_signal(a->irq_ctx, 1);
 			some_recvd = false;
 		}
+#endif /* SYNC_KLOOP_POLL */
 
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
@@ -4231,10 +4237,12 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 
 	nm_kr_put(kring);
 
+#ifdef SYNC_KLOOP_POLL
 	/* Interrupt the application if needed. */
-	if (some_recvd && csb_atok_intr_enabled(csb_atok)) {
-		//nm_os_kctx_send_irq(kth); // TODO
+	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
 	}
+#endif /* SYNC_KLOOP_POLL */
 }
 
 #ifdef SYNC_KLOOP_POLL

From a7fd4e696cb58f997a857566c26d5c06ab3aeb0b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:15:35 +0200
Subject: [PATCH 1295/2207] utils: sync_kloop_test: use 100 us as default sleep
 interval

---
 utils/sync_kloop_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index a334c6d3d..9a3a43d65 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -166,7 +166,7 @@ main(int argc, char **argv)
 	func         = F_RX;
 	ctx.verbose  = 0;
 	ctx.batch    = 1;
-	ctx.sleep_us = 500;
+	ctx.sleep_us = 100;
 
 	while ((opt = getopt(argc, argv, "hi:f:vR:b:u:k")) != -1) {
 		switch (opt) {

From 37d35abc856050f5d6efee3e3d012471cf239539 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:45:33 +0200
Subject: [PATCH 1296/2207] utils: sync_kloop_test: add support for app -->
 kern notifications

---
 utils/sync_kloop_test.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 9a3a43d65..78df2ebe7 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -126,6 +126,7 @@ main(int argc, char **argv)
 {
 	struct nm_csb_atok *atok_base = NULL;
 	struct nm_csb_ktoa *ktoa_base = NULL;
+	struct eventfds *eventfds_base = NULL;
 	int num_tx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
@@ -322,9 +323,11 @@ main(int argc, char **argv)
 #if 0
 	printf("period us %u batch %u\n", period_us, period_budget);
 #endif
+	eventfds_base = ctx.eventfds;
 	if (func == F_RX) {
 		atok_base += num_tx_entries;
 		ktoa_base += num_tx_entries;
+		eventfds_base += num_tx_entries;
 		first_ring = nmd->first_rx_ring;
 		last_ring  = nmd->last_rx_ring;
 	} else {
@@ -373,6 +376,8 @@ main(int argc, char **argv)
 		}
 
 		for (r = first_ring; r <= last_ring; r++) {
+			struct eventfds *evfds = ctx.eventfds ?
+					(eventfds_base + r) : NULL;
 			struct nm_csb_atok *atok = atok_base + r;
 			struct nm_csb_ktoa *ktoa = ktoa_base + r;
 			struct netmap_ring *ring;
@@ -448,7 +453,18 @@ main(int argc, char **argv)
 				bytes += slot->len;
 				head = nm_ring_next(ring, head);
 			}
+			/* Write updated information for the kernel. */
 			nm_sync_kloop_appl_write(atok, head, head);
+			/* Notify the kernel if needed. */
+			if (evfds && ACCESS_ONCE(ktoa->kern_need_kick)) {
+				uint64_t x = 1;
+				int n = write(evfds->ioeventfd, &x, sizeof(x));
+
+				assert(n == sizeof(x));
+				if (ctx.verbose) {
+					printf("Kernel notified\n");
+				}
+			}
 			if (ctx.verbose) {
 				printf("ring #%u, hwcur %u, head %u, hwtail "
 				       "%u\n",

From 6874023fe588a7345fffc4ce958242e80a3fb495 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 16 Oct 2018 17:59:01 +0200
Subject: [PATCH 1297/2207] prune ptnetmap host code

---
 LINUX/Kbuild.in              |    1 -
 extra/python/netmap.c        |    4 -
 sys/dev/netmap/netmap.c      |   11 -
 sys/dev/netmap/netmap_kern.h |   40 +-
 sys/dev/netmap/netmap_pt.c   | 1215 ----------------------------------
 sys/net/netmap.h             |    4 +-
 sys/net/netmap_virt.h        |   60 --
 utils/testmmap.c             |    8 -
 8 files changed, 2 insertions(+), 1341 deletions(-)

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index 1fb190940..a2ce4966c 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -15,7 +15,6 @@ remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
 remoteobjs-$(CONFIG_NETMAP_MONITOR) += netmap_monitor.o
 remoteobjs-$(CONFIG_NETMAP_GENERIC) += netmap_generic.o
 remoteobjs-ptnetmap-$(CONFIG_NETMAP_PTNETMAP_GUEST) = netmap_pt.o
-remoteobjs-ptnetmap-$(CONFIG_NETMAP_PTNETMAP_HOST)  = netmap_pt.o
 remoteobjs-y += $(remoteobjs-ptnetmap-y)
 
 define remote_template
diff --git a/extra/python/netmap.c b/extra/python/netmap.c
index 08da3f521..f34d6c6d5 100644
--- a/extra/python/netmap.c
+++ b/extra/python/netmap.c
@@ -270,10 +270,6 @@ static struct NetmapConst netmap_constants[] = {
         .name = "RegExclusive",
         .value = NR_EXCLUSIVE,
     },
-    {
-        .name = "RegPTNetmapHost",
-        .value = NR_PTNETMAP_HOST,
-    },
     /* Add 'netmap_rings.flags' constants to the module. */
     {
         .name = "NrTimestamp",
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 60f716d8e..5398dddfa 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1526,11 +1526,6 @@ netmap_get_na(struct nmreq_header *hdr,
 	 *  !0    !NULL		impossible
 	 */
 
-	/* try to see if this is a ptnetmap port */
-	error = netmap_get_pt_host_na(hdr, na, nmd, create);
-	if (error || *na != NULL)
-		goto out;
-
 	/* try to see if this is a monitor port */
 	error = netmap_get_monitor_na(hdr, na, nmd, create);
 	if (error || *na != NULL)
@@ -1808,12 +1803,6 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 	enum txrx t;
 	u_int j;
 
-	if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC) ||
-			nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
-		D("Error: only NR_REG_ALL_NIC supported with netmap passthrough");
-		return EINVAL;
-	}
-
 	for_rx_tx(t) {
 		if (nr_flags & excluded_direction[t]) {
 			priv->np_qfirst[t] = priv->np_qlast[t] = 0;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e845ebded..8cd7a3028 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -55,9 +55,6 @@
 #if defined(CONFIG_NETMAP_PTNETMAP_GUEST)
 #define WITH_PTNETMAP_GUEST
 #endif
-#if defined(CONFIG_NETMAP_PTNETMAP_HOST)
-#define WITH_PTNETMAP_HOST
-#endif
 #if defined(CONFIG_NETMAP_SINK)
 #define WITH_SINK
 #endif
@@ -73,7 +70,6 @@
 #define WITH_PIPES
 #define WITH_MONITOR
 #define WITH_GENERIC
-#define WITH_PTNETMAP_HOST	/* ptnetmap host support */
 #define WITH_PTNETMAP_GUEST	/* ptnetmap guest support */
 #define WITH_EXTMEM
 #endif
@@ -698,7 +694,7 @@ struct netmap_adapter {
 				 */
 #define NAF_HOST_RINGS  64	/* the adapter supports the host rings */
 #define NAF_FORCE_NATIVE 128	/* the adapter is always NATIVE */
-#define NAF_PTNETMAP_HOST 256	/* the adapter supports ptnetmap in the host */
+/* free */
 #define NAF_MOREFRAG	512	/* the adapter supports NS_MOREFRAG */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
@@ -2132,40 +2128,6 @@ u_int nm_os_ncpus(void);
 int netmap_sync_kloop(struct netmap_priv_d *priv,
 		      struct nmreq_header *hdr);
 
-#ifdef WITH_PTNETMAP_HOST
-/*
- * netmap adapter for host ptnetmap ports
- */
-struct netmap_pt_host_adapter {
-	struct netmap_adapter up;
-
-	/* the passed-through adapter */
-	struct netmap_adapter *parent;
-	/* parent->na_flags, saved at NETMAP_PT_HOST_CREATE time,
-	 * and restored at NETMAP_PT_HOST_DELETE time */
-	uint32_t parent_na_flags;
-
-	int (*parent_nm_notify)(struct netmap_kring *kring, int flags);
-	void *ptns;
-};
-
-/* ptnetmap host-side routines */
-int netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-			struct netmap_mem_d * nmd, int create);
-int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
-
-static inline int
-nm_ptnetmap_host_on(struct netmap_adapter *na)
-{
-	return na && na->na_flags & NAF_PTNETMAP_HOST;
-}
-#else /* !WITH_PTNETMAP_HOST */
-#define netmap_get_pt_host_na(hdr, _2, _3, _4) \
-	(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
-#define ptnetmap_ctl(_1, _2, _3)   EINVAL
-#define nm_ptnetmap_host_on(_1)   EINVAL
-#endif /* !WITH_PTNETMAP_HOST */
-
 #ifdef WITH_PTNETMAP_GUEST
 /* ptnetmap GUEST routines */
 
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index f53d66282..3f4aa9a28 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -41,10 +41,6 @@
 #include 
 #include 
 
-//#define usleep_range(_1, _2)
-#define usleep_range(_1, _2) \
-	pause_sbt("ptnetmap-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE)
-
 #elif defined(linux)
 #include 
 #endif
@@ -54,1217 +50,6 @@
 #include 
 #include 
 
-#ifdef WITH_PTNETMAP_HOST
-
-/* RX cycle without receive any packets */
-#define PTN_RX_DRY_CYCLES_MAX	10
-
-/* Limit Batch TX to half ring.
- * Currently disabled, since it does not manage NS_MOREFRAG, which
- * results in random drops in the VALE txsync. */
-//#define PTN_TX_BATCH_LIM(_n)	((_n >> 1))
-
-//#define BUSY_WAIT
-
-#define NETMAP_PT_DEBUG  /* Enables communication debugging. */
-#ifdef NETMAP_PT_DEBUG
-#define DBG(x) x
-#else
-#define DBG(x)
-#endif
-
-
-#undef RATE
-//#define RATE  /* Enables communication statistics. */
-#ifdef RATE
-#define IFRATE(x) x
-struct rate_batch_stats {
-    unsigned long sync;
-    unsigned long sync_dry;
-    unsigned long pkt;
-};
-
-struct rate_stats {
-    unsigned long gtxk;     /* Guest --> Host Tx kicks. */
-    unsigned long grxk;     /* Guest --> Host Rx kicks. */
-    unsigned long htxk;     /* Host --> Guest Tx kicks. */
-    unsigned long hrxk;     /* Host --> Guest Rx Kicks. */
-    unsigned long btxwu;    /* Backend Tx wake-up. */
-    unsigned long brxwu;    /* Backend Rx wake-up. */
-    struct rate_batch_stats txbs;
-    struct rate_batch_stats rxbs;
-};
-
-struct rate_context {
-    struct timer_list timer;
-    struct rate_stats new;
-    struct rate_stats old;
-};
-
-#define RATE_PERIOD  2
-static void
-rate_callback(unsigned long arg)
-{
-    struct rate_context * ctx = (struct rate_context *)arg;
-    struct rate_stats cur = ctx->new;
-    struct rate_batch_stats *txbs = &cur.txbs;
-    struct rate_batch_stats *rxbs = &cur.rxbs;
-    struct rate_batch_stats *txbs_old = &ctx->old.txbs;
-    struct rate_batch_stats *rxbs_old = &ctx->old.rxbs;
-    uint64_t tx_batch, rx_batch;
-    unsigned long txpkts, rxpkts;
-    unsigned long gtxk, grxk;
-    int r;
-
-    txpkts = txbs->pkt - txbs_old->pkt;
-    rxpkts = rxbs->pkt - rxbs_old->pkt;
-
-    tx_batch = ((txbs->sync - txbs_old->sync) > 0) ?
-	       txpkts / (txbs->sync - txbs_old->sync): 0;
-    rx_batch = ((rxbs->sync - rxbs_old->sync) > 0) ?
-	       rxpkts / (rxbs->sync - rxbs_old->sync): 0;
-
-    /* Fix-up gtxk and grxk estimates. */
-    gtxk = (cur.gtxk - ctx->old.gtxk) - (cur.btxwu - ctx->old.btxwu);
-    grxk = (cur.grxk - ctx->old.grxk) - (cur.brxwu - ctx->old.brxwu);
-
-    printk("txpkts  = %lu Hz\n", txpkts/RATE_PERIOD);
-    printk("gtxk    = %lu Hz\n", gtxk/RATE_PERIOD);
-    printk("htxk    = %lu Hz\n", (cur.htxk - ctx->old.htxk)/RATE_PERIOD);
-    printk("btxw    = %lu Hz\n", (cur.btxwu - ctx->old.btxwu)/RATE_PERIOD);
-    printk("rxpkts  = %lu Hz\n", rxpkts/RATE_PERIOD);
-    printk("grxk    = %lu Hz\n", grxk/RATE_PERIOD);
-    printk("hrxk    = %lu Hz\n", (cur.hrxk - ctx->old.hrxk)/RATE_PERIOD);
-    printk("brxw    = %lu Hz\n", (cur.brxwu - ctx->old.brxwu)/RATE_PERIOD);
-    printk("txbatch = %llu avg\n", tx_batch);
-    printk("rxbatch = %llu avg\n", rx_batch);
-    printk("\n");
-
-    ctx->old = cur;
-    r = mod_timer(&ctx->timer, jiffies +
-            msecs_to_jiffies(RATE_PERIOD * 1000));
-    if (unlikely(r))
-        D("[ptnetmap] Error: mod_timer()\n");
-}
-
-static void
-rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail,
-		        uint32_t act_tail, uint32_t num_slots)
-{
-    int n = (int)act_tail - pre_tail;
-
-    if (n) {
-        if (n < 0)
-            n += num_slots;
-
-        bf->sync++;
-        bf->pkt += n;
-    } else {
-        bf->sync_dry++;
-    }
-}
-
-#else /* !RATE */
-#define IFRATE(x)
-#endif /* RATE */
-
-struct ptnetmap_state {
-	/* Kthreads. */
-	struct nm_kctx **kctxs;
-
-	/* Shared memory with the guest (TX/RX) */
-	struct ptnet_csb_gh __user *csb_gh;
-	struct ptnet_csb_hg __user *csb_hg;
-
-	bool stopped;
-
-	/* Netmap adapter wrapping the backend. */
-	struct netmap_pt_host_adapter *pth_na;
-
-	IFRATE(struct rate_context rate_ctx;)
-};
-
-static inline void
-ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring)
-{
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d"
-		" rtail: %d head: %d cur: %d tail: %d",
-		title, kring->name, kring->nr_hwcur,
-		kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail,
-		kring->ring->head, kring->ring->cur, kring->ring->tail);
-}
-
-/*
- * TX functions to set/get and to handle host/guest kick.
- */
-
-
-/* Enable or disable guest --> host kicks. */
-static inline void
-pthg_kick_enable(struct ptnet_csb_hg __user *pthg, uint32_t val)
-{
-    CSB_WRITE(pthg, host_need_kick, val);
-}
-
-/* Are guest interrupt enabled or disabled? */
-static inline uint32_t
-ptgh_intr_enabled(struct ptnet_csb_gh __user *ptgh)
-{
-    uint32_t v;
-
-    CSB_READ(ptgh, guest_need_kick, v);
-
-    return v;
-}
-
-/* Handle TX events: from the guest or from the backend */
-static void
-ptnetmap_tx_handler(void *data, int is_kthread)
-{
-    struct netmap_kring *kring = data;
-    struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)kring->na->na_private;
-    struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_csb_gh __user *ptgh;
-    struct ptnet_csb_hg __user *pthg;
-    struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-    bool more_txspace = false;
-    struct nm_kctx *kth;
-    uint32_t num_slots;
-    int batch;
-    IFRATE(uint32_t pre_tail);
-
-    if (unlikely(!ptns)) {
-        D("ERROR ptnetmap state is NULL");
-        return;
-    }
-
-    if (unlikely(ptns->stopped)) {
-        RD(1, "backend netmap is being stopped");
-        return;
-    }
-
-    if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
-        D("ERROR nm_kr_tryget()");
-        return;
-    }
-
-    /* This is a guess, to be fixed in the rate callback. */
-    IFRATE(ptns->rate_ctx.new.gtxk++);
-
-    /* Get TX ptgh/pthg pointer from the CSB. */
-    ptgh = ptns->csb_gh + kring->ring_id;
-    pthg = ptns->csb_hg + kring->ring_id;
-    kth = ptns->kctxs[kring->ring_id];
-
-    num_slots = kring->nkr_num_slots;
-
-    /* Disable guest --> host notifications. */
-    pthg_kick_enable(pthg, 0);
-    /* Copy the guest kring pointers from the CSB */
-    ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-
-    for (;;) {
-	/* If guest moves ahead too fast, let's cut the move so
-	 * that we don't exceed our batch limit. */
-        batch = shadow_ring.head - kring->nr_hwcur;
-        if (batch < 0)
-            batch += num_slots;
-
-#ifdef PTN_TX_BATCH_LIM
-        if (batch > PTN_TX_BATCH_LIM(num_slots)) {
-            uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
-
-            if (head_lim >= num_slots)
-                head_lim -= num_slots;
-            ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
-						     head_lim);
-            shadow_ring.head = head_lim;
-	    batch = PTN_TX_BATCH_LIM(num_slots);
-        }
-#endif /* PTN_TX_BATCH_LIM */
-
-        if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
-            shadow_ring.flags |= NAF_FORCE_RECLAIM;
-        }
-
-        /* Netmap prologue */
-	shadow_ring.tail = kring->rtail;
-        if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
-            /* Reinit ring and enable notifications. */
-            netmap_ring_reinit(kring);
-            pthg_kick_enable(pthg, 1);
-            break;
-        }
-
-        if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-            ptnetmap_kring_dump("pre txsync", kring);
-	}
-
-        IFRATE(pre_tail = kring->rtail);
-        if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            D("ERROR txsync()");
-	    break;
-        }
-
-        /*
-         * Finalize
-         * Copy host hwcur and hwtail into the CSB for the guest sync(), and
-	 * do the nm_sync_finalize.
-         */
-        ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur,
-				      kring->nr_hwtail);
-        if (kring->rtail != kring->nr_hwtail) {
-	    /* Some more room available in the parent adapter. */
-	    kring->rtail = kring->nr_hwtail;
-	    more_txspace = true;
-        }
-
-        IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.txbs, pre_tail,
-				       kring->rtail, num_slots));
-
-        if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-            ptnetmap_kring_dump("post txsync", kring);
-	}
-
-#ifndef BUSY_WAIT
-        /* Interrupt the guest if needed. */
-        if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
-            /* Disable guest kick to avoid sending unnecessary kicks */
-            nm_os_kctx_send_irq(kth);
-            IFRATE(ptns->rate_ctx.new.htxk++);
-            more_txspace = false;
-        }
-#endif
-        /* Read CSB to see if there is more work to do. */
-        ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
-        if (shadow_ring.head == kring->rhead) {
-            /*
-             * No more packets to transmit. We enable notifications and
-             * go to sleep, waiting for a kick from the guest when new
-             * new slots are ready for transmission.
-             */
-            if (is_kthread) {
-                usleep_range(1,1);
-            }
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            /* Doublecheck. */
-            ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-            if (shadow_ring.head != kring->rhead) {
-		/* We won the race condition, there are more packets to
-		 * transmit. Disable notifications and do another cycle */
-		pthg_kick_enable(pthg, 0);
-		continue;
-	    }
-	    break;
-        }
-
-	if (nm_kr_txempty(kring)) {
-	    /* No more available TX slots. We stop waiting for a notification
-	     * from the backend (netmap_tx_irq). */
-            ND(1, "TX ring");
-            break;
-        }
-#endif
-        if (unlikely(ptns->stopped)) {
-            D("backend netmap is being stopped");
-            break;
-        }
-    }
-
-    nm_kr_put(kring);
-
-    if (more_txspace && ptgh_intr_enabled(ptgh) && is_kthread) {
-        nm_os_kctx_send_irq(kth);
-        IFRATE(ptns->rate_ctx.new.htxk++);
-    }
-}
-
-/* Called on backend nm_notify when there is no worker thread. */
-static void
-ptnetmap_tx_nothread_notify(void *data)
-{
-	struct netmap_kring *kring = data;
-	struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)kring->na->na_private;
-	struct ptnetmap_state *ptns = pth_na->ptns;
-
-	if (unlikely(!ptns)) {
-		D("ERROR ptnetmap state is NULL");
-		return;
-	}
-
-	if (unlikely(ptns->stopped)) {
-		D("backend netmap is being stopped");
-		return;
-	}
-
-	/* We cannot access the CSB here (to check ptgh->guest_need_kick),
-	 * unless we switch address space to the one of the guest. For now
-	 * we unconditionally inject an interrupt. */
-        nm_os_kctx_send_irq(ptns->kctxs[kring->ring_id]);
-        IFRATE(ptns->rate_ctx.new.htxk++);
-        ND(1, "%s interrupt", kring->name);
-}
-
-/*
- * We need RX kicks from the guest when (tail == head-1), where we wait
- * for the guest to refill.
- */
-#ifndef BUSY_WAIT
-static inline int
-ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head)
-{
-    return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
-    			    kring->nkr_num_slots - 1));
-}
-#endif /* !BUSY_WAIT */
-
-/* Handle RX events: from the guest or from the backend */
-static void
-ptnetmap_rx_handler(void *data, int is_kthread)
-{
-    struct netmap_kring *kring = data;
-    struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)kring->na->na_private;
-    struct ptnetmap_state *ptns = pth_na->ptns;
-    struct ptnet_csb_gh __user *ptgh;
-    struct ptnet_csb_hg __user *pthg;
-    struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-    struct nm_kctx *kth;
-    uint32_t num_slots;
-    int dry_cycles = 0;
-    bool some_recvd = false;
-    IFRATE(uint32_t pre_tail);
-
-    if (unlikely(!ptns || !ptns->pth_na)) {
-        D("ERROR ptnetmap state %p, ptnetmap host adapter %p", ptns,
-	  ptns ? ptns->pth_na : NULL);
-        return;
-    }
-
-    if (unlikely(ptns->stopped)) {
-        RD(1, "backend netmap is being stopped");
-	return;
-    }
-
-    if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
-        D("ERROR nm_kr_tryget()");
-	return;
-    }
-
-    /* This is a guess, to be fixed in the rate callback. */
-    IFRATE(ptns->rate_ctx.new.grxk++);
-
-    /* Get RX ptgh and pthg pointers from the CSB. */
-    ptgh = ptns->csb_gh + (pth_na->up.num_tx_rings + kring->ring_id);
-    pthg = ptns->csb_hg + (pth_na->up.num_tx_rings + kring->ring_id);
-    kth = ptns->kctxs[pth_na->up.num_tx_rings + kring->ring_id];
-
-    num_slots = kring->nkr_num_slots;
-
-    /* Disable notifications. */
-    pthg_kick_enable(pthg, 0);
-    /* Copy the guest kring pointers from the CSB */
-    ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-
-    for (;;) {
-	uint32_t hwtail;
-
-        /* Netmap prologue */
-	shadow_ring.tail = kring->rtail;
-        if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
-            /* Reinit ring and enable notifications. */
-            netmap_ring_reinit(kring);
-            pthg_kick_enable(pthg, 1);
-            break;
-        }
-
-        if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-            ptnetmap_kring_dump("pre rxsync", kring);
-	}
-
-        IFRATE(pre_tail = kring->rtail);
-        if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            D("ERROR rxsync()");
-	    break;
-        }
-        /*
-         * Finalize
-         * Copy host hwcur and hwtail into the CSB for the guest sync()
-         */
-	hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-        ptnetmap_host_write_kring_csb(pthg, kring->nr_hwcur, hwtail);
-        if (kring->rtail != hwtail) {
-	    kring->rtail = hwtail;
-            some_recvd = true;
-            dry_cycles = 0;
-        } else {
-            dry_cycles++;
-        }
-
-        IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.rxbs, pre_tail,
-	                               kring->rtail, num_slots));
-
-        if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-            ptnetmap_kring_dump("post rxsync", kring);
-	}
-
-#ifndef BUSY_WAIT
-	/* Interrupt the guest if needed. */
-        if (some_recvd && ptgh_intr_enabled(ptgh)) {
-            /* Disable guest kick to avoid sending unnecessary kicks */
-            nm_os_kctx_send_irq(kth);
-            IFRATE(ptns->rate_ctx.new.hrxk++);
-            some_recvd = false;
-        }
-#endif
-        /* Read CSB to see if there is more work to do. */
-        ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-#ifndef BUSY_WAIT
-        if (ptnetmap_norxslots(kring, shadow_ring.head)) {
-            /*
-             * No more slots available for reception. We enable notification and
-             * go to sleep, waiting for a kick from the guest when new receive
-	     * slots are available.
-             */
-            usleep_range(1,1);
-            /* Reenable notifications. */
-            pthg_kick_enable(pthg, 1);
-            /* Doublecheck. */
-            ptnetmap_host_read_kring_csb(ptgh, &shadow_ring, num_slots);
-            if (!ptnetmap_norxslots(kring, shadow_ring.head)) {
-		/* We won the race condition, more slots are available. Disable
-		 * notifications and do another cycle. */
-                pthg_kick_enable(pthg, 0);
-                continue;
-	    }
-            break;
-        }
-
-	hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-        if (unlikely(hwtail == kring->rhead ||
-		     dry_cycles >= PTN_RX_DRY_CYCLES_MAX)) {
-	    /* No more packets to be read from the backend. We stop and
-	     * wait for a notification from the backend (netmap_rx_irq). */
-            ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
-	       hwtail, kring->rhead, dry_cycles);
-            break;
-        }
-#endif
-        if (unlikely(ptns->stopped)) {
-            D("backend netmap is being stopped");
-            break;
-        }
-    }
-
-    nm_kr_put(kring);
-
-    /* Interrupt the guest if needed. */
-    if (some_recvd && ptgh_intr_enabled(ptgh)) {
-        nm_os_kctx_send_irq(kth);
-        IFRATE(ptns->rate_ctx.new.hrxk++);
-    }
-}
-
-#ifdef NETMAP_PT_DEBUG
-static void
-ptnetmap_print_configuration(struct ptnetmap_cfg *cfg)
-{
-	int k;
-
-	D("ptnetmap configuration:");
-	D("  CSB @%p@:%p, num_rings=%u, cfgtype %08x", cfg->csb_gh,
-	  cfg->csb_hg, cfg->num_rings, cfg->cfgtype);
-	for (k = 0; k < cfg->num_rings; k++) {
-		switch (cfg->cfgtype) {
-		case PTNETMAP_CFGTYPE_QEMU: {
-			struct ptnetmap_cfgentry_qemu *e =
-				(struct ptnetmap_cfgentry_qemu *)(cfg+1) + k;
-			D("    ring #%d: ioeventfd=%lu, irqfd=%lu", k,
-				(unsigned long)e->ioeventfd,
-				(unsigned long)e->irqfd);
-			break;
-		}
-
-		case PTNETMAP_CFGTYPE_BHYVE:
-		{
-			struct ptnetmap_cfgentry_bhyve *e =
-				(struct ptnetmap_cfgentry_bhyve *)(cfg+1) + k;
-			D("    ring #%d: wchan=%lu, ioctl_fd=%lu, "
-			  "ioctl_cmd=%lu, msix_msg_data=%lu, msix_addr=%lu",
-				k, (unsigned long)e->wchan,
-				(unsigned long)e->ioctl_fd,
-				(unsigned long)e->ioctl_cmd,
-				(unsigned long)e->ioctl_data.msg_data,
-				(unsigned long)e->ioctl_data.addr);
-			break;
-		}
-		}
-	}
-
-}
-#endif /* NETMAP_PT_DEBUG */
-
-/* Copy actual state of the host ring into the CSB for the guest init */
-static int
-ptnetmap_kring_snapshot(struct netmap_kring *kring,
-			struct ptnet_csb_gh __user *ptgh,
-			struct ptnet_csb_hg __user *pthg)
-{
-    if (CSB_WRITE(ptgh, head, kring->rhead))
-        goto err;
-    if (CSB_WRITE(ptgh, cur, kring->rcur))
-        goto err;
-
-    if (CSB_WRITE(pthg, hwcur, kring->nr_hwcur))
-        goto err;
-    if (CSB_WRITE(pthg, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail)))
-        goto err;
-
-    DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);)
-
-    return 0;
-err:
-    return EFAULT;
-}
-
-static struct netmap_kring *
-ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
-{
-	if (k < pth_na->up.num_tx_rings) {
-		return pth_na->up.tx_rings[k];
-	}
-	return pth_na->up.rx_rings[k - pth_na->up.num_tx_rings];
-}
-
-static int
-ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	struct netmap_kring *kring;
-	unsigned int num_rings;
-	int err = 0, k;
-
-	num_rings = pth_na->up.num_tx_rings +
-		    pth_na->up.num_rx_rings;
-
-	for (k = 0; k < num_rings; k++) {
-		kring = ptnetmap_kring(pth_na, k);
-		err |= ptnetmap_kring_snapshot(kring, ptns->csb_gh + k,
-						ptns->csb_hg + k);
-	}
-
-	return err;
-}
-
-/*
- * Functions to create kernel contexts, and start/stop the workers.
- */
-
-static int
-ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
-		      struct ptnetmap_cfg *cfg, int use_tx_kthreads)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	struct nm_kctx_cfg nmk_cfg;
-	unsigned int num_rings;
-	uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
-	unsigned int expected_cfgtype = 0;
-	int k;
-
-#if defined(__FreeBSD__)
-	expected_cfgtype = PTNETMAP_CFGTYPE_BHYVE;
-#elif defined(linux)
-	expected_cfgtype = PTNETMAP_CFGTYPE_QEMU;
-#endif
-	if (cfg->cfgtype != expected_cfgtype) {
-		D("Unsupported cfgtype %u", cfg->cfgtype);
-		return EINVAL;
-	}
-
-	num_rings = pth_na->up.num_tx_rings +
-		    pth_na->up.num_rx_rings;
-
-	for (k = 0; k < num_rings; k++) {
-		nmk_cfg.attach_user = 1; /* attach kthread to user process */
-		nmk_cfg.worker_private = ptnetmap_kring(pth_na, k);
-		nmk_cfg.type = k;
-		if (k < pth_na->up.num_tx_rings) {
-			nmk_cfg.worker_fn = ptnetmap_tx_handler;
-			nmk_cfg.use_kthread = use_tx_kthreads;
-			nmk_cfg.notify_fn = ptnetmap_tx_nothread_notify;
-		} else {
-			nmk_cfg.worker_fn = ptnetmap_rx_handler;
-			nmk_cfg.use_kthread = 1;
-		}
-
-		ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
-				cfg_entries + k * cfg->entry_size);
-		if (ptns->kctxs[k] == NULL) {
-			goto err;
-		}
-	}
-
-	return 0;
-err:
-	for (k = 0; k < num_rings; k++) {
-		if (ptns->kctxs[k]) {
-			nm_os_kctx_destroy(ptns->kctxs[k]);
-			ptns->kctxs[k] = NULL;
-		}
-	}
-	return EFAULT;
-}
-
-static int
-ptnetmap_start_kctx_workers(struct netmap_pt_host_adapter *pth_na)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	int num_rings;
-	int error;
-	int k;
-
-	if (!ptns) {
-		D("BUG ptns is NULL");
-		return EFAULT;
-	}
-
-	ptns->stopped = false;
-
-	num_rings = ptns->pth_na->up.num_tx_rings +
-		    ptns->pth_na->up.num_rx_rings;
-	for (k = 0; k < num_rings; k++) {
-		//nm_os_kctx_worker_setaff(ptns->kctxs[k], xxx);
-		error = nm_os_kctx_worker_start(ptns->kctxs[k]);
-		if (error) {
-			return error;
-		}
-	}
-
-	return 0;
-}
-
-static void
-ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
-{
-	struct ptnetmap_state *ptns = pth_na->ptns;
-	int num_rings;
-	int k;
-
-	if (!ptns) {
-		/* Nothing to do. */
-		return;
-	}
-
-	ptns->stopped = true;
-
-	num_rings = ptns->pth_na->up.num_tx_rings +
-		    ptns->pth_na->up.num_rx_rings;
-	for (k = 0; k < num_rings; k++) {
-		nm_os_kctx_worker_stop(ptns->kctxs[k]);
-	}
-}
-
-static int nm_unused_notify(struct netmap_kring *, int);
-static int nm_pt_host_notify(struct netmap_kring *, int);
-
-/* Create ptnetmap state and switch parent adapter to ptnetmap mode. */
-static int
-ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
-		struct ptnetmap_cfg *cfg)
-{
-    int use_tx_kthreads = ptnetmap_tx_workers; /* snapshot */
-    struct ptnetmap_state *ptns;
-    unsigned int num_rings;
-    int ret, i;
-
-    /* Check if ptnetmap state is already there. */
-    if (pth_na->ptns) {
-        D("ERROR adapter %p already in ptnetmap mode", pth_na->parent);
-        return EINVAL;
-    }
-
-    num_rings = pth_na->up.num_tx_rings + pth_na->up.num_rx_rings;
-
-    if (num_rings != cfg->num_rings) {
-        D("ERROR configuration mismatch, expected %u rings, found %u",
-           num_rings, cfg->num_rings);
-        return EINVAL;
-    }
-
-    if (!use_tx_kthreads && na_is_generic(pth_na->parent)) {
-        D("ERROR ptnetmap direct transmission not supported with "
-	  "passed-through emulated adapters");
-        return EOPNOTSUPP;
-    }
-
-    ptns = nm_os_malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kctxs));
-    if (!ptns) {
-        return ENOMEM;
-    }
-
-    ptns->kctxs = (struct nm_kctx **)(ptns + 1);
-    ptns->stopped = true;
-
-    /* Cross-link data structures. */
-    pth_na->ptns = ptns;
-    ptns->pth_na = pth_na;
-
-    /* Store the CSB address provided by the hypervisor. */
-    ptns->csb_gh = cfg->csb_gh;
-    ptns->csb_hg = cfg->csb_hg;
-
-    DBG(ptnetmap_print_configuration(cfg));
-
-    /* Create kernel contexts. */
-    if ((ret = ptnetmap_create_kctxs(pth_na, cfg, use_tx_kthreads))) {
-        D("ERROR ptnetmap_create_kctxs()");
-        goto err;
-    }
-    /* Copy krings state into the CSB for the guest initialization */
-    if ((ret = ptnetmap_krings_snapshot(pth_na))) {
-        D("ERROR ptnetmap_krings_snapshot()");
-        goto err;
-    }
-
-    /* Overwrite parent nm_notify krings callback, and
-     * clear NAF_BDG_MAYSLEEP if needed. */
-    pth_na->parent->na_private = pth_na;
-    pth_na->parent_nm_notify = pth_na->parent->nm_notify;
-    pth_na->parent->nm_notify = nm_unused_notify;
-    pth_na->parent_na_flags = pth_na->parent->na_flags;
-    if (!use_tx_kthreads) {
-        /* VALE port txsync is executed under spinlock on Linux, so
-         * we need to make sure the bridge cannot sleep. */
-        pth_na->parent->na_flags &= ~NAF_BDG_MAYSLEEP;
-    }
-
-    for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i]->save_notify =
-        	pth_na->up.rx_rings[i]->nm_notify;
-        pth_na->up.rx_rings[i]->nm_notify = nm_pt_host_notify;
-    }
-    for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i]->save_notify =
-        	pth_na->up.tx_rings[i]->nm_notify;
-        pth_na->up.tx_rings[i]->nm_notify = nm_pt_host_notify;
-    }
-
-#ifdef RATE
-    memset(&ptns->rate_ctx, 0, sizeof(ptns->rate_ctx));
-    setup_timer(&ptns->rate_ctx.timer, &rate_callback,
-            (unsigned long)&ptns->rate_ctx);
-    if (mod_timer(&ptns->rate_ctx.timer, jiffies + msecs_to_jiffies(1500)))
-        D("[ptn] Error: mod_timer()\n");
-#endif
-
-    DBG(D("[%s] ptnetmap configuration DONE", pth_na->up.name));
-
-    return 0;
-
-err:
-    pth_na->ptns = NULL;
-    nm_os_free(ptns);
-    return ret;
-}
-
-/* Switch parent adapter back to normal mode and destroy
- * ptnetmap state. */
-static void
-ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
-{
-    struct ptnetmap_state *ptns = pth_na->ptns;
-    int num_rings;
-    int i;
-
-    if (!ptns) {
-	/* Nothing to do. */
-        return;
-    }
-
-    /* Restore parent adapter callbacks. */
-    pth_na->parent->nm_notify = pth_na->parent_nm_notify;
-    pth_na->parent->na_private = NULL;
-    pth_na->parent->na_flags = pth_na->parent_na_flags;
-
-    for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
-        pth_na->up.rx_rings[i]->nm_notify =
-        	pth_na->up.rx_rings[i]->save_notify;
-        pth_na->up.rx_rings[i]->save_notify = NULL;
-    }
-    for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
-        pth_na->up.tx_rings[i]->nm_notify =
-        	pth_na->up.tx_rings[i]->save_notify;
-        pth_na->up.tx_rings[i]->save_notify = NULL;
-    }
-
-    /* Destroy kernel contexts. */
-    num_rings = ptns->pth_na->up.num_tx_rings +
-                ptns->pth_na->up.num_rx_rings;
-    for (i = 0; i < num_rings; i++) {
-        nm_os_kctx_destroy(ptns->kctxs[i]);
-	ptns->kctxs[i] = NULL;
-    }
-
-    IFRATE(del_timer(&ptns->rate_ctx.timer));
-
-    nm_os_free(ptns);
-
-    pth_na->ptns = NULL;
-
-    DBG(D("[%s] ptnetmap deleted", pth_na->up.name));
-}
-
-/*
- * Called by netmap_ioctl().
- * Operation is indicated in nr_name.
- *
- * Called without NMG_LOCK.
- */
-int
-ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na)
-{
-	struct netmap_pt_host_adapter *pth_na;
-	struct ptnetmap_cfg *cfg = NULL;
-	int error = 0;
-
-	DBG(D("name: %s", nr_name));
-
-	if (!nm_ptnetmap_host_on(na)) {
-		D("ERROR Netmap adapter %p is not a ptnetmap host adapter",
-			na);
-		return ENXIO;
-	}
-	pth_na = (struct netmap_pt_host_adapter *)na;
-
-	NMG_LOCK();
-	if (create) {
-		/* Read hypervisor configuration from userspace. */
-		/* TODO */
-		if (!cfg) {
-			goto out;
-		}
-		/* Create ptnetmap state (kctxs, ...) and switch parent
-		 * adapter to ptnetmap mode. */
-		error = ptnetmap_create(pth_na, cfg);
-		nm_os_free(cfg);
-		if (error) {
-			goto out;
-		}
-		/* Start kthreads. */
-		error = ptnetmap_start_kctx_workers(pth_na);
-		if (error)
-			ptnetmap_delete(pth_na);
-	} else {
-		/* Stop kthreads. */
-		ptnetmap_stop_kctx_workers(pth_na);
-		/* Switch parent adapter back to normal mode and destroy
-		 * ptnetmap state (kthreads, ...). */
-		ptnetmap_delete(pth_na);
-	}
-out:
-	NMG_UNLOCK();
-
-	return error;
-}
-
-/* nm_notify callbacks for ptnetmap */
-static int
-nm_pt_host_notify(struct netmap_kring *kring, int flags)
-{
-	struct netmap_adapter *na = kring->na;
-	struct netmap_pt_host_adapter *pth_na =
-		(struct netmap_pt_host_adapter *)na->na_private;
-	struct ptnetmap_state *ptns;
-	int k;
-
-	/* First check that the passthrough port is not being destroyed. */
-	if (unlikely(!pth_na)) {
-		return NM_IRQ_COMPLETED;
-	}
-
-	ptns = pth_na->ptns;
-	if (unlikely(!ptns || ptns->stopped)) {
-		return NM_IRQ_COMPLETED;
-	}
-
-	k = kring->ring_id;
-
-	/* Notify kthreads (wake up if needed) */
-	if (kring->tx == NR_TX) {
-		ND(1, "TX backend irq");
-		IFRATE(ptns->rate_ctx.new.btxwu++);
-	} else {
-		k += pth_na->up.num_tx_rings;
-		ND(1, "RX backend irq");
-		IFRATE(ptns->rate_ctx.new.brxwu++);
-	}
-	nm_os_kctx_worker_wakeup(ptns->kctxs[k]);
-
-	return NM_IRQ_COMPLETED;
-}
-
-static int
-nm_unused_notify(struct netmap_kring *kring, int flags)
-{
-    D("BUG this should never be called");
-    return ENXIO;
-}
-
-/* nm_config callback for bwrap */
-static int
-nm_pt_host_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-    int error;
-
-    //XXX: maybe calling parent->nm_config is better
-
-    /* forward the request */
-    error = netmap_update_config(parent);
-
-    info->num_rx_rings = na->num_rx_rings = parent->num_rx_rings;
-    info->num_tx_rings = na->num_tx_rings = parent->num_tx_rings;
-    info->num_tx_descs = na->num_tx_desc = parent->num_tx_desc;
-    info->num_rx_descs = na->num_rx_desc = parent->num_rx_desc;
-    info->rx_buf_maxsize = na->rx_buf_maxsize = parent->rx_buf_maxsize;
-
-    return error;
-}
-
-/* nm_krings_create callback for ptnetmap */
-static int
-nm_pt_host_krings_create(struct netmap_adapter *na)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-    enum txrx t;
-    int error;
-
-    DBG(D("%s", pth_na->up.name));
-
-    /* create the parent krings */
-    error = parent->nm_krings_create(parent);
-    if (error) {
-        return error;
-    }
-
-    /* A ptnetmap host adapter points the very same krings
-     * as its parent adapter. These pointer are used in the
-     * TX/RX worker functions. */
-    na->tx_rings = parent->tx_rings;
-    na->rx_rings = parent->rx_rings;
-    na->tailroom = parent->tailroom;
-
-    for_rx_tx(t) {
-	struct netmap_kring *kring;
-
-	/* Parent's kring_create function will initialize
-	 * its own na->si. We have to init our na->si here. */
-	nm_os_selinfo_init(&na->si[t]);
-
-	/* Force the mem_rings_create() method to create the
-	 * host rings independently on what the regif asked for:
-	 * these rings are needed by the guest ptnetmap adapter
-	 * anyway. */
-	kring = NMR(na, t)[nma_get_nrings(na, t)];
-	kring->nr_kflags |= NKR_NEEDRING;
-    }
-
-    return 0;
-}
-
-/* nm_krings_delete callback for ptnetmap */
-static void
-nm_pt_host_krings_delete(struct netmap_adapter *na)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-
-    DBG(D("%s", pth_na->up.name));
-
-    parent->nm_krings_delete(parent);
-
-    na->tx_rings = na->rx_rings = na->tailroom = NULL;
-}
-
-/* nm_register callback */
-static int
-nm_pt_host_register(struct netmap_adapter *na, int onoff)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-    int error;
-    DBG(D("%s onoff %d", pth_na->up.name, onoff));
-
-    if (onoff) {
-        /* netmap_do_regif has been called on the ptnetmap na.
-         * We need to pass the information about the
-         * memory allocator to the parent before
-         * putting it in netmap mode
-         */
-        parent->na_lut = na->na_lut;
-    }
-
-    /* forward the request to the parent */
-    error = parent->nm_register(parent, onoff);
-    if (error)
-        return error;
-
-
-    if (onoff) {
-        na->na_flags |= NAF_NETMAP_ON | NAF_PTNETMAP_HOST;
-    } else {
-        ptnetmap_delete(pth_na);
-        na->na_flags &= ~(NAF_NETMAP_ON | NAF_PTNETMAP_HOST);
-    }
-
-    return 0;
-}
-
-/* nm_dtor callback */
-static void
-nm_pt_host_dtor(struct netmap_adapter *na)
-{
-    struct netmap_pt_host_adapter *pth_na =
-        (struct netmap_pt_host_adapter *)na;
-    struct netmap_adapter *parent = pth_na->parent;
-
-    DBG(D("%s", pth_na->up.name));
-
-    /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor
-     * didn't do it. */
-    ptnetmap_stop_kctx_workers(pth_na);
-    ptnetmap_delete(pth_na);
-
-    parent->na_flags &= ~NAF_BUSY;
-
-    netmap_adapter_put(pth_na->parent);
-    pth_na->parent = NULL;
-}
-
-/* check if nmr is a request for a ptnetmap adapter that we can satisfy */
-int
-netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct netmap_mem_d *nmd, int create)
-{
-    struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
-    struct nmreq_register preq;
-    struct netmap_adapter *parent; /* target adapter */
-    struct netmap_pt_host_adapter *pth_na;
-    struct ifnet *ifp = NULL;
-    int error;
-
-    /* Check if it is a request for a ptnetmap adapter */
-    if ((req->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
-        return 0;
-    }
-
-    D("Requesting a ptnetmap host adapter");
-
-    pth_na = nm_os_malloc(sizeof(*pth_na));
-    if (pth_na == NULL) {
-        D("ERROR malloc");
-        return ENOMEM;
-    }
-
-    /* first, try to find the adapter that we want to passthrough
-     * We use the same req, after we have turned off the ptnetmap flag.
-     * In this way we can potentially passthrough everything netmap understands.
-     */
-    memcpy(&preq, req, sizeof(preq));
-    preq.nr_flags &= ~(NR_PTNETMAP_HOST);
-    hdr->nr_body = (uintptr_t)&preq;
-    error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
-    hdr->nr_body = (uintptr_t)req;
-    if (error) {
-        D("parent lookup failed: %d", error);
-        goto put_out_noputparent;
-    }
-    DBG(D("found parent: %s", parent->name));
-
-    /* make sure the interface is not already in use */
-    if (NETMAP_OWNED_BY_ANY(parent)) {
-        D("NIC %s busy, cannot ptnetmap", parent->name);
-        error = EBUSY;
-        goto put_out;
-    }
-
-    pth_na->parent = parent;
-
-    /* Follow netmap_attach()-like operations for the host
-     * ptnetmap adapter. */
-
-    //XXX pth_na->up.na_flags = parent->na_flags;
-    pth_na->up.num_rx_rings = parent->num_rx_rings;
-    pth_na->up.num_tx_rings = parent->num_tx_rings;
-    pth_na->up.num_tx_desc = parent->num_tx_desc;
-    pth_na->up.num_rx_desc = parent->num_rx_desc;
-
-    pth_na->up.nm_dtor = nm_pt_host_dtor;
-    pth_na->up.nm_register = nm_pt_host_register;
-
-    /* Reuse parent's adapter txsync and rxsync methods. */
-    pth_na->up.nm_txsync = parent->nm_txsync;
-    pth_na->up.nm_rxsync = parent->nm_rxsync;
-
-    pth_na->up.nm_krings_create = nm_pt_host_krings_create;
-    pth_na->up.nm_krings_delete = nm_pt_host_krings_delete;
-    pth_na->up.nm_config = nm_pt_host_config;
-
-    /* Set the notify method only or convenience, it will never
-     * be used, since - differently from default krings_create - we
-     * ptnetmap krings_create callback inits kring->nm_notify
-     * directly. */
-    pth_na->up.nm_notify = nm_unused_notify;
-
-    pth_na->up.nm_mem = netmap_mem_get(parent->nm_mem);
-
-    pth_na->up.na_flags |= NAF_HOST_RINGS;
-
-    error = netmap_attach_common(&pth_na->up);
-    if (error) {
-        D("ERROR netmap_attach_common()");
-        goto put_out;
-    }
-
-    *na = &pth_na->up;
-    /* set parent busy, because attached for ptnetmap */
-    parent->na_flags |= NAF_BUSY;
-    strlcpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name));
-    strcat(pth_na->up.name, "-PTN");
-    netmap_adapter_get(*na);
-
-    DBG(D("%s ptnetmap request DONE", pth_na->up.name));
-
-    /* drop the reference to the ifp, if any */
-    if (ifp)
-        if_rele(ifp);
-
-    return 0;
-
-put_out:
-    netmap_adapter_put(parent);
-    if (ifp)
-	if_rele(ifp);
-put_out_noputparent:
-    nm_os_free(pth_na);
-    return error;
-}
-#endif /* WITH_PTNETMAP_HOST */
-
 #ifdef WITH_PTNETMAP_GUEST
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 44d31a3c9..3da365502 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -560,9 +560,7 @@ struct nmreq_register {
 #define NR_ZCOPY_MON	0x400
 /* request exclusive access to the selected rings */
 #define NR_EXCLUSIVE	0x800
-/* request ptnetmap host support */
-#define NR_PASSTHROUGH_HOST	NR_PTNETMAP_HOST /* deprecated */
-#define NR_PTNETMAP_HOST	0x1000
+/* 0x1000 unused */
 #define NR_RX_RINGS_ONLY	0x2000
 #define NR_TX_RINGS_ONLY	0x4000
 /* Applications set this flag if they are able to deal with virtio-net headers,
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 1b8b26cc9..cef32eed6 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -229,64 +229,4 @@ ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kr
 
 #endif /* WITH_PTNETMAP_GUEST */
 
-#ifdef WITH_PTNETMAP_HOST
-/*
- * ptnetmap kernel thread routines
- * */
-
-/* Functions to read and write CSB fields in the host */
-#if defined (linux)
-#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
-#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
-#else  /* ! linux */
-#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
-#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
-#endif /* ! linux */
-
-/* Host netmap: Write kring pointers (hwcur, hwtail) to the CSB.
- * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
-static inline void
-ptnetmap_host_write_kring_csb(struct ptnet_csb_hg __user *ptr, uint32_t hwcur,
-        uint32_t hwtail)
-{
-    /*
-     * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
-     * We allow the guest to read a value of hwcur more recent than the value
-     * of hwtail, since this would anyway result in a consistent view of the
-     * ring state (and hwcur can never wraparound hwtail, since hwcur must be
-     * behind head).
-     *
-     * The following memory barrier scheme is used to make this happen:
-     *
-     *          Guest                Host
-     *
-     *          STORE(hwcur)         LOAD(hwtail)
-     *          mb() <-------------> mb()
-     *          STORE(hwtail)        LOAD(hwcur)
-     */
-    CSB_WRITE(ptr, hwcur, hwcur);
-    mb();
-    CSB_WRITE(ptr, hwtail, hwtail);
-}
-
-/* Host netmap: Read kring pointers (head, cur, sync_flags) from the CSB.
- * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
-static inline void
-ptnetmap_host_read_kring_csb(struct ptnet_csb_gh __user *ptr,
-			     struct netmap_ring *shadow_ring,
-			     uint32_t num_slots)
-{
-    /*
-     * We place a memory barrier to make sure that the update of head never
-     * overtakes the update of cur.
-     * (see explanation in ptnetmap_guest_write_kring_csb).
-     */
-    CSB_READ(ptr, head, shadow_ring->head);
-    mb();
-    CSB_READ(ptr, cur, shadow_ring->cur);
-    CSB_READ(ptr, sync_flags, shadow_ring->flags);
-}
-
-#endif /* WITH_PTNETMAP_HOST */
-
 #endif /* NETMAP_VIRT_H */
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 9979270cf..f0bb6c311 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1160,9 +1160,6 @@ do_nmr_legacy_dump()
 	if (curr_nmr.nr_flags & NR_EXCLUSIVE) {
 		printf(", EXCLUSIVE");
 	}
-	if (curr_nmr.nr_flags & NR_PTNETMAP_HOST) {
-		printf(", PTNETMAP_HOST");
-	}
 	printf("]\n");
 	printf("spare2[0]: %x\n", curr_nmr.spare2[0]);
 }
@@ -1279,8 +1276,6 @@ do_nmr_legacy_flags()
 			flags |= NR_ZCOPY_MON;
 		} else if (strcmp(arg, "exclusive") == 0) {
 			flags |= NR_EXCLUSIVE;
-		} else if (strcmp(arg, "ptnetmap-host") == 0) {
-			flags |= NR_PTNETMAP_HOST;
 		} else if (strcmp(arg, "default") == 0) {
 			flags = 0;
 		}
@@ -1426,7 +1421,6 @@ nmr_body_dump_register(void *b)
 	pflag(MONITOR_RX);
 	pflag(ZCOPY_MON);
 	pflag(EXCLUSIVE);
-	pflag(PTNETMAP_HOST);
 	pflag(RX_RINGS_ONLY);
 	pflag(TX_RINGS_ONLY);
 	pflag(ACCEPT_VNET_HDR);
@@ -1492,8 +1486,6 @@ do_register_flags()
 			flags |= NR_ZCOPY_MON;
 		} else if (strcmp(arg, "exclusive") == 0) {
 			flags |= NR_EXCLUSIVE;
-		} else if (strcmp(arg, "ptnetmap-host") == 0) {
-			flags |= NR_PTNETMAP_HOST;
 		} else if (strcmp(arg, "rx-rings-only") == 0) {
 			flags |= NR_RX_RINGS_ONLY;
 		} else if (strcmp(arg, "tx-rings-only") == 0) {

From 53b7d4166d51d97e67167d03de38f0ca7a0c4611 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 10:01:28 +0200
Subject: [PATCH 1298/2207] sync-kloop: move code to netmap_pt.c

---
 sys/dev/netmap/netmap.c    | 653 -------------------------------------
 sys/dev/netmap/netmap_pt.c | 653 +++++++++++++++++++++++++++++++++++++
 2 files changed, 653 insertions(+), 653 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5398dddfa..6dc30e389 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3897,659 +3897,6 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
-/* Functions to read and write CSB fields from the kernel. */
-#if defined (linux)
-#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
-#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
-#else  /* ! linux */
-#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
-#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
-#endif /* ! linux */
-
-/* Write kring pointers (hwcur, hwtail) to the CSB.
- * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
-static inline void
-sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
-			   uint32_t hwtail)
-{
-	/*
-	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
-	 * We allow the application to read a value of hwcur more recent than the value
-	 * of hwtail, since this would anyway result in a consistent view of the
-	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
-	 * behind head).
-	 *
-	 * The following memory barrier scheme is used to make this happen:
-	 *
-	 *          Application          Kernel
-	 *
-	 *          STORE(hwcur)         LOAD(hwtail)
-	 *          mb() <-------------> mb()
-	 *          STORE(hwtail)        LOAD(hwcur)
-	 */
-	CSB_WRITE(ptr, hwcur, hwcur);
-	mb();
-	CSB_WRITE(ptr, hwtail, hwtail);
-}
-
-/* Read kring pointers (head, cur, sync_flags) from the CSB.
- * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
-static inline void
-sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
-			  struct netmap_ring *shadow_ring,
-			  uint32_t num_slots)
-{
-	/*
-	 * We place a memory barrier to make sure that the update of head never
-	 * overtakes the update of cur.
-	 * (see explanation in ptnetmap_guest_write_kring_csb).
-	 */
-	CSB_READ(ptr, head, shadow_ring->head);
-	mb();
-	CSB_READ(ptr, cur, shadow_ring->cur);
-	CSB_READ(ptr, sync_flags, shadow_ring->flags);
-}
-
-/* Enable or disable application --> kernel kicks. */
-static inline void
-csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
-{
-	CSB_WRITE(csb_ktoa, kern_need_kick, val);
-}
-
-/* Are application interrupt enabled or disabled? */
-static inline uint32_t
-csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
-{
-	uint32_t v;
-
-	CSB_READ(csb_atok, appl_need_kick, v);
-
-	return v;
-}
-
-static inline void
-sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
-{
-	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
-		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
-		kring->rhead, kring->rcur, kring->rtail);
-}
-
-#define SYNC_KLOOP_POLL
-struct sync_kloop_ring_args {
-	struct netmap_kring *kring;
-	struct nm_csb_atok *csb_atok;
-	struct nm_csb_ktoa *csb_ktoa;
-#ifdef SYNC_KLOOP_POLL
-	struct eventfd_ctx *irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-};
-
-static void
-netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
-{
-	struct netmap_kring *kring = a->kring;
-	struct nm_csb_atok *csb_atok = a->csb_atok;
-	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
-	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-	bool more_txspace = false;
-	uint32_t num_slots;
-	int batch;
-
-	num_slots = kring->nkr_num_slots;
-
-	/* Disable application --> kernel notifications. */
-	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the application kring pointers from the CSB */
-	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-
-	for (;;) {
-		batch = shadow_ring.head - kring->nr_hwcur;
-		if (batch < 0)
-			batch += num_slots;
-
-#ifdef PTN_TX_BATCH_LIM
-		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
-			/* If application moves ahead too fast, let's cut the move so
-			 * that we don't exceed our batch limit. */
-			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
-
-			if (head_lim >= num_slots)
-				head_lim -= num_slots;
-			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
-					head_lim);
-			shadow_ring.head = head_lim;
-			batch = PTN_TX_BATCH_LIM(num_slots);
-		}
-#endif /* PTN_TX_BATCH_LIM */
-
-		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
-			shadow_ring.flags |= NAF_FORCE_RECLAIM;
-		}
-
-		/* Netmap prologue */
-		shadow_ring.tail = kring->rtail;
-		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
-			/* Reinit ring and enable notifications. */
-			netmap_ring_reinit(kring);
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			break;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-			sync_kloop_kring_dump("pre txsync", kring);
-		}
-
-		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			D("ERROR txsync()");
-			break;
-		}
-
-		/*
-		 * Finalize
-		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
-		 * do the nm_sync_finalize.
-		 */
-		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
-				kring->nr_hwtail);
-		if (kring->rtail != kring->nr_hwtail) {
-			/* Some more room available in the parent adapter. */
-			kring->rtail = kring->nr_hwtail;
-			more_txspace = true;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
-			sync_kloop_kring_dump("post txsync", kring);
-		}
-
-		/* Interrupt the application if needed. */
-#ifdef SYNC_KLOOP_POLL
-		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable application kick to avoid sending unnecessary kicks */
-			eventfd_signal(a->irq_ctx, 1);
-			more_txspace = false;
-		}
-#endif /* SYNC_KLOOP_POLL */
-
-		/* Read CSB to see if there is more work to do. */
-		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-		if (shadow_ring.head == kring->rhead) {
-			/*
-			 * No more packets to transmit. We enable notifications and
-			 * go to sleep, waiting for a kick from the application when new
-			 * new slots are ready for transmission.
-			 */
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			/* Doublecheck. */
-			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-			if (shadow_ring.head != kring->rhead) {
-				/* We won the race condition, there are more packets to
-				 * transmit. Disable notifications and do another cycle */
-				csb_ktoa_kick_enable(csb_ktoa, 0);
-				continue;
-			}
-			break;
-		}
-
-		if (nm_kr_txempty(kring)) {
-			/* No more available TX slots. We stop waiting for a notification
-			 * from the backend (netmap_tx_irq). */
-			ND(1, "TX ring");
-			break;
-		}
-	}
-
-#ifdef SYNC_KLOOP_POLL
-	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
-		eventfd_signal(a->irq_ctx, 1);
-	}
-#endif /* SYNC_KLOOP_POLL */
-}
-
-/* RX cycle without receive any packets */
-#define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
-
-static inline int
-sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
-{
-	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
-				kring->nkr_num_slots - 1));
-}
-
-static void
-netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
-{
-
-	struct netmap_kring *kring = a->kring;
-	struct nm_csb_atok *csb_atok = a->csb_atok;
-	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
-	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
-	int dry_cycles = 0;
-	bool some_recvd = false;
-	uint32_t num_slots;
-
-	num_slots = kring->nkr_num_slots;
-
-	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
-	num_slots = kring->nkr_num_slots;
-
-	/* Disable notifications. */
-	csb_ktoa_kick_enable(csb_ktoa, 0);
-	/* Copy the application kring pointers from the CSB */
-	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-
-	for (;;) {
-		uint32_t hwtail;
-
-		/* Netmap prologue */
-		shadow_ring.tail = kring->rtail;
-		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
-			/* Reinit ring and enable notifications. */
-			netmap_ring_reinit(kring);
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			break;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-			sync_kloop_kring_dump("pre rxsync", kring);
-		}
-
-		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			D("ERROR rxsync()");
-			break;
-		}
-
-		/*
-		 * Finalize
-		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
-		 */
-		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
-		if (kring->rtail != hwtail) {
-			kring->rtail = hwtail;
-			some_recvd = true;
-			dry_cycles = 0;
-		} else {
-			dry_cycles++;
-		}
-
-		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
-			sync_kloop_kring_dump("post rxsync", kring);
-		}
-
-#ifdef SYNC_KLOOP_POLL
-		/* Interrupt the application if needed. */
-		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable application kick to avoid sending unnecessary kicks */
-			eventfd_signal(a->irq_ctx, 1);
-			some_recvd = false;
-		}
-#endif /* SYNC_KLOOP_POLL */
-
-		/* Read CSB to see if there is more work to do. */
-		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
-			/*
-			 * No more slots available for reception. We enable notification and
-			 * go to sleep, waiting for a kick from the application when new receive
-			 * slots are available.
-			 */
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
-			/* Doublecheck. */
-			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
-			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
-				/* We won the race condition, more slots are available. Disable
-				 * notifications and do another cycle. */
-				csb_ktoa_kick_enable(csb_ktoa, 0);
-				continue;
-			}
-			break;
-		}
-
-		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
-		if (unlikely(hwtail == kring->rhead ||
-					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
-			/* No more packets to be read from the backend. We stop and
-			 * wait for a notification from the backend (netmap_rx_irq). */
-			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
-					hwtail, kring->rhead, dry_cycles);
-			break;
-		}
-	}
-
-	nm_kr_put(kring);
-
-#ifdef SYNC_KLOOP_POLL
-	/* Interrupt the application if needed. */
-	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
-		eventfd_signal(a->irq_ctx, 1);
-	}
-#endif /* SYNC_KLOOP_POLL */
-}
-
-#ifdef SYNC_KLOOP_POLL
-#include 
-struct sync_kloop_poll_entry {
-	/* Support for receiving notifications from
-	 * a netmap ring or from the application. */
-	struct file *filp;
-	wait_queue_entry_t wait;
-	wait_queue_head_t *wqh;
-
-	/* Support for sending notifications to the application. */
-	struct eventfd_ctx *irq_ctx;
-	struct file *irq_filp;
-};
-
-struct sync_kloop_poll_ctx {
-	poll_table wait_table;
-	unsigned int next_entry;
-	unsigned int num_entries;
-	struct sync_kloop_poll_entry entries[0];
-};
-
-static void
-sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
-				poll_table *pt)
-{
-	struct sync_kloop_poll_ctx *poll_ctx =
-		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
-	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
-						poll_ctx->next_entry;
-
-	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
-	entry->wqh = wqh;
-	entry->filp = file;
-	/* Use the default wake up function. */
-	init_waitqueue_entry(&entry->wait, current);
-	add_wait_queue(wqh, &entry->wait);
-	poll_ctx->next_entry++;
-	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
-}
-#endif  /* SYNC_KLOOP_POLL */
-
-int
-netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
-{
-	struct nmreq_sync_kloop_start *req =
-		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
-	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
-#ifdef SYNC_KLOOP_POLL
-	struct sync_kloop_poll_ctx *poll_ctx = NULL;
-#endif  /* SYNC_KLOOP_POLL */
-	int num_rx_rings, num_tx_rings, num_rings;
-	uint32_t sleep_us = req->sleep_us;
-	struct nm_csb_atok* csb_atok_base;
-	struct nm_csb_ktoa* csb_ktoa_base;
-	struct netmap_adapter *na;
-	struct nmreq_option *opt;
-	int err = 0;
-	int i;
-
-	if (sleep_us > 1000000) {
-		/* We do not accept sleeping for more than a second. */
-		return EINVAL;
-	}
-
-	if (priv->np_nifp == NULL) {
-		return ENXIO;
-	}
-	mb(); /* make sure following reads are not from cache */
-
-	na = priv->np_na;
-	if (!nm_netmap_on(na)) {
-		return ENXIO;
-	}
-
-	if (!(priv->np_flags & NR_EXCLUSIVE)) {
-		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
-		return EINVAL;
-	}
-
-	/* Make sure that no kloop is currently running. */
-	NMG_LOCK();
-	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
-		err = EBUSY;
-	}
-	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
-	NMG_UNLOCK();
-	if (err) {
-		return err;
-	}
-
-	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
-	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
-	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
-	num_rings = num_tx_rings + num_rx_rings;
-
-	/* Validate the CSB entries for both directions (atok and ktoa). */
-	{
-		if (num_rings > 0) {
-			size_t entry_size[2];
-			void *csb_start[2];
-
-			entry_size[0] = sizeof(*csb_atok_base);
-			entry_size[1] = sizeof(*csb_ktoa_base);
-			csb_start[0] = (void *)csb_atok_base;
-			csb_start[1] = (void *)csb_ktoa_base;
-
-			for (i = 0; i < 2; i++) {
-				/* On Linux we could use access_ok() to simplify
-				 * the validation. However, the advantage of
-				 * this approach is that it works also on
-				 * FreeBSD. */
-				size_t csb_size = num_rings * entry_size[i];
-				void *tmp;
-
-				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
-					nm_prerr("Unaligned CSB address\n");
-					err = EINVAL;
-					goto out;
-				}
-
-				tmp = nm_os_malloc(csb_size);
-				if (!tmp) {
-					err = ENOMEM;
-					goto out;
-				}
-				if (i == 0) {
-					/* Application --> kernel direction. */
-					err = copyin(csb_start[i], tmp, csb_size);
-				} else {
-					/* Kernel --> application direction. */
-					memset(tmp, 0, csb_size);
-					err = copyout(tmp, csb_start[i], csb_size);
-				}
-				nm_os_free(tmp);
-				if (err) {
-					nm_prerr("Invalid CSB address\n");
-					goto out;
-				}
-			}
-		}
-	}
-
-	/* Validate notification options. */
-	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
-	if (opt != NULL) {
-		NM_SELINFO_T *si[NR_TXRX];
-
-		err = nmreq_checkduplicate(opt);
-		if (err) {
-			opt->nro_status = err;
-			goto out;
-		}
-		if (opt->nro_size != sizeof(*eventfds_opt) +
-			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
-			/* Option size not consistent with the number of
-			 * entries. */
-			opt->nro_status = err = EINVAL;
-			goto out;
-		}
-#ifdef SYNC_KLOOP_POLL
-		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
-		opt->nro_status = 0;
-		/* We need 2 poll entries for TX and RX notifications coming
-		 * from the netmap adapter, plus one entries per ring for the
-		 * notifications coming from the application. */
-		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
-				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
-		init_poll_funcptr(&poll_ctx->wait_table,
-					sync_kloop_poll_table_queue_proc);
-		poll_ctx->num_entries = 2 + num_rings;
-		poll_ctx->next_entry = 0;
-		/* Poll for notifications coming from the applications through
-		 * eventfds . */
-		for (i = 0; i < num_rings; i++) {
-			struct eventfd_ctx *irq;
-			struct file *filp;
-			unsigned long mask;
-
-			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
-			if (IS_ERR(filp)) {
-				err = PTR_ERR(filp);
-				goto out;
-			}
-			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
-			if (mask & POLLERR) {
-				err = EINVAL;
-				goto out;
-			}
-
-			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
-			if (IS_ERR(filp)) {
-				err = PTR_ERR(filp);
-				goto out;
-			}
-			poll_ctx->entries[i].irq_filp = filp;
-			irq = eventfd_ctx_fileget(filp);
-			if (IS_ERR(irq)) {
-				err = PTR_ERR(irq);
-				goto out;
-			}
-			poll_ctx->entries[i].irq_ctx = irq;
-		}
-		/* Poll for notifications coming from the netmap rings bound to
-		 * this file descriptor. */
-		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
-		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
-		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
-#else   /* SYNC_KLOOP_POLL */
-		opt->nro_status = EOPNOTSUPP;
-		goto out;
-#endif  /* SYNC_KLOOP_POLL */
-	}
-
-	/* Main loop. */
-	for (;;) {
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
-			__set_current_state(TASK_INTERRUPTIBLE);
-#endif  /* SYNC_KLOOP_POLL */
-
-		/* Process all the TX rings bound to this file descriptor. */
-		for (i = 0; i < num_tx_rings; i++) {
-			struct sync_kloop_ring_args a = {
-				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
-				.csb_atok = csb_atok_base + i,
-				.csb_ktoa = csb_ktoa_base + i,
-			};
-
-#ifdef SYNC_KLOOP_POLL
-			if (poll_ctx)
-				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
-				continue;
-			}
-			netmap_sync_kloop_tx_ring(&a);
-			nm_kr_put(a.kring);
-		}
-
-		/* Process all the RX rings bound to this file descriptor. */
-		for (i = 0; i < num_rx_rings; i++) {
-			struct sync_kloop_ring_args a = {
-				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
-				.csb_atok = csb_atok_base + num_tx_rings + i,
-				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
-			};
-
-#ifdef SYNC_KLOOP_POLL
-			if (poll_ctx)
-				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-
-			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
-				continue;
-			}
-			netmap_sync_kloop_rx_ring(&a);
-			nm_kr_put(a.kring);
-		}
-
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx) {
-			/* If a poll context is present, yield to the scheduler
-			 * waiting for a notification to come either from
-			 * netmap or the application. */
-			schedule_timeout_interruptible(msecs_to_jiffies(1000));
-		} else
-#endif /* SYNC_KLOOP_POLL */
-		{
-			/* Default synchronization method: sleep for a while. */
-			usleep_range(sleep_us, sleep_us);
-		}
-
-		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
-			break;
-		}
-	}
-out:
-#ifdef SYNC_KLOOP_POLL
-	if (poll_ctx) {
-		/* Stop polling from netmap and the eventfds, and deallocate
-		 * the poll context. */
-		__set_current_state(TASK_RUNNING);
-		for (i = 0; i < poll_ctx->next_entry; i++) {
-			struct sync_kloop_poll_entry *entry =
-						poll_ctx->entries + i;
-
-			if (entry->wqh)
-				remove_wait_queue(entry->wqh, &entry->wait);
-			/* We did not get a reference to the eventfds, but
-			 * don't do that on netmap file descriptors (since
-			 * a reference was not taken. */
-			if (entry->filp && entry->filp != priv->np_filp)
-				fput(entry->filp);
-			if (entry->irq_ctx)
-				eventfd_ctx_put(entry->irq_ctx);
-			if (entry->irq_filp)
-				fput(entry->irq_filp);
-		}
-		nm_os_free(poll_ctx);
-		poll_ctx = NULL;
-	}
-#endif /* SYNC_KLOOP_POLL */
-
-	/* Reset the kloop state. */
-	NMG_LOCK();
-	priv->np_kloop_state = 0;
-	NMG_UNLOCK();
-
-	return err;
-}
-
 /*
  * Module loader and unloader
  *
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 3f4aa9a28..4d5120238 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -43,6 +43,7 @@
 
 #elif defined(linux)
 #include 
+#include 
 #endif
 
 #include 
@@ -50,6 +51,658 @@
 #include 
 #include 
 
+/* Functions to read and write CSB fields from the kernel. */
+#if defined (linux)
+#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
+#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
+#else  /* ! linux */
+#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
+#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
+#endif /* ! linux */
+
+/* Write kring pointers (hwcur, hwtail) to the CSB.
+ * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
+static inline void
+sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
+			   uint32_t hwtail)
+{
+	/*
+	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
+	 * We allow the application to read a value of hwcur more recent than the value
+	 * of hwtail, since this would anyway result in a consistent view of the
+	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
+	 * behind head).
+	 *
+	 * The following memory barrier scheme is used to make this happen:
+	 *
+	 *          Application          Kernel
+	 *
+	 *          STORE(hwcur)         LOAD(hwtail)
+	 *          mb() <-------------> mb()
+	 *          STORE(hwtail)        LOAD(hwcur)
+	 */
+	CSB_WRITE(ptr, hwcur, hwcur);
+	mb();
+	CSB_WRITE(ptr, hwtail, hwtail);
+}
+
+/* Read kring pointers (head, cur, sync_flags) from the CSB.
+ * This routine is coupled with ptnetmap_guest_write_kring_csb(). */
+static inline void
+sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
+			  struct netmap_ring *shadow_ring,
+			  uint32_t num_slots)
+{
+	/*
+	 * We place a memory barrier to make sure that the update of head never
+	 * overtakes the update of cur.
+	 * (see explanation in ptnetmap_guest_write_kring_csb).
+	 */
+	CSB_READ(ptr, head, shadow_ring->head);
+	mb();
+	CSB_READ(ptr, cur, shadow_ring->cur);
+	CSB_READ(ptr, sync_flags, shadow_ring->flags);
+}
+
+/* Enable or disable application --> kernel kicks. */
+static inline void
+csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
+{
+	CSB_WRITE(csb_ktoa, kern_need_kick, val);
+}
+
+/* Are application interrupt enabled or disabled? */
+static inline uint32_t
+csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
+{
+	uint32_t v;
+
+	CSB_READ(csb_atok, appl_need_kick, v);
+
+	return v;
+}
+
+static inline void
+sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
+{
+	D("%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d rtail: %d",
+		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
+		kring->rhead, kring->rcur, kring->rtail);
+}
+
+#define SYNC_KLOOP_POLL
+struct sync_kloop_ring_args {
+	struct netmap_kring *kring;
+	struct nm_csb_atok *csb_atok;
+	struct nm_csb_ktoa *csb_ktoa;
+#ifdef SYNC_KLOOP_POLL
+	struct eventfd_ctx *irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+};
+
+static void
+netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
+{
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	bool more_txspace = false;
+	uint32_t num_slots;
+	int batch;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable application --> kernel notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the application kring pointers from the CSB */
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		batch = shadow_ring.head - kring->nr_hwcur;
+		if (batch < 0)
+			batch += num_slots;
+
+#ifdef PTN_TX_BATCH_LIM
+		if (batch > PTN_TX_BATCH_LIM(num_slots)) {
+			/* If application moves ahead too fast, let's cut the move so
+			 * that we don't exceed our batch limit. */
+			uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots);
+
+			if (head_lim >= num_slots)
+				head_lim -= num_slots;
+			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
+					head_lim);
+			shadow_ring.head = head_lim;
+			batch = PTN_TX_BATCH_LIM(num_slots);
+		}
+#endif /* PTN_TX_BATCH_LIM */
+
+		if (nm_kr_txspace(kring) <= (num_slots >> 1)) {
+			shadow_ring.flags |= NAF_FORCE_RECLAIM;
+		}
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("pre txsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR txsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync(), and
+		 * do the nm_sync_finalize.
+		 */
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur,
+				kring->nr_hwtail);
+		if (kring->rtail != kring->nr_hwtail) {
+			/* Some more room available in the parent adapter. */
+			kring->rtail = kring->nr_hwtail;
+			more_txspace = true;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+			sync_kloop_kring_dump("post txsync", kring);
+		}
+
+		/* Interrupt the application if needed. */
+#ifdef SYNC_KLOOP_POLL
+		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable application kick to avoid sending unnecessary kicks */
+			eventfd_signal(a->irq_ctx, 1);
+			more_txspace = false;
+		}
+#endif /* SYNC_KLOOP_POLL */
+
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+		if (shadow_ring.head == kring->rhead) {
+			/*
+			 * No more packets to transmit. We enable notifications and
+			 * go to sleep, waiting for a kick from the application when new
+			 * new slots are ready for transmission.
+			 */
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+			if (shadow_ring.head != kring->rhead) {
+				/* We won the race condition, there are more packets to
+				 * transmit. Disable notifications and do another cycle */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		if (nm_kr_txempty(kring)) {
+			/* No more available TX slots. We stop waiting for a notification
+			 * from the backend (netmap_tx_irq). */
+			ND(1, "TX ring");
+			break;
+		}
+	}
+
+#ifdef SYNC_KLOOP_POLL
+	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
+	}
+#endif /* SYNC_KLOOP_POLL */
+}
+
+/* RX cycle without receive any packets */
+#define SYNC_LOOP_RX_DRY_CYCLES_MAX	2
+
+static inline int
+sync_kloop_norxslots(struct netmap_kring *kring, uint32_t g_head)
+{
+	return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head,
+				kring->nkr_num_slots - 1));
+}
+
+static void
+netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
+{
+
+	struct netmap_kring *kring = a->kring;
+	struct nm_csb_atok *csb_atok = a->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
+	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+	int dry_cycles = 0;
+	bool some_recvd = false;
+	uint32_t num_slots;
+
+	num_slots = kring->nkr_num_slots;
+
+	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
+	num_slots = kring->nkr_num_slots;
+
+	/* Disable notifications. */
+	csb_ktoa_kick_enable(csb_ktoa, 0);
+	/* Copy the application kring pointers from the CSB */
+	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+
+	for (;;) {
+		uint32_t hwtail;
+
+		/* Netmap prologue */
+		shadow_ring.tail = kring->rtail;
+		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
+			/* Reinit ring and enable notifications. */
+			netmap_ring_reinit(kring);
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			break;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("pre rxsync", kring);
+		}
+
+		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			D("ERROR rxsync()");
+			break;
+		}
+
+		/*
+		 * Finalize
+		 * Copy kernel hwcur and hwtail into the CSB for the application sync()
+		 */
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
+		if (kring->rtail != hwtail) {
+			kring->rtail = hwtail;
+			some_recvd = true;
+			dry_cycles = 0;
+		} else {
+			dry_cycles++;
+		}
+
+		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+			sync_kloop_kring_dump("post rxsync", kring);
+		}
+
+#ifdef SYNC_KLOOP_POLL
+		/* Interrupt the application if needed. */
+		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
+			/* Disable application kick to avoid sending unnecessary kicks */
+			eventfd_signal(a->irq_ctx, 1);
+			some_recvd = false;
+		}
+#endif /* SYNC_KLOOP_POLL */
+
+		/* Read CSB to see if there is more work to do. */
+		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
+			/*
+			 * No more slots available for reception. We enable notification and
+			 * go to sleep, waiting for a kick from the application when new receive
+			 * slots are available.
+			 */
+			/* Reenable notifications. */
+			csb_ktoa_kick_enable(csb_ktoa, 1);
+			/* Doublecheck. */
+			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
+			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
+				/* We won the race condition, more slots are available. Disable
+				 * notifications and do another cycle. */
+				csb_ktoa_kick_enable(csb_ktoa, 0);
+				continue;
+			}
+			break;
+		}
+
+		hwtail = NM_ACCESS_ONCE(kring->nr_hwtail);
+		if (unlikely(hwtail == kring->rhead ||
+					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
+			/* No more packets to be read from the backend. We stop and
+			 * wait for a notification from the backend (netmap_rx_irq). */
+			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
+					hwtail, kring->rhead, dry_cycles);
+			break;
+		}
+	}
+
+	nm_kr_put(kring);
+
+#ifdef SYNC_KLOOP_POLL
+	/* Interrupt the application if needed. */
+	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
+		eventfd_signal(a->irq_ctx, 1);
+	}
+#endif /* SYNC_KLOOP_POLL */
+}
+
+#ifdef SYNC_KLOOP_POLL
+struct sync_kloop_poll_entry {
+	/* Support for receiving notifications from
+	 * a netmap ring or from the application. */
+	struct file *filp;
+	wait_queue_entry_t wait;
+	wait_queue_head_t *wqh;
+
+	/* Support for sending notifications to the application. */
+	struct eventfd_ctx *irq_ctx;
+	struct file *irq_filp;
+};
+
+struct sync_kloop_poll_ctx {
+	poll_table wait_table;
+	unsigned int next_entry;
+	unsigned int num_entries;
+	struct sync_kloop_poll_entry entries[0];
+};
+
+static void
+sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
+				poll_table *pt)
+{
+	struct sync_kloop_poll_ctx *poll_ctx =
+		container_of(pt, struct sync_kloop_poll_ctx, wait_table);
+	struct sync_kloop_poll_entry *entry = poll_ctx->entries +
+						poll_ctx->next_entry;
+
+	BUG_ON(poll_ctx->next_entry >= poll_ctx->num_entries);
+	entry->wqh = wqh;
+	entry->filp = file;
+	/* Use the default wake up function. */
+	init_waitqueue_entry(&entry->wait, current);
+	add_wait_queue(wqh, &entry->wait);
+	poll_ctx->next_entry++;
+	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
+}
+#endif  /* SYNC_KLOOP_POLL */
+
+int
+netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
+{
+	struct nmreq_sync_kloop_start *req =
+		(struct nmreq_sync_kloop_start *)(uintptr_t)hdr->nr_body;
+	struct nmreq_opt_sync_kloop_eventfds *eventfds_opt = NULL;
+#ifdef SYNC_KLOOP_POLL
+	struct sync_kloop_poll_ctx *poll_ctx = NULL;
+#endif  /* SYNC_KLOOP_POLL */
+	int num_rx_rings, num_tx_rings, num_rings;
+	uint32_t sleep_us = req->sleep_us;
+	struct nm_csb_atok* csb_atok_base;
+	struct nm_csb_ktoa* csb_ktoa_base;
+	struct netmap_adapter *na;
+	struct nmreq_option *opt;
+	int err = 0;
+	int i;
+
+	if (sleep_us > 1000000) {
+		/* We do not accept sleeping for more than a second. */
+		return EINVAL;
+	}
+
+	if (priv->np_nifp == NULL) {
+		return ENXIO;
+	}
+	mb(); /* make sure following reads are not from cache */
+
+	na = priv->np_na;
+	if (!nm_netmap_on(na)) {
+		return ENXIO;
+	}
+
+	if (!(priv->np_flags & NR_EXCLUSIVE)) {
+		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
+		return EINVAL;
+	}
+
+	/* Make sure that no kloop is currently running. */
+	NMG_LOCK();
+	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
+		err = EBUSY;
+	}
+	priv->np_kloop_state |= NM_SYNC_KLOOP_RUNNING;
+	NMG_UNLOCK();
+	if (err) {
+		return err;
+	}
+
+	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
+	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
+	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
+	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+	num_rings = num_tx_rings + num_rx_rings;
+
+	/* Validate the CSB entries for both directions (atok and ktoa). */
+	{
+		if (num_rings > 0) {
+			size_t entry_size[2];
+			void *csb_start[2];
+
+			entry_size[0] = sizeof(*csb_atok_base);
+			entry_size[1] = sizeof(*csb_ktoa_base);
+			csb_start[0] = (void *)csb_atok_base;
+			csb_start[1] = (void *)csb_ktoa_base;
+
+			for (i = 0; i < 2; i++) {
+				/* On Linux we could use access_ok() to simplify
+				 * the validation. However, the advantage of
+				 * this approach is that it works also on
+				 * FreeBSD. */
+				size_t csb_size = num_rings * entry_size[i];
+				void *tmp;
+
+				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
+					nm_prerr("Unaligned CSB address\n");
+					err = EINVAL;
+					goto out;
+				}
+
+				tmp = nm_os_malloc(csb_size);
+				if (!tmp) {
+					err = ENOMEM;
+					goto out;
+				}
+				if (i == 0) {
+					/* Application --> kernel direction. */
+					err = copyin(csb_start[i], tmp, csb_size);
+				} else {
+					/* Kernel --> application direction. */
+					memset(tmp, 0, csb_size);
+					err = copyout(tmp, csb_start[i], csb_size);
+				}
+				nm_os_free(tmp);
+				if (err) {
+					nm_prerr("Invalid CSB address\n");
+					goto out;
+				}
+			}
+		}
+	}
+
+	/* Validate notification options. */
+	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
+	if (opt != NULL) {
+		NM_SELINFO_T *si[NR_TXRX];
+
+		err = nmreq_checkduplicate(opt);
+		if (err) {
+			opt->nro_status = err;
+			goto out;
+		}
+		if (opt->nro_size != sizeof(*eventfds_opt) +
+			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
+			/* Option size not consistent with the number of
+			 * entries. */
+			opt->nro_status = err = EINVAL;
+			goto out;
+		}
+#ifdef SYNC_KLOOP_POLL
+		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
+		opt->nro_status = 0;
+		/* We need 2 poll entries for TX and RX notifications coming
+		 * from the netmap adapter, plus one entries per ring for the
+		 * notifications coming from the application. */
+		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
+				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
+		init_poll_funcptr(&poll_ctx->wait_table,
+					sync_kloop_poll_table_queue_proc);
+		poll_ctx->num_entries = 2 + num_rings;
+		poll_ctx->next_entry = 0;
+		/* Poll for notifications coming from the applications through
+		 * eventfds . */
+		for (i = 0; i < num_rings; i++) {
+			struct eventfd_ctx *irq;
+			struct file *filp;
+			unsigned long mask;
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
+			if (mask & POLLERR) {
+				err = EINVAL;
+				goto out;
+			}
+
+			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
+			if (IS_ERR(filp)) {
+				err = PTR_ERR(filp);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_filp = filp;
+			irq = eventfd_ctx_fileget(filp);
+			if (IS_ERR(irq)) {
+				err = PTR_ERR(irq);
+				goto out;
+			}
+			poll_ctx->entries[i].irq_ctx = irq;
+		}
+		/* Poll for notifications coming from the netmap rings bound to
+		 * this file descriptor. */
+		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
+		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
+#else   /* SYNC_KLOOP_POLL */
+		opt->nro_status = EOPNOTSUPP;
+		goto out;
+#endif  /* SYNC_KLOOP_POLL */
+	}
+
+	/* Main loop. */
+	for (;;) {
+#ifdef SYNC_KLOOP_POLL
+		if (poll_ctx)
+			__set_current_state(TASK_INTERRUPTIBLE);
+#endif  /* SYNC_KLOOP_POLL */
+
+		/* Process all the TX rings bound to this file descriptor. */
+		for (i = 0; i < num_tx_rings; i++) {
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
+				.csb_atok = csb_atok_base + i,
+				.csb_ktoa = csb_ktoa_base + i,
+			};
+
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
+				continue;
+			}
+			netmap_sync_kloop_tx_ring(&a);
+			nm_kr_put(a.kring);
+		}
+
+		/* Process all the RX rings bound to this file descriptor. */
+		for (i = 0; i < num_rx_rings; i++) {
+			struct sync_kloop_ring_args a = {
+				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
+				.csb_atok = csb_atok_base + num_tx_rings + i,
+				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
+			};
+
+#ifdef SYNC_KLOOP_POLL
+			if (poll_ctx)
+				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+
+			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
+				continue;
+			}
+			netmap_sync_kloop_rx_ring(&a);
+			nm_kr_put(a.kring);
+		}
+
+#ifdef SYNC_KLOOP_POLL
+		if (poll_ctx) {
+			/* If a poll context is present, yield to the scheduler
+			 * waiting for a notification to come either from
+			 * netmap or the application. */
+			schedule_timeout_interruptible(msecs_to_jiffies(1000));
+		} else
+#endif /* SYNC_KLOOP_POLL */
+		{
+			/* Default synchronization method: sleep for a while. */
+			usleep_range(sleep_us, sleep_us);
+		}
+
+		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
+			break;
+		}
+	}
+out:
+#ifdef SYNC_KLOOP_POLL
+	if (poll_ctx) {
+		/* Stop polling from netmap and the eventfds, and deallocate
+		 * the poll context. */
+		__set_current_state(TASK_RUNNING);
+		for (i = 0; i < poll_ctx->next_entry; i++) {
+			struct sync_kloop_poll_entry *entry =
+						poll_ctx->entries + i;
+
+			if (entry->wqh)
+				remove_wait_queue(entry->wqh, &entry->wait);
+			/* We did not get a reference to the eventfds, but
+			 * don't do that on netmap file descriptors (since
+			 * a reference was not taken. */
+			if (entry->filp && entry->filp != priv->np_filp)
+				fput(entry->filp);
+			if (entry->irq_ctx)
+				eventfd_ctx_put(entry->irq_ctx);
+			if (entry->irq_filp)
+				fput(entry->irq_filp);
+		}
+		nm_os_free(poll_ctx);
+		poll_ctx = NULL;
+	}
+#endif /* SYNC_KLOOP_POLL */
+
+	/* Reset the kloop state. */
+	NMG_LOCK();
+	priv->np_kloop_state = 0;
+	NMG_UNLOCK();
+
+	return err;
+}
+
 #ifdef WITH_PTNETMAP_GUEST
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.

From d9d5ee342a4595f0b649163aa9d619849112dd42 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 10:18:50 +0200
Subject: [PATCH 1299/2207] merge ptnetmap-host and ptnetmap-guest subsystems

---
 LINUX/Kbuild.in                 |  6 ++----
 LINUX/README                    |  7 +------
 LINUX/configure                 | 18 +++---------------
 LINUX/netmap_linux.c            | 12 ++++++------
 README.ptnetmap                 | 12 +++---------
 sys/dev/netmap/netmap.c         |  8 --------
 sys/dev/netmap/netmap_freebsd.c |  6 +++---
 sys/dev/netmap/netmap_kern.h    | 19 +++++++++++++------
 sys/dev/netmap/netmap_mem2.c    |  4 ++--
 sys/dev/netmap/netmap_mem2.h    |  4 ++--
 sys/dev/netmap/netmap_pt.c      |  4 ++--
 sys/net/netmap_virt.h           |  4 ++--
 12 files changed, 39 insertions(+), 65 deletions(-)

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index a2ce4966c..edcc31d7c 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,14 +8,12 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o netmap_pt.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
 remoteobjs-$(CONFIG_NETMAP_MONITOR) += netmap_monitor.o
 remoteobjs-$(CONFIG_NETMAP_GENERIC) += netmap_generic.o
-remoteobjs-ptnetmap-$(CONFIG_NETMAP_PTNETMAP_GUEST) = netmap_pt.o
-remoteobjs-y += $(remoteobjs-ptnetmap-y)
 
 define remote_template
 $$(obj)/$(1): %.o: $$(SRCDIR)/../sys/dev/netmap/$(2) FORCE
@@ -32,7 +30,7 @@ $(obj)/netmap_linux.o: %.o: $(SRCDIR)/netmap_linux.c FORCE
 # all objects
 $(MODNAME)-objs := $(remoteobjs-y) netmap_common.o netmap_linux.o
 
-ifdef CONFIG_NETMAP_PTNETMAP_GUEST
+ifdef CONFIG_NETMAP_PTNETMAP
 $(obj)/netmap_ptnet.o: %.o: $(SRCDIR)/netmap_ptnet.c FORCE
 	$(call if_changed_rule,cc_o_c)
 
diff --git a/LINUX/README b/LINUX/README
index 8225f1a6d..181d5cce5 100644
--- a/LINUX/README
+++ b/LINUX/README
@@ -91,14 +91,9 @@ features, namely:
 			used to access NICs without native netmap support (at
 			reduced performance).
 
-    ptnetmap-guest:	netmap passthrough support for guests
+    ptnetmap:		netmap passthrough support for guests
 			(including the ptnet driver).
 
-    ptnetmap-host:	netmap passthrough support for the host
-
-    ptnetmap:		shortcut to include both ptnetmap-guest and
-			ptnetmap-host.
-
     sink:		a dummy drop-everything device with native netmap
 			support.  It can emulate a link with configurable
 			packet rate.
diff --git a/LINUX/configure b/LINUX/configure
index 0252c8b0e..731127d0c 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -94,7 +94,7 @@ setop()
 }
 
 # available subsystems
-subsystem_avail="vale pipe monitor generic ptnetmap-guest ptnetmap-host sink \
+subsystem_avail="vale pipe monitor generic ptnetmap sink \
 	extmem"
 #enabled subsystems (bitfield)
 subsystem=0
@@ -317,12 +317,8 @@ Available options:
   --disable-monitor   	       disable the nemtap monitors
   --enable-generic   	       enable the generic netmap adapter
   --disable-generic   	       disable the generic netmap adapter
-  --enable-ptnetmap-guest      enable ptnetmap for guest kernel
-  --disable-ptnetmap-guest     disable ptnetmap for guest kernel
-  --enable-ptnetmap-host       enable ptnetmap for host kernel
-  --disable-ptnetmap-host      disable ptnetmap for host kernel
-  --enable-ptnetmap            enable ptnetmap (both guest and host)
-  --disable-ptnetmap           disable ptnetmap (both guest and host)
+  --enable-ptnetmap            enable ptnetmap
+  --disable-ptnetmap           disable ptnetmap
   --enable-sink   	       enable the netmap sink device
   --disable-sink   	       disable the netmap sink device
   --enable-extmem   	       enable the external memory allocators
@@ -613,14 +609,6 @@ for opt do
 	;;
 	--mod-name=*) MODNAME="$optarg"
 	;;
-	--enable-ptnetmap)
-		subsys enable ptnetmap-guest
-		subsys enable ptnetmap-host
-	;;
-	--disable-ptnetmap)
-		subsys disable ptnetmap-guest
-		subsys disable ptnetmap-host
-	;;
 	--disable-*)
 		subsys disable "${opt#--disable-}"
 	;;
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0b354e903..86d188ab5 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1980,8 +1980,8 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 	kfree(nmk);
 }
 
-/* ##################### PTNETMAP SUPPORT ##################### */
-#ifdef WITH_PTNETMAP_GUEST
+/* ################## PTNETMAP GUEST SUPPORT ################## */
+#ifdef WITH_PTNETMAP
 /*
  * ptnetmap memory device (memdev) for linux guest
  * Used to expose host memory to the guest through PCI-BAR
@@ -2204,10 +2204,10 @@ ptnetmap_guest_fini(void)
 	pci_unregister_driver(&ptnetmap_guest_drivers);
 }
 
-#else /* !WITH_PTNETMAP_GUEST */
+#else /* !WITH_PTNETMAP */
 #define ptnetmap_guest_init()		0
 #define ptnetmap_guest_fini()
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 #ifdef WITH_SINK
 
@@ -2655,12 +2655,12 @@ EXPORT_SYMBOL(__netmap_adapter_put);
 EXPORT_SYMBOL(netmap_adapter_get);
 EXPORT_SYMBOL(netmap_adapter_put);
 #endif /* NM_DEBUG_PUTGET */
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 EXPORT_SYMBOL(netmap_pt_guest_attach);	/* ptnetmap driver attach routine */
 EXPORT_SYMBOL(netmap_pt_guest_rxsync);	/* ptnetmap generic rxsync */
 EXPORT_SYMBOL(netmap_pt_guest_txsync);	/* ptnetmap generic txsync */
 EXPORT_SYMBOL(netmap_mem_pt_guest_ifp_del); /* unlink passthrough interface */
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 EXPORT_SYMBOL(netmap_detach);		/* driver detach routines */
 EXPORT_SYMBOL(netmap_ring_reinit);	/* ring init on error */
 EXPORT_SYMBOL(netmap_reset);		/* ring init routines */
diff --git a/README.ptnetmap b/README.ptnetmap
index e2e7b80e8..1b285473a 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap
@@ -44,16 +44,11 @@ and in section 7 of this document.
 2. Configure Linux host and QEMU for ptnetmap
 ---------------------------------------------------------------------------
 
-(Warning! For ptnetmap use v11.4.
-In the current master, ptnetmap is disabled.
-Support for the current master will be re-added as soon as possible)
-
-On the Linux host, configure, build and install netmap with ptnetmap support:
+On the Linux host, configure, build and install netmap normally:
 
     $ git clone https://github.com/luigirizzo/netmap.git
     $ cd netmap
-    $ git checkout v11.4
-    $ ./configure --enable-ptnetmap [other options]
+    $ ./configure [options]
     $ make
     $ sudo make install
 
@@ -65,9 +60,8 @@ Download, build and install the ptnetmap-enabled QEMU:
     $ make
     $ sudo make install
 
-Load the ptnetmap-enabled netmap
+Load the netmap
 
-    $ sudo rmmod netmap  # Possibly remove a previous netmap module:
     $ sudo modprobe netmap
 
 Example to run a VM passing through a VALE port (vale1:10):
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6dc30e389..8339c4e53 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1031,14 +1031,6 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 	priv->np_nifp = NULL;
 }
 
-/* call with NMG_LOCK held */
-static __inline int
-nm_si_user(struct netmap_priv_d *priv, enum txrx t)
-{
-	return (priv->np_na != NULL &&
-		(priv->np_qlast[t] - priv->np_qfirst[t] > 1));
-}
-
 struct netmap_priv_d*
 netmap_priv_new(void)
 {
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 11f641fa6..2932f29c3 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -733,9 +733,9 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 }
 #endif /* WITH_EXTMEM */
 
-/* ======================== PTNETMAP SUPPORT ========================== */
+/* ================== PTNETMAP GUEST SUPPORT ==================== */
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 #include 
 #include 
 #include         /* bus_dmamap_* */
@@ -930,7 +930,7 @@ ptn_memdev_shutdown(device_t dev)
 	return bus_generic_shutdown(dev);
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 /*
  * In order to track whether pages are still mapped, we hook into
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8cd7a3028..58a44f0e1 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -52,8 +52,8 @@
 #if defined(CONFIG_NETMAP_GENERIC)
 #define WITH_GENERIC
 #endif
-#if defined(CONFIG_NETMAP_PTNETMAP_GUEST)
-#define WITH_PTNETMAP_GUEST
+#if defined(CONFIG_NETMAP_PTNETMAP)
+#define WITH_PTNETMAP
 #endif
 #if defined(CONFIG_NETMAP_SINK)
 #define WITH_SINK
@@ -70,7 +70,7 @@
 #define WITH_PIPES
 #define WITH_MONITOR
 #define WITH_GENERIC
-#define WITH_PTNETMAP_GUEST	/* ptnetmap guest support */
+#define WITH_PTNETMAP	/* ptnetmap guest support */
 #define WITH_EXTMEM
 #endif
 
@@ -1436,7 +1436,6 @@ void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
 
-
 #ifdef WITH_VALE
 uint32_t netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		struct netmap_vp_adapter *, void *private_data);
@@ -1902,6 +1901,14 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
 	return 0;
 }
 
+/* call with NMG_LOCK held */
+static __inline int
+nm_si_user(struct netmap_priv_d *priv, enum txrx t)
+{
+	return (priv->np_na != NULL &&
+		(priv->np_qlast[t] - priv->np_qfirst[t] > 1));
+}
+
 #ifdef WITH_PIPES
 int netmap_pipe_txsync(struct netmap_kring *txkring, int flags);
 int netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags);
@@ -2128,7 +2135,7 @@ u_int nm_os_ncpus(void);
 int netmap_sync_kloop(struct netmap_priv_d *priv,
 		      struct nmreq_header *hdr);
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 /* ptnetmap GUEST routines */
 
 /*
@@ -2165,7 +2172,7 @@ bool netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh,
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 #ifdef __FreeBSD__
 /*
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8334d5b1a..17ddea399 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2343,7 +2343,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 #endif /* WITH_EXTMEM */
 
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 struct mem_pt_if {
 	struct mem_pt_if *next;
 	struct ifnet *ifp;
@@ -2832,4 +2832,4 @@ netmap_mem_pt_guest_new(struct ifnet *ifp,
 	return nmd;
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 3fc48784d..9268024c6 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -156,14 +156,14 @@ struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *,
 	({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
 #endif /* WITH_EXTMEM */
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,
 					     unsigned int nifp_offset,
 					     unsigned int memid);
 struct ptnetmap_memdev;
 struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16_t);
 int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 int netmap_mem_pools_info_get(struct nmreq_pools_info *,
 				struct netmap_mem_d *);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 4d5120238..7c30554ca 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -703,7 +703,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	return err;
 }
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
  * These routines are reused across the different operating systems supported
@@ -933,4 +933,4 @@ netmap_pt_guest_attach(struct netmap_adapter *arg,
 	return 0;
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index cef32eed6..b6788051f 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -172,7 +172,7 @@ struct ptnet_csb_hg {
 	char pad[4+48];
 };
 
-#ifdef WITH_PTNETMAP_GUEST
+#ifdef WITH_PTNETMAP
 
 /* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */
 struct ptnetmap_memdev;
@@ -227,6 +227,6 @@ ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kr
     kring->nr_hwcur = pthg->hwcur;
 }
 
-#endif /* WITH_PTNETMAP_GUEST */
+#endif /* WITH_PTNETMAP */
 
 #endif /* NETMAP_VIRT_H */

From 5c1247fdfd07051c425f7b6b75a0d4adff300fe3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 10:30:46 +0200
Subject: [PATCH 1300/2207] sync-kloop: grab NMG lock to call nm_si_user()

---
 sys/dev/netmap/netmap_pt.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 7c30554ca..2a7e8916d 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -593,10 +593,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
+		NMG_LOCK();
 		si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
 					&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
 		si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
 					&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+		NMG_UNLOCK();
 		poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
 		poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
 #else   /* SYNC_KLOOP_POLL */

From 266a7904626afaba5c612d2624fd8d374c69aae5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 11:56:41 +0200
Subject: [PATCH 1301/2207] ptnetmap: print interface name instead of ifp value

---
 sys/dev/netmap/netmap_mem2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 17ddea399..6d992a5ce 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2386,7 +2386,8 @@ netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
 
 	NMA_UNLOCK(nmd);
 
-	D("added (ifp=%p,nifp_offset=%u)", ptif->ifp, ptif->nifp_offset);
+	nm_prinf("added (ifp=%s,nifp_offset=%u)", ptif->ifp->if_xname,
+						ptif->nifp_offset);
 
 	return 0;
 }

From da631f196ce4c225c9a2409063a37601d8377d2a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:20:47 +0200
Subject: [PATCH 1302/2207] ptnetmap: prune old guest code

---
 LINUX/netmap_linux.c         |   9 ++--
 LINUX/netmap_ptnet.c         | 100 +++++++++++++++++------------------
 sys/dev/netmap/if_ptnet.c    |  90 +++++++++++++++----------------
 sys/dev/netmap/netmap_kern.h |  13 ++---
 sys/dev/netmap/netmap_pt.c   |  42 +++++++--------
 sys/net/netmap_virt.h        |  92 +++-----------------------------
 6 files changed, 132 insertions(+), 214 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 86d188ab5..26e33884f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1784,7 +1784,6 @@ static int
 nm_kctx_open_files(struct nm_kctx *nmk, void *opaque)
 {
 	struct file *file;
-	struct ptnetmap_cfgentry_qemu *ring_cfg = opaque;
 
 	nmk->ioevent_file = NULL;
 	nmk->irq_file = NULL;
@@ -1793,15 +1792,15 @@ nm_kctx_open_files(struct nm_kctx *nmk, void *opaque)
 		return 0;
 	}
 
-	if (ring_cfg->ioeventfd) {
-		file = eventfd_fget(ring_cfg->ioeventfd);
+	if (0 /* TODO cleanup */) {
+		file = eventfd_fget(-1);
 		if (IS_ERR(file))
 			goto err;
 		nmk->ioevent_file = file;
 	}
 
-	if (ring_cfg->irqfd) {
-		file = eventfd_fget(ring_cfg->irqfd);
+	if (0 /* TODO cleanup */) {
+		file = eventfd_fget(-1);
 		if (IS_ERR(file))
 			goto err;
 		nmk->irq_file = file;
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index da3cf5f7a..ee50fd9a9 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -57,8 +57,8 @@ struct ptnet_info;
 /* Per-ring data structure. */
 struct ptnet_queue {
 	struct ptnet_info *pi;
-	struct ptnet_csb_gh *ptgh;
-	struct ptnet_csb_hg *pthg;
+	struct nm_csb_atok *atok;
+	struct nm_csb_ktoa *ktoa;
 	int kring_id;
 	u8* __iomem kick;
 
@@ -107,8 +107,8 @@ struct ptnet_info {
 	/* CSB memory to be used for producer/consumer state
 	 * synchronization. */
 	struct page *csb_pages;
-	struct ptnet_csb_gh *csb_gh;
-	struct ptnet_csb_hg *csb_hg;
+	struct nm_csb_atok *csb_gh;
+	struct nm_csb_ktoa *csb_hg;
 
 	int min_tx_slots;
 
@@ -131,9 +131,9 @@ hang_tmr_callback(unsigned long arg)
 	struct netmap_ring *ring = kring->ring;
 
 	pr_info("PTNET HANG RX#%d: hwc %u h %u c %u hwt %u t %u"
-		" rx.guest_need_kick %u\n",
+		" rx.appl_need_kick %u\n",
 		kring->ring_id, kring->nr_hwcur, ring->head, ring->cur,
-		kring->nr_hwtail, ring->tail, prq->q.ptgh->guest_need_kick);
+		kring->nr_hwtail, ring->tail, prq->q.atok->appl_need_kick);
 
 	if (mod_timer(&prq->hang_timer,
 		      jiffies + msecs_to_jiffies(HANG_INTVAL_MS))) {
@@ -143,12 +143,12 @@ hang_tmr_callback(unsigned long arg)
 #endif
 
 static inline void
-ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-	ptnetmap_guest_read_kring_csb(pthg, kring);
+	ptnetmap_guest_read_kring_csb(ktoa, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -216,8 +216,8 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	int queue_idx = skb_get_queue_mapping(skb);
 	struct ptnet_queue *pq = pi->queues[queue_idx];
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 	struct netmap_kring *kring;
 	struct xmit_copy_args a;
 	int f;
@@ -231,7 +231,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 	/* Update hwcur and hwtail (completed TX slots) as known by the host,
 	 * by reading from CSB. */
-	ptnet_sync_tail(pthg, kring);
+	ptnet_sync_tail(ktoa, kring);
 
 	if (unlikely(ptnet_tx_slots(a.ring) < pi->min_tx_slots)) {
 		ND(1, "TX ring unexpected overflow, requeuing");
@@ -324,13 +324,13 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	if (!XMIT_MORE(skb)) {
 		/* Tell the host to process the new packets, updating cur and
 		 * head in the CSB. */
-		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
+		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
 					       kring->rhead);
 	}
 
 	/* Ask for a kick from a guest to the host if needed. */
-	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-		ptgh->sync_flags = NAF_FORCE_RECLAIM;
+	if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+		atok->sync_flags = NAF_FORCE_RECLAIM;
 		iowrite32(0, pq->kick);
 	}
 
@@ -338,14 +338,14 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	 * qdisc layer and enable notifications. */
 	if (ptnet_tx_slots(a.ring) < pi->min_tx_slots) {
 		netif_stop_subqueue(netdev, pq->kring_id);
-		ptgh->guest_need_kick = 1;
+		atok->appl_need_kick = 1;
 
 		/* Double check. */
-		ptnet_sync_tail(pthg, kring);
+		ptnet_sync_tail(ktoa, kring);
 		if (unlikely(ptnet_tx_slots(a.ring) >= pi->min_tx_slots)) {
 			/* More TX space came in the meanwhile. */
 			netif_start_subqueue(netdev, pq->kring_id);
-			ptgh->guest_need_kick = 0;
+			atok->appl_need_kick = 0;
 		}
 	}
 
@@ -413,13 +413,13 @@ ptnet_napi_schedule(struct ptnet_queue *pq)
 	/* Disable RX interrupts and schedule NAPI. */
 
 	if (likely(napi_schedule_prep(&prq->napi))) {
-		/* It's good thing to reset rx.guest_need_kick as soon as
+		/* It's good thing to reset rx.appl_need_kick as soon as
 		 * possible. */
-		pq->ptgh->guest_need_kick = 0;
+		pq->atok->appl_need_kick = 0;
 		__napi_schedule(&prq->napi);
 	} else {
 		/* NAPI is already scheduled and we are ok with it. */
-		pq->ptgh->guest_need_kick = 1;
+		pq->atok->appl_need_kick = 1;
 	}
 }
 
@@ -476,8 +476,8 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 	struct ptnet_rx_queue *prq = container_of(napi, struct ptnet_rx_queue,
 					          napi);
 	struct ptnet_queue *pq = (struct ptnet_queue *)prq;
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 	struct ptnet_info *pi = pq->pi;
 	struct netmap_adapter *na = &pi->ptna->dr.up;
 	struct netmap_kring *kring = na->rx_rings[pq->kring_id];
@@ -504,7 +504,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 
 	/* Update hwtail, rtail, tail and hwcur to what is known from the host,
 	 * reading from CSB. */
-	ptnet_sync_tail(pthg, kring);
+	ptnet_sync_tail(ktoa, kring);
 
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
@@ -701,7 +701,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		/* Budget was not fully consumed, since we have no more
 		 * completed RX slots. We can enable notifications and
 		 * exit polling mode. */
-		ptgh->guest_need_kick = 1;
+		atok->appl_need_kick = 1;
 #ifdef NETMAP_LINUX_HAVE_NAPI_COMPLETE_DONE
 		napi_complete_done(napi, work_done);
 #else
@@ -709,7 +709,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 #endif
 
 		/* Double check for more completed RX slots. */
-		ptnet_sync_tail(pthg, kring);
+		ptnet_sync_tail(ktoa, kring);
 		if (head != ring->tail) {
 			/* If there is more work to do, disable notifications
 			 * and reschedule. */
@@ -730,11 +730,11 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		ring->head = ring->cur = head;
 		kring->rcur = ring->cur;
 		kring->rhead = ring->head;
-		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
+		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
 					       kring->rhead);
 		/* Kick the host if needed. */
-		if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-			ptgh->sync_flags = NAF_FORCE_READ;
+		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+			atok->sync_flags = NAF_FORCE_READ;
 			iowrite32(0, pq->kick);
 		}
 	}
@@ -1051,8 +1051,8 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < pi->num_rings; i++) {
-		struct ptnet_csb_gh *ptgh = pi->queues[i]->ptgh;
-		struct ptnet_csb_hg *pthg = pi->queues[i]->pthg;
+		struct nm_csb_atok *atok = pi->queues[i]->atok;
+		struct nm_csb_ktoa *ktoa = pi->queues[i]->ktoa;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1060,15 +1060,15 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings[i - na->num_tx_rings];
 		}
-		kring->rhead = kring->ring->head = ptgh->head;
-		kring->rcur = kring->ring->cur = ptgh->cur;
-		kring->nr_hwcur = pthg->hwcur;
+		kring->rhead = kring->ring->head = atok->head;
+		kring->rcur = kring->ring->cur = atok->cur;
+		kring->nr_hwcur = ktoa->hwcur;
 		kring->nr_hwtail = kring->rtail =
-			kring->ring->tail = pthg->hwtail;
+			kring->ring->tail = ktoa->hwtail;
 
 		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
-		   pthg->hwcur, ptgh->head, ptgh->cur,
-		   pthg->hwtail);
+		   ktoa->hwcur, atok->head, atok->cur,
+		   ktoa->hwtail);
 		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
@@ -1094,8 +1094,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	struct net_device *netdev = na->ifp;
 	struct ptnet_info *pi = netdev_priv(netdev);
 	int native = (na == &pi->ptna->hwup.up);
-	struct ptnet_csb_gh *ptgh;
-	struct ptnet_csb_hg *pthg;
+	struct nm_csb_atok *atok;
+	struct nm_csb_ktoa *ktoa;
 	enum txrx t;
 	int ret = 0;
 	int i;
@@ -1116,8 +1116,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		pr_info("%s: Exit netmap mode, re-enable interrupts\n",
 			__func__);
 		for (i = 0; i < pi->num_rings; i++) {
-			ptgh = pi->queues[i]->ptgh;
-			ptgh->guest_need_kick = 1;
+			atok = pi->queues[i]->atok;
+			atok->appl_need_kick = 1;
 		}
 		if (netif_running(netdev)) {
 			pr_info("%s: Exit netmap mode, schedule NAPI to flush RX ring\n",
@@ -1133,10 +1133,10 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		if (pi->ptna->backend_regifs == 0) {
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < pi->num_rings; i++) {
-				ptgh = pi->queues[i]->ptgh;
-				pthg = pi->queues[i]->pthg;
-				ptgh->guest_need_kick = (i >= pi->num_tx_rings);
-				pthg->host_need_kick = 1;
+				atok = pi->queues[i]->atok;
+				ktoa = pi->queues[i]->ktoa;
+				atok->appl_need_kick = (i >= pi->num_tx_rings);
+				ktoa->kern_need_kick = 1;
 			}
 
 			/* Set the virtio-net header length. */
@@ -1231,7 +1231,7 @@ ptnet_nm_txsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = pi->queues[kring->ring_id];
 	bool notify;
 
-	notify = netmap_pt_guest_txsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_txsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		iowrite32(0, pq->kick);
 	}
@@ -1246,7 +1246,7 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = pi->rxqueues[kring->ring_id];
 	bool notify;
 
-	notify = netmap_pt_guest_rxsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_rxsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		iowrite32(0, pq->kick);
 	}
@@ -1262,7 +1262,7 @@ ptnet_nm_intr(struct netmap_adapter *na, int onoff)
 
 	for (i = 0; i < pi->num_rings; i++) {
 		struct ptnet_queue *pq = pi->queues[i];
-		pq->ptgh->guest_need_kick = onoff;
+		pq->atok->appl_need_kick = onoff;
 	}
 }
 
@@ -1368,7 +1368,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	pi->num_rings = num_tx_rings + num_rx_rings;
 	pi->num_tx_rings = num_tx_rings;
 
-	if (pi->num_rings * sizeof(struct ptnet_csb_gh) > PAGE_SIZE) {
+	if (pi->num_rings * sizeof(struct nm_csb_atok) > PAGE_SIZE) {
 		pr_err("%s: CSB for device %s cannot handle too many "
 			"rings (%u)\n",__func__, netdev->name, pi->num_rings);
 		goto err_ptfeat;
@@ -1427,8 +1427,8 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			pq->kring_id -= num_tx_rings;
 		}
 		pq->kick = ioaddr + PTNET_IO_KICK_BASE + 4 * i;
-		pq->ptgh = pi->csb_gh + i;
-		pq->pthg = pi->csb_hg + i;
+		pq->atok = pi->csb_gh + i;
+		pq->ktoa = pi->csb_hg + i;
 	}
 
 	netdev->netdev_ops = &ptnet_netdev_ops;
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 55137f270..f429168da 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -128,8 +128,8 @@ struct ptnet_queue {
 	struct				resource *irq;
 	void				*cookie;
 	int				kring_id;
-	struct ptnet_csb_gh		*ptgh;
-	struct ptnet_csb_hg		*pthg;
+	struct nm_csb_atok		*atok;
+	struct nm_csb_ktoa		*ktoa;
 	unsigned int			kick;
 	struct mtx			lock;
 	struct buf_ring			*bufring; /* for TX queues */
@@ -166,8 +166,8 @@ struct ptnet_softc {
 	unsigned int		num_tx_rings;
 	struct ptnet_queue	*queues;
 	struct ptnet_queue	*rxqueues;
-	struct ptnet_csb_gh    *csb_gh;
-	struct ptnet_csb_hg    *csb_hg;
+	struct nm_csb_atok	*csb_gh;
+	struct nm_csb_ktoa	*csb_hg;
 
 	unsigned int		min_tx_space;
 
@@ -327,7 +327,7 @@ ptnet_attach(device_t dev)
 	sc->num_rings = num_tx_rings + num_rx_rings;
 	sc->num_tx_rings = num_tx_rings;
 
-	if (sc->num_rings * sizeof(struct ptnet_csb_gh) > PAGE_SIZE) {
+	if (sc->num_rings * sizeof(struct nm_csb_atok) > PAGE_SIZE) {
 		device_printf(dev, "CSB cannot handle that many rings (%u)\n",
 				sc->num_rings);
 		err = ENOMEM;
@@ -342,7 +342,7 @@ ptnet_attach(device_t dev)
 		err = ENOMEM;
 		goto err_path;
 	}
-	sc->csb_hg = (struct ptnet_csb_hg *)(((char *)sc->csb_gh) + PAGE_SIZE);
+	sc->csb_hg = (struct nm_csb_ktoa *)(((char *)sc->csb_gh) + PAGE_SIZE);
 
 	{
 		/*
@@ -379,8 +379,8 @@ ptnet_attach(device_t dev)
 		pq->sc = sc;
 		pq->kring_id = i;
 		pq->kick = PTNET_IO_KICK_BASE + 4 * i;
-		pq->ptgh = sc->csb_gh + i;
-		pq->pthg = sc->csb_hg + i;
+		pq->atok = sc->csb_gh + i;
+		pq->ktoa = sc->csb_hg + i;
 		snprintf(pq->lock_name, sizeof(pq->lock_name), "%s-%d",
 			 device_get_nameunit(dev), i);
 		mtx_init(&pq->lock, pq->lock_name, NULL, MTX_DEF);
@@ -796,7 +796,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 					/* Make sure the worker sees the
 					 * IFF_DRV_RUNNING down. */
 					PTNET_Q_LOCK(pq);
-					pq->ptgh->guest_need_kick = 0;
+					pq->atok->appl_need_kick = 0;
 					PTNET_Q_UNLOCK(pq);
 					/* Wait for rescheduling to finish. */
 					if (pq->taskq) {
@@ -810,7 +810,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 				for (i = 0; i < sc->num_rings; i++) {
 					pq = sc-> queues + i;
 					PTNET_Q_LOCK(pq);
-					pq->ptgh->guest_need_kick = 1;
+					pq->atok->appl_need_kick = 1;
 					PTNET_Q_UNLOCK(pq);
 				}
 			}
@@ -1130,8 +1130,8 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 	/* Sync krings from the host, reading from
 	 * CSB. */
 	for (i = 0; i < sc->num_rings; i++) {
-		struct ptnet_csb_gh *ptgh = sc->queues[i].ptgh;
-		struct ptnet_csb_hg *pthg = sc->queues[i].pthg;
+		struct nm_csb_atok *atok = sc->queues[i].atok;
+		struct nm_csb_ktoa *ktoa = sc->queues[i].ktoa;
 		struct netmap_kring *kring;
 
 		if (i < na->num_tx_rings) {
@@ -1139,15 +1139,15 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings[i - na->num_tx_rings];
 		}
-		kring->rhead = kring->ring->head = ptgh->head;
-		kring->rcur = kring->ring->cur = ptgh->cur;
-		kring->nr_hwcur = pthg->hwcur;
+		kring->rhead = kring->ring->head = atok->head;
+		kring->rcur = kring->ring->cur = atok->cur;
+		kring->nr_hwcur = ktoa->hwcur;
 		kring->nr_hwtail = kring->rtail =
-			kring->ring->tail = pthg->hwtail;
+			kring->ring->tail = ktoa->hwtail;
 
 		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
-		   pthg->hwcur, ptgh->head, ptgh->cur,
-		   pthg->hwtail);
+		   ktoa->hwcur, atok->head, atok->cur,
+		   ktoa->hwtail);
 		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
@@ -1191,7 +1191,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		D("Exit netmap mode, re-enable interrupts");
 		for (i = 0; i < sc->num_rings; i++) {
 			pq = sc->queues + i;
-			pq->ptgh->guest_need_kick = 1;
+			pq->atok->appl_need_kick = 1;
 		}
 	}
 
@@ -1200,8 +1200,8 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < sc->num_rings; i++) {
 				pq = sc->queues + i;
-				pq->pthg->host_need_kick = 1;
-				pq->ptgh->guest_need_kick =
+				pq->ktoa->kern_need_kick = 1;
+				pq->atok->appl_need_kick =
 					(!(ifp->if_capenable & IFCAP_POLLING)
 						&& i >= sc->num_tx_rings);
 			}
@@ -1279,7 +1279,7 @@ ptnet_nm_txsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = sc->queues + kring->ring_id;
 	bool notify;
 
-	notify = netmap_pt_guest_txsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_txsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		ptnet_kick(pq);
 	}
@@ -1294,7 +1294,7 @@ ptnet_nm_rxsync(struct netmap_kring *kring, int flags)
 	struct ptnet_queue *pq = sc->rxqueues + kring->ring_id;
 	bool notify;
 
-	notify = netmap_pt_guest_rxsync(pq->ptgh, pq->pthg, kring, flags);
+	notify = netmap_pt_guest_rxsync(pq->atok, pq->ktoa, kring, flags);
 	if (notify) {
 		ptnet_kick(pq);
 	}
@@ -1310,7 +1310,7 @@ ptnet_nm_intr(struct netmap_adapter *na, int onoff)
 
 	for (i = 0; i < sc->num_rings; i++) {
 		struct ptnet_queue *pq = sc->queues + i;
-		pq->ptgh->guest_need_kick = onoff;
+		pq->atok->appl_need_kick = onoff;
 	}
 }
 
@@ -1677,12 +1677,12 @@ ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr)
 /* End of offloading-related functions to be shared with vtnet. */
 
 static inline void
-ptnet_sync_tail(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(pthg, kring);
+        ptnetmap_guest_read_kring_csb(ktoa, kring);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
@@ -1693,8 +1693,8 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 		  unsigned int head, unsigned int sync_flags)
 {
 	struct netmap_ring *ring = kring->ring;
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 
 	/* Some packets have been pushed to the netmap ring. We have
 	 * to tell the host to process the new packets, updating cur
@@ -1704,11 +1704,11 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 	/* Mimic nm_txsync_prologue/nm_rxsync_prologue. */
 	kring->rcur = kring->rhead = head;
 
-	ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
+	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
 
 	/* Kick the host if needed. */
-	if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-		ptgh->sync_flags = sync_flags;
+	if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+		atok->sync_flags = sync_flags;
 		ptnet_kick(pq);
 	}
 }
@@ -1728,8 +1728,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	if_t ifp = sc->ifp;
 	unsigned int batch_count = 0;
-	struct ptnet_csb_gh *ptgh;
-	struct ptnet_csb_hg *pthg;
+	struct nm_csb_atok *atok;
+	struct nm_csb_ktoa *ktoa;
 	struct netmap_kring *kring;
 	struct netmap_ring *ring;
 	struct netmap_slot *slot;
@@ -1758,8 +1758,8 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 		return ENETDOWN;
 	}
 
-	ptgh = pq->ptgh;
-	pthg = pq->pthg;
+	atok = pq->atok;
+	ktoa = pq->ktoa;
 	kring = na->tx_rings[pq->kring_id];
 	ring = kring->ring;
 	lim = kring->nkr_num_slots - 1;
@@ -1771,17 +1771,17 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 			/* We ran out of slot, let's see if the host has
 			 * freed up some, by reading hwcur and hwtail from
 			 * the CSB. */
-			ptnet_sync_tail(pthg, kring);
+			ptnet_sync_tail(ktoa, kring);
 
 			if (PTNET_TX_NOSPACE(head, kring, minspace)) {
 				/* Still no slots available. Reactivate the
 				 * interrupts so that we can be notified
 				 * when some free slots are made available by
 				 * the host. */
-				ptgh->guest_need_kick = 1;
+				atok->appl_need_kick = 1;
 
 				/* Double-check. */
-				ptnet_sync_tail(pthg, kring);
+				ptnet_sync_tail(ktoa, kring);
 				if (likely(PTNET_TX_NOSPACE(head, kring,
 							    minspace))) {
 					break;
@@ -1790,7 +1790,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 				RD(1, "Found more slots by doublecheck");
 				/* More slots were freed before reactivating
 				 * the interrupts. */
-				ptgh->guest_need_kick = 0;
+				atok->appl_need_kick = 0;
 			}
 		}
 
@@ -2020,8 +2020,8 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 {
 	struct ptnet_softc *sc = pq->sc;
 	bool have_vnet_hdr = sc->vnet_hdr_len;
-	struct ptnet_csb_gh *ptgh = pq->ptgh;
-	struct ptnet_csb_hg *pthg = pq->pthg;
+	struct nm_csb_atok *atok = pq->atok;
+	struct nm_csb_ktoa *ktoa = pq->ktoa;
 	struct netmap_adapter *na = &sc->ptna->dr.up;
 	struct netmap_kring *kring = na->rx_rings[pq->kring_id];
 	struct netmap_ring *ring = kring->ring;
@@ -2053,21 +2053,21 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 			/* We ran out of slot, let's see if the host has
 			 * added some, by reading hwcur and hwtail from
 			 * the CSB. */
-			ptnet_sync_tail(pthg, kring);
+			ptnet_sync_tail(ktoa, kring);
 
 			if (head == ring->tail) {
 				/* Still no slots available. Reactivate
 				 * interrupts as they were disabled by the
 				 * host thread right before issuing the
 				 * last interrupt. */
-				ptgh->guest_need_kick = 1;
+				atok->appl_need_kick = 1;
 
 				/* Double-check. */
-				ptnet_sync_tail(pthg, kring);
+				ptnet_sync_tail(ktoa, kring);
 				if (likely(head == ring->tail)) {
 					break;
 				}
-				ptgh->guest_need_kick = 0;
+				atok->appl_need_kick = 0;
 			}
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 58a44f0e1..46a43b2fd 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2160,14 +2160,11 @@ struct netmap_pt_guest_adapter {
 int netmap_pt_guest_attach(struct netmap_adapter *na,
 			unsigned int nifp_offset,
 			unsigned int memid);
-struct ptnet_csb_gh;
-struct ptnet_csb_hg;
-bool netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh,
-			struct ptnet_csb_hg *pthg,
-			struct netmap_kring *kring,
-			int flags);
-bool netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh,
-			struct ptnet_csb_hg *pthg,
+bool netmap_pt_guest_txsync(struct nm_csb_atok *atok,
+			struct nm_csb_ktoa *ktoa,
+			struct netmap_kring *kring, int flags);
+bool netmap_pt_guest_rxsync(struct nm_csb_atok *atok,
+			struct nm_csb_ktoa *ktoa,
 			struct netmap_kring *kring, int flags);
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 2a7e8916d..b03516ab7 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -726,26 +726,26 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
  * block (no space in the ring).
  */
 bool
-netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
+netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
 
 	/* Disable notifications */
-	ptgh->guest_need_kick = 0;
+	atok->appl_need_kick = 0;
 
 	/*
 	 * First part: tell the host (updating the CSB) to process the new
 	 * packets.
 	 */
-	kring->nr_hwcur = pthg->hwcur;
-	ptnetmap_guest_write_kring_csb(ptgh, kring->rcur, kring->rhead);
+	kring->nr_hwcur = ktoa->hwcur;
+	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
 
         /* Ask for a kick from a guest to the host if needed. */
 	if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
-		&& NM_ACCESS_ONCE(pthg->host_need_kick)) ||
+		&& NM_ACCESS_ONCE(ktoa->kern_need_kick)) ||
 			(flags & NAF_FORCE_RECLAIM)) {
-		ptgh->sync_flags = flags;
+		atok->sync_flags = flags;
 		notify = true;
 	}
 
@@ -753,7 +753,7 @@ netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
-                ptnetmap_guest_read_kring_csb(pthg, kring);
+                ptnetmap_guest_read_kring_csb(ktoa, kring);
 	}
 
         /*
@@ -763,17 +763,17 @@ netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
          */
 	if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
-		ptgh->guest_need_kick = 1;
+		atok->appl_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(pthg, kring);
+                ptnetmap_guest_read_kring_csb(ktoa, kring);
                 /* If there is new free space, disable notifications */
 		if (unlikely(!nm_kr_txempty(kring))) {
-			ptgh->guest_need_kick = 0;
+			atok->appl_need_kick = 0;
 		}
 	}
 
 	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
-		kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
+		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
 	return notify;
@@ -791,20 +791,20 @@ netmap_pt_guest_txsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
  * block (no more completed slots in the ring).
  */
 bool
-netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
+netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 			struct netmap_kring *kring, int flags)
 {
 	bool notify = false;
 
         /* Disable notifications */
-	ptgh->guest_need_kick = 0;
+	atok->appl_need_kick = 0;
 
 	/*
 	 * First part: import newly received packets, by updating the kring
 	 * hwtail to the hwtail known from the host (read from the CSB).
 	 * This also updates the kring hwcur.
 	 */
-        ptnetmap_guest_read_kring_csb(pthg, kring);
+        ptnetmap_guest_read_kring_csb(ktoa, kring);
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
 	/*
@@ -812,11 +812,11 @@ netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
 	 * released, by updating cur and head in the CSB.
 	 */
 	if (kring->rhead != kring->nr_hwcur) {
-		ptnetmap_guest_write_kring_csb(ptgh, kring->rcur,
+		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
 					       kring->rhead);
                 /* Ask for a kick from the guest to the host if needed. */
-		if (NM_ACCESS_ONCE(pthg->host_need_kick)) {
-			ptgh->sync_flags = flags;
+		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+			atok->sync_flags = flags;
 			notify = true;
 		}
 	}
@@ -828,17 +828,17 @@ netmap_pt_guest_rxsync(struct ptnet_csb_gh *ptgh, struct ptnet_csb_hg *pthg,
          */
 	if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
-                ptgh->guest_need_kick = 1;
+                atok->appl_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(pthg, kring);
+                ptnetmap_guest_read_kring_csb(ktoa, kring);
                 /* If there are new slots, disable notifications. */
 		if (!nm_kr_rxempty(kring)) {
-                        ptgh->guest_need_kick = 0;
+                        atok->appl_need_kick = 0;
                 }
         }
 
 	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
-		kring->name, ptgh->head, ptgh->cur, pthg->hwtail,
+		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
 	return notify;
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index b6788051f..77b52974e 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -64,70 +64,6 @@
 #define PTNET_MDEV_IO_BUF_POOL_OBJSZ	96
 #define PTNET_MDEV_IO_END		100
 
-/*
- * ptnetmap configuration
- *
- * The ptnet kthreads (running in host kernel-space) need to be configured
- * in order to know how to intercept guest kicks (I/O register writes) and
- * how to inject MSI-X interrupts to the guest. The configuration may vary
- * depending on the hypervisor. Currently, we support QEMU/KVM on Linux and
- * and bhyve on FreeBSD.
- * The configuration is passed by the hypervisor to the host netmap module
- * by means of an ioctl() with nr_cmd=NETMAP_PT_HOST_CREATE, and it is
- * specified by the ptnetmap_cfg struct. This struct contains an header
- * with general informations and an array of entries whose size depends
- * on the hypervisor. The NETMAP_PT_HOST_CREATE command is issued every
- * time the kthreads are started.
- */
-struct ptnetmap_cfg {
-#define PTNETMAP_CFGTYPE_QEMU		0x1
-#define PTNETMAP_CFGTYPE_BHYVE		0x2
-	uint16_t cfgtype;	/* how to interpret the cfg entries */
-	uint16_t entry_size;	/* size of a config entry */
-	uint32_t num_rings;	/* number of config entries */
-	void *csb_gh;		/* CSB for guest --> host communication */
-	void *csb_hg;		/* CSB for host --> guest communication */
-	/* Configuration entries are allocated right after the struct. */
-};
-
-/* Configuration of a ptnetmap ring for QEMU. */
-struct ptnetmap_cfgentry_qemu {
-	uint32_t ioeventfd;	/* to intercept guest register access */
-	uint32_t irqfd;		/* to inject guest interrupts */
-};
-
-/* Configuration of a ptnetmap ring for bhyve. */
-struct ptnetmap_cfgentry_bhyve {
-	uint64_t wchan;		/* tsleep() parameter, to wake up kthread */
-	uint32_t ioctl_fd;	/* ioctl fd */
-	/* ioctl parameters to send irq */
-	uint32_t ioctl_cmd;
-	/* vmm.ko MSIX parameters for IOCTL */
-	struct {
-		uint64_t        msg_data;
-		uint64_t        addr;
-	} ioctl_data;
-};
-
-/*
- * Pass a pointer to a userspace buffer to be passed to kernelspace for write
- * or read. Used by NETMAP_PT_HOST_CREATE.
- * XXX deprecated
- */
-static inline void
-nmreq_pointer_put(struct nmreq *nmr, void *userptr)
-{
-	uintptr_t *pp = (uintptr_t *)&nmr->nr_arg1;
-	*pp = (uintptr_t)userptr;
-}
-
-static inline void *
-nmreq_pointer_get(const struct nmreq *nmr)
-{
-	const uintptr_t *pp = (const uintptr_t *)&nmr->nr_arg1;
-	return (void *)*pp;
-}
-
 /* ptnetmap features */
 #define PTNETMAP_F_VNET_HDR        1
 
@@ -157,21 +93,6 @@ nmreq_pointer_get(const struct nmreq *nmr)
 #define PTNETMAP_PTCTL_CREATE		1
 #define PTNETMAP_PTCTL_DELETE		2
 
-/* ptnetmap synchronization variables shared between guest and host */
-struct ptnet_csb_gh {
-	uint32_t head;		  /* GW+ HR+ the head of the guest netmap_ring */
-	uint32_t cur;		  /* GW+ HR+ the cur of the guest netmap_ring */
-	uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */
-	uint32_t sync_flags;	  /* GW+ HR+ the flags of the guest [tx|rx]sync() */
-	char pad[48];		  /* pad to a 64 bytes cacheline */
-};
-struct ptnet_csb_hg {
-	uint32_t hwcur;		  /* GR+ HW+ the hwcur of the host netmap_kring */
-	uint32_t hwtail;	  /* GR+ HW+ the hwtail of the host netmap_kring */
-	uint32_t host_need_kick;  /* GR+ HW+ guest-->host notification enable */
-	char pad[4+48];
-};
-
 #ifdef WITH_PTNETMAP
 
 /* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */
@@ -184,7 +105,7 @@ uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
 /* Guest driver: Write kring pointers (cur, head) to the CSB.
  * This routine is coupled with ptnetmap_host_read_kring_csb(). */
 static inline void
-ptnetmap_guest_write_kring_csb(struct ptnet_csb_gh *ptr, uint32_t cur,
+ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
 			       uint32_t head)
 {
     /*
@@ -207,24 +128,25 @@ ptnetmap_guest_write_kring_csb(struct ptnet_csb_gh *ptr, uint32_t cur,
      *          mb() <-----------> mb()
      *          STORE(head)        LOAD(cur)
      */
-    ptr->cur = cur;
+    atok->cur = cur;
     mb();
-    ptr->head = head;
+    atok->head = head;
 }
 
 /* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
  * This routine is coupled with ptnetmap_host_write_kring_csb(). */
 static inline void
-ptnetmap_guest_read_kring_csb(struct ptnet_csb_hg *pthg, struct netmap_kring *kring)
+ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
+                              struct netmap_kring *kring)
 {
     /*
      * We place a memory barrier to make sure that the update of hwtail never
      * overtakes the update of hwcur.
      * (see explanation in ptnetmap_host_write_kring_csb).
      */
-    kring->nr_hwtail = pthg->hwtail;
+    kring->nr_hwtail = ktoa->hwtail;
     mb();
-    kring->nr_hwcur = pthg->hwcur;
+    kring->nr_hwcur = ktoa->hwcur;
 }
 
 #endif /* WITH_PTNETMAP */

From c9d18de9e4be7fb503c321cdb781b2688c6ac9a1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:27:46 +0200
Subject: [PATCH 1303/2207] sync-kloop: enable eventfds only on linux

---
 sys/dev/netmap/netmap_mem2.c | 4 ++--
 sys/dev/netmap/netmap_pt.c   | 6 +++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 6d992a5ce..8d9315022 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2386,8 +2386,8 @@ netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
 
 	NMA_UNLOCK(nmd);
 
-	nm_prinf("added (ifp=%s,nifp_offset=%u)", ptif->ifp->if_xname,
-						ptif->nifp_offset);
+	nm_prinf("ptnet if added (ifp=%s,nifp_offset=%u)\n",
+		ptif->ifp->if_xname, ptif->nifp_offset);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index b03516ab7..6f1dffd8d 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -51,6 +51,11 @@
 #include 
 #include 
 
+/* Support for eventfd-based notifications. */
+#if defined(linux)
+#define SYNC_KLOOP_POLL
+#endif
+
 /* Functions to read and write CSB fields from the kernel. */
 #if defined (linux)
 #define CSB_READ(csb, field, r) (get_user(r, &csb->field))
@@ -130,7 +135,6 @@ sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 		kring->rhead, kring->rcur, kring->rtail);
 }
 
-#define SYNC_KLOOP_POLL
 struct sync_kloop_ring_args {
 	struct netmap_kring *kring;
 	struct nm_csb_atok *csb_atok;

From c330d48ba32cc834da0a75961ceac319dbfa9916 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:35:40 +0200
Subject: [PATCH 1304/2207] sync-kloop: use wait_queue_t

---
 sys/dev/netmap/netmap_pt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c
index 6f1dffd8d..387b0cd8f 100644
--- a/sys/dev/netmap/netmap_pt.c
+++ b/sys/dev/netmap/netmap_pt.c
@@ -397,7 +397,7 @@ struct sync_kloop_poll_entry {
 	/* Support for receiving notifications from
 	 * a netmap ring or from the application. */
 	struct file *filp;
-	wait_queue_entry_t wait;
+	wait_queue_t wait;
 	wait_queue_head_t *wqh;
 
 	/* Support for sending notifications to the application. */

From 2620b00dc2b2f74a3bc49fb65267c46011634e5e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 12:39:10 +0200
Subject: [PATCH 1305/2207] rename netmap_pt --> netmap_kloop

---
 LINUX/Kbuild.in                                | 2 +-
 sys/dev/netmap/{netmap_pt.c => netmap_kloop.c} | 0
 sys/modules/netmap/Makefile                    | 2 +-
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename sys/dev/netmap/{netmap_pt.c => netmap_kloop.c} (100%)

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index edcc31d7c..0910ebaec 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -8,7 +8,7 @@ SRCDIR:=@SRCDIR@
 # the source is not here so we need to specify a dependency
 $(foreach s,$(SUBSYS),$(eval CONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_)=y))
 
-remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o netmap_pt.o
+remoteobjs-y := netmap_mem2.o netmap_mbq.o netmap_legacy.o netmap_bdg.o netmap_kloop.o
 
 remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_kloop.c
similarity index 100%
rename from sys/dev/netmap/netmap_pt.c
rename to sys/dev/netmap/netmap_kloop.c
diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index bfb6d7fb3..a6f405d3f 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -20,7 +20,7 @@ SRCS	+= netmap_freebsd.c
 SRCS	+= netmap_offloadings.c
 SRCS	+= netmap_pipe.c
 SRCS	+= netmap_monitor.c
-SRCS	+= netmap_pt.c
+SRCS	+= netmap_kloop.c
 SRCS	+= netmap_legacy.c
 SRCS	+= netmap_bdg.c
 SRCS	+= if_ptnet.c

From 5f69af0c172a5e6063966e2e493ff5eb257f3655 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 14:29:45 +0200
Subject: [PATCH 1306/2207] sync-kloop: include linux/eventfd.h

---
 sys/dev/netmap/netmap_kloop.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 387b0cd8f..4f44bb4c1 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -44,6 +44,7 @@
 #elif defined(linux)
 #include 
 #include 
+#include 
 #endif
 
 #include 

From ae2d5c27a53199876c181d87517ca72dbca0bb3a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 17 Oct 2018 15:06:47 +0200
Subject: [PATCH 1307/2207] utils: ctrl-api-test: add test for sync_kloop
 eventfds option

---
 utils/ctrl-api-test.c | 79 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 69 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 50ddfcfda..fa62a9d74 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -13,6 +13,15 @@
 #include 
 #include 
 
+#ifdef __linux__
+#include 
+#else
+static int eventfd(int x, int y)
+{
+	return 19;
+}
+#endif /* __linux__ */
+
 struct TestContext {
 	int fd; /* netmap file descriptor */
 	const char *ifname;
@@ -633,7 +642,7 @@ infinite_options(struct TestContext *ctx)
 static int
 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 {
-#ifdef linux
+#ifdef __linux__
 	char param[256] = "/sys/module/netmap/parameters/";
 	unsigned long oldv;
 	FILE *f;
@@ -660,7 +669,7 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 	}
 	fclose(f);
 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
-#endif /* linux */
+#endif /* __linux__ */
 	return 0;
 }
 
@@ -858,17 +867,11 @@ sync_kloop_worker(void *opaque)
 }
 
 static int
-sync_kloop(struct TestContext *ctx)
+sync_kloop_start_stop(struct TestContext *ctx)
 {
-	int ret;
 	pthread_t th;
 	int thret;
-
-	ctx->nr_flags = NR_EXCLUSIVE;
-	ret           = port_register_hwall(ctx);
-	if (ret) {
-		return ret;
-	}
+	int ret;
 
 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
 	if (ret) {
@@ -889,6 +892,61 @@ sync_kloop(struct TestContext *ctx)
 	return thret;
 }
 
+static int
+sync_kloop(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	return sync_kloop_start_stop(ctx);
+
+}
+
+static int
+sync_kloop_eventfds(struct TestContext *ctx)
+{
+	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
+	int num_entries;
+	size_t opt_size;
+	int ret, i;
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	num_entries = ctx->nr_rx_rings + ctx->nr_tx_rings;
+	opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
+	opt = malloc(opt_size);
+	memset(opt, 0, opt_size);
+	opt->nro_opt.nro_next    = 0;
+	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
+	opt->nro_opt.nro_status  = 0;
+	opt->nro_opt.nro_size    = opt_size;
+	for (i = 0; i < num_entries; i++) {
+		int efd = eventfd(0, 0);
+
+		assert(efd >= 0);
+		opt->eventfds[i].ioeventfd = efd;
+		efd = eventfd(0, 0);
+		assert(efd >= 0);
+		opt->eventfds[i].irqfd     = efd;
+	}
+
+	push_option((struct nmreq_option *)opt, ctx);
+
+	// TODO check for failure ifdef __FreeBSD__
+	// TODO use checkoption
+	return sync_kloop_start_stop(ctx);
+
+}
+
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
@@ -1007,6 +1065,7 @@ static struct mytest tests[] = {
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
 	decltest(sync_kloop),
+	decltest(sync_kloop_eventfds),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_invalid_csb),
 };

From 8b6c60f04d48166820a12fa37e45c147ebb09509 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Oct 2018 09:49:06 +0200
Subject: [PATCH 1308/2207] utils: ctrl-api-test: fix compilation issue on
 freebsd

---
 utils/ctrl-api-test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fa62a9d74..b2218a7cc 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -18,6 +18,8 @@
 #else
 static int eventfd(int x, int y)
 {
+	(void) x;
+	(void) y;
 	return 19;
 }
 #endif /* __linux__ */

From 00ce48642467bf18a7b64cf8542d8d7d6e197e94 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Oct 2018 10:37:54 +0200
Subject: [PATCH 1309/2207] netmap.h: introduce nm_stst_mb()

---
 sys/net/netmap.h | 44 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3da365502..e823909d8 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -739,6 +739,37 @@ struct nm_csb_ktoa {
 	char pad[4+48];
 };
 
+#ifdef __linux__
+
+#ifdef __KERNEL__
+#define nm_stst_barrier smp_wmb
+#else  /* !__KERNEL__ */
+static inline void nm_stst_barrier(void)
+{
+	/* TODO: This implementation works for x86 because of total store
+	 * ordering. Only a compiler barrier is needed. What we really
+	 * need here in the general case is a portable store-store barrier,
+	 * to prevent the two stores from being reordered (e.g. a "release"
+	 * barrier would be ok). */
+	asm volatile("" ::: "memory");
+}
+#endif /* !__KERNEL__ */
+
+#elif defined(__FreeBSD__)
+
+#ifdef _KERNEL
+#define nm_stst_barrier	atomic_thread_fence_rel
+#else  /* !_KERNEL */
+static inline void nm_stst_barrier(void)
+{
+	asm volatile("" ::: "memory");
+}
+#endif /* !_KERNEL */
+
+#else  /* !__linux__ && !__FreeBSD__ */
+#error "OS not supported"
+#endif /* !__linux__ && !__FreeBSD__ */
+
 /* Application side of sync-kloop: Write ring pointers (cur, head) to the CSB.
  * This routine is coupled with sync_kloop_kernel_read(). */
 static inline void
@@ -765,14 +796,9 @@ nm_sync_kloop_appl_write(struct nm_csb_atok *atok, uint32_t cur,
 	 *          mb() <-----------> mb()
 	 *          STORE(head)        LOAD(cur)
 	 *
-	 * TODO: This implementation work for x86 because of total store
-	 * ordering. Only a compiler barrier is needed. What we really
-	 * need here in the general case is a portable store-store barrier,
-	 * to prevent the two stores from being reordered (e.g. a "release"
-	 * barrier would be ok).
 	 */
 	atok->cur = cur;
-	asm volatile("" ::: "memory");
+	nm_stst_barrier();
 	atok->head = head;
 }
 
@@ -786,13 +812,9 @@ nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
 	 * We place a memory barrier to make sure that the update of hwtail never
 	 * overtakes the update of hwcur.
 	 * (see explanation in sync_kloop_kernel_write).
-	 *
-	 * TODO: This implementation works for x86 because loads are not reordered
-	 * after loads. What we need here is a portable load-load barrier, e.g.
-	 * an "acquire" barrier would be ok.
 	 */
 	*hwtail = ktoa->hwtail;
-	asm volatile("" ::: "memory");
+	nm_stst_barrier();
 	*hwcur = ktoa->hwcur;
 }
 

From 69557d7fdf710dc44c1550dd47c3364d214caa10 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Oct 2018 14:48:21 +0200
Subject: [PATCH 1310/2207] pkt-gen: fix compilation issue

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index ab986920d..05e94975f 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1553,7 +1553,7 @@ sender_body(void *data)
 	    for (i = 0; !targ->cancel && (n == 0 || sent < n); i++) {
 		if (pcap_inject(p, frame, size) != -1)
 			sent++;
-		update_addresses(pkt, targ->g);
+		update_addresses(pkt, targ);
 		if (i > 10000) {
 			targ->ctr.pkts = sent;
 			targ->ctr.bytes = sent*size;

From 079e23214bd7791fa4ddba84c595a0dd502be095 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Oct 2018 15:23:35 +0200
Subject: [PATCH 1311/2207] import pkt-gen.8 man page from freebsd

---
 apps/pkt-gen/pkt-gen.8 | 179 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)
 create mode 100644 apps/pkt-gen/pkt-gen.8

diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
new file mode 100644
index 000000000..62f1d30a1
--- /dev/null
+++ b/apps/pkt-gen/pkt-gen.8
@@ -0,0 +1,179 @@
+.\" Copyright (c) 2016, George V. Neville-Neil
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright notice,
+.\"    this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2016
+.Dt PKT-GEN 8
+.Os
+.Sh NAME
+.Nm pkt-gen
+.Nd Packet generator for use with
+.Xr netmap 4
+.Sh SYNOPSIS
+.Bl -item -compact
+.It
+.Nm
+.Op Fl i Ar interface
+.Op Fl f Ar function
+.Op Fl n Ar count
+.Op Fl t Ar pkts_to_send
+.Op Fl r Ar pkts_to_receive
+.Op Fl l Ar pkt_size
+.Op Fl d Ar dst_ip[:port[-dst_ip:port]]
+.Op Fl s Ar src_ip[:port[-src_ip:port]]
+.Op Fl D Ar dst-mac
+.Op Fl S Ar src-mac
+.Op Fl a Ar cpu_id
+.Op Fl b Ar burst size
+.Op Fl c Ar cores
+.Op Fl p Ar threads
+.Op Fl T Ar report_ms
+.Op Fl P
+.Op Fl w Ar wait_for_link_time
+.Op Fl R Ar rate
+.Op Fl X
+.Op Fl H Ar len
+.Op Fl P Ar xfile
+.Op Fl z
+.Op Fl Z
+.Sh DESCRIPTION
+.Nm
+generates and receives raw network packets using
+.Xr netmap 4 .
+The arguments are as follows:
+.Pp
+.Bl -tag -width Ds
+.It Fl i Ar interface
+Network interface name.
+.It Fl f Ar function tx rx ping pong
+Set the function to transmit, receive of ping/pong.
+.It Fl n count
+Number of iterations (can be 0).
+.It Fl t pkts_to_send
+Number of packets to send.  Also forces transmit mode.
+.It Fl r Ar pkts_to_receive
+Number of packets to receive.  Also forces rx mode.
+.It Fl l Ar pkt_size
+Packet size in bytes excluding CRC.
+.It Fl d Ar dst_ip[:port[-dst_ip:port]]
+Destination IPv4 address and port, single or range.
+.It Fl s Ar src_ip[:port[-src_ip:port]]
+Source IPv4 address and port, single or range.
+.It Fl D Ar dst-mac
+Destination MAC address in colon notation.
+.It Fl S Ar src-mac
+Source MAC address in colon notation.
+.It Fl a Ar cpu_id
+Tie
+.Nm
+to a particular CPU core using
+.Xr setaffinity 2.
+.It Fl b Ar burst size
+Set the size of a burst of packets.
+.It Fl c Ar cores
+Number of cores to use.
+.It Fl p Ar threads
+Number of threads to use.
+.It Fl T Ar report_ms
+Number of milliseconds between reports.
+.It Fl P
+Use libpcap instead of netmap for reading or writing.
+.It Fl w Ar wait_for_link_time
+Number of seconds to wait to make sure that the network link is up.  A
+network device driver may take some time to create a new
+transmit/receive ring pair when
+.Xr netmap 4
+requests one.
+.It Fl R Ar rate
+Packet transmission rate.  Not setting the packet transmission rate tells
+.Nm
+to transmit packets as quickly as possible.  On servers from 2010 on-wards
+.Xr netmap 4
+is able to completely use all of the bandwidth of a 10 or 40Gbps link,
+so this option should be used unless your intention is to saturate the link.
+.It Fl X
+Dump payload transmitted or received.
+.It Fl H Ar len
+Add empty virtio-net-header with size 'len'.  This option is only use
+with Virtual Machine technologies that use virtio as a network interface.
+.It Fl P Ar file
+Load the packet from a pcap file rather than constructing it inside of
+.Nm
+.It Fl z
+Use random IPv4 src address/port
+.It Fl Z
+Use random IPv4 dst address/port
+.El
+.Pp
+.Nm
+is a raw packet generator that can utilize either
+.Xr netmap 4
+or
+.Xr bpf 4
+but which is most often uses with
+.Xr netmap 4 .
+The
+.Ar interface name
+used depends upon how the underlying Ethernet driver exposes its
+transmit and receive rings to
+.Xr netmap 4 .
+Most modern network interfaces that support 10Gbps and higher speeds
+have several transmit and receive rings that are used by the operating
+system to balance traffic across the interface.
+.Nm
+can peel off one or more of the transmit or receive rings for its own
+use without interfering with packets that might otherwise be destined
+for the host.  For example on a system with a Chelsio Network
+Interface Card (NIC) the interface specification of
+.Ar -i netmap:ncxl0
+gives
+.Nm
+access to a pair of transmit and receive rings that are separate from
+the more commonly known cxl0 interface, which is used by the operating
+system's TCP/IP stack.
+.Sh EXAMPLES
+Capture and count all packets arriving on the operating system's cxl0
+interface.  Using this will block packets from reaching the operating
+system's network stack.
+.Dl
+.Pp
+.Nm
+-i cxl0 -f rx
+.Pp
+Send a stream of fake DNS packets between two hosts with a packet
+length of 128 bytes.  You must set the destination MAC address for
+packets to be received by the target host.
+.Pp
+.Dl
+.Nm
+-i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 -D 00:07:43:29:2a:e0
+.Sh FILES
+.Xr netmap 4
+.Sh SEE ALSO
+.Xr netmap 4
+.Sh AUTHORS
+This manual page was written by
+.An George V. Neville-Neil Aq gnn@FreeBSD.org .

From 15ec10e7520acc0326c614d97592783e986019b2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 18 Oct 2018 15:44:19 +0200
Subject: [PATCH 1312/2207] apps: install man pages for all the available
 applications

---
 apps/bridge/GNUmakefile   | 1 +
 apps/pkt-gen/GNUmakefile  | 1 +
 apps/vale-ctl/GNUmakefile | 1 +
 3 files changed, 3 insertions(+)

diff --git a/apps/bridge/GNUmakefile b/apps/bridge/GNUmakefile
index a6c63e99d..b2c4d4d74 100644
--- a/apps/bridge/GNUmakefile
+++ b/apps/bridge/GNUmakefile
@@ -31,6 +31,7 @@ install: $(PROGS:%=install-%)
 
 install-%:
 	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*
+	-install -D -m 644 $(SRCDIR)/apps/bridge/bridge.8 $(DESTDIR)/$(MAN_PREFIX)/man8/bridge.8
 
 bridge-b: bridge-b.o
 
diff --git a/apps/pkt-gen/GNUmakefile b/apps/pkt-gen/GNUmakefile
index e65709b81..25841e844 100644
--- a/apps/pkt-gen/GNUmakefile
+++ b/apps/pkt-gen/GNUmakefile
@@ -37,6 +37,7 @@ install: $(PROGS:%=install-%)
 
 install-%:
 	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*
+	-install -D -m 644 $(SRCDIR)/apps/pkt-gen/pkt-gen.8 $(DESTDIR)/$(MAN_PREFIX)/man8/pkt-gen.8
 
 pkt-gen-b: pkt-gen-b.o
 
diff --git a/apps/vale-ctl/GNUmakefile b/apps/vale-ctl/GNUmakefile
index c417e92b6..68245a15a 100644
--- a/apps/vale-ctl/GNUmakefile
+++ b/apps/vale-ctl/GNUmakefile
@@ -37,3 +37,4 @@ install: $(PROGS:%=install-%)
 
 install-%:
 	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*
+	-install -D -m 644 $(SRCDIR)/apps/vale-ctl/vale-ctl.8 $(DESTDIR)/$(MAN_PREFIX)/man8/vale-ctl.8

From 0474a18ec302f01e9cb2930e0a44d26ae0e821d3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Oct 2018 10:34:40 +0200
Subject: [PATCH 1313/2207] netmap.h: add comments for sync-kloop structs

---
 sys/net/netmap.h | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e823909d8..da4ec157a 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -708,15 +708,19 @@ struct nmreq_pools_info {
  * Start an in-kernel loop that syncs the rings periodically or on
  * notifications. The loop runs in the context of the ioctl syscall,
  * and only stops on NETMAP_REQ_SYNC_KLOOP_STOP.
- * The user must specify the start address of the Communication Status Block
- * (CSB) entries to be used for both directions (kernel read application
- * writes, and kernel writes application read). The number of entries
- * must agree with the number of rings bound to the netmap file descriptor.
+ * The user must specify the start address of two arrays of Communication
+ * Status Block (CSB) entries, for the two directions (kernel read
+ * application write, and kernel write application read). The number of
+ * entries must agree with the number of rings bound to the netmap file
+ * descriptor. The entries corresponding to the TX rings are laid out before
+ * the ones corresponding to the RX rings.
  */
 struct nmreq_sync_kloop_start {
-	/* CSB entries for application --> kernel communication (N entries). */
+	/* Array of CSB entries for application --> kernel communication
+	 * (N entries). */
 	uint64_t csb_atok;
-	/* CSB for kernel --> application communication (N entries). */
+	/* Array of CSB entries for kernel --> application communication
+	 * (N entries). */
 	uint64_t csb_ktoa;
 	/* Sleeping is the default synchronization method for the kloop.
 	 * The 'sleep_us' field specifies how many microsconds to sleep
@@ -825,11 +829,15 @@ nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
 struct nmreq_opt_sync_kloop_eventfds {
 	struct nmreq_option	nro_opt;	/* common header */
 	/* An array of N entries for bidirectional notifications between
-	 * the kernel loop and the application. The number of entries must
-	 * agree with the number of rings bound to the netmap file descriptor.
+	 * the kernel loop and the application. The number of entries and
+	 * their order must agree with the CSB arrays passed in the
+	 * NETMAP_REQ_SYNC_KLOOP_START message. Each entry contains a file
+	 * descriptor backed by an eventfd.
 	 */
 	struct {
+		/* Notifier for the application --> kernel loop direction. */
 		int32_t ioeventfd;
+		/* Notifier for the kernel loop --> application direction. */
 		int32_t irqfd;
 	} eventfds[0];
 };

From 1fc6c2b188fecd7fa43c012ce6d492c4f3b99898 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Oct 2018 10:56:10 +0200
Subject: [PATCH 1314/2207] netmap.h: use GCC __atomic built-ins to implement
 memory barriers

---
 sys/net/netmap.h | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index da4ec157a..3af85f7a7 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -750,12 +750,10 @@ struct nm_csb_ktoa {
 #else  /* !__KERNEL__ */
 static inline void nm_stst_barrier(void)
 {
-	/* TODO: This implementation works for x86 because of total store
-	 * ordering. Only a compiler barrier is needed. What we really
-	 * need here in the general case is a portable store-store barrier,
-	 * to prevent the two stores from being reordered (e.g. a "release"
-	 * barrier would be ok). */
-	asm volatile("" ::: "memory");
+	/* A memory barrier with release semantic has the combined
+	 * effect of a store-store barrier and a load-store barrier,
+	 * which is fine for us. */
+	__atomic_thread_fence(__ATOMIC_RELEASE);
 }
 #endif /* !__KERNEL__ */
 
@@ -766,7 +764,7 @@ static inline void nm_stst_barrier(void)
 #else  /* !_KERNEL */
 static inline void nm_stst_barrier(void)
 {
-	asm volatile("" ::: "memory");
+	__atomic_thread_fence(__ATOMIC_RELEASE);
 }
 #endif /* !_KERNEL */
 

From b24d165172054eee8e79257637272c731a7ef9a0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Oct 2018 11:07:56 +0200
Subject: [PATCH 1315/2207] sync-kloop: remove log statement

---
 sys/dev/netmap/netmap_kloop.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index d00c9485c..dc26704ea 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -433,7 +433,6 @@ sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 	init_waitqueue_entry(&entry->wait, current);
 	add_wait_queue(wqh, &entry->wait);
 	poll_ctx->next_entry++;
-	nm_prinf("poll entry #%d filled\n", poll_ctx->next_entry);
 }
 #endif  /* SYNC_KLOOP_POLL */
 

From 46fd32572fe0118e98a6c7f37dd5c623b3143154 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Oct 2018 11:14:48 +0200
Subject: [PATCH 1316/2207] netmap.h: options: add comments for nro_size field

---
 sys/net/netmap.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3af85f7a7..d288ac61f 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -477,7 +477,9 @@ struct nmreq_option {
 	 * !=0: errno value
 	 */
 	uint32_t		nro_status;
-	/* Option size, used only by variable-size options. */
+	/* Option size, used only for options that can have variable size
+	 * (e.g. because they contain arrays). For fixed-size options this
+	 * field should be set to zero. */
 	uint64_t		nro_size;
 };
 

From b4e4f41c01edeb8201734d2c6f4fcec5f78e5ee0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Oct 2018 12:49:52 +0200
Subject: [PATCH 1317/2207] utils: randomized_tests: check that vale-ctl is
 installed

---
 utils/randomized_tests | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 2d51c8ddb..db1d3bdb0 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -5,8 +5,14 @@
 ################################################################################
 
 if [ "$EUID" -ne "0" ]; then
-   echo "This script must be run as root"
-   exit 1
+	echo "This script must be run as root"
+	exit 1
+fi
+
+which vale-ctl
+if [ "$?" != "0" ]; then
+	echo "vale-ctl program not not found"
+	exit 1
 fi
 
 random_num="$((65 + $RANDOM % 58))"

From 7ec0e64da9a76de0877e995f23e80c5c92ec11af Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 19 Oct 2018 15:44:23 +0200
Subject: [PATCH 1318/2207] linux: virtio_net.c: also drain RX virtqueues when
 entering netmap mode

The NAPI (used for RX) is disabled when entering netmap mode, so the
driver cannot call virtqueue_get_buf() while the nm_register is detaching
unused RX buffers from the avail ring. However, it is possible that the used
ring has some pending entries (to be consumed by the guest) at that time.
If we don't drain those, detaching the pending avail entries in the RX
virtqueue will result into a "is not a head" bug on the next call to
virtqueue_get_buf().
---
 LINUX/if_virtio_net_netmap.h | 54 +++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 26 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 24d296dc4..51b007384 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -303,11 +303,30 @@ void virtio_device_ready(struct virtio_device *dev)
 static int virtnet_open(struct net_device *dev);
 static int virtnet_close(struct net_device *dev);
 
+static void
+virtio_net_netmap_free_os_buf(struct virtnet_info *vi, enum txrx t,
+			      int idx, void *buf)
+{
+	if (t == NR_TX) {
+		dev_kfree_skb(buf);
+	} else {
+		if (vi->mergeable_rx_bufs) {
+			unsigned long ctx = (unsigned long)buf;
+			void *base = mergeable_ctx_to_buf_address(ctx);
+			put_page(virt_to_head_page(base));
+		} else if (vi->big_packets) {
+			give_pages(&vi->rq[idx], buf);
+		} else {
+			dev_kfree_skb(buf);
+		}
+	}
+}
+
 static void
 virtio_net_netmap_detach_unused(struct virtnet_info *vi, bool onoff,
-				enum txrx t, int i)
+				enum txrx t, int idx)
 {
-	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
+	struct virtqueue* vq = (t == NR_RX) ? vi->rq[idx].vq : vi->sq[idx].vq;
 	unsigned int n = 0;
 	void *buf;
 
@@ -315,55 +334,38 @@ virtio_net_netmap_detach_unused(struct virtnet_info *vi, bool onoff,
 		if (!onoff) {
 			/* This is a netmap buffer, so there is
 			 * nothing to do. */
-		} else if (t == NR_TX) {
-			dev_kfree_skb(buf);
 		} else {
-			if (vi->mergeable_rx_bufs) {
-				unsigned long ctx = (unsigned long)buf;
-				void *base = mergeable_ctx_to_buf_address(ctx);
-				put_page(virt_to_head_page(base));
-			} else if (vi->big_packets) {
-				give_pages(&vi->rq[i], buf);
-			} else {
-				dev_kfree_skb(buf);
-			}
+			virtio_net_netmap_free_os_buf(vi, t, idx, buf);
 		}
 		n++;
 	}
 
 	if (n)
 		nm_prinf("%d sgs detached on %s-%d (onoff=%d)\n",
-			 n, nm_txrx2str(t), i, onoff);
+			 n, nm_txrx2str(t), idx, onoff);
 }
 
 static void
 virtio_net_netmap_drain_used(struct virtnet_info *vi, bool onoff,
-				enum txrx t, int i)
+				enum txrx t, int idx)
 {
-	struct virtqueue* vq = (t == NR_RX) ? vi->rq[i].vq : vi->sq[i].vq;
+	struct virtqueue* vq = (t == NR_RX) ? vi->rq[idx].vq : vi->sq[idx].vq;
 	unsigned int len, n = 0;
 	void *buf;
 
-	if (onoff && t == NR_RX) {
-		/* An RX kring is entering netmap mode. Since NAPI has
-		 * been disabled, there cannot be any pending used
-		 * buffers. */
-		return;
-	}
-
 	while ((buf = virtqueue_get_buf(vq, &len)) != NULL) {
 		if (!onoff) {
 			/* This is a netmap buffer, so there is
 			 * nothing to do. */
-		} else if (t == NR_TX) {
-			dev_kfree_skb(buf);
+		} else {
+			virtio_net_netmap_free_os_buf(vi, t, idx, buf);
 		}
 		n++;
 	}
 
 	if (n)
 		nm_prinf("%d sgs drained on %s-%d (onoff=%d)\n",
-			n, nm_txrx2str(t), i, onoff);
+			n, nm_txrx2str(t), idx, onoff);
 }
 
 /* Initialize scatter-gather lists used to publish netmap

From bfaa1f051ec12b100ad1c6dd7e58f952d7080435 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Oct 2018 10:57:25 +0200
Subject: [PATCH 1319/2207] netmap_bdg.h: add missing header

---
 sys/dev/netmap/netmap_bdg.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 3bf5c15a8..8d0c3b579 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -1,3 +1,30 @@
+/*
+ * Copyright (C) 2013-2018 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
 #ifndef _NET_NETMAP_BDG_H_
 #define _NET_NETMAP_BDG_H_
 

From db221e3b5934dfbf1df81d452446b10d539dd159 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Oct 2018 11:17:40 +0200
Subject: [PATCH 1320/2207] apps: bridge: fix manual page using igor and mandoc

---
 apps/bridge/bridge.8 | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/apps/bridge/bridge.8 b/apps/bridge/bridge.8
index d791d9456..f94fe69b9 100644
--- a/apps/bridge/bridge.8
+++ b/apps/bridge/bridge.8
@@ -24,12 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 16, 2016
+.Dd October 23, 2018
 .Dt BRIDGE 1
 .Os
 .Sh NAME
 .Nm bridge
-.Nd A netmap client to bridge two network interfaces (or one interface and the host stack).
+.Nd A netmap client to bridge two network interfaces (or one interface and the host stack)
 .Sh SYNOPSIS
 .Bk -words
 .Bl -tag -width "bridge"
@@ -39,21 +39,23 @@
 .Op Fl w Ar wait-link
 .Op Fl v
 .Op Fl c
+.El
+.Ek
 .Sh DESCRIPTION
 .Nm
-is a simple netmap application that bridges packets between two netmap ports. If the two netmap
-ports use the same netmap memory region
+is a simple netmap application that bridges packets between two netmap ports.
+If the two netmap ports use the same netmap memory region
 .Nm
 operates in zero copy (unless explicitly prevented by the
 .Fl c
 flag).
-.El
 .Bl -tag -width Ds
 .It Fl i Ar port
-Name of the netmap port. It can be supplied up to two times to identifiy
-the ports that must be bridged. Any netmap port type (physical interface, VALE switch, pipe, monitor port...)
-can be used. If the option is supplied only once, then it must be
-for a physical interface and, in that case,
+Name of the netmap port.
+It can be supplied up to two times to identify the ports that must be bridged.
+Any netmap port type (physical interface, VALE switch, pipe, monitor port...)
+can be used.
+If the option is supplied only once, then it must be for a physical interface and, in that case,
 .Nm
 will bridge the port and the host stack.
 .It Fl b Ar batch-size

From 3a181dd06c78ee2a82449cfe13fe3fdc1a4da05d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 Oct 2018 15:22:56 +0200
Subject: [PATCH 1321/2207] linux/drivers: patches for 4.19

---
 ...0--99999 => vanilla--veth.c--30f00--41300} |  0
 .../vanilla--veth.c--41300--99999             | 42 +++++++++++++++++++
 2 files changed, 42 insertions(+)
 rename LINUX/final-patches/{vanilla--veth.c--30f00--99999 => vanilla--veth.c--30f00--41300} (100%)
 create mode 100644 LINUX/final-patches/vanilla--veth.c--41300--99999

diff --git a/LINUX/final-patches/vanilla--veth.c--30f00--99999 b/LINUX/final-patches/vanilla--veth.c--30f00--41300
similarity index 100%
rename from LINUX/final-patches/vanilla--veth.c--30f00--99999
rename to LINUX/final-patches/vanilla--veth.c--30f00--41300
diff --git a/LINUX/final-patches/vanilla--veth.c--41300--99999 b/LINUX/final-patches/vanilla--veth.c--41300--99999
new file mode 100644
index 000000000..6d1e573bf
--- /dev/null
+++ b/LINUX/final-patches/vanilla--veth.c--41300--99999
@@ -0,0 +1,42 @@
+diff --git a/veth.c b/veth.c
+index 41a00cd76955..ce884d392a01 100644
+--- a/veth.c
++++ b/veth.c
+@@ -60,6 +60,10 @@ struct veth_priv {
+ 	unsigned int		requested_headroom;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /*
+  * ethtool interface
+  */
+@@ -765,7 +769,6 @@ static int veth_open(struct net_device *dev)
+ 		netif_carrier_on(dev);
+ 		netif_carrier_on(peer);
+ 	}
+-
+ 	return 0;
+ }
+ 
+@@ -825,12 +828,18 @@ static int veth_dev_init(struct net_device *dev)
+ 		return err;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	veth_netmap_attach(dev);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ }
+ 
+ static void veth_dev_free(struct net_device *dev)
+ {
+ 	veth_free_queues(dev);
++#ifdef DEV_NETMAP
++	netmap_detach(dev);
++#endif /* DEV_NETMAP */
+ 	free_percpu(dev->vstats);
+ }
+ 

From 51e5667157678d4b936388a3c5fe3fbc83499f04 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Oct 2018 12:19:13 +0200
Subject: [PATCH 1322/2207] man: bridge: update from freebsd

---
 apps/bridge/bridge.8 | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/apps/bridge/bridge.8 b/apps/bridge/bridge.8
index f94fe69b9..9ba4cb73a 100644
--- a/apps/bridge/bridge.8
+++ b/apps/bridge/bridge.8
@@ -1,5 +1,4 @@
 .\" Copyright (c) 2016 Luigi Rizzo, Universita` di Pisa
-.\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
@@ -25,11 +24,11 @@
 .\" $FreeBSD$
 .\"
 .Dd October 23, 2018
-.Dt BRIDGE 1
+.Dt BRIDGE 8
 .Os
 .Sh NAME
 .Nm bridge
-.Nd A netmap client to bridge two network interfaces (or one interface and the host stack)
+.Nd netmap client to bridge two netmap ports
 .Sh SYNOPSIS
 .Bk -words
 .Bl -tag -width "bridge"
@@ -46,9 +45,10 @@
 is a simple netmap application that bridges packets between two netmap ports.
 If the two netmap ports use the same netmap memory region
 .Nm
-operates in zero copy (unless explicitly prevented by the
+forwards packets without copying the packets payload (zero-copy mode), unless
+explicitly prevented by the
 .Fl c
-flag).
+flag.
 .Bl -tag -width Ds
 .It Fl i Ar port
 Name of the netmap port.
@@ -69,6 +69,9 @@ Enable verbose mode
 .It Fl c
 Disable zero-copy mode.
 .El
+.Sh SEE ALSO
+.Xr netmap 4 ,
+.Xr pkt-gen 8
 .Sh AUTHORS
 .An -nosplit
 .Nm

From 7981065d2657d8378f64a808d3d708e4ed424a2b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 15:13:56 +0200
Subject: [PATCH 1323/2207] pkt-gen: support NS_MOREFRAG in TX

---
 apps/pkt-gen/pkt-gen.c | 122 ++++++++++++++++++++++++++---------------
 1 file changed, 77 insertions(+), 45 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 05e94975f..bfe7f3efd 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -262,7 +262,8 @@ struct glob_arg {
 	int burst;
 	int forever;
 	uint64_t npackets;	/* total packets to send */
-	int frags;	/* fragments per packet */
+	int frags;		/* fragments per packet */
+	u_int mtu;		/* size of each fragment */
 	int nthreads;
 	int cpus;	/* cpus used for running */
 	int system_cpus;	/* cpus on the system */
@@ -334,6 +335,8 @@ struct targ {
 	struct pkt pkt;
 	void *frame;
 	uint16_t seed[3];
+	u_int frags;
+	u_int frag_size;
 };
 
 static __inline uint16_t
@@ -1108,7 +1111,6 @@ set_vnet_hdr_len(struct glob_arg *g)
 	}
 }
 
-
 /*
  * create and enqueue a batch of packets on a ring.
  * On the last one set NS_REPORT to tell the driver to generate
@@ -1116,19 +1118,14 @@ set_vnet_hdr_len(struct glob_arg *g)
  */
 static int
 send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
-		int size, struct targ *t, u_int count, int options,
-		u_int nfrags)
+		int size, struct targ *t, u_int count, int options)
 {
 	u_int n, sent, cur = ring->cur;
-	u_int fcnt;
+	u_int frags = t->frags;
+	u_int frag_size = t->frag_size;
+	struct netmap_slot *slot = &ring->slot[cur];
 
 	n = nm_ring_space(ring);
-	if (n < count)
-		count = n;
-	if (count < nfrags) {
-		D("truncating packet, no room for frags %d %d",
-				count, nfrags);
-	}
 #if 0
 	if (options & (OPT_COPY | OPT_PREFETCH) ) {
 		for (sent = 0; sent < count; sent++) {
@@ -1141,10 +1138,14 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		cur = ring->cur;
 	}
 #endif
-	for (fcnt = nfrags, sent = 0; sent < count; sent++) {
-		struct netmap_slot *slot = &ring->slot[cur];
-		char *p = NETMAP_BUF(ring, slot->buf_idx);
-		int buf_changed = slot->flags & NS_BUF_CHANGED;
+	for (sent = 0; sent < count && n >= frags; sent++, n--) {
+		char *p;
+		int buf_changed;
+		u_int tosend = size;
+
+		slot = &ring->slot[cur];
+		p = NETMAP_BUF(ring, slot->buf_idx);
+		buf_changed = slot->flags & NS_BUF_CHANGED;
 
 		slot->flags = 0;
 		if (options & OPT_RUBBISH) {
@@ -1152,31 +1153,46 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		} else if (options & OPT_INDIRECT) {
 			slot->flags |= NS_INDIRECT;
 			slot->ptr = (uint64_t)((uintptr_t)frame);
-		} else if ((options & OPT_COPY) || buf_changed) {
-			nm_pkt_copy(frame, p, size);
-			if (fcnt == nfrags)
-				update_addresses(pkt, t);
-		} else if (options & OPT_MEMCPY) {
-			memcpy(p, frame, size);
-			if (fcnt == nfrags)
-				update_addresses(pkt, t);
+		} else if (frags > 1) {
+			u_int i;
+			const char *f = frame;
+			struct netmap_slot *fslot = slot;
+			char *fp = p;
+			for (i = 0; i < frags - 1; i++) {
+				memcpy(fp, f, frag_size);
+				fslot->len = frag_size;
+				fslot->flags = NS_MOREFRAG;
+				if (options & OPT_DUMP)
+					dump_payload(fp, frag_size, ring, cur);
+				tosend -= frag_size;
+				f += frag_size;
+				cur = nm_ring_next(ring, cur);
+				fslot = &ring->slot[cur];
+				fp = NETMAP_BUF(ring, fslot->buf_idx);
+			}
+			n -= (frags - 1);
+			p = fp;
+			fslot->flags = 0;
+			memcpy(p, f, tosend);
+			update_addresses(pkt, t);
+		} else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) {
+			if (options & OPT_COPY)
+				nm_pkt_copy(frame, p, size);
+			else
+				memcpy(p, frame, size);
+			update_addresses(pkt, t);
 		} else if (options & OPT_PREFETCH) {
 			__builtin_prefetch(p);
 		}
+		slot->len = tosend;
 		if (options & OPT_DUMP)
-			dump_payload(p, size, ring, cur);
-		slot->len = size;
-		if (--fcnt > 0)
-			slot->flags |= NS_MOREFRAG;
-		else
-			fcnt = nfrags;
-		if (sent == count - 1) {
-			slot->flags &= ~NS_MOREFRAG;
-			slot->flags |= NS_REPORT;
-		}
+			dump_payload(p, tosend, ring, cur);
 		cur = nm_ring_next(ring, cur);
 	}
-	ring->head = ring->cur = cur;
+	if (sent) {
+		slot->flags |= NS_REPORT;
+		ring->head = ring->cur = cur;
+	}
 
 	return (sent);
 }
@@ -1564,9 +1580,21 @@ sender_body(void *data)
 #endif /* NO_PCAP */
     } else {
 	int tosend = 0;
-	int frags = targ->g->frags;
+	u_int bufsz, mtu = targ->g->mtu;
 
 	nifp = targ->nmd->nifp;
+	txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
+	bufsz = txring->nr_buf_size;
+	if (bufsz < mtu)
+		mtu = bufsz;
+	targ->frag_size = targ->g->pkt_size / targ->frags;
+	if (targ->frag_size > mtu) {
+		targ->frags = targ->g->pkt_size / mtu;
+		targ->frag_size = mtu;
+		if (targ->g->pkt_size % mtu != 0)
+			targ->frags++;
+	}
+	D("frags %u frag_size %u", targ->frags, targ->frag_size);
 	while (!targ->cancel && (n == 0 || sent < n)) {
 		int rv;
 
@@ -1619,8 +1647,6 @@ sender_body(void *data)
 			txring = NETMAP_TXRING(nifp, i);
 			if (nm_ring_empty(txring))
 				continue;
-			if (frags > 1)
-				limit = ((limit + frags - 1) / frags) * frags;
 
 			if (targ->g->pkt_min_size > 0) {
 				size = nrand48(targ->seed) %
@@ -1628,9 +1654,9 @@ sender_body(void *data)
 					targ->g->pkt_min_size;
 			}
 			m = send_packets(txring, pkt, frame, size, targ,
-					 limit, options, frags);
-			ND("limit %lu tail %d frags %d m %d",
-				limit, txring->tail, frags, m);
+					 limit, options);
+			ND("limit %lu tail %d m %d",
+				limit, txring->tail, m);
 			sent += m;
 			if (m > 0) //XXX-ste: can m be 0?
 				event++;
@@ -2307,6 +2333,7 @@ usage(int errcode)
 		     "\t-z			use random IPv4 src address/port\n"
 		     "\t-Z			use random IPv4 dst address/port\n"
 		     "\t-F num_frags		send multi-slot packets\n"
+		     "\t-M			set MTU\n"
 		     "\t-A			activate pps stats on receiver\n"
 		     "\t-4			IPv4\n"
 		     "\t-6			IPv6\n"
@@ -2403,7 +2430,7 @@ start_threads(struct glob_arg *g) {
 				t->nmd = g->nmd;
 			}
 			t->fd = t->nmd->fd;
-
+			t->frags = g->frags;
 		} else {
 			targs[i].fd = g->main_fd;
 		}
@@ -2685,13 +2712,14 @@ main(int arc, char **argv)
 	g.cpus = 1;		/* default */
 	g.forever = 1;
 	g.tx_rate = 0;
-	g.frags = 1;
+	g.frags =1;
+	g.mtu = 1500;
 	g.nmr_config = "";
 	g.virt_header = 0;
 	g.wait_link = 2;	/* wait 2 seconds for physical ports */
 
 	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
-	    "T:w:WvR:XC:H:e:E:m:rP:zZAhB")) != -1) {
+	    "T:w:WvR:XC:H:e:E:m:rP:zZAhBM:")) != -1) {
 
 		switch(ch) {
 		default:
@@ -2727,6 +2755,10 @@ main(int arc, char **argv)
 			g.frags = i;
 			break;
 
+		case 'M':
+			g.mtu = atoi(optarg);
+			break;
+
 		case 'f':
 			for (fn = func; fn->key; fn++) {
 				if (!strcmp(fn->key, optarg))
@@ -3082,8 +3114,8 @@ main(int arc, char **argv)
 		int lim = (g.tx_rate)/300;
 		if (g.burst > lim)
 			g.burst = lim;
-		if (g.burst < g.frags)
-			g.burst = g.frags;
+		if (g.burst == 0)
+			g.burst = 1;
 		x = ((uint64_t)1000000000 * (uint64_t)g.burst) / (uint64_t) g.tx_rate;
 		g.tx_period.tv_nsec = x;
 		g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000;

From e64c431e1a9ea3b32e539d81b9e5a7ca16c746fa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 15:53:12 +0200
Subject: [PATCH 1324/2207] pkt-gen: fix slot usage when passing NS_MOREFRAG

---
 apps/pkt-gen/pkt-gen.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index bfe7f3efd..905cdbb47 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1156,23 +1156,22 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		} else if (frags > 1) {
 			u_int i;
 			const char *f = frame;
-			struct netmap_slot *fslot = slot;
 			char *fp = p;
 			for (i = 0; i < frags - 1; i++) {
 				memcpy(fp, f, frag_size);
-				fslot->len = frag_size;
-				fslot->flags = NS_MOREFRAG;
+				slot->len = frag_size;
+				slot->flags = NS_MOREFRAG;
 				if (options & OPT_DUMP)
 					dump_payload(fp, frag_size, ring, cur);
 				tosend -= frag_size;
 				f += frag_size;
 				cur = nm_ring_next(ring, cur);
-				fslot = &ring->slot[cur];
-				fp = NETMAP_BUF(ring, fslot->buf_idx);
+				slot = &ring->slot[cur];
+				fp = NETMAP_BUF(ring, slot->buf_idx);
 			}
 			n -= (frags - 1);
 			p = fp;
-			fslot->flags = 0;
+			slot->flags = 0;
 			memcpy(p, f, tosend);
 			update_addresses(pkt, t);
 		} else if ((options & (OPT_COPY | OPT_MEMCPY)) || buf_changed) {

From c49ea41e456eacfc03c632f8b68240d00ab2e28d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 16:06:06 +0200
Subject: [PATCH 1325/2207] linux/ixgbe: do not espose incomplete packets

---
 LINUX/ixgbe_netmap_linux.h | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 5d9dba7e9..59474086b 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -518,6 +518,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+	int complete; /* did we see a complete packet ? */
 
 	/* device-specific */
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
@@ -565,7 +566,8 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			staterr = le32toh(curr->wb.upper.status_error);
 
 			slot->len = size;
-			slot->flags = (!(staterr & IXGBE_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
+			complete = staterr & IXGBE_RXD_STAT_EOP;
+			slot->flags = complete ? 0 : NS_MOREFRAG;
 			PNMB(na, slot, &paddr);
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, size, NR_RX);
@@ -580,6 +582,8 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			rxr->next_to_alloc = rxr->next_to_clean;
 #endif /* NETMAP_LINUX_HAVE_NTA */
 			kring->nr_hwtail = nm_i;
+			if (complete)
+				kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}

From d6a01bc8d680659d94892e6c83b895aa52ce8092 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 16:27:22 +0200
Subject: [PATCH 1326/2207] pkt-gen: set cur=tail when not enough slots for
 multi-slot packet

netmap releases tx-slots lazily and, in particular, it may not
release anything while there is any slot still free. Applications
that want to send multi-slot packets (NS_MOREFRAG) which do not
fit in the available free slots must set cur=tail to notify netmap
that they have seen all the free slots and they need more of them.
---
 apps/pkt-gen/pkt-gen.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 905cdbb47..c1c31b9e3 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1192,6 +1192,10 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		slot->flags |= NS_REPORT;
 		ring->head = ring->cur = cur;
 	}
+	if (sent < count) {
+		/* tell netmap that we need more slots */
+		ring->cur = ring->tail;
+	}
 
 	return (sent);
 }

From 1629d111beaa52c3ec89f7153f67f4fb77743fa4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 17:12:50 +0200
Subject: [PATCH 1327/2207] bwrap: advertise NS_MOREFRAG support when available
 in the hwna

Suggested by Josh Raiff.
---
 sys/dev/netmap/netmap_bdg.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index fe43c5890..bcb4097ed 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1590,6 +1590,8 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
 		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
 	}
+	if (hwna->na_flags & NAF_MOREFRAG)
+		na->na_flags |= NAF_MOREFRAG;
 
 	ND("%s<->%s txr %d txd %d rxr %d rxd %d",
 		na->name, ifp->if_xname,

From 303763f99457532dd089faabf72dabe2bdcad811 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 17:24:58 +0200
Subject: [PATCH 1328/2207] vale: set a forced-reclaim when retrying tx for
 lack of slots

This is needed when using multi-slot packets and the destination port is
a bwrap-attached NIC. Whitout the flag, the NIC netmap driver may not
release any slot if there is at least one free slot.
---
 sys/dev/netmap/netmap_vale.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 619ede6c0..13dda8d44 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1036,7 +1036,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 
 		if (dst_na->retry && retry) {
 			/* try to get some free slot from the previous run */
-			kring->nm_notify(kring, 0);
+			kring->nm_notify(kring, NAF_FORCE_RECLAIM);
 			/* actually useful only for bwraps, since there
 			 * the notify will trigger a txsync on the hwna. VALE ports
 			 * have dst_na->retry == 0

From 425375dc14545fd2b92b978b0102a2621bf6a18f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 23 Oct 2018 18:25:55 +0200
Subject: [PATCH 1329/2207] linux: fix compilation on 4.19

---
 LINUX/configure      | 18 ++++++++++++++++++
 LINUX/netmap_linux.c |  2 +-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 731127d0c..aa806da2c 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1083,6 +1083,24 @@ EOF
 	params="NULL, $params"
   done
 
+  # type of the 3rd param of ndo_select_queue
+  add_test 'define SELECT_QUEUE_PARM3 "struct net_device*"' 'define SELECT_QUEUE_PARM3 "void*"' <
+
+	static u16 myselect(struct net_device *dev, struct sk_buff *skb,
+		struct net_device *sb_dev, select_queue_fallback_t fallback)
+	{
+		(void)dev;
+		(void)skb;
+		(void)sb_dev;
+		(void)fallback;
+		return 0;
+	}
+	struct net_device_ops ndo = {
+		.ndo_select_queue = myselect,
+	};
+EOF
+
   # ethtool get_ringparam
   add_test 'have GET_RINGPARAM' <
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0c71d8f22..848544f7a 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -602,7 +602,7 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 static u16
 generic_ndo_select_queue(struct ifnet *ifp, struct mbuf *m
 #if NETMAP_LINUX_SELECT_QUEUE >= 3
-			, void *accel_priv
+			, NETMAP_LINUX_SELECT_QUEUE_PARM3 accel_priv
 #if NETMAP_LINUX_SELECT_QUEUE >= 4
 				, select_queue_fallback_t fallback
 #endif /* >= 4 */

From c5af244fc5b8c0dce54e022ac2343d4e0e2c1149 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Oct 2018 11:39:58 +0200
Subject: [PATCH 1330/2207] vale-ctl: fix man

---
 apps/vale-ctl/GNUmakefile                |   2 +-
 apps/vale-ctl/{vale-ctl.8 => vale-ctl.4} | 133 ++++++++++++++---------
 2 files changed, 82 insertions(+), 53 deletions(-)
 rename apps/vale-ctl/{vale-ctl.8 => vale-ctl.4} (53%)

diff --git a/apps/vale-ctl/GNUmakefile b/apps/vale-ctl/GNUmakefile
index 68245a15a..3fc49b647 100644
--- a/apps/vale-ctl/GNUmakefile
+++ b/apps/vale-ctl/GNUmakefile
@@ -37,4 +37,4 @@ install: $(PROGS:%=install-%)
 
 install-%:
 	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*
-	-install -D -m 644 $(SRCDIR)/apps/vale-ctl/vale-ctl.8 $(DESTDIR)/$(MAN_PREFIX)/man8/vale-ctl.8
+	-install -D -m 644 $(SRCDIR)/apps/vale-ctl/vale-ctl.4 $(DESTDIR)/$(MAN_PREFIX)/man8/vale-ctl.4
diff --git a/apps/vale-ctl/vale-ctl.8 b/apps/vale-ctl/vale-ctl.4
similarity index 53%
rename from apps/vale-ctl/vale-ctl.8
rename to apps/vale-ctl/vale-ctl.4
index a4f47c9de..67e07e59f 100644
--- a/apps/vale-ctl/vale-ctl.8
+++ b/apps/vale-ctl/vale-ctl.4
@@ -24,108 +24,137 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 12, 2016
-.Dt VALE-CTL 1
+.Dd October 24, 2018
+.Dt VALE-CTL 4
 .Os
 .Sh NAME
 .Nm vale-ctl
-.Nd manage the VALE switch from the netmap framework.
+.Nd manage VALE switches provided by netmap
 .Sh SYNOPSIS
 .Bk -words
 .Bl -tag -width "vale-ctl"
 .It Nm
-.Op Fl g Ar vale-port
-.Op Fl a Ar vale-port
-.Op Fl h Ar vale-port
-.Op Fl d Ar vale-port
+.Op Fl g Ar valeSSS:PPP
+.Op Fl a Ar valeSSS:interface
+.Op Fl h Ar valeSSS:interface
+.Op Fl d Ar valeSSS:interface
 .Op Fl n Ar interface
 .Op Fl r Ar interface
-.Op Fl l Ar vale-port
+.Op Fl l Ar valeSSS:PPP
 .Op Fl l
-.Op Fl p Ar vale-switch
-.Op Fl P Ar vale-switch
+.Op Fl p Ar valeSSS:PPP
+.Op Fl P Ar valeSSS:PPP
 .Op Fl C Ar spec
 .Op Fl m Ar memid
+.El
+.Ek
 .Sh DESCRIPTION
 .Nm
-manages VALE switches by attaching and detaching interfaces, creating
-and deleting persistent VALE ports, starting and stopping polling mode.
+manages and inspects
+.Xr vale 4
+switches, for instance attaching and detaching interfaces, creating
+and deleting persistent VALE ports, or listing the existing switches
+and their ports.
+In the following,
+.Ar valeSSS
+is the name of a VALE switch, while
+.Ar valeSSS:PPP
+is the name of a VALE port of
+.Ar valeSSS .
 .Pp
 When issued without options it lists all the existing switch ports together
 with their internal bridge number and port number.
 .Bl -tag -width Ds
-.It Fl g Ar vale-port
+.It Fl g Ar valeSSS:PPP
 Print the number of receive rings of
-.Ar vale-port.
-.It Fl a Ar switch:interface
-Attach the existing
+.Ar valeSSS:PPP .
+.It Fl a Ar valeSSS:interface
+Attach
 .Ar interface
-to
-.Ar switch
+(which must be an existing network interface) to
+.Ar valeSSS
 and detach it from the host stack.
-.It Fl h Ar switch:interface
-Attach the existing
+.It Fl h Ar valeSSS:interface
+Attach
 .Ar interface
-to
-.Ar switch
-while keeping it attached to the host stack. More precisely, packets coming from
+(which must be an existing network interface) to
+.Ar valeSSS
+while keeping it attached to the host stack.
+More precisely, packets coming from
 the host stack and directed to the interface will go through the switch, where
-they can still reach the interface if the switch rules allow it. Conversely,
-packets coming from the interface will go through the switch and, if appropriate,
-will reach the host stack.
-.It Fl d Ar switch:interface
+they can still reach the interface if the switch rules allow it.
+Conversely, packets coming from the interface will go through the switch and,
+if appropriate, will reach the host stack.
+.It Fl d Ar valeSSS:interface
 Detach
 .Ar interface
 from
-.Ar switch.
+.Ar valeSSS .
 .It Fl n Ar interface
 Create a new persistent VALE port with name
-.Ar interface.
+.Ar interface .
+The name must be different from any other network interface
+already present in the system.
 .It Fl d Ar interface
 Destroy the persistent VALE port with name
-.Ar inteface.
-.It Fl l Ar switch:port
+.Ar inteface .
+.It Fl l Ar valeSSS:PPP
 Show the internal bridge number and port number of the given switch port.
-.It Fl p Ar interface
-Start polling mode for
-.Ar interface.
-.It Fl P Ar interface
-Stop polling mode for
-.Ar interface.
+.It Fl p Ar valeSSS:PPP
+Enable polling mode for
+.Ar valeSSS:PPP .
+In polling mode, a dedicated kernel thread is spawned to handle packets
+received from
+.Ar valeSSS:PPP
+and push them into the switch.
+The kernel thread busy waits on the switch port rather than relying on
+interrupts or notifications.
+Polling mode can only be used on physical NICs attached to a VALE switch.
+.It Fl P Ar valeSSS:PPP
+Disable polling mode for
+.Ar valeSSS:PPP .
 .It Fl C Ar x | Ar x,y | Ar x,y,z | Ar x,y,z,w
 When used in conjunction with
 .Fl n
-it supplies the number of tx and rx rings and slots. The full format with four numbers
-gives, in order, numner of tx slots, number of rx slots, number of tx rings and number
-of rx rings. The form with three numbers uses
+it supplies the number of tx and rx rings and slots.
+The full format with four numbers gives, in order, number of tx slots, number
+of rx slots, number of tx rings and number of rx rings.
+The form with three numbers uses
 .Ar z
-for both the number of tx and the number of rx rings. The forms with less than two
-numbers use the default values for the number of rings. 
-The form with two numbers supplies the numbers of tx and rx slots. The form with only one number
-uses
+for both the number of tx and the number of rx rings.
+The forms with less than two numbers use the default values for the number
+of rings.
+The form with two numbers supplies the numbers of tx and rx slots.
+The form with only one number uses
 .Ar x
 for both the number of tx and the number of rx slots.
 .Pp
 When used in conjunction with
 .Fl p
-only the first three forms are used. The first number may be either 0 or 1.
+only the first three forms are used.
+The first number may be either 0 or 1.
 If 0, then all interface rings will be polled by a single thread, running
 on the core id given by the second number (the third number, if present,
-must be 1). If the first number is 1,
-then the ring identified by the second number will be polled by
-the core with the same id. If a third number is given, then this
-is repeated for as many consecutive rings and cores.
+must be 1).
+If the first number is 1, then the ring identified by the second number will
+be polled by the core with the same id.
+If a third number is given, then this is repeated for as many consecutive
+rings and cores.
 .It Fl m Ar memid
 Used in conjunction with
 .Fl n
 supplies the netmap memory region identifier to use together with the newly
-created persistent VALE port. These ports use a private memory region by
-default. Using this option you can let them share memory with other ports.
+created persistent VALE port.
+These ports use a private memory region by default.
+Using this option you can let them share memory with other ports.
 Pass 1 as
 .Ar memid
 to use the global memory region already shared by all
 harware netmap ports.
-.Pp
+.El
+.Sh SEE ALSO
+.Xr netmap 4 ,
+.Xr vale 4
 .Sh AUTHORS
 .An -nosplit
 .Nm

From 0587dc12c9a05beef4768f04236f7a0efc5da514 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Oct 2018 11:45:37 +0200
Subject: [PATCH 1331/2207] apps: fix installation of man pages

---
 apps/bridge/GNUmakefile   | 1 +
 apps/dedup/GNUmakefile    | 2 ++
 apps/pkt-gen/GNUmakefile  | 1 +
 apps/vale-ctl/GNUmakefile | 3 ++-
 4 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/apps/bridge/GNUmakefile b/apps/bridge/GNUmakefile
index b2c4d4d74..22238d521 100644
--- a/apps/bridge/GNUmakefile
+++ b/apps/bridge/GNUmakefile
@@ -20,6 +20,7 @@ ifeq ($(shell uname),Linux)
 endif
 
 PREFIX ?= /usr/local
+MAN_PREFIX = $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)/share/man
 
 all: $(PROGS)
 
diff --git a/apps/dedup/GNUmakefile b/apps/dedup/GNUmakefile
index 07fbb5f28..071e0f176 100644
--- a/apps/dedup/GNUmakefile
+++ b/apps/dedup/GNUmakefile
@@ -21,6 +21,7 @@ ifeq ($(shell uname),Linux)
 endif
 
 PREFIX ?= /usr/local
+MAN_PREFIX = $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)/share/man
 
 all: $(PROGS)
 
@@ -36,3 +37,4 @@ install: $(PROGS:%=install-%)
 
 install-%:
 	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*
+	-install -D -m 644 $(SRCDIR)/apps/lb/lb.8 $(DESTDIR)/$(MAN_PREFIX)/man8/lb.8
diff --git a/apps/pkt-gen/GNUmakefile b/apps/pkt-gen/GNUmakefile
index 25841e844..d5a55b894 100644
--- a/apps/pkt-gen/GNUmakefile
+++ b/apps/pkt-gen/GNUmakefile
@@ -26,6 +26,7 @@ CFLAGS += -DNO_PCAP
 endif
 
 PREFIX ?= /usr/local
+MAN_PREFIX = $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)/share/man
 
 all: $(PROGS)
 
diff --git a/apps/vale-ctl/GNUmakefile b/apps/vale-ctl/GNUmakefile
index 3fc49b647..8ee0e40be 100644
--- a/apps/vale-ctl/GNUmakefile
+++ b/apps/vale-ctl/GNUmakefile
@@ -26,6 +26,7 @@ CFLAGS += -DNO_PCAP
 endif
 
 PREFIX ?= /usr/local
+MAN_PREFIX = $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)/share/man
 
 all: $(PROGS)
 
@@ -37,4 +38,4 @@ install: $(PROGS:%=install-%)
 
 install-%:
 	install -D $* $(DESTDIR)/$(PREFIX)/bin/$*
-	-install -D -m 644 $(SRCDIR)/apps/vale-ctl/vale-ctl.4 $(DESTDIR)/$(MAN_PREFIX)/man8/vale-ctl.4
+	-install -D -m 644 $(SRCDIR)/apps/vale-ctl/vale-ctl.4 $(DESTDIR)/$(MAN_PREFIX)/man4/vale-ctl.4

From 6f36781918e037979f55b924e3376cfc335b0399 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Oct 2018 17:24:50 +0200
Subject: [PATCH 1332/2207] add a NETMAP_REQ_REGISTER option to specify the CSB
 arrays

---
 sys/dev/netmap/netmap.c       |  87 +++++++++++++++-
 sys/dev/netmap/netmap_kern.h  |  16 +++
 sys/dev/netmap/netmap_kloop.c |  57 ++--------
 sys/net/netmap.h              |  38 ++++---
 utils/ctrl-api-test.c         | 190 +++++++++++++++++++++++-----------
 utils/sync_kloop_test.c       | 101 ++++++++++++------
 6 files changed, 334 insertions(+), 155 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 3bdc91300..eaef69f9e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1996,6 +1996,71 @@ nm_priv_rx_enabled(struct netmap_priv_d *priv)
 	return (priv->np_qfirst[NR_RX] != priv->np_qlast[NR_RX]);
 }
 
+/* Validate the CSB entries for both directions (atok and ktoa). */
+static int
+netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
+{
+	int num_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
+			priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
+	struct nm_csb_atok *csb_atok_base =
+		(struct nm_csb_atok *)(uintptr_t)csbo->csb_atok;
+	struct nm_csb_ktoa *csb_ktoa_base =
+		(struct nm_csb_ktoa *)(uintptr_t)csbo->csb_ktoa;
+	size_t entry_size[2];
+	void *csb_start[2];
+	int i;
+
+	if (num_rings <= 0)
+		return 0;
+
+	if (!(priv->np_flags & NR_EXCLUSIVE)) {
+		nm_prerr("CSB mode requires NR_EXCLUSIVE\n");
+		return EINVAL;
+	}
+
+	entry_size[0] = sizeof(*csb_atok_base);
+	entry_size[1] = sizeof(*csb_ktoa_base);
+	csb_start[0] = (void *)csb_atok_base;
+	csb_start[1] = (void *)csb_ktoa_base;
+
+	for (i = 0; i < 2; i++) {
+		/* On Linux we could use access_ok() to simplify
+		 * the validation. However, the advantage of
+		 * this approach is that it works also on
+		 * FreeBSD. */
+		size_t csb_size = num_rings * entry_size[i];
+		void *tmp;
+		int err;
+
+		if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
+			nm_prerr("Unaligned CSB address\n");
+			return EINVAL;
+		}
+
+		tmp = nm_os_malloc(csb_size);
+		if (!tmp)
+			return ENOMEM;
+		if (i == 0) {
+			/* Application --> kernel direction. */
+			err = copyin(csb_start[i], tmp, csb_size);
+		} else {
+			/* Kernel --> application direction. */
+			memset(tmp, 0, csb_size);
+			err = copyout(tmp, csb_start[i], csb_size);
+		}
+		nm_os_free(tmp);
+		if (err) {
+			nm_prerr("Invalid CSB address\n");
+			return err;
+		}
+	}
+
+	priv->np_csb_atok_base = csb_atok_base;
+	priv->np_csb_ktoa_base = csb_ktoa_base;
+
+	return 0;
+}
+
 /*
  * possibly move the interface to netmap-mode.
  * If success it returns a pointer to netmap_if, otherwise NULL.
@@ -2324,9 +2389,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			/* Protect access to priv from concurrent requests. */
 			NMG_LOCK();
 			do {
+				struct nmreq_option *opt;
 				u_int memflags;
 #ifdef WITH_EXTMEM
-				struct nmreq_option *opt;
 #endif /* WITH_EXTMEM */
 
 				if (priv->np_nifp != NULL) {	/* thread already registered */
@@ -2382,6 +2447,23 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				if (error) {    /* reg. failed, release priv and ref */
 					break;
 				}
+
+				opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+							NETMAP_REQ_OPT_CSB);
+				if (opt != NULL) {
+					struct nmreq_opt_csb *csbo =
+						(struct nmreq_opt_csb *)opt;
+					error = nmreq_checkduplicate(opt);
+					if (!error) {
+						error = netmap_csb_validate(priv, csbo);
+					}
+					opt->nro_status = error;
+					if (error) {
+						netmap_do_unregif(priv);
+						break;
+					}
+				}
+
 				nifp = priv->np_nifp;
 				priv->np_td = td; /* for debugging purposes */
 
@@ -2756,6 +2838,9 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 		if (nro_size >= rv)
 			rv = nro_size;
 		break;
+	case NETMAP_REQ_OPT_CSB:
+		rv = sizeof(struct nmreq_opt_csb);
+		break;
 	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 510c5ae69..d57abdbc1 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1874,6 +1874,22 @@ struct netmap_priv_d {
 	 * number of rings.
 	 */
 	NM_SELINFO_T *np_si[NR_TXRX];
+
+	/* In the optional CSB mode, the user must specify the start address
+	 * of two arrays of Communication Status Block (CSB) entries, for the
+	 * two directions (kernel read application write, and kernel write
+	 * application read).
+	 * The number of entries must agree with the number of rings bound to
+	 * the netmap file descriptor. The entries corresponding to the TX
+	 * rings are laid out before the ones corresponding to the RX rings.
+	 *
+	 * Array of CSB entries for application --> kernel communication
+	 * (N entries). */
+	struct nm_csb_atok	*np_csb_atok_base;
+	/* Array of CSB entries for kernel --> application communication
+	 * (N entries). */
+	struct nm_csb_ktoa	*np_csb_ktoa_base;
+
 	struct thread	*np_td;		/* kqueue, just debugging */
 #ifdef linux
 	struct file	*np_filp;  /* used by sync kloop */
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index dc26704ea..1f00c7a1e 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -469,8 +469,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		return ENXIO;
 	}
 
-	if (!(priv->np_flags & NR_EXCLUSIVE)) {
-		nm_prerr("sync-kloop on %s requires NR_EXCLUSIVE\n", na->name);
+	/* Make sure the application is working in CSB mode. */
+	csb_atok_base = priv->np_csb_atok_base;
+	csb_ktoa_base = priv->np_csb_ktoa_base;
+	if (!csb_atok_base || !csb_ktoa_base) {
+		nm_prerr("sync-kloop on %s requires NETMAP_REQ_OPT_CSB "
+			"option\n", na->name);
 		return EINVAL;
 	}
 
@@ -485,59 +489,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		return err;
 	}
 
-	csb_atok_base = (struct nm_csb_atok *)(uintptr_t)req->csb_atok;
-	csb_ktoa_base = (struct nm_csb_ktoa *)(uintptr_t)req->csb_ktoa;
 	num_rx_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX];
 	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
 	num_rings = num_tx_rings + num_rx_rings;
 
-	/* Validate the CSB entries for both directions (atok and ktoa). */
-	{
-		if (num_rings > 0) {
-			size_t entry_size[2];
-			void *csb_start[2];
-
-			entry_size[0] = sizeof(*csb_atok_base);
-			entry_size[1] = sizeof(*csb_ktoa_base);
-			csb_start[0] = (void *)csb_atok_base;
-			csb_start[1] = (void *)csb_ktoa_base;
-
-			for (i = 0; i < 2; i++) {
-				/* On Linux we could use access_ok() to simplify
-				 * the validation. However, the advantage of
-				 * this approach is that it works also on
-				 * FreeBSD. */
-				size_t csb_size = num_rings * entry_size[i];
-				void *tmp;
-
-				if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
-					nm_prerr("Unaligned CSB address\n");
-					err = EINVAL;
-					goto out;
-				}
-
-				tmp = nm_os_malloc(csb_size);
-				if (!tmp) {
-					err = ENOMEM;
-					goto out;
-				}
-				if (i == 0) {
-					/* Application --> kernel direction. */
-					err = copyin(csb_start[i], tmp, csb_size);
-				} else {
-					/* Kernel --> application direction. */
-					memset(tmp, 0, csb_size);
-					err = copyout(tmp, csb_start[i], csb_size);
-				}
-				nm_os_free(tmp);
-				if (err) {
-					nm_prerr("Invalid CSB address\n");
-					goto out;
-				}
-			}
-		}
-	}
-
 	/* Validate notification options. */
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d288ac61f..e4dd5c084 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -533,10 +533,17 @@ enum {
 	/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
 	 * from user-space allocated memory pools (e.g. hugepages). */
 	NETMAP_REQ_OPT_EXTMEM = 1,
+
 	/* ON NETMAP_REQ_SYNC_KLOOP_START, ask netmap to use eventfd-based
 	 * notifications to synchronize the kernel loop with the application.
 	 */
 	NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS,
+
+	/* On NETMAP_REQ_REGISTER, ask netmap to work in CSB mode, where
+	 * head, cur and tail pointers are not exchanged through the
+	 * struct netmap_ring header, but rather using an user-provided
+	 * memory area (see struct nm_csb_atok and struct nm_csb_ktoa). */
+	NETMAP_REQ_OPT_CSB,
 };
 
 /*
@@ -710,26 +717,16 @@ struct nmreq_pools_info {
  * Start an in-kernel loop that syncs the rings periodically or on
  * notifications. The loop runs in the context of the ioctl syscall,
  * and only stops on NETMAP_REQ_SYNC_KLOOP_STOP.
- * The user must specify the start address of two arrays of Communication
- * Status Block (CSB) entries, for the two directions (kernel read
- * application write, and kernel write application read). The number of
- * entries must agree with the number of rings bound to the netmap file
- * descriptor. The entries corresponding to the TX rings are laid out before
- * the ones corresponding to the RX rings.
+ * The netmap port must be open in CSB mode.
  */
 struct nmreq_sync_kloop_start {
-	/* Array of CSB entries for application --> kernel communication
-	 * (N entries). */
-	uint64_t csb_atok;
-	/* Array of CSB entries for kernel --> application communication
-	 * (N entries). */
-	uint64_t csb_ktoa;
 	/* Sleeping is the default synchronization method for the kloop.
 	 * The 'sleep_us' field specifies how many microsconds to sleep
 	 * waiting for more work to come. */
 	uint32_t sleep_us;
 };
 
+/* A CSB entry for the application --> kernel direction. */
 struct nm_csb_atok {
 	uint32_t head;		  /* AW+ KR+ the head of the appl netmap_ring */
 	uint32_t cur;		  /* AW+ KR+ the cur of the appl netmap_ring */
@@ -738,6 +735,7 @@ struct nm_csb_atok {
 	char pad[48];		  /* pad to a 64 bytes cacheline */
 };
 
+/* A CSB entry for the application <-- kernel direction. */
 struct nm_csb_ktoa {
 	uint32_t hwcur;		  /* AR+ KW+ the hwcur of the kern netmap_kring */
 	uint32_t hwtail;	  /* AR+ KW+ the hwtail of the kern netmap_kring */
@@ -831,8 +829,8 @@ struct nmreq_opt_sync_kloop_eventfds {
 	/* An array of N entries for bidirectional notifications between
 	 * the kernel loop and the application. The number of entries and
 	 * their order must agree with the CSB arrays passed in the
-	 * NETMAP_REQ_SYNC_KLOOP_START message. Each entry contains a file
-	 * descriptor backed by an eventfd.
+	 * NETMAP_REQ_OPT_CSB option. Each entry contains a file descriptor
+	 * backed by an eventfd.
 	 */
 	struct {
 		/* Notifier for the application --> kernel loop direction. */
@@ -848,4 +846,16 @@ struct nmreq_opt_extmem {
 	struct nmreq_pools_info	nro_info;	/* (in/out) */
 };
 
+struct nmreq_opt_csb {
+	struct nmreq_option	nro_opt;
+
+	/* Array of CSB entries for application --> kernel communication
+	 * (N entries). */
+	uint64_t		csb_atok;
+
+	/* Array of CSB entries for kernel --> application communication
+	 * (N entries). */
+	uint64_t		csb_ktoa;
+};
+
 #endif /* _NET_NETMAP_H_ */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index c6e6a280e..4b8aa68eb 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -42,6 +42,7 @@ struct TestContext {
 
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
+	void *csb; /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
 };
 
@@ -73,6 +74,7 @@ port_info_get(struct TestContext *ctx)
 {
 	struct nmreq_port_info_get req;
 	struct nmreq_header hdr;
+	int success;
 	int ret;
 
 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
@@ -94,11 +96,21 @@ port_info_get(struct TestContext *ctx)
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
-	return req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
+	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
 	                       req.nr_tx_rings && req.nr_rx_rings &&
-	                       req.nr_tx_rings
-	               ? 0
-	               : -1;
+	                       req.nr_tx_rings;
+	if (!success) {
+		return -1;
+	}
+
+	/* Write back results to the context structure.*/
+	ctx->nr_tx_slots = req.nr_tx_slots;
+	ctx->nr_rx_slots = req.nr_rx_slots;
+	ctx->nr_tx_rings = req.nr_tx_rings;
+	ctx->nr_rx_rings = req.nr_rx_rings;
+	ctx->nr_mem_id = req.nr_mem_id;
+
+	return 0;
 }
 
 /* Single NETMAP_REQ_REGISTER, no use. */
@@ -843,6 +855,81 @@ duplicate_extmem_options(struct TestContext *ctx)
 }
 #endif /* CONFIG_NETMAP_EXTMEM */
 
+static int
+push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
+{
+	size_t csb_size;
+	int num_entries;
+	int ret;
+
+	ctx->nr_flags |= NR_EXCLUSIVE;
+
+	/* Get port info in order to use num_registered_rings(). */
+	ret = port_info_get(ctx);
+	if (ret) {
+		return ret;
+	}
+	num_entries = num_registered_rings(ctx);
+
+	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
+	           num_entries;
+	assert(csb_size > 0);
+	if (ctx->csb) {
+		free(ctx->csb);
+	}
+	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
+	if (ret) {
+		printf("Failed to allocate CSB memory\n");
+		exit(EXIT_FAILURE);
+	}
+
+	memset(opt, 0, sizeof(*opt));
+	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
+	opt->csb_atok = (uintptr_t)ctx->csb;
+	opt->csb_ktoa = (uintptr_t)
+			(ctx->csb + sizeof(struct nm_csb_atok) * num_entries);
+
+	push_option(&opt->nro_opt, ctx);
+
+	return 0;
+}
+
+static int
+csb_mode(struct TestContext *ctx)
+{
+	struct nmreq_opt_csb opt;
+	int ret;
+
+	ret = push_csb_option(ctx, &opt);
+	if (ret) {
+		return ret;
+	}
+
+	ret = port_register_hwall(ctx);
+	clear_options(ctx);
+
+	return ret;
+}
+
+static int
+csb_mode_invalid_memory(struct TestContext *ctx)
+{
+	struct nmreq_opt_csb opt;
+	int ret;
+
+	memset(&opt, 0, sizeof(opt));
+	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
+	opt.csb_atok = (uintptr_t)0x10;
+	opt.csb_ktoa = (uintptr_t)0x800;
+	push_option(&opt.nro_opt, ctx);
+
+	ctx->nr_flags = NR_EXCLUSIVE;
+	ret           = port_register_hwall(ctx);
+	clear_options(ctx);
+
+	return (ret < 0) ? 0 : -1;
+}
+
 static int
 sync_kloop_stop(struct TestContext *ctx)
 {
@@ -863,39 +950,23 @@ static void *
 sync_kloop_worker(void *opaque)
 {
 	struct TestContext *ctx = opaque;
-	size_t num_entries      = num_registered_rings(ctx);
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
-	size_t csb_size;
-	void *csb;
 	int ret;
 
-	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
-	           num_entries;
-	assert(csb_size > 0);
-	ret = posix_memalign(&csb, sizeof(struct nm_csb_atok), csb_size);
-	if (ret) {
-		printf("Failed to allocate CSB memory\n");
-		pthread_exit((void *)-1);
-	}
-
-	printf("Testing NETMAP_REQ_SYNC_KLOOP_START(csb_size=%u) on '%s'\n",
-	       (unsigned)csb_size, ctx->ifname);
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n",
+	       ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
 	hdr.nr_body    = (uintptr_t)&req;
 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
 	memset(&req, 0, sizeof(req));
-	req.csb_atok = (uintptr_t)csb;
-	req.csb_ktoa =
-	        (uintptr_t)(csb + sizeof(struct nm_csb_atok) * num_entries);
 	req.sleep_us = 500;
 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
-	free(csb);
 
 	pthread_exit((void *)(uintptr_t)ret);
 }
@@ -931,8 +1002,7 @@ sync_kloop(struct TestContext *ctx)
 {
 	int ret;
 
-	ctx->nr_flags = NR_EXCLUSIVE;
-	ret           = port_register_hwall(ctx);
+	ret = csb_mode(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -988,8 +1058,7 @@ sync_kloop_eventfds_all(struct TestContext *ctx)
 {
 	int ret;
 
-	ctx->nr_flags = NR_EXCLUSIVE;
-	ret           = port_register_hwall(ctx);
+	ret = csb_mode(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -1001,13 +1070,19 @@ sync_kloop_eventfds_all(struct TestContext *ctx)
 static int
 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 {
+	struct nmreq_opt_csb opt;
 	int ret;
 
-	ctx->nr_flags = NR_EXCLUSIVE;
+	ret = push_csb_option(ctx, &opt);
+	if (ret) {
+		return ret;
+	}
+
 	ret           = port_register_hwall_tx(ctx);
 	if (ret) {
 		return ret;
 	}
+	clear_options(ctx);
 
 	return sync_kloop_eventfds(ctx);
 }
@@ -1015,15 +1090,21 @@ sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
-	int ret;
+	struct nmreq_opt_csb opt;
 	pthread_t th1, th2;
 	int thret1, thret2;
+	int ret;
+
+	ret = push_csb_option(ctx, &opt);
+	if (ret) {
+		return ret;
+	}
 
-	ctx->nr_flags = NR_EXCLUSIVE;
 	ret           = port_register_hwall(ctx);
 	if (ret) {
 		return ret;
 	}
+	clear_options(ctx);
 
 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
 	if (ret) {
@@ -1063,49 +1144,26 @@ sync_kloop_conflict(struct TestContext *ctx)
 }
 
 static int
-sync_kloop_invalid_csb(struct TestContext *ctx)
+sync_kloop_eventfds_mismatch(struct TestContext *ctx)
 {
+	struct nmreq_opt_csb opt;
 	int ret;
-	struct nmreq_sync_kloop_start req;
-	struct nmreq_header hdr;
-
-	ctx->nr_flags = NR_EXCLUSIVE;
-	ret           = port_register_hwall(ctx);
 
-	/* Post a stop request first. */
-	ret = sync_kloop_stop(ctx);
+	ret = push_csb_option(ctx, &opt);
 	if (ret) {
 		return ret;
 	}
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
-	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
-	hdr.nr_body    = (uintptr_t)&req;
-	memset(&req, 0, sizeof(req));
-	req.csb_atok = (uintptr_t)0x10;
-	req.csb_ktoa = (uintptr_t)0x800;
-	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
-		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
-	}
-
-	return (ret < 0) ? 0 : -1;
-}
-
-static int
-sync_kloop_eventfds_mismatch(struct TestContext *ctx)
-{
-	int ret;
-
-	ctx->nr_flags = NR_EXCLUSIVE;
 	ret           = port_register_hwall_rx(ctx);
 	if (ret) {
 		return ret;
 	}
+	clear_options(ctx);
+
 	/* Deceive num_registered_rings() to trigger a failure of
 	 * sync_kloop_eventfds(). The latter will think that all the
 	 * rings were registered, and allocate the wrong number of
-	 * eventfds and CSB entries. */
+	 * eventfds. */
 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
 
 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
@@ -1149,14 +1207,26 @@ static struct mytest tests[] = {
 	decltest(bad_extmem_option),
 	decltest(duplicate_extmem_options),
 #endif /* CONFIG_NETMAP_EXTMEM */
+	decltest(csb_mode),
+	decltest(csb_mode_invalid_memory),
 	decltest(sync_kloop),
 	decltest(sync_kloop_eventfds_all),
 	decltest(sync_kloop_eventfds_all_tx),
 	decltest(sync_kloop_conflict),
-	decltest(sync_kloop_invalid_csb),
 	decltest(sync_kloop_eventfds_mismatch),
 };
 
+static void
+context_cleanup(struct TestContext *ctx)
+{
+	if (ctx->csb) {
+		free(ctx->csb);
+		ctx->csb = NULL;
+	}
+
+	close(ctx->fd);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1236,7 +1306,7 @@ main(int argc, char **argv)
 			goto out;
 		}
 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
-		close(fd);
+		context_cleanup(&ctxcopy);
 	}
 out:
 	if (loopback_if) {
diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 78df2ebe7..3c66bfc0b 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -32,7 +32,7 @@ struct eventfds {
 };
 
 struct context {
-	struct nm_desc *nmd;
+	int fd; /* netmap file descriptor */
 	struct nm_csb_atok *atok_base;
 	struct nm_csb_ktoa *ktoa_base;
 	int sleep_us;
@@ -47,7 +47,6 @@ kloop_worker(void *opaque)
 {
 	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
 	struct context *ctx                       = opaque;
-	struct nm_desc *nmd                       = ctx->nmd;
 	struct nmreq_sync_kloop_start req;
 	struct nmreq_header hdr;
 	int ret;
@@ -77,10 +76,8 @@ kloop_worker(void *opaque)
 	hdr.nr_body    = (uintptr_t)&req;
 	hdr.nr_options = (uintptr_t)opt;
 	memset(&req, 0, sizeof(req));
-	req.csb_atok = (uintptr_t)ctx->atok_base;
-	req.csb_ktoa = (uintptr_t)ctx->ktoa_base;
 	req.sleep_us = (uint32_t)ctx->sleep_us;
-	ret          = ioctl(nmd->fd, NIOCCTRL, &hdr);
+	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 		exit(EXIT_FAILURE);
@@ -127,14 +124,14 @@ main(int argc, char **argv)
 	struct nm_csb_atok *atok_base = NULL;
 	struct nm_csb_ktoa *ktoa_base = NULL;
 	struct eventfds *eventfds_base = NULL;
-	int num_tx_entries;
+	int num_tx_entries, num_rx_entries;
 	unsigned long long bytes = 0;
 	unsigned long long pkts  = 0;
 	const char *ifname       = NULL;
 	void *csb                = NULL;
 	uint16_t first_ring, last_ring;
+	struct netmap_if *nifp = NULL;
 	struct context ctx;
-	struct nm_desc *nmd;
 
 	double target_rate         = 0.0 /* pps */;
 	unsigned int period_us     = 0;
@@ -234,26 +231,38 @@ main(int argc, char **argv)
 		return -1;
 	}
 
+	ctx.fd = open("/dev/netmap", O_RDWR);
+	if (ctx.fd < 0) {
+		perror("open(/dev/netmap)");
+		return ctx.fd;
+	}
+
+	/* Get the number of TX and RX rings. */
 	{
-		/* Open the netmap port with NR_EXCLUSIVE. */
-		struct nmreq nmr;
-
-		memset(&nmr, 0, sizeof(nmr));
-		nmr.nr_flags = NR_EXCLUSIVE;
-		ctx.nmd = nmd = nm_open(ifname, &nmr, 0, NULL);
-		if (!nmd) {
-			printf("nm_open(%s) failed\n", ifname);
-			return -1;
+		struct nmreq_port_info_get req;
+		struct nmreq_header hdr;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.nr_version = NETMAP_API;
+		strncpy(hdr.nr_name, ifname, sizeof(hdr.nr_name) - 1);
+		hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+		hdr.nr_body    = (uintptr_t)&req;
+		memset(&req, 0, sizeof(req));
+		ret = ioctl(ctx.fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
+			return ret;
 		}
+
+		num_tx_entries = req.nr_tx_rings;
+		num_rx_entries = req.nr_rx_rings;
+		ctx.num_entries = num_tx_entries + num_rx_entries;
 	}
 
 	/* Allocate CSB entries. */
 	{
 		size_t csb_size;
 
-		num_tx_entries  = nmd->last_tx_ring - nmd->first_tx_ring + 1;
-		ctx.num_entries = num_tx_entries + nmd->last_rx_ring -
-		                  nmd->first_rx_ring + 1;
 		printf("Number of CSB entries = %d\n", (int)ctx.num_entries);
 		csb_size = (sizeof(struct nm_csb_atok) +
 		            sizeof(struct nm_csb_ktoa)) *
@@ -272,6 +281,43 @@ main(int argc, char **argv)
 		        (struct nm_csb_ktoa *)(ctx.atok_base + ctx.num_entries);
 	}
 
+	{
+		/* Open the netmap port with NR_EXCLUSIVE and with
+		 * the CSB option. */
+		struct nmreq_register req;
+		struct nmreq_opt_csb opt;
+		struct nmreq_header hdr;
+		void *mem;
+
+		memset(&opt, 0, sizeof(opt));
+		opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
+		opt.csb_atok = (uintptr_t)atok_base;
+		opt.csb_ktoa = (uintptr_t)ktoa_base;
+
+		memset(&hdr, 0, sizeof(hdr));
+		hdr.nr_version = NETMAP_API;
+		strncpy(hdr.nr_name, ifname, sizeof(hdr.nr_name) - 1);
+		hdr.nr_reqtype = NETMAP_REQ_REGISTER;
+		hdr.nr_body    = (uintptr_t)&req;
+		hdr.nr_options = (uintptr_t)&opt.nro_opt;
+		memset(&req, 0, sizeof(req));
+		req.nr_mode       = NR_REG_ALL_NIC;
+		req.nr_flags      |= NR_EXCLUSIVE;
+		ret               = ioctl(ctx.fd, NIOCCTRL, &hdr);
+		if (ret) {
+			perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
+			return ret;
+		}
+
+		mem = mmap(0, req.nr_memsize, PROT_WRITE | PROT_READ,
+				MAP_SHARED, ctx.fd, 0);
+		if (mem == MAP_FAILED) {
+			perror("mmap()");
+			return -1;
+		}
+		nifp = NETMAP_IF(mem, req.nr_offset);
+	}
+
 	/* Allocate eventfds. */
 	if (use_eventfds) {
 #ifdef __linux__
@@ -303,7 +349,6 @@ main(int argc, char **argv)
 	ret = pthread_create(&th, NULL, kloop_worker, &ctx);
 	if (ret) {
 		printf("pthread_create() failed: %s\n", strerror(ret));
-		nm_close(nmd);
 		return -1;
 	}
 
@@ -328,11 +373,11 @@ main(int argc, char **argv)
 		atok_base += num_tx_entries;
 		ktoa_base += num_tx_entries;
 		eventfds_base += num_tx_entries;
-		first_ring = nmd->first_rx_ring;
-		last_ring  = nmd->last_rx_ring;
+		first_ring = 0;
+		last_ring  = num_tx_entries-1;
 	} else {
-		first_ring = nmd->first_tx_ring;
-		last_ring  = nmd->last_tx_ring;
+		first_ring = 0;
+		last_ring  = num_rx_entries-1;
 	}
 
 	gettimeofday(&next_time, NULL);
@@ -386,9 +431,9 @@ main(int argc, char **argv)
 			int batch;
 
 			if (func == F_TX) {
-				ring = NETMAP_TXRING(nmd->nifp, r);
+				ring = NETMAP_TXRING(nifp, r);
 			} else {
-				ring = NETMAP_RXRING(nmd->nifp, r);
+				ring = NETMAP_RXRING(nifp, r);
 			}
 
 			head = atok->head;
@@ -495,7 +540,7 @@ main(int argc, char **argv)
 		memset(&hdr, 0, sizeof(hdr));
 		hdr.nr_version = NETMAP_API;
 		hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
-		ret            = ioctl(nmd->fd, NIOCCTRL, &hdr);
+		ret            = ioctl(ctx.fd, NIOCCTRL, &hdr);
 		if (ret) {
 			perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
 		}
@@ -509,7 +554,5 @@ main(int argc, char **argv)
 
 	free(csb);
 
-	nm_close(nmd);
-
 	return 0;
 }

From 4c3d16255ad6134cc4743ecfab32cd5c63c978d6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 23 Oct 2018 17:30:31 +0200
Subject: [PATCH 1333/2207] utils: ctrl-api-test: add test for sync-kloop
 without CSB

---
 utils/ctrl-api-test.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 4b8aa68eb..6f79ba36c 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1087,6 +1087,22 @@ sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 	return sync_kloop_eventfds(ctx);
 }
 
+static int
+sync_kloop_nocsb(struct TestContext *ctx)
+{
+	int ret;
+
+	ret = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	/* Sync kloop must fail because we did not use
+	 * NETMAP_REQ_OPT_CSB. */
+	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
+
+}
+
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
@@ -1212,6 +1228,7 @@ static struct mytest tests[] = {
 	decltest(sync_kloop),
 	decltest(sync_kloop_eventfds_all),
 	decltest(sync_kloop_eventfds_all_tx),
+	decltest(sync_kloop_nocsb),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_eventfds_mismatch),
 };

From 9eb0f6ac8109c4ccc8184d68c848394105e88de4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Oct 2018 12:59:37 +0200
Subject: [PATCH 1334/2207] Allow NETMAP_REQ_POOLS_INFO_GET on unbound control
 devices

This is useful for QEMU and the netmap passthrough.
---
 sys/dev/netmap/netmap.c | 42 +++++++++++++++++++++++++++++++++--------
 sys/net/netmap.h        | 15 +++++++++------
 utils/ctrl-api-test.c   | 14 ++++++++------
 3 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index eaef69f9e..1309a3901 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2670,18 +2670,44 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 #endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
+			/* Get information from the memory allocator used for
+			 * hdr->nr_name. */
 			struct nmreq_pools_info *req =
 				(struct nmreq_pools_info *)(uintptr_t)hdr->nr_body;
-			/* Get information from the memory allocator. This
-			 * netmap device must already be bound to a port.
-			 * Note that hdr->nr_name is ignored. */
 			NMG_LOCK();
-			if (priv->np_na && priv->np_na->nm_mem) {
-				struct netmap_mem_d *nmd = priv->np_na->nm_mem;
+			do {
+				/* Build a nmreq_register out of the nmreq_pools_info,
+				 * so that we can call netmap_get_na(). */
+				struct nmreq_register regreq;
+				bzero(®req, sizeof(regreq));
+				regreq.nr_mem_id = req->nr_mem_id;
+
+				hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+				hdr->nr_body = (uintptr_t)®req;
+				error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
+				hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET; /* reset type */
+				hdr->nr_body = (uintptr_t)req; /* reset nr_body */
+				if (error) {
+					na = NULL;
+					ifp = NULL;
+					break;
+				}
+				nmd = na->nm_mem; /* grab the memory allocator */
+				if (nmd == NULL) {
+					error = EINVAL;
+					break;
+				}
+
+				/* Finalize the memory allocator, get the pools
+				 * information and release the allocator. */
+				error = netmap_mem_finalize(nmd, na);
+				if (error) {
+					break;
+				}
 				error = netmap_mem_pools_info_get(req, nmd);
-			} else {
-				error = EINVAL;
-			}
+				netmap_mem_drop(na);
+			} while (0);
+			netmap_unget_na(na, ifp);
 			NMG_UNLOCK();
 			break;
 		}
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e4dd5c084..a03c252e4 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -613,7 +613,9 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 /*
  * nr_reqtype: NETMAP_REQ_PORT_INFO_GET
  * Get information about a netmap port, including number of rings.
- * slots per ring, id of the memory allocator, etc.
+ * slots per ring, id of the memory allocator, etc. The netmap
+ * control device used for this operation does not need to be bound
+ * to a netmap port.
  */
 struct nmreq_port_info_get {
 	uint64_t	nr_offset;	/* nifp offset in the shared region */
@@ -622,7 +624,7 @@ struct nmreq_port_info_get {
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
 	uint16_t	nr_rx_rings;	/* number of rx rings */
-	uint16_t	nr_mem_id;	/* id of the memory allocator */
+	uint16_t	nr_mem_id;	/* memory allocator id (in/out) */
 };
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
@@ -694,13 +696,14 @@ struct nmreq_vale_polling {
 
 /*
  * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
- * Get info about the pools of the memory allocator of the port bound
- * to a given netmap control device (used i.e. by a ptnetmap-enabled
- * hypervisor). The nr_hdr.nr_name field is ignored.
+ * Get info about the pools of the memory allocator of the netmap
+ * port specified by nr_hdr.nr_name and nr_mem_id. The netmap control
+ * device used for this operation does not need to be bound to a netmap
+ * port.
  */
 struct nmreq_pools_info {
 	uint64_t	nr_memsize;
-	uint16_t	nr_mem_id;
+	uint16_t	nr_mem_id; /* in/out argument */
 	uint64_t	nr_if_pool_offset;
 	uint32_t	nr_if_pool_objtotal;
 	uint32_t	nr_if_pool_objsize;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 6f79ba36c..19290ba84 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -446,6 +446,7 @@ pools_info_get(struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
+	req.nr_mem_id = ctx->nr_mem_id;
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
@@ -474,15 +475,15 @@ pools_info_get(struct TestContext *ctx)
 }
 
 static int
-register_and_pools_info_get(struct TestContext *ctx)
+pools_info_get_and_register(struct TestContext *ctx)
 {
 	int ret;
 
+	/* Check that we can get pools info before we register
+	 * a netmap interface. */
 	ret = pools_info_get(ctx);
-	if (ret == 0) {
-		printf("Failed: POOLS_INFO_GET didn't fail on unbound "
-		       "netmap device\n");
-		return -1;
+	if (ret) {
+		return ret;
 	}
 
 	ctx->nr_mode = NR_REG_ONE_NIC;
@@ -492,6 +493,7 @@ register_and_pools_info_get(struct TestContext *ctx)
 	}
 	ctx->nr_mem_id = 1;
 
+	/* Check that we can get pools info also after we register. */
 	return pools_info_get(ctx);
 }
 
@@ -1212,7 +1214,7 @@ static struct mytest tests[] = {
 	decltest(vale_attach_detach_host_rings),
 	decltest(vale_ephemeral_port_hdr_manipulation),
 	decltest(vale_persistent_port),
-	decltest(register_and_pools_info_get),
+	decltest(pools_info_get_and_register),
 	decltest(pipe_master),
 	decltest(pipe_slave),
 	decltest(vale_polling_enable_disable),

From 0dfea3b2217b8da86c000745cfe89e64f8958134 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 24 Oct 2018 13:08:21 +0200
Subject: [PATCH 1335/2207] utils: ctrl-api-test: add test for empty netmap
 interface name

---
 utils/GNUmakefile     |  2 +-
 utils/ctrl-api-test.c | 10 +++++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 249e41121..4a28f6572 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -14,7 +14,7 @@ NO_MAN=
 CFLAGS  = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys # -I/home/luigi/FreeBSD/head/sys -I../sys
-CFLAGS += -Wextra
+CFLAGS += -Wextra -g
 CFLAGS += $(SUBSYS_FLAGS)
 ifdef WITH_PCAP
 # do not use pcap by default, as it is not always available on linux
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 19290ba84..ed3c8c2a8 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -26,7 +26,7 @@ static int eventfd(int x, int y)
 
 struct TestContext {
 	int fd; /* netmap file descriptor */
-	const char *ifname;
+	char *ifname;
 	const char *bdgname;
 	uint32_t nr_tx_slots;   /* slots in tx rings */
 	uint32_t nr_rx_slots;   /* slots in rx rings */
@@ -497,6 +497,13 @@ pools_info_get_and_register(struct TestContext *ctx)
 	return pools_info_get(ctx);
 }
 
+static int
+pools_info_get_empty_ifname(struct TestContext *ctx)
+{
+	ctx->ifname = "";
+	return pools_info_get(ctx) != 0 ? 0 : -1;
+}
+
 static int
 pipe_master(struct TestContext *ctx)
 {
@@ -1215,6 +1222,7 @@ static struct mytest tests[] = {
 	decltest(vale_ephemeral_port_hdr_manipulation),
 	decltest(vale_persistent_port),
 	decltest(pools_info_get_and_register),
+	decltest(pools_info_get_empty_ifname),
 	decltest(pipe_master),
 	decltest(pipe_slave),
 	decltest(vale_polling_enable_disable),

From 4e7bb06476a509045cbc3849bebe80d261ec948f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 10:10:28 +0200
Subject: [PATCH 1336/2207] sync-kloop: look for CSB option also on kloop start

---
 sys/dev/netmap/netmap.c       |  2 +-
 sys/dev/netmap/netmap_kern.h  |  3 +++
 sys/dev/netmap/netmap_kloop.c | 30 ++++++++++++++++++++++++------
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1309a3901..80db61b95 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1997,7 +1997,7 @@ nm_priv_rx_enabled(struct netmap_priv_d *priv)
 }
 
 /* Validate the CSB entries for both directions (atok and ktoa). */
-static int
+int
 netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 {
 	int num_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d57abdbc1..d768268ee 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1916,6 +1916,9 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
 	return 0;
 }
 
+int netmap_csb_validate(struct netmap_priv_d *priv,
+			struct nmreq_opt_csb *csbo);
+
 /* call with NMG_LOCK held */
 static __inline int
 nm_si_user(struct netmap_priv_d *priv, enum txrx t)
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 1f00c7a1e..e6557f30d 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -469,14 +469,32 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		return ENXIO;
 	}
 
-	/* Make sure the application is working in CSB mode. */
+	/* Make sure the application is working in CSB mode. If it
+	 * is not, check if the user specified the CSB option with
+	 * this command. */
+	if (!priv->np_csb_atok_base || !priv->np_csb_ktoa_base) {
+		struct nmreq_option *opt;
+
+		opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_CSB);
+		if (!opt) {
+			nm_prerr("sync-kloop on %s requires "
+				"NETMAP_REQ_OPT_CSB option\n", na->name);
+			return EINVAL;
+		}
+		err = nmreq_checkduplicate(opt);
+		if (err) {
+			return err;
+		}
+		err = netmap_csb_validate(priv,
+					(struct nmreq_opt_csb *)opt);
+		opt->nro_status = err;
+		if (err) {
+			return err;
+		}
+	}
 	csb_atok_base = priv->np_csb_atok_base;
 	csb_ktoa_base = priv->np_csb_ktoa_base;
-	if (!csb_atok_base || !csb_ktoa_base) {
-		nm_prerr("sync-kloop on %s requires NETMAP_REQ_OPT_CSB "
-			"option\n", na->name);
-		return EINVAL;
-	}
 
 	/* Make sure that no kloop is currently running. */
 	NMG_LOCK();

From 3803fb9922ce38323d2c6b130aee0bcf14dbaca7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 10:10:49 +0200
Subject: [PATCH 1337/2207] utils: ctrl-api-test: add sync_kloop_csb_on_start()
 test

---
 utils/ctrl-api-test.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index ed3c8c2a8..d87ecb45c 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1112,6 +1112,27 @@ sync_kloop_nocsb(struct TestContext *ctx)
 
 }
 
+static int
+sync_kloop_csb_on_start(struct TestContext *ctx)
+{
+	struct nmreq_opt_csb opt;
+	int ret;
+
+	ctx->nr_flags |= NR_EXCLUSIVE;
+	ret = port_register_hwall(ctx);
+	if (ret) {
+		return ret;
+	}
+
+	ret = push_csb_option(ctx, &opt);
+	if (ret) {
+		return ret;
+	}
+
+	return sync_kloop_start_stop(ctx);
+
+}
+
 static int
 sync_kloop_conflict(struct TestContext *ctx)
 {
@@ -1239,6 +1260,7 @@ static struct mytest tests[] = {
 	decltest(sync_kloop_eventfds_all),
 	decltest(sync_kloop_eventfds_all_tx),
 	decltest(sync_kloop_nocsb),
+	decltest(sync_kloop_csb_on_start),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_eventfds_mismatch),
 };

From 3a920d25f8828fe63cfb3b59b70513fb29132ee5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 10:26:20 +0200
Subject: [PATCH 1338/2207] utils: ctrl-api-test: fix compilation issue in
 extmem test

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d87ecb45c..e90bb6078 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -702,7 +702,7 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 	unsigned long oldv;
 	FILE *f;
 
-	strncat(param, pname, 256);
+	strncat(param, pname, sizeof(param)-1);
 
 	f = fopen(param, "r+");
 	if (f == NULL) {

From 351345bea2dde62323f38b99b8775ccec19d67e4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 10:33:15 +0200
Subject: [PATCH 1339/2207] netmap.h: clarify on the PORT_HDR_[SET|GET] API

---
 sys/net/netmap.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a03c252e4..a03258a4e 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -664,7 +664,8 @@ struct nmreq_vale_list {
 
 /*
  * nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
- * Set the port header length.
+ * Set or get the port header length of the port identified by nr_hdr.nr_name.
+ * The control device does not need to be bound to a netmap port.
  */
 struct nmreq_port_hdr {
 	uint32_t	nr_hdr_len;

From 7727c06d40746c7b74dda1ead6adba90595f00d3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 10:34:55 +0200
Subject: [PATCH 1340/2207] netmap.h: small comment fix

---
 sys/net/netmap.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a03258a4e..c31986f4d 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -597,7 +597,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 };
 
 /* A single ioctl number is shared by all the new API command.
- * Demultiplexing is done using the nr_hdr.nr_reqtype field.
+ * Demultiplexing is done using the hdr.nr_reqtype field.
  * FreeBSD uses the size value embedded in the _IOWR to determine
  * how much to copy in/out, so we define the ioctl() command
  * specifying only nmreq_header, and copyin/copyout the rest. */
@@ -664,7 +664,7 @@ struct nmreq_vale_list {
 
 /*
  * nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
- * Set or get the port header length of the port identified by nr_hdr.nr_name.
+ * Set or get the port header length of the port identified by hdr.nr_name.
  * The control device does not need to be bound to a netmap port.
  */
 struct nmreq_port_hdr {
@@ -698,7 +698,7 @@ struct nmreq_vale_polling {
 /*
  * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
  * Get info about the pools of the memory allocator of the netmap
- * port specified by nr_hdr.nr_name and nr_mem_id. The netmap control
+ * port specified by hdr.nr_name and nr_mem_id. The netmap control
  * device used for this operation does not need to be bound to a netmap
  * port.
  */

From 89caedcde8dafe1f842664ce3c05de1a7e58cff2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 11:26:33 +0200
Subject: [PATCH 1341/2207] netmap_ioctl: use NR_REG_ALL_NIC for internal
 register requests

This is necessary for those adapters that do not accept any
nr_mode (e.g. pipes).
---
 sys/dev/netmap/netmap.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 80db61b95..2a97f4aa3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2531,6 +2531,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					 * so that we can call netmap_get_na(). */
 					struct nmreq_register regreq;
 					bzero(®req, sizeof(regreq));
+					regreq.nr_mode = NR_REG_ALL_NIC;
 					regreq.nr_tx_slots = req->nr_tx_slots;
 					regreq.nr_rx_slots = req->nr_rx_slots;
 					regreq.nr_tx_rings = req->nr_tx_rings;
@@ -2598,6 +2599,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
 			bzero(®req, sizeof(regreq));
+			regreq.nr_mode = NR_REG_ALL_NIC;
+
 			/* For now we only support virtio-net headers, and only for
 			 * VALE ports, but this may change in future. Valid lengths
 			 * for the virtio-net header are 0 (no header), 10 and 12. */
@@ -2639,6 +2642,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			struct ifnet *ifp;
 
 			bzero(®req, sizeof(regreq));
+			regreq.nr_mode = NR_REG_ALL_NIC;
 			NMG_LOCK();
 			hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 			hdr->nr_body = (uintptr_t)®req;
@@ -2681,6 +2685,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				struct nmreq_register regreq;
 				bzero(®req, sizeof(regreq));
 				regreq.nr_mem_id = req->nr_mem_id;
+				regreq.nr_mode = NR_REG_ALL_NIC;
 
 				hdr->nr_reqtype = NETMAP_REQ_REGISTER;
 				hdr->nr_body = (uintptr_t)®req;

From 0c4c0596cd029321cddd787da8953f249b916d12 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 12:07:58 +0200
Subject: [PATCH 1342/2207] ctrl-api-test: add pools/port info get tests on
 pipes

---
 utils/ctrl-api-test.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index e90bb6078..f5a11f2ab 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -83,6 +83,7 @@ port_info_get(struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
+	req.nr_mem_id = ctx->nr_mem_id;
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
@@ -534,6 +535,30 @@ pipe_slave(struct TestContext *ctx)
 	return port_register(ctx);
 }
 
+/* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
+ * registration request used internall by netmap. */
+static int
+pipe_port_info_get(struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s}%s", ctx->ifname, "pipeid3");
+	ctx->ifname  = pipe_name;
+
+	return port_info_get(ctx);
+}
+
+static int
+pipe_pools_info_get(struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "xid");
+	ctx->ifname  = pipe_name;
+
+	return pools_info_get(ctx);
+}
+
 /* NETMAP_REQ_VALE_POLLING_ENABLE */
 static int
 vale_polling_enable(struct TestContext *ctx)
@@ -1246,6 +1271,8 @@ static struct mytest tests[] = {
 	decltest(pools_info_get_empty_ifname),
 	decltest(pipe_master),
 	decltest(pipe_slave),
+	decltest(pipe_port_info_get),
+	decltest(pipe_pools_info_get),
 	decltest(vale_polling_enable_disable),
 	decltest(unsupported_option),
 	decltest(infinite_options),

From e56c1e6f0a2511a8cdee56d0e25e419630addbaf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 12:13:26 +0200
Subject: [PATCH 1343/2207] ctrl-api-test: add -l option to list tests

---
 utils/ctrl-api-test.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index f5a11f2ab..6625267d1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1244,7 +1244,10 @@ sync_kloop_eventfds_mismatch(struct TestContext *ctx)
 static void
 usage(const char *prog)
 {
-	printf("%s -i IFNAME [-j TESTCASE]\n", prog);
+	printf("%s -i IFNAME\n"
+		"[-j TESTCASE_NUM]\n"
+		"[-l (list test cases)]\n",
+		prog);
 }
 
 struct mytest {
@@ -1311,14 +1314,15 @@ main(int argc, char **argv)
 	int num_tests;
 	int ret = 0;
 	int j   = -1;
-	int i;
+	int list = 0;
 	int opt;
+	int i;
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ifname  = "lo";
 	ctx.bdgname = "vale1x2";
 
-	while ((opt = getopt(argc, argv, "hi:j:")) != -1) {
+	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0]);
@@ -1332,6 +1336,10 @@ main(int argc, char **argv)
 			j = atoi(optarg);
 			break;
 
+		case 'l':
+			list = 1;
+			break;
+
 		default:
 			printf("    Unrecognized option %c\n", opt);
 			usage(argv[0]);
@@ -1339,6 +1347,16 @@ main(int argc, char **argv)
 		}
 	}
 
+	num_tests = sizeof(tests) / sizeof(tests[0]);
+
+	if (list) {
+		printf("Available tests:\n");
+		for (i = 0; i < num_tests; i++) {
+			printf("#%03d: %s\n", i + 1, tests[i].name);
+		}
+		return 0;
+	}
+
 	loopback_if = !strcmp(ctx.ifname, "lo");
 	if (loopback_if) {
 		/* For the tests, we need the MTU to be smaller than
@@ -1351,8 +1369,6 @@ main(int argc, char **argv)
 		}
 	}
 
-	num_tests = sizeof(tests) / sizeof(tests[0]);
-
 	if (j >= 0) {
 		j--; /* one-based --> zero-based */
 		if (j >= num_tests) {

From 145a11f61e195c0d1fb033fdfafab419b4d8e3cf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 12:15:05 +0200
Subject: [PATCH 1344/2207] ctrl-api-test: small reformatting

---
 utils/ctrl-api-test.c | 78 ++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 42 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 6625267d1..bb8246e9b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -16,10 +16,11 @@
 #ifdef __linux__
 #include 
 #else
-static int eventfd(int x, int y)
+static int
+eventfd(int x, int y)
 {
-	(void) x;
-	(void) y;
+	(void)x;
+	(void)y;
 	return 19;
 }
 #endif /* __linux__ */
@@ -42,7 +43,7 @@ struct TestContext {
 
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
-	void *csb; /* CSB entries (atok and ktoa) */
+	void *csb;                    /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
 };
 
@@ -84,7 +85,7 @@ port_info_get(struct TestContext *ctx)
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id = ctx->nr_mem_id;
-	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
@@ -98,8 +99,7 @@ port_info_get(struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-	                       req.nr_tx_rings && req.nr_rx_rings &&
-	                       req.nr_tx_rings;
+	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
 	if (!success) {
 		return -1;
 	}
@@ -109,7 +109,7 @@ port_info_get(struct TestContext *ctx)
 	ctx->nr_rx_slots = req.nr_rx_slots;
 	ctx->nr_tx_rings = req.nr_tx_rings;
 	ctx->nr_rx_rings = req.nr_rx_rings;
-	ctx->nr_mem_id = req.nr_mem_id;
+	ctx->nr_mem_id   = req.nr_mem_id;
 
 	return 0;
 }
@@ -174,11 +174,11 @@ port_register(struct TestContext *ctx)
 	}
 
 	/* Write back results to the context structure.*/
-	ctx->nr_tx_slots = req.nr_tx_slots;
-	ctx->nr_rx_slots = req.nr_rx_slots;
-	ctx->nr_tx_rings = req.nr_tx_rings;
-	ctx->nr_rx_rings = req.nr_rx_rings;
-	ctx->nr_mem_id = req.nr_mem_id;
+	ctx->nr_tx_slots   = req.nr_tx_slots;
+	ctx->nr_rx_slots   = req.nr_rx_slots;
+	ctx->nr_tx_rings   = req.nr_tx_rings;
+	ctx->nr_rx_rings   = req.nr_rx_rings;
+	ctx->nr_mem_id     = req.nr_mem_id;
 	ctx->nr_extra_bufs = req.nr_extra_bufs;
 
 	return -0;
@@ -189,7 +189,7 @@ static int
 num_registered_rings(struct TestContext *ctx)
 {
 	assert(ctx->nr_tx_slots > 0 && ctx->nr_rx_slots > 0 &&
-		ctx->nr_tx_rings > 0 && ctx->nr_rx_rings > 0);
+	       ctx->nr_tx_rings > 0 && ctx->nr_rx_rings > 0);
 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
 		return ctx->nr_tx_rings;
 	}
@@ -448,7 +448,7 @@ pools_info_get(struct TestContext *ctx)
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id = ctx->nr_mem_id;
-	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
 		return ret;
@@ -543,7 +543,7 @@ pipe_port_info_get(struct TestContext *ctx)
 	char pipe_name[128];
 
 	snprintf(pipe_name, sizeof(pipe_name), "%s}%s", ctx->ifname, "pipeid3");
-	ctx->ifname  = pipe_name;
+	ctx->ifname = pipe_name;
 
 	return port_info_get(ctx);
 }
@@ -554,7 +554,7 @@ pipe_pools_info_get(struct TestContext *ctx)
 	char pipe_name[128];
 
 	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "xid");
-	ctx->ifname  = pipe_name;
+	ctx->ifname = pipe_name;
 
 	return pools_info_get(ctx);
 }
@@ -727,7 +727,7 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 	unsigned long oldv;
 	FILE *f;
 
-	strncat(param, pname, sizeof(param)-1);
+	strncat(param, pname, sizeof(param) - 1);
 
 	f = fopen(param, "r+");
 	if (f == NULL) {
@@ -919,9 +919,9 @@ push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
 
 	memset(opt, 0, sizeof(*opt));
 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
-	opt->csb_atok = (uintptr_t)ctx->csb;
-	opt->csb_ktoa = (uintptr_t)
-			(ctx->csb + sizeof(struct nm_csb_atok) * num_entries);
+	opt->csb_atok            = (uintptr_t)ctx->csb;
+	opt->csb_ktoa            = (uintptr_t)(ctx->csb +
+                                    sizeof(struct nm_csb_atok) * num_entries);
 
 	push_option(&opt->nro_opt, ctx);
 
@@ -953,8 +953,8 @@ csb_mode_invalid_memory(struct TestContext *ctx)
 
 	memset(&opt, 0, sizeof(opt));
 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
-	opt.csb_atok = (uintptr_t)0x10;
-	opt.csb_ktoa = (uintptr_t)0x800;
+	opt.csb_atok            = (uintptr_t)0x10;
+	opt.csb_ktoa            = (uintptr_t)0x800;
 	push_option(&opt.nro_opt, ctx);
 
 	ctx->nr_flags = NR_EXCLUSIVE;
@@ -988,8 +988,7 @@ sync_kloop_worker(void *opaque)
 	struct nmreq_header hdr;
 	int ret;
 
-	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n",
-	       ctx->ifname);
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
@@ -1042,7 +1041,6 @@ sync_kloop(struct TestContext *ctx)
 	}
 
 	return sync_kloop_start_stop(ctx);
-
 }
 
 static int
@@ -1055,8 +1053,8 @@ sync_kloop_eventfds(struct TestContext *ctx)
 	int ret, i;
 
 	num_entries = num_registered_rings(ctx);
-	opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
-	opt = malloc(opt_size);
+	opt_size    = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
+	opt         = malloc(opt_size);
 	memset(opt, 0, opt_size);
 	opt->nro_opt.nro_next    = 0;
 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
@@ -1067,9 +1065,9 @@ sync_kloop_eventfds(struct TestContext *ctx)
 
 		assert(efd >= 0);
 		opt->eventfds[i].ioeventfd = efd;
-		efd = eventfd(0, 0);
+		efd                        = eventfd(0, 0);
 		assert(efd >= 0);
-		opt->eventfds[i].irqfd     = efd;
+		opt->eventfds[i].irqfd = efd;
 	}
 
 	push_option(&opt->nro_opt, ctx);
@@ -1098,7 +1096,6 @@ sync_kloop_eventfds_all(struct TestContext *ctx)
 	}
 
 	return sync_kloop_eventfds(ctx);
-
 }
 
 static int
@@ -1112,7 +1109,7 @@ sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 		return ret;
 	}
 
-	ret           = port_register_hwall_tx(ctx);
+	ret = port_register_hwall_tx(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -1134,7 +1131,6 @@ sync_kloop_nocsb(struct TestContext *ctx)
 	/* Sync kloop must fail because we did not use
 	 * NETMAP_REQ_OPT_CSB. */
 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
-
 }
 
 static int
@@ -1155,7 +1151,6 @@ sync_kloop_csb_on_start(struct TestContext *ctx)
 	}
 
 	return sync_kloop_start_stop(ctx);
-
 }
 
 static int
@@ -1171,7 +1166,7 @@ sync_kloop_conflict(struct TestContext *ctx)
 		return ret;
 	}
 
-	ret           = port_register_hwall(ctx);
+	ret = port_register_hwall(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -1225,7 +1220,7 @@ sync_kloop_eventfds_mismatch(struct TestContext *ctx)
 		return ret;
 	}
 
-	ret           = port_register_hwall_rx(ctx);
+	ret = port_register_hwall_rx(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -1238,16 +1233,15 @@ sync_kloop_eventfds_mismatch(struct TestContext *ctx)
 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
 
 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
-
 }
 
 static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME\n"
-		"[-j TESTCASE_NUM]\n"
-		"[-l (list test cases)]\n",
-		prog);
+	       "[-j TESTCASE_NUM]\n"
+	       "[-l (list test cases)]\n",
+	       prog);
 }
 
 struct mytest {
@@ -1312,8 +1306,8 @@ main(int argc, char **argv)
 	struct TestContext ctx;
 	int loopback_if;
 	int num_tests;
-	int ret = 0;
-	int j   = -1;
+	int ret  = 0;
+	int j    = -1;
 	int list = 0;
 	int opt;
 	int i;

From beab2ba3c77c71485eb44a0785cad40896caac03 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 12:24:21 +0200
Subject: [PATCH 1345/2207] import pkt-gen fixes from freebsd

---
 apps/pkt-gen/pkt-gen.8 | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
index 62f1d30a1..4f522a1b3 100644
--- a/apps/pkt-gen/pkt-gen.8
+++ b/apps/pkt-gen/pkt-gen.8
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 1, 2016
+.Dd October 23, 2018
 .Dt PKT-GEN 8
 .Os
 .Sh NAME
@@ -170,10 +170,9 @@ packets to be received by the target host.
 .Dl
 .Nm
 -i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 -D 00:07:43:29:2a:e0
-.Sh FILES
-.Xr netmap 4
 .Sh SEE ALSO
-.Xr netmap 4
+.Xr netmap 4 ,
+.Xr bridge 8
 .Sh AUTHORS
 This manual page was written by
 .An George V. Neville-Neil Aq gnn@FreeBSD.org .

From f84eed2fa273fd8d1ecbe8944c3566b77f54376f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 12:35:36 +0200
Subject: [PATCH 1346/2207] apps: ctrs.h: add FreeBSD token

---
 apps/include/ctrs.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h
index d2c195e7b..a41ae6853 100644
--- a/apps/include/ctrs.h
+++ b/apps/include/ctrs.h
@@ -1,6 +1,8 @@
 #ifndef CTRS_H_
 #define CTRS_H_
 
+/* $FreeBSD$ */
+
 #include 
 
 /* counters to accumulate statistics */

From 5817f5b2cd38e21c9bb0922f0c95b48470631925 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 16:50:24 +0200
Subject: [PATCH 1347/2207] pkt-gen: small fixes

---
 apps/pkt-gen/pkt-gen.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index c1c31b9e3..9b24e1fe0 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2309,10 +2309,6 @@ usage(int errcode)
 		     "\t-i interface		interface name\n"
 		     "\t-f function		tx rx ping pong txseq rxseq\n"
 		     "\t-n count		number of iterations (can be 0)\n"
-#ifdef notyet
-		     "\t-t pkts_to_send		also forces tx mode\n"
-		     "\t-r pkts_to_receive	also forces rx mode\n"
-#endif
 		     "\t-l pkt_size		in bytes excluding CRC\n"
 		     "\t			(if passed a second time, use random sizes\n"
 		     "\t			 bigger than the second one and lower than\n"
@@ -2371,7 +2367,6 @@ usage(int errcode)
 #endif
 		     "\t-e extra-bufs		extra_bufs - goes in nr_arg3\n"
 		     "\t-B                      account for ethernet framing when showing bps\n"
-		     "\t-m			ignored\n"
 		     "",
 		cmd);
 	exit(errcode);
@@ -2440,7 +2435,7 @@ start_threads(struct glob_arg *g) {
 		t->used = 1;
 		t->me = i;
 		if (g->affinity >= 0) {
-			t->affinity = (g->affinity + i) % g->system_cpus;
+			t->affinity = (g->affinity + i) % g->cpus;
 		} else {
 			t->affinity = -1;
 		}
@@ -2722,7 +2717,7 @@ main(int arc, char **argv)
 	g.wait_link = 2;	/* wait 2 seconds for physical ports */
 
 	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
-	    "T:w:WvR:XC:H:e:E:m:rP:zZAhBM:")) != -1) {
+	    "T:w:WvR:XC:H:e:E:rP:zZAhBM:")) != -1) {
 
 		switch(ch) {
 		default:
@@ -2733,6 +2728,7 @@ main(int arc, char **argv)
 		case 'h':
 			usage(0);
 			break;
+
 		case '4':
 			g.af = AF_INET;
 			break;
@@ -2888,9 +2884,6 @@ main(int arc, char **argv)
 		case 'P':
 			g.packet_file = strdup(optarg);
 			break;
-		case 'm':
-			/* ignored */
-			break;
 		case 'r':
 			g.options |= OPT_RUBBISH;
 			break;

From 879dd25d6286f98870b05a992163afb53e7f71f5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 17:05:22 +0200
Subject: [PATCH 1348/2207] apps: pkt-gen: use g->framing also in tx_output()

---
 apps/pkt-gen/pkt-gen.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 9b24e1fe0..57ece762e 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2267,7 +2267,7 @@ rxseq_body(void *data)
 
 
 static void
-tx_output(struct my_ctrs *cur, double delta, const char *msg)
+tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg)
 {
 	double bw, raw_bw, pps, abs;
 	char b1[40], b2[80], b3[80];
@@ -2291,8 +2291,7 @@ tx_output(struct my_ctrs *cur, double delta, const char *msg)
 		size = 60;
 	pps = cur->pkts / delta;
 	bw = (8.0 * cur->bytes) / delta;
-	/* raw packets have4 bytes crc + 20 bytes framing */
-	raw_bw = (8.0 * (cur->pkts * 24 + cur->bytes)) / delta;
+	raw_bw = (8.0 * cur->bytes + cur->pkts * g->framing) / delta;
 	abs = cur->pkts / (double)(cur->events);
 
 	printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n",
@@ -2585,9 +2584,9 @@ main_thread(struct glob_arg *g)
 	timersub(&toc, &tic, &toc);
 	delta_t = toc.tv_sec + 1e-6* toc.tv_usec;
 	if (g->td_type == TD_TYPE_SENDER)
-		tx_output(&cur, delta_t, "Sent");
+		tx_output(g, &cur, delta_t, "Sent");
 	else if (g->td_type == TD_TYPE_RECEIVER)
-		tx_output(&cur, delta_t, "Received");
+		tx_output(g, &cur, delta_t, "Received");
 }
 
 struct td_desc {
@@ -2897,6 +2896,7 @@ main(int arc, char **argv)
 			g.options |= OPT_PPS_STATS;
 			break;
 		case 'B':
+			/* raw packets have4 bytes crc + 20 bytes framing */
 			// XXX maybe add an option to pass the IFG
 			g.framing = 24 * 8;
 			break;

From 3c782863a2e47009e93bf6f514907584450bf4ad Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 17:15:32 +0200
Subject: [PATCH 1349/2207] apps: pkt-gen: remove unused/obsolete -e and -E
 arguments

---
 apps/pkt-gen/pkt-gen.c | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 57ece762e..9098df20c 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -299,8 +299,6 @@ struct glob_arg {
 	char *nmr_config;
 	int dummy_send;
 	int virt_header;	/* send also the virt_header */
-	int extra_bufs;		/* goes in nr_arg3 */
-	int extra_pipes;	/* goes in nr_arg1 */
 	char *packet_file;	/* -P option */
 #define	STATS_WIN	15
 	int win_idx;
@@ -2364,7 +2362,6 @@ usage(int errcode)
 		     "\t			If there is no 4th number, then the 3rd is\n"
 		     "\t			assigned to both #tx-rings and #rx-rings.\n"
 #endif
-		     "\t-e extra-bufs		extra_bufs - goes in nr_arg3\n"
 		     "\t-B                      account for ethernet framing when showing bps\n"
 		     "",
 		cmd);
@@ -2716,7 +2713,7 @@ main(int arc, char **argv)
 	g.wait_link = 2;	/* wait 2 seconds for physical ports */
 
 	while ((ch = getopt(arc, argv, "46a:f:F:Nn:i:Il:d:s:D:S:b:c:o:p:"
-	    "T:w:WvR:XC:H:e:E:rP:zZAhBM:")) != -1) {
+	    "T:w:WvR:XC:H:rP:zZAhBM:")) != -1) {
 
 		switch(ch) {
 		default:
@@ -2874,12 +2871,6 @@ main(int arc, char **argv)
 		case 'H':
 			g.virt_header = atoi(optarg);
 			break;
-		case 'e': /* extra bufs */
-			g.extra_bufs = atoi(optarg);
-			break;
-		case 'E':
-			g.extra_pipes = atoi(optarg);
-			break;
 		case 'P':
 			g.packet_file = strdup(optarg);
 			break;
@@ -2987,12 +2978,6 @@ main(int arc, char **argv)
 	bzero(&base_nmd, sizeof(base_nmd));
 
 	parse_nmr_config(g.nmr_config, &base_nmd.req);
-	if (g.extra_bufs) {
-		base_nmd.req.nr_arg3 = g.extra_bufs;
-	}
-	if (g.extra_pipes) {
-	    base_nmd.req.nr_arg1 = g.extra_pipes;
-	}
 
 	base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR;
 

From 7978e756058183a0c32cc26ed60c29c511bfd6c9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 17:31:39 +0200
Subject: [PATCH 1350/2207] apps: pkt-gen: improve usage()

---
 apps/pkt-gen/pkt-gen.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 9098df20c..ea3d3f4fc 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -572,7 +572,7 @@ system_ncpus(void)
 /*
  * parse the vale configuration in conf and put it in nmr.
  * Return the flag set if necessary.
- * The configuration may consist of 0 to 4 numbers separated
+ * The configuration may consist of 1 to 4 numbers separated
  * by commas: #tx-slots,#rx-slots,#tx-rings,#rx-rings.
  * Missing numbers or zeroes stand for default values.
  * As an additional convenience, if exactly one number
@@ -2323,7 +2323,6 @@ usage(int errcode)
 		     "\t-R rate			in packets per second\n"
 		     "\t-X			dump payload\n"
 		     "\t-H len			add empty virtio-net-header with size 'len'\n"
-		     "\t-E pipes		allocate extra space for a number of pipes\n"
 		     "\t-r			do not touch the buffers (send rubbish)\n"
 	             "\t-P file			load packet from pcap file\n"
 		     "\t-z			use random IPv4 src address/port\n"
@@ -2350,9 +2349,9 @@ usage(int errcode)
 		     "\t			OPT_PPS_STATS   2048\n"
 		     "\t-W			exit RX with no traffic\n"
 		     "\t-v			verbose (more v = more verbose)\n"
+		     "\t-B                      account for ethernet framing when showing bps\n"
 		     "\t-C vale-config		specify a vale config\n"
-#ifdef notyet
-		     "\t			The configuration may consist of 0 to 4\n"
+		     "\t			The configuration may consist of 1 to 4\n"
 		     "\t			numbers separated by commas:\n"
 		     "\t			#tx-slots,#rx-slots,#tx-rings,#rx-rings.\n"
 		     "\t			Missing numbers or zeroes stand for default\n"
@@ -2361,8 +2360,6 @@ usage(int errcode)
 		     "\t			is assigned to both #tx-slots and #rx-slots.\n"
 		     "\t			If there is no 4th number, then the 3rd is\n"
 		     "\t			assigned to both #tx-rings and #rx-rings.\n"
-#endif
-		     "\t-B                      account for ethernet framing when showing bps\n"
 		     "",
 		cmd);
 	exit(errcode);

From 288c642d9f01f61d03f45695d12d8cf388e888d8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 17:32:36 +0200
Subject: [PATCH 1351/2207] apps: pkt-gen: update man page

---
 apps/pkt-gen/pkt-gen.8 | 227 +++++++++++++++++++++++++++++++----------
 1 file changed, 172 insertions(+), 55 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
index 4f522a1b3..6388ba55b 100644
--- a/apps/pkt-gen/pkt-gen.8
+++ b/apps/pkt-gen/pkt-gen.8
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 23, 2018
+.Dd October 25, 2018
 .Dt PKT-GEN 8
 .Os
 .Sh NAME
@@ -36,96 +36,212 @@
 .Bl -item -compact
 .It
 .Nm
+.Op Fl h46XzZNIWvrAB
 .Op Fl i Ar interface
 .Op Fl f Ar function
 .Op Fl n Ar count
-.Op Fl t Ar pkts_to_send
-.Op Fl r Ar pkts_to_receive
 .Op Fl l Ar pkt_size
+.Op Fl b Ar burst_size
 .Op Fl d Ar dst_ip[:port[-dst_ip:port]]
 .Op Fl s Ar src_ip[:port[-src_ip:port]]
-.Op Fl D Ar dst-mac
-.Op Fl S Ar src-mac
+.Op Fl D Ar dst_mac
+.Op Fl S Ar src_mac
 .Op Fl a Ar cpu_id
-.Op Fl b Ar burst size
-.Op Fl c Ar cores
+.Op Fl c Ar cpus
 .Op Fl p Ar threads
 .Op Fl T Ar report_ms
-.Op Fl P
+.Op Fl P Ar file
 .Op Fl w Ar wait_for_link_time
 .Op Fl R Ar rate
-.Op Fl X
 .Op Fl H Ar len
-.Op Fl P Ar xfile
-.Op Fl z
-.Op Fl Z
+.Op Fl F Ar num_frags
+.Op Fl M Ar frag_size
+.Op Fl C Ar port_config
+.El
 .Sh DESCRIPTION
 .Nm
-generates and receives raw network packets using
-.Xr netmap 4 .
+leverages
+.Xr netmap 4
+to generate and receive raw network packets in batches.
 The arguments are as follows:
-.Pp
 .Bl -tag -width Ds
+.It Fl h
+Show program usage and exit.
 .It Fl i Ar interface
-Network interface name.
-.It Fl f Ar function tx rx ping pong
-Set the function to transmit, receive of ping/pong.
+Name of the network interface that
+.Nm
+operates on.
+It can be a system network interface (e.g., em0),
+the name of a
+.Xr vale 4
+port (e.g., valeSSS:PPP), the name of a netmap pipe or monitor,
+or any valid netmap port name accepted by the
+.Ar nm_open
+library function, as documented in
+.Xr netmap 4
+(NIOCREGIF section).
+.It Fl f Ar function
+The function to be executed by
+.Nm .
+Specify
+.Ar tx
+for transmission,
+.Ar rx
+for reception,
+.Ar ping
+for client-side ping-pong operation, and
+.Ar pong
+for server-side ping-pong operation.
 .It Fl n count
-Number of iterations (can be 0).
-.It Fl t pkts_to_send
-Number of packets to send.  Also forces transmit mode.
-.It Fl r Ar pkts_to_receive
-Number of packets to receive.  Also forces rx mode.
+Number of iterations of the
+.Nm
+function, with 0 meaning infinite).
+In case of
+.Ar tx
+or
+.Ar rx ,
+.Ar count
+is the number of packets to receive or transmit.
+In case of
+.Ar ping
+or
+.Ar pong ,
+.Ar count
+is the number of ping-pong transactions.
 .It Fl l Ar pkt_size
 Packet size in bytes excluding CRC.
+.It Fl b Ar burst_size
+Transmit or receive up to
+.Ar burst_size
+packets at a time.
+.It Fl 4
+Use IPv4 addresses.
+.It Fl 6
+Use IPv6 addresses.
 .It Fl d Ar dst_ip[:port[-dst_ip:port]]
-Destination IPv4 address and port, single or range.
+Destination IPv4/IPv6 address and port, single or range.
 .It Fl s Ar src_ip[:port[-src_ip:port]]
-Source IPv4 address and port, single or range.
-.It Fl D Ar dst-mac
-Destination MAC address in colon notation.
-.It Fl S Ar src-mac
+Source IPv4/IPv6 address and port, single or range.
+.It Fl D Ar dst_mac
+Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).
+.It Fl S Ar src_mac
 Source MAC address in colon notation.
 .It Fl a Ar cpu_id
-Tie
+Pin the first thread of
 .Nm
-to a particular CPU core using
-.Xr setaffinity 2.
-.It Fl b Ar burst size
-Set the size of a burst of packets.
-.It Fl c Ar cores
-Number of cores to use.
+to a particular CPU using
+.Xr pthread_setaffinity_np 3 .
+If more threads are used, they are pinned to the subsequent CPUs,
+one per thread.
+.It Fl c Ar cpus
+Maximum number of CPUs to use (0 means to use all the available ones).
 .It Fl p Ar threads
 Number of threads to use.
+By default, only a single thread is used
+to handle all the netmap rings.
+If
+.Ar threads
+is larger than one, each thread handles a single TX ring (in
+.Ar tx
+mode), a single RX ring (in
+.Ar rx
+mode), or a TX/RX ring couple.
+The number of
+.Ar threads
+must be less or equal than the number of TX (or RX) ring available
+in the device specified by
+.Ar interface .
 .It Fl T Ar report_ms
 Number of milliseconds between reports.
-.It Fl P
-Use libpcap instead of netmap for reading or writing.
 .It Fl w Ar wait_for_link_time
-Number of seconds to wait to make sure that the network link is up.  A
-network device driver may take some time to create a new
-transmit/receive ring pair when
+Number of seconds to wait before starting the
+.Nm
+function, useuful to make sure that the network link is up.
+A network device driver may take some time to enter netmap mode, or
+to create a new transmit/receive ring pair when
 .Xr netmap 4
 requests one.
 .It Fl R Ar rate
-Packet transmission rate.  Not setting the packet transmission rate tells
+Packet transmission rate.
+Not setting the packet transmission rate tells
 .Nm
-to transmit packets as quickly as possible.  On servers from 2010 on-wards
+to transmit packets as quickly as possible.
+On servers from 2010 on-wards
 .Xr netmap 4
 is able to completely use all of the bandwidth of a 10 or 40Gbps link,
 so this option should be used unless your intention is to saturate the link.
 .It Fl X
-Dump payload transmitted or received.
+Dump payload of each packet transmitted or received.
 .It Fl H Ar len
-Add empty virtio-net-header with size 'len'.  This option is only use
-with Virtual Machine technologies that use virtio as a network interface.
+Add empty virtio-net-header with size 'len'.
+Valid sizes are 0, 10 and 12.
+This option is only used with Virtual Machine technologies that use virtio
+as a network interface.
 .It Fl P Ar file
-Load the packet from a pcap file rather than constructing it inside of
-.Nm
+Load the packet to be transmitted from a pcap file rather than constructing
+it within
+.Nm .
 .It Fl z
-Use random IPv4 src address/port
+Use random IPv4/IPv6 src address/port.
 .It Fl Z
-Use random IPv4 dst address/port
+Use random IPv4/IPv6 dst address/port.
+.It Fl N
+Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).
+.It Fl F Ar num_frags
+Send multi-slot packets, each one with
+.Ar num_frags
+fragments.
+A multi-slot packet is represented by two or more consecutive netmap slots
+with the
+.Ar NS_MOREFRAG
+flag set (except for the last slot).
+This is useful to transmit or receive packets larger than the netmap
+buffer size.
+.It Fl M Ar frag_size
+In multi-slot mode,
+.Ar frag_size
+specifies the size of each fragment, if smaller than the packet length
+divided by
+.Ar num_frags .
+.It Fl I
+Use indirect buffers.
+It is only valid for transmitting on VALE ports,
+and it is implemented by setting the
+.Ar NS_INDIRECT
+flag in the netmap slots.
+.It Fl W
+Exit immediately if all the RX rings are empty the first time they are
+examined.
+.It Fl v
+Increase the verbosity level.
+.It Fl r
+In
+.Ar tx
+mode, do not initialize packets, but send whatever the content of
+the uninitialized netmap buffers is (rubbish mode).
+.It Fl A
+Compute mean and standard deviation (over a sliding window) for the
+transmit or receive rate.
+.It Fl B
+Take Ethernet framing and CRC into account when computing the average bps.
+This adds 4 bytes of CRC and 20 bytes of framing to each packet.
+.It Fl C Ar tx_slots[,rx_slots[,tx_rings[,rx_rings]]]
+Configuration in terms of number of rings and slots to be used when
+opening the netmap port.
+Such configuration has effect on software ports
+created on the fly, such as VALE ports and netmap pipes.
+The configuration may consist of 1 to 4 numbers separated by commas:
+.Ar tx_slots , rx_slots , tx_rings , rx_rings .
+Missing numbers or zeroes stand for default values.
+As an additional convenience, if exactly one number is specified,
+then this is assigned to both
+.Ar tx_slots
+and
+.Ar rx_slots .
+If there is no fourth number, then the third one is assigned to both
+.Ar tx_rings
+and
+.Ar rx_rings .
 .El
 .Pp
 .Nm
@@ -133,7 +249,7 @@ is a raw packet generator that can utilize either
 .Xr netmap 4
 or
 .Xr bpf 4
-but which is most often uses with
+but which is most often used with
 .Xr netmap 4 .
 The
 .Ar interface name
@@ -146,7 +262,8 @@ system to balance traffic across the interface.
 .Nm
 can peel off one or more of the transmit or receive rings for its own
 use without interfering with packets that might otherwise be destined
-for the host.  For example on a system with a Chelsio Network
+for the host.
+For example on a system with a Chelsio Network
 Interface Card (NIC) the interface specification of
 .Ar -i netmap:ncxl0
 gives
@@ -156,18 +273,18 @@ the more commonly known cxl0 interface, which is used by the operating
 system's TCP/IP stack.
 .Sh EXAMPLES
 Capture and count all packets arriving on the operating system's cxl0
-interface.  Using this will block packets from reaching the operating
+interface.
+Using this will block packets from reaching the operating
 system's network stack.
-.Dl
 .Pp
 .Nm
 -i cxl0 -f rx
 .Pp
 Send a stream of fake DNS packets between two hosts with a packet
-length of 128 bytes.  You must set the destination MAC address for
+length of 128 bytes.
+You must set the destination MAC address for
 packets to be received by the target host.
 .Pp
-.Dl
 .Nm
 -i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 -D 00:07:43:29:2a:e0
 .Sh SEE ALSO

From 10e9ed1cfc97d848b81dddb18b7b0c9ed6ce4d02 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 17:51:19 +0200
Subject: [PATCH 1352/2207] apps: pkt-gen: generate usage from pkt-gen.8

---
 apps/pkt-gen/pkt-gen.8 |   4 +-
 apps/pkt-gen/pkt-gen.c | 190 ++++++++++++++++++++++++++++-------------
 2 files changed, 136 insertions(+), 58 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
index 6388ba55b..74226cf5d 100644
--- a/apps/pkt-gen/pkt-gen.8
+++ b/apps/pkt-gen/pkt-gen.8
@@ -92,7 +92,7 @@ for reception,
 for client-side ping-pong operation, and
 .Ar pong
 for server-side ping-pong operation.
-.It Fl n count
+.It Fl n Ar count
 Number of iterations of the
 .Nm
 function, with 0 meaning infinite).
@@ -110,6 +110,8 @@ or
 is the number of ping-pong transactions.
 .It Fl l Ar pkt_size
 Packet size in bytes excluding CRC.
+If passed a second time, use random sizes larger or equal than the
+second one and lower than the first one.
 .It Fl b Ar burst_size
 Transmit or receive up to
 .Ar burst_size
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index ea3d3f4fc..a83c94225 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2299,67 +2299,143 @@ tx_output(struct glob_arg *g, struct my_ctrs *cur, double delta, const char *msg
 static void
 usage(int errcode)
 {
+/* This usage is generated from the pkt-gen man page:
+ *   $ man pkt-gen > x
+ * and pasted here adding the string terminators and endlines with simple
+ * regular expressions. */
 	const char *cmd = "pkt-gen";
 	fprintf(stderr,
 		"Usage:\n"
 		"%s arguments\n"
-		     "\t-i interface		interface name\n"
-		     "\t-f function		tx rx ping pong txseq rxseq\n"
-		     "\t-n count		number of iterations (can be 0)\n"
-		     "\t-l pkt_size		in bytes excluding CRC\n"
-		     "\t			(if passed a second time, use random sizes\n"
-		     "\t			 bigger than the second one and lower than\n"
-		     "\t			 the first one)\n"
-		     "\t-d dst_ip[:port[-dst_ip:port]]   single or range\n"
-		     "\t-s src_ip[:port[-src_ip:port]]   single or range\n"
-		     "\t-D dst-mac\n"
-		     "\t-S src-mac\n"
-		     "\t-a cpu_id		use setaffinity\n"
-		     "\t-b burst size		testing, mostly\n"
-		     "\t-c cores		cores to use\n"
-		     "\t-p threads		processes/threads to use\n"
-		     "\t-T report_ms		milliseconds between reports\n"
-		     "\t-w wait_for_link_time	in seconds\n"
-		     "\t-R rate			in packets per second\n"
-		     "\t-X			dump payload\n"
-		     "\t-H len			add empty virtio-net-header with size 'len'\n"
-		     "\t-r			do not touch the buffers (send rubbish)\n"
-	             "\t-P file			load packet from pcap file\n"
-		     "\t-z			use random IPv4 src address/port\n"
-		     "\t-Z			use random IPv4 dst address/port\n"
-		     "\t-F num_frags		send multi-slot packets\n"
-		     "\t-M			set MTU\n"
-		     "\t-A			activate pps stats on receiver\n"
-		     "\t-4			IPv4\n"
-		     "\t-6			IPv6\n"
-		     "\t-N			don't normalize units (Kbps/Mbps/etc)\n"
-		     "\t-I			use indirect buffers, tx only\n"
-		     "\t-o options		data generation options (parsed using atoi)\n"
-		     "\t			OPT_PREFETCH	1\n"
-		     "\t			OPT_ACCESS	2\n"
-		     "\t			OPT_COPY	4\n"
-		     "\t			OPT_MEMCPY	8\n"
-		     "\t			OPT_TS		16 (add a timestamp)\n"
-		     "\t			OPT_INDIRECT	32 (use indirect buffers)\n"
-		     "\t			OPT_DUMP	64 (dump rx/tx traffic)\n"
-		     "\t			OPT_RUBBISH	256\n"
-		     "\t			    (send wathever the buffers contain)\n"
-		     "\t			OPT_RANDOM_SRC  512\n"
-		     "\t			OPT_RANDOM_DST  1024\n"
-		     "\t			OPT_PPS_STATS   2048\n"
-		     "\t-W			exit RX with no traffic\n"
-		     "\t-v			verbose (more v = more verbose)\n"
-		     "\t-B                      account for ethernet framing when showing bps\n"
-		     "\t-C vale-config		specify a vale config\n"
-		     "\t			The configuration may consist of 1 to 4\n"
-		     "\t			numbers separated by commas:\n"
-		     "\t			#tx-slots,#rx-slots,#tx-rings,#rx-rings.\n"
-		     "\t			Missing numbers or zeroes stand for default\n"
-		     "\t			values. As an additional convenience, if\n"
-		     "\t			exactly one number is specified, then this\n"
-		     "\t			is assigned to both #tx-slots and #rx-slots.\n"
-		     "\t			If there is no 4th number, then the 3rd is\n"
-		     "\t			assigned to both #tx-rings and #rx-rings.\n"
+"     -h      Show program usage and exit.\n"
+"\n"
+"     -i interface\n"
+"             Name of the network interface that pkt-gen operates on.  It can be a system network interface\n"
+"             (e.g., em0), the name of a vale(4) port (e.g., valeSSS:PPP), the name of a netmap pipe or\n"
+"             monitor, or any valid netmap port name accepted by the nm_open library function, as docu-\n"
+"             mented in netmap(4) (NIOCREGIF section).\n"
+"\n"
+"     -f function\n"
+"             The function to be executed by pkt-gen.  Specify tx for transmission, rx for reception, ping\n"
+"             for client-side ping-pong operation, and pong for server-side ping-pong operation.\n"
+"\n"
+"     -n count\n"
+"             Number of iterations of the pkt-gen function, with 0 meaning infinite).  In case of tx or rx,\n"
+"             count is the number of packets to receive or transmit.  In case of ping or pong, count is the\n"
+"             number of ping-pong transactions.\n"
+"\n"
+"     -l pkt_size\n"
+"             Packet size in bytes excluding CRC.  If passed a second time, use random sizes larger or\n"
+"             equal than the second one and lower than the first one.\n"
+"\n"
+"     -b burst_size\n"
+"             Transmit or receive up to burst_size packets at a time.\n"
+"\n"
+"     -4      Use IPv4 addresses.\n"
+"\n"
+"     -6      Use IPv6 addresses.\n"
+"\n"
+"     -d dst_ip[:port[-dst_ip:port]]\n"
+"             Destination IPv4/IPv6 address and port, single or range.\n"
+"\n"
+"     -s src_ip[:port[-src_ip:port]]\n"
+"             Source IPv4/IPv6 address and port, single or range.\n"
+"\n"
+"     -D dst_mac\n"
+"             Destination MAC address in colon notation (e.g., aa:bb:cc:dd:ee:00).\n"
+"\n"
+"     -S src_mac\n"
+"             Source MAC address in colon notation.\n"
+"\n"
+"     -a cpu_id\n"
+"             Pin the first thread of pkt-gen to a particular CPU using pthread_setaffinity_np(3).  If more\n"
+"             threads are used, they are pinned to the subsequent CPUs, one per thread.\n"
+"\n"
+"     -c cpus\n"
+"             Maximum number of CPUs to use (0 means to use all the available ones).\n"
+"\n"
+"     -p threads\n"
+"             Number of threads to use.  By default, only a single thread is used to handle all the netmap\n"
+"             rings.  If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n"
+"             single RX ring (in rx mode), or a TX/RX ring couple.  The number of threads must be less or\n"
+"             equal than the number of TX (or RX) ring available in the device specified by interface.\n"
+"\n"
+"     -T report_ms\n"
+"             Number of milliseconds between reports.\n"
+"\n"
+"     -w wait_for_link_time\n"
+"             Number of seconds to wait before starting the pkt-gen function, useuful to make sure that the\n"
+"             network link is up.  A network device driver may take some time to enter netmap mode, or to\n"
+"             create a new transmit/receive ring pair when netmap(4) requests one.\n"
+"\n"
+"     -R rate\n"
+"             Packet transmission rate.  Not setting the packet transmission rate tells pkt-gen to transmit\n"
+"             packets as quickly as possible.  On servers from 2010 on-wards netmap(4) is able to com-\n"
+"             pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n"
+"             your intention is to saturate the link.\n"
+"\n"
+"     -X      Dump payload of each packet transmitted or received.\n"
+"\n"
+"     -H len  Add empty virtio-net-header with size 'len'.  Valid sizes are 0, 10 and 12.  This option is\n"
+"             only used with Virtual Machine technologies that use virtio as a network interface.\n"
+"\n"
+"     -P file\n"
+"             Load the packet to be transmitted from a pcap file rather than constructing it within\n"
+"             pkt-gen.\n"
+"\n"
+"     -z      Use random IPv4/IPv6 src address/port.\n"
+"\n"
+"     -Z      Use random IPv4/IPv6 dst address/port.\n"
+"\n"
+"     -N      Do not normalize units (i.e., use bps, pps instead of Mbps, Kpps, etc.).\n"
+"\n"
+"     -F num_frags\n"
+"             Send multi-slot packets, each one with num_frags fragments.  A multi-slot packet is repre-\n"
+"             sented by two or more consecutive netmap slots with the NS_MOREFRAG flag set (except for the\n"
+"             last slot).  This is useful to transmit or receive packets larger than the netmap buffer\n"
+"             size.\n"
+"\n"
+"     -M frag_size\n"
+"             In multi-slot mode, frag_size specifies the size of each fragment, if smaller than the packet\n"
+"             length divided by num_frags.\n"
+"\n"
+"     -I      Use indirect buffers.  It is only valid for transmitting on VALE ports, and it is implemented\n"
+"             by setting the NS_INDIRECT flag in the netmap slots.\n"
+"\n"
+"     -W      Exit immediately if all the RX rings are empty the first time they are examined.\n"
+"\n"
+"     -v      Increase the verbosity level.\n"
+"\n"
+"     -r      In tx mode, do not initialize packets, but send whatever the content of the uninitialized\n"
+"             netmap buffers is (rubbish mode).\n"
+"\n"
+"     -A      Compute mean and standard deviation (over a sliding window) for the transmit or receive rate.\n"
+"\n"
+"     -B      Take Ethernet framing and CRC into account when computing the average bps.  This adds 4 bytes\n"
+"             of CRC and 20 bytes of framing to each packet.\n"
+"\n"
+"     -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n"
+"             Configuration in terms of number of rings and slots to be used when opening the netmap port.\n"
+"             Such configuration has effect on software ports created on the fly, such as VALE ports and\n"
+"             netmap pipes.  The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n"
+"             rx_slots, tx_rings, rx_rings.  Missing numbers or zeroes stand for default values.  As an\n"
+"             additional convenience, if exactly one number is specified, then this is assigned to both\n"
+"             tx_slots and rx_slots.  If there is no fourth number, then the third one is assigned to both\n"
+"             tx_rings and rx_rings.\n"
+"\n"
+"     -o options		data generation options (parsed using atoi)\n"
+"				OPT_PREFETCH	1\n"
+"				OPT_ACCESS	2\n"
+"				OPT_COPY	4\n"
+"				OPT_MEMCPY	8\n"
+"				OPT_TS		16 (add a timestamp)\n"
+"				OPT_INDIRECT	32 (use indirect buffers)\n"
+"				OPT_DUMP	64 (dump rx/tx traffic)\n"
+"				OPT_RUBBISH	256\n"
+"					(send wathever the buffers contain)\n"
+"				OPT_RANDOM_SRC  512\n"
+"				OPT_RANDOM_DST  1024\n"
+"				OPT_PPS_STATS   2048\n"
 		     "",
 		cmd);
 	exit(errcode);

From 6ed5f144c9e038fd49bbc4ffa41a741de47dea6f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 18:27:13 +0200
Subject: [PATCH 1353/2207] sync-kloop: reuse nm_stst_barrier()

---
 sys/dev/netmap/netmap_kloop.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index e6557f30d..e61d69c35 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -91,7 +91,7 @@ sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 	 *          STORE(hwtail)        LOAD(hwcur)
 	 */
 	CSB_WRITE(ptr, hwcur, hwcur);
-	mb();
+	nm_stst_barrier();
 	CSB_WRITE(ptr, hwtail, hwtail);
 }
 
@@ -108,7 +108,7 @@ sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
 	 * (see explanation in ptnetmap_guest_write_kring_csb).
 	 */
 	CSB_READ(ptr, head, shadow_ring->head);
-	mb();
+	nm_stst_barrier();
 	CSB_READ(ptr, cur, shadow_ring->cur);
 	CSB_READ(ptr, sync_flags, shadow_ring->flags);
 }

From 155bdf7a58178c7a91f33c65aada68a85e22c935 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 25 Oct 2018 18:48:38 +0200
Subject: [PATCH 1354/2207] check that poll() and sync() are not called in CSB
 mode

---
 sys/dev/netmap/netmap.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2a97f4aa3..b21803277 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2742,20 +2742,20 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 	case NIOCTXSYNC:
 	case NIOCRXSYNC: {
-		if (priv->np_nifp == NULL) {
+		if (unlikely(priv->np_nifp == NULL)) {
 			error = ENXIO;
 			break;
 		}
 		mb(); /* make sure following reads are not from cache */
 
-		na = priv->np_na;      /* we have a reference */
-
-		if (na == NULL) {
-			D("Internal error: nifp != NULL && na == NULL");
-			error = ENXIO;
+		if (unlikely(priv->np_csb_atok_base)) {
+			nm_prerr("Invalid sync in CSB mode\n");
+			error = EBUSY;
 			break;
 		}
 
+		na = priv->np_na;      /* we have a reference */
+
 		mbq_init(&q);
 		t = (cmd == NIOCTXSYNC ? NR_TX : NR_RX);
 		krings = NMR(na, t);
@@ -3150,16 +3150,20 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 
 	mbq_init(&q);
 
-	if (priv->np_nifp == NULL) {
-		D("No if registered");
+	if (unlikely(priv->np_nifp == NULL)) {
 		return POLLERR;
 	}
 	mb(); /* make sure following reads are not from cache */
 
 	na = priv->np_na;
 
-	if (!nm_netmap_on(na))
+	if (unlikely(!nm_netmap_on(na)))
+		return POLLERR;
+
+	if (unlikely(priv->np_csb_atok_base)) {
+		nm_prerr("Invalid poll in CSB mode\n");
 		return POLLERR;
+	}
 
 	if (netmap_verbose & 0x8000)
 		D("device %s events 0x%x", na->name, events);

From c262cd2052a32b6d1d7e5958bfd7bdac4c6f55e4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 26 Oct 2018 19:41:30 +0200
Subject: [PATCH 1355/2207] netmap_csb_validate: also initialize CSB

---
 sys/dev/netmap/netmap.c       | 41 +++++++++++++++++++++++++++++++----
 sys/dev/netmap/netmap_kern.h  |  9 ++++++++
 sys/dev/netmap/netmap_kloop.c |  9 --------
 3 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2a97f4aa3..b841a26f1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2000,17 +2000,22 @@ nm_priv_rx_enabled(struct netmap_priv_d *priv)
 int
 netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 {
-	int num_rings = priv->np_qlast[NR_RX] - priv->np_qfirst[NR_RX] +
-			priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
 	struct nm_csb_atok *csb_atok_base =
 		(struct nm_csb_atok *)(uintptr_t)csbo->csb_atok;
 	struct nm_csb_ktoa *csb_ktoa_base =
 		(struct nm_csb_ktoa *)(uintptr_t)csbo->csb_ktoa;
+	enum txrx t;
+	int num_rings[NR_TXRX], tot_rings;
 	size_t entry_size[2];
 	void *csb_start[2];
 	int i;
 
-	if (num_rings <= 0)
+	tot_rings = 0;
+	for_rx_tx(t) {
+		num_rings[t] = priv->np_qlast[t] - priv->np_qfirst[t];
+		tot_rings += num_rings[t];
+	}
+	if (tot_rings <= 0)
 		return 0;
 
 	if (!(priv->np_flags & NR_EXCLUSIVE)) {
@@ -2028,7 +2033,7 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 		 * the validation. However, the advantage of
 		 * this approach is that it works also on
 		 * FreeBSD. */
-		size_t csb_size = num_rings * entry_size[i];
+		size_t csb_size = tot_rings * entry_size[i];
 		void *tmp;
 		int err;
 
@@ -2058,6 +2063,34 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 	priv->np_csb_atok_base = csb_atok_base;
 	priv->np_csb_ktoa_base = csb_ktoa_base;
 
+	/* Initialize the CSB. */
+	for_rx_tx(t) {
+		for (i = 0; i < num_rings[t]; i++) {
+			struct netmap_kring *kring =
+				NMR(priv->np_na, t)[i + priv->np_qfirst[t]];
+			struct nm_csb_atok *csb_atok = csb_atok_base + i;
+			struct nm_csb_ktoa *csb_ktoa = csb_ktoa_base + i;
+
+			if (t == NR_RX) {
+				csb_atok += num_rings[NR_TX];
+				csb_ktoa += num_rings[NR_TX];
+			}
+
+			CSB_WRITE(csb_atok, head, kring->rhead);
+			CSB_WRITE(csb_atok, cur, kring->rcur);
+			CSB_WRITE(csb_atok, appl_need_kick, 1);
+			CSB_WRITE(csb_atok, sync_flags, 1);
+			CSB_WRITE(csb_ktoa, hwcur, kring->nr_hwcur);
+			CSB_WRITE(csb_ktoa, hwtail, kring->nr_hwtail);
+			CSB_WRITE(csb_ktoa, kern_need_kick, 1);
+
+			nm_prinf("csb_init for kring %s: head %u, cur %u, "
+				"hwcur %u, hwtail %u\n", kring->name,
+				kring->rhead, kring->rcur, kring->nr_hwcur,
+				kring->nr_hwtail);
+		}
+	}
+
 	return 0;
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d768268ee..cc8cf19fe 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2303,4 +2303,13 @@ int nmreq_checkduplicate(struct nmreq_option *);
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
 
+/* Functions to read and write CSB fields from the kernel. */
+#if defined (linux)
+#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
+#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
+#else  /* ! linux */
+#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
+#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
+#endif /* ! linux */
+
 #endif /* _NET_NETMAP_KERN_H_ */
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index e6557f30d..60bac89fb 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -60,15 +60,6 @@
 #define SYNC_KLOOP_POLL
 #endif
 
-/* Functions to read and write CSB fields from the kernel. */
-#if defined (linux)
-#define CSB_READ(csb, field, r) (get_user(r, &csb->field))
-#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field))
-#else  /* ! linux */
-#define CSB_READ(csb, field, r) (r = fuword32(&csb->field))
-#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
-#endif /* ! linux */
-
 /* Write kring pointers (hwcur, hwtail) to the CSB.
  * This routine is coupled with ptnetmap_guest_read_kring_csb(). */
 static inline void

From 218583a9c0188be5099e37e28cb53661dd0811a5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 14:11:16 +0200
Subject: [PATCH 1356/2207] ptnet: improve log statement

---
 LINUX/netmap_ptnet.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index ee50fd9a9..055bfe740 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1066,11 +1066,11 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		kring->nr_hwtail = kring->rtail =
 			kring->ring->tail = ktoa->hwtail;
 
-		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
+		ND("%s: csb {hc %u h %u c %u ht %u}", kring->name,
 		   ktoa->hwcur, atok->head, atok->cur,
 		   ktoa->hwtail);
-		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
-		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
+		ND("%s: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
+		   kring->name, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
 		   kring->rtail, kring->ring->tail);
 	}

From 5b2d4b065a9fdc38103b6d2d004c666f9de2bed4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 14:14:55 +0200
Subject: [PATCH 1357/2207] linux: ptnet: sync from CSB only after PTCTL_CREATE

---
 LINUX/netmap_ptnet.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 055bfe740..db8b4328f 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1060,8 +1060,8 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings[i - na->num_tx_rings];
 		}
-		kring->rhead = kring->ring->head = atok->head;
-		kring->rcur = kring->ring->cur = atok->cur;
+		kring->rhead = atok->head;
+		kring->rcur = atok->cur;
 		kring->nr_hwcur = ktoa->hwcur;
 		kring->nr_hwtail = kring->rtail =
 			kring->ring->tail = ktoa->hwtail;
@@ -1148,13 +1148,13 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			if (ret) {
 				return ret;
 			}
-		}
 
-		/* Sync from CSB must be done after REGIF PTCTL. Skip this
-		 * step only if this is a netmap client and it is not the
-		 * first one. */
-		if ((!native && pi->ptna->backend_regifs == 0) ||
-				(native && na->active_fds == 0)) {
+			/* Wait for a while to make sure that the CSB has been
+			 * initialized. TODO fix the need for this */
+			usleep_range(5000, 6000);
+
+			/* Align the guest krings and rings to the state stored
+			 * in the CSB. */
 			ptnet_sync_from_csb(pi, na);
 		}
 
@@ -1187,12 +1187,6 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		/* Sync from CSB must be done before UNREGIF PTCTL, on the last
-		 * netmap client. */
-		if (native && na->active_fds == 0) {
-			ptnet_sync_from_csb(pi, na);
-		}
-
 		if (pi->ptna->backend_regifs == 0) {
 			ret = ptnet_nm_ptctl(netdev, PTNETMAP_PTCTL_DELETE);
 		}

From e69649173eaefb41320a4e60eb7436802b1934c6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 14:33:08 +0200
Subject: [PATCH 1358/2207] fix minor spacing issue

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a00e2ec93..72481d25c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1719,7 +1719,7 @@ nm_rxsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 
 /*
  * Error routine called when txsync/rxsync detects an error.
- * Can't do much more than resetting head =cur = hwcur, tail = hwtail
+ * Can't do much more than resetting head = cur = hwcur, tail = hwtail
  * Return 1 on reinit.
  *
  * This routine is only called by the upper half of the kernel.

From 5700ec821e57f455ae6873beed6d28f664eae5b3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 15:00:59 +0200
Subject: [PATCH 1359/2207] linux: ptnet_irqs_init: don't print function
 pointer in log statement

---
 LINUX/netmap_ptnet.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index db8b4328f..ecc3c2ce1 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -830,8 +830,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 				__func__, ret);
 			goto err_irqs;
 		}
-		pr_info("%s: IRQ for ring #%d --> %u, handler %p\n",
-				__func__, i, vector, handler);
+		pr_info("%s: IRQ for ring #%d --> %u\n", __func__, i, vector);
 	}
 
 	return 0;

From 6a9b752964e223894b33fc0bf1c4228c3e192093 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 15:55:10 +0200
Subject: [PATCH 1360/2207] pipes: don't process host rings

---
 sys/dev/netmap/netmap_pipe.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 9aa74de85..51b4f1616 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -441,7 +441,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 
 		/* In case of no error we put our rings in netmap mode */
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 				if (nm_kring_pending_on(kring)) {
 					struct netmap_kring *sring, *dring;
@@ -488,7 +488,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 		if (na->active_fds == 0)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring)) {
@@ -565,7 +565,7 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 	sna = na;
 cleanup:
 	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(sna, t) + 1; i++) {
+		for (i = 0; i < nma_get_nrings(sna, t); i++) {
 			struct netmap_kring *kring = NMR(sna, t)[i];
 			struct netmap_ring *ring = kring->ring;
 			uint32_t j, lim = kring->nkr_num_slots - 1;

From ad3f14366f7f0e94ee2086e3445b92a5093953e3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 16:44:20 +0200
Subject: [PATCH 1361/2207] freebsd: if_ptnet: import fixes from linux driver
 (sync_from_csb)

---
 sys/dev/netmap/if_ptnet.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index f429168da..f69ff0f59 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1215,13 +1215,9 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			if (ret) {
 				return ret;
 			}
-		}
 
-		/* Sync from CSB must be done after REGIF PTCTL. Skip this
-		 * step only if this is a netmap client and it is not the
-		 * first one. */
-		if ((!native && sc->ptna->backend_regifs == 0) ||
-				(native && na->active_fds == 0)) {
+			/* Align the guest krings and rings to the state stored
+			 * in the CSB. */
 			ptnet_sync_from_csb(sc, na);
 		}
 
@@ -1254,12 +1250,6 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		/* Sync from CSB must be done before UNREGIF PTCTL, on the last
-		 * netmap client. */
-		if (native && na->active_fds == 0) {
-			ptnet_sync_from_csb(sc, na);
-		}
-
 		if (sc->ptna->backend_regifs == 0) {
 			ret = ptnet_nm_ptctl(ifp, PTNETMAP_PTCTL_DELETE);
 		}

From ce9e4ba23fd5fd96b94cc565bbd1989c6aed2001 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 16:45:19 +0200
Subject: [PATCH 1362/2207] linux: ptnet_sync_from_csb: also init
 ring->[head,cur]

---
 LINUX/netmap_ptnet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index ecc3c2ce1..200678822 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1059,8 +1059,8 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		} else {
 			kring = na->rx_rings[i - na->num_tx_rings];
 		}
-		kring->rhead = atok->head;
-		kring->rcur = atok->cur;
+		kring->rhead = kring->ring->head = atok->head;
+		kring->rcur = kring->ring->cur = atok->cur;
 		kring->nr_hwcur = ktoa->hwcur;
 		kring->nr_hwtail = kring->rtail =
 			kring->ring->tail = ktoa->hwtail;

From afb6b86d8aeb7381d472da8e6f53a1ddc2f9397c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 16:51:33 +0200
Subject: [PATCH 1363/2207] netmap_mem_pt_guest_rings_create: handle multiple
 host rings

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8d9315022..4edac9656 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2668,7 +2668,7 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 			continue;
 		kring->ring = (struct netmap_ring *)
 			((char *)nifp +
-			 nifp->ring_ofs[i + na->num_tx_rings + 1]);
+			 nifp->ring_ofs[netmap_all_rings(na, NR_TX) + i]);
 	}
 
 	error = 0;

From 47d65424f259cfe0388d9b21c2bfe4b476c7df1d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 19:54:50 +0200
Subject: [PATCH 1364/2207] PORT_GET_INFO: remove redundant instructions

---
 sys/dev/netmap/netmap.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 72481d25c..a72deed98 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2598,7 +2598,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				if (na == NULL) /* only memory info */
 					break;
 				req->nr_offset = 0;
-				req->nr_rx_slots = req->nr_tx_slots = 0;
 				netmap_update_config(na);
 				req->nr_rx_rings = na->num_rx_rings;
 				req->nr_tx_rings = na->num_tx_rings;

From fa515a3b898781a1681994be5198beb3fd8073cf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 27 Oct 2018 22:04:03 +0200
Subject: [PATCH 1365/2207] port_info_get: remove obsolete nr_offset field

---
 sys/dev/netmap/netmap.c        | 1 -
 sys/dev/netmap/netmap_legacy.c | 2 --
 sys/net/netmap.h               | 1 -
 utils/ctrl-api-test.c          | 1 -
 4 files changed, 5 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a72deed98..6ecbfec9c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2597,7 +2597,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					break;
 				if (na == NULL) /* only memory info */
 					break;
-				req->nr_offset = 0;
 				netmap_update_config(na);
 				req->nr_rx_rings = na->num_rx_rings;
 				req->nr_tx_rings = na->num_tx_rings;
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 728595b29..c36fc8403 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -239,7 +239,6 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			if (!req) { goto oom; }
 			hdr->nr_body = (uintptr_t)req;
 			hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
-			req->nr_offset = nmr->nr_offset;
 			req->nr_memsize = nmr->nr_memsize;
 			req->nr_tx_slots = nmr->nr_tx_slots;
 			req->nr_rx_slots = nmr->nr_rx_slots;
@@ -297,7 +296,6 @@ nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
 	case NETMAP_REQ_PORT_INFO_GET: {
 		struct nmreq_port_info_get *req =
 			(struct nmreq_port_info_get *)(uintptr_t)hdr->nr_body;
-		nmr->nr_offset = req->nr_offset;
 		nmr->nr_memsize = req->nr_memsize;
 		nmr->nr_tx_slots = req->nr_tx_slots;
 		nmr->nr_rx_slots = req->nr_rx_slots;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index c31986f4d..8984282d4 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -618,7 +618,6 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
  * to a netmap port.
  */
 struct nmreq_port_info_get {
-	uint64_t	nr_offset;	/* nifp offset in the shared region */
 	uint64_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index bb8246e9b..276d4611b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -90,7 +90,6 @@ port_info_get(struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
-	printf("nr_offset 0x%lx\n", req.nr_offset);
 	printf("nr_memsize %lu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);

From f46ad3140ac458ab21f0a9bb5d20c11431fbd9fd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 09:15:46 +0100
Subject: [PATCH 1366/2207] ptnetmap: rename backend_regifs --> backend_users

---
 LINUX/netmap_ptnet.c          | 12 ++++++------
 sys/dev/netmap/if_ptnet.c     | 12 ++++++------
 sys/dev/netmap/netmap_kern.h  |  2 +-
 sys/dev/netmap/netmap_kloop.c |  6 +++---
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 200678822..57505c928 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -896,7 +896,7 @@ ptnet_open(struct net_device *netdev)
 		goto err_mem_finalize;
 	}
 
-	if (pi->ptna->backend_regifs == 0) {
+	if (pi->ptna->backend_users == 0) {
 		ret = ptnet_nm_krings_create(na_nm);
 		if (ret) {
 			pr_err("%s: ptnet_nm_krings_create() failed\n",
@@ -1010,7 +1010,7 @@ ptnet_close(struct net_device *netdev)
 
 	ptnet_nm_register(na_dr, 0 /* off */);
 
-	if (pi->ptna->backend_regifs == 0) {
+	if (pi->ptna->backend_users == 0) {
 		netmap_mem_rings_delete(na_dr);
 		ptnet_nm_krings_delete(na_nm);
 	}
@@ -1102,7 +1102,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	BUG_ON(!(na == &pi->ptna->hwup.up || na == &pi->ptna->dr.up));
 
 	if (!onoff) {
-		pi->ptna->backend_regifs--;
+		pi->ptna->backend_users--;
 	}
 
 	/* If this is the last netmap client, guest interrupt enable flags may
@@ -1129,7 +1129,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	}
 
 	if (onoff) {
-		if (pi->ptna->backend_regifs == 0) {
+		if (pi->ptna->backend_users == 0) {
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < pi->num_rings; i++) {
 				atok = pi->queues[i]->atok;
@@ -1186,13 +1186,13 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		if (pi->ptna->backend_regifs == 0) {
+		if (pi->ptna->backend_users == 0) {
 			ret = ptnet_nm_ptctl(netdev, PTNETMAP_PTCTL_DELETE);
 		}
 	}
 
 	if (onoff) {
-		pi->ptna->backend_regifs++;
+		pi->ptna->backend_users++;
 	}
 
 	return ret;
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index f69ff0f59..512488610 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -881,7 +881,7 @@ ptnet_init_locked(struct ptnet_softc *sc)
 		return ret;
 	}
 
-	if (sc->ptna->backend_regifs == 0) {
+	if (sc->ptna->backend_users == 0) {
 		ret = ptnet_nm_krings_create(na_nm);
 		if (ret) {
 			device_printf(sc->dev, "ptnet_nm_krings_create() "
@@ -962,7 +962,7 @@ ptnet_stop(struct ptnet_softc *sc)
 
 	ptnet_nm_register(na_dr, 0 /* off */);
 
-	if (sc->ptna->backend_regifs == 0) {
+	if (sc->ptna->backend_users == 0) {
 		netmap_mem_rings_delete(na_dr);
 		ptnet_nm_krings_delete(na_nm);
 	}
@@ -1178,7 +1178,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	int i;
 
 	if (!onoff) {
-		sc->ptna->backend_regifs--;
+		sc->ptna->backend_users--;
 	}
 
 	/* If this is the last netmap client, guest interrupt enable flags may
@@ -1196,7 +1196,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	}
 
 	if (onoff) {
-		if (sc->ptna->backend_regifs == 0) {
+		if (sc->ptna->backend_users == 0) {
 			/* Initialize notification enable fields in the CSB. */
 			for (i = 0; i < sc->num_rings; i++) {
 				pq = sc->queues + i;
@@ -1250,13 +1250,13 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 			}
 		}
 
-		if (sc->ptna->backend_regifs == 0) {
+		if (sc->ptna->backend_users == 0) {
 			ret = ptnet_nm_ptctl(ifp, PTNETMAP_PTCTL_DELETE);
 		}
 	}
 
 	if (onoff) {
-		sc->ptna->backend_regifs++;
+		sc->ptna->backend_users++;
 	}
 
 	return ret;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index cc8cf19fe..e2a2d4053 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2166,7 +2166,7 @@ struct netmap_pt_guest_adapter {
 	 * network stack and netmap clients.
 	 * Used to decide when we need (de)allocate krings/rings and
 	 * start (stop) ptnetmap kthreads. */
-	int backend_regifs;
+	int backend_users;
 
 };
 
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 9b05b604b..7895ed77d 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -830,7 +830,7 @@ ptnet_nm_krings_create(struct netmap_adapter *na)
 	struct netmap_adapter *na_dr = &ptna->dr.up;
 	int ret;
 
-	if (ptna->backend_regifs) {
+	if (ptna->backend_users) {
 		return 0;
 	}
 
@@ -855,7 +855,7 @@ ptnet_nm_krings_delete(struct netmap_adapter *na)
 	struct netmap_adapter *na_nm = &ptna->hwup.up;
 	struct netmap_adapter *na_dr = &ptna->dr.up;
 
-	if (ptna->backend_regifs) {
+	if (ptna->backend_users) {
 		return;
 	}
 
@@ -904,7 +904,7 @@ netmap_pt_guest_attach(struct netmap_adapter *arg,
 	ptna->dr.up.nm_mem = netmap_mem_get(ptna->hwup.up.nm_mem);
         ptna->dr.up.nm_config = ptna->hwup.up.nm_config;
 
-	ptna->backend_regifs = 0;
+	ptna->backend_users = 0;
 
 	return 0;
 }

From d1362cbb054b37bd7f994d08ced7aeb950c91ce5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 09:45:43 +0100
Subject: [PATCH 1367/2207] apps: lb: import style fixes from freebsd

---
 apps/lb/lb.8 | 50 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 18 deletions(-)

diff --git a/apps/lb/lb.8 b/apps/lb/lb.8
index 643040e8a..235369bf0 100644
--- a/apps/lb/lb.8
+++ b/apps/lb/lb.8
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 3, 2016
+.Dd October 28, 2018
 .Dt LB 1
 .Os
 .Sh NAME
@@ -39,44 +39,52 @@
 .Op Fl B Ar extra-buffers
 .Op Fl b Ar batch-size
 .Op Fl w Ar wait-link
+.El
+.Ek
 .Sh DESCRIPTION
 .Nm
 reads packets from an input netmap port and sends them to a number of netmap pipes,
-trying to balance the packets received by each pipe. Packets belonging to the
+trying to balance the packets received by each pipe.
+Packets belonging to the
 same connection will always be sent to the same pipe.
 .Pp
-.Pp
 Command line options are listed below.
 .Bl -tag -width Ds
 .It Fl i Ar port
-Name of a netmap port. It must be supplied exactly once to identify
+Name of a netmap port.
+It must be supplied exactly once to identify
 the input port.
 Any netmap port type (physical interface, VALE switch, pipe, monitor port...)
 can be used.
 .It Fl p Ar name:number | number
-Add a new pipe group of the given number of pipes. 
+Add a new pipe group of the given number of pipes.
 The pipe group will receive all the packets read from the input port, balanced
-among the available pipes. The receiving ends of the pipes
-will be called name}0 to name}number-1. The name is optional and defaults to
-the name of the input port (stripped down of any netmap operator). If the name
-is omitted, also the colon can be omitted.
+among the available pipes.
+The receiving ends of the pipes
+will be called name}0 to name}number-1.
+The name is optional and defaults to
+the name of the input port (stripped down of any netmap operator).
+If the name is omitted, also the colon can be omitted.
 .Pp
 This option can be supplied multiple times to define a sequence of pipe groups,
 each group receiving all the packets in turn.
 .Pp
 If no -p option is given, a single group of two pipes with default name is assumed.
 .Pp
-It is allowed to use the same name for several groups. The pipe numbering in each
+It is allowed to use the same name for several groups.
+The pipe numbering in each
 group will start from were the previous identically-named group had left.
 .It Fl B Ar extra-buffers
-Try to reserve the given number of extra buffers. Extra buffers are shared among
+Try to reserve the given number of extra buffers.
+Extra buffers are shared among
 all pipes in all groups and work as an extension of the pipe rings.
 If a pipe ring is full for whatever reason,
 .Nm
 tries to use extra buffers before dropping any packets directed to that pipe.
 .Pp
 If all extra buffers are busy, some are stolen from the pipe with the longest
-backlog. This gives preference to newer packets over old ones, and prevents a
+backlog.
+This gives preference to newer packets over old ones, and prevents a
 stalled pipe to deplete the pool of extra buffers.
 .It Fl b Ar batch-size
 Maximum number of packets processed between two read operations from the input port.
@@ -93,20 +101,26 @@ pipes are read-only: they must not modify the buffers or the pipe ring slots
 in any way.
 .Pp
 The group naming is currently implemented by creating a persistent VALE port
-with the given name. If
+with the given name.
+If
 .Nm
-does not exit cleanly the ports will not be removed. Please use
-.Xr vale-ctl 1
+does not exit cleanly the ports will not be removed.
+Please use
+.Xr vale-ctl 4
 to remove any stale persistent VALE port.
 .Sh SEE ALSO
-.Pa http://info.iet.unipi.it/~luigi/netmap/
+.Xr netmap 4 ,
+.Xr vale-ctl 4 ,
+.Xr bridge 8 ,
+.Xr pkt-gen 8
 .Pp
+.Pa http://info.iet.unipi.it/~luigi/netmap/
 .Sh AUTHORS
 .An -nosplit
 .Nm
 has been written by
 .An Seth Hall
-at Corelight, USA. The facilities related to extra buffers and pipe groups
-have been added by
+at Corelight, USA.
+The facilities related to extra buffers and pipe groups have been added by
 .An Giuseppe Lettieri
 at University of Pisa, Italy, under contract by Corelight, USA.

From 0cbb031dd87ae2cf4d1b0a3eb01ed4c4bc1e703d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 09:53:25 +0100
Subject: [PATCH 1368/2207] apps: lb, nmreplay: minor fixes to the man pages

---
 apps/lb/lb.8             | 2 +-
 apps/nmreplay/nmreplay.8 | 2 +-
 share/man/man4/netmap.4  | 7 +++++++
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/apps/lb/lb.8 b/apps/lb/lb.8
index 235369bf0..7a95d63d1 100644
--- a/apps/lb/lb.8
+++ b/apps/lb/lb.8
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd October 28, 2018
-.Dt LB 1
+.Dt LB 8
 .Os
 .Sh NAME
 .Nm lb
diff --git a/apps/nmreplay/nmreplay.8 b/apps/nmreplay/nmreplay.8
index 8e5ddb969..4b8f3a2ca 100644
--- a/apps/nmreplay/nmreplay.8
+++ b/apps/nmreplay/nmreplay.8
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd February 16, 2016
-.Dt NMREPLAY 1
+.Dt NMREPLAY 8
 .Os
 .Sh NAME
 .Nm nmreplay
diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 6e3c92fa5..03f366bd8 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -1082,6 +1082,13 @@ Other
 clients attached to the same switch can now communicate
 with the network card or the host.
 .Sh SEE ALSO
+.Xr vale 4 ,
+.Xr vale-ctl 4 ,
+.Xr bridge 8 ,
+.Xr lb 8 ,
+.Xr nmreplay 8 ,
+.Xr pkt-gen 8
+.Pp
 .Pa http://info.iet.unipi.it/~luigi/netmap/
 .Pp
 Luigi Rizzo, Revisiting network I/O APIs: the netmap framework,

From dcb02a22c08090a43c98f6f2ef9bcc4e51bec523 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 11:13:20 +0100
Subject: [PATCH 1369/2207] netmap_csb_validate: check for CSB mode already on

---
 sys/dev/netmap/netmap.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6ecbfec9c..e11663412 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2010,6 +2010,11 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 	void *csb_start[2];
 	int i;
 
+	if (priv->np_csb_atok_base || priv->np_csb_ktoa_base) {
+		nm_prerr("CSB mode already set\n");
+		return EBUSY;
+	}
+
 	tot_rings = 0;
 	for_rx_tx(t) {
 		num_rings[t] = priv->np_qlast[t] - priv->np_qfirst[t];

From 7a41e115a92eec48ed89e0cb02dcdfbec59ed5a4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 11:16:38 +0100
Subject: [PATCH 1370/2207] utils: ctrl-api-test: improve error log statement

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 276d4611b..99ae52437 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1357,7 +1357,7 @@ main(int argc, char **argv)
 		 * registering the interface. To stay safe, let's
 		 * just use a standard MTU. */
 		if (system("ip link set dev lo mtu 1514")) {
-			perror("system(mtu=1514)");
+			printf("system(%s, mtu=1514) failed\n", ctx.ifname);
 			return -1;
 		}
 	}

From e9911474db85005626abe12a6cf631940197c4f3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 12:07:43 +0100
Subject: [PATCH 1371/2207] introduce NETMAP_REQ_CSB_ENABLE to fix race
 condition on CSB init

---
 sys/dev/netmap/netmap.c       | 22 +++++++++++++++++-
 sys/dev/netmap/netmap_kern.h  |  3 ---
 sys/dev/netmap/netmap_kloop.c | 25 ++++----------------
 sys/net/netmap.h              |  2 ++
 utils/ctrl-api-test.c         | 44 +++++++++++++++++++++++++++++++----
 5 files changed, 67 insertions(+), 29 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e11663412..8dfc6f9af 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1997,7 +1997,7 @@ nm_priv_rx_enabled(struct netmap_priv_d *priv)
 }
 
 /* Validate the CSB entries for both directions (atok and ktoa). */
-int
+static int
 netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 {
 	struct nm_csb_atok *csb_atok_base =
@@ -2753,6 +2753,25 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
+		case NETMAP_REQ_CSB_ENABLE: {
+			struct nmreq_option *opt;
+
+			opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+						NETMAP_REQ_OPT_CSB);
+			if (opt == NULL) {
+				error = EINVAL;
+			} else {
+				struct nmreq_opt_csb *csbo =
+					(struct nmreq_opt_csb *)opt;
+				error = nmreq_checkduplicate(opt);
+				if (!error) {
+					error = netmap_csb_validate(priv, csbo);
+				}
+				opt->nro_status = error;
+			}
+			break;
+		}
+
 		case NETMAP_REQ_SYNC_KLOOP_START: {
 			error = netmap_sync_kloop(priv, hdr);
 			break;
@@ -2875,6 +2894,7 @@ nmreq_size_by_type(uint16_t nr_reqtype)
 		return sizeof(struct nmreq_vale_newif);
 	case NETMAP_REQ_VALE_DELIF:
 	case NETMAP_REQ_SYNC_KLOOP_STOP:
+	case NETMAP_REQ_CSB_ENABLE:
 		return 0;
 	case NETMAP_REQ_VALE_POLLING_ENABLE:
 	case NETMAP_REQ_VALE_POLLING_DISABLE:
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e2a2d4053..99dc9df4b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1916,9 +1916,6 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
 	return 0;
 }
 
-int netmap_csb_validate(struct netmap_priv_d *priv,
-			struct nmreq_opt_csb *csbo);
-
 /* call with NMG_LOCK held */
 static __inline int
 nm_si_user(struct netmap_priv_d *priv, enum txrx t)
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 7895ed77d..78205d4d4 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -460,30 +460,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		return ENXIO;
 	}
 
-	/* Make sure the application is working in CSB mode. If it
-	 * is not, check if the user specified the CSB option with
-	 * this command. */
+	/* Make sure the application is working in CSB mode. */
 	if (!priv->np_csb_atok_base || !priv->np_csb_ktoa_base) {
-		struct nmreq_option *opt;
-
-		opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-				NETMAP_REQ_OPT_CSB);
-		if (!opt) {
-			nm_prerr("sync-kloop on %s requires "
+		nm_prerr("sync-kloop on %s requires "
 				"NETMAP_REQ_OPT_CSB option\n", na->name);
-			return EINVAL;
-		}
-		err = nmreq_checkduplicate(opt);
-		if (err) {
-			return err;
-		}
-		err = netmap_csb_validate(priv,
-					(struct nmreq_opt_csb *)opt);
-		opt->nro_status = err;
-		if (err) {
-			return err;
-		}
+		return EINVAL;
 	}
+
 	csb_atok_base = priv->np_csb_atok_base;
 	csb_ktoa_base = priv->np_csb_ktoa_base;
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 8984282d4..948eeac9f 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -527,6 +527,8 @@ enum {
 	/* Stops the thread executing the in-kernel loop. The thread
 	 * returns from the ioctl syscall. */
 	NETMAP_REQ_SYNC_KLOOP_STOP,
+	/* Enable CSB mode on a registered netmap control device. */
+	NETMAP_REQ_CSB_ENABLE,
 };
 
 enum {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 99ae52437..36cb11cd3 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -922,6 +922,7 @@ push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
 	opt->csb_ktoa            = (uintptr_t)(ctx->csb +
                                     sizeof(struct nm_csb_atok) * num_entries);
 
+	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
 	push_option(&opt->nro_opt, ctx);
 
 	return 0;
@@ -969,6 +970,8 @@ sync_kloop_stop(struct TestContext *ctx)
 	struct nmreq_header hdr;
 	int ret;
 
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname);
+
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
@@ -1128,14 +1131,47 @@ sync_kloop_nocsb(struct TestContext *ctx)
 	}
 
 	/* Sync kloop must fail because we did not use
-	 * NETMAP_REQ_OPT_CSB. */
+	 * NETMAP_REQ_CSB_ENABLE. */
 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
 }
 
 static int
-sync_kloop_csb_on_start(struct TestContext *ctx)
+csb_enable(struct TestContext *ctx)
 {
+	struct nmreq_option saveopt;
 	struct nmreq_opt_csb opt;
+	struct nmreq_header hdr;
+	int ret;
+
+	ret = push_csb_option(ctx, &opt);
+	if (ret) {
+		return ret;
+	}
+	saveopt = opt.nro_opt;
+	saveopt.nro_status = 0;
+
+	nmreq_hdr_init(&hdr, ctx->ifname);
+	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
+	hdr.nr_options = (uintptr_t)ctx->nr_opt;
+	hdr.nr_body = (uintptr_t)NULL;
+
+	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname);
+
+	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
+		return ret;
+	}
+
+	ret = checkoption(&opt.nro_opt, &saveopt);
+	clear_options(ctx);
+
+	return ret;
+}
+
+static int
+sync_kloop_csb_enable(struct TestContext *ctx)
+{
 	int ret;
 
 	ctx->nr_flags |= NR_EXCLUSIVE;
@@ -1144,7 +1180,7 @@ sync_kloop_csb_on_start(struct TestContext *ctx)
 		return ret;
 	}
 
-	ret = push_csb_option(ctx, &opt);
+	ret = csb_enable(ctx);
 	if (ret) {
 		return ret;
 	}
@@ -1283,7 +1319,7 @@ static struct mytest tests[] = {
 	decltest(sync_kloop_eventfds_all),
 	decltest(sync_kloop_eventfds_all_tx),
 	decltest(sync_kloop_nocsb),
-	decltest(sync_kloop_csb_on_start),
+	decltest(sync_kloop_csb_enable),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_eventfds_mismatch),
 };

From 7663e9034462d543ac26900853d350f7c84ab08f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 12:08:24 +0100
Subject: [PATCH 1372/2207] linux: ptnet: remove obsolete usleep()

---
 LINUX/netmap_ptnet.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 57505c928..6d87e3e3b 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1148,10 +1148,6 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 				return ret;
 			}
 
-			/* Wait for a while to make sure that the CSB has been
-			 * initialized. TODO fix the need for this */
-			usleep_range(5000, 6000);
-
 			/* Align the guest krings and rings to the state stored
 			 * in the CSB. */
 			ptnet_sync_from_csb(pi, na);

From c98d25631ab910991ee203258401be664ecd8a21 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 12:42:19 +0100
Subject: [PATCH 1373/2207] netmap_csb_validate: fail if sync-kloop is running

Also, make sure it is called under NMG_LOCK
---
 sys/dev/netmap/netmap.c       | 9 ++++++---
 sys/dev/netmap/netmap_kloop.c | 3 ++-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8dfc6f9af..d75a593f5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1996,7 +1996,8 @@ nm_priv_rx_enabled(struct netmap_priv_d *priv)
 	return (priv->np_qfirst[NR_RX] != priv->np_qlast[NR_RX]);
 }
 
-/* Validate the CSB entries for both directions (atok and ktoa). */
+/* Validate the CSB entries for both directions (atok and ktoa).
+ * To be called under NMG_LOCK(). */
 static int
 netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 {
@@ -2010,8 +2011,8 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 	void *csb_start[2];
 	int i;
 
-	if (priv->np_csb_atok_base || priv->np_csb_ktoa_base) {
-		nm_prerr("CSB mode already set\n");
+	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
+		nm_prerr("Cannot update CSB while kloop is running\n");
 		return EBUSY;
 	}
 
@@ -2765,7 +2766,9 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					(struct nmreq_opt_csb *)opt;
 				error = nmreq_checkduplicate(opt);
 				if (!error) {
+					NMG_LOCK();
 					error = netmap_csb_validate(priv, csbo);
+					NMG_UNLOCK();
 				}
 				opt->nro_status = error;
 			}
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 78205d4d4..4deef1524 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -460,8 +460,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		return ENXIO;
 	}
 
+	NMG_LOCK();
 	/* Make sure the application is working in CSB mode. */
 	if (!priv->np_csb_atok_base || !priv->np_csb_ktoa_base) {
+		NMG_UNLOCK();
 		nm_prerr("sync-kloop on %s requires "
 				"NETMAP_REQ_OPT_CSB option\n", na->name);
 		return EINVAL;
@@ -471,7 +473,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	csb_ktoa_base = priv->np_csb_ktoa_base;
 
 	/* Make sure that no kloop is currently running. */
-	NMG_LOCK();
 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
 		err = EBUSY;
 	}

From 304231a2cbbef1dab91ca9a6cd69be22f360e09d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 15:27:27 +0100
Subject: [PATCH 1374/2207] linux: ptnet: stop sync-kloop on system
 shutdown/reboot

---
 LINUX/netmap_linux.c | 11 +++++++++++
 LINUX/netmap_ptnet.c | 24 ++++++++++++++++--------
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 848544f7a..a9bf77eea 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1757,6 +1757,7 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 
 int ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *id);
 void ptnet_remove(struct pci_dev *pdev);
+void ptnet_shutdown(struct pci_dev *pdev);
 
 /*
  * PCI Device ID Table
@@ -1928,6 +1929,15 @@ ptnetmap_guest_remove(struct pci_dev *pdev)
 	kfree(ptn_dev);
 }
 
+static void
+ptnetmap_guest_shutdown(struct pci_dev *pdev)
+{
+	if (pdev->device == PTNETMAP_PCI_NETIF_ID) {
+		/* Shutdown the ptnet device. */
+		ptnet_shutdown(pdev);
+	}
+}
+
 /*
  * pci driver information
  */
@@ -1936,6 +1946,7 @@ static struct pci_driver ptnetmap_guest_drivers = {
 	.id_table   = ptnetmap_guest_device_table,
 	.probe      = ptnetmap_guest_probe,
 	.remove     = ptnetmap_guest_remove,
+	.shutdown   = ptnetmap_guest_shutdown,
 };
 
 /*
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 6d87e3e3b..a974ce09f 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1528,6 +1528,17 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return err;
 }
 
+static void
+ptnet_device_shutdown(struct ptnet_info *pi)
+{
+	/* Stop the host sync-kloop in case it was running. */
+	ptnet_nm_ptctl(pi->netdev, PTNETMAP_PTCTL_DELETE);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAH);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAL);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAH);
+	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAL);
+}
+
 /*
  * ptnet_remove - Device Removal Routine
  *
@@ -1561,24 +1572,21 @@ ptnet_remove(struct pci_dev *pdev)
 		netif_napi_del(&prq->napi);
 	}
 
+	/* Deallocate resources and disable the device. */
 	ptnet_irqs_fini(pi);
-
+	ptnet_device_shutdown(pi);
 	iounmap(pi->ioaddr);
-	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAH);
-	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAL);
-	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAH);
-	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAL);
 	put_page(pi->csb_pages);
 	pci_release_selected_regions(pdev, pi->bars);
 	free_netdev(netdev);
 	pci_disable_device(pdev);
 }
 
-#if 0
-static void
+void
 ptnet_shutdown(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ptnet_info *pi = netdev_priv(netdev);
 
 	netif_device_detach(netdev);
 
@@ -1586,6 +1594,6 @@ ptnet_shutdown(struct pci_dev *pdev)
 		ptnet_close(netdev);
 	}
 
+	ptnet_device_shutdown(pi);
 	pci_disable_device(pdev);
 }
-#endif

From 60960fb438493d6d17fb6c6062b97b779a6efb73 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 15:43:56 +0100
Subject: [PATCH 1375/2207] linux: ptnet: shutdown sync-kloop first in
 ptnet_remove() and ptnet_shutdown()

---
 LINUX/netmap_linux.c | 11 +++++++++--
 LINUX/netmap_ptnet.c | 20 +++++++++++++-------
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a9bf77eea..2f383e814 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1837,7 +1837,7 @@ nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *ptn_dev)
 }
 
 /*
- * Device Initialization Routine
+ * Device initialization routine
  *
  * Returns 0 on success, negative on failure
  */
@@ -1903,7 +1903,7 @@ ptnetmap_guest_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 }
 
 /*
- * Device Removal Routine
+ * Device removal routine.
  */
 static void
 ptnetmap_guest_remove(struct pci_dev *pdev)
@@ -1929,6 +1929,10 @@ ptnetmap_guest_remove(struct pci_dev *pdev)
 	kfree(ptn_dev);
 }
 
+/*
+ * Device shutdown routine, called when the system is going to power
+ * off or reboot.
+ */
 static void
 ptnetmap_guest_shutdown(struct pci_dev *pdev)
 {
@@ -1936,6 +1940,9 @@ ptnetmap_guest_shutdown(struct pci_dev *pdev)
 		/* Shutdown the ptnet device. */
 		ptnet_shutdown(pdev);
 	}
+
+	/* Shutdown the memdev device. */
+	pci_disable_device(pdev);
 }
 
 /*
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index a974ce09f..a55934cdb 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1267,7 +1267,7 @@ static struct netmap_adapter ptnet_nm_ops = {
 };
 
 /*
- * ptnet_probe - Device Initialization Routine
+ * ptnet_probe - Device initialization routine
  * @ent: entry in ptnet_pci_table
  *
  * Returns 0 on success, negative on failure
@@ -1528,10 +1528,10 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return err;
 }
 
+/* Stop the host sync-kloop in case it was running. */
 static void
 ptnet_device_shutdown(struct ptnet_info *pi)
 {
-	/* Stop the host sync-kloop in case it was running. */
 	ptnet_nm_ptctl(pi->netdev, PTNETMAP_PTCTL_DELETE);
 	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAH);
 	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAL);
@@ -1540,7 +1540,7 @@ ptnet_device_shutdown(struct ptnet_info *pi)
 }
 
 /*
- * ptnet_remove - Device Removal Routine
+ * ptnet_remove - Device removal routine
  *
  * ptnet_remove is called by the PCI subsystem to alert the driver
  * that it should release a PCI device.  The could be caused by a
@@ -1554,6 +1554,9 @@ ptnet_remove(struct pci_dev *pdev)
 	struct ptnet_info *pi = netdev_priv(netdev);
 	int i;
 
+	/* Stop the host sync-kloop. */
+	ptnet_device_shutdown(pi);
+
 	netif_carrier_off(netdev);
 
 	/* When the netdev is unregistered, ptnet_close() is invoked
@@ -1574,7 +1577,6 @@ ptnet_remove(struct pci_dev *pdev)
 
 	/* Deallocate resources and disable the device. */
 	ptnet_irqs_fini(pi);
-	ptnet_device_shutdown(pi);
 	iounmap(pi->ioaddr);
 	put_page(pi->csb_pages);
 	pci_release_selected_regions(pdev, pi->bars);
@@ -1582,18 +1584,22 @@ ptnet_remove(struct pci_dev *pdev)
 	pci_disable_device(pdev);
 }
 
+/*
+ * Device shutdown routine, called when the system is going to
+ * power off or reboot.
+ */
 void
 ptnet_shutdown(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct ptnet_info *pi = netdev_priv(netdev);
 
-	netif_device_detach(netdev);
+	/* Stop the host sync-kloop. */
+	ptnet_device_shutdown(pi);
 
+	netif_device_detach(netdev);
 	if (netif_running(netdev)) {
 		ptnet_close(netdev);
 	}
-
-	ptnet_device_shutdown(pi);
 	pci_disable_device(pdev);
 }

From 2d9a3c6d592ab5a0cbb43da43eb9c2717f7e73fb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 15:57:10 +0100
Subject: [PATCH 1376/2207] freebsd: if_ptnet: implement
 ptnet_device_shutdown()

---
 sys/dev/netmap/if_ptnet.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 512488610..cb8d3409e 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -505,12 +505,25 @@ ptnet_attach(device_t dev)
 	return err;
 }
 
+/* Stop host sync-kloop if it was running. */
+static void
+ptnet_device_shutdown(struct ptnet_softc *sc)
+{
+	ptnet_nm_ptctl(sc->ifp, PTNETMAP_PTCTL_DELETE);
+	bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAH, 0);
+	bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAL, 0);
+	bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAH, 0);
+	bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAL, 0);
+}
+
 static int
 ptnet_detach(device_t dev)
 {
 	struct ptnet_softc *sc = device_get_softc(dev);
 	int i;
 
+	ptnet_device_shutdown(sc);
+
 #ifdef DEVICE_POLLING
 	if (sc->ifp->if_capenable & IFCAP_POLLING) {
 		ether_poll_deregister(sc->ifp);
@@ -543,10 +556,6 @@ ptnet_detach(device_t dev)
 	ptnet_irqs_fini(sc);
 
 	if (sc->csb_gh) {
-		bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAH, 0);
-		bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAL, 0);
-		bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAH, 0);
-		bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAL, 0);
 		contigfree(sc->csb_gh, 2*PAGE_SIZE, M_DEVBUF);
 		sc->csb_gh = NULL;
 		sc->csb_hg = NULL;
@@ -583,9 +592,8 @@ ptnet_detach(device_t dev)
 static int
 ptnet_suspend(device_t dev)
 {
-	struct ptnet_softc *sc;
+	struct ptnet_softc *sc = device_get_softc(dev);
 
-	sc = device_get_softc(dev);
 	(void)sc;
 
 	return (0);
@@ -594,9 +602,8 @@ ptnet_suspend(device_t dev)
 static int
 ptnet_resume(device_t dev)
 {
-	struct ptnet_softc *sc;
+	struct ptnet_softc *sc = device_get_softc(dev);
 
-	sc = device_get_softc(dev);
 	(void)sc;
 
 	return (0);
@@ -605,11 +612,11 @@ ptnet_resume(device_t dev)
 static int
 ptnet_shutdown(device_t dev)
 {
-	/*
-	 * Suspend already does all of what we need to
-	 * do here; we just never expect to be resumed.
-	 */
-	return (ptnet_suspend(dev));
+	struct ptnet_softc *sc = device_get_softc(dev);
+
+	ptnet_device_shutdown(sc);
+
+	return (0);
 }
 
 static int

From 3688c8ba7d15cc249b4e3804ba8214032fb70e39 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 15:59:06 +0100
Subject: [PATCH 1377/2207] linux: ptnet_nm_ptctl: minor simplification

---
 LINUX/netmap_ptnet.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index a55934cdb..29c3806a6 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1032,10 +1032,8 @@ static const struct net_device_ops ptnet_netdev_ops = {
 
 
 static uint32_t
-ptnet_nm_ptctl(struct net_device *netdev, uint32_t cmd)
+ptnet_nm_ptctl(struct ptnet_info *pi, uint32_t cmd)
 {
-	struct ptnet_info *pi = netdev_priv(netdev);
-
 	/* Write a command and read back error status,
 	 * with zero meaning success. */
 	iowrite32(cmd, pi->ioaddr + PTNET_IO_PTCTL);
@@ -1143,7 +1141,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 
 			/* Make sure the host adapter passed through is ready
 			 * for txsync/rxsync. */
-			ret = ptnet_nm_ptctl(netdev, PTNETMAP_PTCTL_CREATE);
+			ret = ptnet_nm_ptctl(pi, PTNETMAP_PTCTL_CREATE);
 			if (ret) {
 				return ret;
 			}
@@ -1183,7 +1181,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		}
 
 		if (pi->ptna->backend_users == 0) {
-			ret = ptnet_nm_ptctl(netdev, PTNETMAP_PTCTL_DELETE);
+			ret = ptnet_nm_ptctl(pi, PTNETMAP_PTCTL_DELETE);
 		}
 	}
 
@@ -1532,7 +1530,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 static void
 ptnet_device_shutdown(struct ptnet_info *pi)
 {
-	ptnet_nm_ptctl(pi->netdev, PTNETMAP_PTCTL_DELETE);
+	ptnet_nm_ptctl(pi, PTNETMAP_PTCTL_DELETE);
 	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAH);
 	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_GH_BAL);
 	iowrite32(0, pi->ioaddr + PTNET_IO_CSB_HG_BAH);

From 234926033e7249a5d5829f4e8a91cf0b92df4314 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 16:01:40 +0100
Subject: [PATCH 1378/2207] freebsd: ptnet_nm_ptctl: minor simplification

---
 sys/dev/netmap/if_ptnet.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index cb8d3409e..f16381f01 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -209,7 +209,7 @@ static void	ptnet_tick(void *opaque);
 static int	ptnet_irqs_init(struct ptnet_softc *sc);
 static void	ptnet_irqs_fini(struct ptnet_softc *sc);
 
-static uint32_t ptnet_nm_ptctl(if_t ifp, uint32_t cmd);
+static uint32_t ptnet_nm_ptctl(struct ptnet_softc *sc, uint32_t cmd);
 static int      ptnet_nm_config(struct netmap_adapter *na,
 				struct nm_config_info *info);
 static void	ptnet_update_vnet_hdr(struct ptnet_softc *sc);
@@ -509,7 +509,7 @@ ptnet_attach(device_t dev)
 static void
 ptnet_device_shutdown(struct ptnet_softc *sc)
 {
-	ptnet_nm_ptctl(sc->ifp, PTNETMAP_PTCTL_DELETE);
+	ptnet_nm_ptctl(sc, PTNETMAP_PTCTL_DELETE);
 	bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAH, 0);
 	bus_write_4(sc->iomem, PTNET_IO_CSB_GH_BAL, 0);
 	bus_write_4(sc->iomem, PTNET_IO_CSB_HG_BAH, 0);
@@ -1099,9 +1099,8 @@ ptnet_media_status(if_t ifp, struct ifmediareq *ifmr)
 }
 
 static uint32_t
-ptnet_nm_ptctl(if_t ifp, uint32_t cmd)
+ptnet_nm_ptctl(struct ptnet_softc *sc, uint32_t cmd)
 {
-	struct ptnet_softc *sc = if_getsoftc(ifp);
 	/*
 	 * Write a command and read back error status,
 	 * with zero meaning success.
@@ -1218,7 +1217,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 
 			/* Make sure the host adapter passed through is ready
 			 * for txsync/rxsync. */
-			ret = ptnet_nm_ptctl(ifp, PTNETMAP_PTCTL_CREATE);
+			ret = ptnet_nm_ptctl(sc, PTNETMAP_PTCTL_CREATE);
 			if (ret) {
 				return ret;
 			}
@@ -1258,7 +1257,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		}
 
 		if (sc->ptna->backend_users == 0) {
-			ret = ptnet_nm_ptctl(ifp, PTNETMAP_PTCTL_DELETE);
+			ret = ptnet_nm_ptctl(sc, PTNETMAP_PTCTL_DELETE);
 		}
 	}
 

From d3ce7f97d0130f1700e85b97c13284b56c091b8e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 16:04:58 +0100
Subject: [PATCH 1379/2207] ptnet_sync_tail: move it into a common header

---
 LINUX/netmap_ptnet.c      | 12 ------------
 sys/dev/netmap/if_ptnet.c | 12 ------------
 sys/net/netmap_virt.h     | 13 +++++++++++++
 3 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 29c3806a6..7bfecc563 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -142,18 +142,6 @@ hang_tmr_callback(unsigned long arg)
 }
 #endif
 
-static inline void
-ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
-{
-	struct netmap_ring *ring = kring->ring;
-
-	/* Update hwcur and hwtail as known by the host. */
-	ptnetmap_guest_read_kring_csb(ktoa, kring);
-
-	/* nm_sync_finalize */
-	ring->tail = kring->rtail = kring->nr_hwtail;
-}
-
 static inline int
 ptnet_tx_slots(struct netmap_ring *ring)
 {
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index f16381f01..c362018b9 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1672,18 +1672,6 @@ ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr)
 }
 /* End of offloading-related functions to be shared with vtnet. */
 
-static inline void
-ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
-{
-	struct netmap_ring *ring = kring->ring;
-
-	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(ktoa, kring);
-
-	/* nm_sync_finalize */
-	ring->tail = kring->rtail = kring->nr_hwtail;
-}
-
 static void
 ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 		  unsigned int head, unsigned int sync_flags)
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 77b52974e..d42f53865 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -149,6 +149,19 @@ ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
     kring->nr_hwcur = ktoa->hwcur;
 }
 
+/* Helper function wrapping ptnetmap_guest_read_kring_csb(). */
+static inline void
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
+{
+	struct netmap_ring *ring = kring->ring;
+
+	/* Update hwcur and hwtail as known by the host. */
+        ptnetmap_guest_read_kring_csb(ktoa, kring);
+
+	/* nm_sync_finalize */
+	ring->tail = kring->rtail = kring->nr_hwtail;
+}
+
 #endif /* WITH_PTNETMAP */
 
 #endif /* NETMAP_VIRT_H */

From d38ce91e1bdac4d7fd7dd625e971e661b1489536 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 16:14:21 +0100
Subject: [PATCH 1380/2207] netmap_virt.h: hide internal code moving it to
 netmap_kern.h

---
 sys/dev/netmap/netmap_kern.h | 71 +++++++++++++++++++++++++++-
 sys/net/netmap_virt.h        | 89 +++++-------------------------------
 2 files changed, 81 insertions(+), 79 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 99dc9df4b..c367f2b9d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2146,7 +2146,16 @@ int netmap_sync_kloop(struct netmap_priv_d *priv,
 		      struct nmreq_header *hdr);
 
 #ifdef WITH_PTNETMAP
-/* ptnetmap GUEST routines */
+/* ptnetmap guest routines */
+
+/*
+ * ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver
+ */
+struct ptnetmap_memdev;
+int nm_os_pt_memdev_iomap(struct ptnetmap_memdev *, vm_paddr_t *, void **,
+                          uint64_t *);
+void nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *);
+uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
 
 /*
  * netmap adapter for guest ptnetmap ports
@@ -2179,6 +2188,66 @@ bool netmap_pt_guest_rxsync(struct nm_csb_atok *atok,
 int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
+
+/* Guest driver: Write kring pointers (cur, head) to the CSB.
+ * This routine is coupled with ptnetmap_host_read_kring_csb(). */
+static inline void
+ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
+			       uint32_t head)
+{
+    /*
+     * We need to write cur and head to the CSB but we cannot do it atomically.
+     * There is no way we can prevent the host from reading the updated value
+     * of one of the two and the old value of the other. However, if we make
+     * sure that the host never reads a value of head more recent than the
+     * value of cur we are safe. We can allow the host to read a value of cur
+     * more recent than the value of head, since in the netmap ring cur can be
+     * ahead of head and cur cannot wrap around head because it must be behind
+     * tail. Inverting the order of writes below could instead result into the
+     * host to think head went ahead of cur, which would cause the sync
+     * prologue to fail.
+     *
+     * The following memory barrier scheme is used to make this happen:
+     *
+     *          Guest              Host
+     *
+     *          STORE(cur)         LOAD(head)
+     *          mb() <-----------> mb()
+     *          STORE(head)        LOAD(cur)
+     */
+    atok->cur = cur;
+    mb();
+    atok->head = head;
+}
+
+/* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
+ * This routine is coupled with ptnetmap_host_write_kring_csb(). */
+static inline void
+ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
+                              struct netmap_kring *kring)
+{
+    /*
+     * We place a memory barrier to make sure that the update of hwtail never
+     * overtakes the update of hwcur.
+     * (see explanation in ptnetmap_host_write_kring_csb).
+     */
+    kring->nr_hwtail = ktoa->hwtail;
+    mb();
+    kring->nr_hwcur = ktoa->hwcur;
+}
+
+/* Helper function wrapping ptnetmap_guest_read_kring_csb(). */
+static inline void
+ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
+{
+	struct netmap_ring *ring = kring->ring;
+
+	/* Update hwcur and hwtail as known by the host. */
+        ptnetmap_guest_read_kring_csb(ktoa, kring);
+
+	/* nm_sync_finalize */
+	ring->tail = kring->rtail = kring->nr_hwtail;
+}
 #endif /* WITH_PTNETMAP */
 
 #ifdef __FreeBSD__
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index d42f53865..07e551aff 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2013-2016 Luigi Rizzo
  * Copyright (C) 2013-2016 Giuseppe Lettieri
- * Copyright (C) 2013-2016 Vincenzo Maffione
+ * Copyright (C) 2013-2018 Vincenzo Maffione
  * Copyright (C) 2015 Stefano Garzarella
  * All rights reserved.
  *
@@ -33,14 +33,15 @@
 #define NETMAP_VIRT_H
 
 /*
- * ptnetmap_memdev: device used to expose memory into the guest VM
+ * Register offsets and other macros for the ptnetmap paravirtual devices:
+ *   ptnetmap-memdev: device used to expose memory into the guest
+ *   ptnet: paravirtualized NIC exposing a netmap port in the guest
  *
  * These macros are used in the hypervisor frontend (QEMU, bhyve) and in the
  * guest device driver.
  */
 
-/* PCI identifiers and PCI BARs for the ptnetmap memdev
- * and ptnetmap network interface. */
+/* PCI identifiers and PCI BARs for ptnetmap-memdev and ptnet. */
 #define PTNETMAP_MEMDEV_NAME            "ptnetmap-memdev"
 #define PTNETMAP_PCI_VENDOR_ID          0x1b36  /* QEMU virtual devices */
 #define PTNETMAP_PCI_DEVICE_ID          0x000c  /* memory device */
@@ -49,7 +50,7 @@
 #define PTNETMAP_MEM_PCI_BAR            1
 #define PTNETMAP_MSIX_PCI_BAR           2
 
-/* Registers for the ptnetmap memdev */
+/* Device registers for ptnetmap-memdev */
 #define PTNET_MDEV_IO_MEMSIZE_LO	0	/* netmap memory size (low) */
 #define PTNET_MDEV_IO_MEMSIZE_HI	4	/* netmap_memory_size (high) */
 #define PTNET_MDEV_IO_MEMID		8	/* memory allocator ID in the host */
@@ -67,7 +68,7 @@
 /* ptnetmap features */
 #define PTNETMAP_F_VNET_HDR        1
 
-/* I/O registers for the ptnet device. */
+/* Device registers for the ptnet network device. */
 #define PTNET_IO_PTFEAT		0
 #define PTNET_IO_PTCTL		4
 #define PTNET_IO_MAC_LO		8
@@ -89,79 +90,11 @@
 #define PTNET_IO_KICK_BASE	128
 #define PTNET_IO_MASK		0xff
 
-/* ptnetmap control commands (values for PTCTL register) */
+/* ptnet control commands (values for PTCTL register):
+ *   - CREATE starts the host sync-kloop
+ *   - DELETE stops the host sync-kloop
+ */
 #define PTNETMAP_PTCTL_CREATE		1
 #define PTNETMAP_PTCTL_DELETE		2
 
-#ifdef WITH_PTNETMAP
-
-/* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */
-struct ptnetmap_memdev;
-int nm_os_pt_memdev_iomap(struct ptnetmap_memdev *, vm_paddr_t *, void **,
-                          uint64_t *);
-void nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *);
-uint32_t nm_os_pt_memdev_ioread(struct ptnetmap_memdev *, unsigned int);
-
-/* Guest driver: Write kring pointers (cur, head) to the CSB.
- * This routine is coupled with ptnetmap_host_read_kring_csb(). */
-static inline void
-ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
-			       uint32_t head)
-{
-    /*
-     * We need to write cur and head to the CSB but we cannot do it atomically.
-     * There is no way we can prevent the host from reading the updated value
-     * of one of the two and the old value of the other. However, if we make
-     * sure that the host never reads a value of head more recent than the
-     * value of cur we are safe. We can allow the host to read a value of cur
-     * more recent than the value of head, since in the netmap ring cur can be
-     * ahead of head and cur cannot wrap around head because it must be behind
-     * tail. Inverting the order of writes below could instead result into the
-     * host to think head went ahead of cur, which would cause the sync
-     * prologue to fail.
-     *
-     * The following memory barrier scheme is used to make this happen:
-     *
-     *          Guest              Host
-     *
-     *          STORE(cur)         LOAD(head)
-     *          mb() <-----------> mb()
-     *          STORE(head)        LOAD(cur)
-     */
-    atok->cur = cur;
-    mb();
-    atok->head = head;
-}
-
-/* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
- * This routine is coupled with ptnetmap_host_write_kring_csb(). */
-static inline void
-ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
-                              struct netmap_kring *kring)
-{
-    /*
-     * We place a memory barrier to make sure that the update of hwtail never
-     * overtakes the update of hwcur.
-     * (see explanation in ptnetmap_host_write_kring_csb).
-     */
-    kring->nr_hwtail = ktoa->hwtail;
-    mb();
-    kring->nr_hwcur = ktoa->hwcur;
-}
-
-/* Helper function wrapping ptnetmap_guest_read_kring_csb(). */
-static inline void
-ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
-{
-	struct netmap_ring *ring = kring->ring;
-
-	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(ktoa, kring);
-
-	/* nm_sync_finalize */
-	ring->tail = kring->rtail = kring->nr_hwtail;
-}
-
-#endif /* WITH_PTNETMAP */
-
 #endif /* NETMAP_VIRT_H */

From 5fa9ba466d0a052a284131a1101583ed29153ee4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 16:15:34 +0100
Subject: [PATCH 1381/2207] ptnet: replace mb() with nm_stst_barrier()

---
 sys/dev/netmap/netmap_kern.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c367f2b9d..6b47dc17d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2216,7 +2216,7 @@ ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
      *          STORE(head)        LOAD(cur)
      */
     atok->cur = cur;
-    mb();
+    nm_stst_barrier();
     atok->head = head;
 }
 
@@ -2232,7 +2232,7 @@ ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
      * (see explanation in ptnetmap_host_write_kring_csb).
      */
     kring->nr_hwtail = ktoa->hwtail;
-    mb();
+    nm_stst_barrier();
     kring->nr_hwcur = ktoa->hwcur;
 }
 

From 4d8198bf6ae5c0cab43049ae4cf56d068a5b2913 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 28 Oct 2018 17:19:29 +0100
Subject: [PATCH 1382/2207] make NETMAP_REQ_SYNC_KLOOP_STOP a synchronous
 command

This is necessary to avoid race conditions where the guest stops
the sync-kloop and immediately deallocates the CSB, and there is
a time window where the sync-kloop can access the CSB memory and
corrupt the guest (use-after-free).
---
 sys/dev/netmap/netmap.c       |  4 +---
 sys/dev/netmap/netmap_kern.h  |  1 +
 sys/dev/netmap/netmap_kloop.c | 28 ++++++++++++++++++++++++----
 sys/net/netmap.h              |  7 ++++---
 4 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d75a593f5..acf68f38d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2781,9 +2781,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		case NETMAP_REQ_SYNC_KLOOP_STOP: {
-			NMG_LOCK();
-			priv->np_kloop_state |= NM_SYNC_KLOOP_STOPPING;
-			NMG_UNLOCK();
+			error = netmap_sync_kloop_stop(priv);
 			break;
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6b47dc17d..3bbe60513 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2144,6 +2144,7 @@ u_int nm_os_ncpus(void);
 
 int netmap_sync_kloop(struct netmap_priv_d *priv,
 		      struct nmreq_header *hdr);
+int netmap_sync_kloop_stop(struct netmap_priv_d *priv);
 
 #ifdef WITH_PTNETMAP
 /* ptnetmap guest routines */
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 4deef1524..92f0d7e88 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -567,6 +567,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 	/* Main loop. */
 	for (;;) {
+		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
+			break;
+		}
+
 #ifdef SYNC_KLOOP_POLL
 		if (poll_ctx)
 			__set_current_state(TASK_INTERRUPTIBLE);
@@ -623,10 +627,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			/* Default synchronization method: sleep for a while. */
 			usleep_range(sleep_us, sleep_us);
 		}
-
-		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
-			break;
-		}
 	}
 out:
 #ifdef SYNC_KLOOP_POLL
@@ -663,6 +663,26 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	return err;
 }
 
+int
+netmap_sync_kloop_stop(struct netmap_priv_d *priv)
+{
+	bool running = true;
+	int err = 0;
+
+	NMG_LOCK();
+	priv->np_kloop_state |= NM_SYNC_KLOOP_STOPPING;
+	NMG_UNLOCK();
+	while (running) {
+		usleep_range(1000, 1500);
+		NMG_LOCK();
+		running = (NM_ACCESS_ONCE(priv->np_kloop_state)
+				& NM_SYNC_KLOOP_RUNNING);
+		NMG_UNLOCK();
+	}
+
+	return err;
+}
+
 #ifdef WITH_PTNETMAP
 /*
  * Guest ptnetmap txsync()/rxsync() routines, used in ptnet device drivers.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 948eeac9f..c96277c73 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -722,12 +722,13 @@ struct nmreq_pools_info {
  * Start an in-kernel loop that syncs the rings periodically or on
  * notifications. The loop runs in the context of the ioctl syscall,
  * and only stops on NETMAP_REQ_SYNC_KLOOP_STOP.
- * The netmap port must be open in CSB mode.
+ * The registered netmap port must be open in CSB mode.
  */
 struct nmreq_sync_kloop_start {
 	/* Sleeping is the default synchronization method for the kloop.
-	 * The 'sleep_us' field specifies how many microsconds to sleep
-	 * waiting for more work to come. */
+	 * The 'sleep_us' field specifies how many microsconds to sleep for
+	 * when there is no work to do, before doing another kloop iteration.
+	 */
 	uint32_t sleep_us;
 };
 

From 5b215e52b44b450563cd5ea7e70f43b6130a4889 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Oct 2018 16:43:31 +0100
Subject: [PATCH 1383/2207] apps: lb: minor manpage fixes from FreeBSD

---
 apps/lb/lb.8 | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/apps/lb/lb.8 b/apps/lb/lb.8
index 7a95d63d1..16633c17b 100644
--- a/apps/lb/lb.8
+++ b/apps/lb/lb.8
@@ -54,14 +54,17 @@ Command line options are listed below.
 Name of a netmap port.
 It must be supplied exactly once to identify
 the input port.
-Any netmap port type (physical interface, VALE switch, pipe, monitor port...)
-can be used.
-.It Fl p Ar name:number | number
+Any netmap port type (e.g., physical interface, VALE switch, pipe,
+monitor port) can be used.
+.It Fl p Ar name Ns Cm : Ns Ar number | number
 Add a new pipe group of the given number of pipes.
 The pipe group will receive all the packets read from the input port, balanced
 among the available pipes.
 The receiving ends of the pipes
-will be called name}0 to name}number-1.
+will be called
+.Dq Ar name Ns Em }0
+to
+.Dq Ar name No Ns Em } Ns Aq Ar number No - 1 .
 The name is optional and defaults to
 the name of the input port (stripped down of any netmap operator).
 If the name is omitted, also the colon can be omitted.
@@ -69,7 +72,9 @@ If the name is omitted, also the colon can be omitted.
 This option can be supplied multiple times to define a sequence of pipe groups,
 each group receiving all the packets in turn.
 .Pp
-If no -p option is given, a single group of two pipes with default name is assumed.
+If no
+.Fl p
+option is given, a single group of two pipes with default name is assumed.
 .Pp
 It is allowed to use the same name for several groups.
 The pipe numbering in each
@@ -110,7 +115,6 @@ Please use
 to remove any stale persistent VALE port.
 .Sh SEE ALSO
 .Xr netmap 4 ,
-.Xr vale-ctl 4 ,
 .Xr bridge 8 ,
 .Xr pkt-gen 8
 .Pp

From a9b393cf4f19ff80bf803b08e7c2d0bc4a06d8c1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Oct 2018 18:24:18 +0100
Subject: [PATCH 1384/2207] fix control API to use natural alignment

Also bump the API version
---
 sys/dev/netmap/netmap.c |  8 ++----
 sys/net/netmap.h        | 56 +++++++++++++++++++++++------------------
 2 files changed, 34 insertions(+), 30 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index acf68f38d..dada5a7e3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2394,14 +2394,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	case NIOCCTRL: {
 		struct nmreq_header *hdr = (struct nmreq_header *)data;
 
-		if (hdr->nr_version != NETMAP_API) {
-			D("API mismatch for reqtype %d: got %d need %d",
-				hdr->nr_version,
-				hdr->nr_version, NETMAP_API);
-			hdr->nr_version = NETMAP_API;
-		}
 		if (hdr->nr_version < NETMAP_MIN_API ||
 		    hdr->nr_version > NETMAP_MAX_API) {
+			D("API mismatch: got %d need %d",
+				hdr->nr_version, NETMAP_API);
 			return EINVAL;
 		}
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index c96277c73..294d07404 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -39,9 +39,9 @@
 #ifndef _NET_NETMAP_H_
 #define _NET_NETMAP_H_
 
-#define	NETMAP_API	12		/* current API version */
+#define	NETMAP_API	13		/* current API version */
 
-#define	NETMAP_MIN_API	11		/* min and max versions accepted */
+#define	NETMAP_MIN_API	13		/* min and max versions accepted */
 #define	NETMAP_MAX_API	15
 /*
  * Some fields should be cache-aligned to reduce contention.
@@ -481,7 +481,7 @@ struct nmreq_option {
 	 * (e.g. because they contain arrays). For fixed-size options this
 	 * field should be set to zero. */
 	uint64_t		nro_size;
-};
+} __attribute__((__packed__));
 
 /* Header common to all requests. Do not reorder these fields, as we need
  * the second one (nr_reqtype) to know how much to copy from/to userspace. */
@@ -493,7 +493,7 @@ struct nmreq_header {
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	uint64_t		nr_options;	/* command-specific options */
 	uint64_t		nr_body;	/* ptr to nmreq_xyz struct */
-};
+} __attribute__((__packed__));
 
 enum {
 	/* Register a netmap port with the device. */
@@ -563,6 +563,7 @@ struct nmreq_register {
 	uint16_t	nr_mem_id;	/* id of the memory allocator */
 	uint16_t	nr_ringid;	/* ring(s) we care about */
 	uint32_t	nr_mode;	/* specify NR_REG_* modes */
+	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
 
 	uint64_t	nr_flags;	/* additional flags (see below) */
 /* monitors use nr_ringid and nr_mode to select the rings to monitor */
@@ -584,9 +585,7 @@ struct nmreq_register {
  * NETMAP_DO_RX_POLL. */
 #define NR_DO_RX_POLL		0x10000
 #define NR_NO_TX_POLL		0x20000
-
-	uint32_t	nr_extra_bufs;	/* number of requested extra buffers */
-};
+} __attribute__((__packed__));
 
 /* Valid values for nmreq_register.nr_mode (see above). */
 enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
@@ -626,7 +625,8 @@ struct nmreq_port_info_get {
 	uint16_t	nr_tx_rings;	/* number of tx rings */
 	uint16_t	nr_rx_rings;	/* number of rx rings */
 	uint16_t	nr_mem_id;	/* memory allocator id (in/out) */
-};
+	uint16_t	pad1;
+} __attribute__((__packed__));
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
@@ -641,7 +641,8 @@ struct nmreq_port_info_get {
 struct nmreq_vale_attach {
 	struct nmreq_register reg;
 	uint32_t port_index;
-};
+	uint32_t pad1;
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_DETACH
@@ -651,7 +652,8 @@ struct nmreq_vale_attach {
  */
 struct nmreq_vale_detach {
 	uint32_t port_index;
-};
+	uint32_t pad1;
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_LIST
@@ -660,8 +662,9 @@ struct nmreq_vale_detach {
 struct nmreq_vale_list {
 	/* Name of the VALE port (valeXXX:YYY) or empty. */
 	uint16_t	nr_bridge_idx;
+	uint16_t	pad1;
 	uint32_t	nr_port_idx;
-};
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
@@ -670,7 +673,8 @@ struct nmreq_vale_list {
  */
 struct nmreq_port_hdr {
 	uint32_t	nr_hdr_len;
-};
+	uint32_t	pad1;
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_NEWIF
@@ -682,7 +686,8 @@ struct nmreq_vale_newif {
 	uint16_t	nr_tx_rings;	/* number of tx rings */
 	uint16_t	nr_rx_rings;	/* number of rx rings */
 	uint16_t	nr_mem_id;	/* id of the memory allocator */
-};
+	uint16_t	pad1;
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
@@ -694,7 +699,8 @@ struct nmreq_vale_polling {
 #define NETMAP_POLLING_MODE_MULTI_CPU 2
 	uint32_t	nr_first_cpu_id;
 	uint32_t	nr_num_polling_cpus;
-};
+	uint32_t	pad1;
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
@@ -706,6 +712,7 @@ struct nmreq_vale_polling {
 struct nmreq_pools_info {
 	uint64_t	nr_memsize;
 	uint16_t	nr_mem_id; /* in/out argument */
+	uint16_t	pad1[3];
 	uint64_t	nr_if_pool_offset;
 	uint32_t	nr_if_pool_objtotal;
 	uint32_t	nr_if_pool_objsize;
@@ -715,7 +722,7 @@ struct nmreq_pools_info {
 	uint64_t	nr_buf_pool_offset;
 	uint32_t	nr_buf_pool_objtotal;
 	uint32_t	nr_buf_pool_objsize;
-};
+} __attribute__((__packed__));
 
 /*
  * nr_reqtype: NETMAP_REQ_SYNC_KLOOP_START
@@ -729,8 +736,9 @@ struct nmreq_sync_kloop_start {
 	 * The 'sleep_us' field specifies how many microsconds to sleep for
 	 * when there is no work to do, before doing another kloop iteration.
 	 */
-	uint32_t sleep_us;
-};
+	uint32_t	sleep_us;
+	uint32_t	pad1;
+} __attribute__((__packed__));
 
 /* A CSB entry for the application --> kernel direction. */
 struct nm_csb_atok {
@@ -738,16 +746,16 @@ struct nm_csb_atok {
 	uint32_t cur;		  /* AW+ KR+ the cur of the appl netmap_ring */
 	uint32_t appl_need_kick;  /* AW+ KR+ kern --> appl notification enable */
 	uint32_t sync_flags;	  /* AW+ KR+ the flags of the appl [tx|rx]sync() */
-	char pad[48];		  /* pad to a 64 bytes cacheline */
-};
+	uint32_t pad[12];	  /* pad to a 64 bytes cacheline */
+} __attribute__((__packed__));
 
 /* A CSB entry for the application <-- kernel direction. */
 struct nm_csb_ktoa {
 	uint32_t hwcur;		  /* AR+ KW+ the hwcur of the kern netmap_kring */
 	uint32_t hwtail;	  /* AR+ KW+ the hwtail of the kern netmap_kring */
 	uint32_t kern_need_kick;  /* AR+ KW+ appl-->kern notification enable */
-	char pad[4+48];
-};
+	uint32_t pad[13];
+} __attribute__((__packed__));
 
 #ifdef __linux__
 
@@ -844,13 +852,13 @@ struct nmreq_opt_sync_kloop_eventfds {
 		/* Notifier for the kernel loop --> application direction. */
 		int32_t irqfd;
 	} eventfds[0];
-};
+} __attribute__((__packed__));
 
 struct nmreq_opt_extmem {
 	struct nmreq_option	nro_opt;	/* common header */
 	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */
 	struct nmreq_pools_info	nro_info;	/* (in/out) */
-};
+} __attribute__((__packed__));
 
 struct nmreq_opt_csb {
 	struct nmreq_option	nro_opt;
@@ -862,6 +870,6 @@ struct nmreq_opt_csb {
 	/* Array of CSB entries for kernel --> application communication
 	 * (N entries). */
 	uint64_t		csb_ktoa;
-};
+} __attribute__((__packed__));
 
 #endif /* _NET_NETMAP_H_ */

From b28c5be0941f0309e32781dd53d2dc72194ff705 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 29 Oct 2018 19:06:06 +0100
Subject: [PATCH 1385/2207] travis: enable virtio_net.c for all the kernel
 versions

---
 ci/build-linux | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/ci/build-linux b/ci/build-linux
index 5be4e31eb..9dc0e3712 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -93,12 +93,7 @@ make -j $PROC_COUNT
 # Then build external intel drivers
 make distclean
 echo "Building external intel drivers (and virtio_net.c)"
-EXTDRIVERS="e1000e,igb,ixgbe,i40e"
-# For kernels >= 3.13 we support virtio_net.c as an external driver
-cmp=$(kverless $KERNEL_VERSION 3.13)
-if [ "$cmp" == "1" ]; then
-	EXTDRIVERS="${EXTDRIVERS},virtio_net.c"
-fi
+EXTDRIVERS="e1000e,igb,ixgbe,i40e,virtio_net.c"
 ./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=${EXTDRIVERS}
 make -j $PROC_COUNT
 

From 09515f8470554949eb055a5cf7b5ef857f34f210 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 10:29:49 +0100
Subject: [PATCH 1386/2207] linux: virtio_net.c: exclude mergeable_rx_bufs code
 for older kernels

---
 LINUX/configure                               |  11 ++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 103 ++++++++++++------
 LINUX/if_virtio_net_netmap.h                  |  14 ++-
 3 files changed, 92 insertions(+), 36 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index aa806da2c..143a2bcca 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1935,6 +1935,17 @@ EOF
 	}
 EOF
 
+  add_test 'have SKB_COALESCE_RX_FRAG' <
+
+	void
+	dummy(struct sk_buff *skb, int i, int size,
+		unsigned int truesize)
+	{
+		skb_coalesce_rx_frag(skb, i, size, truesize);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index f36459b9d..50406b1ed 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..a67bf8e 100644
+index cbf1c61..c287208 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -173,7 +173,41 @@ index cbf1c61..a67bf8e 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -637,7 +680,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -360,6 +403,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
+ 					 unsigned long ctx,
+ 					 unsigned int len)
+ {
++#ifdef WITH_MERGEABLE_RX_BUFS
+ 	void *buf = mergeable_ctx_to_buf_address(ctx);
+ 	struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
+ 	u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
+@@ -439,6 +483,7 @@ err_skb:
+ err_buf:
+ 	dev->stats.rx_dropped++;
+ 	dev_kfree_skb(head_skb);
++#endif  /* WITH_MERGEABLE_RX_BUFS */
+ 	return NULL;
+ }
+ 
+@@ -591,6 +636,7 @@ static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
+ 
+ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
+ {
++#ifdef WITH_MERGEABLE_RX_BUFS
+ 	struct page_frag *alloc_frag = &rq->alloc_frag;
+ 	char *buf;
+ 	unsigned long ctx;
+@@ -622,6 +668,9 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
+ 		put_page(virt_to_head_page(buf));
+ 
+ 	return err;
++#else  /* !WITH_MERGEABLE_RX_BUFS */
++	return -1;
++#endif /* !WITH_MERGEABLE_RX_BUFS */
+ }
+ 
+ /*
+@@ -637,7 +686,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -181,7 +215,7 @@ index cbf1c61..a67bf8e 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +771,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +777,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -261,7 +295,7 @@ index cbf1c61..a67bf8e 100644
  
  static int virtnet_open(struct net_device *dev)
  {
-@@ -789,10 +810,13 @@ static int virtnet_open(struct net_device *dev)
+@@ -789,10 +816,13 @@ static int virtnet_open(struct net_device *dev)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -279,7 +313,7 @@ index cbf1c61..a67bf8e 100644
  		virtnet_napi_enable(&vi->rq[i]);
  	}
  
-@@ -840,7 +864,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +870,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -295,7 +329,7 @@ index cbf1c61..a67bf8e 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +897,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +903,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -307,7 +341,7 @@ index cbf1c61..a67bf8e 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1044,13 @@ out:
+@@ -1009,8 +1050,13 @@ out:
  	return ret;
  }
  
@@ -323,7 +357,7 @@ index cbf1c61..a67bf8e 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1083,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1089,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -336,7 +370,7 @@ index cbf1c61..a67bf8e 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1249,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1255,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -432,7 +466,7 @@ index cbf1c61..a67bf8e 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1295,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1301,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -441,7 +475,7 @@ index cbf1c61..a67bf8e 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1397,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1403,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -461,7 +495,7 @@ index cbf1c61..a67bf8e 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1515,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1521,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -470,7 +504,7 @@ index cbf1c61..a67bf8e 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1563,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1569,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -487,7 +521,7 @@ index cbf1c61..a67bf8e 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1645,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1651,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -498,7 +532,7 @@ index cbf1c61..a67bf8e 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1653,6 @@ err:
+@@ -1701,33 +1659,6 @@ err:
  	return ret;
  }
  
@@ -532,7 +566,7 @@ index cbf1c61..a67bf8e 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1693,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1699,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -542,7 +576,7 @@ index cbf1c61..a67bf8e 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1731,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1737,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -550,7 +584,7 @@ index cbf1c61..a67bf8e 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1739,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1745,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -559,7 +593,7 @@ index cbf1c61..a67bf8e 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1749,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1755,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -579,7 +613,7 @@ index cbf1c61..a67bf8e 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,11 +1790,13 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,11 +1796,13 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -593,7 +627,7 @@ index cbf1c61..a67bf8e 100644
  
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
  		vi->mergeable_rx_bufs = true;
-@@ -1885,6 +1814,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1820,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -601,7 +635,7 @@ index cbf1c61..a67bf8e 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1822,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1828,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -609,7 +643,7 @@ index cbf1c61..a67bf8e 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1836,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1842,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -620,7 +654,7 @@ index cbf1c61..a67bf8e 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1847,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1853,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -638,7 +672,7 @@ index cbf1c61..a67bf8e 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1868,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1874,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -649,7 +683,7 @@ index cbf1c61..a67bf8e 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1897,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1903,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -665,7 +699,7 @@ index cbf1c61..a67bf8e 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1918,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1924,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -674,7 +708,7 @@ index cbf1c61..a67bf8e 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1960,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1966,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -685,7 +719,7 @@ index cbf1c61..a67bf8e 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1969,54 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1975,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -703,13 +737,14 @@ index cbf1c61..a67bf8e 100644
  	VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, \
  	VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, \
 -	VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, \
+-	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
 +	VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
 +#endif /* !DEV_NETMAP */
 +
 +#define VIRTNET_FEATURES \
 +	CSUM_FEATURES \
 +	VIRTIO_NET_F_MAC, \
- 	VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
++	VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
  	VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
  	VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
 -	VIRTIO_NET_F_CTRL_MAC_ADDR, \
@@ -721,6 +756,9 @@ index cbf1c61..a67bf8e 100644
 +#ifdef VIRTIO_NET_F_MTU
 +	VIRTIO_NET_F_MTU,
 +#endif  /* VIRTIO_NET_F_MTU */
++#ifdef WITH_MERGEABLE_RX_BUFS
++	VIRTIO_NET_F_MRG_RXBUF,
++#endif /* WITH_MERGEABLE_RX_BUFS */
  };
  
  static unsigned int features_legacy[] = {
@@ -728,6 +766,9 @@ index cbf1c61..a67bf8e 100644
 +#ifdef VIRTIO_NET_F_MTU
 +	VIRTIO_NET_F_MTU,
 +#endif  /* VIRTIO_NET_F_MTU */
++#ifdef WITH_MERGEABLE_RX_BUFS
++	VIRTIO_NET_F_MRG_RXBUF,
++#endif /* WITH_MERGEABLE_RX_BUFS */
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
  };
@@ -745,7 +786,7 @@ index cbf1c61..a67bf8e 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2029,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2041,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 51b007384..e1c9f2b40 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -60,6 +60,15 @@ static inline int ethtool_validate_duplex(__u8 duplex)
 }
 #endif  /* NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE */
 
+#ifndef NETMAP_LINUX_HAVE_U64_STATS_IRQ
+#define u64_stats_fetch_begin_irq	u64_stats_fetch_begin_bh
+#define u64_stats_fetch_retry_irq	u64_stats_fetch_retry_bh
+#endif  /* NETMAP_LINUX_HAVE_U64_STATS_IRQ */
+
+#ifdef NETMAP_LINUX_HAVE_SKB_COALESCE_RX_FRAG
+#define WITH_MERGEABLE_RX_BUFS
+#endif  /* NETMAP_LINUX_HAVE_SKB_COALESCE_RX_FRAG */
+
 #ifndef NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER
 #include 
 
@@ -282,11 +291,6 @@ void virtio_device_ready(struct virtio_device *dev)
 }
 #endif  /* NETMAP_LINUX_HAVE_VIRTIO_DEVICE_READY */
 
-#ifndef NETMAP_LINUX_HAVE_U64_STATS_IRQ
-#define u64_stats_fetch_begin_irq	u64_stats_fetch_begin_bh
-#define u64_stats_fetch_retry_irq	u64_stats_fetch_retry_bh
-#endif  /* NETMAP_LINUX_HAVE_U64_STATS_IRQ */
-
 #ifndef NETMAP_LINUX_HAVE_VIRTQUEUE_IS_BROKEN
 #define virtqueue_is_broken(_x)	false
 #endif  /* NETMAP_LINUX_HAVE_VIRTQUEUE_IS_BROKEN */

From 0bf18de22ba5e2cb84f3af87636001a96027eab5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 10:41:24 +0100
Subject: [PATCH 1387/2207] linux: virtio_net.c: ignore virtqueue_kick() return
 address

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 60 +++++++++++--------
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 50406b1ed..6561e0a02 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..c287208 100644
+index cbf1c61..50449af 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -341,7 +341,17 @@ index cbf1c61..c287208 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -1009,8 +1050,13 @@ out:
+@@ -951,8 +992,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+ 	BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
+ 	virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
+ 
+-	if (unlikely(!virtqueue_kick(vi->cvq)))
+-		return vi->ctrl_status == VIRTIO_NET_OK;
++	virtqueue_kick(vi->cvq);
+ 
+ 	/* Spin for a response, the kick causes an ioport write, trapping
+ 	 * into the hypervisor, so the request should be handled immediately.
+@@ -1009,8 +1049,13 @@ out:
  	return ret;
  }
  
@@ -357,7 +367,7 @@ index cbf1c61..c287208 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1089,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1088,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -370,7 +380,7 @@ index cbf1c61..c287208 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1255,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1254,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -466,7 +476,7 @@ index cbf1c61..c287208 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1301,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1300,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -475,7 +485,7 @@ index cbf1c61..c287208 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1403,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1402,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -495,7 +505,7 @@ index cbf1c61..c287208 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1521,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1520,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -504,7 +514,7 @@ index cbf1c61..c287208 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1569,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1568,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -521,7 +531,7 @@ index cbf1c61..c287208 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1651,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1650,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -532,7 +542,7 @@ index cbf1c61..c287208 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1659,6 @@ err:
+@@ -1701,33 +1658,6 @@ err:
  	return ret;
  }
  
@@ -566,7 +576,7 @@ index cbf1c61..c287208 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1699,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1698,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -576,7 +586,7 @@ index cbf1c61..c287208 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1737,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1736,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -584,7 +594,7 @@ index cbf1c61..c287208 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1745,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1744,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -593,7 +603,7 @@ index cbf1c61..c287208 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1755,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1754,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -613,7 +623,7 @@ index cbf1c61..c287208 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,11 +1796,13 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,11 +1795,13 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -627,7 +637,7 @@ index cbf1c61..c287208 100644
  
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
  		vi->mergeable_rx_bufs = true;
-@@ -1885,6 +1820,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1819,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -635,7 +645,7 @@ index cbf1c61..c287208 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1828,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1827,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -643,7 +653,7 @@ index cbf1c61..c287208 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1842,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1841,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -654,7 +664,7 @@ index cbf1c61..c287208 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1853,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1852,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -672,7 +682,7 @@ index cbf1c61..c287208 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1874,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1873,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -683,7 +693,7 @@ index cbf1c61..c287208 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1903,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1902,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -699,7 +709,7 @@ index cbf1c61..c287208 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1924,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1923,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -708,7 +718,7 @@ index cbf1c61..c287208 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1966,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1965,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -719,7 +729,7 @@ index cbf1c61..c287208 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1975,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1974,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -786,7 +796,7 @@ index cbf1c61..c287208 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2041,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2040,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 647319442bfcb6cfd4ec03303fc502aad8f69e22 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 11:16:55 +0100
Subject: [PATCH 1388/2207] linux: virtio_net.c: remove warnings

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 31 ++++++++++++++++---
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 6561e0a02..c770d49f4 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..50449af 100644
+index cbf1c61..6478226 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -114,7 +114,7 @@ index cbf1c61..50449af 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -220,17 +248,6 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
+@@ -220,35 +248,44 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
  	return p;
  }
  
@@ -129,10 +129,24 @@ index cbf1c61..50449af 100644
 -	netif_wake_subqueue(vi->dev, vq2txq(vq));
 -}
 -
- static unsigned int mergeable_ctx_to_buf_truesize(unsigned long mrg_ctx)
+-static unsigned int mergeable_ctx_to_buf_truesize(unsigned long mrg_ctx)
++unsigned int mergeable_ctx_to_buf_truesize(unsigned long mrg_ctx)
  {
  	unsigned int truesize = mrg_ctx & (MERGEABLE_BUFFER_ALIGN - 1);
-@@ -249,6 +266,26 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+ 	return (truesize + 1) * MERGEABLE_BUFFER_ALIGN;
+ }
+ 
+-static void *mergeable_ctx_to_buf_address(unsigned long mrg_ctx)
++void *mergeable_ctx_to_buf_address(unsigned long mrg_ctx)
+ {
+ 	return (void *)(mrg_ctx & -MERGEABLE_BUFFER_ALIGN);
+ 
+ }
+ 
+-static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
++unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
+ {
+ 	unsigned int size = truesize / MERGEABLE_BUFFER_ALIGN;
  	return (unsigned long)buf | (size - 1);
  }
  
@@ -189,6 +203,15 @@ index cbf1c61..50449af 100644
  	return NULL;
  }
  
+@@ -579,7 +624,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
+ 	return err;
+ }
+ 
+-static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
++unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
+ {
+ 	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ 	unsigned int len;
 @@ -591,6 +636,7 @@ static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
  
  static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)

From 064b6e4670f1416d121ee567336623c6741fcd72 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 11:25:54 +0100
Subject: [PATCH 1389/2207] linux: virtio_net.c: add compatibility support for
 config accessors

---
 LINUX/configure              |  10 +++
 LINUX/if_virtio_net_netmap.h | 136 +++++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 143a2bcca..a1ac768fc 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1946,6 +1946,16 @@ EOF
 	}
 EOF
 
+  add_test 'have VIRTIO_CONFIG_ACCESSORS' <
+
+	u16
+	dummy(struct virtio_device *vdev, unsigned int offset)
+	{
+		return virtio_cread16(vdev, offset);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index e1c9f2b40..08fc297a1 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -300,6 +300,142 @@ void virtio_device_ready(struct virtio_device *dev)
 #define virtqueue_enable_cb_delayed(_vq)	virtqueue_enable_cb(_vq)
 #endif  /* !VIRTIO_CB_DELAYED */
 
+#ifndef NETMAP_LINUX_HAVE_VIRTIO_CONFIG_ACCESSORS
+#define virtio_cread(vdev, structname, member, ptr)			\
+	do {								\
+		/* Must match the member's type, and be integer */	\
+		if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \
+			(*ptr) = 1;					\
+									\
+		switch (sizeof(*ptr)) {					\
+		case 1:							\
+			*(ptr) = virtio_cread8(vdev,			\
+					       offsetof(structname, member)); \
+			break;						\
+		case 2:							\
+			*(ptr) = virtio_cread16(vdev,			\
+						offsetof(structname, member)); \
+			break;						\
+		case 4:							\
+			*(ptr) = virtio_cread32(vdev,			\
+						offsetof(structname, member)); \
+			break;						\
+		case 8:							\
+			*(ptr) = virtio_cread64(vdev,			\
+						offsetof(structname, member)); \
+			break;						\
+		default:						\
+			BUG();						\
+		}							\
+	} while(0)
+
+/* Config space accessors. */
+#define virtio_cwrite(vdev, structname, member, ptr)			\
+	do {								\
+		/* Must match the member's type, and be integer */	\
+		if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \
+			BUG_ON((*ptr) == 1);				\
+									\
+		switch (sizeof(*ptr)) {					\
+		case 1:							\
+			virtio_cwrite8(vdev,				\
+				       offsetof(structname, member),	\
+				       *(ptr));				\
+			break;						\
+		case 2:							\
+			virtio_cwrite16(vdev,				\
+					offsetof(structname, member),	\
+					*(ptr));			\
+			break;						\
+		case 4:							\
+			virtio_cwrite32(vdev,				\
+					offsetof(structname, member),	\
+					*(ptr));			\
+			break;						\
+		case 8:							\
+			virtio_cwrite64(vdev,				\
+					offsetof(structname, member),	\
+					*(ptr));			\
+			break;						\
+		default:						\
+			BUG();						\
+		}							\
+	} while(0)
+
+static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset)
+{
+	u8 ret;
+	vdev->config->get(vdev, offset, &ret, sizeof(ret));
+	return ret;
+}
+
+static inline void virtio_cread_bytes(struct virtio_device *vdev,
+				      unsigned int offset,
+				      void *buf, size_t len)
+{
+	vdev->config->get(vdev, offset, buf, len);
+}
+
+static inline void virtio_cwrite8(struct virtio_device *vdev,
+				  unsigned int offset, u8 val)
+{
+	vdev->config->set(vdev, offset, &val, sizeof(val));
+}
+
+static inline u16 virtio_cread16(struct virtio_device *vdev,
+				 unsigned int offset)
+{
+	u16 ret;
+	vdev->config->get(vdev, offset, &ret, sizeof(ret));
+	return ret;
+}
+
+static inline void virtio_cwrite16(struct virtio_device *vdev,
+				   unsigned int offset, u16 val)
+{
+	vdev->config->set(vdev, offset, &val, sizeof(val));
+}
+
+static inline u32 virtio_cread32(struct virtio_device *vdev,
+				 unsigned int offset)
+{
+	u32 ret;
+	vdev->config->get(vdev, offset, &ret, sizeof(ret));
+	return ret;
+}
+
+static inline void virtio_cwrite32(struct virtio_device *vdev,
+				   unsigned int offset, u32 val)
+{
+	vdev->config->set(vdev, offset, &val, sizeof(val));
+}
+
+static inline u64 virtio_cread64(struct virtio_device *vdev,
+				 unsigned int offset)
+{
+	u64 ret;
+	vdev->config->get(vdev, offset, &ret, sizeof(ret));
+	return ret;
+}
+
+static inline void virtio_cwrite64(struct virtio_device *vdev,
+				   unsigned int offset, u64 val)
+{
+	vdev->config->set(vdev, offset, &val, sizeof(val));
+}
+
+/* Conditional config space accessors. */
+#define virtio_cread_feature(vdev, fbit, structname, member, ptr)	\
+	({								\
+		int _r = 0;						\
+		if (!virtio_has_feature(vdev, fbit))			\
+			_r = -ENOENT;					\
+		else							\
+			virtio_cread((vdev), structname, member, ptr);	\
+		_r;							\
+	})
+#endif  /* !NETMAP_LINUX_HAVE_VIRTIO_CONFIG_ACCESSORS */
+
 /*************************************************************************/
 /* NETMAP SUPPORT                                                        */
 /*************************************************************************/

From 30c54d8f9d091b746e6af3dfc0f35546a52088c1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 11:53:59 +0100
Subject: [PATCH 1390/2207] linux: virtio_net.c: add compatibility support for
 u64_stats_init()

---
 LINUX/configure              | 10 ++++++++++
 LINUX/if_virtio_net_netmap.h |  8 ++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index a1ac768fc..5eeef7b13 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1956,6 +1956,16 @@ EOF
 	}
 EOF
 
+  add_test 'have U64_STATS_INIT' <
+
+	void
+	dummy(struct u64_stats_sync *syncp)
+	{
+		u64_stats_init(syncp);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 08fc297a1..bac13e66e 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -60,14 +60,18 @@ static inline int ethtool_validate_duplex(__u8 duplex)
 }
 #endif  /* NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE */
 
+#ifndef NETMAP_LINUX_HAVE_U64_STATS_INIT
+#define u64_stats_init(x)
+#endif  /* !NETMAP_LINUX_HAVE_U64_STATS_INIT */
+
 #ifndef NETMAP_LINUX_HAVE_U64_STATS_IRQ
 #define u64_stats_fetch_begin_irq	u64_stats_fetch_begin_bh
 #define u64_stats_fetch_retry_irq	u64_stats_fetch_retry_bh
-#endif  /* NETMAP_LINUX_HAVE_U64_STATS_IRQ */
+#endif  /* !NETMAP_LINUX_HAVE_U64_STATS_IRQ */
 
 #ifdef NETMAP_LINUX_HAVE_SKB_COALESCE_RX_FRAG
 #define WITH_MERGEABLE_RX_BUFS
-#endif  /* NETMAP_LINUX_HAVE_SKB_COALESCE_RX_FRAG */
+#endif  /* !NETMAP_LINUX_HAVE_SKB_COALESCE_RX_FRAG */
 
 #ifndef NETMAP_LINUX_HAVE_VIRTIO_BYTEORDER
 #include 

From 1e1d84d794ea9c6ba22741f508e9f9dc15f1321a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 12:18:57 +0100
Subject: [PATCH 1391/2207] utils: ctrl-api-test: fix test checks for FreeBSD

---
 utils/ctrl-api-test.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 36cb11cd3..5dc0a53c2 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1077,12 +1077,13 @@ sync_kloop_eventfds(struct TestContext *ctx)
 
 	ret = sync_kloop_start_stop(ctx);
 	if (ret) {
-#ifdef __FreeBSD__
-		return 0;
-#endif /* __FreeBSD__ */
 		return ret;
 	}
+#ifdef __linux__
 	save.nro_status = 0;
+#else  /* !__linux__ */
+	save.nro_status = EOPNOTSUPP;
+#endif /* !__linux__ */
 
 	return checkoption(&opt->nro_opt, &save);
 }

From 901dccbaaad3e6b5eece6dda317fa9310fe4ab04 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 12:39:53 +0100
Subject: [PATCH 1392/2207] linux: virtio_net.c: VIRTIO_F_ANY_LAYOUT if not
 defined

---
 LINUX/if_virtio_net_netmap.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index bac13e66e..268ecae0b 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -41,6 +41,10 @@
 #define VIRTIO_F_VERSION_1		32
 #endif
 
+#ifndef VIRTIO_F_ANY_LAYOUT
+#define VIRTIO_F_ANY_LAYOUT		27
+#endif
+
 #ifndef NETMAP_LINUX_HAVE_ETHTOOL_VALIDATE
 static inline int ethtool_validate_speed(__u32 speed)
 {

From a289e6eaed59a8d8c5f1ab1e75f4da6cda633bcb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 12:41:25 +0100
Subject: [PATCH 1393/2207] linux: virtio_net.c: avoid warning on unused
 "features"

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index c770d49f4..b67c9cd97 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..6478226 100644
+index cbf1c61..84ab0fa 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -784,7 +784,8 @@ index cbf1c61..6478226 100644
 -	VIRTIO_NET_F_MTU
 +	VIRTIO_NET_F_CTRL_MAC_ADDR
  
- static unsigned int features[] = {
+-static unsigned int features[] = {
++unsigned int features[] = {
  	VIRTNET_FEATURES,
 +#ifdef VIRTIO_NET_F_MTU
 +	VIRTIO_NET_F_MTU,

From e13e21adb79cbefc2c79e99d6e6e9e5d0b9dc077 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 12:48:19 +0100
Subject: [PATCH 1394/2207] travis: use stable version for 3.10 (3.10.108)

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 3446f7db2..90f46056b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,7 @@ env:
   - KERNEL_VERSION=3.7   ARCH=x86_64
   - KERNEL_VERSION=3.8   ARCH=x86_64
   - KERNEL_VERSION=3.9   ARCH=x86_64
-  - KERNEL_VERSION=3.10  ARCH=x86_64
+  - KERNEL_VERSION=3.10.108  ARCH=x86_64
   - KERNEL_VERSION=3.11  ARCH=x86_64
   - KERNEL_VERSION=3.12  ARCH=x86_64
   - KERNEL_VERSION=3.13  ARCH=x86_64

From 2b1cc7873b4c01384773b593dd6854ec1dac82f7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 15:15:32 +0100
Subject: [PATCH 1395/2207] netmap.h: remove packed attribute

This causes warnings with LLVM when defining pointers to members.
---
 sys/net/netmap.h | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 294d07404..86f395ae5 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -481,7 +481,7 @@ struct nmreq_option {
 	 * (e.g. because they contain arrays). For fixed-size options this
 	 * field should be set to zero. */
 	uint64_t		nro_size;
-} __attribute__((__packed__));
+};
 
 /* Header common to all requests. Do not reorder these fields, as we need
  * the second one (nr_reqtype) to know how much to copy from/to userspace. */
@@ -493,7 +493,7 @@ struct nmreq_header {
 	char			nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
 	uint64_t		nr_options;	/* command-specific options */
 	uint64_t		nr_body;	/* ptr to nmreq_xyz struct */
-} __attribute__((__packed__));
+};
 
 enum {
 	/* Register a netmap port with the device. */
@@ -585,7 +585,7 @@ struct nmreq_register {
  * NETMAP_DO_RX_POLL. */
 #define NR_DO_RX_POLL		0x10000
 #define NR_NO_TX_POLL		0x20000
-} __attribute__((__packed__));
+};
 
 /* Valid values for nmreq_register.nr_mode (see above). */
 enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
@@ -626,7 +626,7 @@ struct nmreq_port_info_get {
 	uint16_t	nr_rx_rings;	/* number of rx rings */
 	uint16_t	nr_mem_id;	/* memory allocator id (in/out) */
 	uint16_t	pad1;
-} __attribute__((__packed__));
+};
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
 
@@ -642,7 +642,7 @@ struct nmreq_vale_attach {
 	struct nmreq_register reg;
 	uint32_t port_index;
 	uint32_t pad1;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_DETACH
@@ -653,7 +653,7 @@ struct nmreq_vale_attach {
 struct nmreq_vale_detach {
 	uint32_t port_index;
 	uint32_t pad1;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_LIST
@@ -664,7 +664,7 @@ struct nmreq_vale_list {
 	uint16_t	nr_bridge_idx;
 	uint16_t	pad1;
 	uint32_t	nr_port_idx;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
@@ -674,7 +674,7 @@ struct nmreq_vale_list {
 struct nmreq_port_hdr {
 	uint32_t	nr_hdr_len;
 	uint32_t	pad1;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_NEWIF
@@ -687,7 +687,7 @@ struct nmreq_vale_newif {
 	uint16_t	nr_rx_rings;	/* number of rx rings */
 	uint16_t	nr_mem_id;	/* id of the memory allocator */
 	uint16_t	pad1;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
@@ -700,7 +700,7 @@ struct nmreq_vale_polling {
 	uint32_t	nr_first_cpu_id;
 	uint32_t	nr_num_polling_cpus;
 	uint32_t	pad1;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
@@ -722,7 +722,7 @@ struct nmreq_pools_info {
 	uint64_t	nr_buf_pool_offset;
 	uint32_t	nr_buf_pool_objtotal;
 	uint32_t	nr_buf_pool_objsize;
-} __attribute__((__packed__));
+};
 
 /*
  * nr_reqtype: NETMAP_REQ_SYNC_KLOOP_START
@@ -738,7 +738,7 @@ struct nmreq_sync_kloop_start {
 	 */
 	uint32_t	sleep_us;
 	uint32_t	pad1;
-} __attribute__((__packed__));
+};
 
 /* A CSB entry for the application --> kernel direction. */
 struct nm_csb_atok {
@@ -747,7 +747,7 @@ struct nm_csb_atok {
 	uint32_t appl_need_kick;  /* AW+ KR+ kern --> appl notification enable */
 	uint32_t sync_flags;	  /* AW+ KR+ the flags of the appl [tx|rx]sync() */
 	uint32_t pad[12];	  /* pad to a 64 bytes cacheline */
-} __attribute__((__packed__));
+};
 
 /* A CSB entry for the application <-- kernel direction. */
 struct nm_csb_ktoa {
@@ -755,7 +755,7 @@ struct nm_csb_ktoa {
 	uint32_t hwtail;	  /* AR+ KW+ the hwtail of the kern netmap_kring */
 	uint32_t kern_need_kick;  /* AR+ KW+ appl-->kern notification enable */
 	uint32_t pad[13];
-} __attribute__((__packed__));
+};
 
 #ifdef __linux__
 
@@ -852,13 +852,13 @@ struct nmreq_opt_sync_kloop_eventfds {
 		/* Notifier for the kernel loop --> application direction. */
 		int32_t irqfd;
 	} eventfds[0];
-} __attribute__((__packed__));
+};
 
 struct nmreq_opt_extmem {
 	struct nmreq_option	nro_opt;	/* common header */
 	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */
 	struct nmreq_pools_info	nro_info;	/* (in/out) */
-} __attribute__((__packed__));
+};
 
 struct nmreq_opt_csb {
 	struct nmreq_option	nro_opt;
@@ -870,6 +870,6 @@ struct nmreq_opt_csb {
 	/* Array of CSB entries for kernel --> application communication
 	 * (N entries). */
 	uint64_t		csb_ktoa;
-} __attribute__((__packed__));
+};
 
 #endif /* _NET_NETMAP_H_ */

From 220d1c15bbd70ac269fb0b5f666024af3d1e57a7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 15:35:46 +0100
Subject: [PATCH 1396/2207] linux: virtio_net.c: check for napi_hash_del

---
 LINUX/configure                               | 10 ++++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 50 +++++++++++--------
 2 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 5eeef7b13..67db2bb96 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1966,6 +1966,16 @@ EOF
 	}
 EOF
 
+  add_test 'have NAPI_HASH_DEL' <
+
+	void
+	dummy(struct napi_struct *napi)
+	{
+		napi_hash_del(napi);
+	}
+EOF
+
     add_test 'define VIRTIO_CB_DELAYED' <
   
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index b67c9cd97..49f9f681e 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..84ab0fa 100644
+index cbf1c61..1885853 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,8 @@
@@ -528,7 +528,17 @@ index cbf1c61..84ab0fa 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1565,8 +1520,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1502,7 +1457,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+ 	int i;
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef NETMAP_LINUX_HAVE_NAPI_HASH_DEL
+ 		napi_hash_del(&vi->rq[i].napi);
++#endif  /* NETMAP_LINUX_HAVE_NAPI_HASH_DEL */
+ 		netif_napi_del(&vi->rq[i].napi);
+ 	}
+ 
+@@ -1565,8 +1522,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -537,7 +547,7 @@ index cbf1c61..84ab0fa 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1568,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1570,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -554,7 +564,7 @@ index cbf1c61..84ab0fa 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1650,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1652,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -565,7 +575,7 @@ index cbf1c61..84ab0fa 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1658,6 @@ err:
+@@ -1701,33 +1660,6 @@ err:
  	return ret;
  }
  
@@ -599,7 +609,7 @@ index cbf1c61..84ab0fa 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1698,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1700,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -609,7 +619,7 @@ index cbf1c61..84ab0fa 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1736,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1738,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -617,7 +627,7 @@ index cbf1c61..84ab0fa 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1744,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1746,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -626,7 +636,7 @@ index cbf1c61..84ab0fa 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1754,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1756,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -646,7 +656,7 @@ index cbf1c61..84ab0fa 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,11 +1795,13 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,11 +1797,13 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -660,7 +670,7 @@ index cbf1c61..84ab0fa 100644
  
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
  		vi->mergeable_rx_bufs = true;
-@@ -1885,6 +1819,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -668,7 +678,7 @@ index cbf1c61..84ab0fa 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1827,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1829,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -676,7 +686,7 @@ index cbf1c61..84ab0fa 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1841,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1843,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -687,7 +697,7 @@ index cbf1c61..84ab0fa 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1852,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1854,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -705,7 +715,7 @@ index cbf1c61..84ab0fa 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1873,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1875,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -716,7 +726,7 @@ index cbf1c61..84ab0fa 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1902,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1904,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -732,7 +742,7 @@ index cbf1c61..84ab0fa 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1923,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1925,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -741,7 +751,7 @@ index cbf1c61..84ab0fa 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1965,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1967,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -752,7 +762,7 @@ index cbf1c61..84ab0fa 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1974,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1976,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -820,7 +830,7 @@ index cbf1c61..84ab0fa 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2040,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2042,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 7eed1072ac4660ec6e64556b9cb0177e245823cc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 16:14:37 +0100
Subject: [PATCH 1397/2207] Revert "travis: enable virtio_net.c for all the
 kernel versions"

This reverts commit b28c5be0941f0309e32781dd53d2dc72194ff705.
---
 ci/build-linux | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/ci/build-linux b/ci/build-linux
index 9dc0e3712..2a0d9db07 100755
--- a/ci/build-linux
+++ b/ci/build-linux
@@ -93,7 +93,12 @@ make -j $PROC_COUNT
 # Then build external intel drivers
 make distclean
 echo "Building external intel drivers (and virtio_net.c)"
-EXTDRIVERS="e1000e,igb,ixgbe,i40e,virtio_net.c"
+EXTDRIVERS="e1000e,igb,ixgbe,i40e"
+# For kernels >= 3.13 we support virtio_net.c as an external driver
+cmp=$(kverless $KERNEL_VERSION 3.10)
+if [ "$cmp" == "1" ]; then
+	EXTDRIVERS="${EXTDRIVERS},virtio_net.c"
+fi
 ./configure --kernel-dir=$PWD/linux-${KERNEL_VERSION} --driver-suffix=_netmap --drivers=${EXTDRIVERS}
 make -j $PROC_COUNT
 

From 073c0d49559701b1406a561cdb8eea16b8507a51 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 30 Oct 2018 16:44:20 +0100
Subject: [PATCH 1398/2207] linux: virtio-net.c: define NAPI_POLL_WEIGHT if not
 defined

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 122 +++++++++---------
 1 file changed, 63 insertions(+), 59 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 49f9f681e..edb350700 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,10 +30,10 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..1885853 100644
+index cbf1c61..53f8779 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
-@@ -26,8 +26,8 @@
+@@ -26,8 +26,12 @@
  #include 
  #include 
  #include 
@@ -41,10 +41,14 @@ index cbf1c61..1885853 100644
 -#include 
 +
 +#include   /* needed for netmap_linux_config.h */
++
++#ifndef NAPI_POLL_WEIGHT
++#define NAPI_POLL_WEIGHT	64
++#endif
  
  static int napi_weight = NAPI_POLL_WEIGHT;
  module_param(napi_weight, int, 0444);
-@@ -40,6 +40,37 @@ module_param(gso, bool, 0444);
+@@ -40,6 +44,37 @@ module_param(gso, bool, 0444);
  #define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
  #define GOOD_COPY_LEN	128
  
@@ -82,7 +86,7 @@ index cbf1c61..1885853 100644
  /* RX packet size EWMA. The average packet size is used to determine the packet
   * buffer size when refilling RX rings. As the entire RX ring may be refilled
   * at once, the weight is chosen so that the EWMA will be insensitive to short-
-@@ -70,6 +101,8 @@ struct send_queue {
+@@ -70,6 +105,8 @@ struct send_queue {
  	/* TX: fragments + linear part + virtio header */
  	struct scatterlist sg[MAX_SKB_FRAGS + 2];
  
@@ -91,7 +95,7 @@ index cbf1c61..1885853 100644
  	/* Name of the send queue: output.$index */
  	char name[40];
  };
-@@ -93,6 +126,8 @@ struct receive_queue {
+@@ -93,6 +130,8 @@ struct receive_queue {
  	/* RX: fragments + linear part + virtio header */
  	struct scatterlist sg[MAX_SKB_FRAGS + 2];
  
@@ -100,7 +104,7 @@ index cbf1c61..1885853 100644
  	/* Name of this receive queue: input.$index */
  	char name[40];
  };
-@@ -135,13 +170,6 @@ struct virtnet_info {
+@@ -135,13 +174,6 @@ struct virtnet_info {
  	/* Work struct for config space updates */
  	struct work_struct config_work;
  
@@ -114,7 +118,7 @@ index cbf1c61..1885853 100644
  	/* Control VQ buffers: protected by the rtnl lock */
  	struct virtio_net_ctrl_hdr ctrl_hdr;
  	virtio_net_ctrl_ack ctrl_status;
-@@ -220,35 +248,44 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
+@@ -220,35 +252,44 @@ static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
  	return p;
  }
  
@@ -173,7 +177,7 @@ index cbf1c61..1885853 100644
  /* Called from bottom half context */
  static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  				   struct receive_queue *rq,
-@@ -263,7 +300,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+@@ -263,7 +304,13 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
  	p = page_address(page) + offset;
  
  	/* copy small packet so we can reuse these pages for small data */
@@ -187,7 +191,7 @@ index cbf1c61..1885853 100644
  	if (unlikely(!skb))
  		return NULL;
  
-@@ -360,6 +403,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
+@@ -360,6 +407,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
  					 unsigned long ctx,
  					 unsigned int len)
  {
@@ -195,7 +199,7 @@ index cbf1c61..1885853 100644
  	void *buf = mergeable_ctx_to_buf_address(ctx);
  	struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
  	u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
-@@ -439,6 +483,7 @@ err_skb:
+@@ -439,6 +487,7 @@ err_skb:
  err_buf:
  	dev->stats.rx_dropped++;
  	dev_kfree_skb(head_skb);
@@ -203,7 +207,7 @@ index cbf1c61..1885853 100644
  	return NULL;
  }
  
-@@ -579,7 +624,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -579,7 +628,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
  	return err;
  }
  
@@ -212,7 +216,7 @@ index cbf1c61..1885853 100644
  {
  	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
  	unsigned int len;
-@@ -591,6 +636,7 @@ static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
+@@ -591,6 +640,7 @@ static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
  
  static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
  {
@@ -220,7 +224,7 @@ index cbf1c61..1885853 100644
  	struct page_frag *alloc_frag = &rq->alloc_frag;
  	char *buf;
  	unsigned long ctx;
-@@ -622,6 +668,9 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
+@@ -622,6 +672,9 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
  		put_page(virt_to_head_page(buf));
  
  	return err;
@@ -230,7 +234,7 @@ index cbf1c61..1885853 100644
  }
  
  /*
-@@ -637,7 +686,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +690,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -238,7 +242,7 @@ index cbf1c61..1885853 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +777,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,16 +781,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -271,13 +275,14 @@ index cbf1c61..1885853 100644
 +		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
 -			virtqueue_disable_cb(rq->vq);
--			__napi_schedule(napi);
--		}
--	}
--
--	return received;
--}
--
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+@@ -746,53 +814,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	return received;
+ }
+ 
 -#ifdef CONFIG_NET_RX_BUSY_POLL
 -/* must be called with local_bh_disable()d */
 -static int virtnet_busy_poll(struct napi_struct *napi)
@@ -307,18 +312,17 @@ index cbf1c61..1885853 100644
 -			budget -= received;
 -			goto again;
 -		} else {
-+			virtqueue_disable_cb(vq);
- 			__napi_schedule(napi);
- 		}
- 	}
- 
- 	return received;
- }
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
 -#endif	/* CONFIG_NET_RX_BUSY_POLL */
- 
+-
  static int virtnet_open(struct net_device *dev)
  {
-@@ -789,10 +816,13 @@ static int virtnet_open(struct net_device *dev)
+ 	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -336,7 +340,7 @@ index cbf1c61..1885853 100644
  		virtnet_napi_enable(&vi->rq[i]);
  	}
  
-@@ -840,7 +870,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +874,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -352,7 +356,7 @@ index cbf1c61..1885853 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +903,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +907,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -364,7 +368,7 @@ index cbf1c61..1885853 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -951,8 +992,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+@@ -951,8 +996,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
  	BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
  	virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
  
@@ -374,7 +378,7 @@ index cbf1c61..1885853 100644
  
  	/* Spin for a response, the kick causes an ioport write, trapping
  	 * into the hypervisor, so the request should be handled immediately.
-@@ -1009,8 +1049,13 @@ out:
+@@ -1009,8 +1053,13 @@ out:
  	return ret;
  }
  
@@ -390,7 +394,7 @@ index cbf1c61..1885853 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1088,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1092,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -403,7 +407,7 @@ index cbf1c61..1885853 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1254,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1258,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -499,7 +503,7 @@ index cbf1c61..1885853 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1300,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1304,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -508,7 +512,7 @@ index cbf1c61..1885853 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1402,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1406,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -528,7 +532,7 @@ index cbf1c61..1885853 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1502,7 +1457,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+@@ -1502,7 +1461,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -538,7 +542,7 @@ index cbf1c61..1885853 100644
  		netif_napi_del(&vi->rq[i].napi);
  	}
  
-@@ -1565,8 +1522,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1526,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -547,7 +551,7 @@ index cbf1c61..1885853 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1570,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1574,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -564,7 +568,7 @@ index cbf1c61..1885853 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1652,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1656,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -575,7 +579,7 @@ index cbf1c61..1885853 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1660,6 @@ err:
+@@ -1701,33 +1664,6 @@ err:
  	return ret;
  }
  
@@ -609,7 +613,7 @@ index cbf1c61..1885853 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1700,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1704,9 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -619,7 +623,7 @@ index cbf1c61..1885853 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1738,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1742,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -627,7 +631,7 @@ index cbf1c61..1885853 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1746,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1750,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -636,7 +640,7 @@ index cbf1c61..1885853 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1756,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1760,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -656,7 +660,7 @@ index cbf1c61..1885853 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,11 +1797,13 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,11 +1801,13 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -670,7 +674,7 @@ index cbf1c61..1885853 100644
  
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
  		vi->mergeable_rx_bufs = true;
-@@ -1885,6 +1821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1825,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -678,7 +682,7 @@ index cbf1c61..1885853 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1829,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1833,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -686,7 +690,7 @@ index cbf1c61..1885853 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1843,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1847,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -697,7 +701,7 @@ index cbf1c61..1885853 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1854,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1858,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -715,7 +719,7 @@ index cbf1c61..1885853 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1875,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1879,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -726,7 +730,7 @@ index cbf1c61..1885853 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1904,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1908,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -742,7 +746,7 @@ index cbf1c61..1885853 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1925,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1929,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -751,7 +755,7 @@ index cbf1c61..1885853 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1967,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1971,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -762,7 +766,7 @@ index cbf1c61..1885853 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1976,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1980,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -830,7 +834,7 @@ index cbf1c61..1885853 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2042,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2046,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 1640ffcad96ecf6517aae3e53979337a54d9a86b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 31 Oct 2018 15:45:28 +0100
Subject: [PATCH 1399/2207] apps: lb man: small fix from FreeBSD

---
 apps/lb/lb.8 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/lb/lb.8 b/apps/lb/lb.8
index 16633c17b..91694cb9b 100644
--- a/apps/lb/lb.8
+++ b/apps/lb/lb.8
@@ -56,7 +56,7 @@ It must be supplied exactly once to identify
 the input port.
 Any netmap port type (e.g., physical interface, VALE switch, pipe,
 monitor port) can be used.
-.It Fl p Ar name Ns Cm : Ns Ar number | number
+.It Fl p Ar name Ns Cm \&: Ns Ar number | number
 Add a new pipe group of the given number of pipes.
 The pipe group will receive all the packets read from the input port, balanced
 among the available pipes.

From c3f62f1f313af8995332b90cf12ca3e7c20020c9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 31 Oct 2018 16:44:48 +0100
Subject: [PATCH 1400/2207] ctrl-api-test: remove memory leak

---
 utils/GNUmakefile     | 2 +-
 utils/ctrl-api-test.c | 8 +++++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 4a28f6572..b17fe1e82 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -12,7 +12,7 @@ VPATH   = $(SRCDIR)/utils
 
 NO_MAN=
 CFLAGS  = -O2 -pipe
-CFLAGS += -Werror -Wall -Wunused-function
+CFLAGS += -Werror -Wall -Wunused-function -fsanitize=address
 CFLAGS += -I $(SRCDIR)/sys # -I/home/luigi/FreeBSD/head/sys -I../sys
 CFLAGS += -Wextra -g
 CFLAGS += $(SUBSYS_FLAGS)
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5dc0a53c2..2a1741b60 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1077,6 +1077,8 @@ sync_kloop_eventfds(struct TestContext *ctx)
 
 	ret = sync_kloop_start_stop(ctx);
 	if (ret) {
+		free(opt);
+		clear_options(ctx);
 		return ret;
 	}
 #ifdef __linux__
@@ -1085,7 +1087,11 @@ sync_kloop_eventfds(struct TestContext *ctx)
 	save.nro_status = EOPNOTSUPP;
 #endif /* !__linux__ */
 
-	return checkoption(&opt->nro_opt, &save);
+	ret = checkoption(&opt->nro_opt, &save);
+	free(opt);
+	clear_options(ctx);
+
+	return ret;
 }
 
 static int

From 1d65a1a6f797803625f22609263d62a8164e4ee8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 31 Oct 2018 18:42:32 +0100
Subject: [PATCH 1401/2207] linux: if_virtio_net_netmap.h: small cosmetic
 changes

---
 LINUX/if_virtio_net_netmap.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 268ecae0b..171fb6a4e 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -792,7 +792,9 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
-	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+	int force_update = (flags & NAF_FORCE_READ) ||
+				(kring->nr_kflags & NKR_PENDINTR);
+	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
 
 	/* device-specific */
 	struct virtnet_info *vi = netdev_priv(ifp);
@@ -802,7 +804,6 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	size_t vnet_hdr_len = vi->mergeable_rx_bufs ?
 				sizeof(rq->shared_rxvhdr) :
 				sizeof(rq->shared_rxvhdr.hdr);
-	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
 
 	virtqueue_disable_cb(vq);
 

From a56a9c5594c9e11160a6b7dd595ad1a52f7656d0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 31 Oct 2018 19:06:22 +0100
Subject: [PATCH 1402/2207] linux: virtio_net: fix typo

---
 LINUX/if_virtio_net_netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 171fb6a4e..94c7e9c44 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -813,7 +813,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * Only accept our own buffers (matching the token). We should only get
 	 * matching buffers, because of virtio_net_netmap_detach_unused() and
 	 * virtio_net_netmap_init_buffers(). We may need to stop early to avoid
-	 * hwtail to overrun hwcur;
+	 * hwtail to overrun hwcur.
 	 */
 	if (netmap_no_pendintr || force_update) {
 		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
@@ -835,7 +835,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 				/* Skip the virtio-net header. */
 				len -= vnet_hdr_len;
 				if (unlikely(len < 0)) {
-					RD(5, "Truncated virtio-net-header, missing %d"
+					RD(1, "Truncated virtio-net-header, missing %d"
 							" bytes", -len);
 					len = 0;
 				}

From 1b5361dfdb4c4d0b217e6ab8362201c732d15078 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 31 Oct 2018 19:08:15 +0100
Subject: [PATCH 1403/2207] linux: virtio_net_netmap_rxsync: fix bug

---
 LINUX/if_virtio_net_netmap.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 94c7e9c44..02f54b2c0 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -860,7 +860,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 	if (nm_i != head) {
 		int nospace = 0;
 
-		for (n = 0; nm_i != head; n++) {
+		for (; nm_i != head; nm_i = nm_next(nm_i, lim)) {
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			void *addr = NMB(na, slot);
 
@@ -879,10 +879,9 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 				   nospace);
 				break;
 			}
-			nm_i = nm_next(nm_i, lim);
 		}
 		virtqueue_kick(vq);
-		kring->nr_hwcur = head;
+		kring->nr_hwcur = nm_i;
 	}
 
 	/* We have finished processing used RX buffers, so we have to tell

From abfdb4a11478da9f7e75e48f91a3c000b1a07727 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 6 Nov 2018 17:01:46 +0100
Subject: [PATCH 1404/2207] README: add example command to disable offloads on
 FreeBSD

---
 README | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/README b/README
index 828c23201..5765df7ba 100644
--- a/README
+++ b/README
@@ -253,6 +253,16 @@ LOWER SPEED THAN LINE RATE
     e1000/e1000e vary between 1.15 and 1.32 Mpps. re/r8169 is
     extremely slow in sending (max 4-500 Kpps)
 
+HOST RINGS DO NOT WORK
+  + disable NIC offloads, because netmap does not support them and
+    packets exchanged between netmap and the kernel stack can be dropped
+    because of invalid checksums. On FreeBSD offloads can be disabled with
+    a command like
+
+      # ifconfig vtnet0 -txcsum -rxcsum -tso4 -tso6 -lro -txcsum6 -rxcsum6
+
+    See LINUX/README for the corresponding Linux command.
+
 
 Credits
 -------

From 5bb657ccce92ea1c3cec12e209673bea114fb89c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 9 Nov 2018 09:46:44 +0100
Subject: [PATCH 1405/2207] lb: add $FreeBSD$ string

---
 apps/lb/lb.c       | 2 +-
 apps/lb/pkt_hash.c | 2 ++
 apps/lb/pkt_hash.h | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 6af4adea0..73fcf20f7 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -22,7 +22,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
+/* $FreeBSD$ */
 #include 
 #include 
 #include 
diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index a05344220..ba7be296c 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -25,6 +25,8 @@
  ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  ** POSSIBILITY OF SUCH DAMAGE.
  **/
+/* $FreeBSD$ */
+
 /* for func prototypes */
 #include "pkt_hash.h"
 
diff --git a/apps/lb/pkt_hash.h b/apps/lb/pkt_hash.h
index 1f73ff97e..7371f0740 100644
--- a/apps/lb/pkt_hash.h
+++ b/apps/lb/pkt_hash.h
@@ -25,6 +25,7 @@
  ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  ** POSSIBILITY OF SUCH DAMAGE.
  **/
+/* $FreeBSD$ */
 #ifndef LB_PKT_HASH_H
 #define LB_PKT_HASH_H
 /*---------------------------------------------------------------------*/

From cd12a65aac212a8dd69969c05b38ba6541b417cb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 9 Nov 2018 15:59:56 +0100
Subject: [PATCH 1406/2207] NETMAP_REQ_REGISTER: warn on missing
 NR_ACCEPT_VNET_HDR

---
 sys/dev/netmap/netmap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index dada5a7e3..cf6b4bc01 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2473,6 +2473,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 				if (na->virt_hdr_len && !(req->nr_flags & NR_ACCEPT_VNET_HDR)) {
+					D("virt_hdr_len=%d, but application does "
+						"not accept it", na->virt_hdr_len);
 					error = EIO;
 					break;
 				}

From 527c1b60803ae54a4dd6a435ff1687384fd6cbf1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 10 Nov 2018 11:12:01 +0100
Subject: [PATCH 1407/2207] add a "null" port as a means of allocating netmap
 ifs/rings and buffers

A null port can be created by opening (NR_REQ_REGISTER) any port
with the new NR_REG_NULL mode. The port name will be ignored and
a new dummy port will be created, with at least a netmap_if and
as many netmap rings and buffers as requested (even zero).
The dummy port makes no use of any of its resources, so these can
be uses by other ports.

These are the intended uses:
- allow ptnet to correctly emulate host rings for passed-through
  ports; even if the passed through port does not support the
  host rings, a ptnet-aware hypervisor can open a null port with
  a couple of rings, and use those to emulate the guest-visible
  host rings
- allow ptnet to allocate other ports (e.g., pipes) in the
  passed through memory region: the guest ptnet-allocator forwards
  the allocation request to the ptnet-aware hypervisor, which
  registers a null port in the host and passes the netmap if
  offset back to the guest
- overcome the register-time-only limitation for the allocation
  of the extra buffers: additional buffers can be allocated by
  registering a null port; notie, however, that de-allocation can
  still only be achieved by closing a port (null or otherwise)
---
 LINUX/Kbuild.in              |   1 +
 LINUX/configure              |   3 +-
 sys/dev/netmap/netmap.c      |  16 +--
 sys/dev/netmap/netmap_kern.h |  19 ++++
 sys/dev/netmap/netmap_null.c | 182 +++++++++++++++++++++++++++++++++++
 sys/net/netmap.h             |   1 +
 utils/GNUmakefile            |   2 +-
 utils/ctrl-api-test.c        |  61 ++++++++++++
 8 files changed, 277 insertions(+), 8 deletions(-)
 create mode 100644 sys/dev/netmap/netmap_null.c

diff --git a/LINUX/Kbuild.in b/LINUX/Kbuild.in
index 0910ebaec..4d0bf7802 100644
--- a/LINUX/Kbuild.in
+++ b/LINUX/Kbuild.in
@@ -14,6 +14,7 @@ remoteobjs-$(CONFIG_NETMAP_VALE)    += netmap_vale.o netmap_offloadings.o
 remoteobjs-$(CONFIG_NETMAP_PIPE)    += netmap_pipe.o
 remoteobjs-$(CONFIG_NETMAP_MONITOR) += netmap_monitor.o
 remoteobjs-$(CONFIG_NETMAP_GENERIC) += netmap_generic.o
+remoteobjs-$(CONFIG_NETMAP_NULL)    += netmap_null.o
 
 define remote_template
 $$(obj)/$(1): %.o: $$(SRCDIR)/../sys/dev/netmap/$(2) FORCE
diff --git a/LINUX/configure b/LINUX/configure
index 67db2bb96..76b6db441 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -95,7 +95,7 @@ setop()
 
 # available subsystems
 subsystem_avail="vale pipe monitor generic ptnetmap sink \
-	extmem"
+	extmem null"
 #enabled subsystems (bitfield)
 subsystem=0
 
@@ -108,6 +108,7 @@ subsys enable vale
 subsys enable pipe
 subsys enable monitor
 subsys enable generic
+subsys enable null
 
 # available drivers
 driver_avail="r8169.c virtio_net.c forcedeth.c veth.c \
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index cf6b4bc01..f9971f67c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1512,6 +1512,9 @@ netmap_get_na(struct nmreq_header *hdr,
 	 *   0	  !NULL		type matches and na created/found
 	 *  !0    !NULL		impossible
 	 */
+	error = netmap_get_null_na(hdr, na, nmd, create);
+	if (error || *na != NULL)
+		goto out;
 
 	/* try to see if this is a monitor port */
 	error = netmap_get_monitor_na(hdr, na, nmd, create);
@@ -1797,6 +1800,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 		}
 		switch (nr_mode) {
 		case NR_REG_ALL_NIC:
+		case NR_REG_NULL:
 			priv->np_qfirst[t] = 0;
 			priv->np_qlast[t] = nma_get_nrings(na, t);
 			ND("ALL/PIPE: %s %d %d", nm_txrx2str(t),
@@ -3497,12 +3501,6 @@ netmap_notify(struct netmap_kring *kring, int flags)
 int
 netmap_attach_common(struct netmap_adapter *na)
 {
-	if (na->num_tx_rings == 0 || na->num_rx_rings == 0) {
-		D("%s: invalid rings tx %d rx %d",
-			na->name, na->num_tx_rings, na->num_rx_rings);
-		return EINVAL;
-	}
-
 	if (!na->rx_buf_maxsize) {
 		/* Set a conservative default (larger is safer). */
 		na->rx_buf_maxsize = PAGE_SIZE;
@@ -3612,6 +3610,12 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 	if (arg == NULL || arg->ifp == NULL)
 		return EINVAL;
 
+	if (arg->num_tx_rings == 0 || arg->num_rx_rings == 0) {
+		D("%s: invalid rings tx %d rx %d",
+			arg->name, arg->num_tx_rings, arg->num_rx_rings);
+		return EINVAL;
+	}
+
 	ifp = arg->ifp;
 	if (NM_NA_CLASH(ifp)) {
 		/* If NA(ifp) is not null but there is no valid netmap
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 3bbe60513..4977ce483 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -58,12 +58,16 @@
 #if defined(CONFIG_NETMAP_SINK)
 #define WITH_SINK
 #endif
+#if defined(CONFIG_NETMAP_NULL)
+#define WITH_NMNULL
+#endif
 
 #elif defined (_WIN32)
 #define WITH_VALE	// comment out to disable VALE support
 #define WITH_PIPES
 #define WITH_MONITOR
 #define WITH_GENERIC
+#define WITH_NMNULL
 
 #else	/* neither linux nor windows */
 #define WITH_VALE	// comment out to disable VALE support
@@ -72,6 +76,7 @@
 #define WITH_GENERIC
 #define WITH_PTNETMAP	/* ptnetmap guest support */
 #define WITH_EXTMEM
+#define WITH_NMNULL
 #endif
 
 #if defined(__FreeBSD__)
@@ -1109,6 +1114,12 @@ struct netmap_pipe_adapter {
 
 #endif /* WITH_PIPES */
 
+#ifdef WITH_NMNULL
+struct netmap_null_adapter {
+	struct netmap_adapter up;
+};
+#endif /* WITH_NMNULL */
+
 
 /* return slots reserved to rx clients; used in drivers */
 static inline uint32_t
@@ -1476,6 +1487,14 @@ void netmap_monitor_stop(struct netmap_adapter *na);
 	(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
 #endif
 
+#ifdef WITH_NMNULL
+int netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create);
+#else /* !WITH_NMNULL */
+#define netmap_get_null_na(hdr, _2, _3, _4) \
+	(((struct nmreq_register *)(uintptr_t)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
+#endif /* WITH_NMNULL */
+
 #ifdef CONFIG_NET_NS
 struct net *netmap_bns_get(void);
 void netmap_bns_put(struct net *);
diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
new file mode 100644
index 000000000..84746dbb7
--- /dev/null
+++ b/sys/dev/netmap/netmap_null.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2018 Giuseppe Lettieri
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(__FreeBSD__)
+#include  /* prerequisite */
+
+#include 
+#include 
+#include 	/* defines used in kernel.h */
+#include 	/* types used in module initialization */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include  /* sockaddrs */
+#include 
+#include 
+#include 	/* bus_dmamap_* */
+#include 
+
+
+#elif defined(linux)
+
+#include "bsd_glue.h"
+
+#elif defined(__APPLE__)
+
+#warning OSX support is only partial
+#include "osx_glue.h"
+
+#elif defined(_WIN32)
+#include "win_glue.h"
+
+#else
+
+#error	Unsupported platform
+
+#endif /* unsupported */
+
+/*
+ * common headers
+ */
+
+#include 
+#include 
+#include 
+
+#ifdef WITH_NMNULL
+
+static int
+netmap_null_txsync(struct netmap_kring *kring, int flags)
+{
+	(void)kring;
+	(void)flags;
+	return 0;
+}
+
+static int
+netmap_null_rxsync(struct netmap_kring *kring, int flags)
+{
+	(void)kring;
+	(void)flags;
+	return 0;
+}
+
+static int
+netmap_null_krings_create(struct netmap_adapter *na)
+{
+	return netmap_krings_create(na, 0);
+}
+
+static void
+netmap_null_krings_delete(struct netmap_adapter *na)
+{
+	netmap_krings_delete(na);
+}
+
+static int
+netmap_null_reg(struct netmap_adapter *na, int onoff)
+{
+	if (na->active_fds == 0) {
+		if (onoff)
+			na->na_flags |= NAF_NETMAP_ON;
+		else
+			na->na_flags &= ~NAF_NETMAP_ON;
+	}
+	return 0;
+}
+
+static int
+netmap_null_bdg_attach(const char *name, struct netmap_adapter *na,
+		struct nm_bridge *b)
+{
+	(void)name;
+	(void)na;
+	(void)b;
+	return EINVAL;
+}
+
+int
+netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
+		struct netmap_mem_d *nmd, int create)
+{
+	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
+	struct netmap_null_adapter *nna;
+	int error;
+
+	if (req->nr_mode != NR_REG_NULL) {
+		D("not a null port");
+		return 0;
+	}
+
+	if (!create) {
+		D("null ports cannot be re-opened");
+		return EINVAL;
+	}
+
+	if (nmd == NULL) {
+		D("null ports must use an existing allocator");
+		return EINVAL;
+	}
+
+	nna = nm_os_malloc(sizeof(*nna));
+	if (nna == NULL) {
+		error = ENOMEM;
+		goto err;
+	}
+	snprintf(nna->up.name, sizeof(nna->up.name), "null:%s", hdr->nr_name);
+
+	nna->up.nm_txsync = netmap_null_txsync;
+	nna->up.nm_rxsync = netmap_null_rxsync;
+	nna->up.nm_register = netmap_null_reg;
+	nna->up.nm_krings_create = netmap_null_krings_create;
+	nna->up.nm_krings_delete = netmap_null_krings_delete;
+	nna->up.nm_bdg_attach = netmap_null_bdg_attach;
+	nna->up.nm_mem = netmap_mem_get(nmd);
+
+	nna->up.num_tx_rings = req->nr_tx_rings;
+	nna->up.num_rx_rings = req->nr_rx_rings;
+	nna->up.num_tx_desc = req->nr_tx_slots;
+	nna->up.num_rx_desc = req->nr_rx_slots;
+	error = netmap_attach_common(&nna->up);
+	if (error)
+		goto free_nna;
+	*na = &nna->up;
+	D("created null %s", nna->up.name);
+
+	return 0;
+
+free_nna:
+	nm_os_free(nna);
+err:
+	return error;
+}
+
+
+#endif /* WITH_NMNULL */
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 86f395ae5..460c6194d 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -595,6 +595,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 	NR_REG_ONE_NIC	= 4,
 	NR_REG_PIPE_MASTER = 5, /* deprecated, use "x{y" port name syntax */
 	NR_REG_PIPE_SLAVE = 6,  /* deprecated, use "x}y" port name syntax */
+	NR_REG_NULL     = 7,
 };
 
 /* A single ioctl number is shared by all the new API command.
diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index b17fe1e82..4a28f6572 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -12,7 +12,7 @@ VPATH   = $(SRCDIR)/utils
 
 NO_MAN=
 CFLAGS  = -O2 -pipe
-CFLAGS += -Werror -Wall -Wunused-function -fsanitize=address
+CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys # -I/home/luigi/FreeBSD/head/sys -I../sys
 CFLAGS += -Wextra -g
 CFLAGS += $(SUBSYS_FLAGS)
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 2a1741b60..2b417c3fe 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1277,6 +1277,64 @@ sync_kloop_eventfds_mismatch(struct TestContext *ctx)
 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
 }
 
+static int
+null_port(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mem_id = 1;
+	ctx->nr_mode = NR_REG_NULL;
+	ctx->nr_tx_rings = 10;
+	ctx->nr_rx_rings = 5;
+	ctx->nr_tx_slots = 256;
+	ctx->nr_rx_slots = 100;
+	ret = port_register(ctx);
+	if (ret) {
+		return ret;
+	}
+	return 0;
+}
+
+static int
+null_port_all_zero(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mem_id = 1;
+	ctx->nr_mode = NR_REG_NULL;
+	ctx->nr_tx_rings = 0;
+	ctx->nr_rx_rings = 0;
+	ctx->nr_tx_slots = 0;
+	ctx->nr_rx_slots = 0;
+	ret = port_register(ctx);
+	if (ret) {
+		return ret;
+	}
+	return 0;
+}
+
+static int
+null_port_sync(struct TestContext *ctx)
+{
+	int ret;
+
+	ctx->nr_mem_id = 1;
+	ctx->nr_mode = NR_REG_NULL;
+	ctx->nr_tx_rings = 10;
+	ctx->nr_rx_rings = 5;
+	ctx->nr_tx_slots = 256;
+	ctx->nr_rx_slots = 100;
+	ret = port_register(ctx);
+	if (ret) {
+		return ret;
+	}
+	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
+	if (ret) {
+		return ret;
+	}
+	return 0;
+}
+
 static void
 usage(const char *prog)
 {
@@ -1329,6 +1387,9 @@ static struct mytest tests[] = {
 	decltest(sync_kloop_csb_enable),
 	decltest(sync_kloop_conflict),
 	decltest(sync_kloop_eventfds_mismatch),
+	decltest(null_port),
+	decltest(null_port_all_zero),
+	decltest(null_port_sync),
 };
 
 static void

From 110a07a98e8be0b6bb9c16d16bfb03c003123cb1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 13 Nov 2018 10:21:38 +0100
Subject: [PATCH 1408/2207] linux/i40e: patch for Intel 2.7.11 version

---
 LINUX/final-patches/intel--i40e--2.7.11 | 167 ++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.7.11

diff --git a/LINUX/final-patches/intel--i40e--2.7.11 b/LINUX/final-patches/intel--i40e--2.7.11
new file mode 100644
index 000000000..dbb9b6d03
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.7.11
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index ba722c7..56fc6ac 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -27,14 +27,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -88,9 +88,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 86d76c0..5629a97 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -132,6 +132,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3442,6 +3447,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3495,6 +3504,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3523,6 +3536,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13429,6 +13447,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13801,6 +13824,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 1859d78..ea1be59 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -783,6 +787,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From b26cbf5639c1c5ef6255aa78fa97530a825d8549 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 13 Nov 2018 10:36:18 +0100
Subject: [PATCH 1409/2207] linux/i40e: patch for Intel 2.7.12 version

---
 LINUX/final-patches/intel--i40e--2.7.12 | 167 ++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.7.12

diff --git a/LINUX/final-patches/intel--i40e--2.7.12 b/LINUX/final-patches/intel--i40e--2.7.12
new file mode 100644
index 000000000..8d8cd2530
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.7.12
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index ba722c7..56fc6ac 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -27,14 +27,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -88,9 +88,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 6f8e9b4..a62aadd 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -132,6 +132,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3442,6 +3447,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3495,6 +3504,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3523,6 +3536,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13432,6 +13450,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13804,6 +13827,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 1859d78..ea1be59 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -783,6 +787,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 44089af1a634c34bce215f3afcf6caca665e7459 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 13 Nov 2018 14:46:12 +0100
Subject: [PATCH 1410/2207] Remove redundant redeclaration of netmap_vp_reg()

Submitted by: bz@FreeBSD.org
---
 sys/dev/netmap/netmap_bdg.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 8d0c3b579..e6811dac2 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -175,7 +175,6 @@ struct nm_bridge *nm_find_bridge(const char *name, int create, struct netmap_bdg
 int netmap_bdg_free(struct nm_bridge *b);
 void netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw);
 int netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na);
-int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
 int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_vp_rxsync(struct netmap_kring *kring, int flags);

From 2e29063093696278d9fcd1c8ef013937d744eba6 Mon Sep 17 00:00:00 2001
From: Joshua Raiff 
Date: Tue, 13 Nov 2018 09:49:42 -0500
Subject: [PATCH 1411/2207] netmap_vale_attach can leak memory references

If netmap_vale_attach() is called with a memory region, it
will leak a reference to that region.  Make sure to do a
netmap_mem_put in this case.  Fixed issue 559
---
 sys/dev/netmap/netmap_vale.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 13dda8d44..0c0ae136e 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -447,12 +447,19 @@ netmap_vale_attach(struct nmreq_header *hdr, void *auth_token)
 	}
 	vpna = (struct netmap_vp_adapter *)na;
 	req->port_index = vpna->bdg_port;
+
+	if (nmd)
+		netmap_mem_put(nmd);
+
 	NMG_UNLOCK();
 	return 0;
 
 unref_exit:
 	netmap_adapter_put(na);
 unlock_exit:
+	if (nmd)
+		netmap_mem_put(nmd);
+
 	NMG_UNLOCK();
 	return error;
 }

From ba9d7ef783c3f20a15aa0472307517744ce97af2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 14 Nov 2018 12:07:19 +0100
Subject: [PATCH 1412/2207] netmap_null: disable verbose log

---
 sys/dev/netmap/netmap_null.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index 84746dbb7..c36c0f3cd 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -131,7 +131,7 @@ netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	int error;
 
 	if (req->nr_mode != NR_REG_NULL) {
-		D("not a null port");
+		ND("not a null port");
 		return 0;
 	}
 

From 4cb1968cf48011316ba051c52cbd7d95f3654435 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 14 Nov 2018 17:05:57 +0100
Subject: [PATCH 1413/2207] linux/ixgbe: clear the heads on nic reset

---
 LINUX/ixgbe_netmap_linux.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 59474086b..9774f238a 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -650,6 +650,7 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	struct ixgbe_hw *hw = &adapter->hw;
 	struct netmap_ixgbe_adapter *ina = (struct netmap_ixgbe_adapter *)na;
 	u64 wba;
+	struct netmap_ixgbe_head *h;
 #endif /* !NM_IXGBE_USE_TDH */
 
 	slot = netmap_reset(na, NR_TX, ring_nr, 0);
@@ -664,6 +665,9 @@ ixgbe_netmap_configure_tx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr, u3
 	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAL(ring_nr),
 		(wba & DMA_BIT_MASK(32)) | IXGBE_TDWBAL_HEAD_WB_ENABLE);
 	IXGBE_WRITE_REG(hw, NM_IXGBE_TDWBAH(ring_nr), wba >> 32);
+	/* reset all heads */
+	h = &ina->heads[ring_nr];
+	*h->phead = 0;
 #endif /* !NM_IXGBE_USE_TDH */
 
 #if 0

From ff1a92d8f4fad75e37a11b51a243d1c6d0914704 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 16 Nov 2018 18:14:21 +0100
Subject: [PATCH 1414/2207] freebsd: set IFCAP_NETMAP in if_capabilities

---
 sys/dev/netmap/netmap_freebsd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 5d8182865..2000f31dd 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1482,6 +1482,7 @@ freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
 void
 nm_os_onattach(struct ifnet *ifp)
 {
+	ifp->if_capabilities |= IFCAP_NETMAP;
 }
 
 void

From 1209c44ee2c03a85c6b6761e239726ba6c9bd535 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 10:49:59 +0100
Subject: [PATCH 1415/2207] utils: add test for legacy ABI, small fix in legacy
 support

---
 sys/dev/netmap/netmap_legacy.c |  7 ++--
 utils/ctrl-api-test.c          | 76 ++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index c36fc8403..93022021d 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -77,10 +77,11 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
 		} else {
 			regmode = NR_REG_ALL_NIC;
 		}
-		nmr->nr_flags = regmode |
-			(nmr->nr_flags & (~NR_REG_MASK));
+		req->nr_mode = regmode;
+	} else {
+		req->nr_mode = nmr->nr_flags & NR_REG_MASK;
 	}
-	req->nr_mode = nmr->nr_flags & NR_REG_MASK;
+
 	/* Fix nr_name, nr_mode and nr_ringid to handle pipe requests. */
 	if (req->nr_mode == NR_REG_PIPE_MASTER ||
 			req->nr_mode == NR_REG_PIPE_SLAVE) {
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 2b417c3fe..a1a2a34f9 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -183,6 +183,81 @@ port_register(struct TestContext *ctx)
 	return -0;
 }
 
+static int
+niocregif(struct TestContext *ctx, int netmap_api)
+{
+	struct nmreq req;
+	int success;
+	int ret;
+
+	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname);
+
+	memset(&req, 0, sizeof(req));
+	strncpy(req.nr_name, ctx->ifname, sizeof(req.nr_name)-1);
+	req.nr_version = netmap_api;
+	req.nr_ringid     = ctx->nr_ringid;
+	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
+	req.nr_tx_slots   = ctx->nr_tx_slots;
+	req.nr_rx_slots   = ctx->nr_rx_slots;
+	req.nr_tx_rings   = ctx->nr_tx_rings;
+	req.nr_rx_rings   = ctx->nr_rx_rings;
+	req.nr_arg2     = ctx->nr_mem_id;
+	req.nr_arg3 = ctx->nr_extra_bufs;
+
+	ret = ioctl(ctx->fd, NIOCREGIF, &req);
+	if (ret) {
+		perror("ioctl(/dev/netmap, NIOCREGIF)");
+		return ret;
+	}
+
+	printf("nr_offset 0x%x\n", req.nr_offset);
+	printf("nr_memsize %u\n", req.nr_memsize);
+	printf("nr_tx_slots %u\n", req.nr_tx_slots);
+	printf("nr_rx_slots %u\n", req.nr_rx_slots);
+	printf("nr_tx_rings %u\n", req.nr_tx_rings);
+	printf("nr_rx_rings %u\n", req.nr_rx_rings);
+	printf("nr_ringid %x\n", req.nr_ringid);
+	printf("nr_flags %x\n", req.nr_flags);
+	printf("nr_arg2 %u\n", req.nr_arg2);
+	printf("nr_arg3 %u\n", req.nr_arg3);
+
+	success = req.nr_memsize &&
+	       (ctx->nr_ringid == req.nr_ringid) &&
+	       ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
+	       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+		(ctx->nr_tx_slots == req.nr_tx_slots)) &&
+	       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+		(ctx->nr_rx_slots == req.nr_rx_slots)) &&
+	       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+		(ctx->nr_tx_rings == req.nr_tx_rings)) &&
+	       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+		(ctx->nr_rx_rings == req.nr_rx_rings)) &&
+	       ((!ctx->nr_mem_id && req.nr_arg2) ||
+		(ctx->nr_mem_id == req.nr_arg2)) &&
+	       (ctx->nr_extra_bufs == req.nr_arg3);
+	if (!success) {
+		return -1;
+	}
+
+	/* Write back results to the context structure.*/
+	ctx->nr_tx_slots   = req.nr_tx_slots;
+	ctx->nr_rx_slots   = req.nr_rx_slots;
+	ctx->nr_tx_rings   = req.nr_tx_rings;
+	ctx->nr_rx_rings   = req.nr_rx_rings;
+	ctx->nr_mem_id     = req.nr_arg2;
+	ctx->nr_extra_bufs = req.nr_arg3;
+
+	return ret;
+}
+
+static int
+legacy_regif(struct TestContext *ctx)
+{
+	/* Use the 11 API, which is the one right before the introduction
+	 * of the new NIOCCTRL API. */
+	return niocregif(ctx, 11);
+}
+
 /* Only valid after a successful port_register(). */
 static int
 num_registered_rings(struct TestContext *ctx)
@@ -1390,6 +1465,7 @@ static struct mytest tests[] = {
 	decltest(null_port),
 	decltest(null_port_all_zero),
 	decltest(null_port_sync),
+	decltest(legacy_regif),
 };
 
 static void

From 150fed41144c60c873d5b2773286ec626b7e02d2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 10:59:40 +0100
Subject: [PATCH 1416/2207] utils: ctrl-api-test: add more tests for the legacy
 ABI

---
 utils/ctrl-api-test.c | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a1a2a34f9..df5c0d618 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -250,12 +250,28 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	return ret;
 }
 
+/* Use the 11 API, which is the one right before the introduction
+ * of the new NIOCCTRL API. */
+#define NETMAP_API_NIOCREGIF	11
+
+static int
+legacy_regif_default(struct TestContext *ctx)
+{
+	return niocregif(ctx, NETMAP_API_NIOCREGIF);
+}
+
 static int
-legacy_regif(struct TestContext *ctx)
+legacy_regif_all_nic(struct TestContext *ctx)
 {
-	/* Use the 11 API, which is the one right before the introduction
-	 * of the new NIOCCTRL API. */
-	return niocregif(ctx, 11);
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	return niocregif(ctx, NETMAP_API);
+}
+
+static int
+legacy_regif_sw(struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_SW;
+	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
 }
 
 /* Only valid after a successful port_register(). */
@@ -1465,7 +1481,9 @@ static struct mytest tests[] = {
 	decltest(null_port),
 	decltest(null_port_all_zero),
 	decltest(null_port_sync),
-	decltest(legacy_regif),
+	decltest(legacy_regif_default),
+	decltest(legacy_regif_all_nic),
+	decltest(legacy_regif_sw),
 };
 
 static void

From f724f7b5d5790f3496e8536b63f659a02bbbcff2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 11:27:05 +0100
Subject: [PATCH 1417/2207] utils: ctrl-api-test: add forward compatibility
 test

---
 utils/ctrl-api-test.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index df5c0d618..cf5a65aa4 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -211,15 +211,16 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	}
 
 	printf("nr_offset 0x%x\n", req.nr_offset);
-	printf("nr_memsize %u\n", req.nr_memsize);
+	printf("nr_memsize  %u\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
-	printf("nr_ringid %x\n", req.nr_ringid);
-	printf("nr_flags %x\n", req.nr_flags);
-	printf("nr_arg2 %u\n", req.nr_arg2);
-	printf("nr_arg3 %u\n", req.nr_arg3);
+	printf("nr_version  %d\n", req.nr_version);
+	printf("nr_ringid   %x\n", req.nr_ringid);
+	printf("nr_flags    %x\n", req.nr_flags);
+	printf("nr_arg2     %u\n", req.nr_arg2);
+	printf("nr_arg3     %u\n", req.nr_arg3);
 
 	success = req.nr_memsize &&
 	       (ctx->nr_ringid == req.nr_ringid) &&
@@ -250,8 +251,9 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	return ret;
 }
 
-/* Use the 11 API, which is the one right before the introduction
- * of the new NIOCCTRL API. */
+/* The 11 ABI is the one right before the introduction of the new NIOCCTRL
+ * ABI. The 11 ABI is useful to perform tests with legacy applications
+ * (which use the 11 ABI) and new kernel (which uses 12, or higher). */
 #define NETMAP_API_NIOCREGIF	11
 
 static int
@@ -274,6 +276,16 @@ legacy_regif_sw(struct TestContext *ctx)
 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
 }
 
+static int
+legacy_regif_future(struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_NIC_SW;
+	/* Test forward compatibility for the legacy ABI. This means
+	 * using an older kernel (with ABI 12 or higher) and a newer
+	 * application (with ABI greater than NETMAP_API). */
+	return niocregif(ctx, NETMAP_API+2);
+}
+
 /* Only valid after a successful port_register(). */
 static int
 num_registered_rings(struct TestContext *ctx)
@@ -1484,6 +1496,7 @@ static struct mytest tests[] = {
 	decltest(legacy_regif_default),
 	decltest(legacy_regif_all_nic),
 	decltest(legacy_regif_sw),
+	decltest(legacy_regif_future),
 };
 
 static void

From 0a23b96cb8bce112461bd017647eb4cc018b0661 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 11:30:43 +0100
Subject: [PATCH 1418/2207] utils: ctrl-api-test: add test for ABI version 12

---
 utils/ctrl-api-test.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index cf5a65aa4..8511a3708 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -269,6 +269,13 @@ legacy_regif_all_nic(struct TestContext *ctx)
 	return niocregif(ctx, NETMAP_API);
 }
 
+static int
+legacy_regif_12(struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
+}
+
 static int
 legacy_regif_sw(struct TestContext *ctx)
 {
@@ -1495,6 +1502,7 @@ static struct mytest tests[] = {
 	decltest(null_port_sync),
 	decltest(legacy_regif_default),
 	decltest(legacy_regif_all_nic),
+	decltest(legacy_regif_12),
 	decltest(legacy_regif_sw),
 	decltest(legacy_regif_future),
 };

From b6c33e81c6aa5a69fdcb06423f85a497a2e5705e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 11:37:10 +0100
Subject: [PATCH 1419/2207] freebsd: update Makefile for netmap_null and add
 $FreeBSD$ string

---
 sys/dev/netmap/netmap_null.c | 1 +
 sys/modules/netmap/Makefile  | 1 +
 2 files changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index c36c0f3cd..6197ca5c4 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -23,6 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/* $FreeBSD$ */
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index a6f405d3f..8d0b35811 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -23,6 +23,7 @@ SRCS	+= netmap_monitor.c
 SRCS	+= netmap_kloop.c
 SRCS	+= netmap_legacy.c
 SRCS	+= netmap_bdg.c
+SRCS	+= netmap_null.c
 SRCS	+= if_ptnet.c
 SRCS	+= opt_inet.h opt_inet6.h
 

From a39fa8e6bb42f872b35c21757871af78e06e9b50 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 11:56:56 +0100
Subject: [PATCH 1420/2207] import license identifier (SPDX) from FreeBSD

---
 sys/dev/netmap/if_em_netmap.h       | 4 +++-
 sys/dev/netmap/if_igb_netmap.h      | 4 +++-
 sys/dev/netmap/if_ixl_netmap.h      | 4 +++-
 sys/dev/netmap/if_lem_netmap.h      | 4 +++-
 sys/dev/netmap/if_re_netmap.h       | 4 +++-
 sys/dev/netmap/netmap.c             | 4 +++-
 sys/dev/netmap/netmap_bdg.c         | 4 +++-
 sys/dev/netmap/netmap_bdg.h         | 4 +++-
 sys/dev/netmap/netmap_freebsd.c     | 4 +++-
 sys/dev/netmap/netmap_generic.c     | 4 +++-
 sys/dev/netmap/netmap_kern.h        | 4 +++-
 sys/dev/netmap/netmap_legacy.c      | 4 +++-
 sys/dev/netmap/netmap_mbq.c         | 4 +++-
 sys/dev/netmap/netmap_mbq.h         | 4 +++-
 sys/dev/netmap/netmap_mem2.c        | 4 +++-
 sys/dev/netmap/netmap_mem2.h        | 4 +++-
 sys/dev/netmap/netmap_offloadings.c | 4 +++-
 sys/dev/netmap/netmap_pipe.c        | 4 +++-
 sys/dev/netmap/netmap_vale.c        | 4 +++-
 sys/net/netmap.h                    | 4 +++-
 sys/net/netmap_legacy.h             | 4 +++-
 sys/net/netmap_user.h               | 4 +++-
 22 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index bf3d432c3..01a7a2971 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index 4d2a1f9a9..b9f8f47b2 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h
index 48369aa02..db7573c34 100644
--- a/sys/dev/netmap/if_ixl_netmap.h
+++ b/sys/dev/netmap/if_ixl_netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2015, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index cd87dd483..edbc666ea 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index c48b77b7e..2d3352353 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f9971f67c..9e5340ea6 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi
  * Copyright (C) 2011-2016 Luigi Rizzo
  * Copyright (C) 2011-2016 Giuseppe Lettieri
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index bcb4097ed..da832161e 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2016 Universita` di Pisa
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index e6811dac2..e4683885e 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2018 Universita` di Pisa
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 2000f31dd..70d2ee443 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index d17c0c440..e4e158b44 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2016 Vincenzo Maffione
  * Copyright (C) 2013-2016 Luigi Rizzo
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4977ce483..a574efed4 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo
  * Copyright (C) 2013-2016 Universita` di Pisa
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 93022021d..dae125e23 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2018 Vincenzo Maffione
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_mbq.c b/sys/dev/netmap/netmap_mbq.c
index 3eb971b74..3ce73f0e0 100644
--- a/sys/dev/netmap/netmap_mbq.c
+++ b/sys/dev/netmap/netmap_mbq.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2014 Vincenzo Maffione
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_mbq.h b/sys/dev/netmap/netmap_mbq.h
index 8ba0947b5..044cb54bb 100644
--- a/sys/dev/netmap/netmap_mbq.h
+++ b/sys/dev/netmap/netmap_mbq.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2014 Vincenzo Maffione
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 4edac9656..841121618 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2014 Matteo Landi
  * Copyright (C) 2012-2016 Luigi Rizzo
  * Copyright (C) 2012-2016 Giuseppe Lettieri
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 9268024c6..8c4bf256f 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2014 Matteo Landi
  * Copyright (C) 2012-2016 Luigi Rizzo
  * Copyright (C) 2012-2016 Giuseppe Lettieri
diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index d16ca1e85..688e0d674 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2014-2015 Vincenzo Maffione
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 51b4f1616..92653b7d6 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2014-2018 Giuseppe Lettieri
  * All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 0c0ae136e..b7b1d2bcf 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2013-2016 Universita` di Pisa
  * All rights reserved.
  *
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 460c6194d..3376509ad 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index c3289093b..041c71a80 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index adf9d0b8c..6d52428bd 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2016 Universita` di Pisa
  * All rights reserved.
  *

From afa26bc3bc4163454da3ad5c3647eed494bc46a2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 12:02:06 +0100
Subject: [PATCH 1421/2207] small fixes related to FreeBSD SPDX declaration

---
 sys/dev/netmap/if_ixl_netmap.h | 4 +---
 sys/dev/netmap/ixgbe_netmap.h  | 4 +++-
 sys/dev/netmap/netmap_bdg.c    | 4 +---
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h
index db7573c34..48369aa02 100644
--- a/sys/dev/netmap/if_ixl_netmap.h
+++ b/sys/dev/netmap/if_ixl_netmap.h
@@ -1,6 +1,4 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
- *
+/*
  * Copyright (C) 2015, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h
index 2a581b490..c57adba71 100644
--- a/sys/dev/netmap/ixgbe_netmap.h
+++ b/sys/dev/netmap/ixgbe_netmap.h
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index da832161e..bcb4097ed 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1,6 +1,4 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
- *
+/*
  * Copyright (C) 2013-2016 Universita` di Pisa
  * All rights reserved.
  *

From c7c3da22181237679aa80d4bc721ce3ccd70ae94 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 14:46:35 +0100
Subject: [PATCH 1422/2207] netmap_legacy.h: add missing $FreeBSD$ string

---
 sys/net/netmap_legacy.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 041c71a80..c7b0dffde 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -30,6 +30,8 @@
 #define _NET_NETMAP_LEGACY_H_
 
 /*
+ * $FreeBSD$
+ *
  * ioctl names and related fields
  *
  * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,

From 31a29bcf4ba5065ed0911c57789c7cc74ca8dfc2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 14:49:37 +0100
Subject: [PATCH 1423/2207] netmap_legacy.c: add missing $FreeBSD$ string

---
 sys/dev/netmap/netmap_legacy.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index dae125e23..e4485c9b8 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+/* $FreeBSD$ */
+
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 #include 

From 88ad54aa8d82b33334cae42090a270aa63ff189c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 14:53:39 +0100
Subject: [PATCH 1424/2207] freebsd: vtnet: fix netmap support

netmap(4) support for vtnet(4) was incomplete and had multiple bugs.
This commit fixes those bugs to bring netmap on vtnet in a functional state.

Changelist:
  - handle errors returned by virtqueue_enqueue() properly (they were
    previously ignored)
  - make sure netmap XOR rest of the kernel access each virtqueue.
  - compute the number of netmap slots for TX and RX separately, according to
    whether indirect descriptors are used or not for a given virtqueue.
  - make sure sglist are freed according to their type (mbufs or netmap
    buffers)
  - add support for mulitiqueue and netmap host (aka sw) rings.
  - intercept VQ interrupts directly instead of intercepting them in txq_eof
    and rxq_eof. This simplifies the code and makes it easier to make sure
    taskqueues are not running for a VQ while it is in netmap mode.
  - implement vntet_netmap_config() to cope with changes in the number of queues.
---
 sys/dev/netmap/if_vtnet_netmap.h | 526 +++++++++++++++++++------------
 1 file changed, 317 insertions(+), 209 deletions(-)

diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index e78cf0ee2..acb58f140 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Vincenzo Maffione, Luigi Rizzo. All rights reserved.
+ * Copyright (C) 2014-2018 Vincenzo Maffione, Luigi Rizzo.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -24,7 +24,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_vtnet_netmap.h 270097 2014-08-17 10:25:27Z luigi $
+ * $FreeBSD: head/sys/dev/netmap/if_vtnet_netmap.h 340436 2018-11-14 15:39:48Z vmaffione $
  */
 
 #include 
@@ -33,74 +33,148 @@
 #include     /* vtophys ? */
 #include 
 
+/*
+ * Return 1 if the queue identified by 't' and 'idx' is in netmap mode.
+ */
+static int
+vtnet_netmap_queue_on(struct vtnet_softc *sc, enum txrx t, int idx)
+{
+	struct netmap_adapter *na = NA(sc->vtnet_ifp);
 
-#define SOFTC_T	vtnet_softc
+	if (!nm_native_on(na))
+		return 0;
+
+	if (t == NR_RX)
+		return !!(idx < na->num_rx_rings &&
+			na->rx_rings[idx]->nr_mode == NKR_NETMAP_ON);
+
+	return !!(idx < na->num_tx_rings &&
+		na->tx_rings[idx]->nr_mode == NKR_NETMAP_ON);
+}
 
-/* Free all the unused buffer in all the RX virtqueues.
- * This function is called when entering and exiting netmap mode.
- * - buffers queued by the virtio driver return skbuf/mbuf pointer
- *   and need to be freed;
- * - buffers queued by netmap return the txq/rxq, and do not need work
- */
 static void
-vtnet_netmap_free_bufs(struct SOFTC_T* sc)
+vtnet_free_used(struct virtqueue *vq, int netmap_bufs, enum txrx t, int idx)
 {
-	int i, nmb = 0, n = 0, last;
+	void *cookie;
+	int deq = 0;
 
-	for (i = 0; i < sc->vtnet_max_vq_pairs; i++) {
-		struct vtnet_rxq *rxq = &sc->vtnet_rxqs[i];
-		struct virtqueue *vq;
-		struct mbuf *m;
-		struct vtnet_txq *txq = &sc->vtnet_txqs[i];
-                struct vtnet_tx_header *txhdr;
+	while ((cookie = virtqueue_dequeue(vq, NULL)) != NULL) {
+		if (netmap_bufs) {
+			/* These are netmap buffers: there is nothing to do. */
+		} else {
+			/* These are mbufs that we need to free. */
+			struct mbuf *m;
 
-		last = 0;
-		vq = rxq->vtnrx_vq;
-		while ((m = virtqueue_drain(vq, &last)) != NULL) {
-			n++;
-			if (m != (void *)rxq)
+			if (t == NR_TX) {
+				struct vtnet_tx_header *txhdr = cookie;
+				m = txhdr->vth_mbuf;
 				m_freem(m);
-			else
-				nmb++;
-		}
-
-		last = 0;
-		vq = txq->vtntx_vq;
-		while ((txhdr = virtqueue_drain(vq, &last)) != NULL) {
-			n++;
-			if (txhdr != (void *)txq) {
-				m_freem(txhdr->vth_mbuf);
 				uma_zfree(vtnet_tx_header_zone, txhdr);
-			} else
-				nmb++;
+			} else {
+				m = cookie;
+				m_freem(m);
+			}
 		}
+		deq++;
 	}
-	D("freed %d mbufs, %d netmap bufs on %d queues",
-		n - nmb, nmb, i);
+
+	if (deq)
+		nm_prinf("%d sgs dequeued from %s-%d (netmap=%d)\n",
+			 deq, nm_txrx2str(t), idx, netmap_bufs);
 }
 
 /* Register and unregister. */
 static int
-vtnet_netmap_reg(struct netmap_adapter *na, int onoff)
+vtnet_netmap_reg(struct netmap_adapter *na, int state)
 {
-        struct ifnet *ifp = na->ifp;
-	struct SOFTC_T *sc = ifp->if_softc;
+	struct ifnet *ifp = na->ifp;
+	struct vtnet_softc *sc = ifp->if_softc;
+	int success;
+	enum txrx t;
+	int i;
+
+	/* Drain the taskqueues to make sure that there are no worker threads
+	 * accessing the virtqueues. */
+	vtnet_drain_taskqueues(sc);
 
 	VTNET_CORE_LOCK(sc);
-	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-	/* enable or disable flags and callbacks in na and ifp */
-	if (onoff) {
+
+	/* We need nm_netmap_on() to return true when called by
+	 * vtnet_init_locked() below. */
+	if (state)
 		nm_set_native_flags(na);
+
+	/* We need to trigger a device reset in order to unexpose guest buffers
+	 * published to the host. */
+	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+	/* Get pending used buffers. The way they are freed depends on whether
+	 * they are netmap buffer or they are mbufs. We can tell apart the two
+	 * cases by looking at kring->nr_mode, before this is possibly updated
+	 * in the loop below. */
+	for (i = 0; i < sc->vtnet_act_vq_pairs; i++) {
+		struct vtnet_txq *txq = &sc->vtnet_txqs[i];
+		struct vtnet_rxq *rxq = &sc->vtnet_rxqs[i];
+		struct netmap_kring *kring;
+
+		VTNET_TXQ_LOCK(txq);
+		kring = NMR(na, NR_TX)[i];
+		vtnet_free_used(txq->vtntx_vq,
+				kring->nr_mode == NKR_NETMAP_ON, NR_TX, i);
+		VTNET_TXQ_UNLOCK(txq);
+
+		VTNET_RXQ_LOCK(rxq);
+		kring = NMR(na, NR_RX)[i];
+		vtnet_free_used(rxq->vtnrx_vq,
+				kring->nr_mode == NKR_NETMAP_ON, NR_RX, i);
+		VTNET_RXQ_UNLOCK(rxq);
+	}
+	vtnet_init_locked(sc);
+	success = (ifp->if_drv_flags & IFF_DRV_RUNNING) ? 0 : ENXIO;
+
+	if (state) {
+		for_rx_tx(t) {
+			/* Hardware rings. */
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+
+				if (nm_kring_pending_on(kring))
+					kring->nr_mode = NKR_NETMAP_ON;
+			}
+
+			/* Host rings. */
+			for (i = 0; i < nma_get_host_nrings(na, t); i++) {
+				struct netmap_kring *kring =
+					NMR(na, t)[nma_get_nrings(na, t) + i];
+
+				if (nm_kring_pending_on(kring))
+					kring->nr_mode = NKR_NETMAP_ON;
+			}
+		}
 	} else {
 		nm_clear_native_flags(na);
+		for_rx_tx(t) {
+			/* Hardware rings. */
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
+				struct netmap_kring *kring = NMR(na, t)[i];
+
+				if (nm_kring_pending_off(kring))
+					kring->nr_mode = NKR_NETMAP_OFF;
+			}
+
+			/* Host rings. */
+			for (i = 0; i < nma_get_host_nrings(na, t); i++) {
+				struct netmap_kring *kring =
+					NMR(na, t)[nma_get_nrings(na, t) + i];
+
+				if (nm_kring_pending_off(kring))
+					kring->nr_mode = NKR_NETMAP_OFF;
+			}
+		}
 	}
-	/* drain queues so netmap and native drivers
-	 * do not interfere with each other
-	 */
-	vtnet_netmap_free_bufs(sc);
-        vtnet_init_locked(sc);       /* also enable intr */
-        VTNET_CORE_UNLOCK(sc);
-        return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1);
+
+	VTNET_CORE_UNLOCK(sc);
+
+	return success;
 }
 
 
@@ -109,20 +183,19 @@ static int
 vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
-        struct ifnet *ifp = na->ifp;
+	struct ifnet *ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int nm_i;	/* index into the netmap ring */
-	u_int nic_i;	/* index into the NIC ring */
-	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 
 	/* device-specific */
-	struct SOFTC_T *sc = ifp->if_softc;
+	struct vtnet_softc *sc = ifp->if_softc;
 	struct vtnet_txq *txq = &sc->vtnet_txqs[ring_nr];
 	struct virtqueue *vq = txq->vtntx_vq;
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
+	u_int n;
 
 	/*
 	 * First part: process new packets to send.
@@ -133,15 +206,13 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (nm_i != head) {	/* we have new packets to send */
 		struct sglist *sg = txq->vtntx_sg;
 
-		nic_i = netmap_idx_k2n(kring, nm_i);
-		for (n = 0; nm_i != head; n++) {
+		for (; nm_i != head; nm_i = nm_next(nm_i, lim)) {
 			/* we use an empty header here */
-			static struct virtio_net_hdr_mrg_rxbuf hdr;
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
-                        int err;
+			int err;
 
 			NM_CHECK_ADDR_LEN(na, addr, len);
 
@@ -150,88 +221,63 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 			 * and kick the hypervisor (if necessary).
 			 */
 			sglist_reset(sg); // cheap
-			// if vtnet_hdr_size > 0 ...
-			err = sglist_append(sg, &hdr, sc->vtnet_hdr_size);
-			// XXX later, support multi segment
-			err = sglist_append_phys(sg, paddr, len);
-			/* use na as the cookie */
-                        err = virtqueue_enqueue(vq, txq, sg, sg->sg_nseg, 0);
-                        if (unlikely(err < 0)) {
-                                D("virtqueue_enqueue failed");
-                                break;
-                        }
-
-			nm_i = nm_next(nm_i, lim);
-			nic_i = nm_next(nic_i, lim);
+			err = sglist_append(sg, &txq->vtntx_shrhdr, sc->vtnet_hdr_size);
+			err |= sglist_append_phys(sg, paddr, len);
+			KASSERT(err == 0, ("%s: cannot append to sglist %d",
+						__func__, err));
+			err = virtqueue_enqueue(vq, /*cookie=*/txq, sg,
+						/*readable=*/sg->sg_nseg,
+						/*writeable=*/0);
+			if (unlikely(err)) {
+				if (err != ENOSPC)
+					nm_prerr("virtqueue_enqueue(%s) failed: %d\n",
+							kring->name, err);
+				break;
+			}
 		}
-		/* Update hwcur depending on where we stopped. */
-		kring->nr_hwcur = nm_i; /* note we migth break early */
 
-		/* No more free TX slots? Ask the hypervisor for notifications,
-		 * possibly only when a considerable amount of work has been
-		 * done.
-		 */
-		ND(3,"sent %d packets, hwcur %d", n, nm_i);
-		virtqueue_disable_intr(vq);
 		virtqueue_notify(vq);
-	} else {
-		if (ring->head != ring->tail)
-		    ND(5, "pure notify ? head %d tail %d nused %d %d",
-			ring->head, ring->tail, virtqueue_nused(vq),
-			(virtqueue_dump(vq), 1));
-		virtqueue_notify(vq);
-		if (interrupts) {
-			virtqueue_enable_intr(vq); // like postpone with 0
-		}
-	}
 
+		/* Update hwcur depending on where we stopped. */
+		kring->nr_hwcur = nm_i; /* note we migth break early */
+	}
 
-        /* Free used slots. We only consider our own used buffers, recognized
-	 * by the token we passed to virtqueue_add_outbuf.
+	/* Free used slots. We only consider our own used buffers, recognized
+	 * by the token we passed to virtqueue_enqueue.
 	 */
-        n = 0;
-        for (;;) {
-                struct vtnet_tx_header *txhdr = virtqueue_dequeue(vq, NULL);
-                if (txhdr == NULL)
-                        break;
-                if (likely(txhdr == (void *)txq)) {
-                        n++;
-			if (virtqueue_nused(vq) < 32) { // XXX slow release
-				break;
-			}
-		} else { /* leftover from previous transmission */
-			m_freem(txhdr->vth_mbuf);
-			uma_zfree(vtnet_tx_header_zone, txhdr);
-		}
-        }
-	if (n) {
+	n = 0;
+	for (;;) {
+		void *token = virtqueue_dequeue(vq, NULL);
+		if (token == NULL)
+			break;
+		if (unlikely(token != (void *)txq))
+			nm_prerr("BUG: TX token mismatch\n");
+		else
+			n++;
+	}
+	if (n > 0) {
 		kring->nr_hwtail += n;
 		if (kring->nr_hwtail > lim)
 			kring->nr_hwtail -= lim + 1;
 	}
-	if (nm_i != kring->nr_hwtail /* && vtnet_txq_below_threshold(txq) == 0*/) {
-		ND(3, "disable intr, hwcur %d", nm_i);
-		virtqueue_disable_intr(vq);
-	} else if (interrupts) {
-		ND(3, "enable intr, hwcur %d", nm_i);
-		virtqueue_postpone_intr(vq, VQ_POSTPONE_SHORT);
-	}
 
-        return 0;
+	if (interrupts && virtqueue_nfree(vq) < 32)
+		virtqueue_postpone_intr(vq, VQ_POSTPONE_LONG);
+
+	return 0;
 }
 
 static int
-vtnet_refill_rxq(struct netmap_kring *kring, u_int nm_i, u_int head)
+vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int nm_i, u_int head)
 {
 	struct netmap_adapter *na = kring->na;
-        struct ifnet *ifp = na->ifp;
+	struct ifnet *ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int const lim = kring->nkr_num_slots - 1;
-	u_int n;
 
 	/* device-specific */
-	struct SOFTC_T *sc = ifp->if_softc;
+	struct vtnet_softc *sc = ifp->if_softc;
 	struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr];
 	struct virtqueue *vq = rxq->vtnrx_vq;
 
@@ -239,12 +285,11 @@ vtnet_refill_rxq(struct netmap_kring *kring, u_int nm_i, u_int head)
 	struct sglist_seg ss[2];
 	struct sglist sg = { ss, 0, 0, 2 };
 
-	for (n = 0; nm_i != head; n++) {
-		static struct virtio_net_hdr_mrg_rxbuf hdr;
+	for (; nm_i != head; nm_i = nm_next(nm_i, lim)) {
 		struct netmap_slot *slot = &ring->slot[nm_i];
 		uint64_t paddr;
 		void *addr = PNMB(na, slot, &paddr);
-		int err = 0;
+		int err;
 
 		if (addr == NETMAP_BUF_BASE(na)) { /* bad buf */
 			if (netmap_ring_reinit(kring))
@@ -252,99 +297,134 @@ vtnet_refill_rxq(struct netmap_kring *kring, u_int nm_i, u_int head)
 		}
 
 		slot->flags &= ~NS_BUF_CHANGED;
-		sglist_reset(&sg); // cheap
-		err = sglist_append(&sg, &hdr, sc->vtnet_hdr_size);
-		err = sglist_append_phys(&sg, paddr, NETMAP_BUF_SIZE(na));
+		sglist_reset(&sg);
+		err = sglist_append(&sg, &rxq->vtnrx_shrhdr, sc->vtnet_hdr_size);
+		err |= sglist_append_phys(&sg, paddr, NETMAP_BUF_SIZE(na));
+		KASSERT(err == 0, ("%s: cannot append to sglist %d",
+					__func__, err));
 		/* writable for the host */
-		err = virtqueue_enqueue(vq, rxq, &sg, 0, sg.sg_nseg);
-		if (err < 0) {
-			D("virtqueue_enqueue failed");
+		err = virtqueue_enqueue(vq, /*cookie=*/rxq, &sg,
+				/*readable=*/0, /*writeable=*/sg.sg_nseg);
+		if (unlikely(err)) {
+			if (err != ENOSPC)
+				nm_prerr("virtqueue_enqueue(%s) failed: %d\n",
+					kring->name, err);
 			break;
 		}
-		nm_i = nm_next(nm_i, lim);
 	}
+
 	return nm_i;
 }
 
+/*
+ * Publish netmap buffers on a RX virtqueue.
+ * Returns -1 if this virtqueue is not being opened in netmap mode.
+ * If the virtqueue is being opened in netmap mode, return 0 on success and
+ * a positive error code on failure.
+ */
+static int
+vtnet_netmap_rxq_populate(struct vtnet_rxq *rxq)
+{
+	struct netmap_adapter *na = NA(rxq->vtnrx_sc->vtnet_ifp);
+	struct netmap_kring *kring;
+	int error;
+
+	if (!nm_native_on(na) || rxq->vtnrx_id >= na->num_rx_rings)
+		return -1;
+
+	kring = na->rx_rings[rxq->vtnrx_id];
+	if (!(nm_kring_pending_on(kring) ||
+			kring->nr_pending_mode == NKR_NETMAP_ON))
+		return -1;
+
+	/* Expose all the RX netmap buffers. Note that the number of
+	 * netmap slots in the RX ring matches the maximum number of
+	 * 2-elements sglist that the RX virtqueue can accommodate. */
+	error = vtnet_netmap_kring_refill(kring, 0, na->num_rx_desc);
+	virtqueue_notify(rxq->vtnrx_vq);
+
+	return error < 0 ? ENXIO : 0;
+}
+
 /* Reconcile kernel and user view of the receive ring. */
 static int
 vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
-        struct ifnet *ifp = na->ifp;
+	struct ifnet *ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int nm_i;	/* index into the netmap ring */
-	// u_int nic_i;	/* index into the NIC ring */
-	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
-	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+	int force_update = (flags & NAF_FORCE_READ) ||
+				(kring->nr_kflags & NKR_PENDINTR);
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
 
 	/* device-specific */
-	struct SOFTC_T *sc = ifp->if_softc;
+	struct vtnet_softc *sc = ifp->if_softc;
 	struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr];
 	struct virtqueue *vq = rxq->vtnrx_vq;
 
-	/* XXX netif_carrier_ok ? */
-
-	if (head > lim)
-		return netmap_ring_reinit(kring);
-
 	rmb();
 	/*
 	 * First part: import newly received packets.
-	 * Only accept our
-	 * own buffers (matching the token). We should only get
-	 * matching buffers, because of vtnet_netmap_free_rx_unused_bufs()
-	 * and vtnet_netmap_init_buffers().
+	 * Only accept our own buffers (matching the token). We should only get
+	 * matching buffers. We may need to stop early to avoid hwtail to overrun
+	 * hwcur.
 	 */
 	if (netmap_no_pendintr || force_update) {
-                struct netmap_adapter *token;
+		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
+		void *token;
 
-                nm_i = kring->nr_hwtail;
-                n = 0;
-		for (;;) {
+		vtnet_rxq_disable_intr(rxq);
+
+		nm_i = kring->nr_hwtail;
+		while (nm_i != hwtail_lim) {
 			int len;
-                        token = virtqueue_dequeue(vq, &len);
-                        if (token == NULL)
-                                break;
-                        if (likely(token == (void *)rxq)) {
-                            ring->slot[nm_i].len = len;
-                            ring->slot[nm_i].flags = 0;
-                            nm_i = nm_next(nm_i, lim);
-                            n++;
-                        } else {
-			    D("This should not happen");
-                        }
+			token = virtqueue_dequeue(vq, &len);
+			if (token == NULL) {
+				if (interrupts && vtnet_rxq_enable_intr(rxq)) {
+					vtnet_rxq_disable_intr(rxq);
+					continue;
+				}
+				break;
+			}
+			if (unlikely(token != (void *)rxq)) {
+				nm_prerr("BUG: RX token mismatch\n");
+			} else {
+				/* Skip the virtio-net header. */
+				len -= sc->vtnet_hdr_size;
+				if (unlikely(len < 0)) {
+					RD(1, "Truncated virtio-net-header, "
+						"missing %d bytes", -len);
+					len = 0;
+				}
+				ring->slot[nm_i].len = len;
+				ring->slot[nm_i].flags = 0;
+				nm_i = nm_next(nm_i, lim);
+			}
 		}
 		kring->nr_hwtail = nm_i;
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
-        ND("[B] h %d c %d hwcur %d hwtail %d",
-		ring->head, ring->cur, kring->nr_hwcur,
-			      kring->nr_hwtail);
+	ND("[B] h %d c %d hwcur %d hwtail %d", ring->head, ring->cur,
+				kring->nr_hwcur, kring->nr_hwtail);
 
 	/*
 	 * Second part: skip past packets that userspace has released.
 	 */
 	nm_i = kring->nr_hwcur; /* netmap ring index */
 	if (nm_i != head) {
-		int err = vtnet_refill_rxq(kring, nm_i, head);
-		if (err < 0)
-			return 1;
-		kring->nr_hwcur = err;
+		int nm_j = vtnet_netmap_kring_refill(kring, nm_i, head);
+		if (nm_j < 0)
+			return nm_j;
+		kring->nr_hwcur = nm_j;
 		virtqueue_notify(vq);
-		/* After draining the queue may need an intr from the hypervisor */
-		if (interrupts) {
-			vtnet_rxq_enable_intr(rxq);
-		}
 	}
 
-        ND("[C] h %d c %d t %d hwcur %d hwtail %d",
-		ring->head, ring->cur, ring->tail,
-		kring->nr_hwcur, kring->nr_hwtail);
+	ND("[C] h %d c %d t %d hwcur %d hwtail %d", ring->head, ring->cur,
+		ring->tail, kring->nr_hwcur, kring->nr_hwtail);
 
 	return 0;
 }
@@ -352,9 +432,9 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 /* Enable/disable interrupts on all virtqueues. */
 static void
-vtnet_netmap_intr(struct netmap_adapter *na, int onoff)
+vtnet_netmap_intr(struct netmap_adapter *na, int state)
 {
-	struct SOFTC_T *sc = na->ifp->if_softc;
+	struct vtnet_softc *sc = na->ifp->if_softc;
 	int i;
 
 	for (i = 0; i < sc->vtnet_max_vq_pairs; i++) {
@@ -362,7 +442,7 @@ vtnet_netmap_intr(struct netmap_adapter *na, int onoff)
 		struct vtnet_txq *txq = &sc->vtnet_txqs[i];
 		struct virtqueue *txvq = txq->vtntx_vq;
 
-		if (onoff) {
+		if (state) {
 			vtnet_rxq_enable_intr(rxq);
 			virtqueue_enable_intr(txvq);
 		} else {
@@ -372,60 +452,88 @@ vtnet_netmap_intr(struct netmap_adapter *na, int onoff)
 	}
 }
 
-/* Make RX virtqueues buffers pointing to netmap buffers. */
 static int
-vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc)
+vtnet_netmap_tx_slots(struct vtnet_softc *sc)
 {
-	struct ifnet *ifp = sc->vtnet_ifp;
-	struct netmap_adapter* na = NA(ifp);
-	unsigned int r;
+	int div;
+
+	/* We need to prepend a virtio-net header to each netmap buffer to be
+	 * transmitted, therefore calling virtqueue_enqueue() passing sglist
+	 * with 2 elements.
+	 * TX virtqueues use indirect descriptors if the feature was negotiated
+	 * with the host, and if sc->vtnet_tx_nsegs > 1. With indirect
+	 * descriptors, a single virtio descriptor is sufficient to reference
+	 * each TX sglist. Without them, we need two separate virtio descriptors
+	 * for each TX sglist. We therefore compute the number of netmap TX
+	 * slots according to these assumptions.
+	 */
+	if ((sc->vtnet_flags & VTNET_FLAG_INDIRECT) && sc->vtnet_tx_nsegs > 1)
+		div = 1;
+	else
+		div = 2;
 
-	if (!nm_native_on(na))
-		return 0;
-	for (r = 0; r < na->num_rx_rings; r++) {
-                struct netmap_kring *kring = na->rx_rings[r];
-		struct vtnet_rxq *rxq = &sc->vtnet_rxqs[r];
-		struct virtqueue *vq = rxq->vtnrx_vq;
-	        struct netmap_slot* slot;
-		int err = 0;
-
-		slot = netmap_reset(na, NR_RX, r, 0);
-		if (!slot) {
-			D("strange, null netmap ring %d", r);
-			return 0;
-		}
-		/* Add up to na>-num_rx_desc-1 buffers to this RX virtqueue.
-		 * It's important to leave one virtqueue slot free, otherwise
-		 * we can run into ring->cur/ring->tail wraparounds.
-		 */
-		err = vtnet_refill_rxq(kring, 0, na->num_rx_desc-1);
-		if (err < 0)
-			return 0;
-		virtqueue_notify(vq);
-	}
+	return virtqueue_size(sc->vtnet_txqs[0].vtntx_vq) / div;
+}
 
-	return 1;
+static int
+vtnet_netmap_rx_slots(struct vtnet_softc *sc)
+{
+	int div;
+
+	/* We need to prepend a virtio-net header to each netmap buffer to be
+	 * received, therefore calling virtqueue_enqueue() passing sglist
+	 * with 2 elements.
+	 * RX virtqueues use indirect descriptors if the feature was negotiated
+	 * with the host, and if sc->vtnet_rx_nsegs > 1. With indirect
+	 * descriptors, a single virtio descriptor is sufficient to reference
+	 * each RX sglist. Without them, we need two separate virtio descriptors
+	 * for each RX sglist. We therefore compute the number of netmap RX
+	 * slots according to these assumptions.
+	 */
+	if ((sc->vtnet_flags & VTNET_FLAG_INDIRECT) && sc->vtnet_rx_nsegs > 1)
+		div = 1;
+	else
+		div = 2;
+
+	return virtqueue_size(sc->vtnet_rxqs[0].vtnrx_vq) / div;
+}
+
+static int
+vtnet_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	struct vtnet_softc *sc = na->ifp->if_softc;
+
+	info->num_tx_rings = sc->vtnet_act_vq_pairs;
+	info->num_rx_rings = sc->vtnet_act_vq_pairs;
+	info->num_tx_descs = vtnet_netmap_tx_slots(sc);
+	info->num_rx_descs = vtnet_netmap_rx_slots(sc);
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
+
+	return 0;
 }
 
 static void
-vtnet_netmap_attach(struct SOFTC_T *sc)
+vtnet_netmap_attach(struct vtnet_softc *sc)
 {
 	struct netmap_adapter na;
 
 	bzero(&na, sizeof(na));
 
 	na.ifp = sc->vtnet_ifp;
-	na.num_tx_desc =  1024;// sc->vtnet_rx_nmbufs;
-	na.num_rx_desc =  1024; // sc->vtnet_rx_nmbufs;
+	na.na_flags = 0;
+	na.num_tx_desc = vtnet_netmap_tx_slots(sc);
+	na.num_rx_desc = vtnet_netmap_rx_slots(sc);
+	na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs;
+	na.rx_buf_maxsize = 0;
 	na.nm_register = vtnet_netmap_reg;
 	na.nm_txsync = vtnet_netmap_txsync;
 	na.nm_rxsync = vtnet_netmap_rxsync;
 	na.nm_intr = vtnet_netmap_intr;
-	na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs;
-	D("max rings %d", sc->vtnet_max_vq_pairs);
+	na.nm_config = vtnet_netmap_config;
+
 	netmap_attach(&na);
 
-        D("virtio attached txq=%d, txd=%d rxq=%d, rxd=%d",
+	nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d\n",
 			na.num_tx_rings, na.num_tx_desc,
 			na.num_tx_rings, na.num_rx_desc);
 }

From 88aa668ef61ba4a385a42483c816f5f670bea1d5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 15:46:01 +0100
Subject: [PATCH 1425/2207] let nm_prinf() and nm_prerr() have the same
 interface as D()

---
 LINUX/if_virtio_net_netmap.h     | 10 +++++-----
 LINUX/netmap_linux.c             |  2 +-
 sys/dev/netmap/if_ixl_netmap.h   |  2 +-
 sys/dev/netmap/if_vtnet_netmap.h | 12 +++++------
 sys/dev/netmap/netmap.c          | 28 +++++++++++++-------------
 sys/dev/netmap/netmap_kern.h     | 34 ++++++++++++++++++++++++--------
 sys/dev/netmap/netmap_kloop.c    | 10 +++++-----
 sys/dev/netmap/netmap_mem2.c     |  4 ++--
 8 files changed, 60 insertions(+), 42 deletions(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 02f54b2c0..e72e6875a 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -489,7 +489,7 @@ virtio_net_netmap_detach_unused(struct virtnet_info *vi, bool onoff,
 	}
 
 	if (n)
-		nm_prinf("%d sgs detached on %s-%d (onoff=%d)\n",
+		nm_prinf("%d sgs detached on %s-%d (onoff=%d)",
 			 n, nm_txrx2str(t), idx, onoff);
 }
 
@@ -512,7 +512,7 @@ virtio_net_netmap_drain_used(struct virtnet_info *vi, bool onoff,
 	}
 
 	if (n)
-		nm_prinf("%d sgs drained on %s-%d (onoff=%d)\n",
+		nm_prinf("%d sgs drained on %s-%d (onoff=%d)",
 			n, nm_txrx2str(t), idx, onoff);
 }
 
@@ -679,11 +679,11 @@ virtio_net_netmap_init_buffers(struct virtnet_info *vi, int r)
 		sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na));
 		err = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC);
 		if (err < 0) {
-			nm_prerr("virtqueue_add_inbuf() failed\n");
+			nm_prerr("virtqueue_add_inbuf() failed");
 			return 0;
 		}
 	}
-	nm_prinf("%s-rx-%d: %d netmap buffers published\n", na->name,
+	nm_prinf("%s-rx-%d: %d netmap buffers published", na->name,
 			r, i);
 
 	return true;
@@ -767,7 +767,7 @@ virtio_net_netmap_txsync(struct netmap_kring *kring, int flags)
 		if (token == NULL)
 			break;
 		if (unlikely(token != na))
-			nm_prerr("BUG: token mismatch\n");
+			nm_prerr("BUG: token mismatch");
 		else
 			n++;
 	}
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 2f383e814..04b1a936d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1107,7 +1107,7 @@ nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
 #else
 		*rxq = 1;
 		nm_prinf("WARNING: netmap will use only the first "
-			 "RX queue of %s\n", ifp->name);
+			 "RX queue of %s", ifp->name);
 #endif /* HAVE_REAL_NUM_RX_QUEUES */
 	}
 }
diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h
index 48369aa02..9309e0d10 100644
--- a/sys/dev/netmap/if_ixl_netmap.h
+++ b/sys/dev/netmap/if_ixl_netmap.h
@@ -129,7 +129,7 @@ ixl_netmap_attach(struct ixl_vsi *vsi)
 	na.ifp = vsi->ifp;
 	na.na_flags = NAF_BDG_MAYSLEEP;
 	// XXX check that queues is set.
-	nm_prinf("queues is %p\n", vsi->queues);
+	nm_prinf("queues is %p", vsi->queues);
 	if (vsi->queues) {
 		na.num_tx_desc = vsi->queues[0].num_desc;
 		na.num_rx_desc = vsi->queues[0].num_desc;
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index acb58f140..cbb9b72a9 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -79,7 +79,7 @@ vtnet_free_used(struct virtqueue *vq, int netmap_bufs, enum txrx t, int idx)
 	}
 
 	if (deq)
-		nm_prinf("%d sgs dequeued from %s-%d (netmap=%d)\n",
+		nm_prinf("%d sgs dequeued from %s-%d (netmap=%d)",
 			 deq, nm_txrx2str(t), idx, netmap_bufs);
 }
 
@@ -230,7 +230,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 						/*writeable=*/0);
 			if (unlikely(err)) {
 				if (err != ENOSPC)
-					nm_prerr("virtqueue_enqueue(%s) failed: %d\n",
+					nm_prerr("virtqueue_enqueue(%s) failed: %d",
 							kring->name, err);
 				break;
 			}
@@ -251,7 +251,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 		if (token == NULL)
 			break;
 		if (unlikely(token != (void *)txq))
-			nm_prerr("BUG: TX token mismatch\n");
+			nm_prerr("BUG: TX token mismatch");
 		else
 			n++;
 	}
@@ -307,7 +307,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int nm_i, u_int head)
 				/*readable=*/0, /*writeable=*/sg.sg_nseg);
 		if (unlikely(err)) {
 			if (err != ENOSPC)
-				nm_prerr("virtqueue_enqueue(%s) failed: %d\n",
+				nm_prerr("virtqueue_enqueue(%s) failed: %d",
 					kring->name, err);
 			break;
 		}
@@ -391,7 +391,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 				break;
 			}
 			if (unlikely(token != (void *)rxq)) {
-				nm_prerr("BUG: RX token mismatch\n");
+				nm_prerr("BUG: RX token mismatch");
 			} else {
 				/* Skip the virtio-net header. */
 				len -= sc->vtnet_hdr_size;
@@ -533,7 +533,7 @@ vtnet_netmap_attach(struct vtnet_softc *sc)
 
 	netmap_attach(&na);
 
-	nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d\n",
+	nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d",
 			na.num_tx_rings, na.num_tx_desc,
 			na.num_tx_rings, na.num_rx_desc);
 }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9e5340ea6..88ba7d78a 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -687,7 +687,7 @@ nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg)
 		op = "Clamp";
 	}
 	if (op && msg)
-		nm_prinf("%s %s to %d (was %d)\n", op, msg, *v, oldv);
+		nm_prinf("%s %s to %d (was %d)", op, msg, *v, oldv);
 	return *v;
 }
 
@@ -2018,7 +2018,7 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 	int i;
 
 	if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
-		nm_prerr("Cannot update CSB while kloop is running\n");
+		nm_prerr("Cannot update CSB while kloop is running");
 		return EBUSY;
 	}
 
@@ -2031,7 +2031,7 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 		return 0;
 
 	if (!(priv->np_flags & NR_EXCLUSIVE)) {
-		nm_prerr("CSB mode requires NR_EXCLUSIVE\n");
+		nm_prerr("CSB mode requires NR_EXCLUSIVE");
 		return EINVAL;
 	}
 
@@ -2050,7 +2050,7 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 		int err;
 
 		if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
-			nm_prerr("Unaligned CSB address\n");
+			nm_prerr("Unaligned CSB address");
 			return EINVAL;
 		}
 
@@ -2067,7 +2067,7 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 		}
 		nm_os_free(tmp);
 		if (err) {
-			nm_prerr("Invalid CSB address\n");
+			nm_prerr("Invalid CSB address");
 			return err;
 		}
 	}
@@ -2097,7 +2097,7 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 			CSB_WRITE(csb_ktoa, kern_need_kick, 1);
 
 			nm_prinf("csb_init for kring %s: head %u, cur %u, "
-				"hwcur %u, hwtail %u\n", kring->name,
+				"hwcur %u, hwtail %u", kring->name,
 				kring->rhead, kring->rcur, kring->nr_hwcur,
 				kring->nr_hwtail);
 		}
@@ -2234,7 +2234,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 				 * cannot be used in this case. */
 				if (nbs < mtu) {
 					nm_prerr("error: netmap buf size (%u) "
-						"< device MTU (%u)\n", nbs, mtu);
+						"< device MTU (%u)", nbs, mtu);
 					error = EINVAL;
 					goto err_drop_mem;
 				}
@@ -2247,14 +2247,14 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 				if (!(na->na_flags & NAF_MOREFRAG)) {
 					nm_prerr("error: large MTU (%d) needed "
 						"but %s does not support "
-						"NS_MOREFRAG\n", mtu,
+						"NS_MOREFRAG", mtu,
 						na->ifp->if_xname);
 					error = EINVAL;
 					goto err_drop_mem;
 				} else if (nbs < na->rx_buf_maxsize) {
 					nm_prerr("error: using NS_MOREFRAG on "
 						"%s requires netmap buf size "
-						">= %u\n", na->ifp->if_xname,
+						">= %u", na->ifp->if_xname,
 						na->rx_buf_maxsize);
 					error = EINVAL;
 					goto err_drop_mem;
@@ -2262,7 +2262,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 					nm_prinf("info: netmap application on "
 						"%s needs to support "
 						"NS_MOREFRAG "
-						"(MTU=%u,netmap_buf_size=%u)\n",
+						"(MTU=%u,netmap_buf_size=%u)",
 						na->ifp->if_xname, mtu, nbs);
 				}
 			}
@@ -2809,7 +2809,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		mb(); /* make sure following reads are not from cache */
 
 		if (unlikely(priv->np_csb_atok_base)) {
-			nm_prerr("Invalid sync in CSB mode\n");
+			nm_prerr("Invalid sync in CSB mode");
 			error = EBUSY;
 			break;
 		}
@@ -3222,7 +3222,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		return POLLERR;
 
 	if (unlikely(priv->np_csb_atok_base)) {
-		nm_prerr("Invalid poll in CSB mode\n");
+		nm_prerr("Invalid poll in CSB mode");
 		return POLLERR;
 	}
 
@@ -4089,7 +4089,7 @@ netmap_fini(void)
 	netmap_uninit_bridges();
 	netmap_mem_fini();
 	NMG_LOCK_DESTROY();
-	nm_prinf("netmap: unloaded module.\n");
+	nm_prinf("netmap: unloaded module.");
 }
 
 
@@ -4126,7 +4126,7 @@ netmap_init(void)
 	if (error)
 		goto fail;
 
-	nm_prinf("netmap: loaded module\n");
+	nm_prinf("netmap: loaded module");
 	return (0);
 fail:
 	netmap_fini();
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a574efed4..4a1778355 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -240,22 +240,40 @@ typedef struct hrtimer{
 #define	NMG_LOCK_ASSERT()	NM_MTX_ASSERT(netmap_global_lock)
 
 #if defined(__FreeBSD__)
-#define nm_prerr	printf
-#define nm_prinf	printf
+#define nm_prerr_int	printf
+#define nm_prinf_int	printf
 #elif defined (_WIN32)
-#define nm_prerr	DbgPrint
-#define nm_prinf	DbgPrint
+#define nm_prerr_int	DbgPrint
+#define nm_prinf_int	DbgPrint
 #elif defined(linux)
-#define nm_prerr(fmt, arg...)    printk(KERN_ERR fmt, ##arg)
-#define nm_prinf(fmt, arg...)    printk(KERN_INFO fmt, ##arg)
+#define nm_prerr_int(fmt, arg...)    printk(KERN_ERR fmt, ##arg)
+#define nm_prinf_int(fmt, arg...)    printk(KERN_INFO fmt, ##arg)
 #endif
 
+#define nm_prinf(format, ...)					\
+	do {							\
+		struct timeval __xxts;				\
+		microtime(&__xxts);				\
+		nm_prinf_int("%03d.%06d [%4d] %-25s " format "\n",\
+		(int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec,	\
+		__LINE__, __FUNCTION__, ##__VA_ARGS__);		\
+	} while (0)
+
+#define nm_prerr(format, ...)					\
+	do {							\
+		struct timeval __xxts;				\
+		microtime(&__xxts);				\
+		nm_prerr_int("%03d.%06d [%4d] %-25s " format "\n",\
+		(int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec,	\
+		__LINE__, __FUNCTION__, ##__VA_ARGS__);		\
+	} while (0)
+
 #define ND(format, ...)
 #define D(format, ...)						\
 	do {							\
 		struct timeval __xxts;				\
 		microtime(&__xxts);				\
-		nm_prerr("%03d.%06d [%4d] %-25s " format "\n",	\
+		nm_prerr_int("%03d.%06d [%4d] %-25s " format "\n",\
 		(int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec,	\
 		__LINE__, __FUNCTION__, ##__VA_ARGS__);		\
 	} while (0)
@@ -269,7 +287,7 @@ typedef struct hrtimer{
 			__cnt = 0;				\
 		}						\
 		if (__cnt++ < lps)				\
-			D(format, ##__VA_ARGS__);		\
+			nm_prinf(format, ##__VA_ARGS__);	\
 	} while (0)
 
 struct netmap_adapter;
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 92f0d7e88..ffb28d192 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -125,8 +125,8 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 {
-	nm_prinf("sync_kloop: %s - name: %s hwcur: %d hwtail: %d "
-		"rhead: %d rcur: %d rtail: %d\n",
+	nm_prinf("%s - name: %s hwcur: %d hwtail: %d "
+		"rhead: %d rcur: %d rtail: %d",
 		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
 		kring->rhead, kring->rcur, kring->rtail);
 }
@@ -198,7 +198,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
-			nm_prerr("sync_kloop: txsync() failed\n");
+			nm_prerr("txsync() failed");
 			break;
 		}
 
@@ -315,7 +315,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
-			nm_prerr("sync_kloop: rxsync() failed\n");
+			nm_prerr("rxsync() failed");
 			break;
 		}
 
@@ -465,7 +465,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	if (!priv->np_csb_atok_base || !priv->np_csb_ktoa_base) {
 		NMG_UNLOCK();
 		nm_prerr("sync-kloop on %s requires "
-				"NETMAP_REQ_OPT_CSB option\n", na->name);
+				"NETMAP_REQ_OPT_CSB option", na->name);
 		return EINVAL;
 	}
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 841121618..b640bc497 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -318,7 +318,7 @@ netmap_mem_get_id(struct netmap_mem_d *nmd)
 
 #ifdef NM_DEBUG_MEM_PUTGET
 #define NM_DBG_REFC(nmd, func, line)	\
-	nm_prinf("%s:%d mem[%d] -> %d\n", func, line, (nmd)->nm_id, (nmd)->refcount);
+	nm_prinf("%d mem[%d] -> %d", line, (nmd)->nm_id, (nmd)->refcount);
 #else
 #define NM_DBG_REFC(nmd, func, line)
 #endif
@@ -2388,7 +2388,7 @@ netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
 
 	NMA_UNLOCK(nmd);
 
-	nm_prinf("ptnet if added (ifp=%s,nifp_offset=%u)\n",
+	nm_prinf("ifp=%s,nifp_offset=%u",
 		ptif->ifp->if_xname, ptif->nifp_offset);
 
 	return 0;

From 5872efbb6c422f5d9819a5e5ffe0c94ad0b98983 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 15:54:54 +0100
Subject: [PATCH 1426/2207] generic: use nm_prinf and nm_prerr rather than D()

---
 sys/dev/netmap/netmap_generic.c | 48 ++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index e4e158b44..ec6718207 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -81,7 +81,6 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap_generic.c 274353 2014-11-10 20:19
 #include 
 #include         /* bus_dmamap_* in netmap_kern.h */
 
-// XXX temporary - D() defined here
 #include 
 #include 
 #include 
@@ -179,7 +178,7 @@ static void rate_callback(unsigned long arg)
 	r = mod_timer(&ctx->timer, jiffies +
 			msecs_to_jiffies(RATE_PERIOD * 1000));
 	if (unlikely(r))
-		D("[v1000] Error: mod_timer()");
+		nm_prerr("mod_timer() failed");
 }
 
 static struct rate_context rate_ctx;
@@ -240,14 +239,14 @@ generic_netmap_unregister(struct netmap_adapter *na)
 
 	for_each_rx_kring_h(r, kring, na) {
 		if (nm_kring_pending_off(kring)) {
-			D("Emulated adapter: ring '%s' deactivated", kring->name);
+			nm_prinf("Emulated adapter: ring '%s' deactivated", kring->name);
 			kring->nr_mode = NKR_NETMAP_OFF;
 		}
 	}
 	for_each_tx_kring_h(r, kring, na) {
 		if (nm_kring_pending_off(kring)) {
 			kring->nr_mode = NKR_NETMAP_OFF;
-			D("Emulated adapter: ring '%s' deactivated", kring->name);
+			nm_prinf("Emulated adapter: ring '%s' deactivated", kring->name);
 		}
 	}
 
@@ -300,11 +299,11 @@ generic_netmap_unregister(struct netmap_adapter *na)
 
 #ifdef RATE_GENERIC
 		if (--rate_ctx.refcount == 0) {
-			D("del_timer()");
+			nm_prinf("del_timer()");
 			del_timer(&rate_ctx.timer);
 		}
 #endif
-		D("Emulated adapter for %s deactivated", na->name);
+		nm_prinf("Emulated adapter for %s deactivated", na->name);
 	}
 
 	return 0;
@@ -329,14 +328,14 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 	}
 
 	if (na->active_fds == 0) {
-		D("Emulated adapter for %s activated", na->name);
+		nm_prinf("Emulated adapter for %s activated", na->name);
 		/* Do all memory allocations when (na->active_fds == 0), to
 		 * simplify error management. */
 
 		/* Allocate memory for mitigation support on all the rx queues. */
 		gna->mit = nm_os_malloc(na->num_rx_rings * sizeof(struct nm_generic_mit));
 		if (!gna->mit) {
-			D("mitigation allocation failed");
+			nm_prerr("mitigation allocation failed");
 			error = ENOMEM;
 			goto out;
 		}
@@ -363,7 +362,7 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 			kring->tx_pool =
 				nm_os_malloc(na->num_tx_desc * sizeof(struct mbuf *));
 			if (!kring->tx_pool) {
-				D("tx_pool allocation failed");
+				nm_prerr("tx_pool allocation failed");
 				error = ENOMEM;
 				goto free_tx_pools;
 			}
@@ -374,14 +373,14 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 
 	for_each_rx_kring_h(r, kring, na) {
 		if (nm_kring_pending_on(kring)) {
-			D("Emulated adapter: ring '%s' activated", kring->name);
+			nm_prinf("Emulated adapter: ring '%s' activated", kring->name);
 			kring->nr_mode = NKR_NETMAP_ON;
 		}
 
 	}
 	for_each_tx_kring_h(r, kring, na) {
 		if (nm_kring_pending_on(kring)) {
-			D("Emulated adapter: ring '%s' activated", kring->name);
+			nm_prinf("Emulated adapter: ring '%s' activated", kring->name);
 			kring->nr_mode = NKR_NETMAP_ON;
 		}
 	}
@@ -399,14 +398,14 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 		/* Prepare to intercept incoming traffic. */
 		error = nm_os_catch_rx(gna, 1);
 		if (error) {
-			D("nm_os_catch_rx(1) failed (%d)", error);
+			nm_prerr("nm_os_catch_rx(1) failed (%d)", error);
 			goto free_tx_pools;
 		}
 
 		/* Let netmap control the packet steering. */
 		error = nm_os_catch_tx(gna, 1);
 		if (error) {
-			D("nm_os_catch_tx(1) failed (%d)", error);
+			nm_prerr("nm_os_catch_tx(1) failed (%d)", error);
 			goto catch_rx;
 		}
 
@@ -414,11 +413,11 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 
 #ifdef RATE_GENERIC
 		if (rate_ctx.refcount == 0) {
-			D("setup_timer()");
+			nm_prinf("setup_timer()");
 			memset(&rate_ctx, 0, sizeof(rate_ctx));
 			setup_timer(&rate_ctx.timer, &rate_callback, (unsigned long)&rate_ctx);
 			if (mod_timer(&rate_ctx.timer, jiffies + msecs_to_jiffies(1500))) {
-				D("Error: mod_timer()");
+				nm_prerr("Error: mod_timer()");
 			}
 		}
 		rate_ctx.refcount++;
@@ -462,7 +461,7 @@ generic_mbuf_destructor(struct mbuf *m)
 	unsigned int r_orig = r;
 
 	if (unlikely(!nm_netmap_on(na) || r >= na->num_tx_rings)) {
-		D("Error: no netmap adapter on device %p",
+		nm_prerr("Error: no netmap adapter on device %p",
 		  GEN_TX_MBUF_IFP(m));
 		return;
 	}
@@ -598,7 +597,7 @@ ring_middle(u_int inf, u_int sup, u_int lim)
 	}
 
 	if (unlikely(e >= n)) {
-		D("This cannot happen");
+		nm_prerr("This cannot happen");
 		e = 0;
 	}
 
@@ -1048,7 +1047,7 @@ generic_netmap_dtor(struct netmap_adapter *na)
 		         */
 		        netmap_adapter_put(prev_na);
 		}
-		D("Native netmap adapter %p restored", prev_na);
+		nm_prinf("Native netmap adapter %p restored", prev_na);
 	}
 	NM_RESTORE_NA(ifp, prev_na);
 	/*
@@ -1056,7 +1055,7 @@ generic_netmap_dtor(struct netmap_adapter *na)
 	 * overrides WNA(ifp) if na->ifp is not NULL.
 	 */
 	na->ifp = NULL;
-	D("Emulated netmap adapter for %s destroyed", na->name);
+	nm_prinf("Emulated netmap adapter for %s destroyed", na->name);
 }
 
 int
@@ -1086,7 +1085,7 @@ generic_netmap_attach(struct ifnet *ifp)
 
 #ifdef __FreeBSD__
 	if (ifp->if_type == IFT_LOOP) {
-		D("if_loop is not supported by %s", __func__);
+		nm_prerr("if_loop is not supported by %s", __func__);
 		return EINVAL;
 	}
 #endif
@@ -1096,22 +1095,21 @@ generic_netmap_attach(struct ifnet *ifp)
 		 * adapter it means that someone else is using the same
 		 * pointer (e.g. ax25_ptr on linux). This happens for
 		 * instance when also PF_RING is in use. */
-		D("Error: netmap adapter hook is busy");
+		nm_prerr("Error: netmap adapter hook is busy");
 		return EBUSY;
 	}
 
 	num_tx_desc = num_rx_desc = netmap_generic_ringsize; /* starting point */
 
 	nm_os_generic_find_num_desc(ifp, &num_tx_desc, &num_rx_desc); /* ignore errors */
-	ND("Netmap ring size: TX = %d, RX = %d", num_tx_desc, num_rx_desc);
 	if (num_tx_desc == 0 || num_rx_desc == 0) {
-		D("Device has no hw slots (tx %u, rx %u)", num_tx_desc, num_rx_desc);
+		nm_prerr("Device has no hw slots (tx %u, rx %u)", num_tx_desc, num_rx_desc);
 		return EINVAL;
 	}
 
 	gna = nm_os_malloc(sizeof(*gna));
 	if (gna == NULL) {
-		D("no memory on attach, give up");
+		nm_prerr("no memory on attach, give up");
 		return ENOMEM;
 	}
 	na = (struct netmap_adapter *)gna;
@@ -1151,7 +1149,7 @@ generic_netmap_attach(struct ifnet *ifp)
 
 	nm_os_generic_set_features(gna);
 
-	D("Emulated adapter for %s created (prev was %p)", na->name, gna->prev);
+	nm_prinf("Emulated adapter for %s created (prev was %p)", na->name, gna->prev);
 
 	return retval;
 }

From 779be78c727e98585f0444ac239e5d077eb9bb14 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 16:05:46 +0100
Subject: [PATCH 1427/2207] generic: use nm_prlim and nm_prdis

---
 sys/dev/netmap/netmap_generic.c | 22 +++++++++++-----------
 sys/dev/netmap/netmap_kern.h    | 20 +++++++++-----------
 2 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index ec6718207..5925544dc 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -487,7 +487,7 @@ generic_mbuf_destructor(struct mbuf *m)
 
 		if (match) {
 			if (r != r_orig) {
-				RD(1, "event %p migrated: ring %u --> %u",
+				nm_prlim(1, "event %p migrated: ring %u --> %u",
 				      m, r_orig, r);
 			}
 			break;
@@ -496,7 +496,7 @@ generic_mbuf_destructor(struct mbuf *m)
 		if (++r == na->num_tx_rings) r = 0;
 
 		if (r == r_orig) {
-			RD(1, "Cannot match event %p", m);
+			nm_prlim(1, "Cannot match event %p", m);
 			return;
 		}
 	}
@@ -527,7 +527,7 @@ generic_netmap_tx_clean(struct netmap_kring *kring, int txqdisc)
 	u_int n = 0;
 	struct mbuf **tx_pool = kring->tx_pool;
 
-	ND("hwcur = %d, hwtail = %d", kring->nr_hwcur, kring->nr_hwtail);
+	nm_prdis("hwcur = %d, hwtail = %d", kring->nr_hwcur, kring->nr_hwtail);
 
 	while (nm_i != hwcur) { /* buffers not completed */
 		struct mbuf *m = tx_pool[nm_i];
@@ -536,7 +536,7 @@ generic_netmap_tx_clean(struct netmap_kring *kring, int txqdisc)
 			if (m == NULL) {
 				/* Nothing to do, this is going
 				 * to be replenished. */
-				RD(3, "Is this happening?");
+				nm_prlim(3, "Is this happening?");
 
 			} else if (MBUF_QUEUED(m)) {
 				break; /* Not dequeued yet. */
@@ -575,7 +575,7 @@ generic_netmap_tx_clean(struct netmap_kring *kring, int txqdisc)
 		nm_i = nm_next(nm_i, lim);
 	}
 	kring->nr_hwtail = nm_prev(nm_i, lim);
-	ND("tx completed [%d] -> hwtail %d", n, kring->nr_hwtail);
+	nm_prdis("tx completed [%d] -> hwtail %d", n, kring->nr_hwtail);
 
 	return n;
 }
@@ -653,7 +653,7 @@ generic_set_tx_event(struct netmap_kring *kring, u_int hwcur)
 
 	kring->tx_pool[e] = NULL;
 
-	ND(5, "Request Event at %d mbuf %p refcnt %d", e, m, m ? MBUF_REFCNT(m) : -2 );
+	nm_prdis("Request Event at %d mbuf %p refcnt %d", e, m, m ? MBUF_REFCNT(m) : -2 );
 
 	/* Decrement the refcount. This will free it if we lose the race
 	 * with the driver. */
@@ -698,7 +698,7 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 			 * but only when cur == hwtail, which means that the
 			 * client is going to block. */
 			event = ring_middle(nm_i, head, lim);
-			ND(3, "Place txqdisc event (hwcur=%u,event=%u,"
+			nm_prdis("Place txqdisc event (hwcur=%u,event=%u,"
 			      "head=%u,hwtail=%u)", nm_i, event, head,
 			      kring->nr_hwtail);
 		}
@@ -724,7 +724,7 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 				kring->tx_pool[nm_i] = m =
 					nm_os_get_mbuf(ifp, NETMAP_BUF_SIZE(na));
 				if (m == NULL) {
-					RD(2, "Failed to replenish mbuf");
+					nm_prlim(2, "Failed to replenish mbuf");
 					/* Here we could schedule a timer which
 					 * retries to replenish after a while,
 					 * and notifies the client when it
@@ -853,7 +853,7 @@ generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
 		/* This may happen when GRO/LRO features are enabled for
 		 * the NIC driver when the generic adapter does not
 		 * support RX scatter-gather. */
-		RD(2, "Warning: driver pushed up big packet "
+		nm_prlim(2, "Warning: driver pushed up big packet "
 				"(size=%d)", (int)MBUF_LEN(m));
 		m_freem(m);
 	} else if (unlikely(mbq_len(&kring->rx_queue) > 1024)) {
@@ -1127,10 +1127,10 @@ generic_netmap_attach(struct ifnet *ifp)
 	 */
 	na->na_flags = NAF_SKIP_INTR | NAF_HOST_RINGS;
 
-	ND("[GNA] num_tx_queues(%d), real_num_tx_queues(%d), len(%lu)",
+	nm_prdis("[GNA] num_tx_queues(%d), real_num_tx_queues(%d), len(%lu)",
 			ifp->num_tx_queues, ifp->real_num_tx_queues,
 			ifp->tx_queue_len);
-	ND("[GNA] num_rx_queues(%d), real_num_rx_queues(%d)",
+	nm_prdis("[GNA] num_rx_queues(%d), real_num_rx_queues(%d)",
 			ifp->num_rx_queues, ifp->real_num_rx_queues);
 
 	nm_os_generic_find_num_queues(ifp, &na->num_tx_rings, &na->num_rx_rings);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4a1778355..34442683f 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -268,18 +268,11 @@ typedef struct hrtimer{
 		__LINE__, __FUNCTION__, ##__VA_ARGS__);		\
 	} while (0)
 
-#define ND(format, ...)
-#define D(format, ...)						\
-	do {							\
-		struct timeval __xxts;				\
-		microtime(&__xxts);				\
-		nm_prerr_int("%03d.%06d [%4d] %-25s " format "\n",\
-		(int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec,	\
-		__LINE__, __FUNCTION__, ##__VA_ARGS__);		\
-	} while (0)
+/* Disabled printf (used to be ND). */
+#define nm_prdis(format, ...)
 
-/* rate limited, lps indicates how many per second */
-#define RD(lps, format, ...)					\
+/* Rate limited, lps indicates how many per second. */
+#define nm_prlim(lps, format, ...)				\
 	do {							\
 		static int t0, __cnt;				\
 		if (t0 != time_second) {			\
@@ -290,6 +283,11 @@ typedef struct hrtimer{
 			nm_prinf(format, ##__VA_ARGS__);	\
 	} while (0)
 
+/* Old macros. */
+#define ND	nm_prdis
+#define D	nm_prerr
+#define RD	nm_prlim
+
 struct netmap_adapter;
 struct nm_bdg_fwd;
 struct nm_bridge;

From dddc1b1699df39661f8cebfbfe3262681a09ac5c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 16:11:06 +0100
Subject: [PATCH 1428/2207] netmap_linux: switch to nm_pr* logging functions

---
 LINUX/netmap_linux.c | 56 ++++++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 04b1a936d..7f0d071d7 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -242,14 +242,14 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 
 	e = nm_os_malloc(sizeof(*e));
 	if (e == NULL) {
-		D("failed to allocate os_extmem");
+		nm_prerr("failed to allocate os_extmem");
 		err = ENOMEM;
 		goto out;
 	}
 
 	pages = nm_os_vmalloc(nr_pages * sizeof(*pages));
 	if (pages == NULL) {
-		D("failed to allocate pages array (nr_pages %d)", nr_pages);
+		nm_prerr("failed to allocate pages array (nr_pages %d)", nr_pages);
 		err = ENOMEM;
 		goto out;
 	}
@@ -295,7 +295,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 	e->nr_pages = res;
 
 	if (res < nr_pages) {
-		D("failed to get user pages: res %d nr_pages %d", res, nr_pages);
+		nm_prerr("failed to get user pages: res %d nr_pages %d", res, nr_pages);
 		err = EFAULT;
 		goto out;
 	}
@@ -582,7 +582,7 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 	int ret = 0;
 
 	if (!ifp) {
-		D("Failed to get ifp");
+		nm_prerr("Failed to get ifp");
 		return -EBUSY;
 	}
 
@@ -664,7 +664,7 @@ generic_qdisc_init(struct Qdisc *qdisc, struct nlattr *opt
 #ifdef NETMAP_LINUX_HAVE_QDISC_EXTACK
 			NL_SET_ERR_MSG(extack, "Invalid netlink attribute");
 #else
-			D("Invalid netlink attribute");
+			nm_prerr("Invalid netlink attribute");
 #endif /* NETMAP_LINUX_HAVE_QDISC_EXTACK */
 			return -EINVAL;
 		}
@@ -687,7 +687,7 @@ generic_qdisc_enqueue(struct mbuf *m, struct Qdisc *qdisc
 	struct nm_generic_qdisc *priv = qdisc_priv(qdisc);
 
 	if (unlikely(qdisc_qlen(qdisc) >= priv->limit)) {
-		RD(5, "dropping mbuf");
+		nm_prlim(5, "dropping mbuf");
 
 		return qdisc_drop(m, qdisc
 #ifdef NETMAP_LINUX_HAVE_QDISC_ENQUEUE_TOFREE
@@ -697,7 +697,7 @@ generic_qdisc_enqueue(struct mbuf *m, struct Qdisc *qdisc
 		/* or qdisc_reshape_fail() ? */
 	}
 
-	ND(5, "Enqueuing mbuf, len %u", qdisc_qlen(qdisc));
+	nm_prdis(5, "Enqueuing mbuf, len %u", qdisc_qlen(qdisc));
 
 	return qdisc_enqueue_tail(m, qdisc);
 }
@@ -716,12 +716,12 @@ generic_qdisc_dequeue(struct Qdisc *qdisc)
 		 * We have to set the priority to the normal TX token, so that
 		 * generic_ndo_start_xmit can pass it to the driver. */
 		m->priority = NM_MAGIC_PRIORITY_TX;
-		ND(5, "Event met, notify %p", m);
+		nm_prdis(5, "Event met, notify %p", m);
 		netmap_generic_irq(NA(qdisc_dev(qdisc)),
 				skb_get_queue_mapping(m), NULL);
 	}
 
-	ND(5, "Dequeuing mbuf, len %u", qdisc_qlen(qdisc));
+	nm_prdis(5, "Dequeuing mbuf, len %u", qdisc_qlen(qdisc));
 
 	return m;
 }
@@ -789,14 +789,14 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 #endif /* NETMAP_LINUX_SOCK_CREATE_KERN_NETNS  */
 				AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
 	if (ret) {
-		D("Failed to create netlink socket (err=%d)", ret);
+		nm_prerr("Failed to create netlink socket (err=%d)", ret);
 		return -ret;
 	}
 
 
 	ret = kernel_bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
 	if (ret) {
-		D("Failed to bind() netlink socket (err=%d)", ret);
+		nm_prerr("Failed to bind() netlink socket (err=%d)", ret);
 		goto release;
 	}
 
@@ -825,13 +825,13 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 	ret = kernel_sendmsg(sock, &msg, (struct kvec *)&iov, 1,
 				iov.iov_len);
 	if (ret != nlreq.hdr.nlmsg_len) {
-		D("Failed to sendmsg to netlink socket (err=%d)", ret);
+		nm_prerr("Failed to sendmsg to netlink socket (err=%d)", ret);
 		ret = -EINVAL;
 		goto release;
 	}
 	ret = 0;
 
-	D("ifp %s qdisc %s parent %u handle %u", ifp->name, qdisc_name, parent, handle);
+	nm_prinf("ifp %s qdisc %s parent %u handle %u", ifp->name, qdisc_name, parent, handle);
 
 release:
 	sock_release(sock);
@@ -887,7 +887,7 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 	int err;
 
 	if (!ifp) {
-		D("Failed to get ifp");
+		nm_prerr("Failed to get ifp");
 		return -1;
 	}
 
@@ -912,7 +912,7 @@ nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 		gna->up.nm_ndo = *ifp->netdev_ops; /* copy all, replace some */
 		gna->up.nm_ndo.ndo_start_xmit = &generic_ndo_start_xmit;
 #ifndef NETMAP_LINUX_SELECT_QUEUE
-		D("No packet steering support");
+		nm_prerr("No packet steering support");
 #else
 		gna->up.nm_ndo.ndo_select_queue = &generic_ndo_select_queue;
 #endif
@@ -1023,7 +1023,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	m->priority = a->qevent ? NM_MAGIC_PRIORITY_TXQE : NM_MAGIC_PRIORITY_TX;
 
 	if (unlikely(m->next)) {
-		RD(1, "Warning: resetting skb->next as it is not NULL\n");
+		nm_prlim(1, "Warning: resetting skb->next as it is not NULL\n");
 		m->next = NULL;
 	}
 
@@ -1045,7 +1045,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 		 * field), and so the temporary noop qdisc enqueue
 		 * method will drop the packet and return NET_XMIT_CN.
 		 */
-		RD(3, "Warning: dev_queue_xmit() is dropping [%d]", ret);
+		nm_prlim(3, "Warning: dev_queue_xmit() is dropping [%d]", ret);
 		return -1;
 	}
 
@@ -1074,11 +1074,11 @@ nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *r
 		*tx = rp.tx_pending ? rp.tx_pending : rp.tx_max_pending;
 		*rx = rp.rx_pending ? rp.rx_pending : rp.rx_max_pending;
 		if (*rx < 3) {
-			D("Invalid RX ring size %u, using default", *rx);
+			nm_prerr("Invalid RX ring size %u, using default", *rx);
 			*rx = netmap_generic_ringsize;
 		}
 		if (*tx < 3) {
-			D("Invalid TX ring size %u, using default", *tx);
+			nm_prerr("Invalid TX ring size %u, using default", *tx);
 			*tx = netmap_generic_ringsize;
 		}
 		error = 0;
@@ -1121,7 +1121,7 @@ netmap_rings_config_get(struct netmap_adapter *na, struct nm_config_info *info)
 	rtnl_lock();
 
 	if (ifp == NULL) {
-		D("zombie adapter");
+		nm_prerr("zombie adapter");
 		error = ENXIO;
 		goto out;
 	}
@@ -1228,7 +1228,7 @@ linux_netmap_fault(struct vm_fault *vmf)
 	unsigned long pa, pfn;
 
 	pa = netmap_mem_ofstophys(na->nm_mem, off);
-	ND("fault off %lx -> phys addr %lx", off, pa);
+	nm_prdis("fault off %lx -> phys addr %lx", off, pa);
 	if (pa == 0)
 		return VM_FAULT_SIGBUS;
 	pfn = pa >> PAGE_SHIFT;
@@ -1266,11 +1266,11 @@ linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
 
 	/* check that [off, off + vsize) is within our memory */
 	error = netmap_mem_get_info(na->nm_mem, &memsize, &memflags, NULL);
-	ND("get_info returned %d", error);
+	nm_prdis("get_info returned %d", error);
 	if (error)
 		return -error;
 	off = vma->vm_pgoff << PAGE_SHIFT;
-	ND("off %lx size %lx memsize %x", off,
+	nm_prdis("off %lx size %lx memsize %x", off,
 			(vma->vm_end - vma->vm_start), memsize);
 	if (off + (vma->vm_end - vma->vm_start) > memsize)
 		return -EINVAL;
@@ -1801,7 +1801,7 @@ nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr,
 	*mem_size = ioread32(ptn_dev->pci_io + PTNET_MDEV_IO_MEMSIZE_LO) |
 		(*mem_size << 32);
 
-	D("=== BAR %d start %llx len %llx mem_size %lx ===",
+	nm_prinf("=== BAR %d start %llx len %llx mem_size %lx ===",
 			PTNETMAP_MEM_PCI_BAR,
 			pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
 			pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR),
@@ -1969,7 +1969,7 @@ ptnetmap_guest_init(void)
 	/* register pci driver */
 	ret = pci_register_driver(&ptnetmap_guest_drivers);
 	if (ret < 0) {
-		D("Failed to register drivers");
+		nm_prerr("Failed to register drivers");
 		return ret;
 	}
 
@@ -2175,14 +2175,14 @@ static int linux_netmap_init(void)
 #ifdef WITH_SINK
 	err = netmap_sink_init();
 	if (err) {
-		D("Error: could not init netmap sink interface");
+		nm_prerr("Error: could not init netmap sink interface");
 		goto ptnetmap_fini;
 	}
 #endif /* WITH_SINK */
 #ifdef WITH_GENERIC
 	err = register_qdisc(&generic_qdisc_ops);
 	if (err) {
-		D("Error: failed to register qdisc for emulated netmap (err=%d)", err);
+		nm_prerr("Error: failed to register qdisc for emulated netmap (err=%d)", err);
 		goto sink_fini;
 	}
 #endif /* WITH_GENERIC */
@@ -2325,7 +2325,7 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 	ifp->dev.driver = &linux_dummy_drv;
 	error = register_netdev(ifp);
 	if (error < 0) {
-		D("error %d", error);
+		nm_prerr("error %d", error);
 		error = -error;
 		goto err_free;
 	}

From e5137f207d5bde35dd8386d46e2888e870f9584e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 16:12:37 +0100
Subject: [PATCH 1429/2207] null: switch to nm_pr* logging functions

---
 sys/dev/netmap/netmap_null.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index 6197ca5c4..4f0c64720 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -132,17 +132,17 @@ netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	int error;
 
 	if (req->nr_mode != NR_REG_NULL) {
-		ND("not a null port");
+		nm_prdis("not a null port");
 		return 0;
 	}
 
 	if (!create) {
-		D("null ports cannot be re-opened");
+		nm_prerr("null ports cannot be re-opened");
 		return EINVAL;
 	}
 
 	if (nmd == NULL) {
-		D("null ports must use an existing allocator");
+		nm_prerr("null ports must use an existing allocator");
 		return EINVAL;
 	}
 
@@ -169,7 +169,7 @@ netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	if (error)
 		goto free_nna;
 	*na = &nna->up;
-	D("created null %s", nna->up.name);
+	nm_prdis("created null %s", nna->up.name);
 
 	return 0;
 

From 17792ff87e163cae89c01713c593959eb326a9a5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 17 Nov 2018 16:16:19 +0100
Subject: [PATCH 1430/2207] kloop: switch to nm_pr* logging functions

---
 sys/dev/netmap/netmap_kloop.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index ffb28d192..e2e9ee4ec 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -171,7 +171,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 
 			if (head_lim >= num_slots)
 				head_lim -= num_slots;
-			ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
+			nm_prdis(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head,
 					head_lim);
 			shadow_ring.head = head_lim;
 			batch = PTN_TX_BATCH_LIM(num_slots);
@@ -252,7 +252,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (nm_kr_txempty(kring)) {
 			/* No more available TX slots. We stop waiting for a notification
 			 * from the backend (netmap_tx_irq). */
-			ND(1, "TX ring");
+			nm_prdis(1, "TX ring");
 			break;
 		}
 	}
@@ -372,7 +372,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 					dry_cycles >= SYNC_LOOP_RX_DRY_CYCLES_MAX)) {
 			/* No more packets to be read from the backend. We stop and
 			 * wait for a notification from the backend (netmap_rx_irq). */
-			ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
+			nm_prdis(1, "nr_hwtail: %d rhead: %d dry_cycles: %d",
 					hwtail, kring->rhead, dry_cycles);
 			break;
 		}
@@ -750,7 +750,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 		}
 	}
 
-	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
+	nm_prdis(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
 		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 
@@ -815,7 +815,7 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
                 }
         }
 
-	ND(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
+	nm_prdis(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
 		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);
 

From 9a5e4a1792e5001dce286618d70275d6ca9b423d Mon Sep 17 00:00:00 2001
From: Grant Curell 
Date: Mon, 19 Nov 2018 11:18:55 -0600
Subject: [PATCH 1431/2207] Update help message in nmreplay

Signed-off-by: Grant Curell 
---
 apps/nmreplay/nmreplay.8 | 4 +++-
 apps/nmreplay/nmreplay.c | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/apps/nmreplay/nmreplay.8 b/apps/nmreplay/nmreplay.8
index 4b8f3a2ca..5279af8bf 100644
--- a/apps/nmreplay/nmreplay.8
+++ b/apps/nmreplay/nmreplay.8
@@ -62,7 +62,9 @@ Command line options are as follows
 .It Fl f Ar pcap-file
 Name of the pcap file to replay.
 .It Fl i Ar interface
-Name of the netmap interface to use as output.
+Name of the netmap interface to use as output. See
+.Xr netmap 4
+for interface name format.
 .It Fl v
 Enable verbose mode
 .It Fl b Ar batch-size
diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index c93e8f8c7..759a8338d 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -972,7 +972,7 @@ usage(void)
 {
 	fprintf(stderr,
 	    "usage: nmreplay [-v] [-D delay] [-B {[constant,]bps|ether,bps|real,speedup}] [-L loss]\n"
-	    "\t[-b burst] -f pcap-file -i ifb\n");
+	    "\t[-b burst] -f pcap-file -i \n");
 	exit(1);
 }
 

From ae888a0b486068af1cbfb45cce685247c10c9121 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 20 Nov 2018 14:51:34 +0100
Subject: [PATCH 1432/2207] update netmap(4) man page

---
 share/man/man4/netmap.4 | 115 ++++++++++++++++++++++------------------
 1 file changed, 63 insertions(+), 52 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 03f366bd8..3ee7ccf13 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -27,17 +27,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 31, 2018
+.Dd November 20, 2018
 .Dt NETMAP 4
 .Os
 .Sh NAME
 .Nm netmap
 .Nd a framework for fast packet I/O
-.Nm VALE
-.Nd a fast VirtuAl Local Ethernet using the netmap API
-.Pp
-.Nm netmap pipes
-.Nd a shared memory packet transport channel
 .Sh SYNOPSIS
 .Cd device netmap
 .Sh DESCRIPTION
@@ -79,7 +74,7 @@ with much less than one core on 10 Gbit/s NICs;
 35-40 Mpps on 40 Gbit/s NICs (limited by the hardware);
 about 20 Mpps per core for VALE ports;
 and over 100 Mpps for
-.Nm netmap pipes.
+.Nm netmap pipes .
 NICs without native
 .Nm
 support can still use the API in emulated mode,
@@ -108,9 +103,9 @@ synchronization and blocking I/O through a file descriptor
 and standard OS mechanisms such as
 .Xr select 2 ,
 .Xr poll 2 ,
-.Xr epoll 2 ,
+.Xr kqueue 2
 and
-.Xr kqueue 2 .
+.Xr epoll 7 .
 All types of
 .Nm netmap ports
 and the
@@ -238,7 +233,7 @@ which is the ultimate reference for the
 API.
 The main structures and fields are indicated below:
 .Bl -tag -width XXX
-.It Dv struct netmap_if (one per interface)
+.It Dv struct netmap_if (one per interface )
 .Bd -literal
 struct netmap_if {
     ...
@@ -260,10 +255,12 @@ normally depends on the hardware.
 NICs also have an extra tx/rx ring pair connected to the host stack.
 .Em NIOCREGIF
 can also request additional unbound buffers in the same memory space,
-to be used as temporary storage for packets. The number of extra
+to be used as temporary storage for packets.
+The number of extra
 buffers is specified in the
 .Va arg.nr_arg3
-field. On success, the kernel writes back to
+field.
+On success, the kernel writes back to
 .Va arg.nr_arg3
 the number of extra buffers actually allocated (they may be less
 than the amount requested if the memory space ran out of buffers).
@@ -273,14 +270,16 @@ which are connected in a list (the first uint32_t of each
 buffer being the index of the next buffer in the list).
 A
 .Dv 0
-indicates the end of the list. The application is free to modify
+indicates the end of the list.
+The application is free to modify
 this list and use the buffers (i.e., binding them to the slots of a
-netmap ring). When closing the netmap file descriptor,
+netmap ring).
+When closing the netmap file descriptor,
 the kernel frees the buffers contained in the list pointed by
 .Pa ni_bufs_head
 , irrespectively of the buffers originally provided by the kernel on
-.Em NIOCREGIF.
-.It Dv struct netmap_ring (one per ring)
+.Em NIOCREGIF .
+.It Dv struct netmap_ring (one per ring )
 .Bd -literal
 struct netmap_ring {
     ...
@@ -302,7 +301,7 @@ Implements transmit and receive rings, with read/write
 pointers, metadata and an array of
 .Em slots
 describing the buffers.
-.It Dv struct netmap_slot (one per buffer)
+.It Dv struct netmap_slot (one per buffer )
 .Bd -literal
 struct netmap_slot {
     uint32_t buf_idx;           /* buffer index                 */
@@ -377,7 +376,6 @@ during the execution of a netmap-related system call.
 The only exception are slots (and buffers) in the range
 .Va tail\  . . . head-1 ,
 that are explicitly assigned to the kernel.
-.Pp
 .Ss TRANSMIT RINGS
 On transmit rings, after a
 .Nm
@@ -674,7 +672,7 @@ and does not need to be sequential.
 On return the pipe
 will only have a single ring pair with index 0,
 irrespective of the value of
-.Va i.
+.Va i .
 .El
 .Pp
 By default, a
@@ -686,11 +684,14 @@ no write events are specified.
 The feature can be disabled by or-ing
 .Va NETMAP_NO_TX_POLL
 to the value written to
-.Va nr_ringid.
+.Va nr_ringid .
 When this feature is used,
 packets are transmitted only on
 .Va ioctl(NIOCTXSYNC)
-or select()/poll() are called with a write event (POLLOUT/wfdset) or a full ring.
+or
+.Va select() /
+.Va poll()
+are called with a write event (POLLOUT/wfdset) or a full ring.
 .Pp
 When registering a virtual interface that is dynamically created to a
 .Xr vale 4
@@ -703,7 +704,7 @@ number of slots available for transmission.
 tells the hardware of consumed packets, and asks for newly available
 packets.
 .El
-.Sh SELECT, POLL, EPOLL, KQUEUE.
+.Sh SELECT, POLL, EPOLL, KQUEUE
 .Xr select 2
 and
 .Xr poll 2
@@ -717,7 +718,7 @@ respectively when write (POLLOUT) and read (POLLIN) events are requested.
 Both block if no slots are available in the ring
 .Va ( ring->cur == ring->tail ) .
 Depending on the platform,
-.Xr epoll 2
+.Xr epoll 7
 and
 .Xr kqueue 2
 are supported too.
@@ -736,7 +737,10 @@ Passing the
 .Dv NETMAP_DO_RX_POLL
 flag to
 .Em NIOCREGIF updates receive rings even without read events.
-Note that on epoll and kqueue,
+Note that on
+.Xr epoll 7
+and
+.Xr kqueue 2 ,
 .Dv NETMAP_NO_TX_POLL
 and
 .Dv NETMAP_DO_RX_POLL
@@ -764,9 +768,9 @@ before
 .Pp
 The following functions are available:
 .Bl -tag -width XXXXX
-.It Va  struct nm_desc * nm_open(const char *ifname, const struct nmreq *req, uint64_t flags, const struct nm_desc *arg)
+.It Va  struct nm_desc * nm_open(const char *ifname, const struct nmreq *req, uint64_t flags, const struct nm_desc *arg )
 similar to
-.Xr pcap_open 3pcap ,
+.Xr pcap_open_live 3 ,
 binds a file descriptor to a port.
 .Bl -tag -width XX
 .It Va ifname
@@ -787,44 +791,50 @@ can be set to a combination of the following flags:
 .Va NETMAP_NO_TX_POLL ,
 .Va NETMAP_DO_RX_POLL
 (copied into nr_ringid);
-.Va NM_OPEN_NO_MMAP (if arg points to the same memory region,
+.Va NM_OPEN_NO_MMAP
+(if arg points to the same memory region,
 avoids the mmap and uses the values from it);
-.Va NM_OPEN_IFNAME (ignores ifname and uses the values in arg);
+.Va NM_OPEN_IFNAME
+(ignores ifname and uses the values in arg);
 .Va NM_OPEN_ARG1 ,
 .Va NM_OPEN_ARG2 ,
-.Va NM_OPEN_ARG3 (uses the fields from arg);
-.Va NM_OPEN_RING_CFG (uses the ring number and sizes from arg).
+.Va NM_OPEN_ARG3
+(uses the fields from arg);
+.Va NM_OPEN_RING_CFG
+(uses the ring number and sizes from arg).
 .El
-.It Va int nm_close(struct nm_desc *d)
+.It Va int nm_close(struct nm_desc *d )
 closes the file descriptor, unmaps memory, frees resources.
-.It Va int nm_inject(struct nm_desc *d, const void *buf, size_t size)
-similar to pcap_inject(), pushes a packet to a ring, returns the size
+.It Va int nm_inject(struct nm_desc *d, const void *buf, size_t size )
+similar to
+.Va pcap_inject() ,
+pushes a packet to a ring, returns the size
 of the packet is successful, or 0 on error;
-.It Va int nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
-similar to pcap_dispatch(), applies a callback to incoming packets
-.It Va u_char * nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr)
-similar to pcap_next(), fetches the next packet
+.It Va int nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg )
+similar to
+.Va pcap_dispatch() ,
+applies a callback to incoming packets
+.It Va u_char * nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr )
+similar to
+.Va pcap_next() ,
+fetches the next packet
 .El
 .Sh SUPPORTED DEVICES
 .Nm
 natively supports the following devices:
 .Pp
-On FreeBSD:
+On
+.Fx :
 .Xr cxgbe 4 ,
 .Xr em 4 ,
-.Xr igb 4 ,
+.Xr iflib 4
+(providing igb, em and lem),
 .Xr ixgbe 4 ,
 .Xr ixl 4 ,
-.Xr lem 4 ,
-.Xr re 4 .
-.Pp
-On Linux
-.Xr e1000 4 ,
-.Xr e1000e 4 ,
-.Xr i40e 4 ,
-.Xr igb 4 ,
-.Xr ixgbe 4 ,
-.Xr r8169 4 .
+.Xr re 4 ,
+.Xr vtnet 4 .
+.Pp
+On Linux e1000, e1000e, i40e, igb, ixgbe, ixgbevf, r8169, virtio_net, vmxnet3.
 .Pp
 NICs without native support can still be used in
 .Nm
@@ -853,10 +863,11 @@ globally controls how netmap mode is implemented.
 .Sh SYSCTL VARIABLES AND MODULE PARAMETERS
 Some aspect of the operation of
 .Nm
-are controlled through sysctl variables on FreeBSD
+are controlled through sysctl variables on
+.Fx
 .Em ( dev.netmap.* )
 and module parameters on Linux
-.Em ( /sys/module/netmap_lin/parameters/* ) :
+.Em ( /sys/module/netmap/parameters/* ) :
 .Bl -tag -width indent
 .It Va dev.netmap.admode: 0
 Controls the use of native or emulated adapter mode.
@@ -917,7 +928,7 @@ Allow ptnet devices to use virtio-net headers
 uses
 .Xr select 2 ,
 .Xr poll 2 ,
-.Xr epoll 2
+.Xr epoll 7
 and
 .Xr kqueue 2
 to wake up processes when significant events occur, and

From 6a96964a3143baef5985104239f3f3808ee288cd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 20 Nov 2018 16:43:06 +0100
Subject: [PATCH 1433/2207] linux/i40e: show the netmap driver suffix in the
 driver name

---
 LINUX/i40e_netmap_linux.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 3dcf5d056..f9a3ed3a7 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -62,6 +62,9 @@ extern int ix_crcstrip;
 #endif
 
 #ifdef NETMAP_I40E_MAIN
+
+#define i40e_driver_name netmap_i40e_driver_name
+char i40e_driver_name[] = "i40e" NETMAP_LINUX_DRIVER_SUFFIX;
 /*
  * device-specific sysctl variables:
  *

From ee4ce9111f6f32d0acec7ec52c4fa92d1720fe02 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 20 Nov 2018 17:59:05 +0100
Subject: [PATCH 1434/2207] linux/i40e: use netmap bufsize for rx bufsize

---
 LINUX/i40e_netmap_linux.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index f9a3ed3a7..17d4700cb 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -229,15 +229,13 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 static int
 i40e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
-	struct i40e_netdev_priv *np = netdev_priv(na->ifp);
-	struct i40e_vsi  *vsi = np->vsi;
 	int ret = netmap_rings_config_get(na, info);
 
 	if (ret) {
 		return ret;
 	}
 
-	info->rx_buf_maxsize = vsi->rx_buf_len;
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
 	return 0;
 }

From d39b89da13daea20591960847bcfc6be1dbc52c2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Nov 2018 10:13:25 +0100
Subject: [PATCH 1435/2207] linux/igb: show the netmap suffix in the driver
 name

---
 LINUX/final-patches/intel--igb--5.3.5.10 | 18 +++++++++---------
 LINUX/final-patches/intel--igb--5.3.5.12 | 14 +++++++-------
 LINUX/final-patches/intel--igb--5.3.5.15 | 18 +++++++++---------
 LINUX/final-patches/intel--igb--5.3.5.18 | 14 +++++++-------
 LINUX/final-patches/intel--igb--5.3.5.20 | 14 +++++++-------
 LINUX/final-patches/intel--igb--5.3.5.4  | 14 +++++++-------
 6 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/LINUX/final-patches/intel--igb--5.3.5.10 b/LINUX/final-patches/intel--igb--5.3.5.10
index d1b9580f4..28975852e 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.10
+++ b/LINUX/final-patches/intel--igb--5.3.5.10
@@ -1,4 +1,4 @@
-diff --git a/igb/Makefile b/src/Makefile
+diff --git a/igb/Makefile b/igb/Makefile
 index e3bd4f3..ef900a4 100644
 --- a/igb/Makefile
 +++ b/igb/Makefile
@@ -50,21 +50,21 @@ index e3bd4f3..ef900a4 100644
  # Clean the module subdirectories
  clean:
  	@+$(call devkernelbuild,clean)
-diff --git a/igb/igb_main.c b/src/igb_main.c
-index 3ee1ec7..b6809c6 100644
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 3ee1ec7..3746d0b 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+@@ -258,6 +258,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
 +
- /**
-  * igb_init_module - Driver Registration Routine
-  *
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
 @@ -3052,6 +3056,10 @@ static int igb_probe(struct pci_dev *pdev,
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
diff --git a/LINUX/final-patches/intel--igb--5.3.5.12 b/LINUX/final-patches/intel--igb--5.3.5.12
index 9e4f55e73..fc627211b 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.12
+++ b/LINUX/final-patches/intel--igb--5.3.5.12
@@ -54,20 +54,20 @@ index e3bd4f3..2f6895a 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 6c9b112..65a4e93 100644
+index 6c9b112..0c65b25 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+@@ -258,6 +258,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
 +
- /**
-  * igb_init_module - Driver Registration Routine
-  *
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
 @@ -3061,6 +3065,10 @@ static int igb_probe(struct pci_dev *pdev,
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
diff --git a/LINUX/final-patches/intel--igb--5.3.5.15 b/LINUX/final-patches/intel--igb--5.3.5.15
index c01a0326f..09b17a9cd 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.15
+++ b/LINUX/final-patches/intel--igb--5.3.5.15
@@ -1,5 +1,5 @@
 diff --git a/igb/Makefile b/igb/Makefile
-index e3bd4f3..eb59e33 100644
+index e3bd4f3..2f6895a 100644
 --- a/igb/Makefile
 +++ b/igb/Makefile
 @@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
@@ -19,7 +19,7 @@ index e3bd4f3..eb59e33 100644
  	e1000_i210.o
  endef
 -igb-y := $(strip ${igb-y})
-+igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
  
 -igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
 +igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
@@ -54,20 +54,20 @@ index e3bd4f3..eb59e33 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index f6faafc..11d8097 100644
+index f6faafc..0bb4c07 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+@@ -258,6 +258,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
 +
- /**
-  * igb_init_module - Driver Registration Routine
-  *
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
 @@ -3061,6 +3065,10 @@ static int igb_probe(struct pci_dev *pdev,
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
diff --git a/LINUX/final-patches/intel--igb--5.3.5.18 b/LINUX/final-patches/intel--igb--5.3.5.18
index a668552f8..21365c277 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.18
+++ b/LINUX/final-patches/intel--igb--5.3.5.18
@@ -50,20 +50,20 @@ index 02d49bb..1267d14 100644
  manfile:
  	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index b98cfa6..13b17ea 100644
+index b98cfa6..928cb8e 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+@@ -258,6 +258,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
 +
- /**
-  * igb_init_module - Driver Registration Routine
-  *
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
 @@ -3073,6 +3077,10 @@ static int igb_probe(struct pci_dev *pdev,
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
diff --git a/LINUX/final-patches/intel--igb--5.3.5.20 b/LINUX/final-patches/intel--igb--5.3.5.20
index c01e85e7f..9523f1cf9 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.20
+++ b/LINUX/final-patches/intel--igb--5.3.5.20
@@ -54,20 +54,20 @@ index 02d49bb..1c88549 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index f7f9095..86990f4 100644
+index f7f9095..fde3f7c 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -317,6 +317,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+@@ -258,6 +258,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
 +
- /**
-  * igb_init_module - Driver Registration Routine
-  *
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
 @@ -3071,6 +3075,10 @@ static int igb_probe(struct pci_dev *pdev,
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
diff --git a/LINUX/final-patches/intel--igb--5.3.5.4 b/LINUX/final-patches/intel--igb--5.3.5.4
index d66a00dc7..e26d7d09a 100644
--- a/LINUX/final-patches/intel--igb--5.3.5.4
+++ b/LINUX/final-patches/intel--igb--5.3.5.4
@@ -31,20 +31,20 @@ index 8e962f7..2c10939 100644
  	install -D -m 644 $(TARGET) $(INSTALL_MOD_PATH)$(INSTDIR)/$(TARGET)
  ifeq (,$(INSTALL_MOD_PATH))
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 2dff0f4..d848e34 100644
+index 2dff0f4..251b755 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -318,6 +318,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+@@ -259,6 +259,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#include 
 +#endif
 +
- /**
-  * igb_init_module - Driver Registration Routine
-  *
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
 @@ -3041,6 +3045,10 @@ static int igb_probe(struct pci_dev *pdev,
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);

From 8dd0aadb5a3fbe15c3b14723cb017f7584b57823 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Nov 2018 12:49:54 +0100
Subject: [PATCH 1436/2207] differentiate between debugging and verbose
 messages

---
 LINUX/bsd_glue.h               |   2 +-
 sys/dev/netmap/netmap.c        | 132 ++++++++++++++++++++-------------
 sys/dev/netmap/netmap_kern.h   |  27 ++++---
 sys/dev/netmap/netmap_kloop.c  |   8 +-
 sys/dev/netmap/netmap_legacy.c |   4 +-
 sys/dev/netmap/netmap_mem2.c   | 126 ++++++++++++++++---------------
 6 files changed, 173 insertions(+), 126 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 24b2433ea..0c56323c6 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -459,7 +459,7 @@ struct nm_linux_selrecord_t;
  */
 #define make_dev_credf(_flags, _cdev, _zero, _cred, _uid, _gid, _perm, _name)	\
 	({error = misc_register(_cdev);				\
-	D("run mknod /dev/%s c %d %d # returned %d",		\
+	nm_prinf("run mknod /dev/%s c %d %d # returned %d",	\
 	    (_cdev)->name, MISC_MAJOR, (_cdev)->minor, error);	\
 	 _cdev; } )
 #define destroy_dev(_cdev)	misc_deregister(_cdev)
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 88ba7d78a..49047510f 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -480,6 +480,9 @@ ports attached to the switch)
 
 /* user-controlled variables */
 int netmap_verbose;
+#ifdef CONFIG_NETMAP_DEBUG
+int netmap_debug;
+#endif /* CONFIG_NETMAP_DEBUG */
 
 static int netmap_no_timestamp; /* don't timestamp on rxsync */
 int netmap_no_pendintr = 1;
@@ -537,6 +540,10 @@ SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
 		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
+#ifdef CONFIG_NETMAP_DEBUG
+SYSCTL_INT(_dev_netmap, OID_AUTO, debug,
+		CTLFLAG_RW, &netmap_debug, 0, "Debug messages");
+#endif /* CONFIG_NETMAP_DEBUG */
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
 		CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, CTLFLAG_RW, &netmap_no_pendintr,
@@ -771,13 +778,14 @@ netmap_update_config(struct netmap_adapter *na)
 		na->num_rx_rings = info.num_rx_rings;
 		na->num_rx_desc = info.num_rx_descs;
 		na->rx_buf_maxsize = info.rx_buf_maxsize;
-		D("configuration changed for %s: txring %d x %d, "
-			"rxring %d x %d, rxbufsz %d",
-			na->name, na->num_tx_rings, na->num_tx_desc,
-			na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
+		if (netmap_verbose)
+			nm_prinf("configuration changed for %s: txring %d x %d, "
+				"rxring %d x %d, rxbufsz %d",
+				na->name, na->num_tx_rings, na->num_tx_desc,
+				na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
 		return 0;
 	}
-	D("WARNING: configuration changed for %s while active: "
+	nm_prerr("WARNING: configuration changed for %s while active: "
 		"txring %d x %d, rxring %d x %d, rxbufsz %d",
 		na->name, info.num_tx_rings, info.num_tx_descs,
 		info.num_rx_rings, info.num_rx_descs,
@@ -823,7 +831,8 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	enum txrx t;
 
 	if (na->tx_rings != NULL) {
-		D("warning: krings were already created");
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prerr("warning: krings were already created");
 		return 0;
 	}
 
@@ -837,7 +846,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 
 	na->tx_rings = nm_os_malloc((size_t)len);
 	if (na->tx_rings == NULL) {
-		D("Cannot allocate krings");
+		nm_prerr("Cannot allocate krings");
 		return ENOMEM;
 	}
 	na->rx_rings = na->tx_rings + n[NR_TX];
@@ -905,7 +914,8 @@ netmap_krings_delete(struct netmap_adapter *na)
 	enum txrx t;
 
 	if (na->tx_rings == NULL) {
-		D("warning: krings were already deleted");
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prerr("warning: krings were already deleted");
 		return;
 	}
 
@@ -1007,11 +1017,11 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 		 * happens if the close() occurs while a concurrent
 		 * syscall is running.
 		 */
-		if (netmap_verbose)
-			D("deleting last instance for %s", na->name);
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prinf("deleting last instance for %s", na->name);
 
 		if (nm_netmap_on(na)) {
-			D("BUG: netmap on while going to delete the krings");
+			nm_prerr("BUG: netmap on while going to delete the krings");
 		}
 
 		na->nm_krings_delete(na);
@@ -1123,8 +1133,8 @@ netmap_send_up(struct ifnet *dst, struct mbq *q)
 	/* Send packets up, outside the lock; head/prev machinery
 	 * is only useful for Windows. */
 	while ((m = mbq_dequeue(q)) != NULL) {
-		if (netmap_verbose & NM_VERB_HOST)
-			D("sending up pkt %p size %d", m, MBUF_LEN(m));
+		if (netmap_debug & NM_DEBUG_HOST)
+			nm_prinf("sending up pkt %p size %d", m, MBUF_LEN(m));
 		prev = nm_os_send_up(dst, m, prev);
 		if (head == NULL)
 			head = prev;
@@ -1319,8 +1329,8 @@ netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
 
 			m_copydata(m, 0, len, NMB(na, slot));
 			ND("nm %d len %d", nm_i, len);
-			if (netmap_verbose)
-				D("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
+			if (netmap_debug & NM_DEBUG_HOST)
+				nm_prinf("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
 
 			slot->len = len;
 			slot->flags = 0;
@@ -1487,7 +1497,7 @@ netmap_get_na(struct nmreq_header *hdr,
 	if (req->nr_mode == NR_REG_PIPE_MASTER ||
 			req->nr_mode == NR_REG_PIPE_SLAVE) {
 		/* Do not accept deprecated pipe modes. */
-		D("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
+		nm_prerr("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
 		return EINVAL;
 	}
 
@@ -1811,7 +1821,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 		case NR_REG_SW:
 		case NR_REG_NIC_SW:
 			if (!(na->na_flags & NAF_HOST_RINGS)) {
-				D("host rings not supported");
+				nm_prerr("host rings not supported");
 				return EINVAL;
 			}
 			priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
@@ -1824,7 +1834,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 		case NR_REG_ONE_NIC:
 			if (nr_ringid >= na->num_tx_rings &&
 					nr_ringid >= na->num_rx_rings) {
-				D("invalid ring id %d", nr_ringid);
+				nm_prerr("invalid ring id %d", nr_ringid);
 				return EINVAL;
 			}
 			/* if not enough rings, use the first one */
@@ -1837,7 +1847,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		default:
-			D("invalid regif type %d", nr_mode);
+			nm_prerr("invalid regif type %d", nr_mode);
 			return EINVAL;
 		}
 	}
@@ -1851,7 +1861,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 	}
 
 	if (netmap_verbose) {
-		D("%s: tx [%d,%d) rx [%d,%d) id %d",
+		nm_prinf("%s: tx [%d,%d) rx [%d,%d) id %d",
 			na->name,
 			priv->np_qfirst[NR_TX],
 			priv->np_qlast[NR_TX],
@@ -1924,8 +1934,8 @@ netmap_krings_get(struct netmap_priv_d *priv)
 	int excl = (priv->np_flags & NR_EXCLUSIVE);
 	enum txrx t;
 
-	if (netmap_verbose)
-		D("%s: grabbing tx [%d, %d) rx [%d, %d)",
+	if (netmap_debug & NM_DEBUG_ON)
+		nm_prinf("%s: grabbing tx [%d, %d) rx [%d, %d)",
 			na->name,
 			priv->np_qfirst[NR_TX],
 			priv->np_qlast[NR_TX],
@@ -2222,7 +2232,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 					na->name, mtu, na->rx_buf_maxsize, nbs);
 
 			if (na->rx_buf_maxsize == 0) {
-				D("%s: error: rx_buf_maxsize == 0", na->name);
+				nm_prerr("%s: error: rx_buf_maxsize == 0", na->name);
 				error = EIO;
 				goto err_drop_mem;
 			}
@@ -2402,7 +2412,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 		if (hdr->nr_version < NETMAP_MIN_API ||
 		    hdr->nr_version > NETMAP_MAX_API) {
-			D("API mismatch: got %d need %d",
+			nm_prerr("API mismatch: got %d need %d",
 				hdr->nr_version, NETMAP_API);
 			return EINVAL;
 		}
@@ -2432,8 +2442,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			do {
 				struct nmreq_option *opt;
 				u_int memflags;
-#ifdef WITH_EXTMEM
-#endif /* WITH_EXTMEM */
 
 				if (priv->np_nifp != NULL) {	/* thread already registered */
 					error = EBUSY;
@@ -2464,6 +2472,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					/* find the allocator and get a reference */
 					nmd = netmap_mem_find(req->nr_mem_id);
 					if (nmd == NULL) {
+						if (netmap_verbose) {
+							nm_prerr("%s: failed to find mem_id %u",
+									hdr->nr_name, req->nr_mem_id);
+						}
 						error = EINVAL;
 						break;
 					}
@@ -2479,7 +2491,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 				if (na->virt_hdr_len && !(req->nr_flags & NR_ACCEPT_VNET_HDR)) {
-					D("virt_hdr_len=%d, but application does "
+					nm_prerr("virt_hdr_len=%d, but application does "
 						"not accept it", na->virt_hdr_len);
 					error = EIO;
 					break;
@@ -2531,12 +2543,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 
 				if (req->nr_extra_bufs) {
 					if (netmap_verbose)
-						D("requested %d extra buffers",
+						nm_prinf("requested %d extra buffers",
 							req->nr_extra_bufs);
 					req->nr_extra_bufs = netmap_extra_alloc(na,
 						&nifp->ni_bufs_head, req->nr_extra_bufs);
 					if (netmap_verbose)
-						D("got %d extra buffers", req->nr_extra_bufs);
+						nm_prinf("got %d extra buffers", req->nr_extra_bufs);
 				}
 				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
 
@@ -2596,6 +2608,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				} else {
 					nmd = netmap_mem_find(req->nr_mem_id ? req->nr_mem_id : 1);
 					if (nmd == NULL) {
+						if (netmap_verbose)
+							nm_prerr("%s: failed to find mem_id %u",
+									hdr->nr_name,
+									req->nr_mem_id ? req->nr_mem_id : 1);
 						error = EINVAL;
 						break;
 					}
@@ -2648,6 +2664,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			if (req->nr_hdr_len != 0 &&
 				req->nr_hdr_len != sizeof(struct nm_vnet_hdr) &&
 					req->nr_hdr_len != 12) {
+				if (netmap_verbose)
+					nm_prerr("invalid hdr_len %u", req->nr_hdr_len);
 				error = EINVAL;
 				break;
 			}
@@ -2664,7 +2682,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				if (na->virt_hdr_len) {
 					vpna->mfs = NETMAP_BUF_SIZE(na);
 				}
-				D("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
+				if (netmap_verbose)
+					nm_prinf("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
 				netmap_adapter_put(na);
 			} else if (!na) {
 				error = ENXIO;
@@ -2833,8 +2852,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			}
 
 			if (cmd == NIOCTXSYNC) {
-				if (netmap_verbose & NM_VERB_TXSYNC)
-					D("pre txsync ring %d cur %d hwcur %d",
+				if (netmap_debug & NM_DEBUG_TXSYNC)
+					nm_prinf("pre txsync ring %d cur %d hwcur %d",
 					    i, ring->cur,
 					    kring->nr_hwcur);
 				if (nm_txsync_prologue(kring, ring) >= kring->nkr_num_slots) {
@@ -2842,8 +2861,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				} else if (kring->nm_sync(kring, sync_flags | NAF_FORCE_RECLAIM) == 0) {
 					nm_sync_finalize(kring);
 				}
-				if (netmap_verbose & NM_VERB_TXSYNC)
-					D("post txsync ring %d cur %d hwcur %d",
+				if (netmap_debug & NM_DEBUG_TXSYNC)
+					nm_prinf("post txsync ring %d cur %d hwcur %d",
 					    i, ring->cur,
 					    kring->nr_hwcur);
 			} else {
@@ -2948,8 +2967,11 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	struct nmreq_option buf;
 	uint64_t *ptrs;
 
-	if (hdr->nr_reserved)
+	if (hdr->nr_reserved) {
+		if (netmap_verbose)
+			nm_prerr("nr_reserved must be zero");
 		return EINVAL;
+	}
 
 	if (!nr_body_is_user)
 		return 0;
@@ -2966,6 +2988,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		(!rqsz && hdr->nr_body != (uintptr_t)NULL)) {
 		/* Request body expected, but not found; or
 		 * request body found but unexpected. */
+		if (netmap_verbose)
+			nm_prerr("nr_body expected but not found, or vice versa");
 		error = EINVAL;
 		goto out_err;
 	}
@@ -3226,8 +3250,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		return POLLERR;
 	}
 
-	if (netmap_verbose & 0x8000)
-		D("device %s events 0x%x", na->name, events);
+	if (netmap_debug & NM_DEBUG_ON)
+		nm_prinf("device %s events 0x%x", na->name, events);
 	want_tx = events & (POLLOUT | POLLWRNORM);
 	want_rx = events & (POLLIN | POLLRDNORM);
 
@@ -3465,7 +3489,7 @@ nma_intr_enable(struct netmap_adapter *na, int onoff)
 	}
 
 	if (!na->nm_intr) {
-		D("Cannot %s interrupts for %s", onoff ? "enable" : "disable",
+		nm_prerr("Cannot %s interrupts for %s", onoff ? "enable" : "disable",
 		  na->name);
 		return -1;
 	}
@@ -3605,16 +3629,21 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 	struct ifnet *ifp = NULL;
 
 	if (size < sizeof(struct netmap_hw_adapter)) {
-		D("Invalid netmap adapter size %d", (int)size);
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prerr("Invalid netmap adapter size %d", (int)size);
 		return EINVAL;
 	}
 
-	if (arg == NULL || arg->ifp == NULL)
+	if (arg == NULL || arg->ifp == NULL) {
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prerr("either arg or arg->ifp is NULL");
 		return EINVAL;
+	}
 
 	if (arg->num_tx_rings == 0 || arg->num_rx_rings == 0) {
-		D("%s: invalid rings tx %d rx %d",
-			arg->name, arg->num_tx_rings, arg->num_rx_rings);
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prerr("%s: invalid rings tx %d rx %d",
+				arg->name, arg->num_tx_rings, arg->num_rx_rings);
 		return EINVAL;
 	}
 
@@ -3624,7 +3653,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		 * adapter it means that someone else is using the same
 		 * pointer (e.g. ax25_ptr on linux). This happens for
 		 * instance when also PF_RING is in use. */
-		D("Error: netmap adapter hook is busy");
+		nm_prerr("Error: netmap adapter hook is busy");
 		return EBUSY;
 	}
 
@@ -3658,7 +3687,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 	return 0;
 
 fail:
-	D("fail, arg %p ifp %p na %p", arg, ifp, hwna);
+	nm_prerr("fail, arg %p ifp %p na %p", arg, ifp, hwna);
 	return (hwna ? EINVAL : ENOMEM);
 }
 
@@ -3696,7 +3725,8 @@ NM_DBG(netmap_adapter_put)(struct netmap_adapter *na)
 		na->nm_dtor(na);
 
 	if (na->tx_rings) { /* XXX should not happen */
-		D("freeing leftover tx_rings");
+		if (netmap_debug & NM_DEBUG_ON)
+			nm_prerr("freeing leftover tx_rings");
 		na->nm_krings_delete(na);
 	}
 	netmap_pipe_dealloc(na);
@@ -3794,7 +3824,7 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	// mtx_lock(&na->core_lock);
 
 	if (!nm_netmap_on(na)) {
-		D("%s not in netmap mode anymore", na->name);
+		nm_prerr("%s not in netmap mode anymore", na->name);
 		error = ENXIO;
 		goto done;
 	}
@@ -3813,7 +3843,7 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 
 	// XXX reconsider long packets if we handle fragments
 	if (len > NETMAP_BUF_SIZE(na)) { /* too long for us */
-		D("%s from_host, drop packet size %d > %d", na->name,
+		nm_prerr("%s from_host, drop packet size %d > %d", na->name,
 			len, NETMAP_BUF_SIZE(na));
 		goto done;
 	}
@@ -3924,8 +3954,8 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 		new_hwofs -= lim + 1;
 
 	/* Always set the new offset value and realign the ring. */
-	if (netmap_verbose)
-	    D("%s %s%d hwofs %d -> %d, hwtail %d -> %d",
+	if (netmap_debug & NM_DEBUG_ON)
+	    nm_prinf("%s %s%d hwofs %d -> %d, hwtail %d -> %d",
 		na->name,
 		tx == NR_TX ? "TX" : "RX", n,
 		kring->nkr_hwofs, new_hwofs,
@@ -3971,8 +4001,8 @@ netmap_common_irq(struct netmap_adapter *na, u_int q, u_int *work_done)
 
 	q &= NETMAP_RING_MASK;
 
-	if (netmap_verbose) {
-	        RD(5, "received %s queue %d", work_done ? "RX" : "TX" , q);
+	if (netmap_debug & (NM_DEBUG_RXINTR|NM_DEBUG_TXINTR)) {
+	        nm_prlim(5, "received %s queue %d", work_done ? "RX" : "TX" , q);
 	}
 
 	if (q >= nma_get_nrings(na, t))
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 34442683f..870209adf 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1580,16 +1580,23 @@ int netmap_adapter_put(struct netmap_adapter *na);
 #define NETMAP_BUF_SIZE(_na)	((_na)->na_lut.objsize)
 extern int netmap_no_pendintr;
 extern int netmap_mitigate;
-extern int netmap_verbose;		/* for debugging */
-enum {                                  /* verbose flags */
-	NM_VERB_ON = 1,                 /* generic verbose */
-	NM_VERB_HOST = 0x2,             /* verbose host stack */
-	NM_VERB_RXSYNC = 0x10,          /* verbose on rxsync/txsync */
-	NM_VERB_TXSYNC = 0x20,
-	NM_VERB_RXINTR = 0x100,         /* verbose on rx/tx intr (driver) */
-	NM_VERB_TXINTR = 0x200,
-	NM_VERB_NIC_RXSYNC = 0x1000,    /* verbose on rx/tx intr (driver) */
-	NM_VERB_NIC_TXSYNC = 0x2000,
+extern int netmap_verbose;
+#ifdef CONFIG_NETMAP_DEBUG
+extern int netmap_debug;		/* for debugging */
+#else /* !CONFIG_NETMAP_DEBUG */
+#define netmap_debug (0)
+#endif /* !CONFIG_NETMAP_DEBUG */
+enum {                                  /* debug flags */
+	NM_DEBUG_ON = 1,		/* generic debug messsages */
+	NM_DEBUG_HOST = 0x2,            /* debug host stack */
+	NM_DEBUG_RXSYNC = 0x10,         /* debug on rxsync/txsync */
+	NM_DEBUG_TXSYNC = 0x20,
+	NM_DEBUG_RXINTR = 0x100,        /* debug on rx/tx intr (driver) */
+	NM_DEBUG_TXINTR = 0x200,
+	NM_DEBUG_NIC_RXSYNC = 0x1000,   /* debug on rx/tx intr (driver) */
+	NM_DEBUG_NIC_TXSYNC = 0x2000,
+	NM_DEBUG_MEM = 0x4000,		/* verbose memory allocations/deallocations */
+	NM_DEBUG_MEM_DEBUG = 0x8000,	/* debug messages from memory allocators */
 };
 
 extern int netmap_txsync_retry;
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index e2e9ee4ec..a2fe52387 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -191,7 +191,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 			break;
 		}
 
-		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+		if (unlikely(netmap_debug & NM_DEBUG_TXSYNC)) {
 			sync_kloop_kring_dump("pre txsync", kring);
 		}
 
@@ -215,7 +215,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 			more_txspace = true;
 		}
 
-		if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) {
+		if (unlikely(netmap_debug & NM_DEBUG_TXSYNC)) {
 			sync_kloop_kring_dump("post txsync", kring);
 		}
 
@@ -308,7 +308,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 			break;
 		}
 
-		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+		if (unlikely(netmap_debug & NM_DEBUG_RXSYNC)) {
 			sync_kloop_kring_dump("pre rxsync", kring);
 		}
 
@@ -333,7 +333,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 			dry_cycles++;
 		}
 
-		if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) {
+		if (unlikely(netmap_debug & NM_DEBUG_RXSYNC)) {
 			sync_kloop_kring_dump("post rxsync", kring);
 		}
 
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index e4485c9b8..9159c1bce 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -223,7 +223,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		}
 		case NETMAP_PT_HOST_CREATE:
 		case NETMAP_PT_HOST_DELETE: {
-			D("Netmap passthrough not supported yet");
+			nm_prerr("Netmap passthrough not supported yet");
 			return NULL;
 			break;
 		}
@@ -263,7 +263,7 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 		}
 		nm_os_free(hdr);
 	}
-	D("Failed to allocate memory for nmreq_xyz struct");
+	nm_prerr("Failed to allocate memory for nmreq_xyz struct");
 
 	return NULL;
 }
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index b640bc497..0450c4f30 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -399,7 +399,7 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 		n = (p->objtotal + 31) / 32;
 		p->bitmap = nm_os_malloc(sizeof(p->bitmap[0]) * n);
 		if (p->bitmap == NULL) {
-			D("Unable to create bitmap (%d entries) for allocator '%s'", (int)n,
+			nm_prerr("Unable to create bitmap (%d entries) for allocator '%s'", (int)n,
 			    p->name);
 			return ENOMEM;
 		}
@@ -416,14 +416,16 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 	 */
 	for (j = 0; j < p->objtotal; j++) {
 		if (p->invalid_bitmap && nm_isset(p->invalid_bitmap, j)) {
-			D("skipping %s %d", p->name, j);
+			if (netmap_debug & NM_DEBUG_MEM)
+				nm_prinf("skipping %s %d", p->name, j);
 			continue;
 		}
 		p->bitmap[ (j>>5) ] |=  ( 1U << (j & 31U) );
 		p->objfree++;
 	}
 
-	ND("%s free %u", p->name, p->objfree);
+	if (netmap_verbose)
+		nm_prinf("%s free %u", p->name, p->objfree);
 	if (p->objfree == 0)
 		return ENOMEM;
 
@@ -722,16 +724,20 @@ nm_mem_assign_group(struct netmap_mem_d *nmd, struct device *dev)
 {
 	int err = 0, id;
 	id = nm_iommu_group_id(dev);
-	if (netmap_verbose)
-		D("iommu_group %d", id);
+	if (netmap_debug & NM_DEBUG_MEM)
+		nm_prinf("iommu_group %d", id);
 
 	NMA_LOCK(nmd);
 
 	if (nmd->nm_grp < 0)
 		nmd->nm_grp = id;
 
-	if (nmd->nm_grp != id)
+	if (nmd->nm_grp != id) {
+		if (netmap_verbose)
+			nm_prerr("iommu group mismatch: %u vs %u",
+					nmd->nm_grp, id);
 		nmd->lasterr = err = ENOMEM;
+	}
 
 	NMA_UNLOCK(nmd);
 	return err;
@@ -807,7 +813,7 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 		return pa;
 	}
 	/* this is only in case of errors */
-	D("invalid ofs 0x%x out of 0x%x 0x%x 0x%x", (u_int)o,
+	nm_prerr("invalid ofs 0x%x out of 0x%x 0x%x 0x%x", (u_int)o,
 		p[NETMAP_IF_POOL].memtotal,
 		p[NETMAP_IF_POOL].memtotal
 			+ p[NETMAP_RING_POOL].memtotal,
@@ -856,13 +862,13 @@ win32_build_user_vm_map(struct netmap_mem_d* nmd)
 	int i, j;
 
 	if (netmap_mem_get_info(nmd, &memsize, &memflags, NULL)) {
-		D("memory not finalised yet");
+		nm_prerr("memory not finalised yet");
 		return NULL;
 	}
 
 	mainMdl = IoAllocateMdl(NULL, memsize, FALSE, FALSE, NULL);
 	if (mainMdl == NULL) {
-		D("failed to allocate mdl");
+		nm_prerr("failed to allocate mdl");
 		return NULL;
 	}
 
@@ -878,7 +884,7 @@ win32_build_user_vm_map(struct netmap_mem_d* nmd)
 		tempMdl = IoAllocateMdl(p->lut[0].vaddr, clsz, FALSE, FALSE, NULL);
 		if (tempMdl == NULL) {
 			NMA_UNLOCK(nmd);
-			D("fail to allocate tempMdl");
+			nm_prerr("fail to allocate tempMdl");
 			IoFreeMdl(mainMdl);
 			return NULL;
 		}
@@ -973,7 +979,7 @@ netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr)
 		    p->name, ofs, i, vaddr);
 		return ofs;
 	}
-	D("address %p is not contained inside any cluster (%s)",
+	nm_prerr("address %p is not contained inside any cluster (%s)",
 	    vaddr, p->name);
 	return 0; /* An error occurred */
 }
@@ -1004,12 +1010,12 @@ netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_
 	void *vaddr = NULL;
 
 	if (len > p->_objsize) {
-		D("%s request size %d too large", p->name, len);
+		nm_prerr("%s request size %d too large", p->name, len);
 		return NULL;
 	}
 
 	if (p->objfree == 0) {
-		D("no more %s objects", p->name);
+		nm_prerr("no more %s objects", p->name);
 		return NULL;
 	}
 	if (start)
@@ -1051,13 +1057,13 @@ netmap_obj_free(struct netmap_obj_pool *p, uint32_t j)
 	uint32_t *ptr, mask;
 
 	if (j >= p->objtotal) {
-		D("invalid index %u, max %u", j, p->objtotal);
+		nm_prerr("invalid index %u, max %u", j, p->objtotal);
 		return 1;
 	}
 	ptr = &p->bitmap[j / 32];
 	mask = (1 << (j % 32));
 	if (*ptr & mask) {
-		D("ouch, double free on buffer %d", j);
+		nm_prerr("ouch, double free on buffer %d", j);
 		return 1;
 	} else {
 		*ptr |= mask;
@@ -1088,7 +1094,7 @@ netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr)
 		netmap_obj_free(p, j);
 		return;
 	}
-	D("address %p is not contained inside any cluster (%s)",
+	nm_prerr("address %p is not contained inside any cluster (%s)",
 	    vaddr, p->name);
 }
 
@@ -1129,7 +1135,7 @@ netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n)
 		uint32_t cur = *head;	/* save current head */
 		uint32_t *p = netmap_buf_malloc(nmd, &pos, head);
 		if (p == NULL) {
-			D("no more buffers after %d of %d", i, n);
+			nm_prerr("no more buffers after %d of %d", i, n);
 			*head = cur; /* restore */
 			break;
 		}
@@ -1160,9 +1166,9 @@ netmap_extra_free(struct netmap_adapter *na, uint32_t head)
 			break;
 	}
 	if (head != 0)
-		D("breaking with head %d", head);
-	if (netmap_verbose)
-		D("freed %d buffers", i);
+		nm_prerr("breaking with head %d", head);
+	if (netmap_debug & NM_DEBUG_MEM)
+		nm_prinf("freed %d buffers", i);
 }
 
 
@@ -1178,7 +1184,7 @@ netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n)
 	for (i = 0; i < n; i++) {
 		void *vaddr = netmap_buf_malloc(nmd, &pos, &index);
 		if (vaddr == NULL) {
-			D("no more buffers after %d of %d", i, n);
+			nm_prerr("no more buffers after %d of %d", i, n);
 			goto cleanup;
 		}
 		slot[i].buf_idx = index;
@@ -1219,7 +1225,7 @@ netmap_free_buf(struct netmap_mem_d *nmd, uint32_t i)
 	struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL];
 
 	if (i < 2 || i >= p->objtotal) {
-		D("Cannot free buf#%d: should be in [2, %d[", i, p->objtotal);
+		nm_prerr("Cannot free buf#%d: should be in [2, %d[", i, p->objtotal);
 		return;
 	}
 	netmap_obj_free(p, i);
@@ -1319,22 +1325,22 @@ netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int obj
 #define LINE_ROUND	NM_CACHE_ALIGN	// 64
 	if (objsize >= MAX_CLUSTSIZE) {
 		/* we could do it but there is no point */
-		D("unsupported allocation for %d bytes", objsize);
+		nm_prerr("unsupported allocation for %d bytes", objsize);
 		return EINVAL;
 	}
 	/* make sure objsize is a multiple of LINE_ROUND */
 	i = (objsize & (LINE_ROUND - 1));
 	if (i) {
-		D("XXX aligning object by %d bytes", LINE_ROUND - i);
+		nm_prinf("aligning object by %d bytes", LINE_ROUND - i);
 		objsize += LINE_ROUND - i;
 	}
 	if (objsize < p->objminsize || objsize > p->objmaxsize) {
-		D("requested objsize %d out of range [%d, %d]",
+		nm_prerr("requested objsize %d out of range [%d, %d]",
 			objsize, p->objminsize, p->objmaxsize);
 		return EINVAL;
 	}
 	if (objtotal < p->nummin || objtotal > p->nummax) {
-		D("requested objtotal %d out of range [%d, %d]",
+		nm_prerr("requested objtotal %d out of range [%d, %d]",
 			objtotal, p->nummin, p->nummax);
 		return EINVAL;
 	}
@@ -1356,13 +1362,13 @@ netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int obj
 	}
 	/* exact solution not found */
 	if (clustentries == 0) {
-		D("unsupported allocation for %d bytes", objsize);
+		nm_prerr("unsupported allocation for %d bytes", objsize);
 		return EINVAL;
 	}
 	/* compute clustsize */
 	clustsize = clustentries * objsize;
-	if (netmap_verbose)
-		D("objsize %d clustsize %d objects %d",
+	if (netmap_debug & NM_DEBUG_MEM)
+		nm_prinf("objsize %d clustsize %d objects %d",
 			objsize, clustsize, clustentries);
 
 	/*
@@ -1405,7 +1411,7 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 
 	p->lut = nm_alloc_lut(p->objtotal);
 	if (p->lut == NULL) {
-		D("Unable to create lookup table for '%s'", p->name);
+		nm_prerr("Unable to create lookup table for '%s'", p->name);
 		goto clean;
 	}
 
@@ -1432,7 +1438,7 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 			 * If we get here, there is a severe memory shortage,
 			 * so halve the allocated memory to reclaim some.
 			 */
-			D("Unable to create cluster at %d for '%s' allocator",
+			nm_prerr("Unable to create cluster at %d for '%s' allocator",
 			    i, p->name);
 			if (i < 2) /* nothing to halve */
 				goto out;
@@ -1468,7 +1474,7 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 	}
 	p->memtotal = p->numclusters * p->_clustsize;
 	if (netmap_verbose)
-		D("Pre-allocated %d clusters (%d/%dKB) for '%s'",
+		nm_prinf("Pre-allocated %d clusters (%d/%dKB) for '%s'",
 		    p->numclusters, p->_clustsize >> 10,
 		    p->memtotal >> 10, p->name);
 
@@ -1500,8 +1506,8 @@ netmap_mem_reset_all(struct netmap_mem_d *nmd)
 {
 	int i;
 
-	if (netmap_verbose)
-		D("resetting %p", nmd);
+	if (netmap_debug & NM_DEBUG_MEM)
+		nm_prinf("resetting %p", nmd);
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		netmap_reset_obj_allocator(&nmd->pools[i]);
 	}
@@ -1527,7 +1533,7 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	(void)i;
 	(void)lim;
 	(void)lut;
-	D("unsupported on Windows");
+	nm_prerr("unsupported on Windows");
 #else /* linux */
 	ND("unmapping and freeing plut for %s", na->name);
 	if (lut->plut == NULL)
@@ -1563,7 +1569,7 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	(void)i;
 	(void)lim;
 	(void)lut;
-	D("unsupported on Windows");
+	nm_prerr("unsupported on Windows");
 #else /* linux */
 
 	if (lut->plut != NULL) {
@@ -1574,7 +1580,7 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	ND("allocating physical lut for %s", na->name);
 	lut->plut = nm_alloc_plut(lim);
 	if (lut->plut == NULL) {
-		D("Failed to allocate physical lut for %s", na->name);
+		nm_prerr("Failed to allocate physical lut for %s", na->name);
 		return ENOMEM;
 	}
 
@@ -1591,7 +1597,7 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 		error = netmap_load_map(na, (bus_dma_tag_t) na->pdev, &lut->plut[i].paddr,
 				p->lut[i].vaddr, p->_clustsize);
 		if (error) {
-			D("Failed to map cluster #%d from the %s pool", i, p->name);
+			nm_prerr("Failed to map cluster #%d from the %s pool", i, p->name);
 			break;
 		}
 
@@ -1629,13 +1635,13 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
 	nmd->flags |= NETMAP_MEM_FINALIZED;
 
 	if (netmap_verbose)
-		D("interfaces %d KB, rings %d KB, buffers %d MB",
+		nm_prinf("interfaces %d KB, rings %d KB, buffers %d MB",
 		    nmd->pools[NETMAP_IF_POOL].memtotal >> 10,
 		    nmd->pools[NETMAP_RING_POOL].memtotal >> 10,
 		    nmd->pools[NETMAP_BUF_POOL].memtotal >> 20);
 
 	if (netmap_verbose)
-		D("Free buffers: %d", nmd->pools[NETMAP_BUF_POOL].objfree);
+		nm_prinf("Free buffers: %d", nmd->pools[NETMAP_BUF_POOL].objfree);
 
 
 	return 0;
@@ -1742,7 +1748,7 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 		p[NETMAP_BUF_POOL].num = v;
 
 	if (netmap_verbose)
-		D("req if %d*%d ring %d*%d buf %d*%d",
+		nm_prinf("req if %d*%d ring %d*%d buf %d*%d",
 			p[NETMAP_IF_POOL].num,
 			p[NETMAP_IF_POOL].size,
 			p[NETMAP_RING_POOL].num,
@@ -1852,13 +1858,13 @@ netmap_free_rings(struct netmap_adapter *na)
 			struct netmap_ring *ring = kring->ring;
 
 			if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) {
-				if (netmap_verbose)
-					D("NOT deleting ring %s (ring %p, users %d neekring %d)",
+				if (netmap_debug & NM_DEBUG_MEM)
+					nm_prinf("NOT deleting ring %s (ring %p, users %d neekring %d)",
 						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
 				continue;
 			}
-			if (netmap_verbose)
-				D("deleting ring %s", kring->name);
+			if (netmap_debug & NM_DEBUG_MEM)
+				nm_prinf("deleting ring %s", kring->name);
 			if (!(kring->nr_kflags & NKR_FAKERING)) {
 				ND("freeing bufs for %s", kring->name);
 				netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots);
@@ -1893,19 +1899,19 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 
 			if (ring || (!kring->users && !(kring->nr_kflags & NKR_NEEDRING))) {
 				/* uneeded, or already created by somebody else */
-				if (netmap_verbose)
-					D("NOT creating ring %s (ring %p, users %d neekring %d)",
+				if (netmap_debug & NM_DEBUG_MEM)
+					nm_prinf("NOT creating ring %s (ring %p, users %d neekring %d)",
 						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
 				continue;
 			}
-			if (netmap_verbose)
-				D("creating %s", kring->name);
+			if (netmap_debug & NM_DEBUG_MEM)
+				nm_prinf("creating %s", kring->name);
 			ndesc = kring->nkr_num_slots;
 			len = sizeof(struct netmap_ring) +
 				  ndesc * sizeof(struct netmap_slot);
 			ring = netmap_ring_malloc(na->nm_mem, len);
 			if (ring == NULL) {
-				D("Cannot allocate %s_ring", nm_txrx2str(t));
+				nm_prerr("Cannot allocate %s_ring", nm_txrx2str(t));
 				goto cleanup;
 			}
 			ND("txring at %p", ring);
@@ -1927,14 +1933,16 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 			ND("initializing slots for %s_ring", nm_txrx2str(t));
 			if (!(kring->nr_kflags & NKR_FAKERING)) {
 				/* this is a real ring */
-				ND("allocating buffers for %s", kring->name);
+				if (netmap_debug & NM_DEBUG_MEM)
+					nm_prinf("allocating buffers for %s", kring->name);
 				if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) {
-					D("Cannot allocate buffers for %s_ring", nm_txrx2str(t));
+					nm_prerr("Cannot allocate buffers for %s_ring", nm_txrx2str(t));
 					goto cleanup;
 				}
 			} else {
 				/* this is a fake ring, set all indices to 0 */
-				ND("NOT allocating buffers for %s", kring->name);
+				if (netmap_debug & NM_DEBUG_MEM)
+					nm_prinf("NOT allocating buffers for %s", kring->name);
 				netmap_mem_set_ring(na->nm_mem, ring->slot, ndesc, 0);
 			}
 		        /* ring info */
@@ -2051,8 +2059,8 @@ static void
 netmap_mem2_deref(struct netmap_mem_d *nmd)
 {
 
-	if (netmap_verbose)
-		D("active = %d", nmd->active);
+	if (netmap_debug & NM_DEBUG_MEM)
+		nm_prinf("active = %d", nmd->active);
 
 }
 
@@ -2219,14 +2227,15 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		pi->nr_buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
 	if (pi->nr_buf_pool_objsize == 0)
 		pi->nr_buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
-	D("if %d %d ring %d %d buf %d %d",
+	if (netmap_verbose & NM_VERB_MEM)
+		nm_prinf("if %d %d ring %d %d buf %d %d",
 			pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize,
 			pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize,
 			pi->nr_buf_pool_objtotal, pi->nr_buf_pool_objsize);
 
 	os = nm_os_extmem_create(usrptr, pi, &error);
 	if (os == NULL) {
-		D("os extmem creation failed");
+		nm_prerr("os extmem creation failed");
 		goto out;
 	}
 
@@ -2235,7 +2244,8 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		nm_os_extmem_delete(os);
 		return &nme->up;
 	}
-	D("not found, creating new");
+	if (netmap_verbose & NM_VERB_MEM_DEBUG)
+		nm_prinf("not found, creating new");
 
 	nme = _netmap_mem_private_new(sizeof(*nme),
 			(struct netmap_obj_params[]){

From 0097eb472051efb4fc388e2c62177959b0cb11a6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Nov 2018 15:42:01 +0100
Subject: [PATCH 1437/2207] linux: ptnet: use compatibility macro for
 ndo_change_mtu

---
 LINUX/netmap_ptnet.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 7bfecc563..6da161f2f 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1008,11 +1008,11 @@ ptnet_close(struct net_device *netdev)
 }
 
 static const struct net_device_ops ptnet_netdev_ops = {
-	.ndo_open		= ptnet_open,
-	.ndo_stop		= ptnet_close,
-	.ndo_start_xmit		= ptnet_start_xmit,
-	.ndo_get_stats		= ptnet_get_stats,
-	.ndo_change_mtu		= ptnet_change_mtu,
+	.ndo_open			= ptnet_open,
+	.ndo_stop			= ptnet_close,
+	.ndo_start_xmit			= ptnet_start_xmit,
+	.ndo_get_stats			= ptnet_get_stats,
+	.NETMAP_LINUX_CHANGE_MTU	= ptnet_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= ptnet_netpoll,
 #endif

From cc95e8c7c89d259238a4977d4d0ae2e578587168 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Nov 2018 16:05:10 +0100
Subject: [PATCH 1438/2207] linux: configure: fix warning in compilation test

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 76b6db441..552ebfdb1 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1626,7 +1626,7 @@ EOF
 	#include 
 
 	DECLARE_EWMA(myname, 1, 64);
-	int
+	void
 	dummy(struct ewma_myname *x) {
 		ewma_myname_add(x, 18);
 	}

From 206bfae2f77d71d4eaf50658384a446e4ec16b5b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Nov 2018 13:55:26 +0100
Subject: [PATCH 1439/2207] vale: disable some debug messages

---
 sys/dev/netmap/netmap_bdg.c  | 58 +++++++++++++++++++-----------------
 sys/dev/netmap/netmap_kern.h |  3 +-
 sys/dev/netmap/netmap_vale.c | 32 ++++++++++++--------
 3 files changed, 51 insertions(+), 42 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index bcb4097ed..7830fea43 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -189,7 +189,7 @@ nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
 	namelen = nm_bdg_name_validate(name,
 			(ops != NULL ? strlen(ops->name) : 0));
 	if (namelen < 0) {
-		D("invalid bridge name %s", name ? name : NULL);
+		nm_prerr("invalid bridge name %s", name ? name : NULL);
 		return NULL;
 	}
 
@@ -214,7 +214,7 @@ nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
 			b->bdg_active_ports);
 		b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH);
 		if (b->ht == NULL) {
-			D("failed to allocate hash table");
+			nm_prerr("failed to allocate hash table");
 			return NULL;
 		}
 		strncpy(b->bdg_basename, name, namelen);
@@ -304,8 +304,8 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	acquire BDG_WLOCK() and copy back the array.
 	 */
 
-	if (netmap_verbose)
-		D("detach %d and %d (lim %d)", hw, sw, lim);
+	if (netmap_debug & NM_DEBUG_BDG)
+		nm_prinf("detach %d and %d (lim %d)", hw, sw, lim);
 	/* make a copy of the list of active ports, update it,
 	 * and then copy back within BDG_WLOCK().
 	 */
@@ -328,7 +328,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 		}
 	}
 	if (hw >= 0 || sw >= 0) {
-		D("XXX delete failed hw %d sw %d, should panic...", hw, sw);
+		nm_prerr("delete failed hw %d sw %d, should panic...", hw, sw);
 	}
 
 	BDG_WLOCK(b);
@@ -439,7 +439,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* yes we should, see if we have space to attach entries */
 	needed = 2; /* in some cases we only need 1 */
 	if (b->bdg_active_ports + needed >= NM_BDG_MAXPORTS) {
-		D("bridge full %d, cannot create new port", b->bdg_active_ports);
+		nm_prerr("bridge full %d, cannot create new port", b->bdg_active_ports);
 		return ENOMEM;
 	}
 	/* record the next two ports available, but do not allocate yet */
@@ -467,7 +467,8 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		/* bdg_netmap_attach creates a struct netmap_adapter */
 		error = b->bdg_ops.vp_create(hdr, NULL, nmd, &vpna);
 		if (error) {
-			D("error %d", error);
+			if (netmap_debug & NM_DEBUG_BDG)
+				nm_prerr("error %d", error);
 			goto out;
 		}
 		/* shortcut - we can skip get_hw_na(),
@@ -610,8 +611,9 @@ nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps)
 		t->bps = bps;
 		t->qfirst = all ? bps->qfirst /* must be 0 */: affinity;
 		t->qlast = all ? bps->qlast : t->qfirst + 1;
-		D("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst,
-			t->qlast);
+		if (netmap_verbose)
+			nm_prinf("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst,
+				t->qlast);
 
 		kcfg.type = i;
 		kcfg.worker_private = t;
@@ -639,7 +641,7 @@ nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps)
 	int error, i, j;
 
 	if (!bps) {
-		D("polling is not configured");
+		nm_prerr("polling is not configured");
 		return EFAULT;
 	}
 	bps->stopped = false;
@@ -648,7 +650,7 @@ nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps)
 		struct nm_bdg_kthread *t = bps->kthreads + i;
 		error = nm_os_kctx_worker_start(t->nmk);
 		if (error) {
-			D("error in nm_kthread_start()");
+			nm_prerr("error in nm_kthread_start(): %d", error);
 			goto cleanup;
 		}
 	}
@@ -691,10 +693,10 @@ get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
 	avail_cpus = nm_os_ncpus();
 
 	if (req_cpus == 0) {
-		D("req_cpus must be > 0");
+		nm_prerr("req_cpus must be > 0");
 		return EINVAL;
 	} else if (req_cpus >= avail_cpus) {
-		D("Cannot use all the CPUs in the system");
+		nm_prerr("Cannot use all the CPUs in the system");
 		return EINVAL;
 	}
 
@@ -704,7 +706,7 @@ get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
 		 * For example, if nr_first_cpu_id=2 and nr_num_polling_cpus=2,
 		 * ring 2 and 3 are polled by core 2 and 3, respectively. */
 		if (i + req_cpus > nma_get_nrings(na, NR_RX)) {
-			D("Rings %u-%u not in range (have %d rings)",
+			nm_prerr("Rings %u-%u not in range (have %d rings)",
 				i, i + req_cpus, nma_get_nrings(na, NR_RX));
 			return EINVAL;
 		}
@@ -716,7 +718,7 @@ get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
 		/* Poll all the rings using a core specified by nr_first_cpu_id.
 		 * the number of cores must be 1. */
 		if (req_cpus != 1) {
-			D("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
+			nm_prerr("ncpus must be 1 for NETMAP_POLLING_MODE_SINGLE_CPU "
 				"(was %d)", req_cpus);
 			return EINVAL;
 		}
@@ -724,7 +726,7 @@ get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
 		qlast = nma_get_nrings(na, NR_RX);
 		core_from = i;
 	} else {
-		D("Invalid polling mode");
+		nm_prerr("Invalid polling mode");
 		return EINVAL;
 	}
 
@@ -733,7 +735,7 @@ get_polling_cfg(struct nmreq_vale_polling *req, struct netmap_adapter *na,
 	bps->qlast = qlast;
 	bps->cpu_from = core_from;
 	bps->ncpus = req_cpus;
-	D("%s qfirst %u qlast %u cpu_from %u ncpus %u",
+	nm_prinf("%s qfirst %u qlast %u cpu_from %u ncpus %u",
 		req->nr_mode == NETMAP_POLLING_MODE_MULTI_CPU ?
 		"MULTI" : "SINGLE",
 		qfirst, qlast, core_from, req_cpus);
@@ -749,7 +751,7 @@ nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *
 
 	bna = (struct netmap_bwrap_adapter *)na;
 	if (bna->na_polling_state) {
-		D("ERROR adapter already in polling mode");
+		nm_prerr("ERROR adapter already in polling mode");
 		return EFAULT;
 	}
 
@@ -778,7 +780,7 @@ nm_bdg_ctl_polling_start(struct nmreq_vale_polling *req, struct netmap_adapter *
 	/* start kthread now */
 	error = nm_bdg_polling_start_kthreads(bps);
 	if (error) {
-		D("ERROR nm_bdg_polling_start_kthread()");
+		nm_prerr("ERROR nm_bdg_polling_start_kthread()");
 		nm_os_free(bps->kthreads);
 		nm_os_free(bps);
 		bna->na_polling_state = NULL;
@@ -794,7 +796,7 @@ nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
 	struct nm_bdg_polling_state *bps;
 
 	if (!bna->na_polling_state) {
-		D("ERROR adapter is not in polling mode");
+		nm_prerr("ERROR adapter is not in polling mode");
 		return EFAULT;
 	}
 	bps = bna->na_polling_state;
@@ -971,7 +973,7 @@ netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags)
 	int n;
 
 	if (head > lim) {
-		D("ouch dangerous reset!!!");
+		nm_prerr("ouch dangerous reset!!!");
 		n = netmap_ring_reinit(kring);
 		goto done;
 	}
@@ -988,7 +990,7 @@ netmap_vp_rxsync_locked(struct netmap_kring *kring, int flags)
 			void *addr = NMB(na, slot);
 
 			if (addr == NETMAP_BUF_BASE(kring->na)) { /* bad buf */
-				D("bad buffer index %d, ignore ?",
+				nm_prerr("bad buffer index %d, ignore ?",
 					slot->buf_idx);
 			}
 			slot->flags &= ~NS_BUF_CHANGED;
@@ -1117,8 +1119,8 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 	int ret = NM_IRQ_COMPLETED;
 	int error;
 
-	if (netmap_verbose)
-	    D("%s %s 0x%x", na->name, kring->name, flags);
+	if (netmap_debug & NM_DEBUG_RXINTR)
+	    nm_prinf("%s %s 0x%x", na->name, kring->name, flags);
 
 	bkring = vpna->up.tx_rings[ring_nr];
 
@@ -1127,8 +1129,8 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 		return EIO;
 	}
 
-	if (netmap_verbose)
-	    D("%s head %d cur %d tail %d",  na->name,
+	if (netmap_debug & NM_DEBUG_RXINTR)
+	    nm_prinf("%s head %d cur %d tail %d",  na->name,
 		kring->rhead, kring->rcur, kring->rtail);
 
 	/* simulate a user wakeup on the rx ring
@@ -1139,7 +1141,7 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 		goto put_out;
 	if (kring->nr_hwcur == kring->nr_hwtail) {
 		if (netmap_verbose)
-			D("how strange, interrupt with no packets on %s",
+			nm_prerr("how strange, interrupt with no packets on %s",
 			    na->name);
 		goto put_out;
 	}
@@ -1522,7 +1524,7 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 
 	/* make sure the NIC is not already in use */
 	if (NETMAP_OWNED_BY_ANY(hwna)) {
-		D("NIC %s busy, cannot attach to bridge", hwna->name);
+		nm_prerr("NIC %s busy, cannot attach to bridge", hwna->name);
 		return EBUSY;
 	}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 870209adf..91d548daa 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1596,7 +1596,8 @@ enum {                                  /* debug flags */
 	NM_DEBUG_NIC_RXSYNC = 0x1000,   /* debug on rx/tx intr (driver) */
 	NM_DEBUG_NIC_TXSYNC = 0x2000,
 	NM_DEBUG_MEM = 0x4000,		/* verbose memory allocations/deallocations */
-	NM_DEBUG_MEM_DEBUG = 0x8000,	/* debug messages from memory allocators */
+	NM_DEBUG_VALE = 0x8000,		/* debug messages from memory allocators */
+	NM_DEBUG_BDG = NM_DEBUG_VALE,
 };
 
 extern int netmap_txsync_retry;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index b7b1d2bcf..7687540d8 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -340,7 +340,7 @@ netmap_vale_list(struct nmreq_header *hdr)
 			i = b->bdg_port_index[j];
 			vpna = b->bdg_ports[i];
 			if (vpna == NULL) {
-				D("This should not happen");
+				nm_prerr("This should not happen");
 				continue;
 			}
 			/* the former and the latter identify a
@@ -653,7 +653,7 @@ nm_vale_preflush(struct netmap_kring *kring, u_int end)
 		buf = ft[ft_i].ft_buf = (slot->flags & NS_INDIRECT) ?
 			(void *)(uintptr_t)slot->ptr : NMB(&na->up, slot);
 		if (unlikely(buf == NULL)) {
-			RD(5, "NULL %s buffer pointer from %s slot %d len %d",
+			nm_prlim(5, "NULL %s buffer pointer from %s slot %d len %d",
 				(slot->flags & NS_INDIRECT) ? "INDIRECT" : "DIRECT",
 				kring->name, j, ft[ft_i].ft_len);
 			buf = ft[ft_i].ft_buf = NETMAP_BUF_BASE(&na->up);
@@ -679,7 +679,7 @@ nm_vale_preflush(struct netmap_kring *kring, u_int end)
 		frags--;
 		ft[ft_i - 1].ft_flags &= ~NS_MOREFRAG;
 		ft[ft_i - frags].ft_frags = frags;
-		D("Truncate incomplete fragment at %d (%d frags)", ft_i, frags);
+		nm_prlim(5, "Truncate incomplete fragment at %d (%d frags)", ft_i, frags);
 	}
 	if (ft_i)
 		ft_i = nm_vale_flush(ft, ft_i, na, ring_nr);
@@ -773,8 +773,8 @@ netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 		/* update source port forwarding entry */
 		na->last_smac = ht[sh].mac = smac;	/* XXX expire ? */
 		ht[sh].ports = mysrc;
-		if (netmap_verbose)
-		    D("src %02x:%02x:%02x:%02x:%02x:%02x on port %d",
+		if (netmap_debug & NM_DEBUG_VALE)
+		    nm_prinf("src %02x:%02x:%02x:%02x:%02x:%02x on port %d",
 			s[0], s[1], s[2], s[3], s[4], s[5], mysrc);
 	}
 	dst = NM_BDG_BROADCAST;
@@ -838,24 +838,28 @@ nm_kr_lease(struct netmap_kring *k, u_int n, int is_rx)
 	k->nkr_leases[lease_idx] = NR_NOSLOT;
 	k->nkr_lease_idx = nm_next(lease_idx, lim);
 
+#ifdef CONFIG_NETMAP_DEBUG
 	if (n > nm_kr_space(k, is_rx)) {
-		D("invalid request for %d slots", n);
+		nm_prerr("invalid request for %d slots", n);
 		panic("x");
 	}
+#endif /* CONFIG NETMAP_DEBUG */
 	/* XXX verify that there are n slots */
 	k->nkr_hwlease += n;
 	if (k->nkr_hwlease > lim)
 		k->nkr_hwlease -= lim + 1;
 
+#ifdef CONFIG_NETMAP_DEBUG
 	if (k->nkr_hwlease >= k->nkr_num_slots ||
 		k->nr_hwcur >= k->nkr_num_slots ||
 		k->nr_hwtail >= k->nkr_num_slots ||
 		k->nkr_lease_idx >= k->nkr_num_slots) {
-		D("invalid kring %s, cur %d tail %d lease %d lease_idx %d lim %d",
+		nm_prerr("invalid kring %s, cur %d tail %d lease %d lease_idx %d lim %d",
 			k->na->name,
 			k->nr_hwcur, k->nr_hwtail, k->nkr_hwlease,
 			k->nkr_lease_idx, k->nkr_num_slots);
 	}
+#endif /* CONFIG_NETMAP_DEBUG */
 	return lease_idx;
 }
 
@@ -1235,14 +1239,14 @@ netmap_vale_vp_txsync(struct netmap_kring *kring, int flags)
 	done = nm_vale_preflush(kring, head);
 done:
 	if (done != head)
-		D("early break at %d/ %d, tail %d", done, head, kring->nr_hwtail);
+		nm_prerr("early break at %d/ %d, tail %d", done, head, kring->nr_hwtail);
 	/*
 	 * packets between 'done' and 'cur' are left unsent.
 	 */
 	kring->nr_hwcur = done;
 	kring->nr_hwtail = nm_prev(done, lim);
-	if (netmap_verbose)
-		D("%s ring %d flags %d", na->up.name, kring->ring_id, flags);
+	if (netmap_debug & NM_DEBUG_TXSYNC)
+		nm_prinf("%s ring %d flags %d", na->up.name, kring->ring_id, flags);
 	return 0;
 }
 
@@ -1304,7 +1308,7 @@ netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	/*if (vpna->mfs > netmap_buf_size)  TODO netmap_buf_size is zero??
 		vpna->mfs = netmap_buf_size; */
 	if (netmap_verbose)
-		D("max frame size %u", vpna->mfs);
+		nm_prinf("max frame size %u", vpna->mfs);
 
 	na->na_flags |= NAF_BDG_MAYSLEEP;
 	/* persistent VALE ports look like hw devices
@@ -1493,7 +1497,8 @@ nm_vi_destroy(const char *name)
 
 	NMG_UNLOCK();
 
-	D("destroying a persistent vale interface %s", ifp->if_xname);
+	if (netmap_verbose)
+		nm_prinf("destroying a persistent vale interface %s", ifp->if_xname);
 	/* Linux requires all the references are released
 	 * before unregister
 	 */
@@ -1571,7 +1576,8 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 	/* netmap_vp_create creates a struct netmap_vp_adapter */
 	error = netmap_vale_vp_create(hdr, ifp, nmd, &vpna);
 	if (error) {
-		D("error %d", error);
+		if (netmap_debug & NM_DEBUG_VALE)
+			nm_prerr("error %d", error);
 		goto err_1;
 	}
 	/* persist-specific routines */

From 58cc05e1869a53d2ac2e34b5a35969fdeb3cc5eb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Nov 2018 16:05:47 +0100
Subject: [PATCH 1440/2207] extmem: fix compilation

---
 sys/dev/netmap/netmap_mem2.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 0450c4f30..58a605d52 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2227,7 +2227,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		pi->nr_buf_pool_objtotal = netmap_min_priv_params[NETMAP_BUF_POOL].num;
 	if (pi->nr_buf_pool_objsize == 0)
 		pi->nr_buf_pool_objsize = netmap_min_priv_params[NETMAP_BUF_POOL].size;
-	if (netmap_verbose & NM_VERB_MEM)
+	if (netmap_verbose & NM_DEBUG_MEM)
 		nm_prinf("if %d %d ring %d %d buf %d %d",
 			pi->nr_if_pool_objtotal, pi->nr_if_pool_objsize,
 			pi->nr_ring_pool_objtotal, pi->nr_ring_pool_objsize,
@@ -2244,7 +2244,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		nm_os_extmem_delete(os);
 		return &nme->up;
 	}
-	if (netmap_verbose & NM_VERB_MEM_DEBUG)
+	if (netmap_verbose & NM_DEBUG_MEM)
 		nm_prinf("not found, creating new");
 
 	nme = _netmap_mem_private_new(sizeof(*nme),

From 1c4a65a8a7a1e0ab0eb824abb239615d7464990c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Nov 2018 16:35:38 +0100
Subject: [PATCH 1441/2207] mem: additional error messages

---
 sys/dev/netmap/netmap_mem2.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 58a605d52..dafdbc487 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -426,8 +426,11 @@ netmap_init_obj_allocator_bitmap(struct netmap_obj_pool *p)
 
 	if (netmap_verbose)
 		nm_prinf("%s free %u", p->name, p->objfree);
-	if (p->objfree == 0)
+	if (p->objfree == 0) {
+		if (netmap_verbose)
+			nm_prerr("%s: no objects available", p->name);
 		return ENOMEM;
+	}
 
 	return 0;
 }
@@ -449,6 +452,7 @@ netmap_mem_init_bitmaps(struct netmap_mem_d *nmd)
 	 * buffers 0 and 1 are reserved
 	 */
 	if (nmd->pools[NETMAP_BUF_POOL].objfree < 2) {
+		nm_prerr("%s: not enough buffers", nmd->pools[NETMAP_BUF_POOL].name);
 		return ENOMEM;
 	}
 

From 7672a356851bd019080d23b99f4ab32fa13d1a01 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 22 Nov 2018 12:57:08 +0100
Subject: [PATCH 1442/2207] linux: virtio_net.c: fix probe bug when
 WITH_MERGEABLE_RX_BUFS is not defined

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 79 +++++++++++--------
 1 file changed, 45 insertions(+), 34 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index edb350700..54228c829 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..53f8779 100644
+index cbf1c61..b1528eb 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,12 @@
@@ -242,7 +242,7 @@ index cbf1c61..53f8779 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,16 +781,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,59 +781,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -275,14 +275,13 @@ index cbf1c61..53f8779 100644
 +		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
 -			virtqueue_disable_cb(rq->vq);
-+			virtqueue_disable_cb(vq);
- 			__napi_schedule(napi);
- 		}
- 	}
-@@ -746,53 +814,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	return received;
- }
- 
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
+-
 -#ifdef CONFIG_NET_RX_BUSY_POLL
 -/* must be called with local_bh_disable()d */
 -static int virtnet_busy_poll(struct napi_struct *napi)
@@ -312,17 +311,18 @@ index cbf1c61..53f8779 100644
 -			budget -= received;
 -			goto again;
 -		} else {
--			__napi_schedule(napi);
--		}
--	}
--
--	return received;
--}
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+ 
+ 	return received;
+ }
 -#endif	/* CONFIG_NET_RX_BUSY_POLL */
--
+ 
  static int virtnet_open(struct net_device *dev)
  {
- 	struct virtnet_info *vi = netdev_priv(dev);
+@@ -789,10 +820,13 @@ static int virtnet_open(struct net_device *dev)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -613,17 +613,18 @@ index cbf1c61..53f8779 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1704,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1704,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
 +#ifdef VIRTIO_NET_F_MTU
  	int mtu;
 +#endif  /* VIRTIO_NET_F_MTU */
++	bool mrg_rxbuf = false;
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1742,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1743,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -631,7 +632,7 @@ index cbf1c61..53f8779 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1750,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1751,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -640,7 +641,7 @@ index cbf1c61..53f8779 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1760,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1761,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -660,7 +661,7 @@ index cbf1c61..53f8779 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,11 +1801,13 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,16 +1802,21 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -672,9 +673,19 @@ index cbf1c61..53f8779 100644
  		vi->big_packets = true;
 +#endif  /* !DEV_NETMAP */
  
- 	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
+-	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
++#ifdef WITH_MERGEABLE_RX_BUFS
++	mrg_rxbuf = virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF);
++#endif
++	if (mrg_rxbuf)
  		vi->mergeable_rx_bufs = true;
-@@ -1885,6 +1825,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+-	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
++	if (mrg_rxbuf ||
+ 	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+ 		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ 	else
+@@ -1885,6 +1829,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -682,7 +693,7 @@ index cbf1c61..53f8779 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1833,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1837,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -690,7 +701,7 @@ index cbf1c61..53f8779 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1847,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1851,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -701,7 +712,7 @@ index cbf1c61..53f8779 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1858,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1862,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -719,7 +730,7 @@ index cbf1c61..53f8779 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1879,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1883,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -730,7 +741,7 @@ index cbf1c61..53f8779 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1908,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1912,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -746,7 +757,7 @@ index cbf1c61..53f8779 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1929,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1933,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -755,7 +766,7 @@ index cbf1c61..53f8779 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1971,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1975,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -766,7 +777,7 @@ index cbf1c61..53f8779 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1980,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1984,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -834,7 +845,7 @@ index cbf1c61..53f8779 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2046,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2050,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From f7a308907920b264b3cc6e6195c59cd2e2a0ba5c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 21 Nov 2018 16:13:05 +0100
Subject: [PATCH 1443/2207] linux: configure: use -Werror when building tests

This is important because some tests need to fail if there is i.e.
a parameter type mismatch.
---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 552ebfdb1..8bb759b6c 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -457,7 +457,7 @@ I_DRIVERS := $(idrv print)
 all: \$(S_DRIVERS:%=get-%) \$(E_DRIVERS:%=build-%) \$(I_DRIVERS:%=patch-%) tests
 
 tests:
-	\$(MAKE) -C $ksrc M=\$\$PWD $kopts
+	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS=-Werror $kopts
 
 -include $BUILDDIR/extdrv-versions.mak
 -include $BUILDDIR/default-config.mak

From fce88df1b49c0dfce4c6d4211f1d4ec62aa320b0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 22 Nov 2018 13:03:53 +0100
Subject: [PATCH 1444/2207] linux: configure: enable ptnetmap by default

---
 LINUX/configure | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/configure b/LINUX/configure
index 8bb759b6c..71936d6e4 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -109,6 +109,7 @@ subsys enable pipe
 subsys enable monitor
 subsys enable generic
 subsys enable null
+subsys enable ptnetmap
 
 # available drivers
 driver_avail="r8169.c virtio_net.c forcedeth.c veth.c \

From 510e2ebaa6f603752be53ab476de92606e31f9f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 24 Nov 2018 14:42:31 +0100
Subject: [PATCH 1445/2207] vale: honor extra-bufs requestes

---
 sys/dev/netmap/netmap_vale.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 7687540d8..e4cb8ea01 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1296,6 +1296,7 @@ netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	 */
 	nm_bound_var(&npipes, 2, 1, NM_MAXPIPES, NULL);
 	/* validate extra bufs */
+	extrabufs = req->nr_extra_bufs;
 	nm_bound_var(&extrabufs, 0, 0,
 			128*NM_BDG_MAXSLOTS, NULL);
 	req->nr_extra_bufs = extrabufs; /* write back */

From 7464dd3596ca3df6f0e4e37b39a6b834081a5477 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 26 Nov 2018 10:46:14 +0100
Subject: [PATCH 1446/2207] linux/intest: run from the build directory

---
 LINUX/configure     | 1 +
 LINUX/netmap.mak.in | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 71936d6e4..62b820cc3 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2190,6 +2190,7 @@ done
 if [ -n "$UTILS" ]; then
 	mkdir -p build-utils
 	ln -s $SRCDIR/../utils/GNUmakefile build-utils/GNUmakefile 2>/dev/null || true
+	ln -s $SRCDIR/../utils/tests 2>/dev/null || true
 fi
 
 # config.status can be used to rerun configure with the
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index b069f57ea..1511e0047 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -149,7 +149,7 @@ clean-utils:
 	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/..
 
 intest: utils
-	utils/randomized_tests
+	$(SRCDIR)/../utils/randomized_tests
 unitest: utils
 	build-utils/ctrl-api-test
 endif
@@ -177,6 +177,7 @@ distclean: clean $(S_DRIVERS:%=distclean-%)
 	if [ -L GNUmakefile ]; then rm GNUmakefile; fi
 	if [ -L drv-subdir.mak ]; then rm drv-subdir.mak; fi
 	if [ -L read-vars.mak ]; then rm read-vars.mak; fi
+	if [ -L tests ]; then rm tests; fi
 	rm -rf build-apps
 	rm -rf build-utils
 

From 191e421e4ec3c18b63312e3425916f2420d6779c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 26 Nov 2018 12:12:42 +0100
Subject: [PATCH 1447/2207] ctrl-api-test: accept an interval of tests

---
 utils/ctrl-api-test.c | 71 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 56 insertions(+), 15 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8511a3708..3c9598857 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,3 +1,4 @@
+#include 
 #include 
 #include 
 #include 
@@ -45,6 +46,8 @@ struct TestContext {
 	uint32_t nr_num_polling_cpus; /* vale polling */
 	void *csb;                    /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
+
+	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
 };
 
 #if 0
@@ -1449,7 +1452,7 @@ static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME\n"
-	       "[-j TESTCASE_NUM]\n"
+	       "[-j TESTCASE_INTERVAL]\n"
 	       "[-l (list test cases)]\n",
 	       prog);
 }
@@ -1518,6 +1521,43 @@ context_cleanup(struct TestContext *ctx)
 	close(ctx->fd);
 }
 
+static int
+parse_interval(const char *arg, int *j, int *k)
+{
+	const char *scan = arg;
+	char *rest;
+
+	*j = 0;
+	*k = -1;
+	if (*scan == '-') {
+		scan++;
+		goto get_k;
+	}
+	if (!isdigit(*scan))
+		goto err;
+	*k = strtol(scan, &rest, 10);
+	*j = *k - 1;
+	scan = rest;
+	if (*scan == '-') {
+		*k = -1;
+		scan++;
+	}
+get_k:
+	if (*scan == '\0')
+		return 0;
+	if (!isdigit(*scan))
+		goto err;
+	*k = strtol(scan, &rest, 10);
+	scan = rest;
+	if (!*scan == '\0')
+		goto err;
+	return 0;
+
+err:
+	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
+	return -1;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1525,7 +1565,8 @@ main(int argc, char **argv)
 	int loopback_if;
 	int num_tests;
 	int ret  = 0;
-	int j    = -1;
+	int j    = 0;
+	int k    = -1;
 	int list = 0;
 	int opt;
 	int i;
@@ -1545,7 +1586,10 @@ main(int argc, char **argv)
 			break;
 
 		case 'j':
-			j = atoi(optarg);
+			if (parse_interval(optarg, &j, &k) < 0) {
+				usage(argv[0]);
+				return -1;
+			}
 			break;
 
 		case 'l':
@@ -1561,6 +1605,14 @@ main(int argc, char **argv)
 
 	num_tests = sizeof(tests) / sizeof(tests[0]);
 
+	if (j < 0 || j >= num_tests || k > num_tests) {
+		fprintf(stderr, "%d-%d out of range (%d-%d)\n",
+				j + 1, k, 1, num_tests + 1);
+	}
+
+	if (k < 0)
+		k = num_tests;
+
 	if (list) {
 		printf("Available tests:\n");
 		for (i = 0; i < num_tests; i++) {
@@ -1581,20 +1633,9 @@ main(int argc, char **argv)
 		}
 	}
 
-	if (j >= 0) {
-		j--; /* one-based --> zero-based */
-		if (j >= num_tests) {
-			printf("Error: Test not in range\n");
-			ret = -1;
-			goto out;
-		}
-	}
-	for (i = 0; i < num_tests; i++) {
+	for (i = j; i < k; i++) {
 		struct TestContext ctxcopy;
 		int fd;
-		if (j >= 0 && j != i) {
-			continue;
-		}
 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
 		fd = open("/dev/netmap", O_RDWR);
 		if (fd < 0) {

From bb422bf0e9bcc8d28f9706520a0ad5f127e532fb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Nov 2018 12:45:59 +0100
Subject: [PATCH 1448/2207] utils: add test for nr_arg3 argument

---
 utils/ctrl-api-test.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8511a3708..bc2b78ca9 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -293,6 +293,27 @@ legacy_regif_future(struct TestContext *ctx)
 	return niocregif(ctx, NETMAP_API+2);
 }
 
+static int
+legacy_regif_extra_bufs(struct TestContext *ctx)
+{
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	ctx->nr_extra_bufs = 20;
+	return niocregif(ctx, NETMAP_API_NIOCREGIF);
+}
+
+static int
+legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
+{
+	char pipe_name[128];
+
+	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeexbuf");
+	ctx->ifname  = pipe_name;
+	ctx->nr_mode = NR_REG_ALL_NIC;
+	ctx->nr_extra_bufs = 20;
+
+	return niocregif(ctx, NETMAP_API_NIOCREGIF);
+}
+
 /* Only valid after a successful port_register(). */
 static int
 num_registered_rings(struct TestContext *ctx)
@@ -1505,6 +1526,8 @@ static struct mytest tests[] = {
 	decltest(legacy_regif_12),
 	decltest(legacy_regif_sw),
 	decltest(legacy_regif_future),
+	decltest(legacy_regif_extra_bufs),
+	decltest(legacy_regif_extra_bufs_pipe),
 };
 
 static void

From aba6320f6e23af57e72ae78d67d0fdd7ebfde42a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Nov 2018 13:02:01 +0100
Subject: [PATCH 1449/2207] utils: ctrl-api-test: improve usage()

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8cbd26099..61b0df9c8 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1473,7 +1473,7 @@ static void
 usage(const char *prog)
 {
 	printf("%s -i IFNAME\n"
-	       "[-j TESTCASE_INTERVAL]\n"
+	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
 	       "[-l (list test cases)]\n",
 	       prog);
 }

From 168b5e4bb78f78361ef9289c0976153c0f21d342 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Nov 2018 13:08:07 +0100
Subject: [PATCH 1450/2207] utils: ctrl-api-test: add missing return

---
 utils/ctrl-api-test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 61b0df9c8..f86117922 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1574,6 +1574,7 @@ parse_interval(const char *arg, int *j, int *k)
 	scan = rest;
 	if (!*scan == '\0')
 		goto err;
+
 	return 0;
 
 err:
@@ -1631,6 +1632,7 @@ main(int argc, char **argv)
 	if (j < 0 || j >= num_tests || k > num_tests) {
 		fprintf(stderr, "%d-%d out of range (%d-%d)\n",
 				j + 1, k, 1, num_tests + 1);
+		return -1;
 	}
 
 	if (k < 0)

From 79a8666afa2667333f6b29bca258e083ac545e22 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 27 Nov 2018 13:14:55 +0100
Subject: [PATCH 1451/2207] utils: ctrl-api-test: add legacy extra bufs test
 with pipes on VALE interfaces

---
 utils/ctrl-api-test.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index f86117922..1dabdc3f1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -317,6 +317,13 @@ legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
 }
 
+static int
+legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
+{
+	ctx->ifname = "valeX1:Y4";
+	return legacy_regif_extra_bufs_pipe(ctx);
+}
+
 /* Only valid after a successful port_register(). */
 static int
 num_registered_rings(struct TestContext *ctx)
@@ -1531,6 +1538,7 @@ static struct mytest tests[] = {
 	decltest(legacy_regif_future),
 	decltest(legacy_regif_extra_bufs),
 	decltest(legacy_regif_extra_bufs_pipe),
+	decltest(legacy_regif_extra_bufs_pipe_vale),
 };
 
 static void

From 0e7b28a5da5be7a53a8c7356f906a53c5b663b85 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 27 Nov 2018 13:14:15 +0100
Subject: [PATCH 1452/2207] ignore some more files

---
 .gitignore | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitignore b/.gitignore
index 259129d58..d2906fd00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,3 +84,5 @@ LINUX/scripts/conf
 config.mak
 *.rej
 utils/producer
+.cache.mk
+utils/sync_kloop_test

From 4746595b27b67c3dd6aa8d78c2c1a89322455c11 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 27 Nov 2018 13:14:38 +0100
Subject: [PATCH 1453/2207] linux/ixgbe: patch for Intel 5.5.2 version

---
 LINUX/final-patches/intel--ixgbe--5.5.2 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.5.2

diff --git a/LINUX/final-patches/intel--ixgbe--5.5.2 b/LINUX/final-patches/intel--ixgbe--5.5.2
new file mode 100644
index 000000000..b296b3331
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.5.2
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bf12f5..fa05036 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -28,24 +28,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 903d688..bf03742 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -694,6 +694,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -713,6 +730,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2192,6 +2220,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3624,6 +3662,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4245,6 +4287,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -12102,6 +12148,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12151,6 +12201,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 19bff7ed904a62d2f2fdd7ad13c1b487ff827749 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 27 Nov 2018 13:28:16 +0100
Subject: [PATCH 1454/2207] linux/igb: patch for Intel 5.3.5.22 version

---
 LINUX/final-patches/intel--igb--5.3.5.22 | 138 +++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.22

diff --git a/LINUX/final-patches/intel--igb--5.3.5.22 b/LINUX/final-patches/intel--igb--5.3.5.22
new file mode 100644
index 000000000..709140d7d
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.22
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 02d49bb..1c88549 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -28,9 +28,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -46,19 +46,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -115,9 +115,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 5e06587..de17ae2 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -258,6 +258,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3071,6 +3075,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3274,6 +3282,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3684,6 +3696,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7236,6 +7251,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8252,6 +8272,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8571,6 +8596,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 8b0680290141db70d788e50d8e79c1f1c7ee6c48 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Nov 2018 11:35:53 +0100
Subject: [PATCH 1455/2207] linux/i40e: fix ring re-init after a down/up cycle

---
 LINUX/i40e_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 17d4700cb..462d56d5c 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -184,7 +184,7 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 		rx->read.pkt_addr = htole64(paddr);
 		rx->read.hdr_addr = 0;
 	}
-	ring->next_to_clean = netmap_idx_k2n(kring, 0);
+	ring->next_to_clean = 0;
 	wmb();
 	writel(lim, ring->tail);
 	return 1;

From 56ccd0782667b4d165f3b7d807ae8e5ee916876a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 29 Nov 2018 12:32:02 +0100
Subject: [PATCH 1456/2207] utils: testmmap: fix bug

---
 utils/testmmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index f0bb6c311..425b4427b 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -789,7 +789,7 @@ dump_payload(char *p, int len)
 
 	/* hexdump routine */
 	for (i = 0; i < len;) {
-		memset(buf, sizeof(buf), ' ');
+		memset(buf, ' ', sizeof(buf));
 		sprintf(buf, "%5d: ", i);
 		i0 = i;
 		for (j = 0; j < 16 && i < len; i++, j++)

From 926ed123e0692713beef7cb84fdf4567f8c2c8af Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 29 Nov 2018 12:34:58 +0100
Subject: [PATCH 1457/2207] utils: ctrl-api-test: fix bug in parse_interval()

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 1dabdc3f1..5f4d81969 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1580,7 +1580,7 @@ parse_interval(const char *arg, int *j, int *k)
 		goto err;
 	*k = strtol(scan, &rest, 10);
 	scan = rest;
-	if (!*scan == '\0')
+	if (!(*scan == '\0'))
 		goto err;
 
 	return 0;

From cfa686742dc42cb33652a82b5b2932f8e3c48cec Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 29 Nov 2018 12:36:29 +0100
Subject: [PATCH 1458/2207] utils: ctrl-api-test: improve log statement

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 5f4d81969..2d76c0478 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1638,7 +1638,7 @@ main(int argc, char **argv)
 	num_tests = sizeof(tests) / sizeof(tests[0]);
 
 	if (j < 0 || j >= num_tests || k > num_tests) {
-		fprintf(stderr, "%d-%d out of range (%d-%d)\n",
+		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
 				j + 1, k, 1, num_tests + 1);
 		return -1;
 	}

From ca85b8483c68aa8c6b9ad3f75cc6426aad71f202 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 1 Dec 2018 15:42:13 +0100
Subject: [PATCH 1459/2207] linux: ixgbe_rxsync: fix logic that updates
 nr_hwtail

---
 LINUX/ixgbe_netmap_linux.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 9774f238a..728acf977 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -518,7 +518,6 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
-	int complete; /* did we see a complete packet ? */
 
 	/* device-specific */
 	struct NM_IXGBE_ADAPTER *adapter = netdev_priv(ifp);
@@ -548,6 +547,8 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * rxr->next_to_clean is set to 0 on a ring reinit
 	 */
 	if (netmap_no_pendintr || force_update) {
+		u_int new_hwtail = (u_int)-1;
+
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -557,6 +558,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			u_int size = le16toh(curr->wb.upper.length);
 			uint64_t paddr;
 			struct netmap_slot *slot = &ring->slot[nm_i];
+			int complete; /* did we see a complete packet ? */
 
 			if (!size)
 				break;
@@ -574,6 +576,9 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
+
+			if (complete)
+				new_hwtail = nm_i;
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
@@ -581,9 +586,8 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 #ifdef NETMAP_LINUX_HAVE_NTA
 			rxr->next_to_alloc = rxr->next_to_clean;
 #endif /* NETMAP_LINUX_HAVE_NTA */
-			kring->nr_hwtail = nm_i;
-			if (complete)
-				kring->nr_hwtail = nm_i;
+			if (new_hwtail != (u_int)-1)
+				kring->nr_hwtail = new_hwtail;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}

From 3a91173c9faeb83165a2b459af87782cc438775c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 1 Dec 2018 16:26:53 +0100
Subject: [PATCH 1460/2207] netmap_idx_n2k, netmap_idx_k2n: optimize the common
 case where hwofs == 0

---
 sys/dev/netmap/netmap_kern.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 91d548daa..d72e21e6c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1805,6 +1805,11 @@ static inline int
 netmap_idx_n2k(struct netmap_kring *kr, int idx)
 {
 	int n = kr->nkr_num_slots;
+
+	if (likely(kr->nkr_hwofs == 0)) {
+		return idx;
+	}
+
 	idx += kr->nkr_hwofs;
 	if (idx < 0)
 		return idx + n;
@@ -1819,6 +1824,11 @@ static inline int
 netmap_idx_k2n(struct netmap_kring *kr, int idx)
 {
 	int n = kr->nkr_num_slots;
+
+	if (likely(kr->nkr_hwofs == 0)) {
+		return idx;
+	}
+
 	idx -= kr->nkr_hwofs;
 	if (idx < 0)
 		return idx + n;

From 540b3b2d88432d8810a5364ee69a32ac6efe98f6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 1 Dec 2018 19:24:17 +0100
Subject: [PATCH 1461/2207] linux: ixgbe: improve comment in rxsync

---
 LINUX/ixgbe_netmap_linux.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 728acf977..e7c479fe3 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -558,7 +558,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			u_int size = le16toh(curr->wb.upper.length);
 			uint64_t paddr;
 			struct netmap_slot *slot = &ring->slot[nm_i];
-			int complete; /* did we see a complete packet ? */
+			int complete;
 
 			if (!size)
 				break;
@@ -586,8 +586,11 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 #ifdef NETMAP_LINUX_HAVE_NTA
 			rxr->next_to_alloc = rxr->next_to_clean;
 #endif /* NETMAP_LINUX_HAVE_NTA */
-			if (new_hwtail != (u_int)-1)
+			if (new_hwtail != (u_int)-1) {
+				/* Update nr_hwtail only if we saw a complete
+				 * packet in the previous loop. */
 				kring->nr_hwtail = new_hwtail;
+			}
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}

From c6013d2d9e280ddfccddf5d3465833dfb7963643 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 2 Dec 2018 09:51:48 +0100
Subject: [PATCH 1462/2207] linux: ixgbe: mark TDH overflow as unlikely

---
 LINUX/ixgbe_netmap_linux.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index e7c479fe3..bca9fc6e8 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -467,8 +467,8 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 		 * good way.
 		 */
 		nic_i = IXGBE_READ_REG(&adapter->hw, NM_IXGBE_TDH(ring_nr));
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("%s: TDH overflow (%d)", kring->name, nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		nm_i = netmap_idx_n2k(kring, nic_i);

From f8c673dd2a2a6c665c4e980826bd60144b6550ee Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 2 Dec 2018 10:00:54 +0100
Subject: [PATCH 1463/2207] linux: ixgbe: add missing le32toh()

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index bca9fc6e8..96648e6e3 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -453,7 +453,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 		nic_i = (nic_i < kring->nkr_num_slots / 4 ||
 			 nic_i >= kring->nkr_num_slots*3/4) ?
 			0 : report_frequency;
-		reclaim_tx = txd[nic_i].wb.status & IXGBE_TXD_STAT_DD;	// XXX cpu_to_le32 ?
+		reclaim_tx = le32toh(txd[nic_i].wb.status) & IXGBE_TXD_STAT_DD;
 	}
 	if (reclaim_tx) {
 		/*

From 7c10f2d9310475a0dfaa322441f57e7e24cf02aa Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 2 Dec 2018 16:19:30 +0100
Subject: [PATCH 1464/2207] nm_ring_empty, nm_ring_space: use ring->head rather
 than ring->cur

---
 sys/net/netmap.h      | 9 +++++++--
 sys/net/netmap_user.h | 5 +++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3376509ad..c50c1de2b 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -333,12 +333,17 @@ struct netmap_ring {
  */
 
 /*
- * check if space is available in the ring.
+ * Check if space is available in the ring. We use ring->head, which
+ * points to the next netmap slot to be published to netmap. It is
+ * possible that the applications moves ring->cur ahead of ring->tail
+ * (e.g., by setting ring->cur <== ring->tail), if it wants more slots
+ * than the ones currently available, and it wants to be notified when
+ * more arrive. See netmap(4) for more details and examples.
  */
 static inline int
 nm_ring_empty(struct netmap_ring *ring)
 {
-	return (ring->cur == ring->tail);
+	return (ring->head == ring->tail);
 }
 
 /*
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 6d52428bd..e9ce9c43e 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -138,11 +138,12 @@ nm_tx_pending(struct netmap_ring *r)
 	return nm_ring_next(r, r->tail) != r->head;
 }
 
-
+/* Compute the number of slots available in the netmap ring. We use
+ * ring->head as explained in the comment above nm_ring_empty(). */
 static inline uint32_t
 nm_ring_space(struct netmap_ring *ring)
 {
-        int ret = ring->tail - ring->cur;
+        int ret = ring->tail - ring->head;
         if (ret < 0)
                 ret += ring->num_slots;
         return ret;

From 9dab31f67a6bd676e31e41a9bbb4ce58fe2223e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 2 Dec 2018 17:17:06 +0100
Subject: [PATCH 1465/2207] pkt-gen: use frag_size = nr_buf_size by default

---
 apps/pkt-gen/pkt-gen.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index a83c94225..1d1fb0ca4 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -263,7 +263,7 @@ struct glob_arg {
 	int forever;
 	uint64_t npackets;	/* total packets to send */
 	int frags;		/* fragments per packet */
-	u_int mtu;		/* size of each fragment */
+	u_int frag_size;	/* size of each fragment */
 	int nthreads;
 	int cpus;	/* cpus used for running */
 	int system_cpus;	/* cpus on the system */
@@ -1581,18 +1581,18 @@ sender_body(void *data)
 #endif /* NO_PCAP */
     } else {
 	int tosend = 0;
-	u_int bufsz, mtu = targ->g->mtu;
+	u_int bufsz, frag_size = targ->g->frag_size;
 
 	nifp = targ->nmd->nifp;
 	txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
 	bufsz = txring->nr_buf_size;
-	if (bufsz < mtu)
-		mtu = bufsz;
+	if (bufsz < frag_size)
+		frag_size = bufsz;
 	targ->frag_size = targ->g->pkt_size / targ->frags;
-	if (targ->frag_size > mtu) {
-		targ->frags = targ->g->pkt_size / mtu;
-		targ->frag_size = mtu;
-		if (targ->g->pkt_size % mtu != 0)
+	if (targ->frag_size > frag_size) {
+		targ->frags = targ->g->pkt_size / frag_size;
+		targ->frag_size = frag_size;
+		if (targ->g->pkt_size % frag_size != 0)
 			targ->frags++;
 	}
 	D("frags %u frag_size %u", targ->frags, targ->frag_size);
@@ -2779,8 +2779,8 @@ main(int arc, char **argv)
 	g.cpus = 1;		/* default */
 	g.forever = 1;
 	g.tx_rate = 0;
-	g.frags =1;
-	g.mtu = 1500;
+	g.frags = 1;
+	g.frag_size = (u_int)-1;	/* use the netmap buffer size by default */
 	g.nmr_config = "";
 	g.virt_header = 0;
 	g.wait_link = 2;	/* wait 2 seconds for physical ports */
@@ -2824,7 +2824,7 @@ main(int arc, char **argv)
 			break;
 
 		case 'M':
-			g.mtu = atoi(optarg);
+			g.frag_size = atoi(optarg);
 			break;
 
 		case 'f':

From 61e52b51aded55cad0a1aca3d64eaf16d5b62775 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 3 Dec 2018 10:57:07 +0100
Subject: [PATCH 1466/2207] pkt-gen: get interface MTU and check against
 pkt_size

---
 apps/pkt-gen/pkt-gen.c | 60 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 52 insertions(+), 8 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 1d1fb0ca4..040992422 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -195,7 +195,7 @@ struct virt_header {
 	uint8_t fields[VIRT_HDR_MAX];
 };
 
-#define MAX_BODYSIZE	16384
+#define MAX_BODYSIZE	65536
 
 struct pkt {
 	struct virt_header vh;
@@ -238,7 +238,6 @@ struct mac_range {
 
 /* 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 */
 
 /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
@@ -308,6 +307,11 @@ struct glob_arg {
 };
 enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP };
 
+enum {
+	TD_TYPE_SENDER = 1,
+	TD_TYPE_RECEIVER,
+	TD_TYPE_OTHER,
+};
 
 /*
  * Arguments for a new thread. The same structure is used by
@@ -509,6 +513,42 @@ extract_mac_range(struct mac_range *r)
 	return 0;
 }
 
+static int
+get_if_mtu(const struct glob_arg *g)
+{
+	char ifname[IFNAMSIZ];
+	struct ifreq ifreq;
+	int s, ret;
+
+	if (!strncmp(g->ifname, "netmap:", 7) && !strchr(g->ifname, '{')
+			&& !strchr(g->ifname, '}')) {
+		/* Parse the interface name and ask the kernel for the
+		 * MTU value. */
+		strncpy(ifname, g->ifname+7, IFNAMSIZ-1);
+		ifname[strcspn(ifname, "-*^{}/@")] = '\0';
+
+		s = socket(AF_INET, SOCK_DGRAM, 0);
+		if (s < 0) {
+			D("socket() failed: %s", strerror(errno));
+			return s;
+		}
+
+		memset(&ifreq, 0, sizeof(ifreq));
+		strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
+
+		ret = ioctl(s, SIOCGIFMTU, &ifreq);
+		if (ret) {
+			D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
+		}
+
+		return ifreq.ifr_mtu;
+	}
+
+	/* This is a pipe or a VALE port, where the MTU is very large,
+	 * so we use some practical limit. */
+	return 65536;
+}
+
 static struct targ *targs;
 static int global_nthreads;
 
@@ -2441,12 +2481,6 @@ usage(int errcode)
 	exit(errcode);
 }
 
-enum {
-	TD_TYPE_SENDER = 1,
-	TD_TYPE_RECEIVER,
-	TD_TYPE_OTHER,
-};
-
 static void
 start_threads(struct glob_arg *g) {
 	int i;
@@ -3104,6 +3138,16 @@ main(int arc, char **argv)
 		// continue, fail later
 	}
 
+	if (g.td_type == TD_TYPE_SENDER) {
+		int mtu = get_if_mtu(&g);
+
+		if (mtu > 0 && g.pkt_size > mtu) {
+			D("pkt_size (%d) must be <= mtu (%d)",
+				g.pkt_size, mtu);
+			return -1;
+		}
+	}
+
 	if (verbose) {
 		struct netmap_if *nifp = g.nmd->nifp;
 		struct nmreq *req = &g.nmd->req;

From a3a41f1c8e398f91724d4915ffced64c9d30207a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Mon, 3 Dec 2018 14:20:37 +0100
Subject: [PATCH 1467/2207] mlx5: upgrade to 4.5

---
 LINUX/default-config.mak.in_            |   6 +-
 LINUX/final-patches/mellanox--mlx5--4.5 | 315 ++++++++++++++++++++++++
 LINUX/mlx5_netmap_linux.h               | 164 ++++++------
 3 files changed, 394 insertions(+), 91 deletions(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--4.5

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 258ec7e28..1941d0a7e 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -90,8 +90,8 @@ $(eval $(call default,i40e,2.4.6))
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 
 define mellanox_driver
-$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://content.mellanox.com/Drivers/mlnx-en-$(2).tgz -P @SRCDIR@/ext-drivers
-$(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
+$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz || wget http://content.mellanox.com/ofed/MLNX_EN-$(2)/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz -P @SRCDIR@/ext-drivers
+$(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz && tar xf mlnx-en-$(2)-ubuntu18.04-x86_64/src/MLNX_EN_SRC-$(2).tgz && tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
 $(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@ @TMPDIR@
 $(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$(EXTRA_CFLAGS)"
@@ -101,7 +101,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,3.3-1.0.0.0))
+$(eval $(call default,mlx5,4.5-1.0.1.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 
diff --git a/LINUX/final-patches/mellanox--mlx5--4.5 b/LINUX/final-patches/mellanox--mlx5--4.5
new file mode 100644
index 000000000..cf79dd9c3
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--4.5
@@ -0,0 +1,315 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index bda9ec7..74cf699 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -1,8 +1,8 @@
+ # SPDX-License-Identifier: GPL-2.0
+-obj-$(CONFIG_MLX5_CORE)		+= mlx5_core.o
++obj-$(CONFIG_MLX5_CORE)		+= mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ subdir-ccflags-y += -I$(src)
+ 
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o srq.o srq_exp.o alloc.o qp.o port.o mr.o pd.o \
+ 		mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
+ 		fs_counters.o rl.o lag.o dev.o wq.o lib/gid.o lib/clock.o \
+@@ -11,24 +11,24 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		icmd.o capi.o diag/fw_tracer.o diag/diag_cnt.o \
+ 		eswitch_devlink_compat.o
+ 
+-mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
+ 		fpga/ipsec.o fpga/tls.o fpga/trans.o fpga/xfer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en_stats.o vxlan.o en_sysfs.o en_ecn.o \
+ 		en_arfs.o en_fs_ethtool.o en_selftest.o en/port.o en_debugfs.o en_sniffer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_MPFS) += lib/mpfs.o
+ 
+-mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
+ 
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o en/port_buffer.o
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o en/port_buffer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 		en_accel/ipsec_stats.o
+ 
+ mlx5_core-$(CONFIG_MLX5_EN_TLS) +=  en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index f0a23e9..3d7e6e5 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -57,6 +57,16 @@
+ #endif
+ #include "en/port.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ struct mlx5e_rq_param {
+ 	u32			rqc[MLX5_ST_SZ_DW(rqc)];
+ 	struct mlx5_wq_param	wq;
+@@ -89,6 +99,9 @@ struct mlx5e_channel_param {
+ 
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -841,6 +854,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ 		rq->dim_obj.dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_free:
+@@ -1062,6 +1079,12 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 	struct mlx5e_channel *c = rq->channel;
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(c->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1104,6 +1127,10 @@ static void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->channel->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1213,6 +1240,9 @@ static void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ 
+ 	u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->channel->netdev)) || NA(rq->channel->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	sq->db.ico_wqe[pi].opcode     = MLX5_OPCODE_NOP;
+ 	nopwqe = mlx5e_post_nop(wq, sq->sqn, &sq->pc);
+@@ -1415,6 +1445,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1628,6 +1663,9 @@ static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	netif_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1645,6 +1683,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 	struct mlx5_rate_limit rl = {0};
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -1663,6 +1707,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->channel->netdev,
+@@ -3306,6 +3354,10 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 	if (priv->profile->update_carrier)
+ 		priv->profile->update_carrier(priv);
+ 
++#ifdef DEV_NETMAP
++	netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	if (priv->profile->update_stats)
+ 		queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
+ 
+@@ -3352,6 +3404,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++	netmap_disable_all_rings(netdev);
++#endif
++
+ 	if (MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER)) {
+ 		mlx5e_sniffer_stop(priv);
+ 		MLX5E_SET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER, 0);
+@@ -5977,6 +6033,11 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ 	const struct mlx5e_profile *profile = priv->profile;
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
++
+ 	destroy_workqueue(priv->wq);
+ 	if (profile->cleanup)
+ 		profile->cleanup(priv);
+@@ -6089,6 +6150,11 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
+ 	mlx5e_dcbnl_init_app(priv);
+ #endif
+ #endif
++
++#ifdef DEV_NETMAP
++	mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return priv;
+ 
+ err_unregister_netdev:
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index d85e0f3..4b0068f 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -50,6 +50,14 @@
+ #include "en_accel/ipsec_rxtx.h"
+ #include "lib/clock.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -155,7 +163,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5e_cq *cq,
+ 					      int budget_rem)
+ {
+@@ -1739,6 +1747,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 124b676..4864b16 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -38,6 +38,15 @@
+ #include "en_accel/en_accel.h"
+ #include "lib/clock.h"
+ 
++
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ #define MLX5E_SQ_NOPS_ROOM  MLX5_SEND_WQE_MAX_WQEBBS
+ 
+ #if defined(CONFIG_MLX5_EN_TLS) && defined(HAVE_UAPI_LINUX_TLS_H)
+@@ -550,6 +559,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->channel->netdev, sq->channel->ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -676,15 +690,17 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 			continue;
+ 		}
+ 
+-		for (i = 0; i < wi->num_dma; i++) {
+-			struct mlx5e_sq_dma *dma =
+-				mlx5e_dma_get(sq, sq->dma_fifo_cc++);
++		if (!nm_netmap_on(NA(sq->txq->dev))) {
++			/* do not free skbs in netmap mode */
++			for (i = 0; i < wi->num_dma; i++) {
++				struct mlx5e_sq_dma *dma =
++					mlx5e_dma_get(sq, sq->dma_fifo_cc++);
+ 
+-			mlx5e_tx_dma_unmap(sq->pdev, dma);
++				mlx5e_tx_dma_unmap(sq->pdev, dma);
++			}
++			dev_kfree_skb_any(skb);
+ 		}
+-
+-		dev_kfree_skb_any(skb);
+-		sq->cc += wi->num_wqebbs;
++        sq->cc += wi->num_wqebbs;
+ 	}
+ }
+ 
diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index 852213b74..ba6263ddc 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -89,15 +89,13 @@
 
 #define NM_MLX5E_ADAPTER mlx5e_priv
 
-/* These functions are in en_rx.c but needed here to
+/* This function is in en_rx.c but needed here to
  * deal with compressed CQEs
  */
-inline void mlx5e_read_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data);
-inline void mlx5e_write_cqe_slot(struct mlx5e_cq *cq, u32 cc, void *data);
-inline void mlx5e_decompress_cqe(struct mlx5e_cq *cq, struct mlx5_cqe64 *title,
-                                 struct mlx5_mini_cqe8 *mini, u16 wqe_counter,
-                                 int i);
-void mlx5e_decompress_cqes(struct mlx5e_cq *cq);
+u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+                          struct mlx5e_cq *cq,
+                          int budget_rem);
+
 
 /*
  * Register/unregister. We are already under netmap lock.
@@ -139,6 +137,10 @@ int mlx5e_netmap_reg(struct netmap_adapter *na, int onoff) {
   return err;
 }
 
+#define MLX5E_SQ_NOPS_ROOM  MLX5_SEND_WQE_MAX_WQEBBS
+#define MLX5E_SQ_STOP_ROOM (MLX5_SEND_WQE_MAX_WQEBBS +\
+                MLX5E_SQ_NOPS_ROOM)
+
 /*
  * Reconcile kernel and user view of the transmit ring.
  *
@@ -168,7 +170,8 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
   /* device-specific */
   struct NM_MLX5E_ADAPTER *priv = netdev_priv(ifp);
 
-  struct mlx5e_sq *sq = priv->txq_to_sq_map[ring_nr];
+  struct mlx5e_txqsq *sq = priv->txq2sq[ring_nr];
+  struct mlx5_wq_cyc *wq = &sq->wq;
   struct mlx5e_cq *cq = &(sq->cq);
   struct mlx5e_tx_wqe *wqe = NULL;
   struct mlx5_cqe64 *cqe = NULL;
@@ -200,6 +203,9 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
      */
 
     for (n = 0; nm_i != head; n++) {
+      if (unlikely(!mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, MLX5E_SQ_STOP_ROOM))) {
+          break;
+      }
 
       struct netmap_slot *slot = &ring->slot[nm_i];
       u_int len = slot->len;
@@ -208,8 +214,7 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
 
       /* Code below based on mlx5e_sq_xmit() in en_tx.c */
 
-      struct mlx5_wq_cyc *wq = &sq->wq;
-      u16 pi = sq->pc & wq->sz_m1; /* producer index */
+      u16 pi = sq->pc & wq->fbc.sz_m1; /* producer index */
 
       u8 opcode = MLX5_OPCODE_SEND;
       u16 ds_cnt;
@@ -231,16 +236,16 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
       eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
 
       /* Use minimum inline header to minimise data copying */
-      ihs = ETH_HLEN + 2; /* MAC + MAC + VLAN + Ethertype = 16 bytes */
+      ihs = ETH_HLEN;
 
       if (unlikely(ihs > len))
         ihs = len; /* whole packet fits inline */
 
-      memcpy(eseg->inline_hdr_start, addr, ihs);
-      eseg->inline_hdr_sz = cpu_to_be16(ihs);
+      memcpy(eseg->inline_hdr.start, addr, ihs);
+      eseg->inline_hdr.sz = cpu_to_be16(ihs);
 
       ds_cnt +=
-          DIV_ROUND_UP(ihs - sizeof(eseg->inline_hdr_start), MLX5_SEND_WQE_DS);
+          DIV_ROUND_UP(ihs - sizeof(eseg->inline_hdr.start), MLX5_SEND_WQE_DS);
 
       dseg = (struct mlx5_wqe_data_seg *)cseg + ds_cnt;
 
@@ -266,28 +271,18 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
        *   - slot number in the netmap kring that this wqe is sending
        *           (in bottom 24 bits)
        */
-      sq->skb[pi] = (void *)(uintptr_t)(nm_i & 0x00FFFFFF) +
-                    ((uintptr_t)num_wqebbs << 24);
+      sq->db.wqe_info[pi].skb = (void *)(uintptr_t)(nm_i & 0x00FFFFFF);
+      sq->db.wqe_info[pi].num_wqebbs = num_wqebbs;
 
-      /* fill sq edge with nops to avoid wqe wrap around */
-      while ((sq->pc & wq->sz_m1) > sq->edge)
-        mlx5e_send_nop(sq, false);
+      mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, cseg);
 
-      sq->stats.packets++;
+      sq->stats->packets++;
 
       /* next netmap slot */
       nm_i = nm_next(nm_i, lim);
     } /* next packet */
 
-    /* Wake up the hardware if any packets enqueued */
-    if (wqe) {
-      /* Request a CQE when the final WQE has completed */
-      cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
-
-      mlx5e_tx_notify_hw(sq, wqe, 0);
-    }
-
-    kring->nr_hwcur = head;
+    kring->nr_hwcur = nm_i;
   }
 
   /*
@@ -301,7 +296,7 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
    * otherwise a cq overrun may occur */
   sqcc = sq->cc;
 
-  cqe = mlx5e_get_cqe(cq);
+  cqe = mlx5_cqwq_get_cqe(&cq->wq);
 
   while (cqe) {
     u16 wqe_counter;
@@ -309,27 +304,25 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
 
     cqe_found = 1;
     mlx5_cqwq_pop(&cq->wq);
-    mlx5e_prefetch_cqe(cq);
 
     /* this cqe could relate to many wqes */
     wqe_counter = be16_to_cpu(cqe->wqe_counter);
 
     do {
-      u16 ci = sqcc & sq->wq.sz_m1;
-      void *skb = sq->skb[ci];
-      u8 num_wqebbs;
+      u16 ci = sqcc & sq->wq.fbc.sz_m1;
+      void *skb = sq->db.wqe_info[ci].skb;
+      u8 num_wqebbs = sq->db.wqe_info[ci].num_wqebbs;
       u32 nm_i_done;
 
       last_wqe = (sqcc == wqe_counter);
 
       if (unlikely(!skb)) { /* nop */
-        sq->stats.nop++;
+        sq->stats->nop++;
         sqcc++;
         continue;
       }
 
-      /* unpack num_wqebbs and slot number from skb pointer */
-      num_wqebbs = (u8)((uintptr_t)skb >> 24);
+      /* unpack slot number from skb pointer */
       nm_i_done = (u32)((uintptr_t)skb & 0x00FFFFFF);
 
       sqcc += num_wqebbs;
@@ -337,7 +330,7 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
 
     } while (!last_wqe);
 
-    cqe = mlx5e_get_cqe(cq);
+    cqe = mlx5_cqwq_get_cqe(&cq->wq);
   }
 
   if (cqe_found) {
@@ -379,17 +372,17 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
 
   /* device-specific */
   struct NM_MLX5E_ADAPTER *priv = netdev_priv(ifp);
-  struct mlx5e_rq *rq = &(priv->channel[ring_nr]->rq);
+  struct mlx5e_rq *rq = &(priv->channels.c[ring_nr]->rq);
   struct mlx5e_cq *cq = &(rq->cq);
   struct mlx5_cqe64 *cqe = NULL;
   int cqe_found = 0;
-
+/*
   if (unlikely(rq->rq_type == RQ_TYPE_STRIDE)) {
     netdev_err(ifp,
                "RQ type is STRIDING - this is not supported in netmap mode\n");
     return 0;
   }
-
+*/
   if (!netif_carrier_ok(ifp))
     return 0;
 
@@ -408,14 +401,13 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
   nm_i = kring->nr_hwcur;
 
   if (nm_i != head) {
-
-    struct mlx5_wq_ll *wq = &rq->wq;
-    struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
+    struct mlx5_wq_cyc *wq = &rq->wqe.wq;
+    struct mlx5e_rx_wqe_cyc *wqe = mlx5_wq_cyc_get_wqe(wq, mlx5_wq_cyc_get_head(wq));
     struct netmap_slot *slot;
     uint64_t paddr;
     void *addr;
 
-    while (nm_i != head && !mlx5_wq_ll_is_full(wq)) {
+    while (nm_i != head && !mlx5_wq_cyc_is_full(wq)) {
 
       slot = &ring->slot[nm_i];
       addr = PNMB(na, slot, &paddr); /* find phys address */
@@ -430,10 +422,10 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
         slot->flags &= ~NS_BUF_CHANGED;
       }
 
-      wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
-      wqe->data.addr = cpu_to_be64(paddr);
+      wqe = mlx5_wq_cyc_get_wqe(wq, mlx5_wq_cyc_get_head(wq));
+      wqe->data->addr = cpu_to_be64(paddr);
 
-      mlx5_wq_ll_push(wq, be16_to_cpu(wqe->next.next_wqe_index));
+      mlx5_wq_cyc_push(wq);
 
       nm_i = nm_next(nm_i, lim);
     }
@@ -442,7 +434,7 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
 
     /* ensure wqes are visible to device before updating doorbell record */
     wmb();
-    mlx5_wq_ll_update_db_record(wq);
+    mlx5_wq_cyc_update_db_record(wq);
   }
 
   /*
@@ -453,36 +445,34 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
    */
   nm_i = kring->nr_hwtail;
 
-  cqe = mlx5e_get_cqe(cq);
+  cqe = mlx5_cqwq_get_cqe(&cq->wq);
 
   while (cqe) {
-    struct mlx5e_rx_wqe *wqe;
+    struct mlx5e_rx_wqe_cyc *wqe;
     u16 bytes_recv = 0;
     __be16 wqe_id_be;
     u16 wqe_counter;
 
     cqe_found = 1;
-
     if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED)
-      mlx5e_decompress_cqes(&rq->cq);
+        mlx5e_decompress_cqes_start(rq, &rq->cq, 1024);
 
     mlx5_cqwq_pop(&cq->wq);
-    mlx5e_prefetch_cqe(cq);
 
     wqe_id_be = cqe->wqe_counter;
     wqe_counter = be16_to_cpu(wqe_id_be);
-    wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
+    wqe = mlx5_wq_cyc_get_wqe( &rq->wqe.wq, wqe_counter);
     bytes_recv = be32_to_cpu(cqe->byte_cnt);
 
     if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) {
-      rq->stats.wqe_err++;
+      rq->stats->wqe_err++;
       netdev_warn(ifp, "Bad response found in CQE for RQ %u\n", ring_nr);
-      goto wq_ll_pop;
+      goto wq_cyc_pop;
     }
 
-    rq->stats.packets++;
+    rq->stats->packets++;
     if (cqe->hds_ip_ext & CQE_L4_OK)
-      rq->stats.csum_good++;
+      rq->stats->csum_unnecessary++;
 
     /* could analyse checksums more thoroughly using flags in
      * l4_hdr_type_etc that us which checksums are applicable
@@ -500,9 +490,9 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
     ring->slot[nm_i].flags = slot_flags;
     nm_i = nm_next(nm_i, lim);
 
-  wq_ll_pop:
-    cqe = mlx5e_get_cqe(cq);
-    mlx5_wq_ll_pop(&rq->wq, wqe_id_be, &wqe->next.next_wqe_index);
+  wq_cyc_pop:
+    cqe = mlx5_cqwq_get_cqe(&cq->wq);
+    mlx5_wq_cyc_pop(&rq->wqe.wq);
   }
 
   if (cqe_found) {
@@ -527,7 +517,7 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
 /*
  * Acknowledge and clear all CQEs when TX queue is closing down
  */
-int mlx5e_netmap_tx_flush(struct mlx5e_sq *sq) {
+int mlx5e_netmap_tx_flush(struct mlx5e_txqsq *sq) {
   struct mlx5e_cq *cq = &(sq->cq);
   struct mlx5_cqe64 *cqe;
   u16 sqcc;
@@ -539,36 +529,35 @@ int mlx5e_netmap_tx_flush(struct mlx5e_sq *sq) {
   sqcc = sq->cc;
 
   /* Any completed jobs in the CQ? */
-  cqe = mlx5e_get_cqe(cq);
+  cqe = mlx5_cqwq_get_cqe(&cq->wq);
 
   while (cqe) {
     u16 wqe_counter;
     bool last_wqe;
 
     mlx5_cqwq_pop(&cq->wq);
-    mlx5e_prefetch_cqe(cq);
 
     /* this cqe could relate to many wqes */
     wqe_counter = be16_to_cpu(cqe->wqe_counter);
 
     do {
-      u16 ci = sqcc & sq->wq.sz_m1;
-      void *skb = sq->skb[ci];
+      u16 ci = sqcc & sq->wq.fbc.sz_m1;
+      void *skb = sq->db.wqe_info[ci].skb;
+      u8 num_wqebbs = sq->db.wqe_info[ci].num_wqebbs;
 
       last_wqe = (sqcc == wqe_counter);
 
       if (unlikely(!skb)) { /* nop */
-        sq->stats.nop++;
+        sq->stats->nop++;
         sqcc++;
         continue;
       }
 
-      /* extract num_wqebbs from skb pointer */
-      sqcc += (u8)((uintptr_t)skb >> 24);
+      sqcc += num_wqebbs;
 
     } while (!last_wqe);
 
-    cqe = mlx5e_get_cqe(cq);
+    cqe = mlx5_cqwq_get_cqe(&cq->wq);
   }
 
   mlx5_cqwq_update_db_record(&cq->wq);
@@ -589,25 +578,24 @@ int mlx5e_netmap_rx_flush(struct mlx5e_rq *rq) {
 
   rmb();
 
-  cqe = mlx5e_get_cqe(cq);
+  cqe = mlx5_cqwq_get_cqe(&cq->wq);
 
   while (cqe) {
-    struct mlx5e_rx_wqe *wqe;
+    struct mlx5e_rx_wqe_cyc *wqe;
     __be16 wqe_id_be;
     u16 wqe_counter;
 
     if (mlx5_get_cqe_format(cqe) == MLX5_COMPRESSED)
-      mlx5e_decompress_cqes(&rq->cq);
+        mlx5e_decompress_cqes_start(rq, &rq->cq, 1024);
 
     mlx5_cqwq_pop(&cq->wq);
-    mlx5e_prefetch_cqe(cq);
 
     wqe_id_be = cqe->wqe_counter;
     wqe_counter = be16_to_cpu(wqe_id_be);
-    wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
+    wqe = mlx5_wq_cyc_get_wqe(&rq->wqe.wq, wqe_counter);
 
-    cqe = mlx5e_get_cqe(cq);
-    mlx5_wq_ll_pop(&rq->wq, wqe_id_be, &wqe->next.next_wqe_index);
+    cqe = mlx5_cqwq_get_cqe(&cq->wq);
+    mlx5_wq_cyc_pop(&rq->wqe.wq);
   }
 
   mlx5_cqwq_update_db_record(&cq->wq);
@@ -654,7 +642,7 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
   int lim; /* number of WQEs to prepare */
   int count = 0;
 
-  struct mlx5_wq_ll *wq = &rq->wq;
+  struct mlx5_wq_cyc *wq = &rq->wqe.wq;
 
   slot = netmap_reset(na, NR_RX, ring_nr, 0);
   if (!slot)
@@ -662,16 +650,16 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
 
   lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 
-  while (!mlx5_wq_ll_is_full(wq) && (count < lim)) {
+  while (!mlx5_wq_cyc_is_full(wq) && (count < lim)) {
 
-    struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(wq, wq->head);
+    struct mlx5e_rx_wqe_cyc *wqe = mlx5_wq_cyc_get_wqe(wq, mlx5_wq_cyc_get_head(wq));
 
     uint64_t paddr;
     PNMB(na, slot + count, &paddr);
 
-    wqe->data.addr = cpu_to_be64(paddr);
+    wqe->data->addr = cpu_to_be64(paddr);
 
-    mlx5_wq_ll_push(wq, be16_to_cpu(wqe->next.next_wqe_index));
+    mlx5_wq_cyc_push(wq);
     count++;
   }
 
@@ -682,7 +670,7 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
 
   /* ensure wqes are visible to device before updating doorbell record */
   wmb();
-  mlx5_wq_ll_update_db_record(wq);
+  mlx5_wq_cyc_update_db_record(wq);
 
   return 1;
 }
@@ -712,16 +700,16 @@ void mlx5e_netmap_attach(struct NM_MLX5E_ADAPTER *adapter) {
 
   na.ifp = adapter->netdev;
   na.pdev = &adapter->mdev->pdev->dev;
-  na.num_tx_desc = (1 << adapter->params.log_sq_size);
-  na.num_rx_desc = (1 << adapter->params.log_rq_size);
+  na.num_tx_desc = (1 << adapter->channels.params.log_sq_size);
+  na.num_rx_desc = (1 << adapter->channels.params.log_rq_mtu_frames);
   na.nm_txsync = mlx5e_netmap_txsync;
   na.nm_rxsync = mlx5e_netmap_rxsync;
   na.nm_register = mlx5e_netmap_reg;
   na.nm_config = mlx5e_netmap_config;
 
   /* each channel has 1 rx ring and a tx for each tc */
-  na.num_tx_rings = adapter->params.num_channels * adapter->params.num_tc;
-  na.num_rx_rings = adapter->params.num_channels;
+  na.num_tx_rings = adapter->channels.params.num_channels * adapter->channels.params.num_tc;
+  na.num_rx_rings = adapter->channels.params.num_channels;
   na.rx_buf_maxsize = 1500; /* will be overwritten by nm_config */
   netmap_attach(&na);
 }

From 760279cfb2730a585b3fcf69b9771e196ce376e1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 5 Dec 2018 12:03:14 +0100
Subject: [PATCH 1468/2207] null: add missing netmap_adapter_get()

This caused reference counter to go negative and cause crashes.
---
 sys/dev/netmap/netmap_null.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index 4f0c64720..b769ae7ed 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -169,6 +169,7 @@ netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	if (error)
 		goto free_nna;
 	*na = &nna->up;
+	netmap_adapter_get(*na);
 	nm_prdis("created null %s", nna->up.name);
 
 	return 0;

From 10a9b04e75a9284cec438cb3131dec7ebefa311d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= 
Date: Wed, 5 Dec 2018 14:08:34 +0100
Subject: [PATCH 1469/2207] mlx5: don't skip prepare step when building patched
 driver

---
 LINUX/default-config.mak.in_ | 2 +-
 LINUX/mlx5-prepare.sh        | 7 -------
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 258ec7e28..399712b79 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -93,7 +93,7 @@ define mellanox_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz || wget http://content.mellanox.com/Drivers/mlnx-en-$(2).tgz -P @SRCDIR@/ext-drivers
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2).tgz && tar xf mlnx-en-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
-$(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@ @TMPDIR@
+$(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@
 $(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$(EXTRA_CFLAGS)"
 $(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
diff --git a/LINUX/mlx5-prepare.sh b/LINUX/mlx5-prepare.sh
index c03d45548..d567c3f02 100755
--- a/LINUX/mlx5-prepare.sh
+++ b/LINUX/mlx5-prepare.sh
@@ -1,17 +1,10 @@
 #!/bin/sh -x
 
 KSRC=$1
-TMPDIR=$2
 
 if [ -e mlx5/config.mk ]; then
 	exit 0
 fi
 
-if [ -e $TMPDIR/mlx5/config.mk ]; then
-	sed "s|^CWD=.*|CWD=$PWD/mlx5|" $TMPDIR/mlx5/config.mk > mlx5/config.mk
-	cp -r $TMPDIR/mlx5/compat/* mlx5/compat/
-	exit 0
-fi
-
 cd mlx5
 scripts/mlnx_en_patch.sh --without-mlx4 -s $KSRC -j$(grep -c processor /proc/cpuinfo)

From fe926125e8e61aa58763dce4f6e4fc0d2cf498e2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 5 Dec 2018 16:56:46 +0100
Subject: [PATCH 1470/2207] FreeBSD: netmap.h: include stdatomic.h

The stdatomic.h header exports atomic_thread_fence(), that
can be used to implement the nm_stst_barrier() macro needed
by netmap.
---
 sys/net/netmap.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index c50c1de2b..60a1d22c7 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -784,9 +784,10 @@ static inline void nm_stst_barrier(void)
 #ifdef _KERNEL
 #define nm_stst_barrier	atomic_thread_fence_rel
 #else  /* !_KERNEL */
+#include 
 static inline void nm_stst_barrier(void)
 {
-	__atomic_thread_fence(__ATOMIC_RELEASE);
+	atomic_thread_fence(memory_order_release);
 }
 #endif /* !_KERNEL */
 

From fda138e7312004cd5765c1778c458019390ecc82 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Dec 2018 17:56:47 +0100
Subject: [PATCH 1471/2207] pipe: make sure both ends use the same number of
 slots

---
 sys/dev/netmap/netmap_pipe.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 92653b7d6..c5bfc367a 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -782,9 +782,11 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* most fields are the same, copy from master and then fix */
 	*sna = *mna;
 	sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
-	/* swap the number of tx/rx rings */
+	/* swap the number of tx/rx rings and slots */
 	sna->up.num_tx_rings = mna->up.num_rx_rings;
+	sna->up.num_tx_desc  = mna->up.num_rx_desc;
 	sna->up.num_rx_rings = mna->up.num_tx_rings;
+	sna->up.num_rx_desc  = mna->up.num_tx_desc;
 	snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
 	sna->role = NM_PIPE_ROLE_SLAVE;
 	error = netmap_attach_common(&sna->up);

From 6402da309026c94b744aa552e453f32dd553d300 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Dec 2018 10:11:32 +0100
Subject: [PATCH 1472/2207] linux/i40e: patch for Intel 2.7.26 version

---
 LINUX/final-patches/intel--i40e--2.7.26 | 167 ++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.7.26

diff --git a/LINUX/final-patches/intel--i40e--2.7.26 b/LINUX/final-patches/intel--i40e--2.7.26
new file mode 100644
index 000000000..242a42fe2
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.7.26
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 4d046c5..5f2e15a 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 6d2e21d..9845b9d 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -132,6 +132,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3442,6 +3447,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3495,6 +3504,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3523,6 +3536,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13432,6 +13450,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13804,6 +13827,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 1859d78..ea1be59 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -783,6 +787,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 180e079837587acaf1dec9ea56dee3e640d75beb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 6 Dec 2018 12:44:38 +0100
Subject: [PATCH 1473/2207] FreeBSD: netmap_transmit should honor bpf packet
 tap hook

This allows tcpdump to capture outbound kernel packets while
in netmap mode.

Submitted by:   Marc de la Gueronniere 
Reviewed by:    vmaffione
Sponsored by:   Verisign, Inc.
Differential Revision:  https://reviews.freebsd.org/D17896
---
 sys/dev/netmap/netmap.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 49047510f..b5f450e10 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -449,6 +449,7 @@ ports attached to the switch)
 #include 	/* bus_dmamap_* */
 #include 
 #include 
+#include 	/* ETHER_BPF_MTAP */
 
 
 #elif defined(linux)
@@ -3860,6 +3861,10 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 		goto done;
 	}
 
+#ifdef __FreeBSD__
+	ETHER_BPF_MTAP(ifp, m);
+#endif /* __FreeBSD__ */
+
 	/* protect against netmap_rxsync_from_host(), netmap_sw_to_nic()
 	 * and maybe other instances of netmap_transmit (the latter
 	 * not possible on Linux).

From 3f2b38ecebd4fc53598db185c72b58deb6d74243 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 7 Dec 2018 10:16:52 +0100
Subject: [PATCH 1474/2207] utils: sync_kloop_test: fix build issue

---
 utils/sync_kloop_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/sync_kloop_test.c b/utils/sync_kloop_test.c
index 3c66bfc0b..0b9069f19 100644
--- a/utils/sync_kloop_test.c
+++ b/utils/sync_kloop_test.c
@@ -86,7 +86,7 @@ kloop_worker(void *opaque)
 	return NULL;
 }
 
-inline int
+static inline int
 ringspace(struct netmap_ring *ring, uint32_t head)
 {
 	int space = ring->tail - head;

From dd9c08c644fa407d23d1287863c43eb6bd913025 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 7 Dec 2018 10:53:39 +0100
Subject: [PATCH 1475/2207] utils: ctrl-api-test: don't pass int variables
 through pthread_exit

This causes subtle memory corruption (catched on FreeBSD).
---
 utils/ctrl-api-test.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 2d76c0478..9a42017f0 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -26,6 +26,9 @@ eventfd(int x, int y)
 }
 #endif /* __linux__ */
 
+#define THRET_SUCCESS	((void *)128)
+#define THRET_FAILURE	((void *)0)
+
 struct TestContext {
 	int fd; /* netmap file descriptor */
 	char *ifname;
@@ -1144,14 +1147,14 @@ sync_kloop_worker(void *opaque)
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
 
-	pthread_exit((void *)(uintptr_t)ret);
+	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
 }
 
 static int
 sync_kloop_start_stop(struct TestContext *ctx)
 {
 	pthread_t th;
-	int thret;
+	void *thret = THRET_FAILURE;
 	int ret;
 
 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
@@ -1165,12 +1168,12 @@ sync_kloop_start_stop(struct TestContext *ctx)
 		return ret;
 	}
 
-	ret = pthread_join(th, (void **)&thret);
+	ret = pthread_join(th, &thret);
 	if (ret) {
 		printf("pthread_join(kloop): %s\n", strerror(ret));
 	}
 
-	return thret;
+	return thret == THRET_SUCCESS ? 0 : -1;
 }
 
 static int
@@ -1341,7 +1344,7 @@ sync_kloop_conflict(struct TestContext *ctx)
 {
 	struct nmreq_opt_csb opt;
 	pthread_t th1, th2;
-	int thret1, thret2;
+	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
@@ -1376,18 +1379,19 @@ sync_kloop_conflict(struct TestContext *ctx)
 		return ret;
 	}
 
-	ret = pthread_join(th1, (void **)&thret1);
+	ret = pthread_join(th1, &thret1);
 	if (ret) {
 		printf("pthread_join(kloop1): %s\n", strerror(ret));
 	}
 
-	ret = pthread_join(th2, (void **)&thret2);
+	ret = pthread_join(th2, &thret2);
 	if (ret) {
-		printf("pthread_join(kloop2): %s\n", strerror(ret));
+		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
 	}
 
 	/* Check that one of the two failed, while the other one succeeded. */
-	return ((thret1 == 0 && thret2 != 0) || (thret1 != 0 && thret2 == 0))
+	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
+			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
 	               ? 0
 	               : -1;
 }

From 1231b88330f4f7fb95872355ac64617761221505 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 8 Dec 2018 19:36:59 +0100
Subject: [PATCH 1476/2207] utils: ctrl-api-test: fix compiler warning

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 9a42017f0..db39f3c98 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -31,7 +31,7 @@ eventfd(int x, int y)
 
 struct TestContext {
 	int fd; /* netmap file descriptor */
-	char *ifname;
+	const char *ifname;
 	const char *bdgname;
 	uint32_t nr_tx_slots;   /* slots in tx rings */
 	uint32_t nr_rx_slots;   /* slots in rx rings */

From 62d48f676eff1beeff54d0ba1675596a242f72d2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 9 Dec 2018 11:18:12 +0100
Subject: [PATCH 1477/2207] utils: ctrl-api-test: fix compiler warning

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index db39f3c98..83d7d2f8a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1063,7 +1063,7 @@ push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
 	memset(opt, 0, sizeof(*opt));
 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
 	opt->csb_atok            = (uintptr_t)ctx->csb;
-	opt->csb_ktoa            = (uintptr_t)(ctx->csb +
+	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
                                     sizeof(struct nm_csb_atok) * num_entries);
 
 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");

From 5b3ec3b782f5bc3b8f5be8df2df47e788d3435ee Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 9 Dec 2018 15:10:15 +0100
Subject: [PATCH 1478/2207] utils: ctrl-api-test: use dedicated tap interface
 as default

This helps interoperability with FreeBSD.
---
 utils/ctrl-api-test.c | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 83d7d2f8a..63e85067a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1598,17 +1598,17 @@ int
 main(int argc, char **argv)
 {
 	struct TestContext ctx;
-	int loopback_if;
 	int num_tests;
 	int ret  = 0;
 	int j    = 0;
 	int k    = -1;
 	int list = 0;
+	int create_tap = 1;
 	int opt;
 	int i;
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname  = "lo";
+	ctx.ifname  = "tap931";
 	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
@@ -1619,6 +1619,7 @@ main(int argc, char **argv)
 
 		case 'i':
 			ctx.ifname = optarg;
+			create_tap = 0;
 			break;
 
 		case 'j':
@@ -1658,14 +1659,15 @@ main(int argc, char **argv)
 		return 0;
 	}
 
-	loopback_if = !strcmp(ctx.ifname, "lo");
-	if (loopback_if) {
-		/* For the tests, we need the MTU to be smaller than
-		 * the NIC RX buffer size, otherwise we will fail on
-		 * registering the interface. To stay safe, let's
-		 * just use a standard MTU. */
-		if (system("ip link set dev lo mtu 1514")) {
-			printf("system(%s, mtu=1514) failed\n", ctx.ifname);
+	if (create_tap) {
+		char cmdbuf[64];
+#ifdef __FreeBSD__
+		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s create up", ctx.ifname);
+#else
+		snprintf(cmdbuf, sizeof(cmdbuf), "ip tuntap add mode tap name %s", ctx.ifname);
+#endif
+		if (system(cmdbuf)) {
+			printf("%s: failed\n", cmdbuf);
 			return -1;
 		}
 	}
@@ -1691,9 +1693,15 @@ main(int argc, char **argv)
 		context_cleanup(&ctxcopy);
 	}
 out:
-	if (loopback_if) {
-		if (system("ip link set dev lo mtu 65536")) {
-			perror("system(mtu=1514)");
+	if (create_tap) {
+		char cmdbuf[64];
+#ifdef __FreeBSD__
+		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s destroy", ctx.ifname);
+#else
+		snprintf(cmdbuf, sizeof(cmdbuf), "ip link del %s", ctx.ifname);
+#endif
+		if (system(cmdbuf)) {
+			printf("%s: failed\n", cmdbuf);
 			return -1;
 		}
 	}

From c14f3399281a7abf9bc3a6a211e95e4a747028be Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 9 Dec 2018 21:41:16 +0100
Subject: [PATCH 1479/2207] utils: ctrl-api-test: randomly generate tap name

---
 utils/ctrl-api-test.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 63e85067a..fa1f345e3 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifdef __linux__
 #include 
@@ -1598,17 +1599,25 @@ int
 main(int argc, char **argv)
 {
 	struct TestContext ctx;
+	int create_tap = 1;
+	char tapname[64];
 	int num_tests;
 	int ret  = 0;
 	int j    = 0;
 	int k    = -1;
 	int list = 0;
-	int create_tap = 1;
 	int opt;
 	int i;
 
+	{
+		int tapidx;
+		srand(time(0));
+		tapidx = rand() % 8000 + 100;
+		snprintf(tapname, sizeof(tapname), "tap%d", tapidx);
+	}
+
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname  = "tap931";
+	ctx.ifname  = tapname;
 	ctx.bdgname = "vale1x2";
 
 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {

From 04bc2c3e4827df7aa22d56b797a8f8e47424a408 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 09:49:42 +0100
Subject: [PATCH 1480/2207] utils: ctrl-api-test: use calloc() instead of
 malloc() + memset()

---
 utils/ctrl-api-test.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fa1f345e3..592b8f2cf 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1201,8 +1201,7 @@ sync_kloop_eventfds(struct TestContext *ctx)
 
 	num_entries = num_registered_rings(ctx);
 	opt_size    = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
-	opt         = malloc(opt_size);
-	memset(opt, 0, opt_size);
+	opt = calloc(1, opt_size);
 	opt->nro_opt.nro_next    = 0;
 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
 	opt->nro_opt.nro_status  = 0;

From 8aee2224a082312e4aaddd2fdd37ba2aef82b45d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 09:50:52 +0100
Subject: [PATCH 1481/2207] utils: ctrl-api-test: prune dead code

---
 utils/ctrl-api-test.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 592b8f2cf..50f9543b0 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -54,18 +54,6 @@ struct TestContext {
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
 };
 
-#if 0
-static void
-ctx_reset(struct TestContext *ctx)
-{
-	const char *tmp1 = ctx->ifname;
-	const char *tmp2 = ctx->bdgname;
-	memset(ctx, 0, sizeof(*ctx));
-	ctx->ifname = tmp1;
-	ctx->bdgname = tmp2;
-}
-#endif
-
 typedef int (*testfunc_t)(struct TestContext *ctx);
 
 static void

From 57a27b5097cd29f47b5734bb7796ff4824133ac0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 10:00:39 +0100
Subject: [PATCH 1482/2207] utils: ctrl-api-test: avoid pointers to stack
 (string) variables

---
 utils/ctrl-api-test.c | 76 +++++++++++++++++++------------------------
 1 file changed, 33 insertions(+), 43 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 50f9543b0..f8c1e3b01 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -32,8 +32,8 @@ eventfd(int x, int y)
 
 struct TestContext {
 	int fd; /* netmap file descriptor */
-	const char *ifname;
-	const char *bdgname;
+	char ifname[128];
+	char bdgname[64];
 	uint32_t nr_tx_slots;   /* slots in tx rings */
 	uint32_t nr_rx_slots;   /* slots in rx rings */
 	uint16_t nr_tx_rings;   /* number of tx rings */
@@ -188,7 +188,8 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname);
 
 	memset(&req, 0, sizeof(req));
-	strncpy(req.nr_name, ctx->ifname, sizeof(req.nr_name)-1);
+	memcpy(req.nr_name, ctx->ifname, sizeof(req.nr_name));
+	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
 	req.nr_version = netmap_api;
 	req.nr_ringid     = ctx->nr_ringid;
 	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
@@ -299,10 +300,7 @@ legacy_regif_extra_bufs(struct TestContext *ctx)
 static int
 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
 {
-	char pipe_name[128];
-
-	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeexbuf");
-	ctx->ifname  = pipe_name;
+	strncat(ctx->ifname, "{pipeexbuf", sizeof(ctx->ifname));
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	ctx->nr_extra_bufs = 20;
 
@@ -312,7 +310,7 @@ legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
 static int
 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
 {
-	ctx->ifname = "valeX1:Y4";
+	strncpy(ctx->ifname, "valeX1:Y4", sizeof(ctx->ifname));
 	return legacy_regif_extra_bufs_pipe(ctx);
 }
 
@@ -500,7 +498,7 @@ vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
 {
 	int ret;
 
-	ctx->ifname  = "vale:eph0";
+	strncpy(ctx->ifname, "vale:eph0", sizeof(ctx->ifname));
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	if ((ret = port_register(ctx))) {
 		return ret;
@@ -529,7 +527,7 @@ vale_persistent_port(struct TestContext *ctx)
 	int result;
 	int ret;
 
-	ctx->ifname = "per4";
+	strncpy(ctx->ifname, "per4", sizeof(ctx->ifname));
 
 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
 
@@ -633,17 +631,14 @@ pools_info_get_and_register(struct TestContext *ctx)
 static int
 pools_info_get_empty_ifname(struct TestContext *ctx)
 {
-	ctx->ifname = "";
+	strncpy(ctx->ifname, "", sizeof(ctx->ifname));
 	return pools_info_get(ctx) != 0 ? 0 : -1;
 }
 
 static int
 pipe_master(struct TestContext *ctx)
 {
-	char pipe_name[128];
-
-	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "pipeid1");
-	ctx->ifname  = pipe_name;
+	strncat(ctx->ifname, "{pipeid1", sizeof(ctx->ifname));
 	ctx->nr_mode = NR_REG_NIC_SW;
 
 	if (port_register(ctx) == 0) {
@@ -658,10 +653,7 @@ pipe_master(struct TestContext *ctx)
 static int
 pipe_slave(struct TestContext *ctx)
 {
-	char pipe_name[128];
-
-	snprintf(pipe_name, sizeof(pipe_name), "%s}%s", ctx->ifname, "pipeid2");
-	ctx->ifname  = pipe_name;
+	strncat(ctx->ifname, "}pipeid2", sizeof(ctx->ifname));
 	ctx->nr_mode = NR_REG_ALL_NIC;
 
 	return port_register(ctx);
@@ -672,10 +664,7 @@ pipe_slave(struct TestContext *ctx)
 static int
 pipe_port_info_get(struct TestContext *ctx)
 {
-	char pipe_name[128];
-
-	snprintf(pipe_name, sizeof(pipe_name), "%s}%s", ctx->ifname, "pipeid3");
-	ctx->ifname = pipe_name;
+	strncat(ctx->ifname, "}pipeid3", sizeof(ctx->ifname));
 
 	return port_info_get(ctx);
 }
@@ -683,10 +672,7 @@ pipe_port_info_get(struct TestContext *ctx)
 static int
 pipe_pools_info_get(struct TestContext *ctx)
 {
-	char pipe_name[128];
-
-	snprintf(pipe_name, sizeof(pipe_name), "%s{%s", ctx->ifname, "xid");
-	ctx->ifname = pipe_name;
+	strncat(ctx->ifname, "{xid", sizeof(ctx->ifname));
 
 	return pools_info_get(ctx);
 }
@@ -950,7 +936,7 @@ _extmem_option(struct TestContext *ctx, int new_rsz)
 
 	save = e;
 
-	ctx->ifname      = "vale0:0";
+	strncpy(ctx->ifname, "vale0:0", sizeof(ctx->ifname));
 	ctx->nr_tx_slots = 16;
 	ctx->nr_rx_slots = 16;
 
@@ -1587,7 +1573,6 @@ main(int argc, char **argv)
 {
 	struct TestContext ctx;
 	int create_tap = 1;
-	char tapname[64];
 	int num_tests;
 	int ret  = 0;
 	int j    = 0;
@@ -1596,17 +1581,18 @@ main(int argc, char **argv)
 	int opt;
 	int i;
 
+	memset(&ctx, 0, sizeof(ctx));
+
 	{
-		int tapidx;
+		int idx;
+
 		srand(time(0));
-		tapidx = rand() % 8000 + 100;
-		snprintf(tapname, sizeof(tapname), "tap%d", tapidx);
+		idx = rand() % 8000 + 100;
+		snprintf(ctx.ifname, sizeof(ctx.ifname), "tap%d", idx);
+		idx = rand() % 800 + 100;
+		snprintf(ctx.bdgname, sizeof(ctx.bdgname), "vale%d", idx);
 	}
 
-	memset(&ctx, 0, sizeof(ctx));
-	ctx.ifname  = tapname;
-	ctx.bdgname = "vale1x2";
-
 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
 		switch (opt) {
 		case 'h':
@@ -1614,7 +1600,7 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'i':
-			ctx.ifname = optarg;
+			strncpy(ctx.ifname, optarg, sizeof(ctx.ifname) - 1);
 			create_tap = 0;
 			break;
 
@@ -1656,11 +1642,13 @@ main(int argc, char **argv)
 	}
 
 	if (create_tap) {
-		char cmdbuf[64];
+		char cmdbuf[256];
 #ifdef __FreeBSD__
-		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s create up", ctx.ifname);
+		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s create up",
+			ctx.ifname);
 #else
-		snprintf(cmdbuf, sizeof(cmdbuf), "ip tuntap add mode tap name %s", ctx.ifname);
+		snprintf(cmdbuf, sizeof(cmdbuf),
+			"ip tuntap add mode tap name %s", ctx.ifname);
 #endif
 		if (system(cmdbuf)) {
 			printf("%s: failed\n", cmdbuf);
@@ -1690,11 +1678,13 @@ main(int argc, char **argv)
 	}
 out:
 	if (create_tap) {
-		char cmdbuf[64];
+		char cmdbuf[256];
 #ifdef __FreeBSD__
-		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s destroy", ctx.ifname);
+		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s destroy",
+			ctx.ifname);
 #else
-		snprintf(cmdbuf, sizeof(cmdbuf), "ip link del %s", ctx.ifname);
+		snprintf(cmdbuf, sizeof(cmdbuf), "ip link del %s",
+			ctx.ifname);
 #endif
 		if (system(cmdbuf)) {
 			printf("%s: failed\n", cmdbuf);

From 6942fd8feacc59a28ea7d887664994ffc036bb4e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 10:29:20 +0100
Subject: [PATCH 1483/2207] utils: ctrl-api-test: remove redundant assert()

---
 utils/ctrl-api-test.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index f8c1e3b01..375a8ddf1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -318,8 +318,6 @@ legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
 static int
 num_registered_rings(struct TestContext *ctx)
 {
-	assert(ctx->nr_tx_slots > 0 && ctx->nr_rx_slots > 0 &&
-	       ctx->nr_tx_rings > 0 && ctx->nr_rx_rings > 0);
 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
 		return ctx->nr_tx_rings;
 	}

From accf1241f12e1ef97534bb6c228da35507db004d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 10:46:44 +0100
Subject: [PATCH 1484/2207] utils: ctrl-api-test: use POSIX semaphores to avoid
 usleep()

---
 utils/ctrl-api-test.c | 40 +++++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 375a8ddf1..7b97cd6c1 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifdef __linux__
 #include 
@@ -51,6 +52,8 @@ struct TestContext {
 	void *csb;                    /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
 
+	sem_t *sem;	/* for thread synchronization */
+
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
 };
 
@@ -1120,6 +1123,10 @@ sync_kloop_worker(void *opaque)
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
 
+	if (ctx->sem) {
+		sem_post(ctx->sem);
+	}
+
 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
 }
 
@@ -1317,6 +1324,9 @@ sync_kloop_conflict(struct TestContext *ctx)
 	struct nmreq_opt_csb opt;
 	pthread_t th1, th2;
 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
+	struct timespec to;
+	sem_t sem;
+	int err = 0;
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
@@ -1330,37 +1340,52 @@ sync_kloop_conflict(struct TestContext *ctx)
 	}
 	clear_options(ctx);
 
+	sem_init(&sem, 0, 0);
+	ctx->sem = &sem;
+
 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
+	err |= ret;
 	if (ret) {
 		printf("pthread_create(kloop1): %s\n", strerror(ret));
-		return -1;
 	}
 
 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
+	err |= ret;
 	if (ret) {
 		printf("pthread_create(kloop2): %s\n", strerror(ret));
-		return -1;
 	}
 
-	/* Try to avoid a race condition where th1 starts the loop and stops,
+	/* Wait for one of the two threads to fail to start the kloop, to
+	 * avoid a race condition where th1 starts the loop and stops,
 	 * and after that th2 starts the loop successfully. */
-	usleep(500000);
-
-	ret = sync_kloop_stop(ctx);
+	clock_gettime(CLOCK_REALTIME, &to);
+	to.tv_sec += 2;
+	ret = sem_timedwait(&sem, &to);
+	err |= ret;
 	if (ret) {
-		return ret;
+		printf("sem_timedwait() failed: %s\n", strerror(errno));
 	}
 
+	err |= sync_kloop_stop(ctx);
+
 	ret = pthread_join(th1, &thret1);
+	err |= ret;
 	if (ret) {
 		printf("pthread_join(kloop1): %s\n", strerror(ret));
 	}
 
 	ret = pthread_join(th2, &thret2);
+	err |= ret;
 	if (ret) {
 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
 	}
 
+	sem_destroy(&sem);
+	ctx->sem = NULL;
+	if (err) {
+		return err;
+	}
+
 	/* Check that one of the two failed, while the other one succeeded. */
 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
@@ -1526,6 +1551,7 @@ context_cleanup(struct TestContext *ctx)
 	}
 
 	close(ctx->fd);
+	ctx->fd = -1;
 }
 
 static int

From 3d1d868ea292135a42aa38be569ebba7eecdbb3b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 10:52:59 +0100
Subject: [PATCH 1485/2207] utils: ctrl-api-test: add some comments to extmem
 memsize

---
 utils/ctrl-api-test.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 7b97cd6c1..99d90f6ca 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -875,9 +875,11 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 static int
 push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 {
+	/* 4MiB is enough for netmap memory-mapped data structures. */
+	const size_t memsize = (1U << 22);
 	void *addr;
 
-	addr = mmap(NULL, (1U << 22), PROT_READ | PROT_WRITE,
+	addr = mmap(NULL, memsize, PROT_READ | PROT_WRITE,
 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 	if (addr == MAP_FAILED) {
 		perror("mmap");
@@ -887,7 +889,7 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 	memset(e, 0, sizeof(*e));
 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
 	e->nro_usrptr          = (uintptr_t)addr;
-	e->nro_info.nr_memsize = (1U << 22);
+	e->nro_info.nr_memsize = memsize;
 
 	push_option(&e->nro_opt, ctx);
 

From 6ec5dcd307ec8f90dfdb0948913b114ebdbc33bb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 10:58:42 +0100
Subject: [PATCH 1486/2207] utils: ctrl-api-test: better argument for srand()

---
 utils/ctrl-api-test.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 99d90f6ca..eb50aca04 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1610,9 +1610,11 @@ main(int argc, char **argv)
 	memset(&ctx, 0, sizeof(ctx));
 
 	{
+		struct timespec t;
 		int idx;
 
-		srand(time(0));
+		clock_gettime(CLOCK_REALTIME, &t);
+		srand((unsigned int)t.tv_nsec);
 		idx = rand() % 8000 + 100;
 		snprintf(ctx.ifname, sizeof(ctx.ifname), "tap%d", idx);
 		idx = rand() % 800 + 100;

From 2b6674fb29787013ea36f8e456609bfa89f2e4d3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 11:20:36 +0100
Subject: [PATCH 1487/2207] utils: ctrl-api-test: introduce exec_command()
 helper function

---
 utils/ctrl-api-test.c | 86 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 72 insertions(+), 14 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index eb50aca04..66dc71ef8 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifdef __linux__
 #include 
@@ -28,6 +29,48 @@ eventfd(int x, int y)
 }
 #endif /* __linux__ */
 
+static int
+exec_command(int argc, char *argv[])
+{
+	pid_t child_pid;
+	int child_status;
+	int i;
+
+	printf("Executing command: ");
+	for (i = 0; i < argc - 1; i++) {
+		if (i) {
+			putchar(' ');
+		}
+		printf("%s", argv[i]);
+	}
+	putchar('\n');
+
+	child_pid = fork();
+	if (child_pid == 0) {
+		/* Child process. Redirect stdin, stdout
+		 * and stderr. */
+		close(0);
+		close(1);
+		close(2);
+		if (open("/dev/null", O_RDONLY) < 0 ||
+			open("/dev/null", O_RDONLY) < 0 ||
+			open("/dev/null", O_RDONLY) < 0) {
+			return -1;
+		}
+		execvp(argv[0], argv);
+		perror("execvp()");
+		exit(EXIT_FAILURE);
+	}
+
+	waitpid(child_pid, &child_status, 0);
+	if (WIFEXITED(child_status)) {
+		return WEXITSTATUS(child_status);
+	}
+
+	return -1;
+}
+
+
 #define THRET_SUCCESS	((void *)128)
 #define THRET_FAILURE	((void *)0)
 
@@ -1641,6 +1684,7 @@ main(int argc, char **argv)
 
 		case 'l':
 			list = 1;
+			create_tap = 0;
 			break;
 
 		default:
@@ -1670,16 +1714,25 @@ main(int argc, char **argv)
 	}
 
 	if (create_tap) {
-		char cmdbuf[256];
+		char *av[16];
+		int ac = 0;
 #ifdef __FreeBSD__
-		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s create up",
-			ctx.ifname);
+		av[ac++] = "ifconfig";
+		av[ac++] = ctx.ifname;
+		av[ac++] = "create";
+		av[ac++] = "up";
 #else
-		snprintf(cmdbuf, sizeof(cmdbuf),
-			"ip tuntap add mode tap name %s", ctx.ifname);
+		av[ac++] = "ip";
+		av[ac++] = "tuntap";
+		av[ac++] = "add";
+		av[ac++] = "mode";
+		av[ac++] = "tap";
+		av[ac++] = "name";
+		av[ac++] = ctx.ifname;
 #endif
-		if (system(cmdbuf)) {
-			printf("%s: failed\n", cmdbuf);
+		av[ac++] = NULL;
+		if (exec_command(ac, av)) {
+			printf("Failed to create tap interface\n");
 			return -1;
 		}
 	}
@@ -1706,16 +1759,21 @@ main(int argc, char **argv)
 	}
 out:
 	if (create_tap) {
-		char cmdbuf[256];
+		char *av[16];
+		int ac = 0;
 #ifdef __FreeBSD__
-		snprintf(cmdbuf, sizeof(cmdbuf), "ifconfig %s destroy",
-			ctx.ifname);
+		av[ac++] = "ifconfig";
+		av[ac++] = ctx.ifname;
+		av[ac++] = "destroy";
 #else
-		snprintf(cmdbuf, sizeof(cmdbuf), "ip link del %s",
-			ctx.ifname);
+		av[ac++] = "ip";
+		av[ac++] = "link";
+		av[ac++] = "del";
+		av[ac++] = ctx.ifname;
 #endif
-		if (system(cmdbuf)) {
-			printf("%s: failed\n", cmdbuf);
+		av[ac++] = NULL;
+		if (exec_command(ac, av)) {
+			printf("Failed to destroy tap interface\n");
 			return -1;
 		}
 	}

From 300d8b216450c410eaa2c3dab33eeddcf633e030 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 15:09:28 +0100
Subject: [PATCH 1488/2207] utils: ctrl-api-test: fix compilation warning

---
 utils/ctrl-api-test.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 66dc71ef8..561cb23db 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1714,7 +1714,7 @@ main(int argc, char **argv)
 	}
 
 	if (create_tap) {
-		char *av[16];
+		const char *av[16];
 		int ac = 0;
 #ifdef __FreeBSD__
 		av[ac++] = "ifconfig";
@@ -1731,7 +1731,7 @@ main(int argc, char **argv)
 		av[ac++] = ctx.ifname;
 #endif
 		av[ac++] = NULL;
-		if (exec_command(ac, av)) {
+		if (exec_command(ac, (char **)av)) {
 			printf("Failed to create tap interface\n");
 			return -1;
 		}
@@ -1759,7 +1759,7 @@ main(int argc, char **argv)
 	}
 out:
 	if (create_tap) {
-		char *av[16];
+		const char *av[16];
 		int ac = 0;
 #ifdef __FreeBSD__
 		av[ac++] = "ifconfig";
@@ -1772,7 +1772,7 @@ main(int argc, char **argv)
 		av[ac++] = ctx.ifname;
 #endif
 		av[ac++] = NULL;
-		if (exec_command(ac, av)) {
+		if (exec_command(ac, (char **)av)) {
 			printf("Failed to destroy tap interface\n");
 			return -1;
 		}

From f3f2012a31963e3916fe6324de162ae974b86631 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 10 Dec 2018 15:40:20 +0100
Subject: [PATCH 1489/2207] utils: ctrl-api-test: fix more compilation warning
 in exec_command()

---
 utils/ctrl-api-test.c | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 561cb23db..a210ef205 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -30,7 +30,7 @@ eventfd(int x, int y)
 #endif /* __linux__ */
 
 static int
-exec_command(int argc, char *argv[])
+exec_command(int argc, const char *const argv[])
 {
 	pid_t child_pid;
 	int child_status;
@@ -38,7 +38,11 @@ exec_command(int argc, char *argv[])
 
 	printf("Executing command: ");
 	for (i = 0; i < argc - 1; i++) {
-		if (i) {
+		if (!argv[i]) {
+			/* Invalid argument. */
+			return -1;
+		}
+		if (i > 0) {
 			putchar(' ');
 		}
 		printf("%s", argv[i]);
@@ -47,6 +51,8 @@ exec_command(int argc, char *argv[])
 
 	child_pid = fork();
 	if (child_pid == 0) {
+		char **av;
+
 		/* Child process. Redirect stdin, stdout
 		 * and stderr. */
 		close(0);
@@ -57,7 +63,19 @@ exec_command(int argc, char *argv[])
 			open("/dev/null", O_RDONLY) < 0) {
 			return -1;
 		}
-		execvp(argv[0], argv);
+
+		/* Make a copy of the arguments, passing them to execvp. */
+		av = calloc(argc, sizeof(av[0]));
+		if (!av) {
+			exit(EXIT_FAILURE);
+		}
+		for (i = 0; i < argc - 1; i++) {
+			av[i] = strdup(argv[i]);
+			if (!av[i]) {
+				exit(EXIT_FAILURE);
+			}
+		}
+		execvp(av[0], av);
 		perror("execvp()");
 		exit(EXIT_FAILURE);
 	}
@@ -1731,7 +1749,7 @@ main(int argc, char **argv)
 		av[ac++] = ctx.ifname;
 #endif
 		av[ac++] = NULL;
-		if (exec_command(ac, (char **)av)) {
+		if (exec_command(ac, av)) {
 			printf("Failed to create tap interface\n");
 			return -1;
 		}
@@ -1772,7 +1790,7 @@ main(int argc, char **argv)
 		av[ac++] = ctx.ifname;
 #endif
 		av[ac++] = NULL;
-		if (exec_command(ac, (char **)av)) {
+		if (exec_command(ac, av)) {
 			printf("Failed to destroy tap interface\n");
 			return -1;
 		}

From f7c1bb7f997c80b361287c5006099e68ae7d18ae Mon Sep 17 00:00:00 2001
From: Joshua Raiff 
Date: Fri, 7 Dec 2018 09:25:53 -0500
Subject: [PATCH 1490/2207] Add ability to change MTU device driver is loaded.

If the linux interface device driver supports NS_MOREFRAG or the
new MTU still fits within a netmap buffer, allow the MTU to be
changed.
---
 LINUX/netmap_linux.c         | 10 +++-
 sys/dev/netmap/netmap.c      | 92 ++++++++++++++++++++----------------
 sys/dev/netmap/netmap_kern.h |  1 +
 3 files changed, 61 insertions(+), 42 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 7f0d071d7..d1eb8bed3 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1308,12 +1308,20 @@ linux_netmap_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	return (NETDEV_TX_OK);
 }
 
+#define native_change_mtu(na, dev, mtu)					\
+	(((struct net_device_ops *)(na)->if_transmit)->NETMAP_LINUX_CHANGE_MTU(dev, mtu))
+
 int
 linux_netmap_change_mtu(struct net_device *dev, int new_mtu)
 {
-	return -EBUSY;
+	struct netmap_adapter *na = NA(dev);
+
+	if (netmap_buf_size_validate(na, new_mtu))
+		return -EINVAL;
+	return native_change_mtu(na, dev, new_mtu);
 }
 
+
 /* while in netmap mode, we cannot tolerate any change in the
  * number of rx/tx rings and descriptors
  *
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b5f450e10..a6af3d3ee 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2117,6 +2117,53 @@ netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
 	return 0;
 }
 
+/* Ensure that the netmap adapter can support the given MTU.
+ * @return EINVAL if the na cannot be set to mtu, 0 otherwise.
+ */
+int
+netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
+	unsigned nbs = NETMAP_BUF_SIZE(na);
+
+	if (mtu <= na->rx_buf_maxsize) {
+		/* The MTU fits a single NIC slot. We only
+		 * Need to check that netmap buffers are
+		 * large enough to hold an MTU. NS_MOREFRAG
+		 * cannot be used in this case. */
+		if (nbs < mtu) {
+			nm_prerr("error: netmap buf size (%u) "
+				 "< device MTU (%u)", nbs, mtu);
+			return EINVAL;
+		}
+	} else {
+		/* More NIC slots may be needed to receive
+		 * or transmit a single packet. Check that
+		 * the adapter supports NS_MOREFRAG and that
+		 * netmap buffers are large enough to hold
+		 * the maximum per-slot size. */
+		if (!(na->na_flags & NAF_MOREFRAG)) {
+			nm_prerr("error: large MTU (%d) needed "
+				 "but %s does not support "
+				 "NS_MOREFRAG", mtu,
+				 na->ifp->if_xname);
+			return EINVAL;
+		} else if (nbs < na->rx_buf_maxsize) {
+			nm_prerr("error: using NS_MOREFRAG on "
+				 "%s requires netmap buf size "
+				 ">= %u", na->ifp->if_xname,
+				 na->rx_buf_maxsize);
+			return EINVAL;
+		} else {
+			nm_prinf("info: netmap application on "
+				 "%s needs to support "
+				 "NS_MOREFRAG "
+				 "(MTU=%u,netmap_buf_size=%u)",
+				 na->ifp->if_xname, mtu, nbs);
+		}
+	}
+	return 0;
+}
+
+
 /*
  * possibly move the interface to netmap-mode.
  * If success it returns a pointer to netmap_if, otherwise NULL.
@@ -2226,11 +2273,10 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		 */
 		if (na->ifp && nm_priv_rx_enabled(priv)) {
 			/* This netmap adapter is attached to an ifnet. */
-			unsigned nbs = NETMAP_BUF_SIZE(na);
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
 
 			ND("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",
-					na->name, mtu, na->rx_buf_maxsize, nbs);
+				na->name, mtu, na->rx_buf_maxsize, NETMAP_BUF_SIZE(na));
 
 			if (na->rx_buf_maxsize == 0) {
 				nm_prerr("%s: error: rx_buf_maxsize == 0", na->name);
@@ -2238,45 +2284,9 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 				goto err_drop_mem;
 			}
 
-			if (mtu <= na->rx_buf_maxsize) {
-				/* The MTU fits a single NIC slot. We only
-				 * Need to check that netmap buffers are
-				 * large enough to hold an MTU. NS_MOREFRAG
-				 * cannot be used in this case. */
-				if (nbs < mtu) {
-					nm_prerr("error: netmap buf size (%u) "
-						"< device MTU (%u)", nbs, mtu);
-					error = EINVAL;
-					goto err_drop_mem;
-				}
-			} else {
-				/* More NIC slots may be needed to receive
-				 * or transmit a single packet. Check that
-				 * the adapter supports NS_MOREFRAG and that
-				 * netmap buffers are large enough to hold
-				 * the maximum per-slot size. */
-				if (!(na->na_flags & NAF_MOREFRAG)) {
-					nm_prerr("error: large MTU (%d) needed "
-						"but %s does not support "
-						"NS_MOREFRAG", mtu,
-						na->ifp->if_xname);
-					error = EINVAL;
-					goto err_drop_mem;
-				} else if (nbs < na->rx_buf_maxsize) {
-					nm_prerr("error: using NS_MOREFRAG on "
-						"%s requires netmap buf size "
-						">= %u", na->ifp->if_xname,
-						na->rx_buf_maxsize);
-					error = EINVAL;
-					goto err_drop_mem;
-				} else {
-					nm_prinf("info: netmap application on "
-						"%s needs to support "
-						"NS_MOREFRAG "
-						"(MTU=%u,netmap_buf_size=%u)",
-						na->ifp->if_xname, mtu, nbs);
-				}
-			}
+			error = netmap_buf_size_validate(na, mtu);
+			if (error)
+				goto err_drop_mem;
 		}
 
 		/*
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d72e21e6c..f0905c1f2 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1454,6 +1454,7 @@ void netmap_set_all_rings(struct netmap_adapter *, int stopped);
 void netmap_disable_all_rings(struct ifnet *);
 void netmap_enable_all_rings(struct ifnet *);
 
+int netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu);
 int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags);
 void netmap_do_unregif(struct netmap_priv_d *priv);

From c2aca1d99fa26527b7b54b7899020c420fb57012 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 13:11:38 +0100
Subject: [PATCH 1491/2207] utils: some renaming in intest helper programs

---
 utils/get_tx_rings_avail_sends.c | 31 +++++++++++++++++--------------
 utils/get_tx_rings_max_sends.c   | 31 +++++++++++++++++--------------
 2 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/utils/get_tx_rings_avail_sends.c b/utils/get_tx_rings_avail_sends.c
index 618c15f2f..c811f4d02 100644
--- a/utils/get_tx_rings_avail_sends.c
+++ b/utils/get_tx_rings_avail_sends.c
@@ -1,7 +1,9 @@
 /* Given an interface name and a packet length (optional), prints to stdout
- * the number of packets that can be send through the interface rings. If the
- * packet length is missing, the number of available slot is printed instead.
- * Prints "-1" if something went wrong.
+ * the maximum number of packets (each within that length) that fits in the
+ * currently available TX slots. If the packet length is not specified, it
+ * is assumed that any packet to be transmitted fits within a single netmap
+ * slot, hence printing the number of available TX slots.
+ * On error, "-1" is printed.
  * Arguments:
  *    $1 -> interface name
  *    $2 -> packet length
@@ -16,40 +18,40 @@
 #include 
 
 uint64_t
-slot_per_send(struct netmap_ring *ring, unsigned pkt_len)
+slots_per_packet(struct netmap_ring *ring, unsigned pkt_len)
 {
 	return (uint64_t)(ceil((double)pkt_len / (double)ring->nr_buf_size));
 }
 
 uint64_t
-ring_avail_sends(struct netmap_ring *ring, unsigned pkt_len)
+ring_avail_tx_packets(struct netmap_ring *ring, unsigned pkt_len)
 {
 	if (pkt_len == 0) {
 		return nm_ring_space(ring);
 	}
 
-	return nm_ring_space(ring) / slot_per_send(ring, pkt_len);
+	return nm_ring_space(ring) / slots_per_packet(ring, pkt_len);
 }
 
 uint64_t
-adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+nmport_avail_tx_packets(struct nm_desc *nmd, unsigned pkt_len)
 {
-	uint64_t sends_available = 0;
+	uint64_t total = 0;
 	unsigned int i;
 
 	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
 		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
 
-		sends_available += ring_avail_sends(ring, pkt_len);
+		total += ring_avail_tx_packets(ring, pkt_len);
 	}
 
-	return sends_available;
+	return total;
 }
 
 int
 main(int argc, char **argv)
 {
-	uint64_t avail_sends;
+	uint64_t avail_tx_packets;
 	struct nm_desc *nmd;
 	const char *if_name;
 	uint64_t pkt_len;
@@ -75,7 +77,8 @@ main(int argc, char **argv)
 		exit(EXIT_FAILURE);
 	}
 
-	avail_sends = adapter_avail_sends(nmd, pkt_len);
-	printf("%" PRId64, avail_sends);
+	avail_tx_packets = nmport_avail_tx_packets(nmd, pkt_len);
+	printf("%" PRId64, avail_tx_packets);
+
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/utils/get_tx_rings_max_sends.c b/utils/get_tx_rings_max_sends.c
index 865e4b0e7..4ef03ebec 100644
--- a/utils/get_tx_rings_max_sends.c
+++ b/utils/get_tx_rings_max_sends.c
@@ -1,7 +1,9 @@
 /* Given an interface name and a packet length (optional), prints to stdout
- * the max number of packets that can be send through the interface rings.
- * If packet length is missing, the total number of slot is printed instead.
- * Prints "-1" if something went wrong.
+ * the maximum number of packets (each within that length) that fits in the
+ * transmit rings, assuming they are all empty. If the packet length is not
+ * specified, it is assumed that any packet to be transmitted fits within a
+ * single netmap slot, hence printing the total number of TX slots.
+ * On error, "-1" is printed.
  * Arguments:
  *    $1 -> interface name
  *    $2 -> packet length
@@ -15,40 +17,40 @@
 #include 
 
 uint64_t
-slot_per_send(struct netmap_ring *ring, unsigned pkt_len)
+slots_per_packet(struct netmap_ring *ring, unsigned pkt_len)
 {
 	return (uint64_t)(ceil((double)pkt_len / (double)ring->nr_buf_size));
 }
 
 uint64_t
-ring_max_sends(struct netmap_ring *ring, unsigned pkt_len)
+ring_max_tx_packets(struct netmap_ring *ring, unsigned pkt_len)
 {
 	if (pkt_len == 0) {
 		return nm_ring_space(ring) - 1;
 	}
 
-	return (ring->num_slots - 1) / slot_per_send(ring, pkt_len);
+	return (ring->num_slots - 1) / slots_per_packet(ring, pkt_len);
 }
 
 uint64_t
-adapter_max_sends(struct nm_desc *nmd, unsigned pkt_len)
+nmport_max_tx_packets(struct nm_desc *nmd, unsigned pkt_len)
 {
-	uint64_t sends_available = 0;
+	uint64_t total = 0;
 	unsigned int i;
 
 	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
 		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
 
-		sends_available += ring_max_sends(ring, pkt_len);
+		total += ring_max_tx_packets(ring, pkt_len);
 	}
 
-	return sends_available;
+	return total;
 }
 
 int
 main(int argc, char **argv)
 {
-	uint64_t max_sends;
+	uint64_t max_tx_packets;
 	struct nm_desc *nmd;
 	const char *if_name;
 	uint64_t pkt_len;
@@ -74,7 +76,8 @@ main(int argc, char **argv)
 		exit(EXIT_FAILURE);
 	}
 
-	max_sends = adapter_max_sends(nmd, pkt_len);
-	printf("%" PRId64, max_sends);
+	max_tx_packets = nmport_max_tx_packets(nmd, pkt_len);
+	printf("%" PRId64, max_tx_packets);
+
 	return 0;
-}
\ No newline at end of file
+}

From b76d338de9f9fadf37cd02f9595a1580c232531b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 13:16:01 +0100
Subject: [PATCH 1492/2207] utils: rename intest helper programs

---
 utils/GNUmakefile                                    |  2 +-
 ...tx_rings_avail_sends.c => get_avail_tx_packets.c} |  0
 ...get_tx_rings_max_sends.c => get_max_tx_packets.c} |  0
 utils/randomized_tests                               |  2 +-
 utils/tests/partial_read_pipe_test                   | 12 ++++++------
 5 files changed, 8 insertions(+), 8 deletions(-)
 rename utils/{get_tx_rings_avail_sends.c => get_avail_tx_packets.c} (100%)
 rename utils/{get_tx_rings_max_sends.c => get_max_tx_packets.c} (100%)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 4a28f6572..68cc2b966 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,7 +1,7 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
 PROGS	  = test_select testmmap test_nm functional ctrl-api-test fd_server
-PROGS    += get_tx_rings_avail_sends get_tx_rings_max_sends extmem-example sync_kloop_test
+PROGS    += get_avail_tx_packets get_max_tx_packets extmem-example sync_kloop_test
 X86PROGS  = testlock testcsum producer
 LIBNETMAP =
 
diff --git a/utils/get_tx_rings_avail_sends.c b/utils/get_avail_tx_packets.c
similarity index 100%
rename from utils/get_tx_rings_avail_sends.c
rename to utils/get_avail_tx_packets.c
diff --git a/utils/get_tx_rings_max_sends.c b/utils/get_max_tx_packets.c
similarity index 100%
rename from utils/get_tx_rings_max_sends.c
rename to utils/get_max_tx_packets.c
diff --git a/utils/randomized_tests b/utils/randomized_tests
index db1d3bdb0..ca9f1c3db 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -39,7 +39,7 @@ pushd $(pwd)
 cd $(dirname $0)
 
 # Add the current directory (and build-utils) to the PATH. In this way we can
-# easily invoke functional, get_tx_rings_avail_sends and the other executables
+# easily invoke functional, get_avail_tx_packets and the other executables
 # from the test scripts.
 PATH="$(pwd)/../build-utils:$(pwd):${PATH}"
 
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index 3ef3f6bab..c6566d0fc 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -37,27 +37,27 @@ e1=$?
 check_success $e1 "receive-7 netmap:${pipe}{1"
 check_success $e2 "send-10 netmap:${pipe}}1"
 
-# At the moment get_tx_rings_max_sends and get_tx_rings_avail_sends do not
+# At the moment get_max_tx_packets and get_avail_tx_packets do not
 # get the interface fd from fd_server, they request it directly through an
 # nm_open(), but they still read the correct values stored inside each struct
 # netmap ring. This only happens if the multiple processes / threads synchronize
 # with each other when sharing the same netmap interface. This happens
-# implicitly for us because get_tx_rings_max_sends and get_tx_rings_avail_sends
+# implicitly for us because get_max_tx_packets and get_avail_tx_packets
 # are called after the first send-receive action, and the second one doesn't
 # happen until they terminate.
 exit_status=0
-ring_max_sends=$(./get_tx_rings_max_sends "netmap:${pipe}}1" "$len")
+ring_max_sends=$(./get_max_tx_packets "netmap:${pipe}}1" "$len")
 if [ $ring_max_sends = -1 ] ; then
 	exit_status=1
 fi
-check_success $exit_status "get_tx_rings_max_sends netmap:${pipe}}1 $len"
+check_success $exit_status "get_max_tx_packets netmap:${pipe}}1 $len"
 
 exit_status=0
-ring_avail_sends=$(./get_tx_rings_avail_sends "netmap:${pipe}}1" "$len")
+ring_avail_sends=$(./get_avail_tx_packets "netmap:${pipe}}1" "$len")
 if [ $ring_avail_sends = -1 ] ; then
 	exit_status=1
 fi
-check_success $exit_status "get_tx_rings_avail_sends netmap:${pipe}}1 $len"
+check_success $exit_status "get_avail_tx_packets netmap:${pipe}}1 $len"
 
 exit_status=0
 ring_used_sends="$(($ring_max_sends - $ring_avail_sends))"

From 2ee45bec365cd1332d996f9a60fe528f46fcd6e7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 15:55:51 +0100
Subject: [PATCH 1493/2207] utils: remove unused header file

---
 utils/ctrs.h | 106 ---------------------------------------------------
 1 file changed, 106 deletions(-)
 delete mode 100644 utils/ctrs.h

diff --git a/utils/ctrs.h b/utils/ctrs.h
deleted file mode 100644
index 40c6b3dfb..000000000
--- a/utils/ctrs.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef CTRS_H_
-#define CTRS_H_
-
-#include 
-
-/* counters to accumulate statistics */
-struct my_ctrs {
-	uint64_t pkts, bytes, events, drop;
-	uint64_t min_space;
-	struct timeval t;
-};
-
-/* very crude code to print a number in normalized form.
- * Caller has to make sure that the buffer is large enough.
- */
-static const char *
-norm2(char *buf, double val, char *fmt)
-{
-	char *units[] = { "", "K", "M", "G", "T" };
-	u_int i;
-
-	for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++)
-		val /= 1000;
-	sprintf(buf, fmt, val, units[i]);
-	return buf;
-}
-
-static __inline const char *
-norm(char *buf, double val)
-{
-	return norm2(buf, val, "%.3f %s");
-}
-
-static __inline int
-timespec_ge(const struct timespec *a, const struct timespec *b)
-{
-
-	if (a->tv_sec > b->tv_sec)
-		return (1);
-	if (a->tv_sec < b->tv_sec)
-		return (0);
-	if (a->tv_nsec >= b->tv_nsec)
-		return (1);
-	return (0);
-}
-
-static __inline struct timespec
-timeval2spec(const struct timeval *a)
-{
-	struct timespec ts = {
-		.tv_sec = a->tv_sec,
-		.tv_nsec = a->tv_usec * 1000
-	};
-	return ts;
-}
-
-static __inline struct timeval
-timespec2val(const struct timespec *a)
-{
-	struct timeval tv = {
-		.tv_sec = a->tv_sec,
-		.tv_usec = a->tv_nsec / 1000
-	};
-	return tv;
-}
-
-
-static __inline struct timespec
-timespec_add(struct timespec a, struct timespec b)
-{
-	struct timespec ret = { a.tv_sec + b.tv_sec, a.tv_nsec + b.tv_nsec };
-	if (ret.tv_nsec >= 1000000000) {
-		ret.tv_sec++;
-		ret.tv_nsec -= 1000000000;
-	}
-	return ret;
-}
-
-static __inline struct timespec
-timespec_sub(struct timespec a, struct timespec b)
-{
-	struct timespec ret = { a.tv_sec - b.tv_sec, a.tv_nsec - b.tv_nsec };
-	if (ret.tv_nsec < 0) {
-		ret.tv_sec--;
-		ret.tv_nsec += 1000000000;
-	}
-	return ret;
-}
-
-static uint64_t
-wait_for_next_report(struct timeval *prev, struct timeval *cur,
-		int report_interval)
-{
-	struct timeval delta;
-
-	delta.tv_sec = report_interval/1000;
-	delta.tv_usec = (report_interval%1000)*1000;
-	if (select(0, NULL, NULL, NULL, &delta) < 0 && errno != EINTR) {
-		perror("select");
-		abort();
-	}
-	gettimeofday(cur, NULL);
-	timersub(cur, prev, &delta);
-	return delta.tv_sec* 1000000 + delta.tv_usec;
-}
-#endif /* CTRS_H_ */

From ff2c98ee87c3d5ca8577557854d875e95b121165 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 16:14:40 +0100
Subject: [PATCH 1494/2207] utils: update README

---
 utils/README        | 26 +++++++++++++++++++++++---
 utils/producer.c    |  1 +
 utils/test_select.c |  1 +
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/utils/README b/utils/README
index e4a1e6876..002fa9e56 100644
--- a/utils/README
+++ b/utils/README
@@ -1,5 +1,25 @@
-$FreeBSD: head/tools/tools/netmap/README 227614 2011-11-17 12:17:39Z luigi $
+$FreeBSD$
 
-This directory contains examples that use netmap
+This directory contains miscellaneous programs related to netmap
 
-	click*		various click examples
+	ctrl-api-test.c		suite of unit tests for the netmap control ABI
+	sync_kloop_test.c	example program for the CSB mode with sync-kloop
+	extmem-example.c	example program for the extmem feature
+	producer.c		transmitter example with constant per-packet
+				work
+	testmmap.c		test program for interactively test the netmap
+				control ABI (open, mmap, NIOCREGIF, NIOCGETINFO)
+	test_nm.c		example program for nm_inject and nm_dispatch
+	fd_server.[ch]		helper program for integration tests
+	get_avail_tx_packets.c	"
+	get_max_tx_packets.c	"
+	functional.c		"
+	tests/			suite of integration tests (shell scripts)
+	test_lib		helper shell functions for integration tests
+	randomized_tests	script to run all the integration tests
+	switch-modules/		(old) patches for Open VSwitch to use netmap
+	click-test.cfg		(old) simple click example
+	testcsum.c		(old) benchmarks for checksum computation
+	testlock.c		(old) benchmarks for locks and concurrency
+	test_select.c		(old) benchmarks for select() and poll()
+	testmod/		(old) benchmarks for FreeBSD kernel
diff --git a/utils/producer.c b/utils/producer.c
index 8bafbd3cf..da2a05ceb 100644
--- a/utils/producer.c
+++ b/utils/producer.c
@@ -77,6 +77,7 @@ tsc_sleep_till(uint64_t when)
         barrier();
 #undef barrier
 }
+
 int main(int argc, char **argv)
 {
 	const char *ifname = "netmap:nmsink0";
diff --git a/utils/test_select.c b/utils/test_select.c
index ed737c3b8..8ec50ea3f 100644
--- a/utils/test_select.c
+++ b/utils/test_select.c
@@ -14,6 +14,7 @@
 
 enum { M_SELECT =0 , M_POLL, M_USLEEP };
 static const char *names[] = { "select", "poll", "usleep" };
+
 int
 main(int argc, char *argv[])
 {

From 0ab44865972310b5c17f35b0f915d538f0a77e16 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 16:32:34 +0100
Subject: [PATCH 1495/2207] utils: randomized_tests: add option parsing

---
 utils/randomized_tests | 68 ++++++++++++++++++++++++++++++++++++++----
 utils/test_select.c    |  2 +-
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index ca9f1c3db..ae40cbea1 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -1,9 +1,67 @@
 #!/usr/bin/env bash
+
 ################################################################################
-# Runs all the tests using randomized values for number of packets, fill
-# character and packets length.
+# Run all the tests using randomized values for number of packets, fill
+# character and packet length.
 ################################################################################
 
+usage() {
+    cat < 0 ]]
+do
+	key="$1"
+	case $key in
+	"-h")
+		usage
+		exit 0
+		;;
+
+	"--help")
+		usage
+		exit 0
+		;;
+
+	"-j")
+		if [ -n "$2" ]; then
+			TESTID=$2
+			shift
+		else
+			echo "-j requires an ID argument"
+			exit 255
+		fi
+		;;
+
+	"-l")
+		LIST="y"
+		;;
+
+	*)
+		echo "Unknown option '$key'"
+		echo "Try $0 -h"
+		exit 255
+		;;
+	esac
+	shift
+done
+
+if [ -n "$LIST" ]; then
+	echo "Available tests:"
+	i="1"
+	for t in tests/*_test ; do
+		echo "    #${i}:  ${t}"
+		i=$((i + 1))
+	done
+	exit 0
+fi
+
 if [ "$EUID" -ne "0" ]; then
 	echo "This script must be run as root"
 	exit 1
@@ -47,9 +105,9 @@ source test_lib
 
 netmap_load
 
-for test in tests/*_test ; do
+for t in tests/*_test ; do
 	restart_fd_server
-	$test -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
+	$t -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
 	close_fd_server
 	if [ $? != 0 ] ; then
 		echo "Rerunning the test that just failed with -v"
@@ -59,7 +117,7 @@ for test in tests/*_test ; do
 		#    -vvv  -> -vv and packet building
 		#    -vvvv -> -vvv and arguments parsing
 		restart_fd_server
-		$test -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
+		$t -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
 		close_fd_server
 		popd
 		exit $?
diff --git a/utils/test_select.c b/utils/test_select.c
index 8ec50ea3f..644c0b60b 100644
--- a/utils/test_select.c
+++ b/utils/test_select.c
@@ -12,7 +12,7 @@
 #include 
 #include 
 
-enum { M_SELECT =0 , M_POLL, M_USLEEP };
+enum { M_SELECT = 0 , M_POLL, M_USLEEP };
 static const char *names[] = { "select", "poll", "usleep" };
 
 int

From 9ed48a1b145b6cce055fd3ab0bd1242f418e99c0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 16:42:09 +0100
Subject: [PATCH 1496/2207] utils: randomized_tests: implement -j argument

---
 utils/randomized_tests | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index ae40cbea1..db1b141db 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -105,10 +105,19 @@ source test_lib
 
 netmap_load
 
+i=0
 for t in tests/*_test ; do
+	i=$((i + 1))
+
+	# Possibly filter tests by TESTID
+	[ -n "$TESTID" ] && [ "$i" != "$TESTID" ] && continue
+
+	# Run this test
+	echo "Running test #${i}: ${t}"
 	restart_fd_server
 	$t -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
 	close_fd_server
+	echo "Test #${i} ran successfully"
 	if [ $? != 0 ] ; then
 		echo "Rerunning the test that just failed with -v"
 		# Select verbosity of output after an error occurred:

From 487d035577096df65ff3d10f56691cd26143cf4c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 16:48:13 +0100
Subject: [PATCH 1497/2207] utils: randomized_tests: use colored output

---
 utils/randomized_tests | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index db1b141db..9422af20f 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -52,6 +52,13 @@ do
 	shift
 done
 
+# Support for colored output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+CYAN='\033[0;36m'
+ORANGE='\033[0;33m'
+NOC='\033[0m' # No Color
+
 if [ -n "$LIST" ]; then
 	echo "Available tests:"
 	i="1"
@@ -113,11 +120,16 @@ for t in tests/*_test ; do
 	[ -n "$TESTID" ] && [ "$i" != "$TESTID" ] && continue
 
 	# Run this test
-	echo "Running test #${i}: ${t}"
+	echo -e "${ORANGE}>>> Running test #${i}: ${CYAN}\"${t}\"${NOC}"
 	restart_fd_server
 	$t -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
+	res="$?"
 	close_fd_server
-	echo "Test #${i} ran successfully"
+	if [ "$res" == 0 ]; then
+		echo -e "${GREEN}>>> Test #${i} PASSED${NOC}"
+	else
+		echo -e "${RED}>>> Test #${i} FAILED${NOC}"
+	fi
 	if [ $? != 0 ] ; then
 		echo "Rerunning the test that just failed with -v"
 		# Select verbosity of output after an error occurred:

From de71e783e1afa83cf749832ab2f950d39720c77f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 16:59:40 +0100
Subject: [PATCH 1498/2207] utils: randomized_tests: add support for increased
 verbosity

---
 utils/randomized_tests | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 9422af20f..11dd3fecf 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -11,10 +11,12 @@ randomized_tests:
 	-h		Show this help and exit
 	-j ID		Run only the test specified by ID
 	-l		List available tests and exit
+	-v		Increase verbosity of the tests
 EOF
 }
 
 # Option parsing
+OUTPUT="/dev/null"
 while [[ $# > 0 ]]
 do
 	key="$1"
@@ -35,7 +37,7 @@ do
 			shift
 		else
 			echo "-j requires an ID argument"
-			exit 255
+			exit 1
 		fi
 		;;
 
@@ -43,10 +45,23 @@ do
 		LIST="y"
 		;;
 
+	"-v")
+		# Select verbosity:
+		#    -v    -> prints error messages
+		#    -vv   -> -v, send and receive actions
+		#    -vvv  -> -vv and packet building
+		#    -vvvv -> -vvv and arguments parsing
+		if [ -z "$VERB" ]; then
+			VERB="-"
+		fi
+		VERB="${VERB}v"
+		OUTPUT="/dev/stdout"
+		;;
+
 	*)
 		echo "Unknown option '$key'"
 		echo "Try $0 -h"
-		exit 255
+		exit 1
 		;;
 	esac
 	shift
@@ -122,26 +137,15 @@ for t in tests/*_test ; do
 	# Run this test
 	echo -e "${ORANGE}>>> Running test #${i}: ${CYAN}\"${t}\"${NOC}"
 	restart_fd_server
-	$t -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>/dev/null
+	$t $VERB -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>${OUTPUT}
 	res="$?"
 	close_fd_server
 	if [ "$res" == 0 ]; then
 		echo -e "${GREEN}>>> Test #${i} PASSED${NOC}"
 	else
 		echo -e "${RED}>>> Test #${i} FAILED${NOC}"
-	fi
-	if [ $? != 0 ] ; then
-		echo "Rerunning the test that just failed with -v"
-		# Select verbosity of output after an error occurred:
-		#    -v    -> prints error messages
-		#    -vv   -> -v, send and receive actions
-		#    -vvv  -> -vv and packet building
-		#    -vvvv -> -vvv and arguments parsing
-		restart_fd_server
-		$t -v -n $random_packet_num -l $random_len -f $random_fill "$seq_check"
-		close_fd_server
-		popd
-		exit $?
+		# popd
+		# exit 1
 	fi
 done
 

From 8f843147fdc0184c430784b20278679447462683 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:05:38 +0100
Subject: [PATCH 1499/2207] utils: tests: minor cleanup in test description

---
 utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test  | 1 -
 utils/tests/extra_buf_send_rec_persistent_vale_ports_test | 1 -
 utils/tests/extra_buf_send_rec_pipe_test                  | 1 -
 utils/tests/learning_bridge_test                          | 1 -
 utils/tests/partial_read_pipe_test                        | 1 -
 utils/tests/rec_cp_mon_ephemeral_vale_port_test           | 1 -
 utils/tests/rec_cp_mon_persistent_vale_port_test          | 1 -
 utils/tests/rec_cp_mon_pipe_test                          | 1 -
 utils/tests/rec_zcp_mon_ephemeral_vale_port_test          | 1 -
 utils/tests/rec_zcp_mon_persistent_vale_port_test         | 1 -
 utils/tests/rec_zcp_mon_pipe_test                         | 1 -
 utils/tests/send_cp_mon_ephemeral_vale_port_test          | 1 -
 utils/tests/send_cp_mon_persistent_vale_port_test         | 1 -
 utils/tests/send_cp_mon_pipe_test                         | 1 -
 utils/tests/send_rec_ephemeral_vale_ports_test            | 1 -
 utils/tests/send_rec_persistent_vale_ports_test           | 1 -
 utils/tests/send_rec_pipe_test                            | 1 -
 utils/tests/send_rec_veth_test                            | 1 -
 utils/tests/send_zcp_mon_ephemeral_vale_port_test         | 1 -
 utils/tests/send_zcp_mon_persistent_vale_port_test        | 1 -
 utils/tests/send_zcp_mon_pipe_test                        | 1 -
 21 files changed, 21 deletions(-)

diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 6dea470ad..51dda2f0b 100755
--- a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -3,7 +3,6 @@
 # Test objective: check if we can send packets through ephimeral VALE ports
 #                 while using extra buffers.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) send from vale0:v0 using extra buffers, and check that both, vale0:v1 and
 #    vale0:v2, receive.
 ################################################################################
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index 4064cee28..5f266ae47 100755
--- a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -3,7 +3,6 @@
 # Test objective: check if we can send packets through persistent VALE ports
 #                 while using extra buffers.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create 3 persistent VALE ports (v0, v1, v2) and attach them to vale0.
 # 2) send from vale0:v2 using extra buffers, and check that both, vale0:v0 and
 #    vale0:v1, receive.
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
index e9503046f..f066dc97c 100755
--- a/utils/tests/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -3,7 +3,6 @@
 # Test objective: check if we can send packets through netmap pipes while using
 #                 extra buffers.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
 # 2) send from pipeA{1 using extra buffers and check if pipeA}1 receives.
 ################################################################################
diff --git a/utils/tests/learning_bridge_test b/utils/tests/learning_bridge_test
index 4280ba583..77a9ba389 100755
--- a/utils/tests/learning_bridge_test
+++ b/utils/tests/learning_bridge_test
@@ -2,7 +2,6 @@
 ################################################################################
 # Test objective: check if the switch learning algorithm is working.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) connect 3 ephemeral VALE ports (v0, v1, v2) to the same VALE switch.
 # 2) send from v2 specifying a source MAC address and check that v0 and v1
 #    receive the frame.
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index c6566d0fc..371314776 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -4,7 +4,6 @@
 #                 sending pipe sent, the non-received slot are left inside the
 #                 sending pipe ring.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) send X packets from pipe{1 and receive X-Y packets from pipe}1.
 # 2) check that pipe{1 still has X-Y slots pending for transmission.
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
index 1a0953a10..bf89da65c 100755
--- a/utils/tests/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -4,7 +4,6 @@
 #                 monitored ephemeral VALE port is receiving, even if the
 #                 monitored port hasn't yet read the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) connect two ephemeral VALE ports (v0, v1) to the same VALE switch.
 # 2) open a receiving copy monitor vo/r for v0.
 # 3) send from v1 and don't read from v0, check that v0/r receives the frame.
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
index 757b5347c..dcf7dc62f 100755
--- a/utils/tests/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -4,7 +4,6 @@
 #                 monitored persistent VALE port is receiving, even if the
 #                 monitored port hasn't yet read the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
 # 3) open a receiving copy monitor vo/r for v0.
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
index 41ada55b4..e9bf98ecb 100755
--- a/utils/tests/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -4,7 +4,6 @@
 #                 monitored netmap pipe is receiving, even if the monitored pipe
 #                 hasn't yet read the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a receive copy monitor pipe{1/r for pipe{1.
 # 3) send from pipe}1 and don't read from pipe{1, check that pipe{1/r receives
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index bd34fa18c..95f0ef495 100755
--- a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -3,7 +3,6 @@
 # Test objective: check if a zero-copy monitor is correctly blocked until the
 #                 monitored ephemeral VALE port reads the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) connect two ephemeral VALE ports (v0, v1) to the same VALE switch.
 # 2) open a zero-copy monitor v0/z for v0.
 # 3) send from v1 without receiving from v0, check that v0/z doesn't receive the
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
index a32618c3d..6331a7e42 100755
--- a/utils/tests/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -3,7 +3,6 @@
 # Test objective: check if a zero-copy monitor is correctly blocked until the
 #                 monitored persistent VALE port reads the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch (vale0).
 # 3) open a zero-copy monitor v0/z for v0.
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
index b05282e7d..de9f067b5 100755
--- a/utils/tests/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -3,7 +3,6 @@
 # Test objective: check if a zero-copy monitor is correctly blocked until the
 #                 monitored netmap pipe reads the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a zero-copy monitor pipe{1/z for pipe{1.
 # 3) send from pipe}1 without receiving from pipe{1, check that pipe{1/z doesn't
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
index fa05c9399..748059b3c 100755
--- a/utils/tests/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -3,7 +3,6 @@
 # Test objective: check if a send copy monitor receives frames when its
 #                 monitored ephemeral VALE port is sending.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) open a send copy monitor v0/t for v0.
 # 3) send from v0, check that both v0/t and v1 receive the frame.
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
index 82e42ee4c..2198a2850 100755
--- a/utils/tests/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -3,7 +3,6 @@
 # Test objective: check if a send copy monitor receives frames when its
 #                 monitored persistent VALE port is sending.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
 # 3) open a send copy monitor v0/t for v0.
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
index 6447758bc..6b98e50c1 100755
--- a/utils/tests/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -4,7 +4,6 @@
 #                 monitored netmap pipe is sending, even if the non-monitored
 #                 port hasn't yet read the frame.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a send copy monitor pipe{1/t for pipe{1.
 # 3) send from pipe{1 and don't read from pipe}1, check that pipe{1/t receives
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
index a41565637..a13ec6482 100755
--- a/utils/tests/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -3,7 +3,6 @@
 # Test objective: check if we can send and receive packets through ephimeral
 #                 VALE ports.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) send from vale0:v2 and check that both, vale0:v0 and vale0:v1, receive.
 # 2) send from vale0:v0 and check that both, vale0:v1 and vale0:v2, receive.
 ################################################################################
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
index dd4524548..7cbd12f08 100755
--- a/utils/tests/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -3,7 +3,6 @@
 # Test objective: check if we can send and receive packets through persistent
 #                 VALE ports.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create 3 persistent VALE ports (v0, v1, v2) and attach them to vale0.
 # 2) send from vale0:v2 and check that both, vale0:v0 and vale0:v1, receive.
 # 3) send from vale0:v0 and check that both, vale0:v1 and vale0:v2, receive.
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
index 31a655241..95130b09f 100755
--- a/utils/tests/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -2,7 +2,6 @@
 ################################################################################
 # Test objective: check if we can send and receive packets through netmap pipes.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipeA{1, pipeA}1).
 # 2) send from pipeA{1 and check if pipeA}1 receives.
 # 3) send from pipeA}1 and check if pipeA{1 receives.
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/send_rec_veth_test
index 37f997859..327b12bd0 100755
--- a/utils/tests/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -2,7 +2,6 @@
 ################################################################################
 # Test objective: check if we can send and receive through veth interfaces.
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of veth interfaces (veth1A, veth1B).
 # 2) send from veth1B and check if veth1A receives.
 # 3) send from veth1A and check if veth1B receives.
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
index d76267ff7..8534fe1c1 100755
--- a/utils/tests/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -5,7 +5,6 @@
 #                 destination port hasn't yet read the frame (this happens
 #                 because VALE switches do not use zero-copy).
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) connect two ephemeral VALE ports (v0, v1) to the same VALE switch.
 # 2) open a zero-copy monitor v0/z for v0.
 # 3) send from v0 and don't read from v1, check that v0/z receives the frame.
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
index e93188d31..4637f1588 100755
--- a/utils/tests/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -5,7 +5,6 @@
 #                 destination port hasn't yet read the frame (this happens
 #                 because VALE switches do not use zero-copy).
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a persistent VALE port (v0).
 # 2) connect v0 and a VALE ephimeral port (v1) to the same VALE switch.
 # 3) open a zero-copy monitor v0/z for v0.
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index 0f92032e9..430767add 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -4,7 +4,6 @@
 #                 non-monitored netmap pipe reads the frame (and the slot is
 #                 given back to the sending pipe).
 # Operations:
-# 0) restart fd_server to have a clean starting state
 # 1) create a pair of netmap pipes (pipe{1, pipe}1).
 # 2) open a zero-copy monitor pipe{1/z for pipe{1.
 # 3) send from pipe{1 without receiving from pipe}1, check that pipe{1/z doesn't

From 5b7b8628f9318370d8b8d5baedea8ce6de449f74 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:29:24 +0100
Subject: [PATCH 1500/2207] utils: tests: partial_read_pipe_test: fix and
 improve

---
 utils/tests/partial_read_pipe_test | 34 +++++++++++++-----------------
 1 file changed, 15 insertions(+), 19 deletions(-)

diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index 371314776..bb32ac261 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -5,7 +5,7 @@
 #                 sending pipe ring.
 # Operations:
 # 1) create a pair of netmap pipes (pipe{1, pipe}1).
-# 2) send X packets from pipe{1 and receive X-Y packets from pipe}1.
+# 2) send X packets to pipe}1 and receive X-Y packets from pipe{1.
 # 2) check that pipe{1 still has X-Y slots pending for transmission.
 ################################################################################
 source test_lib
@@ -20,7 +20,7 @@ num_send=10
 num_recv=7
 pipe="pipeA"
 
-# Pre-opening interface that will be needed. This is needed to avoid a race
+# Pre-open netmap ports for the test. This is needed to avoid a race
 # condition between the sending and receiving ports.
 functional $verbosity -i "netmap:${pipe}{1"
 check_success $? "pre-open netmap:${pipe}{1"
@@ -36,37 +36,33 @@ e1=$?
 check_success $e1 "receive-7 netmap:${pipe}{1"
 check_success $e2 "send-10 netmap:${pipe}}1"
 
-# At the moment get_max_tx_packets and get_avail_tx_packets do not
-# get the interface fd from fd_server, they request it directly through an
-# nm_open(), but they still read the correct values stored inside each struct
-# netmap ring. This only happens if the multiple processes / threads synchronize
-# with each other when sharing the same netmap interface. This happens
-# implicitly for us because get_max_tx_packets and get_avail_tx_packets
-# are called after the first send-receive action, and the second one doesn't
-# happen until they terminate.
+# At the moment get_max_tx_packets and get_avail_tx_packets do not get the
+# netmap port fd from fd_server. They request it directly through nm_open().
+# However, they still read the correct values stored inside each struct
+# netmap ring, because the netmap ports have not been closed in the meanwhile.
 exit_status=0
-ring_max_sends=$(./get_max_tx_packets "netmap:${pipe}}1" "$len")
-if [ $ring_max_sends = -1 ] ; then
+max_packets=$(get_max_tx_packets "netmap:${pipe}}1" "$len")
+if [ "$max_packets" == -1 ] ; then
 	exit_status=1
 fi
 check_success $exit_status "get_max_tx_packets netmap:${pipe}}1 $len"
 
 exit_status=0
-ring_avail_sends=$(./get_avail_tx_packets "netmap:${pipe}}1" "$len")
-if [ $ring_avail_sends = -1 ] ; then
+avail_packets=$(get_avail_tx_packets "netmap:${pipe}}1" "$len")
+if [ "$avail_packets" == -1 ] ; then
 	exit_status=1
 fi
 check_success $exit_status "get_avail_tx_packets netmap:${pipe}}1 $len"
 
 exit_status=0
-ring_used_sends="$(($ring_max_sends - $ring_avail_sends))"
-pending_sends="$(($num_send - $num_recv))"
-if [ $ring_used_sends != $pending_sends ] ; then
+pending_packets="$(($max_packets - $avail_packets))"
+pending_transmissions="$(($num_send - $num_recv))"
+if [ $pending_packets != $pending_transmissions ] ; then
 	exit_status = 1
 fi
-check_exit $pending_sends $ring_used_sends "pending_sends=ring_used_sends"
+check_exit $pending_transmissions $pending_packets "pending_transmissions=pending_packets"
 
-num_send="$(($ring_avail_sends + 1))"
+num_send="$(($avail_packets + 1))"
 functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 check_failure $? "send-${num_send} netmap:${pipe}}1"
 

From b94063ae79f3db8f6afef658a406ba1c5f74fac4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:38:26 +0100
Subject: [PATCH 1501/2207] utils: tests: remove redundant calls to
 "test_successful"

---
 utils/tests/exclusive_open_ephemeral_vale_port_test       | 2 --
 utils/tests/exclusive_open_persistent_vale_port_test      | 2 --
 utils/tests/exclusive_open_pipe_test                      | 2 --
 utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test  | 2 --
 utils/tests/extra_buf_send_rec_persistent_vale_ports_test | 2 --
 utils/tests/extra_buf_send_rec_pipe_test                  | 2 --
 utils/tests/learning_bridge_test                          | 2 --
 utils/tests/partial_read_pipe_test                        | 2 --
 utils/tests/persistent_vale_port_destroy                  | 2 --
 utils/tests/persistent_vale_port_double_attach            | 2 --
 utils/tests/persistent_vale_port_double_create            | 2 --
 utils/tests/rec_cp_mon_ephemeral_vale_port_test           | 2 --
 utils/tests/rec_cp_mon_persistent_vale_port_test          | 2 --
 utils/tests/rec_cp_mon_pipe_test                          | 2 --
 utils/tests/rec_zcp_mon_ephemeral_vale_port_test          | 2 --
 utils/tests/rec_zcp_mon_persistent_vale_port_test         | 2 --
 utils/tests/rec_zcp_mon_pipe_test                         | 2 --
 utils/tests/send_cp_mon_ephemeral_vale_port_test          | 2 --
 utils/tests/send_cp_mon_persistent_vale_port_test         | 2 --
 utils/tests/send_cp_mon_pipe_test                         | 2 --
 utils/tests/send_rec_ephemeral_vale_ports_test            | 2 --
 utils/tests/send_rec_persistent_vale_ports_test           | 2 --
 utils/tests/send_rec_pipe_test                            | 2 --
 utils/tests/send_rec_veth_test                            | 2 --
 utils/tests/send_zcp_mon_ephemeral_vale_port_test         | 2 --
 utils/tests/send_zcp_mon_persistent_vale_port_test        | 2 --
 utils/tests/send_zcp_mon_pipe_test                        | 2 --
 27 files changed, 54 deletions(-)

diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/exclusive_open_ephemeral_vale_port_test
index 916f2b6e6..b280ea507 100755
--- a/utils/tests/exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/exclusive_open_ephemeral_vale_port_test
@@ -23,5 +23,3 @@ check_failure $? "no-open ${bridge}:${port}"
 # Check that another exclusive open request fails.
 functional $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
-
-test_successful "$0"
diff --git a/utils/tests/exclusive_open_persistent_vale_port_test b/utils/tests/exclusive_open_persistent_vale_port_test
index daaffe12a..258b944fd 100755
--- a/utils/tests/exclusive_open_persistent_vale_port_test
+++ b/utils/tests/exclusive_open_persistent_vale_port_test
@@ -26,5 +26,3 @@ check_failure $? "no-open ${bridge}:${port}"
 # Check that another exclusive open request fails.
 functional $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
-
-test_successful "$0"
diff --git a/utils/tests/exclusive_open_pipe_test b/utils/tests/exclusive_open_pipe_test
index 387307c20..8750afa16 100755
--- a/utils/tests/exclusive_open_pipe_test
+++ b/utils/tests/exclusive_open_pipe_test
@@ -22,5 +22,3 @@ check_failure $? "no-open netmap:${pipe}"
 # Check that another exclusive open request fails.
 functional $verbosity -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
-
-test_successful "$0"
diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
index 51dda2f0b..0759e8f5d 100755
--- a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
@@ -38,5 +38,3 @@ e2=$?
 check_success $e1 "receive-${num} vale0:v1"
 check_success $e2 "receive-${num} vale0:v2"
 check_success $e3 "send-${num} vale0:v0"
-
-test_successful "$0"
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
index 5f266ae47..c92c2e863 100755
--- a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/extra_buf_send_rec_persistent_vale_ports_test
@@ -45,5 +45,3 @@ e2=$?
 check_success $e1 "receive-${num} vale0:v0"
 check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
-
-test_successful "$0"
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/extra_buf_send_rec_pipe_test
index f066dc97c..349eff49b 100755
--- a/utils/tests/extra_buf_send_rec_pipe_test
+++ b/utils/tests/extra_buf_send_rec_pipe_test
@@ -31,5 +31,3 @@ wait $p1
 e1=$?
 check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
-
-test_successful "$0"
diff --git a/utils/tests/learning_bridge_test b/utils/tests/learning_bridge_test
index 77a9ba389..f9d9ddc81 100755
--- a/utils/tests/learning_bridge_test
+++ b/utils/tests/learning_bridge_test
@@ -56,5 +56,3 @@ e5=$?
 check_success $e1 "receive vale0:v0"
 check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
-
-test_successful "$0"
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/partial_read_pipe_test
index bb32ac261..f67496d16 100755
--- a/utils/tests/partial_read_pipe_test
+++ b/utils/tests/partial_read_pipe_test
@@ -65,5 +65,3 @@ check_exit $pending_transmissions $pending_packets "pending_transmissions=pendin
 num_send="$(($avail_packets + 1))"
 functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 check_failure $? "send-${num_send} netmap:${pipe}}1"
-
-test_successful "$0"
diff --git a/utils/tests/persistent_vale_port_destroy b/utils/tests/persistent_vale_port_destroy
index 64307daad..48f94f7fa 100755
--- a/utils/tests/persistent_vale_port_destroy
+++ b/utils/tests/persistent_vale_port_destroy
@@ -29,5 +29,3 @@ destroy_vale_persistent_port "$port" 1
 
 detach_from_vale_bridge "$bridgeA" "$port" 0
 destroy_vale_persistent_port "$port" 0
-
-test_successful "$0"
diff --git a/utils/tests/persistent_vale_port_double_attach b/utils/tests/persistent_vale_port_double_attach
index 4548d2938..8b2d260ad 100755
--- a/utils/tests/persistent_vale_port_double_attach
+++ b/utils/tests/persistent_vale_port_double_attach
@@ -18,5 +18,3 @@ create_vale_persistent_port "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 0
 attach_to_vale_bridge "$bridgeA" "$port" 1
 attach_to_vale_bridge "$bridgeB" "$port" 0
-
-test_successful "$0"
diff --git a/utils/tests/persistent_vale_port_double_create b/utils/tests/persistent_vale_port_double_create
index c2d12a7b9..6da7c5cc9 100755
--- a/utils/tests/persistent_vale_port_double_create
+++ b/utils/tests/persistent_vale_port_double_create
@@ -21,5 +21,3 @@ create_vale_persistent_port "$port" 1
 
 attach_to_vale_bridge "$bridgeB" "$port" 0
 create_vale_persistent_port "$port" 1
-
-test_successful "$0"
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
index bf89da65c..288b160c5 100755
--- a/utils/tests/rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_cp_mon_ephemeral_vale_port_test
@@ -41,5 +41,3 @@ check_success $e2 "send-${num} vale0:v1"
 functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
-
-test_successful "$0"
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/rec_cp_mon_persistent_vale_port_test
index dcf7dc62f..28af6ac8a 100755
--- a/utils/tests/rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_cp_mon_persistent_vale_port_test
@@ -44,5 +44,3 @@ check_success $e2 "send-${num} vale0:v1"
 functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
-
-test_successful "$0"
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/rec_cp_mon_pipe_test
index e9bf98ecb..608dcad0b 100755
--- a/utils/tests/rec_cp_mon_pipe_test
+++ b/utils/tests/rec_cp_mon_pipe_test
@@ -42,5 +42,3 @@ check_success $e2 "send-${num}${seq} netmap:pipe}1"
 functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
-
-test_successful "$0"
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
index 95f0ef495..cc5af56b6 100755
--- a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/rec_zcp_mon_ephemeral_vale_port_test
@@ -48,5 +48,3 @@ wait $p3
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} vale0:v0/z"
-
-test_successful "$0"
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/rec_zcp_mon_persistent_vale_port_test
index 6331a7e42..4844c8c5f 100755
--- a/utils/tests/rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/rec_zcp_mon_persistent_vale_port_test
@@ -51,5 +51,3 @@ wait $p3
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
 check_success $e4 "receive-${num} netmap:v0/z"
-
-test_successful "$0"
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/rec_zcp_mon_pipe_test
index de9f067b5..4b0bc5cf7 100755
--- a/utils/tests/rec_zcp_mon_pipe_test
+++ b/utils/tests/rec_zcp_mon_pipe_test
@@ -48,5 +48,3 @@ wait $p3
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe{1"
 check_success $e4 "receive-${num} netmap:pipe{1/z"
-
-test_successful "$0"
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/send_cp_mon_ephemeral_vale_port_test
index 748059b3c..6fe0540eb 100755
--- a/utils/tests/send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_cp_mon_ephemeral_vale_port_test
@@ -39,5 +39,3 @@ check_success $e2 "send-${num} vale0:v0"
 functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
-
-test_successful "$0"
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/send_cp_mon_persistent_vale_port_test
index 2198a2850..911be00f1 100755
--- a/utils/tests/send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/send_cp_mon_persistent_vale_port_test
@@ -42,5 +42,3 @@ check_success $e2 "send-${num} vale0:v0"
 functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
-
-test_successful "$0"
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/send_cp_mon_pipe_test
index 6b98e50c1..f1c7d9933 100755
--- a/utils/tests/send_cp_mon_pipe_test
+++ b/utils/tests/send_cp_mon_pipe_test
@@ -42,5 +42,3 @@ check_success $e2 "send-${num} netmap:pipe{1"
 functional $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
-
-test_successful "$0"
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/send_rec_ephemeral_vale_ports_test
index a13ec6482..253e0cd41 100755
--- a/utils/tests/send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/send_rec_ephemeral_vale_ports_test
@@ -53,5 +53,3 @@ e5=$?
 check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
-
-test_successful "$0"
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/send_rec_persistent_vale_ports_test
index 7cbd12f08..e467b11d2 100755
--- a/utils/tests/send_rec_persistent_vale_ports_test
+++ b/utils/tests/send_rec_persistent_vale_ports_test
@@ -60,5 +60,3 @@ e5=$?
 check_success $e4 "receive-${num} vale0:v1"
 check_success $e5 "receive-${num} vale0:v2"
 check_success $e6 "send-${num} vale0:v0"
-
-test_successful "$0"
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/send_rec_pipe_test
index 95130b09f..cc905b57b 100755
--- a/utils/tests/send_rec_pipe_test
+++ b/utils/tests/send_rec_pipe_test
@@ -41,5 +41,3 @@ wait $p3
 e2=$?
 check_success $e2 "receive-${num} netmap:pipeA}1"
 check_success $e4 "send-${num} netmap:pipeA{1"
-
-test_successful "$0"
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/send_rec_veth_test
index 327b12bd0..86ba2e882 100755
--- a/utils/tests/send_rec_veth_test
+++ b/utils/tests/send_rec_veth_test
@@ -44,5 +44,3 @@ wait $p3
 e3=$?
 check_success $e3 "receive-${num} netmap:veth1B"
 check_success $e4 "send-${num} netmap:veth1A"
-
-test_successful "$0"
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
index 8534fe1c1..93b296b5b 100755
--- a/utils/tests/send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/send_zcp_mon_ephemeral_vale_port_test
@@ -42,5 +42,3 @@ check_success $e2 "send-${num} vale0:v0"
 functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
-
-test_successful "$0"
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/send_zcp_mon_persistent_vale_port_test
index 4637f1588..2b56bc75e 100755
--- a/utils/tests/send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/send_zcp_mon_persistent_vale_port_test
@@ -45,5 +45,3 @@ check_success $e2 "send-${num} vale0:v0"
 functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
-
-test_successful "$0"
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/send_zcp_mon_pipe_test
index 430767add..2882f0646 100755
--- a/utils/tests/send_zcp_mon_pipe_test
+++ b/utils/tests/send_zcp_mon_pipe_test
@@ -55,5 +55,3 @@ e3=$?
 check_success $e4 "receive-${num} netmap:pipe}1"
 check_success $e5 "send-${num} netmap:pipe{1"
 check_success $e3 "receive-${num} netmap:pipe{1/z"
-
-test_successful "$0"

From 607664420a92a369fc83977fe224f551992f1c70 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:39:02 +0100
Subject: [PATCH 1502/2207] utils: randomized_tests: enable test failure

---
 utils/randomized_tests | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 11dd3fecf..155447f39 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -144,8 +144,8 @@ for t in tests/*_test ; do
 		echo -e "${GREEN}>>> Test #${i} PASSED${NOC}"
 	else
 		echo -e "${RED}>>> Test #${i} FAILED${NOC}"
-		# popd
-		# exit 1
+		popd
+		exit 1
 	fi
 done
 

From b2c0c10b7584453aba25bcfbf1753e9234facf71 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:44:42 +0100
Subject: [PATCH 1503/2207] utils: randomized_tests: switch to getopts

---
 utils/randomized_tests | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 155447f39..17df3f565 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -17,35 +17,27 @@ EOF
 
 # Option parsing
 OUTPUT="/dev/null"
-while [[ $# > 0 ]]
-do
-	key="$1"
-	case $key in
-	"-h")
+while getopts "hlvj:" opt; do
+	case $opt in
+	"h")
 		usage
 		exit 0
 		;;
 
-	"--help")
-		usage
-		exit 0
-		;;
-
-	"-j")
+	"j")
 		if [ -n "$2" ]; then
-			TESTID=$2
-			shift
+			TESTID=${OPTARG}
 		else
 			echo "-j requires an ID argument"
 			exit 1
 		fi
 		;;
 
-	"-l")
+	"l")
 		LIST="y"
 		;;
 
-	"-v")
+	"v")
 		# Select verbosity:
 		#    -v    -> prints error messages
 		#    -vv   -> -v, send and receive actions
@@ -58,13 +50,13 @@ do
 		OUTPUT="/dev/stdout"
 		;;
 
-	*)
-		echo "Unknown option '$key'"
-		echo "Try $0 -h"
+	\?)
+		echo "Unknown option '$opt'"
+		echo ""
+		usage
 		exit 1
 		;;
 	esac
-	shift
 done
 
 # Support for colored output

From 969badadbd2d97d54561d946f6628902b2f3b11d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:48:55 +0100
Subject: [PATCH 1504/2207] utils: randomized_tests: unload module also on
 failure

---
 utils/randomized_tests | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 17df3f565..f8ea3ca04 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -119,6 +119,7 @@ source test_lib
 
 netmap_load
 
+RET=0
 i=0
 for t in tests/*_test ; do
 	i=$((i + 1))
@@ -136,8 +137,8 @@ for t in tests/*_test ; do
 		echo -e "${GREEN}>>> Test #${i} PASSED${NOC}"
 	else
 		echo -e "${RED}>>> Test #${i} FAILED${NOC}"
-		popd
-		exit 1
+		RET="1"
+		break
 	fi
 done
 
@@ -145,4 +146,6 @@ done
 sleep 0.5
 
 netmap_unload
+
 popd
+exit ${RET}

From 013cd8d6044809957cf3e6442437a9d8b095cabd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 17:58:40 +0100
Subject: [PATCH 1505/2207] utils: randomized_tests: cd into utils before
 listing

---
 utils/randomized_tests | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index f8ea3ca04..10cc022de 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -67,12 +67,15 @@ ORANGE='\033[0;33m'
 NOC='\033[0m' # No Color
 
 if [ -n "$LIST" ]; then
+	pushd $(pwd)
+	cd $(dirname $0)
 	echo "Available tests:"
 	i="1"
 	for t in tests/*_test ; do
-		echo "    #${i}:  ${t}"
+		printf "    #%03d: %s\n" $i $t
 		i=$((i + 1))
 	done
+	popd
 	exit 0
 fi
 

From 9742c85c3c36a2b292fe9e7bedd72feee9fade64 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 18:08:41 +0100
Subject: [PATCH 1506/2207] utils: tests: add numeric prefix to names

---
 ...vale_port_test => 001_exclusive_open_ephemeral_vale_port_test} | 0
 ...ale_port_test => 002_exclusive_open_persistent_vale_port_test} | 0
 .../{exclusive_open_pipe_test => 003_exclusive_open_pipe_test}    | 0
 ...orts_test => 004_extra_buf_send_rec_ephemeral_vale_ports_test} | 0
 ...rts_test => 005_extra_buf_send_rec_persistent_vale_ports_test} | 0
 ...ra_buf_send_rec_pipe_test => 006_extra_buf_send_rec_pipe_test} | 0
 utils/tests/{learning_bridge_test => 007_learning_bridge_test}    | 0
 .../tests/{partial_read_pipe_test => 008_partial_read_pipe_test}  | 0
 ...sistent_vale_port_destroy => 009_persistent_vale_port_destroy} | 0
 ..._port_double_attach => 010_persistent_vale_port_double_attach} | 0
 ..._port_double_create => 011_persistent_vale_port_double_create} | 0
 ...ral_vale_port_test => 012_rec_cp_mon_ephemeral_vale_port_test} | 0
 ...nt_vale_port_test => 013_rec_cp_mon_persistent_vale_port_test} | 0
 utils/tests/{rec_cp_mon_pipe_test => 014_rec_cp_mon_pipe_test}    | 0
 ...al_vale_port_test => 015_rec_zcp_mon_ephemeral_vale_port_test} | 0
 ...t_vale_port_test => 016_rec_zcp_mon_persistent_vale_port_test} | 0
 utils/tests/{rec_zcp_mon_pipe_test => 017_rec_zcp_mon_pipe_test}  | 0
 ...al_vale_port_test => 018_send_cp_mon_ephemeral_vale_port_test} | 0
 ...t_vale_port_test => 019_send_cp_mon_persistent_vale_port_test} | 0
 utils/tests/{send_cp_mon_pipe_test => 020_send_cp_mon_pipe_test}  | 0
 ...ral_vale_ports_test => 021_send_rec_ephemeral_vale_ports_test} | 0
 ...nt_vale_ports_test => 022_send_rec_persistent_vale_ports_test} | 0
 utils/tests/{send_rec_pipe_test => 023_send_rec_pipe_test}        | 0
 utils/tests/{send_rec_veth_test => 024_send_rec_veth_test}        | 0
 ...l_vale_port_test => 025_send_zcp_mon_ephemeral_vale_port_test} | 0
 ..._vale_port_test => 026_send_zcp_mon_persistent_vale_port_test} | 0
 .../tests/{send_zcp_mon_pipe_test => 027_send_zcp_mon_pipe_test}  | 0
 27 files changed, 0 insertions(+), 0 deletions(-)
 rename utils/tests/{exclusive_open_ephemeral_vale_port_test => 001_exclusive_open_ephemeral_vale_port_test} (100%)
 rename utils/tests/{exclusive_open_persistent_vale_port_test => 002_exclusive_open_persistent_vale_port_test} (100%)
 rename utils/tests/{exclusive_open_pipe_test => 003_exclusive_open_pipe_test} (100%)
 rename utils/tests/{extra_buf_send_rec_ephemeral_vale_ports_test => 004_extra_buf_send_rec_ephemeral_vale_ports_test} (100%)
 rename utils/tests/{extra_buf_send_rec_persistent_vale_ports_test => 005_extra_buf_send_rec_persistent_vale_ports_test} (100%)
 rename utils/tests/{extra_buf_send_rec_pipe_test => 006_extra_buf_send_rec_pipe_test} (100%)
 rename utils/tests/{learning_bridge_test => 007_learning_bridge_test} (100%)
 rename utils/tests/{partial_read_pipe_test => 008_partial_read_pipe_test} (100%)
 rename utils/tests/{persistent_vale_port_destroy => 009_persistent_vale_port_destroy} (100%)
 rename utils/tests/{persistent_vale_port_double_attach => 010_persistent_vale_port_double_attach} (100%)
 rename utils/tests/{persistent_vale_port_double_create => 011_persistent_vale_port_double_create} (100%)
 rename utils/tests/{rec_cp_mon_ephemeral_vale_port_test => 012_rec_cp_mon_ephemeral_vale_port_test} (100%)
 rename utils/tests/{rec_cp_mon_persistent_vale_port_test => 013_rec_cp_mon_persistent_vale_port_test} (100%)
 rename utils/tests/{rec_cp_mon_pipe_test => 014_rec_cp_mon_pipe_test} (100%)
 rename utils/tests/{rec_zcp_mon_ephemeral_vale_port_test => 015_rec_zcp_mon_ephemeral_vale_port_test} (100%)
 rename utils/tests/{rec_zcp_mon_persistent_vale_port_test => 016_rec_zcp_mon_persistent_vale_port_test} (100%)
 rename utils/tests/{rec_zcp_mon_pipe_test => 017_rec_zcp_mon_pipe_test} (100%)
 rename utils/tests/{send_cp_mon_ephemeral_vale_port_test => 018_send_cp_mon_ephemeral_vale_port_test} (100%)
 rename utils/tests/{send_cp_mon_persistent_vale_port_test => 019_send_cp_mon_persistent_vale_port_test} (100%)
 rename utils/tests/{send_cp_mon_pipe_test => 020_send_cp_mon_pipe_test} (100%)
 rename utils/tests/{send_rec_ephemeral_vale_ports_test => 021_send_rec_ephemeral_vale_ports_test} (100%)
 rename utils/tests/{send_rec_persistent_vale_ports_test => 022_send_rec_persistent_vale_ports_test} (100%)
 rename utils/tests/{send_rec_pipe_test => 023_send_rec_pipe_test} (100%)
 rename utils/tests/{send_rec_veth_test => 024_send_rec_veth_test} (100%)
 rename utils/tests/{send_zcp_mon_ephemeral_vale_port_test => 025_send_zcp_mon_ephemeral_vale_port_test} (100%)
 rename utils/tests/{send_zcp_mon_persistent_vale_port_test => 026_send_zcp_mon_persistent_vale_port_test} (100%)
 rename utils/tests/{send_zcp_mon_pipe_test => 027_send_zcp_mon_pipe_test} (100%)

diff --git a/utils/tests/exclusive_open_ephemeral_vale_port_test b/utils/tests/001_exclusive_open_ephemeral_vale_port_test
similarity index 100%
rename from utils/tests/exclusive_open_ephemeral_vale_port_test
rename to utils/tests/001_exclusive_open_ephemeral_vale_port_test
diff --git a/utils/tests/exclusive_open_persistent_vale_port_test b/utils/tests/002_exclusive_open_persistent_vale_port_test
similarity index 100%
rename from utils/tests/exclusive_open_persistent_vale_port_test
rename to utils/tests/002_exclusive_open_persistent_vale_port_test
diff --git a/utils/tests/exclusive_open_pipe_test b/utils/tests/003_exclusive_open_pipe_test
similarity index 100%
rename from utils/tests/exclusive_open_pipe_test
rename to utils/tests/003_exclusive_open_pipe_test
diff --git a/utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/004_extra_buf_send_rec_ephemeral_vale_ports_test
similarity index 100%
rename from utils/tests/extra_buf_send_rec_ephemeral_vale_ports_test
rename to utils/tests/004_extra_buf_send_rec_ephemeral_vale_ports_test
diff --git a/utils/tests/extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/005_extra_buf_send_rec_persistent_vale_ports_test
similarity index 100%
rename from utils/tests/extra_buf_send_rec_persistent_vale_ports_test
rename to utils/tests/005_extra_buf_send_rec_persistent_vale_ports_test
diff --git a/utils/tests/extra_buf_send_rec_pipe_test b/utils/tests/006_extra_buf_send_rec_pipe_test
similarity index 100%
rename from utils/tests/extra_buf_send_rec_pipe_test
rename to utils/tests/006_extra_buf_send_rec_pipe_test
diff --git a/utils/tests/learning_bridge_test b/utils/tests/007_learning_bridge_test
similarity index 100%
rename from utils/tests/learning_bridge_test
rename to utils/tests/007_learning_bridge_test
diff --git a/utils/tests/partial_read_pipe_test b/utils/tests/008_partial_read_pipe_test
similarity index 100%
rename from utils/tests/partial_read_pipe_test
rename to utils/tests/008_partial_read_pipe_test
diff --git a/utils/tests/persistent_vale_port_destroy b/utils/tests/009_persistent_vale_port_destroy
similarity index 100%
rename from utils/tests/persistent_vale_port_destroy
rename to utils/tests/009_persistent_vale_port_destroy
diff --git a/utils/tests/persistent_vale_port_double_attach b/utils/tests/010_persistent_vale_port_double_attach
similarity index 100%
rename from utils/tests/persistent_vale_port_double_attach
rename to utils/tests/010_persistent_vale_port_double_attach
diff --git a/utils/tests/persistent_vale_port_double_create b/utils/tests/011_persistent_vale_port_double_create
similarity index 100%
rename from utils/tests/persistent_vale_port_double_create
rename to utils/tests/011_persistent_vale_port_double_create
diff --git a/utils/tests/rec_cp_mon_ephemeral_vale_port_test b/utils/tests/012_rec_cp_mon_ephemeral_vale_port_test
similarity index 100%
rename from utils/tests/rec_cp_mon_ephemeral_vale_port_test
rename to utils/tests/012_rec_cp_mon_ephemeral_vale_port_test
diff --git a/utils/tests/rec_cp_mon_persistent_vale_port_test b/utils/tests/013_rec_cp_mon_persistent_vale_port_test
similarity index 100%
rename from utils/tests/rec_cp_mon_persistent_vale_port_test
rename to utils/tests/013_rec_cp_mon_persistent_vale_port_test
diff --git a/utils/tests/rec_cp_mon_pipe_test b/utils/tests/014_rec_cp_mon_pipe_test
similarity index 100%
rename from utils/tests/rec_cp_mon_pipe_test
rename to utils/tests/014_rec_cp_mon_pipe_test
diff --git a/utils/tests/rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/015_rec_zcp_mon_ephemeral_vale_port_test
similarity index 100%
rename from utils/tests/rec_zcp_mon_ephemeral_vale_port_test
rename to utils/tests/015_rec_zcp_mon_ephemeral_vale_port_test
diff --git a/utils/tests/rec_zcp_mon_persistent_vale_port_test b/utils/tests/016_rec_zcp_mon_persistent_vale_port_test
similarity index 100%
rename from utils/tests/rec_zcp_mon_persistent_vale_port_test
rename to utils/tests/016_rec_zcp_mon_persistent_vale_port_test
diff --git a/utils/tests/rec_zcp_mon_pipe_test b/utils/tests/017_rec_zcp_mon_pipe_test
similarity index 100%
rename from utils/tests/rec_zcp_mon_pipe_test
rename to utils/tests/017_rec_zcp_mon_pipe_test
diff --git a/utils/tests/send_cp_mon_ephemeral_vale_port_test b/utils/tests/018_send_cp_mon_ephemeral_vale_port_test
similarity index 100%
rename from utils/tests/send_cp_mon_ephemeral_vale_port_test
rename to utils/tests/018_send_cp_mon_ephemeral_vale_port_test
diff --git a/utils/tests/send_cp_mon_persistent_vale_port_test b/utils/tests/019_send_cp_mon_persistent_vale_port_test
similarity index 100%
rename from utils/tests/send_cp_mon_persistent_vale_port_test
rename to utils/tests/019_send_cp_mon_persistent_vale_port_test
diff --git a/utils/tests/send_cp_mon_pipe_test b/utils/tests/020_send_cp_mon_pipe_test
similarity index 100%
rename from utils/tests/send_cp_mon_pipe_test
rename to utils/tests/020_send_cp_mon_pipe_test
diff --git a/utils/tests/send_rec_ephemeral_vale_ports_test b/utils/tests/021_send_rec_ephemeral_vale_ports_test
similarity index 100%
rename from utils/tests/send_rec_ephemeral_vale_ports_test
rename to utils/tests/021_send_rec_ephemeral_vale_ports_test
diff --git a/utils/tests/send_rec_persistent_vale_ports_test b/utils/tests/022_send_rec_persistent_vale_ports_test
similarity index 100%
rename from utils/tests/send_rec_persistent_vale_ports_test
rename to utils/tests/022_send_rec_persistent_vale_ports_test
diff --git a/utils/tests/send_rec_pipe_test b/utils/tests/023_send_rec_pipe_test
similarity index 100%
rename from utils/tests/send_rec_pipe_test
rename to utils/tests/023_send_rec_pipe_test
diff --git a/utils/tests/send_rec_veth_test b/utils/tests/024_send_rec_veth_test
similarity index 100%
rename from utils/tests/send_rec_veth_test
rename to utils/tests/024_send_rec_veth_test
diff --git a/utils/tests/send_zcp_mon_ephemeral_vale_port_test b/utils/tests/025_send_zcp_mon_ephemeral_vale_port_test
similarity index 100%
rename from utils/tests/send_zcp_mon_ephemeral_vale_port_test
rename to utils/tests/025_send_zcp_mon_ephemeral_vale_port_test
diff --git a/utils/tests/send_zcp_mon_persistent_vale_port_test b/utils/tests/026_send_zcp_mon_persistent_vale_port_test
similarity index 100%
rename from utils/tests/send_zcp_mon_persistent_vale_port_test
rename to utils/tests/026_send_zcp_mon_persistent_vale_port_test
diff --git a/utils/tests/send_zcp_mon_pipe_test b/utils/tests/027_send_zcp_mon_pipe_test
similarity index 100%
rename from utils/tests/send_zcp_mon_pipe_test
rename to utils/tests/027_send_zcp_mon_pipe_test

From 9f6434857f5bc1af8f4add75d80fe02dbdfe5182 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 18:10:37 +0100
Subject: [PATCH 1507/2207] utils: randomized_tests: enable all the tests

Three of them where disabled because their name did not end with
"_test".
---
 utils/randomized_tests | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 10cc022de..49b12f40d 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -71,7 +71,7 @@ if [ -n "$LIST" ]; then
 	cd $(dirname $0)
 	echo "Available tests:"
 	i="1"
-	for t in tests/*_test ; do
+	for t in tests/* ; do
 		printf "    #%03d: %s\n" $i $t
 		i=$((i + 1))
 	done
@@ -124,7 +124,7 @@ netmap_load
 
 RET=0
 i=0
-for t in tests/*_test ; do
+for t in tests/* ; do
 	i=$((i + 1))
 
 	# Possibly filter tests by TESTID

From 418398d08c461bd9fb71a71f9e7850f022f2f677 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 19:36:05 +0100
Subject: [PATCH 1508/2207] add man page for ptnet

---
 share/man/man4/ptnet.4 | 133 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)
 create mode 100644 share/man/man4/ptnet.4

diff --git a/share/man/man4/ptnet.4 b/share/man/man4/ptnet.4
new file mode 100644
index 000000000..54ca7118e
--- /dev/null
+++ b/share/man/man4/ptnet.4
@@ -0,0 +1,133 @@
+.\" Copyright (c) 2018 Vincenzo Maffione
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 11, 2018
+.Dt PTNET 4
+.Os
+.Sh NAME
+.Nm ptnet
+.Nd Ethernet driver for passed-through netmap ports
+.Sh SYNOPSIS
+This network driver is included in
+.Xr netmap 4 ,
+and it can be compiled into the kernel by adding the following
+line in your kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device netmap"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+device driver provides direct access to an host netmap port,
+from within a Virtual Machine (VM). An application running inside
+the VM can access the transmit and receive rings of a netmap port
+that the hypervisor has passed-through to the VM.
+Hypervisor support for
+.Nm
+is currently only available for QEMU/KVM.
+Any
+.Xr netmap 4
+port can be passed-through, including physical NICs,
+.Xr vale 4
+ports, netmap pipes, etc.
+.Pp
+The main use-case for netmap passthrough is Network Function
+Virtualization (NFV), where middlebox applications running within
+VMs may want to process very high packet rates (e.g., 1-10 millions
+packets per second or more). Note, however, that those applications
+must use the device in netmap mode in order to achieve such rates.
+The improved performance of
+.Nm
+when compared to hypervisor device emulation or paravirtualization (e.g.,
+.Xr vtnet 4 ,
+.Xr vmx 4 )
+comes from the hypervisor being completely bypassed in the data-path.
+For example, when using
+.Xr vtnet 4
+the VM has to convert each mbuf to a VirtIO-specific packet representation
+and publish that to a VirtIO queue; on the hypervisor side, the
+packet is extracted from the VirtIO queue and converted to an
+hypervisor-specific packet representation.
+The overhead of format conversions (and packet copies, in same cases) is not
+incured by
+.Nm
+in netmap mode, because mbufs are not used, and the packet format is
+the one defined by netmap (e.g.
+.Ar struct netmap_slot )
+along the whole data-path. No format conversions or copies
+happen, similarly to what happens with PCI passthrough.
+
+It is also possible to use a
+.Nm
+device as a regular network interface, interacting with the FreeBSD
+network stack (i.e., not in netmap mode).
+However, in that case it is necessary to pay the cost of a copy between
+the mbuf and the netmap buffer, which generally results in lower TCP/UDP
+performance than
+.Xr vtnet 4
+or other paravirtualized network devices.
+If the passed-through netmap port supports the VirtIO network header,
+.Nm
+is able to use it, and support TCP/UDP checksum offload (for both transmit
+and receive), TCP segmentation offload (TSO) and TCP large receive offload
+(LRO).
+Currently, only
+.Xr vale 4
+ports support the header.
+Note that for NFV use-cases the VirtIO network header should not be used.
+.Sh TUNABLES
+Tunables can be set at the
+.Xr loader 8
+prompt before booting the kernel or stored in
+.Xr loader.conf 5 .
+.Bl -tag -width "xxxxxx"
+.It Va dev.netmap.ptnet_vnet_hdr
+This tunable enables (1) or disables (0) the virtio-net header.
+If enabled,
+.Nm
+uses the same header used by
+.Xr vtnet 4
+to exchange offload metadata with the hypervisor.
+If disabled, no header is prepended to transmitted and received
+packets.
+The metadata is necessary to enable TCP/UDP checksum offloads,
+TSO, and LRO.
+The default value is 1.
+.El
+.Sh SEE ALSO
+.Xr netintro 4 ,
+.Xr netmap 4 ,
+.Xr ifconfig 8 ,
+.Xr vale 4 ,
+.Xr virtio 4 ,
+.Xr vmx 4
+.Sh HISTORY
+The
+.Nm
+driver was written by
+.An Vincenzo Maffione Aq Mt vmaffione@FreeBSD.org .
+It first appeared in
+.Fx 12.0 .

From ecb317648a7c7ffacf96f0392e1e55269a637f75 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 19:38:08 +0100
Subject: [PATCH 1509/2207] linux: install ptnet man page

---
 LINUX/netmap.mak.in | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 1511e0047..f1be117fd 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -167,6 +167,7 @@ MAN_PREFIX := $(INCLUDE_PREFIX)
 install-docs:
 	install -D -m 644 $(SRCDIR)/../share/man/man4/netmap.4 $(DESTDIR)/$(MAN_PREFIX)/share/man/man4/netmap.4
 	install -D -m 644 $(SRCDIR)/../share/man/man4/vale.4 $(DESTDIR)/$(MAN_PREFIX)/share/man/man4/vale.4
+	install -D -m 644 $(SRCDIR)/../share/man/man4/ptnet.4 $(DESTDIR)/$(MAN_PREFIX)/share/man/man4/ptnet.4
 
 distclean: clean $(S_DRIVERS:%=distclean-%)
 	rm -f config.status config.log netmap_linux_config.h \

From 3abb05487f22c83a04a495f9f7e543398a47ca9d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 22:37:37 +0100
Subject: [PATCH 1510/2207] improvements to the ptnet man page

---
 share/man/man4/ptnet.4 | 38 +++++++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 17 deletions(-)

diff --git a/share/man/man4/ptnet.4 b/share/man/man4/ptnet.4
index 54ca7118e..83805e81f 100644
--- a/share/man/man4/ptnet.4
+++ b/share/man/man4/ptnet.4
@@ -41,13 +41,13 @@ line in your kernel configuration file:
 .Sh DESCRIPTION
 The
 .Nm
-device driver provides direct access to an host netmap port,
-from within a Virtual Machine (VM). An application running inside
-the VM can access the transmit and receive rings of a netmap port
+device driver provides direct access to host netmap ports,
+from within a Virtual Machine (VM). Applications running inside
+the VM can access the TX/RX rings and buffers of a netmap port
 that the hypervisor has passed-through to the VM.
 Hypervisor support for
 .Nm
-is currently only available for QEMU/KVM.
+is currently available for QEMU/KVM.
 Any
 .Xr netmap 4
 port can be passed-through, including physical NICs,
@@ -59,7 +59,8 @@ Virtualization (NFV), where middlebox applications running within
 VMs may want to process very high packet rates (e.g., 1-10 millions
 packets per second or more). Note, however, that those applications
 must use the device in netmap mode in order to achieve such rates.
-The improved performance of
+In addition to the general advantages of netmap, the improved
+performance of
 .Nm
 when compared to hypervisor device emulation or paravirtualization (e.g.,
 .Xr vtnet 4 ,
@@ -67,26 +68,28 @@ when compared to hypervisor device emulation or paravirtualization (e.g.,
 comes from the hypervisor being completely bypassed in the data-path.
 For example, when using
 .Xr vtnet 4
-the VM has to convert each mbuf to a VirtIO-specific packet representation
+the VM has to convert each
+.Xr mbuf 9
+to a VirtIO-specific packet representation
 and publish that to a VirtIO queue; on the hypervisor side, the
 packet is extracted from the VirtIO queue and converted to an
 hypervisor-specific packet representation.
 The overhead of format conversions (and packet copies, in same cases) is not
 incured by
 .Nm
-in netmap mode, because mbufs are not used, and the packet format is
-the one defined by netmap (e.g.
+in netmap mode, because mbufs are not used at all, and the packet format
+is the one defined by netmap (e.g.
 .Ar struct netmap_slot )
 along the whole data-path. No format conversions or copies
-happen, similarly to what happens with PCI passthrough.
+happen.
 
 It is also possible to use a
 .Nm
-device as a regular network interface, interacting with the FreeBSD
+device like a regular network interface, which interacts with the FreeBSD
 network stack (i.e., not in netmap mode).
-However, in that case it is necessary to pay the cost of a copy between
-the mbuf and the netmap buffer, which generally results in lower TCP/UDP
-performance than
+However, in that case it is necessary to pay the cost of data copies
+between mbufs and netmap buffers, which generally results in lower
+TCP/UDP performance than
 .Xr vtnet 4
 or other paravirtualized network devices.
 If the passed-through netmap port supports the VirtIO network header,
@@ -94,10 +97,11 @@ If the passed-through netmap port supports the VirtIO network header,
 is able to use it, and support TCP/UDP checksum offload (for both transmit
 and receive), TCP segmentation offload (TSO) and TCP large receive offload
 (LRO).
-Currently, only
+Currently,
 .Xr vale 4
 ports support the header.
-Note that for NFV use-cases the VirtIO network header should not be used.
+Note that the VirtIO network header is generally not used in NFV
+use-cases, because middleboxes are not endpoint of TCP/UDP connections.
 .Sh TUNABLES
 Tunables can be set at the
 .Xr loader 8
@@ -105,7 +109,7 @@ prompt before booting the kernel or stored in
 .Xr loader.conf 5 .
 .Bl -tag -width "xxxxxx"
 .It Va dev.netmap.ptnet_vnet_hdr
-This tunable enables (1) or disables (0) the virtio-net header.
+This tunable enables (1) or disables (0) the VirtIO network header.
 If enabled,
 .Nm
 uses the same header used by
@@ -113,7 +117,7 @@ uses the same header used by
 to exchange offload metadata with the hypervisor.
 If disabled, no header is prepended to transmitted and received
 packets.
-The metadata is necessary to enable TCP/UDP checksum offloads,
+The metadata is necessary to support TCP/UDP checksum offloads,
 TSO, and LRO.
 The default value is 1.
 .El

From b0a912e162d0b80c4792633d044ef246261724e3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 11 Dec 2018 22:48:42 +0100
Subject: [PATCH 1511/2207] fix warnings (igor, mandoc) on the ptnet man page

---
 share/man/man4/ptnet.4 | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/share/man/man4/ptnet.4 b/share/man/man4/ptnet.4
index 83805e81f..c8d48c296 100644
--- a/share/man/man4/ptnet.4
+++ b/share/man/man4/ptnet.4
@@ -42,7 +42,8 @@ line in your kernel configuration file:
 The
 .Nm
 device driver provides direct access to host netmap ports,
-from within a Virtual Machine (VM). Applications running inside
+from within a Virtual Machine (VM).
+Applications running inside
 the VM can access the TX/RX rings and buffers of a netmap port
 that the hypervisor has passed-through to the VM.
 Hypervisor support for
@@ -57,7 +58,8 @@ ports, netmap pipes, etc.
 The main use-case for netmap passthrough is Network Function
 Virtualization (NFV), where middlebox applications running within
 VMs may want to process very high packet rates (e.g., 1-10 millions
-packets per second or more). Note, however, that those applications
+packets per second or more).
+Note, however, that those applications
 must use the device in netmap mode in order to achieve such rates.
 In addition to the general advantages of netmap, the improved
 performance of
@@ -78,14 +80,15 @@ The overhead of format conversions (and packet copies, in same cases) is not
 incured by
 .Nm
 in netmap mode, because mbufs are not used at all, and the packet format
-is the one defined by netmap (e.g.
+is the one defined by netmap (e.g.,
 .Ar struct netmap_slot )
-along the whole data-path. No format conversions or copies
-happen.
-
+along the whole data-path.
+No format conversions or copies happen.
+.Pp
 It is also possible to use a
 .Nm
-device like a regular network interface, which interacts with the FreeBSD
+device like a regular network interface, which interacts with the
+.Fx
 network stack (i.e., not in netmap mode).
 However, in that case it is necessary to pay the cost of data copies
 between mbufs and netmap buffers, which generally results in lower
@@ -124,10 +127,10 @@ The default value is 1.
 .Sh SEE ALSO
 .Xr netintro 4 ,
 .Xr netmap 4 ,
-.Xr ifconfig 8 ,
 .Xr vale 4 ,
 .Xr virtio 4 ,
-.Xr vmx 4
+.Xr vmx 4 ,
+.Xr ifconfig 8
 .Sh HISTORY
 The
 .Nm

From d4583cf68fc0ac804badb0a75cf3ccbc12045879 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 12 Dec 2018 17:04:15 +0100
Subject: [PATCH 1512/2207] netmap_kloop: fix warning on FreeBSD

---
 sys/dev/netmap/netmap_kloop.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index a2fe52387..2d4b1caa9 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -111,6 +111,7 @@ csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
 	CSB_WRITE(csb_ktoa, kern_need_kick, val);
 }
 
+#ifdef linux
 /* Are application interrupt enabled or disabled? */
 static inline uint32_t
 csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
@@ -121,6 +122,7 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 
 	return v;
 }
+#endif  /* linux */
 
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)

From 73096ebed4c4db34bc1dd58119f47a65b41c6430 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 12 Dec 2018 17:12:42 +0100
Subject: [PATCH 1513/2207] sync-kloop: guard on SYNC_KLOOP_POLL rather than on
 "linux"

---
 sys/dev/netmap/netmap_kloop.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 2d4b1caa9..11ec70914 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -111,7 +111,7 @@ csb_ktoa_kick_enable(struct nm_csb_ktoa __user *csb_ktoa, uint32_t val)
 	CSB_WRITE(csb_ktoa, kern_need_kick, val);
 }
 
-#ifdef linux
+#ifdef SYNC_KLOOP_POLL
 /* Are application interrupt enabled or disabled? */
 static inline uint32_t
 csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
@@ -122,7 +122,7 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 
 	return v;
 }
-#endif  /* linux */
+#endif  /* SYNC_KLOOP_POLL */
 
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)

From 863fe66c01c113db4d3b86fa1f4aac894b746d28 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 12 Dec 2018 17:17:49 +0100
Subject: [PATCH 1514/2207] man: ptnet.4: import fixes from FreeBSD

---
 share/man/man4/ptnet.4 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/ptnet.4 b/share/man/man4/ptnet.4
index c8d48c296..b4a1a5379 100644
--- a/share/man/man4/ptnet.4
+++ b/share/man/man4/ptnet.4
@@ -74,7 +74,7 @@ the VM has to convert each
 .Xr mbuf 9
 to a VirtIO-specific packet representation
 and publish that to a VirtIO queue; on the hypervisor side, the
-packet is extracted from the VirtIO queue and converted to an
+packet is extracted from the VirtIO queue and converted to a
 hypervisor-specific packet representation.
 The overhead of format conversions (and packet copies, in same cases) is not
 incured by
@@ -104,7 +104,7 @@ Currently,
 .Xr vale 4
 ports support the header.
 Note that the VirtIO network header is generally not used in NFV
-use-cases, because middleboxes are not endpoint of TCP/UDP connections.
+use-cases, because middleboxes are not endpoints of TCP/UDP connections.
 .Sh TUNABLES
 Tunables can be set at the
 .Xr loader 8

From 757da9982aaeae10df3f2afecdf28e4587b44269 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 16 Dec 2018 16:58:59 +0100
Subject: [PATCH 1515/2207] utils: ctrl-api-test: reviews from FreeBSD

---
 utils/ctrl-api-test.c | 189 +++++++++++++++++++++++++-----------------
 1 file changed, 115 insertions(+), 74 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a210ef205..8fb13fe66 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,31 +1,58 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Vincenzo Maffione
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include 
+#include 
+#include 
+
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
-#include 
-#include 
 #include 
-#include 
-#include 
+#include 
 
 #ifdef __linux__
 #include 
 #else
 static int
-eventfd(int x, int y)
+eventfd(int x __unused, int y __unused)
 {
-	(void)x;
-	(void)y;
-	return 19;
+	errno = ENODEV;
+	return -1;
 }
 #endif /* __linux__ */
 
@@ -33,6 +60,7 @@ static int
 exec_command(int argc, const char *const argv[])
 {
 	pid_t child_pid;
+	pid_t wret;
 	int child_status;
 	int i;
 
@@ -80,7 +108,11 @@ exec_command(int argc, const char *const argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	waitpid(child_pid, &child_status, 0);
+	wret = waitpid(child_pid, &child_status, 0);
+	if (wret < 0) {
+		fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
+		return wret;
+	}
 	if (WIFEXITED(child_status)) {
 		return WEXITSTATUS(child_status);
 	}
@@ -93,7 +125,6 @@ exec_command(int argc, const char *const argv[])
 #define THRET_FAILURE	((void *)0)
 
 struct TestContext {
-	int fd; /* netmap file descriptor */
 	char ifname[128];
 	char bdgname[64];
 	uint32_t nr_tx_slots;   /* slots in tx rings */
@@ -103,18 +134,16 @@ struct TestContext {
 	uint16_t nr_mem_id;     /* id of the memory allocator */
 	uint16_t nr_ringid;     /* ring(s) we care about */
 	uint32_t nr_mode;       /* specify NR_REG_* modes */
-	uint64_t nr_flags;      /* additional flags (see below) */
 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
-
+	uint64_t nr_flags;      /* additional flags (see below) */
 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
-
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
+	int fd; /* netmap file descriptor */
+
 	void *csb;                    /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
-
 	sem_t *sem;	/* for thread synchronization */
-
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
 };
 
@@ -145,7 +174,7 @@ port_info_get(struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id = ctx->nr_mem_id;
 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
@@ -162,7 +191,7 @@ port_info_get(struct TestContext *ctx)
 		return -1;
 	}
 
-	/* Write back results to the context structure.*/
+	/* Write back results to the context structure. */
 	ctx->nr_tx_slots = req.nr_tx_slots;
 	ctx->nr_rx_slots = req.nr_rx_slots;
 	ctx->nr_tx_rings = req.nr_tx_rings;
@@ -200,7 +229,7 @@ port_register(struct TestContext *ctx)
 	req.nr_rx_rings   = ctx->nr_rx_rings;
 	req.nr_extra_bufs = ctx->nr_extra_bufs;
 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
 	}
@@ -239,7 +268,7 @@ port_register(struct TestContext *ctx)
 	ctx->nr_mem_id     = req.nr_mem_id;
 	ctx->nr_extra_bufs = req.nr_extra_bufs;
 
-	return -0;
+	return 0;
 }
 
 static int
@@ -265,7 +294,7 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	req.nr_arg3 = ctx->nr_extra_bufs;
 
 	ret = ioctl(ctx->fd, NIOCREGIF, &req);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCREGIF)");
 		return ret;
 	}
@@ -357,7 +386,7 @@ static int
 legacy_regif_extra_bufs(struct TestContext *ctx)
 {
 	ctx->nr_mode = NR_REG_ALL_NIC;
-	ctx->nr_extra_bufs = 20;
+	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
 }
 
@@ -366,7 +395,7 @@ legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
 {
 	strncat(ctx->ifname, "{pipeexbuf", sizeof(ctx->ifname));
 	ctx->nr_mode = NR_REG_ALL_NIC;
-	ctx->nr_extra_bufs = 20;
+	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
 
 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
 }
@@ -443,7 +472,7 @@ vale_attach(struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
 	struct nmreq_header hdr;
-	char vpname[256];
+	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname)];
 	int ret;
 
 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
@@ -459,7 +488,7 @@ vale_attach(struct TestContext *ctx)
 	}
 	req.reg.nr_mode = ctx->nr_mode;
 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
 		return ret;
 	}
@@ -488,7 +517,7 @@ vale_detach(struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	hdr.nr_body    = (uintptr_t)&req;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
 		return ret;
 	}
@@ -502,7 +531,7 @@ vale_attach_detach(struct TestContext *ctx)
 {
 	int ret;
 
-	if ((ret = vale_attach(ctx))) {
+	if ((ret = vale_attach(ctx)) != 0) {
 		return ret;
 	}
 
@@ -533,7 +562,7 @@ port_hdr_set_and_get(struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.nr_hdr_len = ctx->nr_hdr_len;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
 	}
@@ -546,7 +575,7 @@ port_hdr_set_and_get(struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
 	req.nr_hdr_len = 0;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
 		return ret;
 	}
@@ -555,6 +584,14 @@ port_hdr_set_and_get(struct TestContext *ctx)
 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
 }
 
+/*
+ * Possible lengths for the VirtIO network header, as specified by
+ * the standard:
+ *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
+ */
+#define VIRTIO_NET_HDR_LEN				10
+#define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
+
 static int
 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
 {
@@ -566,7 +603,7 @@ vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
 		return ret;
 	}
 	/* Try to set and get all the acceptable values. */
-	ctx->nr_hdr_len = 12;
+	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
 	if ((ret = port_hdr_set_and_get(ctx))) {
 		return ret;
 	}
@@ -574,7 +611,7 @@ vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
 	if ((ret = port_hdr_set_and_get(ctx))) {
 		return ret;
 	}
-	ctx->nr_hdr_len = 10;
+	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
 	if ((ret = port_hdr_set_and_get(ctx))) {
 		return ret;
 	}
@@ -603,7 +640,7 @@ vale_persistent_port(struct TestContext *ctx)
 	req.nr_tx_rings = ctx->nr_tx_rings;
 	req.nr_rx_rings = ctx->nr_rx_rings;
 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		return ret;
 	}
@@ -615,7 +652,7 @@ vale_persistent_port(struct TestContext *ctx)
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	hdr.nr_body    = (uintptr_t)NULL;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
 		if (result == 0) {
 			result = ret;
@@ -641,7 +678,7 @@ pools_info_get(struct TestContext *ctx)
 	memset(&req, 0, sizeof(req));
 	req.nr_mem_id = ctx->nr_mem_id;
 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
 		return ret;
 	}
@@ -675,13 +712,13 @@ pools_info_get_and_register(struct TestContext *ctx)
 	/* Check that we can get pools info before we register
 	 * a netmap interface. */
 	ret = pools_info_get(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
 	ctx->nr_mode = NR_REG_ONE_NIC;
 	ret          = port_register(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	ctx->nr_mem_id = 1;
@@ -759,7 +796,7 @@ vale_polling_enable(struct TestContext *ctx)
 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
 		return ret;
 	}
@@ -788,7 +825,7 @@ vale_polling_disable(struct TestContext *ctx)
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
 		return ret;
 	}
@@ -801,7 +838,7 @@ vale_polling_enable_disable(struct TestContext *ctx)
 {
 	int ret = 0;
 
-	if ((ret = vale_attach(ctx))) {
+	if ((ret = vale_attach(ctx)) != 0) {
 		return ret;
 	}
 
@@ -1082,7 +1119,7 @@ push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
 
 	/* Get port info in order to use num_registered_rings(). */
 	ret = port_info_get(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	num_entries = num_registered_rings(ctx);
@@ -1094,7 +1131,7 @@ push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
 		free(ctx->csb);
 	}
 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
-	if (ret) {
+	if (ret != 0) {
 		printf("Failed to allocate CSB memory\n");
 		exit(EXIT_FAILURE);
 	}
@@ -1118,7 +1155,7 @@ csb_mode(struct TestContext *ctx)
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
@@ -1158,7 +1195,7 @@ sync_kloop_stop(struct TestContext *ctx)
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
 	}
 
@@ -1182,7 +1219,7 @@ sync_kloop_worker(void *opaque)
 	memset(&req, 0, sizeof(req));
 	req.sleep_us = 500;
 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
 	}
 
@@ -1201,18 +1238,18 @@ sync_kloop_start_stop(struct TestContext *ctx)
 	int ret;
 
 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
-	if (ret) {
+	if (ret != 0) {
 		printf("pthread_create(kloop): %s\n", strerror(ret));
 		return -1;
 	}
 
 	ret = sync_kloop_stop(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
 	ret = pthread_join(th, &thret);
-	if (ret) {
+	if (ret != 0) {
 		printf("pthread_join(kloop): %s\n", strerror(ret));
 	}
 
@@ -1225,7 +1262,7 @@ sync_kloop(struct TestContext *ctx)
 	int ret;
 
 	ret = csb_mode(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
@@ -1262,7 +1299,7 @@ sync_kloop_eventfds(struct TestContext *ctx)
 	save = opt->nro_opt;
 
 	ret = sync_kloop_start_stop(ctx);
-	if (ret) {
+	if (ret != 0) {
 		free(opt);
 		clear_options(ctx);
 		return ret;
@@ -1286,7 +1323,7 @@ sync_kloop_eventfds_all(struct TestContext *ctx)
 	int ret;
 
 	ret = csb_mode(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
@@ -1300,12 +1337,12 @@ sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
 	ret = port_register_hwall_tx(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	clear_options(ctx);
@@ -1319,7 +1356,7 @@ sync_kloop_nocsb(struct TestContext *ctx)
 	int ret;
 
 	ret = port_register_hwall(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
@@ -1337,7 +1374,7 @@ csb_enable(struct TestContext *ctx)
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	saveopt = opt.nro_opt;
@@ -1351,7 +1388,7 @@ csb_enable(struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname);
 
 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
-	if (ret) {
+	if (ret != 0) {
 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
 		return ret;
 	}
@@ -1369,12 +1406,12 @@ sync_kloop_csb_enable(struct TestContext *ctx)
 
 	ctx->nr_flags |= NR_EXCLUSIVE;
 	ret = port_register_hwall(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
 	ret = csb_enable(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
@@ -1393,28 +1430,32 @@ sync_kloop_conflict(struct TestContext *ctx)
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
 	ret = port_register_hwall(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	clear_options(ctx);
 
-	sem_init(&sem, 0, 0);
+	ret = sem_init(&sem, 0, 0);
+	if (ret != 0) {
+		printf("sem_init() failed: %s\n", strerror(ret));
+		return ret;
+	}
 	ctx->sem = &sem;
 
 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
 	err |= ret;
-	if (ret) {
+	if (ret != 0) {
 		printf("pthread_create(kloop1): %s\n", strerror(ret));
 	}
 
 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
 	err |= ret;
-	if (ret) {
+	if (ret != 0) {
 		printf("pthread_create(kloop2): %s\n", strerror(ret));
 	}
 
@@ -1425,7 +1466,7 @@ sync_kloop_conflict(struct TestContext *ctx)
 	to.tv_sec += 2;
 	ret = sem_timedwait(&sem, &to);
 	err |= ret;
-	if (ret) {
+	if (ret != 0) {
 		printf("sem_timedwait() failed: %s\n", strerror(errno));
 	}
 
@@ -1433,13 +1474,13 @@ sync_kloop_conflict(struct TestContext *ctx)
 
 	ret = pthread_join(th1, &thret1);
 	err |= ret;
-	if (ret) {
+	if (ret != 0) {
 		printf("pthread_join(kloop1): %s\n", strerror(ret));
 	}
 
 	ret = pthread_join(th2, &thret2);
 	err |= ret;
-	if (ret) {
+	if (ret != 0) {
 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
 	}
 
@@ -1463,12 +1504,12 @@ sync_kloop_eventfds_mismatch(struct TestContext *ctx)
 	int ret;
 
 	ret = push_csb_option(ctx, &opt);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 
 	ret = port_register_hwall_rx(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	clear_options(ctx);
@@ -1494,7 +1535,7 @@ null_port(struct TestContext *ctx)
 	ctx->nr_tx_slots = 256;
 	ctx->nr_rx_slots = 100;
 	ret = port_register(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	return 0;
@@ -1512,7 +1553,7 @@ null_port_all_zero(struct TestContext *ctx)
 	ctx->nr_tx_slots = 0;
 	ctx->nr_rx_slots = 0;
 	ret = port_register(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	return 0;
@@ -1530,11 +1571,11 @@ null_port_sync(struct TestContext *ctx)
 	ctx->nr_tx_slots = 256;
 	ctx->nr_rx_slots = 100;
 	ret = port_register(ctx);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
-	if (ret) {
+	if (ret != 0) {
 		return ret;
 	}
 	return 0;
@@ -1768,7 +1809,7 @@ main(int argc, char **argv)
 		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
 		ctxcopy.fd = fd;
 		ret        = tests[i].test(&ctxcopy);
-		if (ret) {
+		if (ret != 0) {
 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
 			goto out;
 		}

From 2d292e5e79c46fa4caee273a9873977cad000acf Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 16 Dec 2018 17:12:43 +0100
Subject: [PATCH 1516/2207] utils: ctrl-api-test: remove assertion on eventfd()

This is useful on FreeBSD, to avoid returning a fake fd that can
clash with real ones.
---
 utils/ctrl-api-test.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 8fb13fe66..b5e2d1270 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1288,10 +1288,8 @@ sync_kloop_eventfds(struct TestContext *ctx)
 	for (i = 0; i < num_entries; i++) {
 		int efd = eventfd(0, 0);
 
-		assert(efd >= 0);
 		opt->eventfds[i].ioeventfd = efd;
 		efd                        = eventfd(0, 0);
-		assert(efd >= 0);
 		opt->eventfds[i].irqfd = efd;
 	}
 

From b3109b3a22c6804bea09073ab1afc4fa1ef07b31 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 16 Dec 2018 18:35:04 +0100
Subject: [PATCH 1517/2207] utils: ctrl-api-test: assert() on command arguments

---
 utils/ctrl-api-test.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b5e2d1270..e52a1b900 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1771,7 +1771,7 @@ main(int argc, char **argv)
 	}
 
 	if (create_tap) {
-		const char *av[16];
+		const char *av[8];
 		int ac = 0;
 #ifdef __FreeBSD__
 		av[ac++] = "ifconfig";
@@ -1788,6 +1788,7 @@ main(int argc, char **argv)
 		av[ac++] = ctx.ifname;
 #endif
 		av[ac++] = NULL;
+		assert(ac <= (int)(sizeof(av) / sizeof(av[0])));
 		if (exec_command(ac, av)) {
 			printf("Failed to create tap interface\n");
 			return -1;
@@ -1816,7 +1817,7 @@ main(int argc, char **argv)
 	}
 out:
 	if (create_tap) {
-		const char *av[16];
+		const char *av[8];
 		int ac = 0;
 #ifdef __FreeBSD__
 		av[ac++] = "ifconfig";
@@ -1829,6 +1830,7 @@ main(int argc, char **argv)
 		av[ac++] = ctx.ifname;
 #endif
 		av[ac++] = NULL;
+		assert(ac <= (int)(sizeof(av) / sizeof(av[0])));
 		if (exec_command(ac, av)) {
 			printf("Failed to destroy tap interface\n");
 			return -1;

From 64c9981e3dcb3b4fdad1926a275fb9ce595c5ad0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 17 Dec 2018 14:54:43 +0100
Subject: [PATCH 1518/2207] utils: ctrl-api-test: improve extmem tests

Use the nro_info field of struct nmreq_opt_extmem to specify
a set of allocator parameters that are consistent with the purpose
of the tests.
---
 utils/ctrl-api-test.c | 76 +++++++++++++++++++++++++++++++------------
 1 file changed, 56 insertions(+), 20 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index e52a1b900..6f32e75be 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -936,7 +936,7 @@ infinite_options(struct TestContext *ctx)
 }
 
 #ifdef CONFIG_NETMAP_EXTMEM
-static int
+int
 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 {
 #ifdef __linux__
@@ -971,13 +971,12 @@ change_param(const char *pname, unsigned long newv, unsigned long *poldv)
 }
 
 static int
-push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
+push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
+		struct nmreq_opt_extmem *e)
 {
-	/* 4MiB is enough for netmap memory-mapped data structures. */
-	const size_t memsize = (1U << 22);
 	void *addr;
 
-	addr = mmap(NULL, memsize, PROT_READ | PROT_WRITE,
+	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 	if (addr == MAP_FAILED) {
 		perror("mmap");
@@ -986,8 +985,8 @@ push_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *e)
 
 	memset(e, 0, sizeof(*e));
 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
+	e->nro_info = *pi;
 	e->nro_usrptr          = (uintptr_t)addr;
-	e->nro_info.nr_memsize = memsize;
 
 	push_option(&e->nro_opt, ctx);
 
@@ -1026,13 +1025,13 @@ pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
 }
 
 static int
-_extmem_option(struct TestContext *ctx, int new_rsz)
+_extmem_option(struct TestContext *ctx,
+		const struct nmreq_pools_info *pi)
 {
 	struct nmreq_opt_extmem e, save;
 	int ret;
-	unsigned long old_rsz;
 
-	if ((ret = push_extmem_option(ctx, &e)) < 0)
+	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
 		return ret;
 
 	save = e;
@@ -1041,48 +1040,85 @@ _extmem_option(struct TestContext *ctx, int new_rsz)
 	ctx->nr_tx_slots = 16;
 	ctx->nr_rx_slots = 16;
 
-	if ((ret = change_param("priv_ring_size", new_rsz, &old_rsz)))
-		return ret;
-
 	if ((ret = port_register_hwall(ctx)))
 		return ret;
 
 	ret = pop_extmem_option(ctx, &save);
 
-	if (change_param("priv_ring_size", old_rsz, NULL) < 0)
-		return -1;
-
 	return ret;
 }
 
+static size_t
+pools_info_min_memsize(const struct nmreq_pools_info *pi)
+{
+	size_t tot = 0;
+
+	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
+	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
+	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
+
+	return tot;
+}
+
+/*
+ * Fill the specification of a netmap memory allocator to be
+ * used with the 'struct nmreq_opt_extmem' option. Arbitrary
+ * values are used for the parameters, but with enough netmap
+ * rings, netmap ifs, and buffers to support a VALE port.
+ */
+static void
+pools_info_fill(struct nmreq_pools_info *pi)
+{
+	pi->nr_if_pool_objtotal = 2;
+	pi->nr_if_pool_objsize = 1024;
+	pi->nr_ring_pool_objtotal = 64;
+	pi->nr_ring_pool_objsize = 512;
+	pi->nr_buf_pool_objtotal = 4096;
+	pi->nr_buf_pool_objsize = 2048;
+	pi->nr_memsize = pools_info_min_memsize(pi);
+}
+
 static int
 extmem_option(struct TestContext *ctx)
 {
-	printf("Testing extmem option on vale0:0\n");
+	struct nmreq_pools_info	pools_info;
 
-	return _extmem_option(ctx, 512);
+	pools_info_fill(&pools_info);
+
+	printf("Testing extmem option on vale0:0\n");
+	return _extmem_option(ctx, &pools_info);
 }
 
 static int
 bad_extmem_option(struct TestContext *ctx)
 {
+	struct nmreq_pools_info	pools_info;
+
 	printf("Testing bad extmem option on vale0:0\n");
 
-	return _extmem_option(ctx, (1 << 16)) < 0 ? 0 : -1;
+	pools_info_fill(&pools_info);
+	/* Request a large ring size, to make sure that the kernel
+	 * rejects our request. */
+	pools_info.nr_ring_pool_objsize = (1 << 16);
+
+	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
 }
 
 static int
 duplicate_extmem_options(struct TestContext *ctx)
 {
 	struct nmreq_opt_extmem e1, save1, e2, save2;
+	struct nmreq_pools_info	pools_info;
 	int ret;
 
 	printf("Testing duplicate extmem option on vale0:0\n");
 
-	if ((ret = push_extmem_option(ctx, &e1)) < 0)
+	pools_info_fill(&pools_info);
+
+	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
 		return ret;
 
-	if ((ret = push_extmem_option(ctx, &e2)) < 0) {
+	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
 		clear_options(ctx);
 		return ret;
 	}

From 0084e2e1441f26b91649178521685a5426b6bffd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 19 Dec 2018 10:08:04 +0100
Subject: [PATCH 1519/2207] utils: ctrl-api-test: introduce ARGV_APPEND macro

This is needed to avoid segmentation faults on the av[] on-stack
array.
---
 utils/ctrl-api-test.c | 48 +++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 6f32e75be..b1ace9b0a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1730,6 +1730,12 @@ parse_interval(const char *arg, int *j, int *k)
 	return -1;
 }
 
+#define ARGV_APPEND(_av, _ac, _x)\
+	do {\
+		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
+		(_av)[(_ac)++] = _x;\
+	} while (0)
+
 int
 main(int argc, char **argv)
 {
@@ -1810,21 +1816,20 @@ main(int argc, char **argv)
 		const char *av[8];
 		int ac = 0;
 #ifdef __FreeBSD__
-		av[ac++] = "ifconfig";
-		av[ac++] = ctx.ifname;
-		av[ac++] = "create";
-		av[ac++] = "up";
+		ARGV_APPEND(av, ac, "ifconfig");
+		ARGV_APPEND(av, ac, ctx.ifname);
+		ARGV_APPEND(av, ac, "create");
+		ARGV_APPEND(av, ac, "up");
 #else
-		av[ac++] = "ip";
-		av[ac++] = "tuntap";
-		av[ac++] = "add";
-		av[ac++] = "mode";
-		av[ac++] = "tap";
-		av[ac++] = "name";
-		av[ac++] = ctx.ifname;
+		ARGV_APPEND(av, ac, "ip");
+		ARGV_APPEND(av, ac, "tuntap");
+		ARGV_APPEND(av, ac, "add");
+		ARGV_APPEND(av, ac, "mode");
+		ARGV_APPEND(av, ac, "tap");
+		ARGV_APPEND(av, ac, "name");
+		ARGV_APPEND(av, ac, ctx.ifname);
 #endif
-		av[ac++] = NULL;
-		assert(ac <= (int)(sizeof(av) / sizeof(av[0])));
+		ARGV_APPEND(av, ac, NULL);
 		if (exec_command(ac, av)) {
 			printf("Failed to create tap interface\n");
 			return -1;
@@ -1856,17 +1861,16 @@ main(int argc, char **argv)
 		const char *av[8];
 		int ac = 0;
 #ifdef __FreeBSD__
-		av[ac++] = "ifconfig";
-		av[ac++] = ctx.ifname;
-		av[ac++] = "destroy";
+		ARGV_APPEND(av, ac, "ifconfig");
+		ARGV_APPEND(av, ac, ctx.ifname);
+		ARGV_APPEND(av, ac, "destroy");
 #else
-		av[ac++] = "ip";
-		av[ac++] = "link";
-		av[ac++] = "del";
-		av[ac++] = ctx.ifname;
+		ARGV_APPEND(av, ac, "ip");
+		ARGV_APPEND(av, ac, "link");
+		ARGV_APPEND(av, ac, "del");
+		ARGV_APPEND(av, ac, ctx.ifname);
 #endif
-		av[ac++] = NULL;
-		assert(ac <= (int)(sizeof(av) / sizeof(av[0])));
+		ARGV_APPEND(av, ac, NULL);
 		if (exec_command(ac, av)) {
 			printf("Failed to destroy tap interface\n");
 			return -1;

From 4559587a53c9653ccc549e0b1656732c81bfc870 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 20 Dec 2018 16:50:01 +0100
Subject: [PATCH 1520/2207] utils: functional: remove dead code

---
 utils/functional.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/utils/functional.c b/utils/functional.c
index efc753900..4d9b100bb 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -328,18 +328,6 @@ build_packet(struct Global *g)
 	                                                           udpofs))))));
 }
 
-// static unsigned
-// tx_bytes_avail(struct netmap_ring *ring, unsigned max_frag_size)
-// {
-// 	unsigned avail_per_slot = ring->nr_buf_size;
-
-// 	if (max_frag_size < avail_per_slot) {
-// 		avail_per_slot = max_frag_size;
-// 	}
-
-// 	return nm_ring_space(ring) * avail_per_slot;
-// }
-
 static int
 tx_flush(struct Global *g)
 {

From ff99af1b04e9d6727cfb8f6fabc085c065ec6402 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 21 Dec 2018 13:07:06 +0100
Subject: [PATCH 1521/2207] linux/i40e: patch for Intel 2.7.29 driver

---
 LINUX/final-patches/intel--i40e--2.7.29 | 167 ++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.7.29

diff --git a/LINUX/final-patches/intel--i40e--2.7.29 b/LINUX/final-patches/intel--i40e--2.7.29
new file mode 100644
index 000000000..09ab66da8
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.7.29
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 4d046c5..5f2e15a 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 1914934..c1dcee9 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -132,6 +132,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3442,6 +3447,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3495,6 +3504,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3523,6 +3536,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13432,6 +13450,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13804,6 +13827,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 1859d78..ea1be59 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -783,6 +787,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 619de130b86d661f384920039a2c385c533c1b97 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 21 Dec 2018 14:50:43 +0100
Subject: [PATCH 1522/2207] apps: nmreplay: add $FreeBSD$ string

---
 apps/nmreplay/nmreplay.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index 759a8338d..d4857a3f7 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -21,6 +21,8 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * $FreeBSD$
  */
 
 

From ffdfc14b984631cbc8cbc15c97f42cbc6b583427 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Dec 2018 15:47:54 +0100
Subject: [PATCH 1523/2207] freebsd: fix bug in netmap_poll() optimization

This bug was introduced by 968a6287512c701e1, and it only affects
select(), which uses POLLRDNORM/POLLWRNORM. The poll() syscall is
not affected by this bug, because POLLIN is used and POLLIN == 1.

Sponsored-by: Sunny Valley Networks
---
 sys/dev/netmap/netmap.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a6af3d3ee..b51c03004 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3304,16 +3304,19 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	}
 	if (want_rx) {
 		enum txrx t = NR_RX;
-		want_rx = 0; /* look for a reason to run the handlers */
+		int rxsync_needed = 0;
+
+		/* look for a reason to run the handlers */
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
 			kring = NMR(na, t)[i];
 			if (kring->ring->cur == kring->ring->tail /* try fetch new buffers */
 			    || kring->rhead != kring->ring->head /* release buffers */) {
-				want_rx = 1;
+				rxsync_needed = 1;
+				break;
 			}
 		}
-		if (!want_rx)
-			revents |= events & (POLLIN | POLLRDNORM); /* we have data */
+		if (!rxsync_needed)
+			revents |= want_rx; /* we have data */
 	}
 #endif
 

From 8b8a3a5008c1bd1f7e5352cf518d39b926638e38 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Dec 2018 16:22:34 +0100
Subject: [PATCH 1524/2207] netmap_poll: make 't' variable a const one

---
 sys/dev/netmap/netmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b51c03004..ca9906f39 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3292,7 +3292,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	 * that we must call nm_os_selrecord() unconditionally.
 	 */
 	if (want_tx) {
-		enum txrx t = NR_TX;
+		const enum txrx t = NR_TX;
 		for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) {
 			kring = NMR(na, t)[i];
 			/* XXX compare ring->cur and kring->tail */
@@ -3303,7 +3303,7 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		}
 	}
 	if (want_rx) {
-		enum txrx t = NR_RX;
+		const enum txrx t = NR_RX;
 		int rxsync_needed = 0;
 
 		/* look for a reason to run the handlers */

From 49207f0e02b86005ec578d615a19c9e5303df7c0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 22 Dec 2018 16:41:50 +0100
Subject: [PATCH 1525/2207] netmap_poll: fix optimization check for TX rings

---
 sys/dev/netmap/netmap.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index ca9906f39..2d3db72f5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3293,12 +3293,14 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	 */
 	if (want_tx) {
 		const enum txrx t = NR_TX;
-		for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) {
+		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
 			kring = NMR(na, t)[i];
-			/* XXX compare ring->cur and kring->tail */
-			if (!nm_ring_empty(kring->ring)) {
+			if (kring->ring->cur != kring->ring->tail) {
+				/* Some unseen TX space is available, so what
+				 * we don't need to run txsync. */
 				revents |= want[t];
-				want[t] = 0;	/* also breaks the loop */
+				want[t] = 0;
+				break;
 			}
 		}
 	}
@@ -3306,17 +3308,22 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 		const enum txrx t = NR_RX;
 		int rxsync_needed = 0;
 
-		/* look for a reason to run the handlers */
 		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
 			kring = NMR(na, t)[i];
-			if (kring->ring->cur == kring->ring->tail /* try fetch new buffers */
-			    || kring->rhead != kring->ring->head /* release buffers */) {
+			if (kring->ring->cur == kring->ring->tail
+				|| kring->rhead != kring->ring->head) {
+				/* There are no unseen packets on this ring,
+				 * or there are some buffers to be returned
+				 * to the netmap port. We therefore go ahead
+				 * and run rxsync. */
 				rxsync_needed = 1;
 				break;
 			}
 		}
-		if (!rxsync_needed)
-			revents |= want_rx; /* we have data */
+		if (!rxsync_needed) {
+			revents |= want_rx;
+			want_rx = 0;
+		}
 	}
 #endif
 

From 79a2acdfde1ac95731bd04b9de3c7bfca705f3d2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 24 Dec 2018 13:36:09 +0100
Subject: [PATCH 1526/2207] linux: patches for 4.20 drivers

---
 ...000--99999 => vanilla--i40e--41000--41400} |   0
 .../final-patches/vanilla--i40e--41400--99999 | 114 ++++++++++++++++++
 ...00--99999 => vanilla--ixgbe--41000--41400} |   0
 ...0--99999 => vanilla--veth.c--41300--41400} |   0
 .../vanilla--veth.c--41400--99999             |  42 +++++++
 5 files changed, 156 insertions(+)
 rename LINUX/final-patches/{vanilla--i40e--41000--99999 => vanilla--i40e--41000--41400} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--41400--99999
 rename LINUX/final-patches/{vanilla--ixgbe--41000--99999 => vanilla--ixgbe--41000--41400} (100%)
 rename LINUX/final-patches/{vanilla--veth.c--41300--99999 => vanilla--veth.c--41300--41400} (100%)
 create mode 100644 LINUX/final-patches/vanilla--veth.c--41400--99999

diff --git a/LINUX/final-patches/vanilla--i40e--41000--99999 b/LINUX/final-patches/vanilla--i40e--41000--41400
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--41000--99999
rename to LINUX/final-patches/vanilla--i40e--41000--41400
diff --git a/LINUX/final-patches/vanilla--i40e--41400--99999 b/LINUX/final-patches/vanilla--i40e--41400--99999
new file mode 100644
index 000000000..6ab0f7d1d
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--41400--99999
@@ -0,0 +1,114 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 0e5dc74b4ef2..604130f5879d 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -95,6 +95,10 @@ MODULE_LICENSE("GPL v2");
+ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+@@ -3170,6 +3174,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3254,6 +3262,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3282,6 +3294,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 	ok = ring->xsk_umem ?
+ 	     i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring)) :
+ 	     !i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+@@ -12675,6 +12691,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13042,6 +13063,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index d0a95424ce58..993ff2722007 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_txrx_common.h"
+ #include "i40e_xsk.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -781,6 +785,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2334,6 +2343,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
diff --git a/LINUX/final-patches/vanilla--ixgbe--41000--99999 b/LINUX/final-patches/vanilla--ixgbe--41000--41400
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbe--41000--99999
rename to LINUX/final-patches/vanilla--ixgbe--41000--41400
diff --git a/LINUX/final-patches/vanilla--veth.c--41300--99999 b/LINUX/final-patches/vanilla--veth.c--41300--41400
similarity index 100%
rename from LINUX/final-patches/vanilla--veth.c--41300--99999
rename to LINUX/final-patches/vanilla--veth.c--41300--41400
diff --git a/LINUX/final-patches/vanilla--veth.c--41400--99999 b/LINUX/final-patches/vanilla--veth.c--41400--99999
new file mode 100644
index 000000000..7b3442eba
--- /dev/null
+++ b/LINUX/final-patches/vanilla--veth.c--41400--99999
@@ -0,0 +1,42 @@
+diff --git a/veth.c b/veth.c
+index 890fa5b905e2..ad8f96f1a6a8 100644
+--- a/veth.c
++++ b/veth.c
+@@ -63,6 +63,10 @@ struct veth_priv {
+ 	unsigned int		requested_headroom;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /*
+  * ethtool interface
+  */
+@@ -891,7 +895,6 @@ static int veth_open(struct net_device *dev)
+ 		netif_carrier_on(dev);
+ 		netif_carrier_on(peer);
+ 	}
+-
+ 	return 0;
+ }
+ 
+@@ -953,12 +956,18 @@ static int veth_dev_init(struct net_device *dev)
+ 		return err;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	veth_netmap_attach(dev);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ }
+ 
+ static void veth_dev_free(struct net_device *dev)
+ {
+ 	veth_free_queues(dev);
++#ifdef DEV_NETMAP
++	netmap_detach(dev);
++#endif /* DEV_NETMAP */
+ 	free_percpu(dev->lstats);
+ }
+ 

From 0c6f609f7b5e693737a48dd0fdf9f4350abb2650 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Dec 2018 16:46:33 +0100
Subject: [PATCH 1527/2207] utils: ctrl-api-test: remove TAP in signal handler

---
 utils/ctrl-api-test.c | 61 ++++++++++++++++++++++++++++---------------
 1 file changed, 40 insertions(+), 21 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index b1ace9b0a..fd8db749c 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -145,7 +145,7 @@ struct TestContext {
 	struct nmreq_option *nr_opt;  /* list of options */
 	sem_t *sem;	/* for thread synchronization */
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
-};
+} ctx;
 
 typedef int (*testfunc_t)(struct TestContext *ctx);
 
@@ -1736,10 +1736,32 @@ parse_interval(const char *arg, int *j, int *k)
 		(_av)[(_ac)++] = _x;\
 	} while (0)
 
+static void
+tap_cleanup(int signo)
+{
+	const char *av[8];
+	int ac = 0;
+
+	(void)signo;
+#ifdef __FreeBSD__
+	ARGV_APPEND(av, ac, "ifconfig");
+	ARGV_APPEND(av, ac, ctx.ifname);
+	ARGV_APPEND(av, ac, "destroy");
+#else
+	ARGV_APPEND(av, ac, "ip");
+	ARGV_APPEND(av, ac, "link");
+	ARGV_APPEND(av, ac, "del");
+	ARGV_APPEND(av, ac, ctx.ifname);
+#endif
+	ARGV_APPEND(av, ac, NULL);
+	if (exec_command(ac, av)) {
+		printf("Failed to destroy tap interface\n");
+	}
+}
+
 int
 main(int argc, char **argv)
 {
-	struct TestContext ctx;
 	int create_tap = 1;
 	int num_tests;
 	int ret  = 0;
@@ -1813,6 +1835,7 @@ main(int argc, char **argv)
 	}
 
 	if (create_tap) {
+		struct sigaction sa;
 		const char *av[8];
 		int ac = 0;
 #ifdef __FreeBSD__
@@ -1834,6 +1857,20 @@ main(int argc, char **argv)
 			printf("Failed to create tap interface\n");
 			return -1;
 		}
+
+		sa.sa_handler = tap_cleanup;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_RESTART;
+		ret         = sigaction(SIGINT, &sa, NULL);
+		if (ret) {
+			perror("sigaction(SIGINT)");
+			goto out;
+		}
+		ret = sigaction(SIGTERM, &sa, NULL);
+		if (ret) {
+			perror("sigaction(SIGTERM)");
+			goto out;
+		}
 	}
 
 	for (i = j; i < k; i++) {
@@ -1857,25 +1894,7 @@ main(int argc, char **argv)
 		context_cleanup(&ctxcopy);
 	}
 out:
-	if (create_tap) {
-		const char *av[8];
-		int ac = 0;
-#ifdef __FreeBSD__
-		ARGV_APPEND(av, ac, "ifconfig");
-		ARGV_APPEND(av, ac, ctx.ifname);
-		ARGV_APPEND(av, ac, "destroy");
-#else
-		ARGV_APPEND(av, ac, "ip");
-		ARGV_APPEND(av, ac, "link");
-		ARGV_APPEND(av, ac, "del");
-		ARGV_APPEND(av, ac, ctx.ifname);
-#endif
-		ARGV_APPEND(av, ac, NULL);
-		if (exec_command(ac, av)) {
-			printf("Failed to destroy tap interface\n");
-			return -1;
-		}
-	}
+	tap_cleanup(0);
 
 	return ret;
 }

From 1b7ee8290fc5aaf75afe0857eaf112cf3254f980 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 24 Dec 2018 19:43:14 +0100
Subject: [PATCH 1528/2207] utils: ctrl-api-test: fix -Wshadow warning

---
 utils/ctrl-api-test.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fd8db749c..fd1ce318c 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -145,7 +145,7 @@ struct TestContext {
 	struct nmreq_option *nr_opt;  /* list of options */
 	sem_t *sem;	/* for thread synchronization */
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
-} ctx;
+} ctx_;
 
 typedef int (*testfunc_t)(struct TestContext *ctx);
 
@@ -1745,13 +1745,13 @@ tap_cleanup(int signo)
 	(void)signo;
 #ifdef __FreeBSD__
 	ARGV_APPEND(av, ac, "ifconfig");
-	ARGV_APPEND(av, ac, ctx.ifname);
+	ARGV_APPEND(av, ac, ctx_.ifname);
 	ARGV_APPEND(av, ac, "destroy");
 #else
 	ARGV_APPEND(av, ac, "ip");
 	ARGV_APPEND(av, ac, "link");
 	ARGV_APPEND(av, ac, "del");
-	ARGV_APPEND(av, ac, ctx.ifname);
+	ARGV_APPEND(av, ac, ctx_.ifname);
 #endif
 	ARGV_APPEND(av, ac, NULL);
 	if (exec_command(ac, av)) {
@@ -1771,7 +1771,7 @@ main(int argc, char **argv)
 	int opt;
 	int i;
 
-	memset(&ctx, 0, sizeof(ctx));
+	memset(&ctx_, 0, sizeof(ctx_));
 
 	{
 		struct timespec t;
@@ -1780,9 +1780,9 @@ main(int argc, char **argv)
 		clock_gettime(CLOCK_REALTIME, &t);
 		srand((unsigned int)t.tv_nsec);
 		idx = rand() % 8000 + 100;
-		snprintf(ctx.ifname, sizeof(ctx.ifname), "tap%d", idx);
+		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
 		idx = rand() % 800 + 100;
-		snprintf(ctx.bdgname, sizeof(ctx.bdgname), "vale%d", idx);
+		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
 	}
 
 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
@@ -1792,7 +1792,7 @@ main(int argc, char **argv)
 			return 0;
 
 		case 'i':
-			strncpy(ctx.ifname, optarg, sizeof(ctx.ifname) - 1);
+			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
 			create_tap = 0;
 			break;
 
@@ -1840,7 +1840,7 @@ main(int argc, char **argv)
 		int ac = 0;
 #ifdef __FreeBSD__
 		ARGV_APPEND(av, ac, "ifconfig");
-		ARGV_APPEND(av, ac, ctx.ifname);
+		ARGV_APPEND(av, ac, ctx_.ifname);
 		ARGV_APPEND(av, ac, "create");
 		ARGV_APPEND(av, ac, "up");
 #else
@@ -1850,7 +1850,7 @@ main(int argc, char **argv)
 		ARGV_APPEND(av, ac, "mode");
 		ARGV_APPEND(av, ac, "tap");
 		ARGV_APPEND(av, ac, "name");
-		ARGV_APPEND(av, ac, ctx.ifname);
+		ARGV_APPEND(av, ac, ctx_.ifname);
 #endif
 		ARGV_APPEND(av, ac, NULL);
 		if (exec_command(ac, av)) {
@@ -1883,7 +1883,7 @@ main(int argc, char **argv)
 			ret = fd;
 			goto out;
 		}
-		memcpy(&ctxcopy, &ctx, sizeof(ctxcopy));
+		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
 		ctxcopy.fd = fd;
 		ret        = tests[i].test(&ctxcopy);
 		if (ret != 0) {

From 18567464a67f8cfa0ad097235ce712c272fe817f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 25 Dec 2018 17:34:29 +0100
Subject: [PATCH 1529/2207] utils: ctrl-api-test: add missing 

---
 utils/ctrl-api-test.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fd1ce318c..d2ec47973 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifdef __linux__
 #include 

From ba02539859d46d33d401811466e8d425f560d603 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 25 Dec 2018 17:40:08 +0100
Subject: [PATCH 1530/2207] utils: ctrl-api-test: use static declaration of
 global variable

---
 utils/ctrl-api-test.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d2ec47973..202a33857 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -146,7 +146,9 @@ struct TestContext {
 	struct nmreq_option *nr_opt;  /* list of options */
 	sem_t *sem;	/* for thread synchronization */
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
-} ctx_;
+};
+
+static struct TestContext ctx_;
 
 typedef int (*testfunc_t)(struct TestContext *ctx);
 

From 254615b1fbbc7c179e59e60948b94cd34db99823 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 31 Dec 2018 12:32:52 +0100
Subject: [PATCH 1531/2207] utils: ctrl-api-test: add FreeBSD string

---
 utils/ctrl-api-test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 202a33857..20033da78 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -23,6 +23,8 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * $FreeBSD$
  */
 
 #include 

From ee49b56786d1de67811173dcb34e5014f2712ac5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 31 Dec 2018 12:58:39 +0100
Subject: [PATCH 1532/2207] utils: ctrl-api-test: fix warnings on FreeBSD
 non-x86 builds

---
 utils/ctrl-api-test.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 20033da78..960762d28 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -183,7 +183,7 @@ port_info_get(struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
-	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
@@ -216,8 +216,9 @@ port_register(struct TestContext *ctx)
 	int ret;
 
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
-	       "flags=0x%lx) on '%s'\n",
-	       ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
+	       "flags=0x%llx) on '%s'\n",
+	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
+	       ctx->ifname);
 
 	nmreq_hdr_init(&hdr, ctx->ifname);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
@@ -238,8 +239,8 @@ port_register(struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
 		return ret;
 	}
-	printf("nr_offset 0x%lx\n", req.nr_offset);
-	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
+	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
@@ -687,15 +688,18 @@ pools_info_get(struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
 		return ret;
 	}
-	printf("nr_memsize %lu\n", req.nr_memsize);
+	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
-	printf("nr_if_pool_offset 0x%lx\n", req.nr_if_pool_offset);
+	printf("nr_if_pool_offset 0x%llx\n",
+		(unsigned long long)req.nr_if_pool_offset);
 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
-	printf("nr_ring_pool_offset 0x%lx\n", req.nr_if_pool_offset);
+	printf("nr_ring_pool_offset 0x%llx\n",
+		(unsigned long long)req.nr_if_pool_offset);
 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
-	printf("nr_buf_pool_offset 0x%lx\n", req.nr_buf_pool_offset);
+	printf("nr_buf_pool_offset 0x%llx\n",
+		(unsigned long long)req.nr_buf_pool_offset);
 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
 

From f79181a39e26e25e217477a5ca9179a9c7a4c2d4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 3 Jan 2019 13:24:59 +0100
Subject: [PATCH 1533/2207] utils: ctrl-api-test: fix issues found by coverity
 scan (FreeBSD)

---
 utils/ctrl-api-test.c | 100 +++++++++++++++++++++++-------------------
 1 file changed, 54 insertions(+), 46 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 960762d28..622220431 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -83,16 +83,20 @@ exec_command(int argc, const char *const argv[])
 	child_pid = fork();
 	if (child_pid == 0) {
 		char **av;
+		int fds[3];
+		int i;
 
 		/* Child process. Redirect stdin, stdout
 		 * and stderr. */
-		close(0);
-		close(1);
-		close(2);
-		if (open("/dev/null", O_RDONLY) < 0 ||
-			open("/dev/null", O_RDONLY) < 0 ||
-			open("/dev/null", O_RDONLY) < 0) {
-			return -1;
+		for (i = 0; i < 3; i++) {
+			close(i);
+			fds[i] = open("/dev/null", O_RDONLY);
+			if (fds[i] < 0) {
+				for (i--; i >= 0; i--) {
+					close(fds[i]);
+				}
+				return -1;
+			}
 		}
 
 		/* Make a copy of the arguments, passing them to execvp. */
@@ -128,7 +132,8 @@ exec_command(int argc, const char *const argv[])
 #define THRET_FAILURE	((void *)0)
 
 struct TestContext {
-	char ifname[128];
+	char ifname[64];
+	char ifname_ext[128];
 	char bdgname[64];
 	uint32_t nr_tx_slots;   /* slots in tx rings */
 	uint32_t nr_rx_slots;   /* slots in rx rings */
@@ -171,9 +176,9 @@ port_info_get(struct TestContext *ctx)
 	int success;
 	int ret;
 
-	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
@@ -218,9 +223,9 @@ port_register(struct TestContext *ctx)
 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
 	       "flags=0x%llx) on '%s'\n",
 	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
-	       ctx->ifname);
+	       ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
 	hdr.nr_body    = (uintptr_t)&req;
 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
@@ -284,10 +289,10 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	int success;
 	int ret;
 
-	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname);
+	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
 
 	memset(&req, 0, sizeof(req));
-	memcpy(req.nr_name, ctx->ifname, sizeof(req.nr_name));
+	memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
 	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
 	req.nr_version = netmap_api;
 	req.nr_ringid     = ctx->nr_ringid;
@@ -399,7 +404,7 @@ legacy_regif_extra_bufs(struct TestContext *ctx)
 static int
 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
 {
-	strncat(ctx->ifname, "{pipeexbuf", sizeof(ctx->ifname));
+	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
 
@@ -409,7 +414,7 @@ legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
 static int
 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
 {
-	strncpy(ctx->ifname, "valeX1:Y4", sizeof(ctx->ifname));
+	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
 	return legacy_regif_extra_bufs_pipe(ctx);
 }
 
@@ -478,10 +483,10 @@ vale_attach(struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
 	struct nmreq_header hdr;
-	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname)];
+	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
 
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
@@ -516,7 +521,7 @@ vale_detach(struct TestContext *ctx)
 	char vpname[256];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
@@ -560,9 +565,9 @@ port_hdr_set_and_get(struct TestContext *ctx)
 	struct nmreq_header hdr;
 	int ret;
 
-	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
@@ -577,7 +582,7 @@ port_hdr_set_and_get(struct TestContext *ctx)
 		return -1;
 	}
 
-	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
 	req.nr_hdr_len = 0;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
@@ -603,7 +608,7 @@ vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
 {
 	int ret;
 
-	strncpy(ctx->ifname, "vale:eph0", sizeof(ctx->ifname));
+	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
 	ctx->nr_mode = NR_REG_ALL_NIC;
 	if ((ret = port_register(ctx))) {
 		return ret;
@@ -632,11 +637,11 @@ vale_persistent_port(struct TestContext *ctx)
 	int result;
 	int ret;
 
-	strncpy(ctx->ifname, "per4", sizeof(ctx->ifname));
+	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
 
-	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
@@ -654,7 +659,7 @@ vale_persistent_port(struct TestContext *ctx)
 	/* Attach the persistent VALE port to a switch and then detach. */
 	result = vale_attach_detach(ctx);
 
-	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
 	hdr.nr_body    = (uintptr_t)NULL;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
@@ -676,9 +681,9 @@ pools_info_get(struct TestContext *ctx)
 	struct nmreq_header hdr;
 	int ret;
 
-	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
 	hdr.nr_body    = (uintptr_t)&req;
 	memset(&req, 0, sizeof(req));
@@ -739,14 +744,14 @@ pools_info_get_and_register(struct TestContext *ctx)
 static int
 pools_info_get_empty_ifname(struct TestContext *ctx)
 {
-	strncpy(ctx->ifname, "", sizeof(ctx->ifname));
+	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
 	return pools_info_get(ctx) != 0 ? 0 : -1;
 }
 
 static int
 pipe_master(struct TestContext *ctx)
 {
-	strncat(ctx->ifname, "{pipeid1", sizeof(ctx->ifname));
+	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
 	ctx->nr_mode = NR_REG_NIC_SW;
 
 	if (port_register(ctx) == 0) {
@@ -761,7 +766,7 @@ pipe_master(struct TestContext *ctx)
 static int
 pipe_slave(struct TestContext *ctx)
 {
-	strncat(ctx->ifname, "}pipeid2", sizeof(ctx->ifname));
+	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
 	ctx->nr_mode = NR_REG_ALL_NIC;
 
 	return port_register(ctx);
@@ -772,7 +777,7 @@ pipe_slave(struct TestContext *ctx)
 static int
 pipe_port_info_get(struct TestContext *ctx)
 {
-	strncat(ctx->ifname, "}pipeid3", sizeof(ctx->ifname));
+	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
 
 	return port_info_get(ctx);
 }
@@ -780,7 +785,7 @@ pipe_port_info_get(struct TestContext *ctx)
 static int
 pipe_pools_info_get(struct TestContext *ctx)
 {
-	strncat(ctx->ifname, "{xid", sizeof(ctx->ifname));
+	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
 
 	return pools_info_get(ctx);
 }
@@ -794,7 +799,7 @@ vale_polling_enable(struct TestContext *ctx)
 	char vpname[256];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
 	nmreq_hdr_init(&hdr, vpname);
@@ -826,7 +831,7 @@ vale_polling_disable(struct TestContext *ctx)
 	char vpname[256];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
+	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
 	nmreq_hdr_init(&hdr, vpname);
@@ -861,8 +866,9 @@ vale_polling_enable_disable(struct TestContext *ctx)
 		 * because it is currently broken. We are happy to see that
 		 * it fails. */
 		return 0;
-#endif
+#else
 		return ret;
+#endif
 	}
 
 	if ((ret = vale_polling_disable(ctx))) {
@@ -913,7 +919,7 @@ unsupported_option(struct TestContext *ctx)
 {
 	struct nmreq_option opt, save;
 
-	printf("Testing unsupported option on %s\n", ctx->ifname);
+	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
 
 	memset(&opt, 0, sizeof(opt));
 	opt.nro_reqtype = 1234;
@@ -933,7 +939,7 @@ infinite_options(struct TestContext *ctx)
 {
 	struct nmreq_option opt;
 
-	printf("Testing infinite list of options on %s\n", ctx->ifname);
+	printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
 
 	opt.nro_reqtype = 1234;
 	push_option(&opt, ctx);
@@ -1045,7 +1051,7 @@ _extmem_option(struct TestContext *ctx,
 
 	save = e;
 
-	strncpy(ctx->ifname, "vale0:0", sizeof(ctx->ifname));
+	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
 	ctx->nr_tx_slots = 16;
 	ctx->nr_rx_slots = 16;
 
@@ -1235,9 +1241,9 @@ sync_kloop_stop(struct TestContext *ctx)
 	struct nmreq_header hdr;
 	int ret;
 
-	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret != 0) {
@@ -1255,9 +1261,9 @@ sync_kloop_worker(void *opaque)
 	struct nmreq_header hdr;
 	int ret;
 
-	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
 	hdr.nr_body    = (uintptr_t)&req;
 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
@@ -1423,12 +1429,12 @@ csb_enable(struct TestContext *ctx)
 	saveopt = opt.nro_opt;
 	saveopt.nro_status = 0;
 
-	nmreq_hdr_init(&hdr, ctx->ifname);
+	nmreq_hdr_init(&hdr, ctx->ifname_ext);
 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
 	hdr.nr_body = (uintptr_t)NULL;
 
-	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname);
+	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
 
 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
 	if (ret != 0) {
@@ -1894,6 +1900,8 @@ main(int argc, char **argv)
 		}
 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
 		ctxcopy.fd = fd;
+		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
+			sizeof(ctxcopy.ifname));
 		ret        = tests[i].test(&ctxcopy);
 		if (ret != 0) {
 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);

From 7d995d5c3facd76c06a13954bb07d995c184efbe Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 3 Jan 2019 17:29:50 +0100
Subject: [PATCH 1534/2207] utils: ctrl-api-test: fix warning

---
 utils/ctrl-api-test.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 622220431..e7ea8f711 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -84,7 +84,6 @@ exec_command(int argc, const char *const argv[])
 	if (child_pid == 0) {
 		char **av;
 		int fds[3];
-		int i;
 
 		/* Child process. Redirect stdin, stdout
 		 * and stderr. */

From 26fd5ebc8e4c78268f80a6b047803a6eaaa64060 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Jan 2019 08:45:59 +0100
Subject: [PATCH 1535/2207] linux/scripts: prepare for major number change

---
 LINUX/scripts/vers | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/LINUX/scripts/vers b/LINUX/scripts/vers
index 00d15a77d..9afeff5df 100755
--- a/LINUX/scripts/vers
+++ b/LINUX/scripts/vers
@@ -59,6 +59,12 @@ sub next
 		} else {
 			return "4.0";
 		}
+	} elsif ($may == 4) {
+		if ($min < 20) {
+			return "4." . ($min + 1);
+		} else {
+			return "5.0";
+		}
 	} else {
 		return "$may." . ($min + 1);
 	}
@@ -74,6 +80,8 @@ sub prev
 			return "2.6.39";
 		} elsif ($may == 4) {
 			return "3.19";
+		} elsif ($may == 5) {
+			return "4.20";
 		} else {
 			die "Unknown version: $v";
 		}

From dbd01494b6707375a53a63d465a410d07e3b9600 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 8 Jan 2019 12:39:47 +0100
Subject: [PATCH 1536/2207] linux: ptnet: free bugs in irq setup error path

This fixes a resource leak and an invalid resource freeing.
---
 LINUX/netmap_ptnet.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 6da161f2f..eb9015e9b 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -824,7 +824,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 	return 0;
 
 err_irqs:
-	for (; i>=0; i--) {
+	for (i--; i>=0; i--) {
 		free_irq(ptnet_get_irq_vector(pi, i), pi->queues[i]);
 	}
 	i = pi->num_rings-1;
@@ -835,6 +835,8 @@ ptnet_irqs_init(struct ptnet_info *pi)
 err_alloc:
 #ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX
 	kfree(pi->msix_entries);
+#else
+	pci_free_irq_vectors(pi->pdev);
 #endif
 	return ret;
 }

From 44b9d7ab9839feb4c1c6ad1c381e302051f29f70 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 8 Jan 2019 12:41:55 +0100
Subject: [PATCH 1537/2207] linux: ptnet: remove unused CPU affinity mask

---
 LINUX/netmap_ptnet.c | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index eb9015e9b..6cd9d07aa 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -64,7 +64,6 @@ struct ptnet_queue {
 
 	/* MSI-X interrupt data structures. */
 	char msix_name[64];
-	cpumask_var_t msix_affinity_mask;
 };
 
 struct ptnet_rx_queue {
@@ -794,16 +793,6 @@ ptnet_irqs_init(struct ptnet_info *pi)
 		goto err_alloc;
 	}
 
-	for (i=0; inum_rings; i++) {
-		struct ptnet_queue *pq = pi->queues[i];
-
-		memset(&pq->msix_affinity_mask, 0, sizeof(pq->msix_affinity_mask));
-		if (!alloc_cpumask_var(&pq->msix_affinity_mask, GFP_KERNEL)) {
-			pr_err("%s: Failed to alloc cpumask var\n", __func__);
-			goto err_masks;
-		}
-	}
-
 	for (i=0; inum_rings; i++) {
 		struct ptnet_queue *pq = pi->queues[i];
 		irq_handler_t handler = (i < pi->num_tx_rings) ?
@@ -828,10 +817,6 @@ ptnet_irqs_init(struct ptnet_info *pi)
 		free_irq(ptnet_get_irq_vector(pi, i), pi->queues[i]);
 	}
 	i = pi->num_rings-1;
-err_masks:
-	for (; i>=0; i--) {
-		free_cpumask_var(pi->queues[i]->msix_affinity_mask);
-	}
 err_alloc:
 #ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX
 	kfree(pi->msix_entries);
@@ -850,9 +835,6 @@ ptnet_irqs_fini(struct ptnet_info *pi)
 		struct ptnet_queue *pq = pi->queues[i];
 
 		free_irq(ptnet_get_irq_vector(pi, i), pq);
-		if (pq->msix_affinity_mask) {
-			free_cpumask_var(pq->msix_affinity_mask);
-		}
 	}
 #ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX
 	pci_disable_msix(pi->pdev);

From 17dbdd60b708e5f7e76650c18372d91bbf9bccbc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 9 Jan 2019 15:44:21 +0100
Subject: [PATCH 1538/2207] vale.4: fix small typo

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=212333
---
 share/man/man4/vale.4 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
index 4917632ce..4b74ae28f 100644
--- a/share/man/man4/vale.4
+++ b/share/man/man4/vale.4
@@ -28,7 +28,7 @@
 .\" $FreeBSD$
 .\" $Id: $
 .\"
-.Dd July 27, 2012
+.Dd Jan 9, 2019
 .Dt VALE 4
 .Os
 .Sh NAME
@@ -85,7 +85,7 @@ changed to sysctl variables in future releases.
 .Nm
 uses the following sysctl variables to control operation:
 .Bl -tag -width dev.netmap.verbose
-.It dev.netmap.bridge
+.It dev.netmap.bridge_batch
 The maximum number of packets processed internally
 in each iteration.
 Defaults to 1024, use lower values to trade latency

From 3acde6bfae98adc6201d267a9196f79584edf0d8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 9 Jan 2019 15:58:26 +0100
Subject: [PATCH 1539/2207] vale.4: remove redundant paragraph

---
 share/man/man4/vale.4 | 2 --
 1 file changed, 2 deletions(-)

diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
index 4b74ae28f..dcdd24ccc 100644
--- a/share/man/man4/vale.4
+++ b/share/man/man4/vale.4
@@ -112,8 +112,6 @@ qemu -net nic -net netmap,ifname=vale2:d ... &
 .Sh SEE ALSO
 .Xr netmap 4
 .Pp
-.Xr http://info.iet.unipi.it/~luigi/vale/
-.Pp
 Luigi Rizzo, Giuseppe Lettieri: VALE, a switched ethernet for virtual machines,
 June 2012, http://info.iet.unipi.it/~luigi/vale/
 .Sh AUTHORS

From 97f4fdf3fceaab1acfc2a9a6f20968ca0844a142 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 9 Jan 2019 16:01:18 +0100
Subject: [PATCH 1540/2207] netmap.4: update bridge example

---
 share/man/man4/netmap.4 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 3ee7ccf13..cbdd55435 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -981,9 +981,9 @@ is another test program which interconnects two
 ports.
 It can be used for transparent forwarding between
 interfaces, as in
-.Dl bridge -i ix0 -i ix1
+.Dl bridge -i netmap:ix0 -i netmap:ix1
 or even connect the NIC to the host stack using netmap
-.Dl bridge -i ix0 -i ix0
+.Dl bridge -i netmap:ix0
 .Ss USING THE NATIVE API
 The following code implements a traffic generator
 .Pp

From c80a9cb0d093707ddd14e74a13824fec3fcc77a7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 18 Jan 2019 16:14:42 +0100
Subject: [PATCH 1541/2207] netmap_sync_kloop: poll_wait on TX nmirq before RX
 nmirqs

This is not meant to have any effect, but only to improve consistency
and help with debugging (since TX CSB entries are laid out before RX CSB
entries).
---
 sys/dev/netmap/netmap_kloop.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 11ec70914..0429f1dd0 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -558,8 +558,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
 				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
 			NMG_UNLOCK();
-			poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
 			poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
+			poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
 		}
 #else   /* SYNC_KLOOP_POLL */
 		opt->nro_status = EOPNOTSUPP;

From b5afd073e30fa13d4f2504d2335a33cec7ab1362 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 18 Jan 2019 16:37:14 +0100
Subject: [PATCH 1542/2207] kloop: fix race condition on setting task state

---
 sys/dev/netmap/netmap_kloop.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 0429f1dd0..067a373d8 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -574,8 +574,18 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
-			__set_current_state(TASK_INTERRUPTIBLE);
+		if (poll_ctx) {
+			/* It is important to set the task state as
+			 * interruptible before processing any TX/RX ring,
+			 * so that if a notification on ring Y comes after
+			 * we have processed ring Y, but before we call
+			 * schedule(), we don't miss it. This is true because
+			 * the wake up function will change the the task state,
+			 * and therefore the schedule_timeout() call below
+			 * will observe the change).
+			 */
+			set_current_state(TASK_INTERRUPTIBLE);
+		}
 #endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
@@ -622,7 +632,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			/* If a poll context is present, yield to the scheduler
 			 * waiting for a notification to come either from
 			 * netmap or the application. */
-			schedule_timeout_interruptible(msecs_to_jiffies(1000));
+			schedule_timeout(msecs_to_jiffies(20000));
 		} else
 #endif /* SYNC_KLOOP_POLL */
 		{

From cd10c5b94a5c6a300dce0b373205e493649772a7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 18 Jan 2019 17:21:42 +0100
Subject: [PATCH 1543/2207] kloop: prepare sync arguments in advance

---
 sys/dev/netmap/netmap_kloop.c | 70 ++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 25 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 067a373d8..bc6e259fa 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -439,6 +439,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct sync_kloop_poll_ctx *poll_ctx = NULL;
 #endif  /* SYNC_KLOOP_POLL */
 	int num_rx_rings, num_tx_rings, num_rings;
+	struct sync_kloop_ring_args *args = NULL;
 	uint32_t sleep_us = req->sleep_us;
 	struct nm_csb_atok* csb_atok_base;
 	struct nm_csb_ktoa* csb_ktoa_base;
@@ -488,6 +489,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	num_tx_rings = priv->np_qlast[NR_TX] - priv->np_qfirst[NR_TX];
 	num_rings = num_tx_rings + num_rx_rings;
 
+	args = nm_os_malloc(num_rings * sizeof(args[0]));
+	if (!args) {
+		err = ENOMEM;
+		goto out;
+	}
+
 	/* Validate notification options. */
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
@@ -567,6 +574,31 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 	}
 
+	/* Prepare the arguments for netmap_sync_kloop_tx_ring()
+	 * and netmap_sync_kloop_rx_ring(). */
+	for (i = 0; i < num_tx_rings; i++) {
+		struct sync_kloop_ring_args *a = args + i;
+
+		a->kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
+		a->csb_atok = csb_atok_base + i;
+		a->csb_ktoa = csb_ktoa_base + i;
+#ifdef SYNC_KLOOP_POLL
+		if (poll_ctx)
+			a->irq_ctx = poll_ctx->entries[i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+	}
+	for (i = 0; i < num_rx_rings; i++) {
+		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
+
+		a->kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
+		a->csb_atok = csb_atok_base + num_tx_rings + i;
+		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
+#ifdef SYNC_KLOOP_POLL
+		if (poll_ctx)
+			a->irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
+#endif /* SYNC_KLOOP_POLL */
+	}
+
 	/* Main loop. */
 	for (;;) {
 		if (unlikely(NM_ACCESS_ONCE(priv->np_kloop_state) & NM_SYNC_KLOOP_STOPPING)) {
@@ -590,41 +622,24 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; i < num_tx_rings; i++) {
-			struct sync_kloop_ring_args a = {
-				.kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]],
-				.csb_atok = csb_atok_base + i,
-				.csb_ktoa = csb_ktoa_base + i,
-			};
+			struct sync_kloop_ring_args *a = args + i;
 
-#ifdef SYNC_KLOOP_POLL
-			if (poll_ctx)
-				a.irq_ctx = poll_ctx->entries[i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
+			if (unlikely(nm_kr_tryget(a->kring, 1, NULL))) {
 				continue;
 			}
-			netmap_sync_kloop_tx_ring(&a);
-			nm_kr_put(a.kring);
+			netmap_sync_kloop_tx_ring(a);
+			nm_kr_put(a->kring);
 		}
 
 		/* Process all the RX rings bound to this file descriptor. */
 		for (i = 0; i < num_rx_rings; i++) {
-			struct sync_kloop_ring_args a = {
-				.kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]],
-				.csb_atok = csb_atok_base + num_tx_rings + i,
-				.csb_ktoa = csb_ktoa_base + num_tx_rings + i,
-			};
+			struct sync_kloop_ring_args *a = args + num_tx_rings + i;
 
-#ifdef SYNC_KLOOP_POLL
-			if (poll_ctx)
-				a.irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-
-			if (unlikely(nm_kr_tryget(a.kring, 1, NULL))) {
+			if (unlikely(nm_kr_tryget(a->kring, 1, NULL))) {
 				continue;
 			}
-			netmap_sync_kloop_rx_ring(&a);
-			nm_kr_put(a.kring);
+			netmap_sync_kloop_rx_ring(a);
+			nm_kr_put(a->kring);
 		}
 
 #ifdef SYNC_KLOOP_POLL
@@ -667,6 +682,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	}
 #endif /* SYNC_KLOOP_POLL */
 
+	if (args) {
+		nm_os_free(args);
+		args = NULL;
+	}
+
 	/* Reset the kloop state. */
 	NMG_LOCK();
 	priv->np_kloop_state = 0;

From d5cee4216695f0d254da6a391c6b721b57ce3e2c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 18 Jan 2019 17:54:38 +0100
Subject: [PATCH 1544/2207] sync_kloop_kring_dump: sort values in the correct
 order

---
 sys/dev/netmap/netmap_kloop.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index bc6e259fa..883ef67e3 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -127,10 +127,10 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 {
-	nm_prinf("%s - name: %s hwcur: %d hwtail: %d "
-		"rhead: %d rcur: %d rtail: %d",
-		title, kring->name, kring->nr_hwcur, kring->nr_hwtail,
-		kring->rhead, kring->rcur, kring->rtail);
+	nm_prinf("%s - %s hwcur: %d rhead: %d "
+		"rcur: %d rtail: %d hwtail: %d",
+		title, kring->name, kring->nr_hwcur, kring->rhead,
+		kring->rcur, kring->rtail, kring->nr_hwtail);
 }
 
 struct sync_kloop_ring_args {

From 33f0cfef13ca7fa08c4d425503b39c6c80426546 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 18 Jan 2019 18:05:43 +0100
Subject: [PATCH 1545/2207] sync_kloop_kring_dump: improve formatting

---
 sys/dev/netmap/netmap_kloop.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 883ef67e3..b46183c84 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -127,8 +127,8 @@ csb_atok_intr_enabled(struct nm_csb_atok __user *csb_atok)
 static inline void
 sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 {
-	nm_prinf("%s - %s hwcur: %d rhead: %d "
-		"rcur: %d rtail: %d hwtail: %d",
+	nm_prinf("%s, kring %s, hwcur %d, rhead %d, "
+		"rcur %d, rtail %d, hwtail %d",
 		title, kring->name, kring->nr_hwcur, kring->rhead,
 		kring->rcur, kring->rtail, kring->nr_hwtail);
 }

From 12e7116be380fb49ca516807fc37215130634aa2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 18 Jan 2019 18:33:57 +0100
Subject: [PATCH 1546/2207] update nm_kr_[tr]xempty to check rhead rather than
 rcur

A TX (RX) ring is empty when head == tail. The cur pointer can be
between head and tail included (typically if the application looks
for more space). In CSB mode, the kernel kloop may see cur ahead
of head because of a (safe) race condition. This was causing
problems with netmap passthrough experiments (over netmap pipes),
where the race condition can be observed.
---
 sys/dev/netmap/netmap_kern.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f0905c1f2..f68ed1bb8 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1159,7 +1159,7 @@ nm_kr_rxspace(struct netmap_kring *k)
 static inline int
 nm_kr_txempty(struct netmap_kring *kring)
 {
-	return kring->rcur == kring->nr_hwtail;
+	return kring->rhead == kring->nr_hwtail;
 }
 
 /* True if no more completed slots in the rx ring, only valid after

From 87e240de50b81fe2b8a07e8d488c65d470d090ce Mon Sep 17 00:00:00 2001
From: DanielPharos 
Date: Sun, 20 Jan 2019 16:58:36 +0100
Subject: [PATCH 1547/2207] Corrected for driver-suffix.

---
 LINUX/final-patches/mellanox--mlx5--4.5 | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/LINUX/final-patches/mellanox--mlx5--4.5 b/LINUX/final-patches/mellanox--mlx5--4.5
index cf79dd9c3..978a2589c 100644
--- a/LINUX/final-patches/mellanox--mlx5--4.5
+++ b/LINUX/final-patches/mellanox--mlx5--4.5
@@ -13,39 +13,41 @@ index bda9ec7..74cf699 100644
  		health.o mcg.o cq.o srq.o srq_exp.o alloc.o qp.o port.o mr.o pd.o \
  		mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
  		fs_counters.o rl.o lag.o dev.o wq.o lib/gid.o lib/clock.o \
-@@ -11,24 +11,24 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+@@ -11,25 +11,25 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
  		icmd.o capi.o diag/fw_tracer.o diag/diag_cnt.o \
  		eswitch_devlink_compat.o
  
 -mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
  
 -mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
  		fpga/ipsec.o fpga/tls.o fpga/trans.o fpga/xfer.o
  
 -mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
  		en_tx.o en_rx.o en_dim.o en_txrx.o en_stats.o vxlan.o en_sysfs.o en_ecn.o \
  		en_arfs.o en_fs_ethtool.o en_selftest.o en/port.o en_debugfs.o en_sniffer.o
  
 -mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_MPFS) += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
  
 -mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
  
 -mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o en/port_buffer.o
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o en/port_buffer.o
  
 -mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
  
 -mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
-+mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
  		en_accel/ipsec_stats.o
  
- mlx5_core-$(CONFIG_MLX5_EN_TLS) +=  en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) +=  en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) +=  en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
+ 
 diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 index f0a23e9..3d7e6e5 100644
 --- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c

From 80ed863a285e40364960e656d8f25d9261992372 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 11:06:20 +0100
Subject: [PATCH 1548/2207] ptnetmap: use proper memory barriers to interact
 with CSB

---
 LINUX/netmap_ptnet.c         | 11 +++++++++--
 sys/dev/netmap/if_ptnet.c    | 14 ++++++++++++--
 sys/dev/netmap/netmap_kern.h | 18 +++++++++++++-----
 sys/net/netmap.h             | 13 +++++++++++++
 4 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 6cd9d07aa..fa59c035e 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -327,7 +327,10 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 		netif_stop_subqueue(netdev, pq->kring_id);
 		atok->appl_need_kick = 1;
 
-		/* Double check. */
+		/* Double check. We need a full barrier to prevent the store
+		 * to atok->appl_need_kick to be reordered with the load from
+		 * ktoa->hwcur and ktoa->hwtail (store-load barrier). */
+		smp_mb();
 		ptnet_sync_tail(ktoa, kring);
 		if (unlikely(ptnet_tx_slots(a.ring) >= pi->min_tx_slots)) {
 			/* More TX space came in the meanwhile. */
@@ -695,7 +698,11 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		napi_complete(napi);
 #endif
 
-		/* Double check for more completed RX slots. */
+		/* Double check for more completed RX slots.
+		 * We need a full barrier to prevent the store to
+		 * atok->appl_need_kick to be reordered with the load from
+		 * ktoa->hwcur and ktoa->hwtail (store-load barrier). */
+		smp_mb();
 		ptnet_sync_tail(ktoa, kring);
 		if (head != ring->tail) {
 			/* If there is more work to do, disable notifications
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index c362018b9..fadba6c55 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1764,7 +1764,12 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 				 * the host. */
 				atok->appl_need_kick = 1;
 
-				/* Double-check. */
+				/* Double check. We need a full barrier to
+				 * prevent the store to atok->appl_need_kick
+				 * to be reordered with the load from
+				 * ktoa->hwcur and ktoa->hwtail (store-load
+				 * barrier). */
+				atomic_thread_fence_seq_cst();
 				ptnet_sync_tail(ktoa, kring);
 				if (likely(PTNET_TX_NOSPACE(head, kring,
 							    minspace))) {
@@ -2046,7 +2051,12 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 				 * last interrupt. */
 				atok->appl_need_kick = 1;
 
-				/* Double-check. */
+				/* Double check for more completed RX slots.
+				 * We need a full barrier to prevent the store
+				 * to atok->appl_need_kick to be reordered with
+				 * the load from ktoa->hwcur and ktoa->hwtail
+				 * (store-load barrier). */
+				atomic_thread_fence_seq_cst();
 				ptnet_sync_tail(ktoa, kring);
 				if (likely(head == ring->tail)) {
 					break;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f68ed1bb8..414229343 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2252,6 +2252,10 @@ static inline void
 ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
 			       uint32_t head)
 {
+    /* Issue a first store-store barrier to make sure writes to the
+     * netmap ring do not overcome updates on atok->cur and atok->head. */
+    nm_stst_barrier();
+
     /*
      * We need to write cur and head to the CSB but we cannot do it atomically.
      * There is no way we can prevent the host from reading the updated value
@@ -2266,11 +2270,11 @@ ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
      *
      * The following memory barrier scheme is used to make this happen:
      *
-     *          Guest              Host
+     *          Guest                Host
      *
-     *          STORE(cur)         LOAD(head)
-     *          mb() <-----------> mb()
-     *          STORE(head)        LOAD(cur)
+     *          STORE(cur)           LOAD(head)
+     *          wmb() <----------->  rmb()
+     *          STORE(head)          LOAD(cur)
      */
     atok->cur = cur;
     nm_stst_barrier();
@@ -2289,8 +2293,12 @@ ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
      * (see explanation in ptnetmap_host_write_kring_csb).
      */
     kring->nr_hwtail = ktoa->hwtail;
-    nm_stst_barrier();
+    nm_ldld_barrier();
     kring->nr_hwcur = ktoa->hwcur;
+
+    /* Make sure that loads from ktoa->hwtail and ktoa->hwcur are not delayed
+     * after the loads from the netmap ring. */
+    nm_ldld_barrier();
 }
 
 /* Helper function wrapping ptnetmap_guest_read_kring_csb(). */
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 60a1d22c7..a0d4fa0e4 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -769,6 +769,7 @@ struct nm_csb_ktoa {
 
 #ifdef __KERNEL__
 #define nm_stst_barrier smp_wmb
+#define nm_ldld_barrier smp_rmb
 #else  /* !__KERNEL__ */
 static inline void nm_stst_barrier(void)
 {
@@ -777,18 +778,30 @@ static inline void nm_stst_barrier(void)
 	 * which is fine for us. */
 	__atomic_thread_fence(__ATOMIC_RELEASE);
 }
+static inline void nm_ldld_barrier(void)
+{
+	/* A memory barrier with acquire semantic has the combined
+	 * effect of a load-load barrier and a store-load barrier,
+	 * which is fine for us. */
+	__atomic_thread_fence(__ATOMIC_ACQUIRE);
+}
 #endif /* !__KERNEL__ */
 
 #elif defined(__FreeBSD__)
 
 #ifdef _KERNEL
 #define nm_stst_barrier	atomic_thread_fence_rel
+#define nm_stst_barrier	atomic_thread_fence_acq
 #else  /* !_KERNEL */
 #include 
 static inline void nm_stst_barrier(void)
 {
 	atomic_thread_fence(memory_order_release);
 }
+static inline void nm_ldld_barrier(void)
+{
+	atomic_thread_fence(memory_order_acquire);
+}
 #endif /* !_KERNEL */
 
 #else  /* !__linux__ && !__FreeBSD__ */

From a465b6328d88895ba67354d68e5461a6268304c1 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 11:19:31 +0100
Subject: [PATCH 1549/2207] introduce nm_stld_barrier(), to implement
 store-load inter-CPU barrier

---
 LINUX/netmap_ptnet.c      | 4 ++--
 sys/dev/netmap/if_ptnet.c | 4 ++--
 sys/net/netmap.h          | 2 ++
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index fa59c035e..3641882d7 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -330,7 +330,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 		/* Double check. We need a full barrier to prevent the store
 		 * to atok->appl_need_kick to be reordered with the load from
 		 * ktoa->hwcur and ktoa->hwtail (store-load barrier). */
-		smp_mb();
+		nm_stld_barrier();
 		ptnet_sync_tail(ktoa, kring);
 		if (unlikely(ptnet_tx_slots(a.ring) >= pi->min_tx_slots)) {
 			/* More TX space came in the meanwhile. */
@@ -702,7 +702,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		 * We need a full barrier to prevent the store to
 		 * atok->appl_need_kick to be reordered with the load from
 		 * ktoa->hwcur and ktoa->hwtail (store-load barrier). */
-		smp_mb();
+		nm_stld_barrier();
 		ptnet_sync_tail(ktoa, kring);
 		if (head != ring->tail) {
 			/* If there is more work to do, disable notifications
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index fadba6c55..67318969e 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1769,7 +1769,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 				 * to be reordered with the load from
 				 * ktoa->hwcur and ktoa->hwtail (store-load
 				 * barrier). */
-				atomic_thread_fence_seq_cst();
+				nm_stld_barrier();
 				ptnet_sync_tail(ktoa, kring);
 				if (likely(PTNET_TX_NOSPACE(head, kring,
 							    minspace))) {
@@ -2056,7 +2056,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 				 * to atok->appl_need_kick to be reordered with
 				 * the load from ktoa->hwcur and ktoa->hwtail
 				 * (store-load barrier). */
-				atomic_thread_fence_seq_cst();
+				nm_stld_barrier();
 				ptnet_sync_tail(ktoa, kring);
 				if (likely(head == ring->tail)) {
 					break;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index a0d4fa0e4..4aaa84d24 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -770,6 +770,7 @@ struct nm_csb_ktoa {
 #ifdef __KERNEL__
 #define nm_stst_barrier smp_wmb
 #define nm_ldld_barrier smp_rmb
+#define nm_stld_barrier smp_mb
 #else  /* !__KERNEL__ */
 static inline void nm_stst_barrier(void)
 {
@@ -792,6 +793,7 @@ static inline void nm_ldld_barrier(void)
 #ifdef _KERNEL
 #define nm_stst_barrier	atomic_thread_fence_rel
 #define nm_stst_barrier	atomic_thread_fence_acq
+#define nm_stld_barrier atomic_thread_fence_seq_cst
 #else  /* !_KERNEL */
 #include 
 static inline void nm_stst_barrier(void)

From 5f883024a94eafaefd56ceaf7c5b2ea733915446 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 11:39:51 +0100
Subject: [PATCH 1550/2207] ptnetmap, csb: remove ptnetmap_guest_*_kring_csb()

These functions have been obsoleted by nm_sync_kloop_appl_*
---
 LINUX/netmap_ptnet.c          |  6 ++--
 sys/dev/netmap/if_ptnet.c     |  2 +-
 sys/dev/netmap/netmap_kern.h  | 59 ++---------------------------------
 sys/dev/netmap/netmap_kloop.c | 16 +++++-----
 sys/net/netmap.h              | 18 ++++++++---
 5 files changed, 27 insertions(+), 74 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 3641882d7..53391378d 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -311,8 +311,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	if (!XMIT_MORE(skb)) {
 		/* Tell the host to process the new packets, updating cur and
 		 * head in the CSB. */
-		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
-					       kring->rhead);
+		nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
 	}
 
 	/* Ask for a kick from a guest to the host if needed. */
@@ -724,8 +723,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 		ring->head = ring->cur = head;
 		kring->rcur = ring->cur;
 		kring->rhead = ring->head;
-		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
-					       kring->rhead);
+		nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
 		/* Kick the host if needed. */
 		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
 			atok->sync_flags = NAF_FORCE_READ;
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 67318969e..203316f68 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1688,7 +1688,7 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 	/* Mimic nm_txsync_prologue/nm_rxsync_prologue. */
 	kring->rcur = kring->rhead = head;
 
-	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
+	ptnetmap_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
 
 	/* Kick the host if needed. */
 	if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 414229343..8c20d479c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2246,69 +2246,14 @@ int ptnet_nm_krings_create(struct netmap_adapter *na);
 void ptnet_nm_krings_delete(struct netmap_adapter *na);
 void ptnet_nm_dtor(struct netmap_adapter *na);
 
-/* Guest driver: Write kring pointers (cur, head) to the CSB.
- * This routine is coupled with ptnetmap_host_read_kring_csb(). */
-static inline void
-ptnetmap_guest_write_kring_csb(struct nm_csb_atok *atok, uint32_t cur,
-			       uint32_t head)
-{
-    /* Issue a first store-store barrier to make sure writes to the
-     * netmap ring do not overcome updates on atok->cur and atok->head. */
-    nm_stst_barrier();
-
-    /*
-     * We need to write cur and head to the CSB but we cannot do it atomically.
-     * There is no way we can prevent the host from reading the updated value
-     * of one of the two and the old value of the other. However, if we make
-     * sure that the host never reads a value of head more recent than the
-     * value of cur we are safe. We can allow the host to read a value of cur
-     * more recent than the value of head, since in the netmap ring cur can be
-     * ahead of head and cur cannot wrap around head because it must be behind
-     * tail. Inverting the order of writes below could instead result into the
-     * host to think head went ahead of cur, which would cause the sync
-     * prologue to fail.
-     *
-     * The following memory barrier scheme is used to make this happen:
-     *
-     *          Guest                Host
-     *
-     *          STORE(cur)           LOAD(head)
-     *          wmb() <----------->  rmb()
-     *          STORE(head)          LOAD(cur)
-     */
-    atok->cur = cur;
-    nm_stst_barrier();
-    atok->head = head;
-}
-
-/* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB.
- * This routine is coupled with ptnetmap_host_write_kring_csb(). */
-static inline void
-ptnetmap_guest_read_kring_csb(struct nm_csb_ktoa *ktoa,
-                              struct netmap_kring *kring)
-{
-    /*
-     * We place a memory barrier to make sure that the update of hwtail never
-     * overtakes the update of hwcur.
-     * (see explanation in ptnetmap_host_write_kring_csb).
-     */
-    kring->nr_hwtail = ktoa->hwtail;
-    nm_ldld_barrier();
-    kring->nr_hwcur = ktoa->hwcur;
-
-    /* Make sure that loads from ktoa->hwtail and ktoa->hwcur are not delayed
-     * after the loads from the netmap ring. */
-    nm_ldld_barrier();
-}
-
-/* Helper function wrapping ptnetmap_guest_read_kring_csb(). */
+/* Helper function wrapping nm_sync_kloop_appl_read(). */
 static inline void
 ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
 {
 	struct netmap_ring *ring = kring->ring;
 
 	/* Update hwcur and hwtail as known by the host. */
-        ptnetmap_guest_read_kring_csb(ktoa, kring);
+        nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail, &kring->nr_hwcur);
 
 	/* nm_sync_finalize */
 	ring->tail = kring->rtail = kring->nr_hwtail;
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index b46183c84..7d0db03ba 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -749,7 +749,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * packets.
 	 */
 	kring->nr_hwcur = ktoa->hwcur;
-	ptnetmap_guest_write_kring_csb(atok, kring->rcur, kring->rhead);
+	nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
 
         /* Ask for a kick from a guest to the host if needed. */
 	if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
@@ -763,7 +763,8 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
-                ptnetmap_guest_read_kring_csb(ktoa, kring);
+                nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
+					&kring->nr_hwcur);
 	}
 
         /*
@@ -775,7 +776,8 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 		/* Reenable notifications. */
 		atok->appl_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(ktoa, kring);
+                nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
+					&kring->nr_hwcur);
                 /* If there is new free space, disable notifications */
 		if (unlikely(!nm_kr_txempty(kring))) {
 			atok->appl_need_kick = 0;
@@ -814,7 +816,7 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * hwtail to the hwtail known from the host (read from the CSB).
 	 * This also updates the kring hwcur.
 	 */
-        ptnetmap_guest_read_kring_csb(ktoa, kring);
+	nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail, &kring->nr_hwcur);
 	kring->nr_kflags &= ~NKR_PENDINTR;
 
 	/*
@@ -822,8 +824,7 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * released, by updating cur and head in the CSB.
 	 */
 	if (kring->rhead != kring->nr_hwcur) {
-		ptnetmap_guest_write_kring_csb(atok, kring->rcur,
-					       kring->rhead);
+		nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
                 /* Ask for a kick from the guest to the host if needed. */
 		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
 			atok->sync_flags = flags;
@@ -840,7 +841,8 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 		/* Reenable notifications. */
                 atok->appl_need_kick = 1;
                 /* Double check */
-                ptnetmap_guest_read_kring_csb(ktoa, kring);
+		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
+					&kring->nr_hwcur);
                 /* If there are new slots, disable notifications. */
 		if (!nm_kr_rxempty(kring)) {
                         atok->appl_need_kick = 0;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 4aaa84d24..3b24f1fe3 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -816,6 +816,10 @@ static inline void
 nm_sync_kloop_appl_write(struct nm_csb_atok *atok, uint32_t cur,
 			 uint32_t head)
 {
+	/* Issue a first store-store barrier to make sure writes to the
+	 * netmap ring do not overcome updates on atok->cur and atok->head. */
+	nm_stst_barrier();
+
 	/*
 	 * We need to write cur and head to the CSB but we cannot do it atomically.
 	 * There is no way we can prevent the host from reading the updated value
@@ -830,11 +834,11 @@ nm_sync_kloop_appl_write(struct nm_csb_atok *atok, uint32_t cur,
 	 *
 	 * The following memory barrier scheme is used to make this happen:
 	 *
-	 *          Guest              Host
+	 *          Guest                Host
 	 *
-	 *          STORE(cur)         LOAD(head)
-	 *          mb() <-----------> mb()
-	 *          STORE(head)        LOAD(cur)
+	 *          STORE(cur)           LOAD(head)
+	 *          wmb() <----------->  rmb()
+	 *          STORE(head)          LOAD(cur)
 	 *
 	 */
 	atok->cur = cur;
@@ -854,8 +858,12 @@ nm_sync_kloop_appl_read(struct nm_csb_ktoa *ktoa, uint32_t *hwtail,
 	 * (see explanation in sync_kloop_kernel_write).
 	 */
 	*hwtail = ktoa->hwtail;
-	nm_stst_barrier();
+	nm_ldld_barrier();
 	*hwcur = ktoa->hwcur;
+
+	/* Make sure that loads from ktoa->hwtail and ktoa->hwcur are not delayed
+	 * after the loads from the netmap ring. */
+	nm_ldld_barrier();
 }
 
 /*

From 3c44b38463bb6a02ee79ff58d3f557c6dbc23c68 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 11:59:40 +0100
Subject: [PATCH 1551/2207] sync-kloop: add proper memory barriers

---
 sys/dev/netmap/netmap_kloop.c | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 7d0db03ba..e2afbaaec 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -66,8 +66,12 @@ static inline void
 sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 			   uint32_t hwtail)
 {
+	/* Issue a first store-store barrier to make sure writes to the
+	 * netmap ring do not overcome updates on ktoa->hwcur and ktoa->hwtail. */
+	nm_stst_barrier();
+
 	/*
-	 * The same scheme used in ptnetmap_guest_write_kring_csb() applies here.
+	 * The same scheme used in nm_sync_kloop_appl_write() applies here.
 	 * We allow the application to read a value of hwcur more recent than the value
 	 * of hwtail, since this would anyway result in a consistent view of the
 	 * ring state (and hwcur can never wraparound hwtail, since hwcur must be
@@ -75,11 +79,11 @@ sync_kloop_kernel_write(struct nm_csb_ktoa __user *ptr, uint32_t hwcur,
 	 *
 	 * The following memory barrier scheme is used to make this happen:
 	 *
-	 *          Application          Kernel
+	 *          Application            Kernel
 	 *
-	 *          STORE(hwcur)         LOAD(hwtail)
-	 *          mb() <-------------> mb()
-	 *          STORE(hwtail)        LOAD(hwcur)
+	 *          STORE(hwcur)           LOAD(hwtail)
+	 *          wmb() <------------->  rmb()
+	 *          STORE(hwtail)          LOAD(hwcur)
 	 */
 	CSB_WRITE(ptr, hwcur, hwcur);
 	nm_stst_barrier();
@@ -96,12 +100,16 @@ sync_kloop_kernel_read(struct nm_csb_atok __user *ptr,
 	/*
 	 * We place a memory barrier to make sure that the update of head never
 	 * overtakes the update of cur.
-	 * (see explanation in ptnetmap_guest_write_kring_csb).
+	 * (see explanation in sync_kloop_kernel_write).
 	 */
 	CSB_READ(ptr, head, shadow_ring->head);
-	nm_stst_barrier();
+	nm_ldld_barrier();
 	CSB_READ(ptr, cur, shadow_ring->cur);
 	CSB_READ(ptr, sync_flags, shadow_ring->flags);
+
+	/* Make sure that loads from atok->head and atok->cur are not delayed
+	 * after the loads from the netmap ring. */
+	nm_ldld_barrier();
 }
 
 /* Enable or disable application --> kernel kicks. */
@@ -240,7 +248,8 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 			 */
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
-			/* Doublecheck. */
+			/* Double check, with store-load memory barrier. */
+			nm_stld_barrier();
 			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 			if (shadow_ring.head != kring->rhead) {
 				/* We won the race condition, there are more packets to
@@ -358,7 +367,8 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 			 */
 			/* Reenable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
-			/* Doublecheck. */
+			/* Double check, with store-load memory barrier. */
+			nm_stld_barrier();
 			sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 			if (!sync_kloop_norxslots(kring, shadow_ring.head)) {
 				/* We won the race condition, more slots are available. Disable
@@ -775,7 +785,8 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
 		atok->appl_need_kick = 1;
-                /* Double check */
+                /* Double check, with store-load memory barrier. */
+		nm_stld_barrier();
                 nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
                 /* If there is new free space, disable notifications */
@@ -840,7 +851,8 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
                 atok->appl_need_kick = 1;
-                /* Double check */
+                /* Double check, with store-load memory barrier. */
+		nm_stld_barrier();
 		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
                 /* If there are new slots, disable notifications. */

From 0159b1db5d00fdb5de8995370c325d2bfecfbf30 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 12:12:14 +0100
Subject: [PATCH 1552/2207] netmap.h, kloop: fix typos

---
 sys/dev/netmap/netmap_kloop.c | 4 ++--
 sys/net/netmap.h              | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index e2afbaaec..5a6243e16 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -773,7 +773,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
 	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
-                nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
+		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
 	}
 
@@ -787,7 +787,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 		atok->appl_need_kick = 1;
                 /* Double check, with store-load memory barrier. */
 		nm_stld_barrier();
-                nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
+		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
                 /* If there is new free space, disable notifications */
 		if (unlikely(!nm_kr_txempty(kring))) {
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 3b24f1fe3..707fc7c9d 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -792,8 +792,8 @@ static inline void nm_ldld_barrier(void)
 
 #ifdef _KERNEL
 #define nm_stst_barrier	atomic_thread_fence_rel
-#define nm_stst_barrier	atomic_thread_fence_acq
-#define nm_stld_barrier atomic_thread_fence_seq_cst
+#define nm_ldld_barrier	atomic_thread_fence_acq
+#define nm_stld_barrier	atomic_thread_fence_seq_cst
 #else  /* !_KERNEL */
 #include 
 static inline void nm_stst_barrier(void)

From 4161ace8809661c4ffd9d64a0bae344ce056ab00 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 12:50:57 +0100
Subject: [PATCH 1553/2207] if_ptnet: remove usage of
 ptnetmap_sync_kloop_appl_write()

---
 sys/dev/netmap/if_ptnet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 203316f68..02f91ee3d 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1688,7 +1688,7 @@ ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 	/* Mimic nm_txsync_prologue/nm_rxsync_prologue. */
 	kring->rcur = kring->rhead = head;
 
-	ptnetmap_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
+	nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
 
 	/* Kick the host if needed. */
 	if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {

From dd803f7822f019fe587feae97b32287dd92a6667 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 23 Jan 2019 13:00:56 +0100
Subject: [PATCH 1554/2207] freebsd: fix knote() argument to match the mutex
 state

The nm_os_selwakeup function needs to call knote() to wake up kqueue(9) users.
However, this function can be called from different code paths, with different lock requirements.
This patch fixes the knote() call argument to match the relavant lock state.

Reported-by: Aleksandr Fedorov 
---
 sys/dev/netmap/netmap.c         |  5 +-
 sys/dev/netmap/netmap_freebsd.c | 85 +++++++++++++++------------------
 sys/dev/netmap/netmap_kern.h    |  1 -
 3 files changed, 41 insertions(+), 50 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2d3db72f5..8b508737e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2531,7 +2531,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 				nifp = priv->np_nifp;
-				priv->np_td = td; /* for debugging purposes */
 
 				/* return the offset of the netmap_if object */
 				req->nr_rx_rings = na->num_rx_rings;
@@ -3207,8 +3206,8 @@ nmreq_checkoptions(struct nmreq_header *hdr)
  *
  * Can be called for one or more queues.
  * Return true the event mask corresponding to ready events.
- * If there are no ready events, do a selrecord on either individual
- * selinfo or on the global one.
+ * If there are no ready events (and 'sr' is not NULL), do a
+ * selrecord on either individual selinfo or on the global one.
  * Device-dependent parts (locking and sync of tx/rx rings)
  * are done through callbacks.
  *
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 70d2ee443..c21aed65a 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -85,7 +85,7 @@ void
 nm_os_selinfo_uninit(NM_SELINFO_T *si)
 {
 	/* XXX kqueue(9) needed; these will mirror knlist_init. */
-	knlist_delete(&si->si.si_note, curthread, 0 /* not locked */ );
+	knlist_delete(&si->si.si_note, curthread, /*islocked=*/0);
 	knlist_destroy(&si->si.si_note);
 	/* now we don't need the mutex anymore */
 	mtx_destroy(&si->m);
@@ -1294,21 +1294,21 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 /******************** kqueue support ****************/
 
 /*
- * nm_os_selwakeup also needs to issue a KNOTE_UNLOCKED.
- * We use a non-zero argument to distinguish the call from the one
- * in kevent_scan() which instead also needs to run netmap_poll().
- * The knote uses a global mutex for the time being. We might
- * try to reuse the one in the si, but it is not allocated
- * permanently so it might be a bit tricky.
+ * In addition to calling selwakeuppri(), nm_os_selwakeup() also
+ * needs to call KNOTE to wake up kqueue listeners.
+ * We use a non-zero 'hint' argument to inform the netmap_knrw()
+ * function that it is being called from 'nm_os_selwakeup'; this
+ * is necessary because when netmap_knrw() is called by the kevent
+ * subsystem (i.e. kevent_scan()) we also need to call netmap_poll().
+ * The knote uses a private mutex associated to the 'si' (see struct
+ * selinfo, struct nm_selinfo, and nm_os_selinfo_init).
  *
- * The *kqfilter function registers one or another f_event
- * depending on read or write mode.
- * In the call to f_event() td_fpop is NULL so any child function
- * calling devfs_get_cdevpriv() would fail - and we need it in
- * netmap_poll(). As a workaround we store priv into kn->kn_hook
- * and pass it as first argument to netmap_poll(), which then
- * uses the failure to tell that we are called from f_event()
- * and do not need the selrecord().
+ * The netmap_kqfilter() function registers one or another f_event
+ * depending on read or write mode. A pointer to the struct
+ * 'netmap_priv_d' is stored into kn->kn_hook, so that it can later
+ * be passed to netmap_poll(). We pass NULL as a third argument to
+ * netmap_poll(), so that the latter only runs the txsync/rxsync
+ * (if necessary), and skips the nm_os_selrecord() calls.
  */
 
 
@@ -1316,12 +1316,13 @@ void
 nm_os_selwakeup(struct nm_selinfo *si)
 {
 	if (netmap_verbose)
-		D("on knote %p", &si->si.si_note);
+		nm_prinf("on knote %p", &si->si.si_note);
 	selwakeuppri(&si->si, PI_NET);
-	/* use a non-zero hint to tell the notification from the
-	 * call done in kqueue_scan() which uses 0
+	/* We use a non-zero hint to distinguish this notification call
+	 * from the call done in kqueue_scan(), which uses hint=0.
 	 */
-	KNOTE_UNLOCKED(&si->si.si_note, 0x100 /* notification */);
+	KNOTE(&si->si.si_note, /*hint=*/0x100,
+	    mtx_owned(&si->m) ? KNF_LISTLOCKED : 0);
 }
 
 void
@@ -1337,7 +1338,7 @@ netmap_knrdetach(struct knote *kn)
 	struct selinfo *si = &priv->np_si[NR_RX]->si;
 
 	D("remove selinfo %p", si);
-	knlist_remove(&si->si_note, kn, 0);
+	knlist_remove(&si->si_note, kn, /*islocked=*/0);
 }
 
 static void
@@ -1347,14 +1348,15 @@ netmap_knwdetach(struct knote *kn)
 	struct selinfo *si = &priv->np_si[NR_TX]->si;
 
 	D("remove selinfo %p", si);
-	knlist_remove(&si->si_note, kn, 0);
+	knlist_remove(&si->si_note, kn, /*islocked=*/0);
 }
 
 /*
- * callback from notifies (generated externally) and our
- * calls to kevent(). The former we just return 1 (ready)
- * since we do not know better.
- * In the latter we call netmap_poll and return 0/1 accordingly.
+ * Callback triggered by netmap notifications (see netmap_notify()),
+ * and by the application calling kevent(). In the former case we
+ * just return 1 (events ready), since we are not able to do better.
+ * In the latter case we use netmap_poll() to see which events are
+ * ready.
  */
 static int
 netmap_knrw(struct knote *kn, long hint, int events)
@@ -1363,21 +1365,17 @@ netmap_knrw(struct knote *kn, long hint, int events)
 	int revents;
 
 	if (hint != 0) {
-		ND(5, "call from notify");
-		return 1; /* assume we are ready */
-	}
-	priv = kn->kn_hook;
-	/* the notification may come from an external thread,
-	 * in which case we do not want to run the netmap_poll
-	 * This should be filtered above, but check just in case.
-	 */
-	if (curthread != priv->np_td) { /* should not happen */
-		RD(5, "curthread changed %p %p", curthread, priv->np_td);
+		/* Called from netmap_notify(), typically from a
+		 * thread different from the one issuing kevent().
+		 * Assume we are ready. */
 		return 1;
-	} else {
-		revents = netmap_poll(priv, events, NULL);
-		return (events & revents) ? 1 : 0;
 	}
+
+	/* Called from kevent(). */
+	priv = kn->kn_hook;
+	revents = netmap_poll(priv, events, /*thread=*/NULL);
+
+	return (events & revents) ? 1 : 0;
 }
 
 static int
@@ -1408,7 +1406,7 @@ static struct filterops netmap_wfiltops = {
 /*
  * This is called when a thread invokes kevent() to record
  * a change in the configuration of the kqueue().
- * The 'priv' should be the same as in the netmap device.
+ * The 'priv' is the one associated to the open netmap device.
  */
 static int
 netmap_kqfilter(struct cdev *dev, struct knote *kn)
@@ -1435,16 +1433,11 @@ netmap_kqfilter(struct cdev *dev, struct knote *kn)
 	}
 	/* the si is indicated in the priv */
 	si = priv->np_si[(ev == EVFILT_WRITE) ? NR_TX : NR_RX];
-	// XXX lock(priv) ?
 	kn->kn_fop = (ev == EVFILT_WRITE) ?
 		&netmap_wfiltops : &netmap_rfiltops;
 	kn->kn_hook = priv;
-	knlist_add(&si->si.si_note, kn, 0);
-	// XXX unlock(priv)
-	ND("register %p %s td %p priv %p kn %p np_nifp %p kn_fp/fpop %s",
-		na, na->ifp->if_xname, curthread, priv, kn,
-		priv->np_nifp,
-		kn->kn_fp == curthread->td_fpop ? "match" : "MISMATCH");
+	knlist_add(&si->si.si_note, kn, /*islocked=*/0);
+
 	return 0;
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8c20d479c..68b1fd762 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1946,7 +1946,6 @@ struct netmap_priv_d {
 	 * (N entries). */
 	struct nm_csb_ktoa	*np_csb_ktoa_base;
 
-	struct thread	*np_td;		/* kqueue, just debugging */
 #ifdef linux
 	struct file	*np_filp;  /* used by sync kloop */
 #endif /* linux */

From 51c9fa4ccca2a77313bbc082938ef316901ad9db Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 24 Jan 2019 11:25:40 +0100
Subject: [PATCH 1555/2207] netmap_freebsd: replace D(), RD() and ND() with
 nm_pr*()

---
 sys/dev/netmap/netmap_freebsd.c | 83 ++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 43 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index c21aed65a..ad26d2b46 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -240,7 +240,7 @@ nm_os_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data,
 	static int notsupported = 0;
 	if (!notsupported) {
 		notsupported = 1;
-		D("inet4 segmentation not supported");
+		nm_prerr("inet4 segmentation not supported");
 	}
 #endif
 }
@@ -256,7 +256,7 @@ nm_os_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data,
 	static int notsupported = 0;
 	if (!notsupported) {
 		notsupported = 1;
-		D("inet6 segmentation not supported");
+		nm_prerr("inet6 segmentation not supported");
 	}
 #endif
 }
@@ -288,8 +288,9 @@ freebsd_generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
 {
 	int stolen;
 
-	if (!NM_NA_VALID(ifp)) {
-		RD(1, "Warning: got RX packet for invalid emulated adapter");
+	if (unlikely(!NM_NA_VALID(ifp))) {
+		nm_prlim(1, "Warning: RX packet intercepted, but no"
+				" emulated adapter");
 		return;
 	}
 
@@ -315,15 +316,16 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 	nm_os_ifnet_lock();
 	if (intercept) {
 		if (gna->save_if_input) {
-			D("cannot intercept again");
-			ret = EINVAL; /* already set */
+			nm_prerr("RX on %s already intercepted", na->name);
+			ret = EBUSY; /* already set */
 			goto out;
 		}
 		gna->save_if_input = ifp->if_input;
 		ifp->if_input = freebsd_generic_rx_handler;
 	} else {
-		if (!gna->save_if_input){
-			D("cannot restore");
+		if (!gna->save_if_input) {
+			nm_prerr("Failed to undo RX intercept on %s",
+				na->name);
 			ret = EINVAL;  /* not saved */
 			goto out;
 		}
@@ -392,11 +394,11 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	 * we need to copy from the cluster to the netmap buffer.
 	 */
 	if (MBUF_REFCNT(m) != 1) {
-		D("invalid refcnt %d for %p", MBUF_REFCNT(m), m);
+		nm_prerr("invalid refcnt %d for %p", MBUF_REFCNT(m), m);
 		panic("in generic_xmit_frame");
 	}
 	if (m->m_ext.ext_size < len) {
-		RD(5, "size %d < len %d", m->m_ext.ext_size, len);
+		nm_prlim(2, "size %d < len %d", m->m_ext.ext_size, len);
 		len = m->m_ext.ext_size;
 	}
 	bcopy(a->addr, m->m_data, len);
@@ -459,7 +461,6 @@ nm_os_generic_set_features(struct netmap_generic_adapter *gna)
 void
 nm_os_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na)
 {
-	ND("called");
 	mit->mit_pending = 0;
 	mit->mit_ring_idx = idx;
 	mit->mit_na = na;
@@ -469,21 +470,19 @@ nm_os_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter
 void
 nm_os_mitigation_start(struct nm_generic_mit *mit)
 {
-	ND("called");
 }
 
 
 void
 nm_os_mitigation_restart(struct nm_generic_mit *mit)
 {
-	ND("called");
 }
 
 
 int
 nm_os_mitigation_active(struct nm_generic_mit *mit)
 {
-	ND("called");
+
 	return 0;
 }
 
@@ -491,12 +490,12 @@ nm_os_mitigation_active(struct nm_generic_mit *mit)
 void
 nm_os_mitigation_cleanup(struct nm_generic_mit *mit)
 {
-	ND("called");
 }
 
 static int
 nm_vi_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr)
 {
+
 	return EINVAL;
 }
 
@@ -559,7 +558,7 @@ nm_vi_free_index(uint8_t val)
 		}
 	}
 	if (lim == nm_vi_indices.active)
-		D("funny, index %u didn't found", val);
+		nm_prerr("Index %u not found", val);
 	mtx_unlock(&nm_vi_indices.lock);
 }
 #undef NM_VI_MAX
@@ -597,7 +596,7 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 
 	ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL) {
-		D("if_alloc failed");
+		nm_prerr("if_alloc failed");
 		return ENOMEM;
 	}
 	if_initname(ifp, name, IF_DUNIT_NONE);
@@ -638,7 +637,7 @@ struct nm_os_extmem {
 void
 nm_os_extmem_delete(struct nm_os_extmem *e)
 {
-	D("freeing %zx bytes", (size_t)e->size);
+	nm_prinf("freeing %zx bytes", (size_t)e->size);
 	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
 	nm_os_free(e);
 }
@@ -688,7 +687,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 	rv = vm_map_lookup(&map, p, VM_PROT_RW, &entry,
 			&obj, &index, &prot, &wired);
 	if (rv != KERN_SUCCESS) {
-		D("address %lx not found", p);
+		nm_prerr("address %lx not found", p);
 		goto out_free;
 	}
 	/* check that we are given the whole vm_object ? */
@@ -707,13 +706,13 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
 			VM_PROT_READ | VM_PROT_WRITE, 0);
 	if (rv != KERN_SUCCESS) {
-		D("vm_map_find(%zx) failed", (size_t)e->size);
+		nm_prerr("vm_map_find(%zx) failed", (size_t)e->size);
 		goto out_rel;
 	}
 	rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,
 			VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
 	if (rv != KERN_SUCCESS) {
-		D("vm_map_wire failed");
+		nm_prerr("vm_map_wire failed");
 		goto out_rem;
 	}
 
@@ -795,7 +794,7 @@ nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr,
 {
 	int rid;
 
-	D("ptn_memdev_driver iomap");
+	nm_prinf("ptn_memdev_driver iomap");
 
 	rid = PCIR_BAR(PTNETMAP_MEM_PCI_BAR);
 	*mem_size = bus_read_4(ptn_dev->pci_io, PTNET_MDEV_IO_MEMSIZE_HI);
@@ -814,7 +813,7 @@ nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr,
 	*nm_paddr = rman_get_start(ptn_dev->pci_mem);
 	*nm_addr = rman_get_virtual(ptn_dev->pci_mem);
 
-	D("=== BAR %d start %lx len %lx mem_size %lx ===",
+	nm_prinf("=== BAR %d start %lx len %lx mem_size %lx ===",
 			PTNETMAP_MEM_PCI_BAR,
 			(unsigned long)(*nm_paddr),
 			(unsigned long)rman_get_size(ptn_dev->pci_mem),
@@ -832,7 +831,7 @@ nm_os_pt_memdev_ioread(struct ptnetmap_memdev *ptn_dev, unsigned int reg)
 void
 nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *ptn_dev)
 {
-	D("ptn_memdev_driver iounmap");
+	nm_prinf("ptn_memdev_driver iounmap");
 
 	if (ptn_dev->pci_mem) {
 		bus_release_resource(ptn_dev->dev, SYS_RES_MEMORY,
@@ -868,8 +867,6 @@ ptn_memdev_attach(device_t dev)
 	int rid;
 	uint16_t mem_id;
 
-	D("ptn_memdev_driver attach");
-
 	ptn_dev = device_get_softc(dev);
 	ptn_dev->dev = dev;
 
@@ -893,7 +890,7 @@ ptn_memdev_attach(device_t dev)
 	}
 	netmap_mem_get(ptn_dev->nm_mem);
 
-	D("ptn_memdev_driver probe OK - host_mem_id: %d", mem_id);
+	nm_prinf("ptnetmap memdev attached, host memid: %u", mem_id);
 
 	return (0);
 }
@@ -904,10 +901,11 @@ ptn_memdev_detach(device_t dev)
 {
 	struct ptnetmap_memdev *ptn_dev;
 
-	D("ptn_memdev_driver detach");
 	ptn_dev = device_get_softc(dev);
 
 	if (ptn_dev->nm_mem) {
+		nm_prinf("ptnetmap memdev detached, host memid %u",
+			netmap_mem_get_id(ptn_dev->nm_mem));
 		netmap_mem_put(ptn_dev->nm_mem);
 		ptn_dev->nm_mem = NULL;
 	}
@@ -928,7 +926,6 @@ ptn_memdev_detach(device_t dev)
 static int
 ptn_memdev_shutdown(device_t dev)
 {
-	D("ptn_memdev_driver shutdown");
 	return bus_generic_shutdown(dev);
 }
 
@@ -953,7 +950,7 @@ netmap_dev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
 	struct netmap_vm_handle_t *vmh = handle;
 
 	if (netmap_verbose)
-		D("handle %p size %jd prot %d foff %jd",
+		nm_prinf("handle %p size %jd prot %d foff %jd",
 			handle, (intmax_t)size, prot, (intmax_t)foff);
 	if (color)
 		*color = 0;
@@ -970,7 +967,7 @@ netmap_dev_pager_dtor(void *handle)
 	struct netmap_priv_d *priv = vmh->priv;
 
 	if (netmap_verbose)
-		D("handle %p", handle);
+		nm_prinf("handle %p", handle);
 	netmap_dtor(priv);
 	free(vmh, M_DEVBUF);
 	dev_rel(dev);
@@ -989,7 +986,7 @@ netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
 	vm_memattr_t memattr;
 	vm_pindex_t pidx;
 
-	ND("object %p offset %jd prot %d mres %p",
+	nm_prdis("object %p offset %jd prot %d mres %p",
 			object, (intmax_t)offset, prot, mres);
 	memattr = object->memattr;
 	pidx = OFF_TO_IDX(offset);
@@ -1045,7 +1042,7 @@ netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff,
 	vm_object_t obj;
 
 	if (netmap_verbose)
-		D("cdev %p foff %jd size %jd objp %p prot %d", cdev,
+		nm_prinf("cdev %p foff %jd size %jd objp %p prot %d", cdev,
 		    (intmax_t )*foff, (intmax_t )objsize, objp, prot);
 
 	vmh = malloc(sizeof(struct netmap_vm_handle_t), M_DEVBUF,
@@ -1070,7 +1067,7 @@ netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff,
 		&netmap_cdev_pager_ops, objsize, prot,
 		*foff, NULL);
 	if (obj == NULL) {
-		D("cdev_pager_allocate failed");
+		nm_prerr("cdev_pager_allocate failed");
 		error = EINVAL;
 		goto err_deref;
 	}
@@ -1104,7 +1101,7 @@ static int
 netmap_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
 {
 	if (netmap_verbose)
-		D("dev %p fflag 0x%x devtype %d td %p",
+		nm_prinf("dev %p fflag 0x%x devtype %d td %p",
 			dev, fflag, devtype, td);
 	return 0;
 }
@@ -1255,11 +1252,11 @@ nm_os_kctx_worker_start(struct nm_kctx *nmk)
 		goto err;
 	}
 
-	D("nm_kthread started td %p", nmk->worker);
+	nm_prinf("nm_kthread started td %p", nmk->worker);
 
 	return 0;
 err:
-	D("nm_kthread start failed err %d", error);
+	nm_prerr("nm_kthread start failed err %d", error);
 	nmk->worker = NULL;
 	return error;
 }
@@ -1337,7 +1334,7 @@ netmap_knrdetach(struct knote *kn)
 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
 	struct selinfo *si = &priv->np_si[NR_RX]->si;
 
-	D("remove selinfo %p", si);
+	nm_prinf("remove selinfo %p", si);
 	knlist_remove(&si->si_note, kn, /*islocked=*/0);
 }
 
@@ -1347,7 +1344,7 @@ netmap_knwdetach(struct knote *kn)
 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
 	struct selinfo *si = &priv->np_si[NR_TX]->si;
 
-	D("remove selinfo %p", si);
+	nm_prinf("remove selinfo %p", si);
 	knlist_remove(&si->si_note, kn, /*islocked=*/0);
 }
 
@@ -1418,17 +1415,17 @@ netmap_kqfilter(struct cdev *dev, struct knote *kn)
 	int ev = kn->kn_filter;
 
 	if (ev != EVFILT_READ && ev != EVFILT_WRITE) {
-		D("bad filter request %d", ev);
+		nm_prerr("bad filter request %d", ev);
 		return 1;
 	}
 	error = devfs_get_cdevpriv((void**)&priv);
 	if (error) {
-		D("device not yet setup");
+		nm_prerr("device not yet setup");
 		return 1;
 	}
 	na = priv->np_na;
 	if (na == NULL) {
-		D("no netmap adapter for this file descriptor");
+		nm_prerr("no netmap adapter for this file descriptor");
 		return 1;
 	}
 	/* the si is indicated in the priv */
@@ -1535,7 +1532,7 @@ netmap_loader(__unused struct module *module, int event, __unused void *arg)
 		 * then the module can not be unloaded.
 		 */
 		if (netmap_use_count) {
-			D("netmap module can not be unloaded - netmap_use_count: %d",
+			nm_prerr("netmap module can not be unloaded - netmap_use_count: %d",
 					netmap_use_count);
 			error = EBUSY;
 			break;

From 8b188b77abcdcf9a42e1cd7027a3586b07db6822 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 22 Jan 2019 19:15:30 +0100
Subject: [PATCH 1556/2207] linux/ixgbe: patch for Intel 5.5.3 version

---
 LINUX/final-patches/intel--ixgbe--5.5.3 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.5.3

diff --git a/LINUX/final-patches/intel--ixgbe--5.5.3 b/LINUX/final-patches/intel--ixgbe--5.5.3
new file mode 100644
index 000000000..d915b0e24
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.5.3
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bf12f5..fa05036 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -28,24 +28,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index b39b93e..207dadb 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -694,6 +694,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -713,6 +730,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2192,6 +2220,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3624,6 +3662,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4245,6 +4287,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -12099,6 +12145,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12148,6 +12198,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 4cda4b7de7b92a3470ddd8903f1149c43af12f6e Mon Sep 17 00:00:00 2001
From: Corey Bonnell 
Date: Thu, 24 Jan 2019 11:45:26 -0500
Subject: [PATCH 1557/2207] New vmxnet3 RX/TX routines

---
 LINUX/if_vmxnet3_netmap_v2.h | 555 +++++++++++++++++++++++++++++++++++
 1 file changed, 555 insertions(+)
 create mode 100644 LINUX/if_vmxnet3_netmap_v2.h

diff --git a/LINUX/if_vmxnet3_netmap_v2.h b/LINUX/if_vmxnet3_netmap_v2.h
new file mode 100644
index 000000000..9601e59b1
--- /dev/null
+++ b/LINUX/if_vmxnet3_netmap_v2.h
@@ -0,0 +1,555 @@
+
+#ifndef _IF_VMXNET3_NETMAP_H_
+#define _IF_VMXNET3_NETMAP_H_
+
+#include 
+#include 
+#include 
+
+#define SOFTC_T vmxnet3_adapter
+
+static int vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter);
+
+static int
+vmxnet3_netmap_reg(struct netmap_adapter *na, int onoff)
+{
+	int err = 0;
+
+	struct ifnet *ifp       = na->ifp;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+
+	/* protect against other reinit */
+	while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+		usleep_range(1000, 2000);
+
+	if (netif_running(adapter->netdev)) {
+		vmxnet3_quiesce_dev(adapter);
+		vmxnet3_reset_dev(adapter);
+
+		vmxnet3_rq_destroy_all(adapter);
+	}
+
+	/* enable or disable flags and callbacks in na and ifp */
+	if (onoff) {
+		nm_set_native_flags(na);
+	} else {
+		nm_clear_native_flags(na);
+	}
+
+	err = vmxnet3_rq_create_all(adapter);
+	if (err)
+		goto out;
+
+	if (netif_running(adapter->netdev)) {
+		err = vmxnet3_activate_dev(adapter);
+		if (err)
+			goto out;
+	} else {
+		vmxnet3_reset_dev(adapter);
+	}
+
+out:
+	clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+
+	if (err) {
+		vmxnet3_force_close(adapter);
+	}
+
+	return 0;
+}
+
+static u_int
+vmxnet3_netmap_tq_tx_complete(struct vmxnet3_tx_queue *tq, struct pci_dev *pdev)
+{
+	u_int completed = 0;
+	union Vmxnet3_GenericDesc *gdesc;
+
+	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+
+	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
+		vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
+		vmxnet3_comp_ring_adv_next2proc(&tq->comp_ring);
+
+		gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+
+		completed++;
+	}
+
+	return completed;
+}
+
+static int
+vmxnet3_netmap_txsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp         = na->ifp;
+	struct netmap_ring *ring  = kring->ring;
+
+	u_int n;
+	u_int nm_i; // index into the netmap ring
+	u_int completed;
+	u_int transmitted = 0;
+	u_int ring_nr     = kring->ring_id;
+
+	u_int const lim  = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+
+	struct SOFTC_T *adapter     = netdev_priv(ifp);
+	struct vmxnet3_tx_queue *tq = &adapter->tx_queue[ring_nr];
+
+	if (!netif_carrier_ok(ifp))
+		return 0;
+
+	//
+	// Free up the comp_descriptors aggressively
+	//
+
+	completed = vmxnet3_netmap_tq_tx_complete(tq, adapter->pdev);
+
+	//
+	// Reclaim buffers for completed transmissions
+	//
+
+	kring->nr_hwtail =
+	        nm_prev(tq->comp_ring.next2proc, tq->comp_ring.size - 1);
+
+	//
+	// Process new packets to send
+	//
+
+	nm_i = kring->nr_hwcur;
+
+	if (nm_i != head) {
+		for (n = 0; nm_i != head; n++) {
+			int free_cmd_desc_count;
+			unsigned long lock_flags;
+
+			struct netmap_slot *slot = ring->slot + nm_i;
+			u_int packet_len         = slot->len;
+			struct vmxnet3_tx_buf_info *tbi;
+			union Vmxnet3_GenericDesc *gdesc;
+			uint64_t paddr;
+
+			PNMB(na, slot, &paddr);
+
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			netmap_sync_map_dev(na, (bus_dma_tag_t)na->pdev, &paddr,
+			                    packet_len, NR_TX);
+
+			spin_lock_irqsave(&tq->tx_lock, lock_flags);
+
+			tbi   = tq->buf_info + tq->tx_ring.next2fill;
+			gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
+
+			free_cmd_desc_count =
+			        vmxnet3_cmd_ring_desc_avail(&tq->tx_ring);
+
+			if (free_cmd_desc_count < 1) {
+				tq->stats.tx_ring_full++;
+				spin_unlock_irqrestore(&tq->tx_lock,
+				                       lock_flags);
+				break;
+			}
+
+			BUG_ON(packet_len > VMXNET3_MAX_TX_BUF_SIZE);
+			BUG_ON(gdesc->txd.addr != tbi->dma_addr);
+			BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
+
+			/*	comments in other driver implementations
+			 *indicate a size of 0 denotes a packet of
+			 *VMXNET3_MAX_TX_BUF_SIZE bytes */
+			tbi->len = packet_len == VMXNET3_MAX_TX_BUF_SIZE
+			                   ? 0
+			                   : packet_len;
+
+			gdesc->dword[3] =
+			        cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP);
+
+			dma_wmb();
+
+			// set the packet length and flip the GEN bit
+			gdesc->dword[2] = cpu_to_le32(
+			        tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT |
+			        packet_len);
+
+			vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
+
+			transmitted++;
+			spin_unlock_irqrestore(&tq->tx_lock, lock_flags);
+
+			//
+			// go to the next netmap slot
+			//
+			nm_i = nm_next(nm_i, lim);
+		}
+
+		kring->nr_hwcur = head;
+	}
+
+	//
+	// Notify vSwitch that packets are available.
+
+	if (transmitted >= tq->shared->txThreshold) {
+		tq->shared->txThreshold = 0;
+		VMXNET3_WRITE_BAR0_REG(
+		        adapter,
+		        (VMXNET3_REG_TXPROD + tq->qid * VMXNET3_REG_ALIGN),
+		        tq->tx_ring.next2fill);
+	}
+
+	return 0;
+}
+
+static int
+vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
+{
+	static const u32 rxprod_reg[] = {VMXNET3_REG_RXPROD,
+	                                 VMXNET3_REG_RXPROD2};
+
+	u_int num_pkts = 0;
+	u_int nm_i;
+	u_int n;
+
+	struct netmap_adapter *na  = kring->na;
+	struct ifnet *ifp          = na->ifp;
+	struct netmap_ring *nmring = kring->ring;
+
+	u_int ring_nr    = kring->ring_id;
+	u_int const lim  = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	int force_update =
+	        (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+
+	struct Vmxnet3_RxCompDesc *rcd;
+	struct SOFTC_T *adapter     = netdev_priv(ifp);
+	struct vmxnet3_rx_queue *rq = &adapter->rx_queue[ring_nr];
+
+	if (!netif_carrier_ok(ifp))
+		return 0;
+
+	if (head > lim)
+		return netmap_ring_reinit(kring);
+
+	//
+	// First part: import newly received packets.
+	//
+
+	if (netmap_no_pendintr || force_update) {
+		u_int hwtail_lim = nm_prev(kring->nr_hwcur, lim);
+		nm_i             = kring->nr_hwtail;
+
+		for (n = 0; nm_i != hwtail_lim; n++) {
+			struct netmap_slot *slot;
+			struct vmxnet3_cmd_ring *cmd_ring;
+			u_int rx_idx;
+			u_int ring_idx;
+			u_int num_to_alloc;
+			uint64_t paddr;
+
+			vmxnet3_getRxComp(
+			        rcd,
+			        &rq->comp_ring.base[rq->comp_ring.next2proc]
+			                 .rcd,
+			        &rxComp);
+
+			if (rcd->gen != rq->comp_ring.gen)
+				break;
+
+			dma_rmb();
+
+			slot = nmring->slot + nm_i;
+			PNMB(na, slot, &paddr);
+
+			// data ring has been disabled on device init
+			BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
+
+			/*	RX queues were configured to not fragment
+			 *packets, so we expect both the SOP and EOP flags to be
+			 *set in the RX completion desc
+			 */
+			BUG_ON(!(rcd->sop && rcd->eop));
+			BUG_ON(rcd->len > NETMAP_BUF_SIZE(na));
+
+			ring_idx = VMXNET3_GET_RING_IDX(adapter, rcd->rqID);
+			rx_idx   = rcd->rxdIdx;
+			cmd_ring = rq->rx_ring + ring_idx;
+
+			slot->len   = rcd->len;
+			slot->flags = 0;
+			netmap_sync_map_cpu(na, (bus_dma_tag_t)na->pdev, &paddr,
+			                    slot->len, NR_RX);
+			num_pkts++;
+
+			nm_i = nm_next(nm_i, lim);
+
+			/* XXX can this ever happen with all offloads disabled?
+			 */
+			if (rcd->err) {
+				rq->stats.drop_total++;
+				rq->stats.drop_err++;
+
+				if (!rcd->fcs)
+					rq->stats.drop_fcs++;
+			}
+
+			/* device may have skipped some rx descs */
+			cmd_ring->next2comp = rx_idx;
+			num_to_alloc = vmxnet3_cmd_ring_desc_avail(cmd_ring);
+
+			/* Ensure that the writes to rxd->gen bits will be
+			 * observed after all other writes to rxd objects.
+			 */
+			dma_wmb();
+
+			while (num_to_alloc) {
+				struct Vmxnet3_RxDesc *rxd;
+
+				vmxnet3_getRxDesc(
+				        rxd,
+				        &cmd_ring->base[cmd_ring->next2fill]
+				                 .rxd,
+				        &rxCmdDesc);
+				BUG_ON(!rxd->addr);
+
+				/* Recv desc is ready to be used by the device
+				 */
+				rxd->gen = cmd_ring->gen;
+				vmxnet3_cmd_ring_adv_next2fill(cmd_ring);
+				num_to_alloc--;
+			}
+
+			/* if needed, update the register */
+			if (unlikely(rq->shared->updateRxProd)) {
+				VMXNET3_WRITE_BAR0_REG(
+				        adapter,
+				        rxprod_reg[ring_idx] +
+				                rq->qid * VMXNET3_REG_ALIGN,
+				        cmd_ring->next2fill);
+			}
+
+			vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
+		}
+
+		if (num_pkts) {
+			kring->nr_hwtail = nm_i;
+		}
+
+		kring->nr_kflags &= ~NKR_PENDINTR;
+	}
+
+	//
+	// Second part: skip past packets that userspace has released.
+	//
+
+	nm_i = kring->nr_hwcur;
+
+	if (nm_i != head) {
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &nmring->slot[nm_i];
+			uint64_t paddr;
+			void *addr = PNMB(na, slot, &paddr);
+
+			if (addr == NETMAP_BUF_BASE(na)) // bad buf
+				goto ring_reset;
+
+			slot->flags &= ~NS_BUF_CHANGED;
+
+			netmap_sync_map_dev(na, (bus_dma_tag_t)na->pdev, &paddr,
+			                    NETMAP_BUF_SIZE(na), NR_RX);
+
+			nm_i = nm_next(nm_i, lim);
+		}
+		kring->nr_hwcur = head;
+	}
+
+	return 0;
+
+ring_reset:
+	return netmap_ring_reinit(kring);
+}
+
+static void
+vmxnet3_netmap_intr(struct netmap_adapter *na, int onoff)
+{
+	struct ifnet *ifp       = na->ifp;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+
+	if (onoff)
+		vmxnet3_enable_all_intrs(adapter);
+	else
+		vmxnet3_disable_all_intrs(adapter);
+}
+
+/* configure RX queue buffers to point to Netmap buffers */
+static int
+vmxnet3_netmap_rq_config_rx_buf(struct vmxnet3_rx_queue *rq,
+                                struct SOFTC_T *adapter)
+{
+	struct ifnet *ifp         = adapter->netdev;
+	struct netmap_adapter *na = NA(ifp);
+
+	u_int i;
+	u_int nm_i;
+	u_int ring_idx;
+	u_int ring_nr            = rq - adapter->rx_queue;
+	struct netmap_slot *slot = netmap_reset(na, NR_RX, ring_nr, 0);
+
+	if (!slot) {
+		return 0; // not in native netmap mode
+	}
+
+	nm_i = 0;
+	/* use only the 0th ring of each RX queue as it appears that the 1st
+	   ring can only be used for packet fragments (VMXNET3_RXD_BTYPE_BODY),
+	   which this driver doesn't support */
+	for (ring_idx = 0; ring_idx < 1; ring_idx++) {
+		struct vmxnet3_cmd_ring *cmd_ring = rq->rx_ring + ring_idx;
+
+		for (i = 0; i < cmd_ring->size; i++) {
+			struct vmxnet3_rx_buf_info *rbi =
+			        rq->buf_info[ring_idx] + i;
+			union Vmxnet3_GenericDesc *gd = cmd_ring->base + i;
+			uint64_t paddr;
+			u_int si = netmap_idx_n2k(na->rx_rings[ring_nr], nm_i);
+
+			PNMB(na, slot + si, &paddr);
+
+			rbi->buf_type = VMXNET3_RX_BUF_NONE;
+			rbi->len      = NETMAP_BUF_SIZE(na);
+			rbi->dma_addr = (dma_addr_t)paddr;
+
+			gd->rxd.addr = cpu_to_le64(rbi->dma_addr);
+			gd->dword[2] = cpu_to_le32(
+			        (!cmd_ring->gen << VMXNET3_RXD_GEN_SHIFT) |
+			        (VMXNET3_RXD_BTYPE_HEAD
+			         << VMXNET3_RXD_BTYPE_SHIFT) |
+			        rbi->len);
+			nm_i++;
+
+			if (i == cmd_ring->size - 1)
+				break;
+
+			gd->dword[2] = cpu_to_le32(
+			        gd->dword[2] |
+			        (cmd_ring->gen << VMXNET3_RXD_GEN_SHIFT));
+			vmxnet3_cmd_ring_adv_next2fill(cmd_ring);
+		}
+	}
+
+	return 1;
+}
+
+/* configure TX queue buffers to point to Netmap buffers */
+static int
+vmxnet3_netmap_tq_config_tx_buf(struct vmxnet3_tx_queue *tq,
+                                struct SOFTC_T *adapter)
+{
+	struct ifnet *ifp         = adapter->netdev;
+	struct netmap_adapter *na = NA(ifp);
+
+	u_int i;
+	u_int ring_nr                     = tq - adapter->tx_queue;
+	struct vmxnet3_cmd_ring *cmd_ring = &tq->tx_ring;
+	struct netmap_slot *slot          = netmap_reset(na, NR_TX, ring_nr, 0);
+
+	if (!slot) {
+		return 0; // not in native netmap mode
+	}
+
+	for (i = 0; i < cmd_ring->size; i++) {
+		struct vmxnet3_tx_buf_info *tbi = tq->buf_info + i;
+		union Vmxnet3_GenericDesc *gd   = cmd_ring->base + i;
+		uint64_t paddr;
+		u_int si = netmap_idx_n2k(na->tx_rings[ring_nr], i);
+
+		PNMB(na, slot + si, &paddr);
+
+		tbi->map_type = VMXNET3_MAP_NONE;
+		/*	the buffer length will get overriden by the actual
+		   packet length on transmit */
+		tbi->len      = NETMAP_BUF_SIZE(na);
+		tbi->dma_addr = (dma_addr_t)paddr;
+		tbi->sop_idx  = i;
+
+		gd->txd.addr = cpu_to_le64(tbi->dma_addr);
+		gd->dword[2] = 0;
+		gd->dword[3] = 0;
+	}
+
+	return 1;
+}
+
+static void
+vmxnet3_netmap_set_rxdataring_enabled(struct SOFTC_T *adapter)
+{
+	struct ifnet *ifp         = adapter->netdev;
+	struct netmap_adapter *na = NA(ifp);
+
+	adapter->rxdataring_enabled =
+	        nm_native_on(na) ? 0 : VMXNET3_VERSION_GE_3(adapter);
+}
+
+static void
+vmxnet3_netmap_init_buffers(struct SOFTC_T *adapter)
+{
+	struct ifnet *ifp         = adapter->netdev;
+	struct netmap_adapter *na = NA(ifp);
+
+	u_int r;
+
+	if (!nm_native_on(na))
+		return;
+
+	for (r = 0; r < na->num_rx_rings; r++) {
+		(void)netmap_reset(na, NR_RX, r, 0);
+	}
+
+	for (r = 0; r < na->num_tx_rings; r++) {
+		(void)netmap_reset(na, NR_TX, r, 0);
+	}
+
+	return;
+}
+
+static int
+vmxnet3_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	int ret = netmap_rings_config_get(na, info);
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
+
+	return 0;
+}
+
+static void
+vmxnet3_netmap_attach(struct SOFTC_T *adapter)
+{
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp          = adapter->netdev;
+	na.pdev         = &adapter->pdev->dev;
+	na.num_tx_desc  = adapter->tx_ring_size;
+	na.num_rx_desc  = adapter->rx_ring_size;
+	na.nm_register  = vmxnet3_netmap_reg;
+	na.nm_txsync    = vmxnet3_netmap_txsync;
+	na.nm_rxsync    = vmxnet3_netmap_rxsync;
+	na.num_tx_rings = adapter->num_tx_queues;
+	na.num_rx_rings = adapter->num_rx_queues;
+	na.nm_intr      = vmxnet3_netmap_intr;
+	na.nm_config    = vmxnet3_netmap_config;
+
+	netmap_attach(&na);
+}
+
+static void
+vmxnet3_netmap_detach(struct net_device *device)
+{
+	netmap_detach(device);
+}
+
+#endif // _IF_VMXNET3_NETMAP_H_

From 0e3e89047e8ae1296e6de792194d46035aab6483 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 24 Jan 2019 18:54:21 +0100
Subject: [PATCH 1558/2207] monitor: provide a dummy sync callback for bwrap

---
 sys/dev/netmap/netmap_monitor.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 2dc5fd4b6..d7112a0d5 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -259,11 +259,20 @@ static int netmap_monitor_parent_txsync(struct netmap_kring *, int);
 static int netmap_monitor_parent_rxsync(struct netmap_kring *, int);
 static int netmap_monitor_parent_notify(struct netmap_kring *, int);
 
+static int
+nm_monitor_dummycb(struct netmap_kring *kring, int flags)
+{
+	(void)kring;
+	(void)flags;
+	return 0;
+}
+
 static void
 nm_monitor_intercept_callbacks(struct netmap_kring *kring)
 {
 	ND("intercept callbacks on %s", kring->name);
-	kring->mon_sync = kring->nm_sync;
+	kring->mon_sync = kring->nm_sync != NULL ?
+		kring->nm_sync : nm_monitor_dummycb;
 	kring->mon_notify = kring->nm_notify;
 	if (kring->tx == NR_TX) {
 		kring->nm_sync = netmap_monitor_parent_txsync;

From 91305af053e53da78dcbe9ced8fee6c9588bc2e2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 25 Jan 2019 01:11:39 -0800
Subject: [PATCH 1559/2207] linux/scripts: avoid new-lines in make variable
 when multiple patches are used

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 62b820cc3..3bc2ceaa9 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -914,7 +914,7 @@ EOF
 	cat >> drivers.mak <
Date: Fri, 25 Jan 2019 03:10:20 -0800
Subject: [PATCH 1560/2207] linux/vmxnet3: fix buffer ownership and skipped
 slots

---
 LINUX/if_vmxnet3_netmap_v2.h | 128 ++++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 62 deletions(-)

diff --git a/LINUX/if_vmxnet3_netmap_v2.h b/LINUX/if_vmxnet3_netmap_v2.h
index 9601e59b1..cebb5cbb9 100644
--- a/LINUX/if_vmxnet3_netmap_v2.h
+++ b/LINUX/if_vmxnet3_netmap_v2.h
@@ -206,9 +206,8 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 	static const u32 rxprod_reg[] = {VMXNET3_REG_RXPROD,
 	                                 VMXNET3_REG_RXPROD2};
 
-	u_int num_pkts = 0;
 	u_int nm_i;
-	u_int n;
+	u_int nic_i;
 
 	struct netmap_adapter *na  = kring->na;
 	struct ifnet *ifp          = na->ifp;
@@ -223,6 +222,7 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 	struct Vmxnet3_RxCompDesc *rcd;
 	struct SOFTC_T *adapter     = netdev_priv(ifp);
 	struct vmxnet3_rx_queue *rq = &adapter->rx_queue[ring_nr];
+	struct vmxnet3_cmd_ring *cmd_ring = rq->rx_ring;
 
 	if (!netif_carrier_ok(ifp))
 		return 0;
@@ -235,15 +235,11 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 	//
 
 	if (netmap_no_pendintr || force_update) {
-		u_int hwtail_lim = nm_prev(kring->nr_hwcur, lim);
-		nm_i             = kring->nr_hwtail;
-
-		for (n = 0; nm_i != hwtail_lim; n++) {
+		nm_i   = kring->nr_hwtail;
+		nic_i  = netmap_idx_k2n(kring, nm_i);
+		for (;;) {
 			struct netmap_slot *slot;
-			struct vmxnet3_cmd_ring *cmd_ring;
 			u_int rx_idx;
-			u_int ring_idx;
-			u_int num_to_alloc;
 			uint64_t paddr;
 
 			vmxnet3_getRxComp(
@@ -257,9 +253,6 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			dma_rmb();
 
-			slot = nmring->slot + nm_i;
-			PNMB(na, slot, &paddr);
-
 			// data ring has been disabled on device init
 			BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
 
@@ -269,18 +262,36 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 			 */
 			BUG_ON(!(rcd->sop && rcd->eop));
 			BUG_ON(rcd->len > NETMAP_BUF_SIZE(na));
+			BUG_ON(VMXNET3_GET_RING_IDX(adapter, rcd->rqID) != 0);
 
-			ring_idx = VMXNET3_GET_RING_IDX(adapter, rcd->rqID);
 			rx_idx   = rcd->rxdIdx;
-			cmd_ring = rq->rx_ring + ring_idx;
+
+			/* device may have skipped some rx descs */
+			while (unlikely(nic_i != rx_idx)) {
+				D("%u skipped! rx_idx %u", nic_i, rx_idx);
+				/* the nic has skipped some slots because who
+				 * knows why. To shelter the application from
+				 * this we would need to rotate the
+				 * kernel-owned segments of the netmap and nic
+				 * rings.  For now, we just set len=0 in the
+				 * skipped slots and hope that this never
+				 * happens.
+				 */
+
+				nmring->slot[nm_i].len = 0;
+				nm_i = nm_next(nm_i, lim);
+				nic_i = nm_next(nic_i, lim);
+			}
+
+			slot = nmring->slot + nm_i;
+			PNMB(na, slot, &paddr);
 
 			slot->len   = rcd->len;
 			slot->flags = 0;
 			netmap_sync_map_cpu(na, (bus_dma_tag_t)na->pdev, &paddr,
 			                    slot->len, NR_RX);
-			num_pkts++;
-
 			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
 
 			/* XXX can this ever happen with all offloads disabled?
 			 */
@@ -292,48 +303,10 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 					rq->stats.drop_fcs++;
 			}
 
-			/* device may have skipped some rx descs */
-			cmd_ring->next2comp = rx_idx;
-			num_to_alloc = vmxnet3_cmd_ring_desc_avail(cmd_ring);
-
-			/* Ensure that the writes to rxd->gen bits will be
-			 * observed after all other writes to rxd objects.
-			 */
-			dma_wmb();
-
-			while (num_to_alloc) {
-				struct Vmxnet3_RxDesc *rxd;
-
-				vmxnet3_getRxDesc(
-				        rxd,
-				        &cmd_ring->base[cmd_ring->next2fill]
-				                 .rxd,
-				        &rxCmdDesc);
-				BUG_ON(!rxd->addr);
-
-				/* Recv desc is ready to be used by the device
-				 */
-				rxd->gen = cmd_ring->gen;
-				vmxnet3_cmd_ring_adv_next2fill(cmd_ring);
-				num_to_alloc--;
-			}
-
-			/* if needed, update the register */
-			if (unlikely(rq->shared->updateRxProd)) {
-				VMXNET3_WRITE_BAR0_REG(
-				        adapter,
-				        rxprod_reg[ring_idx] +
-				                rq->qid * VMXNET3_REG_ALIGN,
-				        cmd_ring->next2fill);
-			}
-
 			vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
 		}
 
-		if (num_pkts) {
-			kring->nr_hwtail = nm_i;
-		}
-
+		kring->nr_hwtail = nm_i;
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
 
@@ -344,22 +317,53 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 	nm_i = kring->nr_hwcur;
 
 	if (nm_i != head) {
-		for (n = 0; nm_i != head; n++) {
+		nic_i = netmap_idx_k2n(kring, nm_i);
+		while (nm_i != head) {
 			struct netmap_slot *slot = &nmring->slot[nm_i];
+			struct Vmxnet3_RxDesc *rxd;
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
 
-			if (addr == NETMAP_BUF_BASE(na)) // bad buf
-				goto ring_reset;
-
-			slot->flags &= ~NS_BUF_CHANGED;
+			if (slot->flags & NS_BUF_CHANGED) {
 
-			netmap_sync_map_dev(na, (bus_dma_tag_t)na->pdev, &paddr,
-			                    NETMAP_BUF_SIZE(na), NR_RX);
+				if (addr == NETMAP_BUF_BASE(na)) // bad buf
+					goto ring_reset;
 
+				vmxnet3_getRxDesc(
+					rxd,
+					&cmd_ring->base[nic_i].rxd,
+					&rxCmdDesc);
+
+				rxd->addr = paddr;
+				slot->flags &= ~NS_BUF_CHANGED;
+				/* Ensure that the writes to rxd->gen bits will be
+				 * observed after all other writes to rxd objects.
+				 */
+				dma_wmb();
+			}
+			netmap_sync_map_dev(na,
+					(bus_dma_tag_t)na->pdev, &paddr,
+					    NETMAP_BUF_SIZE(na), NR_RX);
+
+			vmxnet3_getRxDesc(
+				rxd,
+				&cmd_ring->base[cmd_ring->next2fill].rxd,
+				&rxCmdDesc);
+			rxd->gen = cmd_ring->gen;
+			vmxnet3_cmd_ring_adv_next2fill(cmd_ring);
 			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
 		}
 		kring->nr_hwcur = head;
+
+		/* if needed, update the register */
+		if (unlikely(rq->shared->updateRxProd)) {
+			VMXNET3_WRITE_BAR0_REG(
+				adapter,
+				rxprod_reg[kring->ring_id] +
+					rq->qid * VMXNET3_REG_ALIGN,
+				cmd_ring->next2fill);
+		}
 	}
 
 	return 0;

From cd6623767e13af264c3e82b1e5e863d8fcd0a6e1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 25 Jan 2019 12:14:12 +0100
Subject: [PATCH 1561/2207] linux/vmxnet3: enable v2 netmap patch

---
 ...--99999 => vanilla--vmxnet3--31000--40d00} |   0
 .../vanilla--vmxnet3--40d00--99999            | 152 ++++++++++++++++++
 2 files changed, 152 insertions(+)
 rename LINUX/final-patches/{vanilla--vmxnet3--31000--99999 => vanilla--vmxnet3--31000--40d00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--vmxnet3--40d00--99999

diff --git a/LINUX/final-patches/vanilla--vmxnet3--31000--99999 b/LINUX/final-patches/vanilla--vmxnet3--31000--40d00
similarity index 100%
rename from LINUX/final-patches/vanilla--vmxnet3--31000--99999
rename to LINUX/final-patches/vanilla--vmxnet3--31000--40d00
diff --git a/LINUX/final-patches/vanilla--vmxnet3--40d00--99999 b/LINUX/final-patches/vanilla--vmxnet3--40d00--99999
new file mode 100644
index 000000000..d0763e7aa
--- /dev/null
+++ b/LINUX/final-patches/vanilla--vmxnet3--40d00--99999
@@ -0,0 +1,152 @@
+diff --git a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
+old mode 100644
+new mode 100755
+index d1c7029ded7c..e827e6fe8fa3
+--- a/vmxnet3/vmxnet3_drv.c
++++ b/vmxnet3/vmxnet3_drv.c
+@@ -308,6 +308,11 @@ static u32 get_bitfield32(const __le32 *bitfield, u32 pos, u32 size)
+ #endif /* __BIG_ENDIAN_BITFIELD  */
+ 
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE) || defined(DEV_NETMAP)
++#include "if_vmxnet3_netmap_v2.h"
++#endif
++
++
+ static void
+ vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
+ 		     struct pci_dev *pdev)
+@@ -367,6 +372,13 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
+ 	int completed = 0;
+ 	union Vmxnet3_GenericDesc *gdesc;
+ 
++#ifdef DEV_NETMAP
++	struct net_device *netdev = adapter->netdev;
++
++	if (netmap_tx_irq(netdev, tq - adapter->tx_queue) != NM_IRQ_PASS)
++		return 0;
++#endif
++
+ 	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+ 	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
+ 		completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX(
+@@ -492,6 +504,10 @@ vmxnet3_tq_init(struct vmxnet3_tx_queue *tq,
+ 	for (i = 0; i < tq->tx_ring.size; i++)
+ 		tq->buf_info[i].map_type = VMXNET3_MAP_NONE;
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_tq_config_tx_buf(tq, adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* stats are not reset */
+ }
+ 
+@@ -1269,6 +1285,15 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ 	struct Vmxnet3_RxDesc rxCmdDesc;
+ 	struct Vmxnet3_RxCompDesc rxComp;
+ #endif
++
++#ifdef DEV_NETMAP
++	u_int total_packets = 0;
++	struct net_device *netdev = adapter->netdev;
++
++	if (netmap_rx_irq(netdev, rq - adapter->rx_queue, &total_packets) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
+ 			  &rxComp);
+ 	while (rcd->gen == rq->comp_ring.gen) {
+@@ -1692,12 +1717,18 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
+ 		       sizeof(struct Vmxnet3_RxDesc));
+ 		rq->rx_ring[i].gen = VMXNET3_INIT_GEN;
+ 	}
+-	if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1,
+-				    adapter) == 0) {
+-		/* at least has 1 rx buffer for the 1st ring */
+-		return -ENOMEM;
++#ifdef DEV_NETMAP
++	if (!vmxnet3_netmap_rq_config_rx_buf(rq, adapter)) {
++#endif /* DEV_NETMAP */
++		if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1,
++					    adapter) == 0) {
++			/* at least has 1 rx buffer for the 1st ring */
++			return -ENOMEM;
++		}
++		vmxnet3_rq_alloc_rx_buf(rq, 1, rq->rx_ring[1].size - 1, adapter);
++#ifdef DEV_NETMAP
+ 	}
+-	vmxnet3_rq_alloc_rx_buf(rq, 1, rq->rx_ring[1].size - 1, adapter);
++#endif /* DEV_NETMAP */
+ 
+ 	/* reset the comp ring */
+ 	rq->comp_ring.next2proc = 0;
+@@ -1801,7 +1832,11 @@ vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter)
+ {
+ 	int i, err = 0;
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_set_rxdataring_enabled(adapter);
++#else
+ 	adapter->rxdataring_enabled = VMXNET3_VERSION_GE_3(adapter);
++#endif /* DEV_NETMAP */
+ 
+ 	for (i = 0; i < adapter->num_rx_queues; i++) {
+ 		err = vmxnet3_rq_create(&adapter->rx_queue[i], adapter);
+@@ -2537,7 +2572,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+ 		adapter->rx_queue[0].rx_ring[0].size,
+ 		adapter->rx_queue[0].rx_ring[1].size);
+ 
+-	vmxnet3_tq_init_all(adapter);
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_init_buffers(adapter);
++#endif /* DEV_NETMAP */
++
+ 	err = vmxnet3_rq_init_all(adapter);
+ 	if (err) {
+ 		netdev_err(adapter->netdev,
+@@ -2545,6 +2583,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+ 		goto rq_err;
+ 	}
+ 
++	vmxnet3_tq_init_all(adapter);
++
+ 	err = vmxnet3_request_irqs(adapter);
+ 	if (err) {
+ 		netdev_err(adapter->netdev,
+@@ -2832,7 +2872,12 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
+ 	adapter->rx_queue[0].rx_ring[1].size = rx_ring2_size;
+ 	vmxnet3_adjust_rx_ring_size(adapter);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_set_rxdataring_enabled(adapter);
++#else
+ 	adapter->rxdataring_enabled = VMXNET3_VERSION_GE_3(adapter);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < adapter->num_rx_queues; i++) {
+ 		struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
+ 		/* qid and qid2 for rx queues will be assigned later when num
+@@ -3463,6 +3508,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
+ 		goto err_register;
+ 	}
+ 
++
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_check_link(adapter, false);
+ 	return 0;
+ 
+@@ -3520,6 +3570,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
+ 
+ 	unregister_netdev(netdev);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_free_intr_resources(adapter);
+ 	vmxnet3_free_pci_resources(adapter);
+ 	if (VMXNET3_VERSION_GE_3(adapter)) {

From 5d73e114c51818176a16222d876bc776cd02e76b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 25 Jan 2019 13:05:41 +0100
Subject: [PATCH 1562/2207] netmap_bwrap_intr_notify: improve logging

---
 sys/dev/netmap/netmap_bdg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 7830fea43..1e41896ee 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1141,8 +1141,8 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 		goto put_out;
 	if (kring->nr_hwcur == kring->nr_hwtail) {
 		if (netmap_verbose)
-			nm_prerr("how strange, interrupt with no packets on %s",
-			    na->name);
+			nm_prlim(1, "interrupt with no packets on %s",
+				kring->name);
 		goto put_out;
 	}
 

From 7b3ccde59bab300566977116e15b3a61f7d2206f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 28 Jan 2019 11:57:54 +0100
Subject: [PATCH 1563/2207] linux: ptnetmap_guest_shutdown: don't disable
 memdev twice

---
 LINUX/netmap_linux.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d1eb8bed3..34236667f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1947,10 +1947,10 @@ ptnetmap_guest_shutdown(struct pci_dev *pdev)
 	if (pdev->device == PTNETMAP_PCI_NETIF_ID) {
 		/* Shutdown the ptnet device. */
 		ptnet_shutdown(pdev);
+	} else if (pdev->device == PTNETMAP_PCI_DEVICE_ID) {
+		/* Shutdown the memdev device. */
+		pci_disable_device(pdev);
 	}
-
-	/* Shutdown the memdev device. */
-	pci_disable_device(pdev);
 }
 
 /*

From b20b2258c3f7ab040c925a612a01e2f0063fd203 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 28 Jan 2019 16:26:59 +0100
Subject: [PATCH 1564/2207] sync-kloop: use a saner timeout value for
 schedule_timeout (3 seconds)

---
 sys/dev/netmap/netmap_kloop.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 5a6243e16..bf1c4f2d8 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -657,7 +657,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			/* If a poll context is present, yield to the scheduler
 			 * waiting for a notification to come either from
 			 * netmap or the application. */
-			schedule_timeout(msecs_to_jiffies(20000));
+			schedule_timeout(msecs_to_jiffies(3000));
 		} else
 #endif /* SYNC_KLOOP_POLL */
 		{

From 7028dc359a5860cd41fd1648b41ed6379fbb9240 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 28 Jan 2019 22:33:21 +0100
Subject: [PATCH 1565/2207] netmap_sync_kloop_stop: send wakeup signal to stop
 immediately

---
 sys/dev/netmap/netmap_kloop.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index bf1c4f2d8..a4769a9ef 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -708,12 +708,34 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 int
 netmap_sync_kloop_stop(struct netmap_priv_d *priv)
 {
+	struct netmap_adapter *na;
 	bool running = true;
+	NM_SELINFO_T *si;
 	int err = 0;
 
+	if (priv->np_nifp == NULL) {
+		return ENXIO;
+	}
+	mb(); /* make sure following reads are not from cache */
+
+	na = priv->np_na;
+	if (!nm_netmap_on(na)) {
+		return ENXIO;
+	}
+
+	/* Set the kloop stopping flag. */
 	NMG_LOCK();
 	priv->np_kloop_state |= NM_SYNC_KLOOP_STOPPING;
 	NMG_UNLOCK();
+
+	/* Send a notification to the kloop, in case it is blocked in
+	 * schedule_timeout(). We can use either RX or TX, because the
+	 * kloop is waiting on both. */
+	si = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+		&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+	nm_os_selwakeup(si);
+
+	/* Wait for the kloop to actually terminate. */
 	while (running) {
 		usleep_range(1000, 1500);
 		NMG_LOCK();

From d8866f1d07f661240cc1eee67ce7883700fffc2c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 28 Jan 2019 22:50:56 +0100
Subject: [PATCH 1566/2207] sync-kloop: reuse values stored in priv->np_si

---
 sys/dev/netmap/netmap_kloop.c | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index a4769a9ef..98536cd03 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -567,16 +567,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
 		{
-			NM_SELINFO_T *si[NR_TXRX];
-
 			NMG_LOCK();
-			si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-			si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+			poll_wait(priv->np_filp, priv->np_si[NR_TX],
+			    &poll_ctx->wait_table);
+			poll_wait(priv->np_filp, priv->np_si[NR_RX],
+			    &poll_ctx->wait_table);
 			NMG_UNLOCK();
-			poll_wait(priv->np_filp, si[NR_TX], &poll_ctx->wait_table);
-			poll_wait(priv->np_filp, si[NR_RX], &poll_ctx->wait_table);
 		}
 #else   /* SYNC_KLOOP_POLL */
 		opt->nro_status = EOPNOTSUPP;
@@ -710,7 +706,6 @@ netmap_sync_kloop_stop(struct netmap_priv_d *priv)
 {
 	struct netmap_adapter *na;
 	bool running = true;
-	NM_SELINFO_T *si;
 	int err = 0;
 
 	if (priv->np_nifp == NULL) {
@@ -731,9 +726,7 @@ netmap_sync_kloop_stop(struct netmap_priv_d *priv)
 	/* Send a notification to the kloop, in case it is blocked in
 	 * schedule_timeout(). We can use either RX or TX, because the
 	 * kloop is waiting on both. */
-	si = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-		&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-	nm_os_selwakeup(si);
+	nm_os_selwakeup(priv->np_si[NR_RX]);
 
 	/* Wait for the kloop to actually terminate. */
 	while (running) {

From d34d06f378203f2250721a2db3af6c01209d8d49 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 28 Jan 2019 23:09:06 +0100
Subject: [PATCH 1567/2207] netmap_poll: reuse priv->np_si instead of
 recomputing it

---
 sys/dev/netmap/netmap.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 8b508737e..953280fb6 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3278,10 +3278,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
 	 * there are pending packets to send. The latter can be disabled
 	 * passing NETMAP_NO_TX_POLL in the NIOCREG call.
 	 */
-	si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
-				&na->rx_rings[priv->np_qfirst[NR_RX]]->si;
-	si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
-				&na->tx_rings[priv->np_qfirst[NR_TX]]->si;
+	si[NR_RX] = priv->np_si[NR_RX];
+	si[NR_TX] = priv->np_si[NR_TX];
 
 #ifdef __FreeBSD__
 	/*

From 2acb148ebd501791ef956b2830d584630cc7e863 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 29 Jan 2019 18:25:20 +0100
Subject: [PATCH 1568/2207] netmap.h: add macros for more sync-kloop
 synchronization options

---
 sys/net/netmap.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 707fc7c9d..921b26964 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -553,6 +553,11 @@ enum {
 	 * struct netmap_ring header, but rather using an user-provided
 	 * memory area (see struct nm_csb_atok and struct nm_csb_ktoa). */
 	NETMAP_REQ_OPT_CSB,
+
+	/* Like NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS, but the 'ioeventfd'
+	 * are mandatory (cannot be < 0), and the TX ring is synced in
+	 * the context of the VM exit. */
+	NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT,
 };
 
 /*
@@ -877,6 +882,12 @@ struct nmreq_opt_sync_kloop_eventfds {
 	 * their order must agree with the CSB arrays passed in the
 	 * NETMAP_REQ_OPT_CSB option. Each entry contains a file descriptor
 	 * backed by an eventfd.
+	 *
+	 * If any of the 'ioeventfd' entries is < 0, the event loop uses
+	 * the sleeping synchronization strategy (according to sleep_us),
+	 * and keeps kern_need_kick always disabled.
+	 * Each 'irqfd' can be < 0, and in that case the corresponding queue
+	 * is never notified.
 	 */
 	struct {
 		/* Notifier for the application --> kernel loop direction. */

From e5a7063084457578988b78c2a447189183d9f47e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 30 Jan 2019 11:23:06 +0100
Subject: [PATCH 1569/2207] freebsd: fix lock order reversal related to kqueue
 usage

When using poll(), select() or kevent() on netmap file descriptors,
netmap executes the equivalent of NIOCTXSYNC and NIOCRXSYNC commands,
before collecting the events that are ready. In other words, the
poll/kevent callback has side effects. This is done to avoid the
overhead of two system call per iteration (e.g., poll() + ioctl(NIOC*XSYNC)).

When the kqueue subsystem invokes the kqueue(9) f_event callback
(netmap_knrw), it holds the lock of the struct knlist object associated
to the netmap port (the lock is provided at initialization, by calling
knlist_init_mtx).
However, netmap_knrw() may need to wake up another netmap port (or even
the same one), which means that it may need to call knote().
Since knote() needs the lock of the struct knlist object associated to
the to-be-wake-up netmap port, it is possible to have a lock order
reversal problem (AB/BA deadlock).

This change prevents the deadlock by executing the knote() call in
a taskqueue, where it is possible to hold a mutex.
---
 LINUX/netmap_linux.c            |  5 ++-
 WINDOWS/win_glue.h              |  5 ++-
 sys/dev/netmap/netmap.c         | 19 ++++++---
 sys/dev/netmap/netmap_freebsd.c | 68 ++++++++++++++++++++++++---------
 sys/dev/netmap/netmap_kern.h    |  5 ++-
 5 files changed, 75 insertions(+), 27 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 34236667f..e2e289d65 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -83,10 +83,11 @@ nm_os_vfree(void *addr){
 	vfree(addr);
 }
 
-void
-nm_os_selinfo_init(NM_SELINFO_T *si)
+int
+nm_os_selinfo_init(NM_SELINFO_T *si, const char *name)
 {
 	init_waitqueue_head(si);
+	return 0;
 }
 
 void
diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index 14078e5e1..39523d194 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -215,11 +215,12 @@ typedef struct _win_SELINFO
 	KGUARDED_MUTEX mutex;
 } win_SELINFO;
 
-static void
-nm_os_selinfo_init(win_SELINFO* queue)
+static int
+nm_os_selinfo_init(win_SELINFO* queue, const char *name)
 {
 	KeInitializeEvent(&queue->queue, NotificationEvent, TRUE);
 	KeInitializeGuardedMutex(&queue->mutex);
+	return 0;
 }
 
 static void nm_os_selinfo_uninit(win_SELINFO *queue) { /* XXX nothing to do here? */ }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 953280fb6..2fd979fc7 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -830,6 +830,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	struct netmap_kring *kring;
 	u_int n[NR_TXRX];
 	enum txrx t;
+	int err = 0;
 
 	if (na->tx_rings != NULL) {
 		if (netmap_debug & NM_DEBUG_ON)
@@ -869,7 +870,6 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 		for (i = 0; i < n[t]; i++) {
 			kring = NMR(na, t)[i];
 			bzero(kring, sizeof(*kring));
-			kring->na = na;
 			kring->notify_na = na;
 			kring->ring_id = i;
 			kring->tx = t;
@@ -895,13 +895,21 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 					nm_txrx2str(t), i);
 			ND("ktx %s h %d c %d t %d",
 				kring->name, kring->rhead, kring->rcur, kring->rtail);
+			err = nm_os_selinfo_init(&kring->si, kring->name);
+			if (err) {
+				netmap_krings_delete(na);
+				return err;
+			}
 			mtx_init(&kring->q_lock, (t == NR_TX ? "nm_txq_lock" : "nm_rxq_lock"), NULL, MTX_DEF);
-			nm_os_selinfo_init(&kring->si);
+			kring->na = na;	/* setting this field marks the mutex as initialized */
+		}
+		err = nm_os_selinfo_init(&na->si[t], na->name);
+		if (err) {
+			netmap_krings_delete(na);
+			return err;
 		}
-		nm_os_selinfo_init(&na->si[t]);
 	}
 
-
 	return 0;
 }
 
@@ -925,7 +933,8 @@ netmap_krings_delete(struct netmap_adapter *na)
 
 	/* we rely on the krings layout described above */
 	for ( ; kring != na->tailroom; kring++) {
-		mtx_destroy(&(*kring)->q_lock);
+		if ((*kring)->na != NULL)
+			mtx_destroy(&(*kring)->q_lock);
 		nm_os_selinfo_uninit(&(*kring)->si);
 	}
 	nm_os_free(na->tx_rings);
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index ad26d2b46..a64964c2c 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -58,6 +58,7 @@
 #include  /* RFNOWAIT */
 #include  /* sched_bind() */
 #include  /* mp_maxid */
+#include  /* taskqueue_enqueue(), taskqueue_create(), ... */
 #include 
 #include 
 #include  /* IFT_ETHER */
@@ -75,16 +76,48 @@
 
 /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */
 
-void nm_os_selinfo_init(NM_SELINFO_T *si) {
-	struct mtx *m = &si->m;
-	mtx_init(m, "nm_kn_lock", NULL, MTX_DEF);
-	knlist_init_mtx(&si->si.si_note, m);
+static void
+nm_kqueue_notify(void *opaque, int pending)
+{
+	struct nm_selinfo *si = opaque;
+
+	/* We use a non-zero hint to distinguish this notification call
+	 * from the call done in kqueue_scan(), which uses hint=0.
+	 */
+	KNOTE_UNLOCKED(&si->si.si_note, /*hint=*/0x100);
+}
+
+int nm_os_selinfo_init(NM_SELINFO_T *si, const char *name) {
+	int err;
+
+	TASK_INIT(&si->ntfytask, 0, nm_kqueue_notify, si);
+	si->ntfytq = taskqueue_create(name, M_NOWAIT,
+	    taskqueue_thread_enqueue, &si->ntfytq);
+	if (si->ntfytq == NULL)
+		return -ENOMEM;
+	err = taskqueue_start_threads(&si->ntfytq, 1, PI_NET, "tq %s", name);
+	if (err) {
+		taskqueue_free(si->ntfytq);
+		si->ntfytq = NULL;
+		return err;
+	}
+
+	snprintf(si->mtxname, sizeof(si->mtxname), "nmkl%s", name);
+	mtx_init(&si->m, si->mtxname, NULL, MTX_DEF);
+	knlist_init_mtx(&si->si.si_note, &si->m);
+
+	return (0);
 }
 
 void
 nm_os_selinfo_uninit(NM_SELINFO_T *si)
 {
-	/* XXX kqueue(9) needed; these will mirror knlist_init. */
+	if (si->ntfytq == NULL) {
+		return;	/* si was not initialized */
+	}
+	taskqueue_drain(si->ntfytq, &si->ntfytask);
+	taskqueue_free(si->ntfytq);
+	si->ntfytq = NULL;
 	knlist_delete(&si->si.si_note, curthread, /*islocked=*/0);
 	knlist_destroy(&si->si.si_note);
 	/* now we don't need the mutex anymore */
@@ -1292,13 +1325,18 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 
 /*
  * In addition to calling selwakeuppri(), nm_os_selwakeup() also
- * needs to call KNOTE to wake up kqueue listeners.
- * We use a non-zero 'hint' argument to inform the netmap_knrw()
- * function that it is being called from 'nm_os_selwakeup'; this
- * is necessary because when netmap_knrw() is called by the kevent
- * subsystem (i.e. kevent_scan()) we also need to call netmap_poll().
- * The knote uses a private mutex associated to the 'si' (see struct
- * selinfo, struct nm_selinfo, and nm_os_selinfo_init).
+ * needs to call knote() to wake up kqueue listeners.
+ * This operation is deferred to a taskqueue in order to avoid possible
+ * lock order reversals; these may happen because knote() grabs a
+ * private lock associated to the 'si' (see struct selinfo,
+ * struct nm_selinfo, and nm_os_selinfo_init), and nm_os_selwakeup()
+ * can be called while holding the lock associated to a different
+ * 'si'.
+ * When calling knote() we use a non-zero 'hint' argument to inform
+ * the netmap_knrw() function that it is being called from
+ * 'nm_os_selwakeup'; this is necessary because when netmap_knrw() is
+ * called by the kevent subsystem (i.e. kevent_scan()) we also need to
+ * call netmap_poll().
  *
  * The netmap_kqfilter() function registers one or another f_event
  * depending on read or write mode. A pointer to the struct
@@ -1315,11 +1353,7 @@ nm_os_selwakeup(struct nm_selinfo *si)
 	if (netmap_verbose)
 		nm_prinf("on knote %p", &si->si.si_note);
 	selwakeuppri(&si->si, PI_NET);
-	/* We use a non-zero hint to distinguish this notification call
-	 * from the call done in kqueue_scan(), which uses hint=0.
-	 */
-	KNOTE(&si->si.si_note, /*hint=*/0x100,
-	    mtx_owned(&si->m) ? KNF_LISTLOCKED : 0);
+	taskqueue_enqueue(si->ntfytq, &si->ntfytask);
 }
 
 void
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 68b1fd762..3b05d306c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -133,7 +133,10 @@ struct netmap_adapter *netmap_getna(if_t ifp);
 
 struct nm_selinfo {
 	struct selinfo si;
+	struct taskqueue *ntfytq;
+	struct task ntfytask;
 	struct mtx m;
+	char mtxname[32];
 };
 
 
@@ -295,7 +298,7 @@ struct netmap_priv_d;
 struct nm_bdg_args;
 
 /* os-specific NM_SELINFO_T initialzation/destruction functions */
-void nm_os_selinfo_init(NM_SELINFO_T *);
+int nm_os_selinfo_init(NM_SELINFO_T *, const char *name);
 void nm_os_selinfo_uninit(NM_SELINFO_T *);
 
 const char *nm_dump_buf(char *p, int len, int lim, char *dst);

From 0497bbafd222014ba04a64820925b52d192b630f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 30 Jan 2019 12:46:08 +0100
Subject: [PATCH 1570/2207] sync-kloop: add support for busy-wait (no kicks)
 and unspecified irqfds

---
 sys/dev/netmap/netmap_kloop.c | 134 +++++++++++++++++++++++-----------
 1 file changed, 90 insertions(+), 44 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 98536cd03..27b8d13f2 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -148,6 +148,7 @@ struct sync_kloop_ring_args {
 #ifdef SYNC_KLOOP_POLL
 	struct eventfd_ctx *irq_ctx;
 #endif /* SYNC_KLOOP_POLL */
+	bool use_kicks;
 };
 
 static void
@@ -197,7 +198,9 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
 			/* Reinit ring and enable notifications. */
 			netmap_ring_reinit(kring);
-			csb_ktoa_kick_enable(csb_ktoa, 1);
+			if (a->use_kicks) {
+				csb_ktoa_kick_enable(csb_ktoa, 1);
+			}
 			break;
 		}
 
@@ -206,8 +209,10 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
+			if (a->use_kicks) {
+				/* Reenable notifications. */
+				csb_ktoa_kick_enable(csb_ktoa, 1);
+			}
 			nm_prerr("txsync() failed");
 			break;
 		}
@@ -232,7 +237,8 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		/* Interrupt the application if needed. */
 #ifdef SYNC_KLOOP_POLL
 		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable application kick to avoid sending unnecessary kicks */
+			/* We could disable kernel --> application kicks here,
+			 * to avoid spurious interrupts. */
 			eventfd_signal(a->irq_ctx, 1);
 			more_txspace = false;
 		}
@@ -241,6 +247,9 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (shadow_ring.head == kring->rhead) {
+			if (!a->use_kicks) {
+				break;
+			}
 			/*
 			 * No more packets to transmit. We enable notifications and
 			 * go to sleep, waiting for a kick from the application when new
@@ -315,7 +324,9 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
 			/* Reinit ring and enable notifications. */
 			netmap_ring_reinit(kring);
-			csb_ktoa_kick_enable(csb_ktoa, 1);
+			if (a->use_kicks) {
+				csb_ktoa_kick_enable(csb_ktoa, 1);
+			}
 			break;
 		}
 
@@ -324,8 +335,10 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		}
 
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			/* Reenable notifications. */
-			csb_ktoa_kick_enable(csb_ktoa, 1);
+			if (a->use_kicks) {
+				/* Reenable notifications. */
+				csb_ktoa_kick_enable(csb_ktoa, 1);
+			}
 			nm_prerr("rxsync() failed");
 			break;
 		}
@@ -351,7 +364,8 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 #ifdef SYNC_KLOOP_POLL
 		/* Interrupt the application if needed. */
 		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
-			/* Disable application kick to avoid sending unnecessary kicks */
+			/* We could disable kernel --> application kicks here,
+			 * to avoid spurious interrupts. */
 			eventfd_signal(a->irq_ctx, 1);
 			some_recvd = false;
 		}
@@ -360,6 +374,9 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
+			if (!a->use_kicks) {
+				break;
+			}
 			/*
 			 * No more slots available for reception. We enable notification and
 			 * go to sleep, waiting for a kick from the application when new receive
@@ -435,7 +452,6 @@ sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 	/* Use the default wake up function. */
 	init_waitqueue_entry(&entry->wait, current);
 	add_wait_queue(wqh, &entry->wait);
-	poll_ctx->next_entry++;
 }
 #endif  /* SYNC_KLOOP_POLL */
 
@@ -455,6 +471,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct nm_csb_ktoa* csb_ktoa_base;
 	struct netmap_adapter *na;
 	struct nmreq_option *opt;
+	bool use_sleep = true;
 	int err = 0;
 	int i;
 
@@ -508,6 +525,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	/* Validate notification options. */
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
+	if (opt == NULL)
+		opt = nmreq_findoption((struct nmreq_option *)
+				(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
 	if (opt != NULL) {
 		err = nmreq_checkduplicate(opt);
 		if (err) {
@@ -524,6 +545,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #ifdef SYNC_KLOOP_POLL
 		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
 		opt->nro_status = 0;
+
 		/* We need 2 poll entries for TX and RX notifications coming
 		 * from the netmap adapter, plus one entries per ring for the
 		 * notifications coming from the application. */
@@ -533,45 +555,66 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					sync_kloop_poll_table_queue_proc);
 		poll_ctx->num_entries = 2 + num_rings;
 		poll_ctx->next_entry = 0;
+
+		/* Check if some ioeventfd entry is not defined, and force sleep
+		 * synchronization in that case. */
+		use_sleep = false;
+		for (i = 0; i < num_rings; i++) {
+			if (eventfds_opt->eventfds[i].ioeventfd < 0) {
+				use_sleep = true;
+				break;
+			}
+		}
+
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
-		for (i = 0; i < num_rings; i++) {
-			struct eventfd_ctx *irq;
-			struct file *filp;
+		for (i = 0; i < num_rings; i++, poll_ctx->next_entry++) {
+			struct eventfd_ctx *irq = NULL;
+			struct file *filp = NULL;
 			unsigned long mask;
 
-			filp = eventfd_fget(eventfds_opt->eventfds[i].ioeventfd);
-			if (IS_ERR(filp)) {
-				err = PTR_ERR(filp);
-				goto out;
-			}
-			mask = filp->f_op->poll(filp, &poll_ctx->wait_table);
-			if (mask & POLLERR) {
-				err = EINVAL;
-				goto out;
-			}
-
-			filp = eventfd_fget(eventfds_opt->eventfds[i].irqfd);
-			if (IS_ERR(filp)) {
-				err = PTR_ERR(filp);
-				goto out;
+			if (eventfds_opt->eventfds[i].irqfd >= 0) {
+				filp = eventfd_fget(
+				    eventfds_opt->eventfds[i].irqfd);
+				if (IS_ERR(filp)) {
+					err = PTR_ERR(filp);
+					goto out;
+				}
+				irq = eventfd_ctx_fileget(filp);
+				if (IS_ERR(irq)) {
+					err = PTR_ERR(irq);
+					goto out;
+				}
 			}
 			poll_ctx->entries[i].irq_filp = filp;
-			irq = eventfd_ctx_fileget(filp);
-			if (IS_ERR(irq)) {
-				err = PTR_ERR(irq);
-				goto out;
-			}
 			poll_ctx->entries[i].irq_ctx = irq;
+
+			if (eventfds_opt->eventfds[i].ioeventfd >= 0) {
+				filp = eventfd_fget(
+				    eventfds_opt->eventfds[i].ioeventfd);
+				if (IS_ERR(filp)) {
+					err = PTR_ERR(filp);
+					goto out;
+				}
+				mask = filp->f_op->poll(filp,
+				    &poll_ctx->wait_table);
+				if (mask & POLLERR) {
+					err = EINVAL;
+					goto out;
+				}
+			}
 		}
+
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
-		{
+		if (!use_sleep) {
 			NMG_LOCK();
 			poll_wait(priv->np_filp, priv->np_si[NR_TX],
 			    &poll_ctx->wait_table);
+			poll_ctx->next_entry++;
 			poll_wait(priv->np_filp, priv->np_si[NR_RX],
 			    &poll_ctx->wait_table);
+			poll_ctx->next_entry++;
 			NMG_UNLOCK();
 		}
 #else   /* SYNC_KLOOP_POLL */
@@ -592,6 +635,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		if (poll_ctx)
 			a->irq_ctx = poll_ctx->entries[i].irq_ctx;
 #endif /* SYNC_KLOOP_POLL */
+		a->use_kicks = !use_sleep;
 	}
 	for (i = 0; i < num_rx_rings; i++) {
 		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
@@ -603,6 +647,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		if (poll_ctx)
 			a->irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
 #endif /* SYNC_KLOOP_POLL */
+		a->use_kicks = !use_sleep;
 	}
 
 	/* Main loop. */
@@ -612,7 +657,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		if (poll_ctx) {
+		if (!use_sleep) {
 			/* It is important to set the task state as
 			 * interruptible before processing any TX/RX ring,
 			 * so that if a notification on ring Y comes after
@@ -648,25 +693,26 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			nm_kr_put(a->kring);
 		}
 
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx) {
-			/* If a poll context is present, yield to the scheduler
-			 * waiting for a notification to come either from
-			 * netmap or the application. */
-			schedule_timeout(msecs_to_jiffies(3000));
-		} else
-#endif /* SYNC_KLOOP_POLL */
-		{
+		if (use_sleep) {
 			/* Default synchronization method: sleep for a while. */
 			usleep_range(sleep_us, sleep_us);
 		}
+#ifdef SYNC_KLOOP_POLL
+		else {
+			/* Yield to the scheduler waiting for a notification
+			 * to come either from netmap or the application. */
+			schedule_timeout(msecs_to_jiffies(3000));
+		}
+#endif /* SYNC_KLOOP_POLL */
 	}
 out:
 #ifdef SYNC_KLOOP_POLL
 	if (poll_ctx) {
 		/* Stop polling from netmap and the eventfds, and deallocate
 		 * the poll context. */
-		__set_current_state(TASK_RUNNING);
+		if (!use_sleep) {
+			__set_current_state(TASK_RUNNING);
+		}
 		for (i = 0; i < poll_ctx->next_entry; i++) {
 			struct sync_kloop_poll_entry *entry =
 						poll_ctx->entries + i;

From 216074fafbd42165e6e536ea7b8a29f1789ca620 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 30 Jan 2019 16:25:07 +0100
Subject: [PATCH 1571/2207] sync-kloop: add support for custom wake-up function

---
 sys/dev/netmap/netmap_kloop.c | 45 ++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 11 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 27b8d13f2..36f88b0cc 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -433,6 +433,7 @@ struct sync_kloop_poll_entry {
 struct sync_kloop_poll_ctx {
 	poll_table wait_table;
 	unsigned int next_entry;
+	int (*next_wake_fun)(wait_queue_t *, unsigned, int, void *);
 	unsigned int num_entries;
 	struct sync_kloop_poll_entry entries[0];
 };
@@ -450,7 +451,12 @@ sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 	entry->wqh = wqh;
 	entry->filp = file;
 	/* Use the default wake up function. */
-	init_waitqueue_entry(&entry->wait, current);
+	if (poll_ctx->next_wake_fun == NULL) {
+		init_waitqueue_entry(&entry->wait, current);
+	} else {
+		init_waitqueue_func_entry(&entry->wait,
+		    poll_ctx->next_wake_fun);
+	}
 	add_wait_queue(wqh, &entry->wait);
 }
 #endif  /* SYNC_KLOOP_POLL */
@@ -530,6 +536,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 				(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
 	if (opt != NULL) {
+		bool direct;
+
 		err = nmreq_checkduplicate(opt);
 		if (err) {
 			opt->nro_status = err;
@@ -546,16 +554,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		eventfds_opt = (struct nmreq_opt_sync_kloop_eventfds *)opt;
 		opt->nro_status = 0;
 
-		/* We need 2 poll entries for TX and RX notifications coming
-		 * from the netmap adapter, plus one entries per ring for the
-		 * notifications coming from the application. */
-		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
-				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
-		init_poll_funcptr(&poll_ctx->wait_table,
-					sync_kloop_poll_table_queue_proc);
-		poll_ctx->num_entries = 2 + num_rings;
-		poll_ctx->next_entry = 0;
-
 		/* Check if some ioeventfd entry is not defined, and force sleep
 		 * synchronization in that case. */
 		use_sleep = false;
@@ -566,6 +564,27 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			}
 		}
 
+		direct = (opt->nro_reqtype ==
+		    NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
+
+		if (use_sleep && direct) {
+			/* For 'direct' processing we need all the
+			 * ioeventfds to be valid. */
+			opt->nro_status = err = EINVAL;
+			goto out;
+		}
+
+		/* We need 2 poll entries for TX and RX notifications coming
+		 * from the netmap adapter, plus one entries per ring for the
+		 * notifications coming from the application. */
+		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
+				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
+		init_poll_funcptr(&poll_ctx->wait_table,
+					sync_kloop_poll_table_queue_proc);
+		poll_ctx->num_entries = 2 + num_rings;
+		poll_ctx->next_entry = 0;
+		poll_ctx->next_wake_fun = NULL;
+
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
 		for (i = 0; i < num_rings; i++, poll_ctx->next_entry++) {
@@ -596,6 +615,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					err = PTR_ERR(filp);
 					goto out;
 				}
+				if (direct && i < num_tx_rings) {
+				} else {
+					poll_ctx->next_wake_fun = NULL;
+				}
 				mask = filp->f_op->poll(filp,
 				    &poll_ctx->wait_table);
 				if (mask & POLLERR) {

From 159b996e6727d05c37616533443eadaeeb992359 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 30 Jan 2019 18:29:13 +0100
Subject: [PATCH 1572/2207] sync-kloop: add support for
 NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT

---
 sys/dev/netmap/netmap.c       |   1 +
 sys/dev/netmap/netmap_kloop.c | 120 +++++++++++++++++++++++++---------
 2 files changed, 91 insertions(+), 30 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2fd979fc7..78c08cb77 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2965,6 +2965,7 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 		break;
 #endif /* WITH_EXTMEM */
 	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
+	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT:
 		if (nro_size >= rv)
 			rv = nro_size;
 		break;
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 36f88b0cc..f202f4366 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -418,6 +418,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 }
 
 #ifdef SYNC_KLOOP_POLL
+struct sync_kloop_poll_ctx;
 struct sync_kloop_poll_entry {
 	/* Support for receiving notifications from
 	 * a netmap ring or from the application. */
@@ -428,6 +429,12 @@ struct sync_kloop_poll_entry {
 	/* Support for sending notifications to the application. */
 	struct eventfd_ctx *irq_ctx;
 	struct file *irq_filp;
+
+	/* Arguments for the ring processing function. Useful
+	 * in case of custom wake-up function. */
+	struct sync_kloop_ring_args *args;
+	struct sync_kloop_poll_ctx *parent;
+
 };
 
 struct sync_kloop_poll_ctx {
@@ -435,6 +442,10 @@ struct sync_kloop_poll_ctx {
 	unsigned int next_entry;
 	int (*next_wake_fun)(wait_queue_t *, unsigned, int, void *);
 	unsigned int num_entries;
+	unsigned int num_tx_rings;
+	/* First num_tx_rings entries are for the TX kicks.
+	 * Then the RX kicks entries follow. The last two
+	 * entries are for TX irq, and RX irq. */
 	struct sync_kloop_poll_entry entries[0];
 };
 
@@ -459,6 +470,38 @@ sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
 	}
 	add_wait_queue(wqh, &entry->wait);
 }
+
+static int
+sync_kloop_tx_kick_wake_fun(wait_queue_t *wait, unsigned mode,
+    int wake_flags, void *key)
+{
+	struct sync_kloop_poll_entry *entry =
+	    container_of(wait, struct sync_kloop_poll_entry, wait);
+
+	netmap_sync_kloop_tx_ring(entry->args);
+
+	return 0;
+}
+
+static int
+sync_kloop_tx_irq_wake_fun(wait_queue_t *wait, unsigned mode,
+    int wake_flags, void *key)
+{
+	struct sync_kloop_poll_entry *entry =
+	    container_of(wait, struct sync_kloop_poll_entry, wait);
+	struct sync_kloop_poll_ctx *poll_ctx = entry->parent;
+	int i;
+
+	for (i = 0; i < poll_ctx->num_tx_rings; i++) {
+		struct eventfd_ctx *irq_ctx = poll_ctx->entries[i].irq_ctx;
+
+		if (irq_ctx) {
+			eventfd_signal(irq_ctx, 1);
+		}
+	}
+
+	return 0;
+}
 #endif  /* SYNC_KLOOP_POLL */
 
 int
@@ -478,6 +521,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct netmap_adapter *na;
 	struct nmreq_option *opt;
 	bool use_sleep = true;
+	bool direct = false;
 	int err = 0;
 	int i;
 
@@ -528,6 +572,25 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		goto out;
 	}
 
+	/* Prepare the arguments for netmap_sync_kloop_tx_ring()
+	 * and netmap_sync_kloop_rx_ring(). */
+	for (i = 0; i < num_tx_rings; i++) {
+		struct sync_kloop_ring_args *a = args + i;
+
+		a->kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
+		a->csb_atok = csb_atok_base + i;
+		a->csb_ktoa = csb_ktoa_base + i;
+		a->use_kicks = false;
+	}
+	for (i = 0; i < num_rx_rings; i++) {
+		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
+
+		a->kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
+		a->csb_atok = csb_atok_base + num_tx_rings + i;
+		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
+		a->use_kicks = false;
+	}
+
 	/* Validate notification options. */
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
@@ -536,8 +599,6 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 				(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
 	if (opt != NULL) {
-		bool direct;
-
 		err = nmreq_checkduplicate(opt);
 		if (err) {
 			opt->nro_status = err;
@@ -578,13 +639,19 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		 * from the netmap adapter, plus one entries per ring for the
 		 * notifications coming from the application. */
 		poll_ctx = nm_os_malloc(sizeof(*poll_ctx) +
-				(2 + num_rings) * sizeof(poll_ctx->entries[0]));
+				(num_rings + 2) * sizeof(poll_ctx->entries[0]));
 		init_poll_funcptr(&poll_ctx->wait_table,
 					sync_kloop_poll_table_queue_proc);
 		poll_ctx->num_entries = 2 + num_rings;
+		poll_ctx->num_tx_rings = num_tx_rings;
 		poll_ctx->next_entry = 0;
 		poll_ctx->next_wake_fun = NULL;
 
+		for (i = 0; i < num_rings + 2; i++) {
+			poll_ctx->entries[i].args = args + i;
+			poll_ctx->entries[i].parent = poll_ctx;
+		}
+
 		/* Poll for notifications coming from the applications through
 		 * eventfds . */
 		for (i = 0; i < num_rings; i++, poll_ctx->next_entry++) {
@@ -607,6 +674,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			}
 			poll_ctx->entries[i].irq_filp = filp;
 			poll_ctx->entries[i].irq_ctx = irq;
+			/* Don't let netmap_sync_kloop_tx_ring() use
+			 * IRQs in direct mode. */
+			poll_ctx->entries[i].args->irq_ctx =
+			    direct ? NULL : poll_ctx->entries[i].irq_ctx;
+			poll_ctx->entries[i].args->use_kicks = !use_sleep;
 
 			if (eventfds_opt->eventfds[i].ioeventfd >= 0) {
 				filp = eventfd_fget(
@@ -616,6 +688,12 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					goto out;
 				}
 				if (direct && i < num_tx_rings) {
+					/* Override the wake up function
+					 * so that it can directly call
+					 * netmap_sync_kloop_tx_ring().
+					 */
+					poll_ctx->next_wake_fun =
+					    sync_kloop_tx_kick_wake_fun;
 				} else {
 					poll_ctx->next_wake_fun = NULL;
 				}
@@ -632,9 +710,16 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		 * this file descriptor. */
 		if (!use_sleep) {
 			NMG_LOCK();
+			/* In direct mode, override the wake up function so
+			 * that it can forward the netmap_tx_irq() to the
+			 * guest. */
+			poll_ctx->next_wake_fun = direct ?
+			    sync_kloop_tx_irq_wake_fun : NULL;
 			poll_wait(priv->np_filp, priv->np_si[NR_TX],
 			    &poll_ctx->wait_table);
 			poll_ctx->next_entry++;
+
+			poll_ctx->next_wake_fun = NULL;
 			poll_wait(priv->np_filp, priv->np_si[NR_RX],
 			    &poll_ctx->wait_table);
 			poll_ctx->next_entry++;
@@ -646,32 +731,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 	}
 
-	/* Prepare the arguments for netmap_sync_kloop_tx_ring()
-	 * and netmap_sync_kloop_rx_ring(). */
-	for (i = 0; i < num_tx_rings; i++) {
-		struct sync_kloop_ring_args *a = args + i;
-
-		a->kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
-		a->csb_atok = csb_atok_base + i;
-		a->csb_ktoa = csb_ktoa_base + i;
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
-			a->irq_ctx = poll_ctx->entries[i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-		a->use_kicks = !use_sleep;
-	}
-	for (i = 0; i < num_rx_rings; i++) {
-		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
-
-		a->kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
-		a->csb_atok = csb_atok_base + num_tx_rings + i;
-		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
-#ifdef SYNC_KLOOP_POLL
-		if (poll_ctx)
-			a->irq_ctx = poll_ctx->entries[num_tx_rings + i].irq_ctx;
-#endif /* SYNC_KLOOP_POLL */
-		a->use_kicks = !use_sleep;
-	}
+	nm_prinf("kloop sleep: %u direct %u", use_sleep, direct);
 
 	/* Main loop. */
 	for (;;) {
@@ -695,7 +755,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
-		for (i = 0; i < num_tx_rings; i++) {
+		for (i = 0; !direct && i < num_tx_rings; i++) {
 			struct sync_kloop_ring_args *a = args + i;
 
 			if (unlikely(nm_kr_tryget(a->kring, 1, NULL))) {

From 5d106a16404dd212623ba5f0dda837abf53fdc66 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 30 Jan 2019 18:43:41 +0100
Subject: [PATCH 1573/2207] sync-kloop: fix "scheduling while atomic" bug

---
 sys/dev/netmap/netmap_kloop.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index f202f4366..dc486fb79 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -520,6 +520,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct nm_csb_ktoa* csb_ktoa_base;
 	struct netmap_adapter *na;
 	struct nmreq_option *opt;
+	bool na_could_sleep = false;
 	bool use_sleep = true;
 	bool direct = false;
 	int err = 0;
@@ -647,6 +648,15 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		poll_ctx->next_entry = 0;
 		poll_ctx->next_wake_fun = NULL;
 
+		if (direct && (na->na_flags & NAF_BDG_MAYSLEEP)) {
+			/* In direct mode, VALE txsync is called from
+			 * wake-up context, where it is not possible
+			 * to sleep.
+			 */
+			na->na_flags &= ~NAF_BDG_MAYSLEEP;
+			na_could_sleep = true;
+		}
+
 		for (i = 0; i < num_rings + 2; i++) {
 			poll_ctx->entries[i].args = args + i;
 			poll_ctx->entries[i].parent = poll_ctx;
@@ -731,7 +741,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 	}
 
-	nm_prinf("kloop sleep: %u direct %u", use_sleep, direct);
+	nm_prinf("kloop use_sleep %u, direct %u, na_could_sleep %u",
+	    use_sleep, direct, na_could_sleep);
 
 	/* Main loop. */
 	for (;;) {
@@ -825,6 +836,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	/* Reset the kloop state. */
 	NMG_LOCK();
 	priv->np_kloop_state = 0;
+	if (na_could_sleep) {
+		na->na_flags |= NAF_BDG_MAYSLEEP;
+	}
 	NMG_UNLOCK();
 
 	return err;

From 7a6bad0ca995f162a0e426a082f6e4cfc8321fe0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 30 Jan 2019 18:45:40 +0100
Subject: [PATCH 1574/2207] sync-kloop: allow RX irqs in direct mode

---
 sys/dev/netmap/netmap_kloop.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index dc486fb79..1427afc07 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -687,7 +687,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			/* Don't let netmap_sync_kloop_tx_ring() use
 			 * IRQs in direct mode. */
 			poll_ctx->entries[i].args->irq_ctx =
-			    direct ? NULL : poll_ctx->entries[i].irq_ctx;
+			    (direct && i < num_tx_rings) ? NULL :
+			    poll_ctx->entries[i].irq_ctx;
 			poll_ctx->entries[i].args->use_kicks = !use_sleep;
 
 			if (eventfds_opt->eventfds[i].ioeventfd >= 0) {

From aa263e74643001802224c658031645b5b7ebd9c6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 12:18:54 +0100
Subject: [PATCH 1575/2207] sync-kloop: introduce nm_kr_wouldblock

---
 sys/dev/netmap/netmap_kern.h  |  9 +++++++++
 sys/dev/netmap/netmap_kloop.c | 16 ++++++++--------
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 3b05d306c..85df9aa0d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1169,6 +1169,15 @@ nm_kr_txempty(struct netmap_kring *kring)
  * rxsync_prologue */
 #define nm_kr_rxempty(_k)	nm_kr_txempty(_k)
 
+/* True if the application needs to wait for more space on the ring
+ * (more received packets or more free tx slots).
+ * Only valid after *xsync_prologue. */
+static inline int
+nm_kr_wouldblock(struct netmap_kring *kring)
+{
+	return kring->rcur == kring->nr_hwtail;
+}
+
 /*
  * protect against multiple threads using the same ring.
  * also check that the ring has not been stopped or locked
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 1427afc07..e8ba81187 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -914,14 +914,14 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	atok->appl_need_kick = 0;
 
 	/*
-	 * First part: tell the host (updating the CSB) to process the new
-	 * packets.
+	 * First part: tell the host to process the new packets,
+	 * updating the CSB.
 	 */
 	kring->nr_hwcur = ktoa->hwcur;
 	nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
 
         /* Ask for a kick from a guest to the host if needed. */
-	if (((kring->rhead != kring->nr_hwcur || nm_kr_txempty(kring))
+	if (((kring->rhead != kring->nr_hwcur || nm_kr_wouldblock(kring))
 		&& NM_ACCESS_ONCE(ktoa->kern_need_kick)) ||
 			(flags & NAF_FORCE_RECLAIM)) {
 		atok->sync_flags = flags;
@@ -931,7 +931,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
-	if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) {
+	if (nm_kr_wouldblock(kring) || (flags & NAF_FORCE_RECLAIM)) {
 		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
 	}
@@ -941,7 +941,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * go to sleep and we need to be notified by the host when more free
 	 * space is available.
          */
-	if (nm_kr_txempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
+	if (nm_kr_wouldblock(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
 		atok->appl_need_kick = 1;
                 /* Double check, with store-load memory barrier. */
@@ -949,7 +949,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
                 /* If there is new free space, disable notifications */
-		if (unlikely(!nm_kr_txempty(kring))) {
+		if (unlikely(!nm_kr_wouldblock(kring))) {
 			atok->appl_need_kick = 0;
 		}
 	}
@@ -1007,7 +1007,7 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * we need to be notified by the host when more RX slots have been
 	 * completed.
          */
-	if (nm_kr_rxempty(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
+	if (nm_kr_wouldblock(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
 		/* Reenable notifications. */
                 atok->appl_need_kick = 1;
                 /* Double check, with store-load memory barrier. */
@@ -1015,7 +1015,7 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 		nm_sync_kloop_appl_read(ktoa, &kring->nr_hwtail,
 					&kring->nr_hwcur);
                 /* If there are new slots, disable notifications. */
-		if (!nm_kr_rxempty(kring)) {
+		if (!nm_kr_wouldblock(kring)) {
                         atok->appl_need_kick = 0;
                 }
         }

From f93a4e3cba50edbad427babf5951ecb27ffb6225 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 12:29:45 +0100
Subject: [PATCH 1576/2207] ptnetmap guest rxsync: ask a kick also if the kring
 would block

---
 sys/dev/netmap/netmap_kloop.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index e8ba81187..f98c4718f 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -995,11 +995,6 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 */
 	if (kring->rhead != kring->nr_hwcur) {
 		nm_sync_kloop_appl_write(atok, kring->rcur, kring->rhead);
-                /* Ask for a kick from the guest to the host if needed. */
-		if (NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
-			atok->sync_flags = flags;
-			notify = true;
-		}
 	}
 
         /*
@@ -1020,6 +1015,13 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
                 }
         }
 
+	/* Ask for a kick from the guest to the host if needed. */
+	if ((kring->rhead != kring->nr_hwcur || nm_kr_wouldblock(kring))
+		&& NM_ACCESS_ONCE(ktoa->kern_need_kick)) {
+		atok->sync_flags = flags;
+		notify = true;
+	}
+
 	nm_prdis(1, "%s CSB(head:%u cur:%u hwtail:%u) KRING(head:%u cur:%u tail:%u)",
 		kring->name, atok->head, atok->cur, ktoa->hwtail,
 		kring->rhead, kring->rcur, kring->nr_hwtail);

From 05f6205c7910c678c7a452f9a32a5639f3500e47 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 12:56:00 +0100
Subject: [PATCH 1577/2207] sync-kloop: keep kicks disabled in direct mode

---
 sys/dev/netmap/netmap_kloop.c | 60 ++++++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 22 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index f98c4718f..7b2013811 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -141,6 +141,9 @@ sync_kloop_kring_dump(const char *title, const struct netmap_kring *kring)
 		kring->rcur, kring->rtail, kring->nr_hwtail);
 }
 
+/* Arguments for netmap_sync_kloop_tx_ring() and
+ * netmap_sync_kloop_rx_ring().
+ */
 struct sync_kloop_ring_args {
 	struct netmap_kring *kring;
 	struct nm_csb_atok *csb_atok;
@@ -148,7 +151,10 @@ struct sync_kloop_ring_args {
 #ifdef SYNC_KLOOP_POLL
 	struct eventfd_ctx *irq_ctx;
 #endif /* SYNC_KLOOP_POLL */
-	bool use_kicks;
+	/* Are we busy waiting rather than using a schedule() loop ? */
+	bool busy_wait;
+	/* Are we processing in the context of VM exit ? */
+	bool direct;
 };
 
 static void
@@ -162,10 +168,16 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 	uint32_t num_slots;
 	int batch;
 
+	if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+		return;
+	}
+
 	num_slots = kring->nkr_num_slots;
 
 	/* Disable application --> kernel notifications. */
-	csb_ktoa_kick_enable(csb_ktoa, 0);
+	if (!a->direct) {
+		csb_ktoa_kick_enable(csb_ktoa, 0);
+	}
 	/* Copy the application kring pointers from the CSB */
 	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 
@@ -198,7 +210,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) {
 			/* Reinit ring and enable notifications. */
 			netmap_ring_reinit(kring);
-			if (a->use_kicks) {
+			if (!a->busy_wait) {
 				csb_ktoa_kick_enable(csb_ktoa, 1);
 			}
 			break;
@@ -209,7 +221,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			if (a->use_kicks) {
+			if (!a->busy_wait) {
 				/* Reenable notifications. */
 				csb_ktoa_kick_enable(csb_ktoa, 1);
 			}
@@ -247,7 +259,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (shadow_ring.head == kring->rhead) {
-			if (!a->use_kicks) {
+			if (a->busy_wait) {
 				break;
 			}
 			/*
@@ -282,6 +294,8 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		eventfd_signal(a->irq_ctx, 1);
 	}
 #endif /* SYNC_KLOOP_POLL */
+
+	nm_kr_put(kring);
 }
 
 /* RX cycle without receive any packets */
@@ -306,13 +320,19 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 	bool some_recvd = false;
 	uint32_t num_slots;
 
+	if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
+		return;
+	}
+
 	num_slots = kring->nkr_num_slots;
 
 	/* Get RX csb_atok and csb_ktoa pointers from the CSB. */
 	num_slots = kring->nkr_num_slots;
 
 	/* Disable notifications. */
-	csb_ktoa_kick_enable(csb_ktoa, 0);
+	if (!a->direct) {
+		csb_ktoa_kick_enable(csb_ktoa, 0);
+	}
 	/* Copy the application kring pointers from the CSB */
 	sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 
@@ -324,7 +344,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) {
 			/* Reinit ring and enable notifications. */
 			netmap_ring_reinit(kring);
-			if (a->use_kicks) {
+			if (!a->busy_wait) {
 				csb_ktoa_kick_enable(csb_ktoa, 1);
 			}
 			break;
@@ -335,7 +355,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		}
 
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
-			if (a->use_kicks) {
+			if (!a->busy_wait) {
 				/* Reenable notifications. */
 				csb_ktoa_kick_enable(csb_ktoa, 1);
 			}
@@ -374,7 +394,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		/* Read CSB to see if there is more work to do. */
 		sync_kloop_kernel_read(csb_atok, &shadow_ring, num_slots);
 		if (sync_kloop_norxslots(kring, shadow_ring.head)) {
-			if (!a->use_kicks) {
+			if (a->busy_wait) {
 				break;
 			}
 			/*
@@ -415,6 +435,8 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		eventfd_signal(a->irq_ctx, 1);
 	}
 #endif /* SYNC_KLOOP_POLL */
+
+	nm_kr_put(kring);
 }
 
 #ifdef SYNC_KLOOP_POLL
@@ -581,7 +603,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
 		a->csb_atok = csb_atok_base + i;
 		a->csb_ktoa = csb_ktoa_base + i;
-		a->use_kicks = false;
+		a->busy_wait = false;
+		a->direct = false;
 	}
 	for (i = 0; i < num_rx_rings; i++) {
 		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
@@ -589,7 +612,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
 		a->csb_atok = csb_atok_base + num_tx_rings + i;
 		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
-		a->use_kicks = false;
+		a->busy_wait = false;
+		a->direct = false;
 	}
 
 	/* Validate notification options. */
@@ -689,7 +713,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			poll_ctx->entries[i].args->irq_ctx =
 			    (direct && i < num_tx_rings) ? NULL :
 			    poll_ctx->entries[i].irq_ctx;
-			poll_ctx->entries[i].args->use_kicks = !use_sleep;
+			poll_ctx->entries[i].args->busy_wait = use_sleep;
+			poll_ctx->entries[i].args->direct =
+			    (direct && i < num_tx_rings);
 
 			if (eventfds_opt->eventfds[i].ioeventfd >= 0) {
 				filp = eventfd_fget(
@@ -769,23 +795,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		/* Process all the TX rings bound to this file descriptor. */
 		for (i = 0; !direct && i < num_tx_rings; i++) {
 			struct sync_kloop_ring_args *a = args + i;
-
-			if (unlikely(nm_kr_tryget(a->kring, 1, NULL))) {
-				continue;
-			}
 			netmap_sync_kloop_tx_ring(a);
-			nm_kr_put(a->kring);
 		}
 
 		/* Process all the RX rings bound to this file descriptor. */
 		for (i = 0; i < num_rx_rings; i++) {
 			struct sync_kloop_ring_args *a = args + num_tx_rings + i;
-
-			if (unlikely(nm_kr_tryget(a->kring, 1, NULL))) {
-				continue;
-			}
 			netmap_sync_kloop_rx_ring(a);
-			nm_kr_put(a->kring);
 		}
 
 		if (use_sleep) {

From 287f88a8371ee3159d43efdfd2ddb1becd41e2f9 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 15:50:59 +0100
Subject: [PATCH 1578/2207] sync-kloop: improve initialization of kloop
 arguments

---
 sys/dev/netmap/netmap_kloop.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 7b2013811..f55d8b6e8 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -603,8 +603,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
 		a->csb_atok = csb_atok_base + i;
 		a->csb_ktoa = csb_ktoa_base + i;
-		a->busy_wait = false;
-		a->direct = false;
+		a->busy_wait = use_sleep;
+		a->direct = direct;
 	}
 	for (i = 0; i < num_rx_rings; i++) {
 		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
@@ -612,8 +612,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
 		a->csb_atok = csb_atok_base + num_tx_rings + i;
 		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
-		a->busy_wait = false;
-		a->direct = false;
+		a->busy_wait = use_sleep;
+		a->direct = direct;
 	}
 
 	/* Validate notification options. */
@@ -687,7 +687,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 		/* Poll for notifications coming from the applications through
-		 * eventfds . */
+		 * eventfds. */
 		for (i = 0; i < num_rings; i++, poll_ctx->next_entry++) {
 			struct eventfd_ctx *irq = NULL;
 			struct file *filp = NULL;

From 19355df4f5814425700ff7b245cfebb730a7407e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 16:19:00 +0100
Subject: [PATCH 1579/2207] sync-kloop: don't poll any ioeventfd in busy-wait
 mode

---
 sys/dev/netmap/netmap_kloop.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index f55d8b6e8..b8fc637f6 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -717,7 +717,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			poll_ctx->entries[i].args->direct =
 			    (direct && i < num_tx_rings);
 
-			if (eventfds_opt->eventfds[i].ioeventfd >= 0) {
+			if (!use_sleep) {
 				filp = eventfd_fget(
 				    eventfds_opt->eventfds[i].ioeventfd);
 				if (IS_ERR(filp)) {

From 6e4a5510f73cd0be95857622de602051c86b4c20 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 16:25:06 +0100
Subject: [PATCH 1580/2207] sync-kloop: remove double nm_kr_put()

---
 sys/dev/netmap/netmap_kloop.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index b8fc637f6..ae4cbb85b 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -289,13 +289,13 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		}
 	}
 
+	nm_kr_put(kring);
+
 #ifdef SYNC_KLOOP_POLL
 	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
 		eventfd_signal(a->irq_ctx, 1);
 	}
 #endif /* SYNC_KLOOP_POLL */
-
-	nm_kr_put(kring);
 }
 
 /* RX cycle without receive any packets */
@@ -435,8 +435,6 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		eventfd_signal(a->irq_ctx, 1);
 	}
 #endif /* SYNC_KLOOP_POLL */
-
-	nm_kr_put(kring);
 }
 
 #ifdef SYNC_KLOOP_POLL

From 108ae2eef0a9618366a81c6edc8c773f0cedf171 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 16:26:22 +0100
Subject: [PATCH 1581/2207] sync-kloop: rename local variable "use_sleep" -->
 "busy_wait"

---
 sys/dev/netmap/netmap_kloop.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index ae4cbb85b..84f90daf4 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -541,7 +541,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct netmap_adapter *na;
 	struct nmreq_option *opt;
 	bool na_could_sleep = false;
-	bool use_sleep = true;
+	bool busy_wait = true;
 	bool direct = false;
 	int err = 0;
 	int i;
@@ -601,7 +601,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->kring = NMR(na, NR_TX)[i + priv->np_qfirst[NR_TX]];
 		a->csb_atok = csb_atok_base + i;
 		a->csb_ktoa = csb_ktoa_base + i;
-		a->busy_wait = use_sleep;
+		a->busy_wait = busy_wait;
 		a->direct = direct;
 	}
 	for (i = 0; i < num_rx_rings; i++) {
@@ -610,7 +610,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->kring = NMR(na, NR_RX)[i + priv->np_qfirst[NR_RX]];
 		a->csb_atok = csb_atok_base + num_tx_rings + i;
 		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
-		a->busy_wait = use_sleep;
+		a->busy_wait = busy_wait;
 		a->direct = direct;
 	}
 
@@ -640,10 +640,10 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 		/* Check if some ioeventfd entry is not defined, and force sleep
 		 * synchronization in that case. */
-		use_sleep = false;
+		busy_wait = false;
 		for (i = 0; i < num_rings; i++) {
 			if (eventfds_opt->eventfds[i].ioeventfd < 0) {
-				use_sleep = true;
+				busy_wait = true;
 				break;
 			}
 		}
@@ -651,7 +651,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		direct = (opt->nro_reqtype ==
 		    NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
 
-		if (use_sleep && direct) {
+		if (busy_wait && direct) {
 			/* For 'direct' processing we need all the
 			 * ioeventfds to be valid. */
 			opt->nro_status = err = EINVAL;
@@ -711,11 +711,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			poll_ctx->entries[i].args->irq_ctx =
 			    (direct && i < num_tx_rings) ? NULL :
 			    poll_ctx->entries[i].irq_ctx;
-			poll_ctx->entries[i].args->busy_wait = use_sleep;
+			poll_ctx->entries[i].args->busy_wait = busy_wait;
 			poll_ctx->entries[i].args->direct =
 			    (direct && i < num_tx_rings);
 
-			if (!use_sleep) {
+			if (!busy_wait) {
 				filp = eventfd_fget(
 				    eventfds_opt->eventfds[i].ioeventfd);
 				if (IS_ERR(filp)) {
@@ -743,7 +743,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 		/* Poll for notifications coming from the netmap rings bound to
 		 * this file descriptor. */
-		if (!use_sleep) {
+		if (!busy_wait) {
 			NMG_LOCK();
 			/* In direct mode, override the wake up function so
 			 * that it can forward the netmap_tx_irq() to the
@@ -766,8 +766,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 	}
 
-	nm_prinf("kloop use_sleep %u, direct %u, na_could_sleep %u",
-	    use_sleep, direct, na_could_sleep);
+	nm_prinf("kloop busy_wait %u, direct %u, na_could_sleep %u",
+	    busy_wait, direct, na_could_sleep);
 
 	/* Main loop. */
 	for (;;) {
@@ -776,7 +776,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 #ifdef SYNC_KLOOP_POLL
-		if (!use_sleep) {
+		if (!busy_wait) {
 			/* It is important to set the task state as
 			 * interruptible before processing any TX/RX ring,
 			 * so that if a notification on ring Y comes after
@@ -802,7 +802,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			netmap_sync_kloop_rx_ring(a);
 		}
 
-		if (use_sleep) {
+		if (busy_wait) {
 			/* Default synchronization method: sleep for a while. */
 			usleep_range(sleep_us, sleep_us);
 		}
@@ -819,7 +819,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	if (poll_ctx) {
 		/* Stop polling from netmap and the eventfds, and deallocate
 		 * the poll context. */
-		if (!use_sleep) {
+		if (!busy_wait) {
 			__set_current_state(TASK_RUNNING);
 		}
 		for (i = 0; i < poll_ctx->next_entry; i++) {

From 3d28a38b7f6d032e6397a3ae5ea1c3379f8b1524 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 16:45:43 +0100
Subject: [PATCH 1582/2207] sync-kloop: add support for direct RX mode

---
 sys/dev/netmap/netmap_kloop.c | 46 ++++++++++++++++++++++++++++++++---
 sys/net/netmap.h              |  4 +--
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 84f90daf4..317a33d2e 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -463,6 +463,7 @@ struct sync_kloop_poll_ctx {
 	int (*next_wake_fun)(wait_queue_t *, unsigned, int, void *);
 	unsigned int num_entries;
 	unsigned int num_tx_rings;
+	unsigned int num_rings;
 	/* First num_tx_rings entries are for the TX kicks.
 	 * Then the RX kicks entries follow. The last two
 	 * entries are for TX irq, and RX irq. */
@@ -522,6 +523,38 @@ sync_kloop_tx_irq_wake_fun(wait_queue_t *wait, unsigned mode,
 
 	return 0;
 }
+
+static int
+sync_kloop_rx_kick_wake_fun(wait_queue_t *wait, unsigned mode,
+    int wake_flags, void *key)
+{
+	struct sync_kloop_poll_entry *entry =
+	    container_of(wait, struct sync_kloop_poll_entry, wait);
+
+	netmap_sync_kloop_rx_ring(entry->args);
+
+	return 0;
+}
+
+static int
+sync_kloop_rx_irq_wake_fun(wait_queue_t *wait, unsigned mode,
+    int wake_flags, void *key)
+{
+	struct sync_kloop_poll_entry *entry =
+	    container_of(wait, struct sync_kloop_poll_entry, wait);
+	struct sync_kloop_poll_ctx *poll_ctx = entry->parent;
+	int i;
+
+	for (i = poll_ctx->num_tx_rings; i < poll_ctx->num_rings; i++) {
+		struct eventfd_ctx *irq_ctx = poll_ctx->entries[i].irq_ctx;
+
+		if (irq_ctx) {
+			eventfd_signal(irq_ctx, 1);
+		}
+	}
+
+	return 0;
+}
 #endif  /* SYNC_KLOOP_POLL */
 
 int
@@ -667,6 +700,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					sync_kloop_poll_table_queue_proc);
 		poll_ctx->num_entries = 2 + num_rings;
 		poll_ctx->num_tx_rings = num_tx_rings;
+		poll_ctx->num_rings = num_rings;
 		poll_ctx->next_entry = 0;
 		poll_ctx->next_wake_fun = NULL;
 
@@ -709,11 +743,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			/* Don't let netmap_sync_kloop_tx_ring() use
 			 * IRQs in direct mode. */
 			poll_ctx->entries[i].args->irq_ctx =
-			    (direct && i < num_tx_rings) ? NULL :
+			    (direct) ? NULL :
 			    poll_ctx->entries[i].irq_ctx;
 			poll_ctx->entries[i].args->busy_wait = busy_wait;
 			poll_ctx->entries[i].args->direct =
-			    (direct && i < num_tx_rings);
+			    (direct);
 
 			if (!busy_wait) {
 				filp = eventfd_fget(
@@ -729,6 +763,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					 */
 					poll_ctx->next_wake_fun =
 					    sync_kloop_tx_kick_wake_fun;
+				} else if (direct) {
+					poll_ctx->next_wake_fun =
+					    sync_kloop_rx_kick_wake_fun;
 				} else {
 					poll_ctx->next_wake_fun = NULL;
 				}
@@ -754,7 +791,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			    &poll_ctx->wait_table);
 			poll_ctx->next_entry++;
 
-			poll_ctx->next_wake_fun = NULL;
+			poll_ctx->next_wake_fun = direct ?
+			    sync_kloop_rx_irq_wake_fun : NULL;
 			poll_wait(priv->np_filp, priv->np_si[NR_RX],
 			    &poll_ctx->wait_table);
 			poll_ctx->next_entry++;
@@ -797,7 +835,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 
 		/* Process all the RX rings bound to this file descriptor. */
-		for (i = 0; i < num_rx_rings; i++) {
+		for (i = 0; !direct && i < num_rx_rings; i++) {
 			struct sync_kloop_ring_args *a = args + num_tx_rings + i;
 			netmap_sync_kloop_rx_ring(a);
 		}
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 921b26964..2051b17c2 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -555,8 +555,8 @@ enum {
 	NETMAP_REQ_OPT_CSB,
 
 	/* Like NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS, but the 'ioeventfd'
-	 * are mandatory (cannot be < 0), and the TX ring is synced in
-	 * the context of the VM exit. */
+	 * fields are mandatory (cannot be < 0), and the TX and/or RX rings
+	 * are synced in the context of the VM exit. */
 	NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT,
 };
 

From 1e07c1ddcc2747202b0750ac93766094004cc3cc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 18:02:50 +0100
Subject: [PATCH 1583/2207] sync-kloop: allow separate direct tx and direct rx
 modes

---
 sys/dev/netmap/netmap.c       |  4 ++-
 sys/dev/netmap/netmap_kloop.c | 58 ++++++++++++++++++++---------------
 sys/net/netmap.h              | 22 +++++++++----
 3 files changed, 52 insertions(+), 32 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 78c08cb77..61739bec5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2965,13 +2965,15 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 		break;
 #endif /* WITH_EXTMEM */
 	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
-	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT:
 		if (nro_size >= rv)
 			rv = nro_size;
 		break;
 	case NETMAP_REQ_OPT_CSB:
 		rv = sizeof(struct nmreq_opt_csb);
 		break;
+	case NETMAP_REQ_OPT_SYNC_KLOOP_MODE:
+		rv = sizeof(struct nmreq_opt_sync_kloop_mode);
+		break;
 	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 317a33d2e..7142a3abb 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -575,7 +575,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct nmreq_option *opt;
 	bool na_could_sleep = false;
 	bool busy_wait = true;
-	bool direct = false;
+	bool direct_tx = false;
+	bool direct_rx = false;
 	int err = 0;
 	int i;
 
@@ -635,7 +636,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->csb_atok = csb_atok_base + i;
 		a->csb_ktoa = csb_ktoa_base + i;
 		a->busy_wait = busy_wait;
-		a->direct = direct;
+		a->direct = direct_tx;
 	}
 	for (i = 0; i < num_rx_rings; i++) {
 		struct sync_kloop_ring_args *a = args + num_tx_rings + i;
@@ -644,16 +645,22 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		a->csb_atok = csb_atok_base + num_tx_rings + i;
 		a->csb_ktoa = csb_ktoa_base + num_tx_rings + i;
 		a->busy_wait = busy_wait;
-		a->direct = direct;
+		a->direct = direct_rx;
 	}
 
 	/* Validate notification options. */
+	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
+				NETMAP_REQ_OPT_SYNC_KLOOP_MODE);
+	if (opt != NULL) {
+		struct nmreq_opt_sync_kloop_mode *mode_opt =
+		    (struct nmreq_opt_sync_kloop_mode *)opt;
+
+		direct_tx = !!(mode_opt->mode & NM_OPT_SYNC_KLOOP_DIRECT_TX);
+		direct_rx = !!(mode_opt->mode & NM_OPT_SYNC_KLOOP_DIRECT_RX);
+		opt->nro_status = 0;
+	}
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
 				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
-	if (opt == NULL)
-		opt = nmreq_findoption((struct nmreq_option *)
-				(uintptr_t)hdr->nr_options,
-				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
 	if (opt != NULL) {
 		err = nmreq_checkduplicate(opt);
 		if (err) {
@@ -681,11 +688,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			}
 		}
 
-		direct = (opt->nro_reqtype ==
-		    NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT);
-
-		if (busy_wait && direct) {
-			/* For 'direct' processing we need all the
+		if (busy_wait && (direct_tx || direct_rx)) {
+			/* For direct processing we need all the
 			 * ioeventfds to be valid. */
 			opt->nro_status = err = EINVAL;
 			goto out;
@@ -704,7 +708,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		poll_ctx->next_entry = 0;
 		poll_ctx->next_wake_fun = NULL;
 
-		if (direct && (na->na_flags & NAF_BDG_MAYSLEEP)) {
+		if (direct_tx && (na->na_flags & NAF_BDG_MAYSLEEP)) {
 			/* In direct mode, VALE txsync is called from
 			 * wake-up context, where it is not possible
 			 * to sleep.
@@ -724,6 +728,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			struct eventfd_ctx *irq = NULL;
 			struct file *filp = NULL;
 			unsigned long mask;
+			bool tx_ring = (i < num_tx_rings);
 
 			if (eventfds_opt->eventfds[i].irqfd >= 0) {
 				filp = eventfd_fget(
@@ -740,14 +745,15 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			}
 			poll_ctx->entries[i].irq_filp = filp;
 			poll_ctx->entries[i].irq_ctx = irq;
-			/* Don't let netmap_sync_kloop_tx_ring() use
+			poll_ctx->entries[i].args->busy_wait = busy_wait;
+			/* Don't let netmap_sync_kloop_*x_ring() use
 			 * IRQs in direct mode. */
 			poll_ctx->entries[i].args->irq_ctx =
-			    (direct) ? NULL :
+			    ((tx_ring && direct_tx) ||
+			    (!tx_ring && direct_rx)) ? NULL :
 			    poll_ctx->entries[i].irq_ctx;
-			poll_ctx->entries[i].args->busy_wait = busy_wait;
 			poll_ctx->entries[i].args->direct =
-			    (direct);
+			    (tx_ring ? direct_tx : direct_rx);
 
 			if (!busy_wait) {
 				filp = eventfd_fget(
@@ -756,14 +762,15 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 					err = PTR_ERR(filp);
 					goto out;
 				}
-				if (direct && i < num_tx_rings) {
+				if (tx_ring && direct_tx) {
 					/* Override the wake up function
 					 * so that it can directly call
 					 * netmap_sync_kloop_tx_ring().
 					 */
 					poll_ctx->next_wake_fun =
 					    sync_kloop_tx_kick_wake_fun;
-				} else if (direct) {
+				} else if (!tx_ring && direct_rx) {
+					/* Same for direct RX. */
 					poll_ctx->next_wake_fun =
 					    sync_kloop_rx_kick_wake_fun;
 				} else {
@@ -785,13 +792,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			/* In direct mode, override the wake up function so
 			 * that it can forward the netmap_tx_irq() to the
 			 * guest. */
-			poll_ctx->next_wake_fun = direct ?
+			poll_ctx->next_wake_fun = direct_tx ?
 			    sync_kloop_tx_irq_wake_fun : NULL;
 			poll_wait(priv->np_filp, priv->np_si[NR_TX],
 			    &poll_ctx->wait_table);
 			poll_ctx->next_entry++;
 
-			poll_ctx->next_wake_fun = direct ?
+			poll_ctx->next_wake_fun = direct_rx ?
 			    sync_kloop_rx_irq_wake_fun : NULL;
 			poll_wait(priv->np_filp, priv->np_si[NR_RX],
 			    &poll_ctx->wait_table);
@@ -804,8 +811,9 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 	}
 
-	nm_prinf("kloop busy_wait %u, direct %u, na_could_sleep %u",
-	    busy_wait, direct, na_could_sleep);
+	nm_prinf("kloop busy_wait %u, direct_tx %u, direct_rx %u, "
+	    "na_could_sleep %u", busy_wait, direct_tx, direct_rx,
+	    na_could_sleep);
 
 	/* Main loop. */
 	for (;;) {
@@ -829,13 +837,13 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 #endif  /* SYNC_KLOOP_POLL */
 
 		/* Process all the TX rings bound to this file descriptor. */
-		for (i = 0; !direct && i < num_tx_rings; i++) {
+		for (i = 0; !direct_tx && i < num_tx_rings; i++) {
 			struct sync_kloop_ring_args *a = args + i;
 			netmap_sync_kloop_tx_ring(a);
 		}
 
 		/* Process all the RX rings bound to this file descriptor. */
-		for (i = 0; !direct && i < num_rx_rings; i++) {
+		for (i = 0; !direct_rx && i < num_rx_rings; i++) {
 			struct sync_kloop_ring_args *a = args + num_tx_rings + i;
 			netmap_sync_kloop_rx_ring(a);
 		}
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 2051b17c2..704c5162c 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -540,7 +540,8 @@ enum {
 
 enum {
 	/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
-	 * from user-space allocated memory pools (e.g. hugepages). */
+	 * from user-space allocated memory pools (e.g. hugepages).
+	 */
 	NETMAP_REQ_OPT_EXTMEM = 1,
 
 	/* ON NETMAP_REQ_SYNC_KLOOP_START, ask netmap to use eventfd-based
@@ -551,13 +552,15 @@ enum {
 	/* On NETMAP_REQ_REGISTER, ask netmap to work in CSB mode, where
 	 * head, cur and tail pointers are not exchanged through the
 	 * struct netmap_ring header, but rather using an user-provided
-	 * memory area (see struct nm_csb_atok and struct nm_csb_ktoa). */
+	 * memory area (see struct nm_csb_atok and struct nm_csb_ktoa).
+	 */
 	NETMAP_REQ_OPT_CSB,
 
-	/* Like NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS, but the 'ioeventfd'
-	 * fields are mandatory (cannot be < 0), and the TX and/or RX rings
-	 * are synced in the context of the VM exit. */
-	NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS_DIRECT,
+	/* An extension to NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS, which specifies
+	 * if the TX and/or RX rings are synced in the context of the VM exit.
+	 * This requires the 'ioeventfd' fields to be valid (cannot be < 0).
+	 */
+	NETMAP_REQ_OPT_SYNC_KLOOP_MODE,
 };
 
 /*
@@ -897,6 +900,13 @@ struct nmreq_opt_sync_kloop_eventfds {
 	} eventfds[0];
 };
 
+struct nmreq_opt_sync_kloop_mode {
+	struct nmreq_option	nro_opt;	/* common header */
+#define NM_OPT_SYNC_KLOOP_DIRECT_TX (1 << 0)
+#define NM_OPT_SYNC_KLOOP_DIRECT_RX (1 << 1)
+	uint32_t mode;
+};
+
 struct nmreq_opt_extmem {
 	struct nmreq_option	nro_opt;	/* common header */
 	uint64_t		nro_usrptr;	/* (in) ptr to usr memory */

From 7016efe342dd76319d99f67ed42aad023865a028 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 18:15:30 +0100
Subject: [PATCH 1584/2207] sync-kloop: validate sync kloop mode option

---
 sys/dev/netmap/netmap_kloop.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 7142a3abb..2bd3685a2 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -657,6 +657,11 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 		direct_tx = !!(mode_opt->mode & NM_OPT_SYNC_KLOOP_DIRECT_TX);
 		direct_rx = !!(mode_opt->mode & NM_OPT_SYNC_KLOOP_DIRECT_RX);
+		if (mode_opt->mode & ~(NM_OPT_SYNC_KLOOP_DIRECT_TX |
+		    NM_OPT_SYNC_KLOOP_DIRECT_RX)) {
+			opt->nro_status = err = EINVAL;
+			goto out;
+		}
 		opt->nro_status = 0;
 	}
 	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,

From 00f187baea1fe982f5e4d42671e8cd87da40bebb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 31 Jan 2019 18:36:20 +0100
Subject: [PATCH 1585/2207] utils: ctrl-api-test: add test cases for sync-kloop
 modes

---
 utils/ctrl-api-test.c | 76 +++++++++++++++++++++++++++++++++----------
 1 file changed, 58 insertions(+), 18 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index e7ea8f711..37f5c230b 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -146,6 +146,7 @@ struct TestContext {
 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
 	uint32_t nr_first_cpu_id;     /* vale polling */
 	uint32_t nr_num_polling_cpus; /* vale polling */
+	uint32_t sync_kloop_mode; /* sync-kloop */
 	int fd; /* netmap file descriptor */
 
 	void *csb;                    /* CSB entries (atok and ktoa) */
@@ -1322,51 +1323,58 @@ sync_kloop(struct TestContext *ctx)
 static int
 sync_kloop_eventfds(struct TestContext *ctx)
 {
-	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
-	struct nmreq_option save;
+	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
+	struct nmreq_opt_sync_kloop_mode modeopt;
+	struct nmreq_option evsave;
 	int num_entries;
 	size_t opt_size;
 	int ret, i;
 
+	memset(&modeopt, 0, sizeof(modeopt));
+	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
+	modeopt.mode = ctx->sync_kloop_mode;
+	push_option(&modeopt.nro_opt, ctx);
+
 	num_entries = num_registered_rings(ctx);
-	opt_size    = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
-	opt = calloc(1, opt_size);
-	opt->nro_opt.nro_next    = 0;
-	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
-	opt->nro_opt.nro_status  = 0;
-	opt->nro_opt.nro_size    = opt_size;
+	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
+	evopt = calloc(1, opt_size);
+	evopt->nro_opt.nro_next    = 0;
+	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
+	evopt->nro_opt.nro_status  = 0;
+	evopt->nro_opt.nro_size    = opt_size;
 	for (i = 0; i < num_entries; i++) {
 		int efd = eventfd(0, 0);
 
-		opt->eventfds[i].ioeventfd = efd;
+		evopt->eventfds[i].ioeventfd = efd;
 		efd                        = eventfd(0, 0);
-		opt->eventfds[i].irqfd = efd;
+		evopt->eventfds[i].irqfd = efd;
 	}
 
-	push_option(&opt->nro_opt, ctx);
-	save = opt->nro_opt;
+	push_option(&evopt->nro_opt, ctx);
+	evsave = evopt->nro_opt;
 
 	ret = sync_kloop_start_stop(ctx);
 	if (ret != 0) {
-		free(opt);
+		free(evopt);
 		clear_options(ctx);
 		return ret;
 	}
 #ifdef __linux__
-	save.nro_status = 0;
+	evsave.nro_status = 0;
 #else  /* !__linux__ */
-	save.nro_status = EOPNOTSUPP;
+	evsave.nro_status = EOPNOTSUPP;
 #endif /* !__linux__ */
 
-	ret = checkoption(&opt->nro_opt, &save);
-	free(opt);
+	ret = checkoption(&evopt->nro_opt, &evsave);
+	free(evopt);
 	clear_options(ctx);
 
 	return ret;
 }
 
 static int
-sync_kloop_eventfds_all(struct TestContext *ctx)
+sync_kloop_eventfds_all_mode(struct TestContext *ctx,
+			     uint32_t sync_kloop_mode)
 {
 	int ret;
 
@@ -1375,9 +1383,17 @@ sync_kloop_eventfds_all(struct TestContext *ctx)
 		return ret;
 	}
 
+	ctx->sync_kloop_mode = sync_kloop_mode;
+
 	return sync_kloop_eventfds(ctx);
 }
 
+static int
+sync_kloop_eventfds_all(struct TestContext *ctx)
+{
+	return sync_kloop_eventfds_all_mode(ctx, 0);
+}
+
 static int
 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 {
@@ -1398,6 +1414,27 @@ sync_kloop_eventfds_all_tx(struct TestContext *ctx)
 	return sync_kloop_eventfds(ctx);
 }
 
+static int
+sync_kloop_eventfds_all_direct(struct TestContext *ctx)
+{
+	return sync_kloop_eventfds_all_mode(ctx,
+	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
+}
+
+static int
+sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
+{
+	return sync_kloop_eventfds_all_mode(ctx,
+	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
+}
+
+static int
+sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
+{
+	return sync_kloop_eventfds_all_mode(ctx,
+	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
+}
+
 static int
 sync_kloop_nocsb(struct TestContext *ctx)
 {
@@ -1677,6 +1714,9 @@ static struct mytest tests[] = {
 	decltest(sync_kloop),
 	decltest(sync_kloop_eventfds_all),
 	decltest(sync_kloop_eventfds_all_tx),
+	decltest(sync_kloop_eventfds_all_direct),
+	decltest(sync_kloop_eventfds_all_direct_tx),
+	decltest(sync_kloop_eventfds_all_direct_rx),
 	decltest(sync_kloop_nocsb),
 	decltest(sync_kloop_csb_enable),
 	decltest(sync_kloop_conflict),

From 597052718395aa470a10b8b5eac08b133a7859f2 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 11:54:01 +0100
Subject: [PATCH 1586/2207] README: port to markup language

---
 README    | 316 ------------------------------------------------------
 README.md | 312 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 312 insertions(+), 316 deletions(-)
 delete mode 100644 README
 create mode 100644 README.md

diff --git a/README b/README
deleted file mode 100644
index 5765df7ba..000000000
--- a/README
+++ /dev/null
@@ -1,316 +0,0 @@
-	    Netmap - a framework for fast packet I/O
-	VALE -  a Virtual Local Ethernet using the netmap API
-========================================================================
-
-NETMAP is a framework for very fast packet I/O from userspace.
-VALE is an equally fast in-kernel software switch using the netmap API.
-Both are implemented as a single kernel module for FreeBSD, Linux and
-since summer 2015, also for Windows.
-Netmap/VALE can handle tens of millions of packets per second, matching
-the speed of 10G and 40G ports even with minimum sized frames.
-See details at
-
-	http://info.iet.unipi.it/~luigi/netmap/
-
-This repository, hosted at https://github.com/luigirizzo/netmap , contains
-source code (BSD-Copyright) for FreeBSD, Linux and Windows.
-Note that recent FreeBSD distributions already include both NETMAP and VALE.
-
-A netmap tutorial is avaliable at https://github.com/vmaffione/netmap-tutorial.
-
-
-What is this good for
----------------------
-Netmap is mostly useful for userspace applications that must deal with raw
-packets: traffic generators, sinks, monitors, loggers, software switches
-and routers, generic middleboxes, interconnection of virtual machines.
-
-The example/ directory includes pkt-gen.c (a fast traffic generator/receiver)
-and bridge.c, a simple bidirectional interconnect between two ports.
-The kernel module itself implements a learning ethernet bridge.
-
-More resources are hosted on other repositories. For example
-
-  https://github.com/luigirizzo/netmap-libpcap
-
-    contains a netmap-enabled version of libpcap (which is also
-    included in FreeBSD distribution) so you can run any libpcap client
-    on top of netmap at much higher speeds than using bpf.
-
-  https://github.com/luigirizzo/netmap-ipfw
-
-    is a userspace version of ipfw and dummynet which can handle several
-    million packets per second in a single thread
-
-Qemu/kvm has native netmap support, so it can interconnect VMs at high speed
-through netmap ports. There is experimental netmap support in the FreeBSD's
-bhyve hypervisor.
-
-
-Netmap alone DOES NOT accelerate your TCP. For that you need to implement
-your own tcp/ip stack probably using some of the techniques indicated
-below to reduce the processing costs.
-
-Architecture
-------------
-netmap uses a number of techniques to establish a fast and efficient path
-between applications and the network. In order of importance:
-
-	1. I/O batching
-	2. efficient device drivers
-	3. pre-allocated tx/rx buffers
-	4. memory mapped buffers
-
-Despite the name, memory mapping is NOT the key feature for netmap's
-speed; systems that do not apply all these techniques do not achieve
-the same speed _and_ efficiency.
-
-Netmap clients use a select()-able file descriptor to synchronize
-with the network card/software switch, and exchange multiple packets
-per system call through device-independent memory mapped buffers and
-descriptors. Device drivers are completely in the kernel, and the system
-does not rely on IOMMU or other special mechanisms.
-
-
-Installation instructions
--------------------------
-A single kernel module implements the core NETMAP functions, including
-the VALE switch and access to physical NICS using unmodified device drivers
-(at the price of much lower performance than netmap-aware drivers).
-
-Netmap-aware device drivers are needed to use netmap at high speed
-on ethernet ports.  To date, we have support for Intel ixgbe (10G),
-ixl (10/40G), e1000/e1000e/igb (1G), Realtek 8169 (1G) and Nvidia (1G).
-FreeBSD has also native netmap support in the Chelsio 10/40G cards.
-
-  FreeBSD
-  -------
-  Since recent FreeBSD distributions already include netmap, you only
-  need build the new kernel or modules as below:
-
-  + add 'device netmap' to your kernel config file and rebuild a kernel.
-    This will include the netmap module and netmap support in the device
-    drivers.  Alternatively, you can build standalone modules
-    (netmap, ixgbe, em, lem, re, igb)
-  + sample applications are in the examples/ directory in this archive,
-    or in src/tools/tools/netmap/ in FreeBSD distributions
-
-  Linux
-  -----
-  The ./configure && make build system in the LINUX/
-  directory will let you patch device driver sources and build
-  some netmap-enabled device drivers.
-  Please look at LINUX/README for details.
-
-  + make sure you have kernel headers matching your installed kernel.
-
-  + the sources for e1000e, igb, ixgbe and i40e will be downloaded
-    from the Intel e1000 project on sourceforce.
-
-  + if you need the netmap enabled drivers for e1000, veth, forcedeth,
-    virtio-net or r8169 you will also need the full kernel sources.
-
-  + Configure netmap.
-    To compile NETMAP/VALE and the Intel drivers above: 
-
-	./configure
-
-    (This will also download the Intel driver sources from sourceforce).
-    To compile only NETMAP/VALE (using unmodified drivers):
-
-	./configure --no-drivers # only netmap
-
-    If you need the full kernel sources and you have installed them in
-    /a/b/c/linux-A.B.C/, then you should do
-
-	./configure --kernel-dir=/a/b/c/linux-A.B.C/ # netmap+device drivers
-
-    You can omit --kernel-dir if your kernel sources are in a standard place.
-
-    If you use distribution packages, full sources and headers  may be in
-    different places contain headers (e.g., on debian systems). Use
-
-        ./configure --kernel-sources=/a/b/c/linux-sources-A.B/ \
-		    --kernel-dir=/a/b/c/linux-headers-A.B/
-
-  + build kernel modules and sample applications:
-
-	make
-
-  + (optionally) install the new modules and the applications:
-
-	make install # as root
-   
-    To have the new netmap-enabled driver modules alongside the original
-    ones, you may want to add --driver-suffix=-netmap to the configure
-    command above. The new drivers will then be called e1000e-netmap,
-    ixgbe-netmap and so on.
-
-   WINDOWS
-   -------
-   Netmap has been ported to Windows in summer 2015 by Alessio Faina as part of
-   his Master thesis. Please look at WINDOWS/README.txt for details.
-
-Applications
-------------
-The directory examples/ contains some programs that use the netmap API
-
-    pkt-gen.c	a packet generator/receiver working at line rate at 10Gbit/s
-    vale-cfg.c	utility to configure ports of a VALE switch
-    bridge.c	a utility that bridges two interfaces or one interface
-		with the host stack
-
-For libpcap and other applications look at the extra/ directory.
-
-Testing
--------
-pkt-gen is a generic test program which can act as a sender or receiver.
-It has a large number of options, but the simplest form is:
-
-    pkt-gen -i ix0 -f rx	# receive and print stats
-    pkt-gen -i ix0 -f tx -l 60	# send a stream of 60-byte packets
-
-(replace ix0 with the name of the interface or VALE port).
-This should be able to work at line rate (up to 14.88 Mpps on 10
-Gbit/interfaces, even higher on VALE) but note the following
-
-OPERATING SPEED
----------------
-Netmap is able to send packets at very high rates, and for simple
-packet transmission and reception, speed generally not limited by
-the CPU but by other factors (link speed, bus or NIC hw limitations).
-
-For a physical link, the maximum numer of packets per second can
-be computed with the formula:
-
-	pps = line_rate / (672 + 8 * pkt_size)
-
-where "line_rate" is the nominal link rate (e.g 10 Gbit/s) and
-pkt_size is the actual packet size including MAC headers and CRC.
-The following table summarizes some results (in Mpps)
-
-			LINE RATE
-    pkt_size \	100M	1G	10G	40G
-
-	  64	.1488	1.488	14.88	59.52
-	 128	.0589	0.589	 5.89	23.58
-	 256	.0367	0.367	 3.67	14.70
-	 512	.0209	0.209	 2.09	 8.38
-	1024	.0113	0.113	 1.13	 4.51
-	1518	.0078	0.078	 0.78	 3.12
-
-On VALE ports, there is no physical link and the throughput is
-limited by CPU or memory depending on the packet size.
-
-COMMON PROBLEMS
----------------
-Before reporting slow send or receive speed on a physical interface,
-check ALL of the following:
-
-CANNOT SET THE DEVICE IN NETMAP MODE:
-  + make sure that the netmap module and drivers are correctly
-    loaded and can allocate all the memory they need (check into
-    /var/log/messages or equivalent)
-  + check permissions on /dev/netmap
-  + make sure the interface is up before invoking pkt-gen
-
-SENDER DOES NOT TRANSMIT
-  + some switches/interfaces take a long time to (re)negotiate
-    the link after starting pkt-gen; in case, use the -w N option
-    to increase the initial delay to N seconds;
-
-    	This may cause inability to transmit, or lost packets for
-	the first few seconds of transmission
-
-RECEIVER DOES NOT RECEIVE
-  + make sure traffic uses a broadcast MAC addresses, or the UNICAST
-    address of the receiving interface, or the receiving interface is in
-    promiscuous mode (this must be done with ifconfig; pkt-gen does not
-    change the operating mode)
-
-LOWER SPEED THAN LINE RATE
-  + check that your CPUs are running at the maximum clock rate
-    and are not throttled down by the governor/powerd.
-
-	Linux:
-		lscpu # shows current cpu speed
-		# install cpufrequtils
-		# sudo apt-get install cpufrequtils
-
-
-  + make sure that the sender/receiver interfaces and switch have
-    flow control (FC) disabled (either via sysctl or ethtool).
-
-        If FC is enabled and the receiving end is unable to cope
-	with the traffic, the driver will try to slow down transmission,
-	sometimes to very low rates.
-
-  + a lot of hardware is not able to sustain line rate. For instance,
-    ixgbe has problems with receiving frames that are not multiple
-    of 64 bytes (with/without CRC depending on the driver); also on
-    transmissions, ixgbe tops at about 12.5 Mpps unless the driver
-    prefetches tx descriptors. igb does line rate in all configurations.
-    e1000/e1000e vary between 1.15 and 1.32 Mpps. re/r8169 is
-    extremely slow in sending (max 4-500 Kpps)
-
-HOST RINGS DO NOT WORK
-  + disable NIC offloads, because netmap does not support them and
-    packets exchanged between netmap and the kernel stack can be dropped
-    because of invalid checksums. On FreeBSD offloads can be disabled with
-    a command like
-
-      # ifconfig vtnet0 -txcsum -rxcsum -tso4 -tso6 -lro -txcsum6 -rxcsum6
-
-    See LINUX/README for the corresponding Linux command.
-
-
-Credits
--------
-NETMAP and VALE are projects of the Universita` di Pisa,
-partially supported by various entities including:
-Intel Research Berkeley, EU FP7 projects CHANGE and OPENLAB,
-Netapp/Silicon Valley Community Foundation, ICSI
-
-Author:		Luigi Rizzo
-Contributors:
-		Giuseppe Lettieri
-		Michio Honda
-		Marta Carbone
-		Gaetano Catalli
-		Matteo Landi
-		Vincenzo Maffione
-		Stefano Garzarella
-		Alessio Faina
-
-References
-----------
-There are a few academic papers describing netmap, VALE and applications.
-You can find the papers at http://info.iet.unipi.it/~luigi/research.html
-
-+ Luigi Rizzo,
-	netmap: a novel framework for fast packet I/O,
-	Usenix ATC'12, Boston, June 2012
-
-+ Luigi Rizzo,
-	Revisiting network I/O APIs: the netmap framework,
-	Communications of the ACM 55 (3), 45-51, March 2012
-
-+ Luigi Rizzo, Marta Carbone, Gaetano Catalli,
-	Transparent acceleration of software packet forwarding using netmap,
-	IEEE Infocom 2012, Orlando, March 2012
-
-+ Luigi Rizzo, Giuseppe Lettieri,
-	VALE: a switched ethernet for virtual machines,
-	ACM Conext 2012, Nice, Dec. 2012
-
-+ Luigi Rizzo, Giuseppe Lettieri, Vincenzo Maffione,
-	Speeding up packet I/O in virtual machines,
-	IEEE/ACM ANCS 2013, San Jose, Oct. 2013
-
-+ Stefano Garzarella, Giuseppe Lettieri, Luigi Rizzo,
-	Virtual device passthrough for high speed VM networking
-	IEEE/ACM ANCS 2015, Oakland, May 2015
-
-+ Vincenzo Maffione, Luigi Rizzo, Giuseppe Lettieri,
-	Flexible virtual machine networking using netmap passthrough
-	IEEE Lanman 2016, Rome, June 2016
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..cde91af2a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,312 @@
+# Netmap: a framework for fast packet I/O
+
+## Introduction
+
+Netmap is a framework for very fast packet I/O from userspace.
+VALE is an equally fast in-kernel L2 software switch using the netmap API.
+Both are implemented as a single kernel module for FreeBSD and Linux.
+Netmap/VALE can handle tens of millions of packets per second, matching
+the speed of 10G and 40G ports even with minimum sized frames.
+More information is available at http://info.iet.unipi.it/~luigi/netmap/
+and in the [references](#references).
+
+This repository contains source code (BSD-Copyright) for FreeBSD, Linux and
+Windows.
+Note that recent FreeBSD distributions (>= 10.x) already include both
+Netmap and VALE.
+
+A netmap tutorial is avaliable at https://github.com/vmaffione/netmap-tutorial.
+
+
+## What this is good for
+
+Netmap is mostly useful for userspace applications that must deal with raw
+packets: traffic generators, sinks, monitors, loggers, software switches
+and routers, generic middleboxes, interconnection of virtual machines.
+
+The `apps/` directory includes `pkt-gen.c` (a fast traffic generator/receiver)
+and `bridge.c`, a simple bidirectional interconnect between two ports.
+The kernel module itself implements a learning ethernet bridge.
+
+More resources are hosted on other repositories. For example
+https://github.com/luigirizzo/netmap-libpcap contains a netmap-enabled version
+of libpcap (which is also included in FreeBSD distribution) so you can run
+any libpcap client on top of netmap at much higher speeds than using bpf.
+The https://github.com/luigirizzo/netmap-ipfw repository contains
+a userspace version of ipfw and dummynet which can handle several
+million packets per second in a single thread
+
+QEMU has native netmap support, so it can interconnect VMs at high speed
+through netmap ports. There is experimental netmap support in the FreeBSD's
+bhyve hypervisor.
+
+Netmap alone **does not** accelerate your TCP. For that you need to implement
+your own tcp/ip stack probably using some of the techniques indicated
+below to reduce the processing costs.
+
+## Architecture
+
+netmap uses a number of techniques to establish a fast and efficient path
+between applications and the network. In order of importance:
+
+* I/O batching
+* efficient device drivers
+* pre-allocated tx/rx buffers
+* memory mapped buffers
+
+Despite the name, memory mapping is NOT the key feature for netmap's
+speed; systems that do not apply all these techniques do not achieve
+the same speed _and_ efficiency.
+
+Netmap clients use a select()-able file descriptor to synchronize
+with the network card/software switch, and exchange multiple packets
+per system call through device-independent memory mapped buffers and
+descriptors. Device drivers are completely in the kernel, and the system
+does not rely on IOMMU or other special mechanisms.
+
+
+## Installation instructions
+
+A single kernel module implements the core Netmap functions, including
+the VALE switch and access to physical NICS using unmodified device drivers
+(at the price of much lower performance than netmap-aware drivers).
+
+Netmap-aware device drivers are needed to use netmap at high speed
+on ethernet ports.  To date, we have support for Intel ixgbe (10G),
+ixl (10/40G), e1000/e1000e/igb (1G), Realtek 8169 (1G) and Nvidia (1G).
+FreeBSD has also native netmap support in the Chelsio 10/40G cards.
+
+### FreeBSD
+Since recent FreeBSD distributions already include netmap, you only
+need build the new kernel or modules as below:
+
+* add 'device netmap' to your kernel config file and rebuild a kernel.
+  This will include the netmap module and netmap support in the device
+  drivers.  Alternatively, you can build standalone modules
+  (netmap, ixgbe, em, lem, re, igb)
+* sample applications are in the `apps/` directory in this repository,
+  or in `src/tools/tools/netmap/` in FreeBSD distributions
+
+
+### Linux
+
+The `./configure && make` build system in the LINUX/
+directory will let you patch device driver sources and build
+some netmap-enabled device drivers.
+Please look at `LINUX/README.md` for details.
+
+Make sure you have kernel headers matching your installed kernel.
+The sources for e1000e, igb, ixgbe and i40e will be downloaded
+from the Intel e1000 project on sourceforce.
+If you need the netmap enabled drivers for e1000, veth, forcedeth,
+virtio-net or r8169 you will also need the full kernel sources.
+
+#### Step 1
+
+Configure netmap. To compile Netmap/VALE and the Intel drivers above:
+
+	./configure
+
+(This will also download the Intel driver sources from sourceforce).
+To compile only Netmap/VALE (using unmodified drivers):
+
+	./configure --no-drivers # only netmap, no unmodified drivers
+
+If you need the full kernel sources and you have installed them in
+/a/b/c/linux-A.B.C/, then you should do
+
+	./configure --kernel-dir=/a/b/c/linux-A.B.C/ # netmap+device drivers
+
+You can omit --kernel-dir if your kernel sources are in a standard place.
+
+If you use distribution packages, full sources and headers  may be in
+different places contain headers (e.g., on debian systems). Use
+
+	./configure --kernel-sources=/a/b/c/linux-sources-A.B/ --kernel-dir=/a/b/c/linux-headers-A.B/
+
+#### Step 2
+
+Build kernel modules and sample applications:
+
+	make
+
+#### Step 3
+
+Install the new modules and the applications:
+
+	sudo make install
+
+To have the new netmap-enabled driver modules alongside the original
+ones, you may want to add `--driver-suffix=-netmap` to the configure
+command above. The new drivers will then be called `e1000e-netmap`,
+`ixgbe-netmap`, and so on.
+
+### Windows
+
+Netmap has been ported to Windows in summer 2015 by Alessio Faina as part of
+his Master thesis. Please look at `WINDOWS/README.txt` for details.
+
+## Applications
+
+The directory `apps/` contains some programs that use the netmap API
+
+* `pkt-gen.c`	a packet generator/receiver working at line rate at 10Gbit/s
+* `vale-ctl.c`	utility to configure ports of a VALE switch
+* `bridge.c`	a utility that bridges two interfaces or one interface
+		with the host stack
+
+For libpcap and other applications look at the extra/ directory.
+
+## Testing
+
+`pkt-gen` is a generic test program which can act as a sender or receiver.
+It has a large number of options, but the simplest form is:
+
+    pkt-gen -i ix0 -f rx	# receive and print stats
+    pkt-gen -i ix0 -f tx -l 60	# send a stream of 60-byte packets
+
+(replace ix0 with the name of the interface or VALE port).
+This should be able to work at line rate (up to 14.88 Mpps on 10
+Gbit/interfaces, even higher on VALE) but note the following
+
+## Operating Speed
+
+Netmap is able to send packets at very high rates, and for simple
+packet transmission and reception, speed generally not limited by
+the CPU but by other factors (link speed, bus or NIC hw limitations).
+
+For a physical link, the maximum numer of packets per second can
+be computed with the formula:
+
+	pps = line_rate / (672 + 8 * pkt_size)
+
+where "line_rate" is the nominal link rate (e.g 10 Gbit/s) and
+pkt_size is the actual packet size including MAC headers and CRC.
+The following table summarizes some results (in Mpps)
+
+			LINE RATE
+    pkt_size 	100M	1G	10G	40G
+
+          64	.1488	1.488	14.88	59.52
+         128	.0589	0.589	 5.89	23.58
+         256	.0367	0.367	 3.67	14.70
+         512	.0209	0.209	 2.09	 8.38
+        1024	.0113	0.113	 1.13	 4.51
+        1518	.0078	0.078	 0.78	 3.12
+
+On VALE ports, there is no physical link and the throughput is
+limited by CPU or memory depending on the packet size.
+
+## Common problems
+
+Before reporting slow send or receive speed on a physical interface,
+check ALL of the following:
+
+### Cannot set the device in netmap mode:
+* make sure that the netmap module and drivers are correctly
+    loaded and can allocate all the memory they need (check into
+    /var/log/messages or equivalent)
+* check permissions on `/dev/netmap`
+* make sure the interface is up before invoking `pkt-gen`
+
+### Sender does not transmit
+* some switches/interfaces take a long time to (re)negotiate
+the link after starting `pkt-gen`; in case, use the -w N option
+to increase the initial delay to N seconds;
+
+This may cause inability to transmit, or lost packets for
+the first few seconds of transmission
+
+### Receiver does not receive
+* make sure traffic uses a broadcast MAC addresses, or the UNICAST
+address of the receiving interface, or the receiving interface is in
+promiscuous mode (this must be done with ifconfig; `pkt-gen` does not
+change the operating mode)
+
+### Lower speed than line rate
+* check that your CPUs are running at the maximum clock rate
+and are not throttled down by the governor/powerd.
+On Linux:
+
+	lscpu # shows current cpu speed
+	sudo apt-get install cpufrequtils
+
+* make sure that the sender/receiver interfaces and switch have
+flow control (FC) disabled (either via sysctl or ethtool).
+If FC is enabled and the receiving end is unable to cope
+with the traffic, the driver will try to slow down transmission,
+sometimes to very low rates.
+
+* a lot of hardware is not able to sustain line rate. For instance,
+ixgbe has problems with receiving frames that are not multiple
+of 64 bytes (with/without CRC depending on the driver); also on
+transmissions, ixgbe tops at about 12.5 Mpps unless the driver
+prefetches tx descriptors. igb does line rate in all configurations.
+e1000/e1000e vary between 1.15 and 1.32 Mpps. re/r8169 is
+extremely slow in sending (max 4-500 Kpps)
+
+### Host rings do not work
+
+* disable NIC offloads, because netmap does not support them and
+packets exchanged between netmap and the kernel stack can be dropped
+because of invalid checksums. On FreeBSD offloads can be disabled with
+a command like
+
+	sudo ifconfig vtnet0 -txcsum -rxcsum -tso4 -tso6 -lro -txcsum6 -rxcsum6
+
+See `LINUX/README.md` for the corresponding Linux command.
+
+
+## Credits
+
+Netmap and VALE are projects of the Universita` di Pisa,
+partially supported by various entities including:
+Intel Research Berkeley, EU FP7 projects CHANGE and OPENLAB,
+Netapp/Silicon Valley Community Foundation, ICSI
+
+Authors:
+* Luigi Rizzo
+
+Contributors (https://github.com/netmap-unipi/netmap/graphs/contributors):
+
+* Giuseppe Lettieri
+* Michio Honda
+* Marta Carbone
+* Gaetano Catalli
+* Matteo Landi
+* Vincenzo Maffione
+* Stefano Garzarella
+* Alessio Faina
+
+## References
+
+There are a few academic papers describing netmap, VALE and applications.
+You can find the papers at http://info.iet.unipi.it/~luigi/research.html
+
+* Luigi Rizzo,
+	netmap: a novel framework for fast packet I/O,
+	Usenix ATC'12, Boston, June 2012
+
+* Luigi Rizzo,
+	Revisiting network I/O APIs: the netmap framework,
+	Communications of the ACM 55 (3), 45-51, March 2012
+
+* Luigi Rizzo, Marta Carbone, Gaetano Catalli,
+	Transparent acceleration of software packet forwarding using netmap,
+	IEEE Infocom 2012, Orlando, March 2012
+
+* Luigi Rizzo, Giuseppe Lettieri,
+	VALE: a switched ethernet for virtual machines,
+	ACM Conext 2012, Nice, Dec. 2012
+
+* Luigi Rizzo, Giuseppe Lettieri, Vincenzo Maffione,
+	Speeding up packet I/O in virtual machines,
+	IEEE/ACM ANCS 2013, San Jose, Oct. 2013
+
+* Stefano Garzarella, Giuseppe Lettieri, Luigi Rizzo,
+	Virtual device passthrough for high speed VM networking
+	IEEE/ACM ANCS 2015, Oakland, May 2015
+
+* Vincenzo Maffione, Luigi Rizzo, Giuseppe Lettieri,
+	Flexible virtual machine networking using netmap passthrough
+	IEEE Lanman 2016, Rome, June 2016

From e078da252656159e372d2eac2376f1fac3e5ded6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 12:44:16 +0100
Subject: [PATCH 1587/2207] README/LINUX: port to markup language

---
 LINUX/README    | 324 ------------------------------------------------
 LINUX/README.md | 283 ++++++++++++++++++++++++++++++++++++++++++
 README.md       |  33 ++---
 3 files changed, 301 insertions(+), 339 deletions(-)
 delete mode 100644 LINUX/README
 create mode 100644 LINUX/README.md

diff --git a/LINUX/README b/LINUX/README
deleted file mode 100644
index 181d5cce5..000000000
--- a/LINUX/README
+++ /dev/null
@@ -1,324 +0,0 @@
-# $Id: README 10863 2012-04-11 17:10:39Z luigi $
-
-NETMAP FOR LINUX
-----------------
-
-This directory contains a version of the "netmap" and "VALE" code for Linux.
-
-Netmap is a BSD-licensed framework that supports line-rate direct packet
-I/O even on 10GBit/s interfaces (14.88Mpps) with limited system load,
-and includes a libpcap emulation library to port applications.
-
-See
-
-	http://info.iet.unipi.it/~luigi/netmap/
-
-for more details. There you can also find the latest versions
-of the code and documentation as well as pre-built TinyCore
-images based on linux 3.0.3 and containing the netmap modules
-and some test applications.
-
-This version supports r8169, ixgbe, igb, i40e, e1000, e1000e and
-forcedeth.
-
-Netmap relies on a kernel module (netmap.ko) and slightly modified
-device drivers. Userspace programs can use the native API (documented
-in netmap.4) or a libpcap emulation library.
-
-The FreeBSD and Linux versions share the same codebase, which
-is located in ../sys . For Linux we use some additional glue code,
-(bsd_glue.h).
-
-Device drivers are taken directly from either the Linux distributions,
-or the Intel out-of-tree drivers, and patched using the files in
-the patches/ directory.  Common driver modifications are in the .h
-files in this directory. Note that the patches for e1000, forcedeth,
-virtio-net have been prepared on the vanilla kernel: this is usually
-sufficient for Debian/Ubuntu, but it often fails on Red Hat/CentOS.
-The patches for igb, e1000e, ixgbe and i40e, instead, are against
-a specific version of the out-of-tree Intel drivers, and should compile
-without any problem on the same systems where the original drivers do.
-
-Linux distributions used and tested
------------------------------------
-
-Development:
-	Ubuntu 16.04.1 LTS (tested on kernel 4.4.0-53-generic)
-	Archlinux (tested on the 4.8.x vanilla kernel provided by Arch)
-
-Supported for general compatibility:
-	Ubuntu 16.10 (tested on kernel 4.8.0-30-generic)
-	CentOS 7     (tested on kernel 3.10.0-514.2.2.el7.x86_64)
-
-On Archlinux systems the netmap software is provided by the 'netmap'
-AUR package (https://aur.archlinux.org/packages/netmap/).  In general,
-you can build and install netmap following the instruction in 'HOW TO
-BUILD THE CODE'.
-
-HOW TO BUILD THE CODE
----------------------
-
-The netmap port for linux is built and installed using the standard
-./configure; make; sudo make install workflow.
-
-The main purpose of the configure script is to determine the features of
-your kernel using simple compile tests, since just trusting the kernel
-version number is unreliable. The outcomes of the tests are stored in
-a set of macros in the generated netmap_linux_config.h file.
-
-The configure script also controls the compilation of optional netmap
-features, namely:
-
-  netmap subsystems
-  -----------------
-
-  These are optional parts of netmap that can be compiled in with
-  --enable-SUBSYSTEM and commented out with --disable-SUBSYSTEM.
-  The available subsystems the following (the starred ones are enabled
-  by default):
-
-    vale (*):		the VALE switch (a fast switch that uses
-			the netmap API).
-
-    pipe (*):		netmap pipes (pairs of netmap ports connected
-			back to back).
-
-    monitor (*):	netmap monitors (can monitor other netmap ports
-			in copy and zero-copy modes, without stopping
-			traffic).
-
-    generic (*):	the generic (a.k.a. emulated) netmap adapter that is
-			used to access NICs without native netmap support (at
-			reduced performance).
-
-    ptnetmap:		netmap passthrough support for guests
-			(including the ptnet driver).
-
-    sink:		a dummy drop-everything device with native netmap
-			support.  It can emulate a link with configurable
-			packet rate.
-
-  NIC drivers
-  --------------
-
-  The emulated (generic) adapter can be used to open in netmap mode any NIC
-  for which the host OS already supplies a driver. The optimal performance,
-  however, is only obtained with netmap-enabled NIC drivers.  The configure
-  script implements two methods to obtain the netmap-enabled drivers:
-
-	1. patching the native drivers that come with your kernel;
-	2. patching NIC-vendors out-of-tree drivers selected by us.
-
-  Both methods have advantages and drawbacks and none is perfect.
-  In method 1 the patches we supply may fail to apply (especially on
-  Red Hat based distributions), but compilation of successfully patched
-  drivers usually works. In method 2 the patches will be guaranteed to
-  apply, but compilation may fail since the out-of-tree drivers may
-  not support your kernel.
-
-  By default e1000e, i40e, ixgbe, ixgbevf and igb use method 2, while
-  e1000, r8169.c, forcedeth.c, veth.c and virtio_net.c drivers use method
-  1. The list of supported drivers can be obtained by running configure
-  with the --show-drivers option, while --show-ext-drivers lists the
-  drivers that use method 2 by default. For the latter drivers you may
-  also choose to use method 1 using the --no-ext-drivers (use method
-  1 for everything) or --no-ext-drivers= followed by a comma separated
-  list of drivers.
-
-  For method 1 you need the driver sources for your kernel.
-
-	- If you have built your own kernel, you need to tell configure
-	  where the kernel build directory is using the --kernel-dir=
-	  option. The build directory must have been prepared for external
-	  modules compilation.
-
-	- If you are using the kernel provided by your Linux distribution
-	  you need to install the full kernel-sources package (how to do
-	  so depends on the distribution).  Note that, even when you have
-	  installed the sources, configure will automatically find them
-	  only if they are pointed to by /lib/modules/$(uname -r)/build
-	  or /lib/modules/$(uname -r)/build/sources. If the sources are
-	  anywhere else, you need to tell configure where to find them
-	  using the --kernel-sources= options. The --kernel-dir= option
-	  must still point to a directory where all the information for
-	  external module compilation is available and there is typically
-	  no need to supply it, since configure is already able to find
-	  it in the standard place.
-
-  The configure script selects the patch to apply based only on the
-  kernel version. Moreover, we only supply patches for the vanilla kernel
-  from the Torvalds repository (not even the stable kernels). If the
-  patch selected by configure for a driver fails to apply, the driver
-  is disabled and will not be built my make.
-
-  For method 2 you need an Internet connection, since the external drivers
-  are downloaded by configure from the vendor repository.  Otherwise,
-  follow the instructions printed by the script.  The configure script
-  will try to build the original external driver before applying the
-  netmap patches: if the clean build fails then the vendor driver does
-  not support your kernel (yet?) and the driver is disabled.
-
-  If you want support for additional drivers please have a look at
-  ixgbe_netmap_linux.h and the patches in patches/ The patch file are
-  named as vanilla--DRIVER--LOW--HIGH where DRIVER is the driver name
-  to patch, LOW and HIGH are the versions to which the patch applies
-  (LOW included, HIGH excluded, so vanilla--r8169.c--20638--30300 applies
-  from 2.6.38 to 3.3.0 (excluded).
-
-  The patches for the external drivers are named VENDOR--DRIVER--VERSION,
-  where VENDOR is just intel as of now, and VERSION is the upstream driver
-  version number (assigned by the VENDOR). If you want to use a different
-  VERSION than the default, and the patches directory contains a patch
-  for the version you are interest in, you can use the --select-version
-  option of configure. E.g., to select the 5.2.4 version of the ixgbe
-  external driver, pass --select-version=ixgbe:5.2.4 to configure.
-
-HOW TO USE THE CODE
--------------------
-
-    REMEMBER
-	THIS IS EXPERIMENTAL CODE WHICH MAY CRASH YOUR SYSTEM.
-	USE IT AT YOUR OWN RISk.
-
-Whether you built your own modules, or are using the prebuilt
-TinyCore image, the following steps can be used for initial testing:
-
-1. unload any modules for the network cards you want to use, e.g.
-	sudo rmmod ixgbe
-	sudo rmmod e1000
-	...
-
-2. load netmap and device driver module
-	sudo insmod ./netmap.ko
-	sudo insmod ./ixgbe/ixgbe.ko
-	sudo insmod ./e1000/e1000.ko
-	...
-
-3. turn the interface(s) up
-
-	sudo ifconfig eth0 up # and same for others
-
-4. Run test applications -- as an example, pkt-gen is a raw packet
-   sender/receiver which can do line rate on a 10G interface
-
-	# send about 500 million packets of 60 bytes each.
-	# wait 5s before starting, so the link can go up
-	sudo pkt-gen -i eth0 -f tx -n 500111222 -l 60 -w 5
-	# you should see about 14.88 Mpps
-
-	sudo pkt-gen -i eth0 -f rx # act as a receiver
-
-
-COMMON PROBLEMS
-----------------
-
-* switching in/out of netmap mode causes the link to go down and up.
-  If your card is connected to a switch with spanning tree enabled,
-  the switch will likely MUTE THE LINK FOR 10 SECONDS while it is
-  detecting the new topology. Either disable the spanning tree on
-  the switch or use long pauses before sending data;
-
-* Not all cards can do line rate no matter how fast is your software or
-  CPU. Several have hardware limitations that prevent reaching the peak
-  speed, especially for small packet sizes. Examples:
-
-  - ixgbe cannot receive at line rate with packet sizes that are
-    not multiple of 64 (after CRC stripping).
-    This is especially evident with minimum-sized frames (-l 60 )
-
-  - some of the low-end 'e1000' cards can send 1.2 - 1.3Mpps instead
-    of the theoretical maximum (1.488Mpps)
-
-  - the 'realtek' cards seem unable to send more than 450-500Kpps
-    even though they can receive at least 1.1Mpps
-
-* if the link is not up when the packet generator starts, you will
-  see frequent messages about a link reset. While we work on a fix,
-  use the '-w' argument on the generator to specify a longer timeout
-
-* the ixgbe driver (and perhaps others) is severely slowed down if the
-  remote party is sending flow control frames to slow down traffic.
-  If that happens try to use the ethtool command to disable flow control.
-
-* netmap does not program the NICs to perform offloadings such as TSO,
-  UFO, RX/TX checksum offloadings, etc. As a result, in order to let
-  netmap applications correctly interact with the host rings, you need
-  to disable these offloadings
-
-      # ethtool -K eth0 tx off rx off gso off tso off gro off lro off
-
-  If offloadings are not disabled, the network stack may try to send
-  GSO packets (up to 64KB) that are dropped by netmap (as they are
-  too big for the netmap buffers); or the network stack could send
-  unchecksummed packets that end up in the host RX ring, and if
-  transmitted by netmap on a NIC TX ring they will be dropped by the
-  destination as the checksum is wrong.
-
-* if you are using netmap to implement an L2 switch (e.g. using the
-  bridge application), you must put the NIC in promiscuous mode,
-  otherwise the NIC (usually) drops all the frames whose destination
-  MAC is different from the MAC of the NIC.
-
-      # ip link set eth0 promisc on
-
-  Some drivers (e.g. the netmap-patched i40e) may disable promiscuous
-  mode during the down/up cycle that happens when putting the NIC
-  in netmap mode. This means that it may be necessary to enable
-  promiscuous mode again after starting the netmap application.
-  If the promiscuous mode was already enabled, you may need to
-  disable it before enabling it again. For these drivers, start the
-  application first, and then execute these commands:
-
-      # ip link set eth0 promisc off
-      # ip link set eth0 promisc on
-
-  or incorporate equivalent operations in your application.
-
-* if you are receiving VLAN-tagged packets, netmap applications (with
-  patched drivers) may not see the VLAN tag because receive VLAN offloading
-  is enabled (and so VLAN tags are stripped by the NIC). To disable it use
-
-      # ethtool -K eth0 rxvlan off
-
-  In emulated netmap mode (i.e. with unpatched drivers) VLAN tags are never
-  visible by the netmap application.
-
-* When opening a veth interface in native netmap mode, the peer veth interface
-  must also be opened in native netmap mode, otherwise the traffic won't flow.
-  In other words, one cannot use native netmap mode on a veth endpoint and
-  use the kernel network stack on the other endpoint. This is not a missing
-  feature, as the native veth datapath is implemented using netmap pipes, and
-  it does not make sense (in terms of performance) for pipes to support
-  conversion betweeen netmap buffers and skbuffs.
-
-REVISION HISTORY
------------------
-
-20120813 - updated distribution using common code for FreeBSD and Linux,
-	and inclusion of drivers from the linux source tree
-
-20120322 - fixed the 'igb' driver, now it can send and receive correctly
-	(the problem was in netmap_rx_irq() so it might have affected
-	other multiqueue cards).
-	Also tested the 'r8169' in transmit mode.
-	Added comments on switches and spanning tree.
-
-20120217 - initial version. Only ixgbe, e1000 and e1000e are working.
-	Other drivers (igb, r8169, forcedeth) are supplied only as a
-	proof of concept.
-
-DETAILS
---------
-+ igb: on linux 3.2 and above the igb driver moved to split buffers,
-  and netmap was not updated until end of june 2013.
-  Symptoms were inability to receive short packets.
-
-+ there are reports of ixgbe and igb unable to read packets.
-  We are unable to reproduce the problem.
-  - Ubuntu 12.04 LTS 3.5.0-25-generic. igb read problems ?
-  - 3.2.0-32-generic with 82598 not working
-
-+ if_e1000_e uses regular descriptor up 3.1 at least
-  3.2.32 is reported to use extended descriptors
-	(in my repo updated at -r 11975)
-
diff --git a/LINUX/README.md b/LINUX/README.md
new file mode 100644
index 000000000..1a76d0a19
--- /dev/null
+++ b/LINUX/README.md
@@ -0,0 +1,283 @@
+# Netmap for Linux
+
+This file contains instructions on how to build, install and use Netmap
+on Linux.
+This directory contains Linux-specific code to let netmap work on
+Linux.
+Native support is available for r8169, ixgbe, igb, i40e, e1000, e1000e,
+virtio-net, and forcedeth Linux drivers.
+
+Netmap relies on a kernel module (`netmap.ko`) and modified
+device drivers. Userspace programs can use the native API (documented
+in `netmap.4`) or a libpcap emulation library.
+
+Most of the codebase is shared between FreeBSD and Linux, and it
+is located in `sys/` in the root directory of this repository.
+For Linux we use some additional glue code, (`bsd_glue.h`, in this
+directory).
+
+Device drivers are taken directly from either the Linux distributions
+or vendor-provided out-of-tree drivers, and patched using the files in
+the patches/ directory.  Common driver modifications are in the .h
+files in this directory. Note that the patches for e1000, forcedeth,
+virtio-net have been prepared on the vanilla kernel: this is usually
+sufficient for Debian/Ubuntu, but it often fails on Red Hat/CentOS.
+The patches for igb, e1000e, ixgbe and i40e, instead, are against
+a specific version of the out-of-tree Intel drivers, and should compile
+without any problem on the same systems where the original drivers do.
+
+## Linux distributions used and tested
+
+Development:
+
+* Ubuntu 16.04.1 LTS (tested on kernel `4.4.0-53-generic`)
+* Archlinux (tested on the `4.8.x` vanilla kernel provided by Arch)
+
+Supported for general compatibility:
+
+* Ubuntu 16.10 (tested on kernel `4.8.0-30-generic`)
+* CentOS 7     (tested on kernel `3.10.0-514.2.2.el7.x86_64`)
+
+On Archlinux systems the netmap software is provided by the 'netmap'
+AUR package (https://aur.archlinux.org/packages/netmap/).  In general,
+you can build and install netmap on any distribution, by following the
+instruction in reported in the following [section](#how-to-build-the-code).
+
+## How to build the code
+
+The netmap port for linux is built and installed using the standard
+`./configure && make && sudo make install` workflow.
+
+The main purpose of the configure script is to determine the features of
+your kernel using simple compile tests, since just trusting the kernel
+version number is unreliable. The outcomes of the tests are stored in
+a set of macros in the generated `netmap_linux_config.h` file.
+
+The configure script also controls the compilation of optional netmap
+features, namely [netmap subsystems](#netmap-subsystems).
+
+### Netmap subsystems
+
+These are optional parts of netmap that can be compiled in with
+`--enable-SUBSYSTEM` and ruled out with `--disable-SUBSYSTEM`.
+The available subsystems the following (the starred ones are enabled
+by default):
+
+* **vale** (\*): the VALE L2 switch (a fast switch that uses the netmap API).
+* **pipe** (\*): netmap pipes (pairs of netmap virtual ports connected back to back).
+* **monitor** (\*): netmap monitors (can monitor other netmap ports in copy
+and zero-copy modes, without stopping traffic).
+* **generic** (\*): the generic (a.k.a. emulated) netmap adapter that is
+used to access NICs without native netmap support (at reduced performance).
+* **ptnetmap** (\*): netmap passthrough support for guests (including the ptnet
+driver).
+* **sink**: a dummy drop-everything device with native netmap support.
+It can emulate a link with configurable packet rate.
+
+### NIC drivers
+
+The emulated (generic) adapter can be used to open in netmap mode any NIC
+for which the host OS already supplies a driver. The optimal performance,
+however, is only obtained with netmap-enabled NIC drivers.  The configure
+script implements two methods to obtain the netmap-enabled drivers:
+
+1. patching the native drivers that come with your kernel;
+2. patching NIC-vendors out-of-tree drivers selected by us.
+
+Both methods have advantages and drawbacks and none is perfect.
+In method 1 the patches we supply may fail to apply (especially on
+Red Hat based distributions), but compilation of successfully patched
+drivers usually works. In method 2 the patches will be guaranteed to
+apply, but compilation may fail since the out-of-tree drivers may
+not support your kernel.
+
+By default `e1000e`, `i40e`, `ixgbe`, `ixgbevf` and igb use method 2,
+while `e1000`, `r8169.c`, `forcedeth.c`, `veth.c` and `virtio_net.c`
+drivers use method 1\.
+The list of supported drivers can be obtained by running configure
+with the `--show-drivers` option, while `--show-ext-drivers` lists the
+drivers that use method 2 by default. For the latter drivers you may
+also choose to use method 1 using the `--no-ext-drivers` (use method
+1 for everything) or `--no-ext-drivers=` followed by a comma separated
+list of drivers.
+
+For method 1 you need the driver sources for your kernel.
+
+* If you have built your own kernel, you need to tell configure
+where the kernel build directory is using the `--kernel-dir=`
+option. The build directory must have been prepared for external
+modules compilation.
+
+* If you are using the kernel provided by your Linux distribution
+you need to install the full kernel-sources package (how to do
+so depends on the distribution).  Note that, even when you have
+installed the sources, configure will automatically find them
+only if they are pointed to by /lib/modules/$(uname -r)/build
+or /lib/modules/$(uname -r)/build/sources. If the sources are
+anywhere else, you need to tell configure where to find them
+using the `--kernel-sources=` options. The `--kernel-dir=` option
+must still point to a directory where all the information for
+external module compilation is available and there is typically
+no need to supply it, since configure is already able to find
+it in the standard place.
+
+The configure script selects the patch to apply based only on the
+kernel version. Moreover, we only supply patches for the vanilla kernel
+from the Torvalds repository (not even the stable kernels). If the
+patch selected by configure for a driver fails to apply, the driver
+is disabled and will not be built my make.
+
+For method 2 you need an Internet connection, since the external drivers
+are downloaded by configure from the vendor repository.  Otherwise,
+follow the instructions printed by the script.  The configure script
+will try to build the original external driver before applying the
+netmap patches: if the clean build fails then the vendor driver does
+not support your kernel (yet?) and the driver is disabled.
+
+If you want support for additional drivers please have a look at
+`ixgbe_netmap_linux.h` and the patches in patches/ The patch file are
+named as `vanilla--DRIVER--LOW--HIGH` where DRIVER is the driver name
+to patch, LOW and HIGH are the versions to which the patch applies
+(LOW included, HIGH excluded, so `vanilla--r8169.c--20638--30300` applies
+from 2.6.38 to 3.3.0 (excluded).
+
+The patches for the external drivers are named VENDOR--DRIVER--VERSION,
+where VENDOR is just intel as of now, and VERSION is the upstream driver
+version number (assigned by the VENDOR). If you want to use a different
+VERSION than the default, and the patches directory contains a patch
+for the version you are interest in, you can use the `--select-version`
+option of configure. E.g., to select the 5.2.4 version of the ixgbe
+external driver, pass `--select-version=ixgbe:5.2.4` to configure.
+
+## How to use the code
+
+Disclaimer: _This is experimental code which may crash your system.
+use it at your own risk._
+
+The following steps can be used for initial testing.
+Unload any modules for the network cards you want to use, e.g.
+
+	sudo rmmod ixgbe
+	sudo rmmod e1000
+	...
+
+Load netmap and device driver module
+
+	sudo insmod ./netmap.ko
+	sudo insmod ./ixgbe/ixgbe.ko
+	sudo insmod ./e1000/e1000.ko
+	...
+
+Turn the interface(s) up
+
+	sudo ifconfig eth0 up # and same for others
+
+Run test applications -- as an example, pkt-gen is a raw packet
+sender/receiver which can do line rate on a 10G interface.
+
+Send about 500 million packets of 60 bytes each.
+wait 5s before starting, so the link can go up
+
+	sudo pkt-gen -i eth0 -f tx -n 500111222 -l 60 -w 5
+
+On the receiver, you should see about 14.88 Mpps
+
+	sudo pkt-gen -i eth0 -f rx # act as a receiver
+
+
+## Common problems
+
+* switching in/out of netmap mode causes the link to go down and up.
+  If your card is connected to a switch with spanning tree enabled,
+  the switch will likely MUTE THE LINK FOR 10 SECONDS while it is
+  detecting the new topology. Either disable the spanning tree on
+  the switch or use long pauses before sending data;
+
+* Not all cards can do line rate no matter how fast is your software or
+  CPU. Several have hardware limitations that prevent reaching the peak
+  speed, especially for small packet sizes. Examples:
+
+  - ixgbe cannot receive at line rate with packet sizes that are
+    not multiple of 64 (after CRC stripping).
+    This is especially evident with minimum-sized frames (-l 60 )
+
+  - some of the low-end 'e1000' cards can send 1.2 - 1.3Mpps instead
+    of the theoretical maximum (1.488Mpps)
+
+  - the 'realtek' cards seem unable to send more than 450-500Kpps
+    even though they can receive at least 1.1Mpps
+
+* if the link is not up when the packet generator starts, you will
+  see frequent messages about a link reset. While we work on a fix,
+  use the '-w' argument on the generator to specify a longer timeout
+
+* the ixgbe driver (and perhaps others) is severely slowed down if the
+  remote party is sending flow control frames to slow down traffic.
+  If that happens try to use the ethtool command to disable flow control.
+
+* netmap does not program the NICs to perform offloadings such as TSO,
+  UFO, RX/TX checksum offloadings, etc. As a result, in order to let
+  netmap applications correctly interact with the host rings, you need
+  to disable these offloadings
+
+      # ethtool -K eth0 tx off rx off gso off tso off gro off lro off
+
+  If offloadings are not disabled, the network stack may try to send
+  GSO packets (up to 64KB) that are dropped by netmap (as they are
+  too big for the netmap buffers); or the network stack could send
+  unchecksummed packets that end up in the host RX ring, and if
+  transmitted by netmap on a NIC TX ring they will be dropped by the
+  destination as the checksum is wrong.
+
+* if you are using netmap to implement an L2 switch (e.g. using the
+  bridge application), you must put the NIC in promiscuous mode,
+  otherwise the NIC (usually) drops all the frames whose destination
+  MAC is different from the MAC of the NIC.
+
+      # ip link set eth0 promisc on
+
+  Some drivers (e.g. the netmap-patched i40e) may disable promiscuous
+  mode during the down/up cycle that happens when putting the NIC
+  in netmap mode. This means that it may be necessary to enable
+  promiscuous mode again after starting the netmap application.
+  If the promiscuous mode was already enabled, you may need to
+  disable it before enabling it again. For these drivers, start the
+  application first, and then execute these commands:
+
+      # ip link set eth0 promisc off
+      # ip link set eth0 promisc on
+
+  or incorporate equivalent operations in your application.
+
+* if you are receiving VLAN-tagged packets, netmap applications (with
+  patched drivers) may not see the VLAN tag because receive VLAN offloading
+  is enabled (and so VLAN tags are stripped by the NIC). To disable it use
+
+      # ethtool -K eth0 rxvlan off
+
+  In emulated netmap mode (i.e. with unpatched drivers) VLAN tags are never
+  visible by the netmap application.
+
+* When opening a veth interface in native netmap mode, the peer veth interface
+  must also be opened in native netmap mode, otherwise the traffic won't flow.
+  In other words, one cannot use native netmap mode on a veth endpoint and
+  use the kernel network stack on the other endpoint. This is not a missing
+  feature, as the native veth datapath is implemented using netmap pipes, and
+  it does not make sense (in terms of performance) for pipes to support
+  conversion betweeen netmap buffers and skbuffs.
+
+
+## Additional information
+
+* igb: on linux 3.2 and above the igb driver moved to split buffers,
+  and netmap was not updated until end of june 2013.
+  Symptoms were inability to receive short packets.
+
+* there are reports of ixgbe and igb unable to read packets.
+  We are unable to reproduce the problem.
+  - Ubuntu 12.04 LTS 3.5.0-25-generic. igb read problems ?
+  - 3.2.0-32-generic with 82598 not working
+
+* e1000e uses regular descriptor up 3.1 at least
+  3.2.32 is reported to use extended descriptors
+	(in my repo updated at -r 11975)
diff --git a/README.md b/README.md
index cde91af2a..990864e2f 100644
--- a/README.md
+++ b/README.md
@@ -2,23 +2,26 @@
 
 ## Introduction
 
-Netmap is a framework for very fast packet I/O from userspace.
+Netmap is a an framework for very fast packet I/O from userspace.
 VALE is an equally fast in-kernel L2 software switch using the netmap API.
 Both are implemented as a single kernel module for FreeBSD and Linux.
 Netmap/VALE can handle tens of millions of packets per second, matching
 the speed of 10G and 40G ports even with minimum sized frames.
-More information is available at http://info.iet.unipi.it/~luigi/netmap/
-and in the [references](#references).
+
+To learn about netmap, you can use the following resources:
+
+* the man pages (https://www.freebsd.org/cgi/man.cgi?query=netmap&sektion=4 or
+`share/man/man4/netmap.4` in this repository)
+* the [papers](#references).
+* the tutorials, available at https://github.com/netmap-unipi/netmap-tutorial
 
 This repository contains source code (BSD-Copyright) for FreeBSD, Linux and
 Windows.
 Note that recent FreeBSD distributions (>= 10.x) already include both
 Netmap and VALE.
 
-A netmap tutorial is avaliable at https://github.com/vmaffione/netmap-tutorial.
-
 
-## What this is good for
+## Why should I use netmap?
 
 Netmap is mostly useful for userspace applications that must deal with raw
 packets: traffic generators, sinks, monitors, loggers, software switches
@@ -77,15 +80,15 @@ ixl (10/40G), e1000/e1000e/igb (1G), Realtek 8169 (1G) and Nvidia (1G).
 FreeBSD has also native netmap support in the Chelsio 10/40G cards.
 
 ### FreeBSD
-Since recent FreeBSD distributions already include netmap, you only
-need build the new kernel or modules as below:
+FreeBSD already includes netmap kernel support by
+default since version 11.
+If your kernel configuration does not include netmap, you can enable it
+by adding a `dev netmap` line, and rebuilding the kernel.
+Alternatively, you can build standalone modules (netmap, ixgbe, em, lem,
+re, igb, ...).
 
-* add 'device netmap' to your kernel config file and rebuild a kernel.
-  This will include the netmap module and netmap support in the device
-  drivers.  Alternatively, you can build standalone modules
-  (netmap, ixgbe, em, lem, re, igb)
-* sample applications are in the `apps/` directory in this repository,
-  or in `src/tools/tools/netmap/` in FreeBSD distributions
+Example applications are available in the `apps/` directory in this
+repository, or in `src/tools/tools/netmap/` in the FreeBSD source tree.
 
 
 ### Linux
@@ -93,7 +96,7 @@ need build the new kernel or modules as below:
 The `./configure && make` build system in the LINUX/
 directory will let you patch device driver sources and build
 some netmap-enabled device drivers.
-Please look at `LINUX/README.md` for details.
+Please look at `LINUX/README.md` for more instructions.
 
 Make sure you have kernel headers matching your installed kernel.
 The sources for e1000e, igb, ixgbe and i40e will be downloaded

From 4e16971ba3f20c282c09294867a77ff15727dbfb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 13:43:46 +0100
Subject: [PATCH 1588/2207] port README.ptnetmap to markdown language

---
 LINUX/README.md                       |  6 +-
 README.md                             | 12 ++--
 README.ptnetmap => README.ptnetmap.md | 90 +++++++++++----------------
 3 files changed, 45 insertions(+), 63 deletions(-)
 rename README.ptnetmap => README.ptnetmap.md (74%)

diff --git a/LINUX/README.md b/LINUX/README.md
index 1a76d0a19..a4ca957b9 100644
--- a/LINUX/README.md
+++ b/LINUX/README.md
@@ -149,12 +149,8 @@ for the version you are interest in, you can use the `--select-version`
 option of configure. E.g., to select the 5.2.4 version of the ixgbe
 external driver, pass `--select-version=ixgbe:5.2.4` to configure.
 
-## How to use the code
+## How to load netmap in your system
 
-Disclaimer: _This is experimental code which may crash your system.
-use it at your own risk._
-
-The following steps can be used for initial testing.
 Unload any modules for the network cards you want to use, e.g.
 
 	sudo rmmod ixgbe
diff --git a/README.md b/README.md
index 990864e2f..0dad76b1e 100644
--- a/README.md
+++ b/README.md
@@ -40,8 +40,10 @@ a userspace version of ipfw and dummynet which can handle several
 million packets per second in a single thread
 
 QEMU has native netmap support, so it can interconnect VMs at high speed
-through netmap ports. There is experimental netmap support in the FreeBSD's
-bhyve hypervisor.
+through netmap ports (e.g., using VALE ports or netmap pipes).
+For maximum performance, it is also possible to pass-through any netmap port
+into a QEMU VM, as described [here](README.ptnetmap.md).
+Also the FreeBSD bhyve hypervisor has native support for netmap.
 
 Netmap alone **does not** accelerate your TCP. For that you need to implement
 your own tcp/ip stack probably using some of the techniques indicated
@@ -96,7 +98,7 @@ repository, or in `src/tools/tools/netmap/` in the FreeBSD source tree.
 The `./configure && make` build system in the LINUX/
 directory will let you patch device driver sources and build
 some netmap-enabled device drivers.
-Please look at `LINUX/README.md` for more instructions.
+Please look [here](LINUX/README.md) for more instructions.
 
 Make sure you have kernel headers matching your installed kernel.
 The sources for e1000e, igb, ixgbe and i40e will be downloaded
@@ -147,7 +149,7 @@ command above. The new drivers will then be called `e1000e-netmap`,
 ### Windows
 
 Netmap has been ported to Windows in summer 2015 by Alessio Faina as part of
-his Master thesis. Please look at `WINDOWS/README.txt` for details.
+his Master thesis. Please look [here](WINDOWS/README.txt) for details.
 
 ## Applications
 
@@ -257,7 +259,7 @@ a command like
 
 	sudo ifconfig vtnet0 -txcsum -rxcsum -tso4 -tso6 -lro -txcsum6 -rxcsum6
 
-See `LINUX/README.md` for the corresponding Linux command.
+Check [here](LINUX/README.md) for the corresponding Linux command.
 
 
 ## Credits
diff --git a/README.ptnetmap b/README.ptnetmap.md
similarity index 74%
rename from README.ptnetmap
rename to README.ptnetmap.md
index 457373cdb..834e5734e 100644
--- a/README.ptnetmap
+++ b/README.ptnetmap.md
@@ -1,10 +1,6 @@
-===========================================================================
-                        NETMAP PASSTHROUGH HOWTO
-===========================================================================
+# Netmap passthrough howto
 
----------------------------------------------------------------------------
-1. Introduction
----------------------------------------------------------------------------
+## 1. Introduction
 
 This document describes how to configure netmap passthrough, a technology
 that enables very fast network I/O (up to 30 Mpps and more) for QEMU Virtual
@@ -31,91 +27,83 @@ directly passing a dedicated physical netmap port to a VM.
 
 More information about ptnetmap are available in these slides:
 
-    * https://github.com/vmaffione/netmap-tutorial/blob/master/virtualization.pdf
+* https://github.com/vmaffione/netmap-tutorial/blob/master/virtualization.pdf
 
 and in these papers
 
-    * http://info.iet.unipi.it/~luigi/papers/20160613-ptnet.pdf
-    * http://info.iet.unipi.it/~luigi/papers/20150315-netmap-passthrough.pdf (older)
+* http://info.iet.unipi.it/~luigi/papers/20160613-ptnet.pdf
+* http://info.iet.unipi.it/~luigi/papers/20150315-netmap-passthrough.pdf (older)
 
 and in section 7 of this document.
 
----------------------------------------------------------------------------
-2. Configure Linux host and QEMU for ptnetmap
----------------------------------------------------------------------------
+## 2. Configure Linux host and QEMU for ptnetmap
 
 On the Linux host, configure, build and install netmap normally:
 
-    $ git clone https://github.com/luigirizzo/netmap.git
-    $ cd netmap
-    $ ./configure [options]
-    $ make
-    $ sudo make install
+	git clone https://github.com/luigirizzo/netmap.git
+	cd netmap
+	./configure [options]
+	make
+	sudo make install
 
 Download, build and install the ptnetmap-enabled QEMU:
 
-    $ git clone https://github.com/vmaffione/qemu
-    $ cd qemu
-    $ ./configure --target-list=x86_64-softmmu --enable-kvm --enable-vhost-net --disable-werror --enable-netmap
-    $ make
-    $ sudo make install
+	git clone https://github.com/netmap-unipi/qemu
+	cd qemu
+	./configure --target-list=x86_64-softmmu --enable-kvm --enable-vhost-net --disable-werror --enable-netmap
+	make
+	sudo make install
 
 Load the netmap
 
-    $ sudo modprobe netmap
+	sudo modprobe netmap
 
 Example to run a VM passing through a VALE port (vale1:10):
 
-    $ sudo qemu-system-x86_64 img.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device ptnet-pci,netdev=data10,mac=00:AA:BB:CC:0a:0a -netdev netmap,ifname=vale1:10,id=data10,passthrough=on
+	sudo qemu-system-x86_64 img.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device ptnet-pci,netdev=data10,mac=00:AA:BB:CC:0a:0a -netdev netmap,ifname=vale1:10,id=data10,passthrough=on
 
 Example to run a VM passing though the "left" endpoints of two pipes endpoints
 (the "right" endpoints can be connected to other VMs or netmap programs running
 directly on the host.
 
-    $ sudo qemu-system-x86_64 img.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device ptnet-pci,netdev=data1,mac=00:AA:BB:CC:0b:01 -netdev netmap,ifname=netmap:pipe0{1,id=data1,passthrough=on -device ptnet-pci,netdev=data1,mac=00:AA:BB:CC:0b:02 -netdev netmap,ifname=netmap:pipe1{1,id=data1,passthrough=on
+	sudo qemu-system-x86_64 img.qcow2 -enable-kvm -smp 2 -m 2G -vga std -device ptnet-pci,netdev=data1,mac=00:AA:BB:CC:0b:01 -netdev netmap,ifname=netmap:pipe0{1,id=data1,passthrough=on -device ptnet-pci,netdev=data1,mac=00:AA:BB:CC:0b:02 -netdev netmap,ifname=netmap:pipe1{1,id=data1,passthrough=on
 
 
----------------------------------------------------------------------------
-3. Configure FreeBSD host and bhyve for ptnetmap
----------------------------------------------------------------------------
+## 3. Configure FreeBSD host and bhyve for ptnetmap
 TODO
 
 
----------------------------------------------------------------------------
-4. Configure Linux guest for ptnetmap
----------------------------------------------------------------------------
+## 4. Configure Linux guest for ptnetmap
 
 In the Linux guest, compile, build and install netmap with ptnetmap support:
 
-    $ git clone https://github.com/luigirizzo/netmap.git
-    $ cd netmap
-    $ ./configure --enable-ptnetmap
-    $ make
-    $ sudo make install
+	git clone https://github.com/luigirizzo/netmap.git
+	cd netmap
+	./configure --enable-ptnetmap
+	make
+	sudo make install
 
 Load netmap module
 
-    $ sudo rmmod netmap  # Possibly remove a previous netmap module:
-    $ sudo modprobe netmap
+	sudo rmmod netmap  # Possibly remove a previous netmap module:
+	sudo modprobe netmap
 
 As the netmap module is loaded, a new network interface will show up for each
 passed-through netmap port, (e.g. 'ens4'). You can check that an interface is
 a netmap passthrough one checking the driver:
 
-    $ ethtool -i ens4
-    driver: ptnetmap-guest-drivers
-    version:
-    [...]
+	ethtool -i ens4
+	  driver: ptnetmap-guest-drivers
+	  version:
+	  [...]
 
 A guest ptnetmap port behaves like any other netmap ports. You can use pkt-gen
 to test transmission;
 
-    $ sudo pkt-gen -i ens4 -f tx
+	sudo pkt-gen -i ens4 -f tx
 
 
----------------------------------------------------------------------------
-5. Use ptnetmap with FreeBSD guests
----------------------------------------------------------------------------
+## 5. Use ptnetmap with FreeBSD guests
 
 Netmap passthrough guest drivers are already included with netmap from FreeBSD
 12 versions. When running FreeBSD guest with ptnetmap ports (e.g. using QEMU as
@@ -126,9 +114,7 @@ FreeBSD source tree with the updated netmap code from github and rebuild your
 kernel.
 
 
-----------------------------------------------------------------------
-6. ptnetmap tunables
-----------------------------------------------------------------------
+## 6. ptnetmap tunables
 
 While ptnetmap is mainly designed for the VMs to run middleboxes applications
 (e.g. firewall, DDoS prevention, load balancing, IDS, typically carried out
@@ -148,16 +134,14 @@ If you want to use ptnetmap mainly to run middleboxes application (which
 is the common case), you should disable the virtio-net header in the guest
 OS:
 
-    # echo 0 > /sys/module/netmap/parameters/ptnet_vnet_hdr
+	# echo 0 > /sys/module/netmap/parameters/ptnet_vnet_hdr
 
 This step is needed to avoid performance issues in case your datapath exits the
 hypervisor host through a physical NIC or goes through netmap ports that don't
 support the virtio-net header.
 
 
----------------------------------------------------------------------------
-7. Some background about ptnetmap
----------------------------------------------------------------------------
+## 7. Some background about ptnetmap
 
 Netmap is a framework for high performance network I/O. It exposes an
 hardware-independent API which allows userspace application to directly interact

From 060adfba73dd389253717860b1abd54806cd2bfb Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 13:58:24 +0100
Subject: [PATCH 1589/2207] freebsd: remove obsolete log statement

---
 sys/dev/netmap/netmap_freebsd.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index a64964c2c..b71210f8d 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1350,8 +1350,6 @@ nm_os_kctx_destroy(struct nm_kctx *nmk)
 void
 nm_os_selwakeup(struct nm_selinfo *si)
 {
-	if (netmap_verbose)
-		nm_prinf("on knote %p", &si->si.si_note);
 	selwakeuppri(&si->si, PI_NET);
 	taskqueue_enqueue(si->ntfytq, &si->ntfytask);
 }

From 38cbc64d005029324cd63896fe9ad644d7d9d2bd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 18:37:31 +0100
Subject: [PATCH 1590/2207] linux: veth: align register and kring creation to
 netmap pipes

---
 LINUX/veth_netmap.h | 31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index e7ec5ff60..f97c2f80c 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -141,12 +141,21 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 
 		/* In case of no error we put our rings in netmap mode */
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
-
 				if (nm_kring_pending_on(kring)) {
 					struct netmap_kring *sring, *dring;
 
+					kring->nr_mode = NKR_NETMAP_ON;
+					if ((kring->nr_kflags & NKR_FAKERING) &&
+					    (kring->pipe->nr_kflags & NKR_FAKERING)) {
+						/* this is a re-open of a pipe
+						 * end-point kept alive by the other end.
+						 * We need to leave everything as it is
+						 */
+						continue;
+					}
+
 					/* copy the buffers from the non-fake ring */
 					if (kring->nr_kflags & NKR_FAKERING) {
 						sring = kring->pipe;
@@ -181,7 +190,7 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		nm_clear_native_flags(na);
 
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
+			for (i = 0; i < nma_get_nrings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 
 				if (nm_kring_pending_off(kring)) {
@@ -233,6 +242,7 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 	}
 
 	if (vna->peer_ref) {
+		int i;
 
 		/* create my krings */
 		error = netmap_krings_create(na, 0);
@@ -248,13 +258,16 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 		 * the host krings) */
 		for_rx_tx(t) {
 			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-			int i;
-
 			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				NMR(na, t)[i]->pipe = NMR(peer_na, r)[i];
-				NMR(peer_na, r)[i]->pipe = NMR(na, t)[i];
+				struct netmap_kring *k1 = NMR(na, t)[i],
+					            *k2 = NMR(peer_na, r)[i];
+				k1->pipe = k2;
+				k2->pipe = k1;
 				/* mark all peer-adapter rings as fake */
-				NMR(peer_na, r)[i]->nr_kflags |= NKR_FAKERING;
+				k2->nr_kflags |= NKR_FAKERING;
+				/* init tails */
+				k1->pipe_tail = k1->nr_hwtail;
+				k2->pipe_tail = k2->nr_hwtail;
 			}
 		}
 
@@ -309,7 +322,7 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 			if (ring == NULL)
 				continue;
 
-			if (kring->nr_hwtail == kring->nr_hwcur)
+			if (kring->tx == NR_RX)
 				ring->slot[kring->nr_hwtail].buf_idx = 0;
 
 			for (j = nm_next(kring->nr_hwtail, lim);

From 61cfe625ce63399d4109fbea5c74f8fd8e069be8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 22:52:19 +0100
Subject: [PATCH 1591/2207] pipes, veth: share krings_create implementation

---
 LINUX/netmap_linux.c         |  1 +
 LINUX/veth_netmap.h          | 44 ++------------------
 sys/dev/netmap/netmap_kern.h |  2 +
 sys/dev/netmap/netmap_pipe.c | 80 +++++++++++++++++++-----------------
 4 files changed, 49 insertions(+), 78 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e2e289d65..ed5b38821 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2479,6 +2479,7 @@ EXPORT_SYMBOL(netmap_mem_rings_delete);	/* used by veth module */
 #ifdef WITH_PIPES
 EXPORT_SYMBOL(netmap_pipe_txsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_rxsync);	/* used by veth module */
+EXPORT_SYMBOL(netmap_pipe_krings_create_both);
 #endif /* WITH_PIPES */
 EXPORT_SYMBOL(netmap_verbose);
 EXPORT_SYMBOL(nm_set_native_flags);
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index f97c2f80c..c550ad427 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -227,8 +227,6 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 {
 	struct netmap_veth_adapter *vna = (struct netmap_veth_adapter *)na;
 	struct netmap_adapter *peer_na;
-	int error = 0;
-	enum txrx t;
 
 	/* The nm_krings_create callback is called first in netmap_do_regif(),
 	 * so the the cross linking happens now (if this is the first endpoint
@@ -237,50 +235,14 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 	peer_na = veth_get_peer_na(na);
 	rcu_read_unlock();
 	if (!peer_na) {
-		D("veth peer not found");
+		nm_prerr("veth peer not found for %s", na->name);
 		return ENXIO;
 	}
 
-	if (vna->peer_ref) {
-		int i;
-
-		/* create my krings */
-		error = netmap_krings_create(na, 0);
-		if (error)
-			return error;
-
-		/* create the krings of the other end */
-		error = netmap_krings_create(peer_na, 0);
-		if (error)
-			goto del_krings1;
-
-		/* cross link the krings (only the hw ones, not
-		 * the host krings) */
-		for_rx_tx(t) {
-			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *k1 = NMR(na, t)[i],
-					            *k2 = NMR(peer_na, r)[i];
-				k1->pipe = k2;
-				k2->pipe = k1;
-				/* mark all peer-adapter rings as fake */
-				k2->nr_kflags |= NKR_FAKERING;
-				/* init tails */
-				k1->pipe_tail = k1->nr_hwtail;
-				k2->pipe_tail = k2->nr_hwtail;
-			}
-		}
-
-		if (netmap_verbose) {
-			D("created krings for %s and its peer", na->name);
-		}
-	}
+	if (vna->peer_ref)
+		return netmap_pipe_krings_create_both(na, peer_na);
 
 	return 0;
-
-del_krings1:
-	netmap_krings_delete(na);
-	return error;
 }
 
 /* See netmap_pipe_krings_delete(). */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 85df9aa0d..f20f36025 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1994,6 +1994,8 @@ nm_si_user(struct netmap_priv_d *priv, enum txrx t)
 #ifdef WITH_PIPES
 int netmap_pipe_txsync(struct netmap_kring *txkring, int flags);
 int netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags);
+int netmap_pipe_krings_create_both(struct netmap_adapter *na,
+				  struct netmap_adapter *ona);
 #endif /* WITH_PIPES */
 
 #ifdef WITH_MONITOR
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index c5bfc367a..74698595f 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -312,6 +312,47 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
  */
 
 
+int netmap_pipe_krings_create_both(struct netmap_adapter *na,
+				  struct netmap_adapter *ona)
+{
+	enum txrx t;
+	int error;
+	int i;
+
+	/* case 1) below */
+	ND("%p: case 1, create both ends", na);
+	error = netmap_krings_create(na, 0);
+	if (error)
+		return error;
+
+	/* create the krings of the other end */
+	error = netmap_krings_create(ona, 0);
+	if (error)
+		goto del_krings1;
+
+	/* cross link the krings and initialize the pipe_tails */
+	for_rx_tx(t) {
+		enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
+		for (i = 0; i < nma_get_nrings(na, t); i++) {
+			struct netmap_kring *k1 = NMR(na, t)[i],
+					    *k2 = NMR(ona, r)[i];
+			k1->pipe = k2;
+			k2->pipe = k1;
+			/* mark all peer-adapter rings as fake */
+			k2->nr_kflags |= NKR_FAKERING;
+			/* init tails */
+			k1->pipe_tail = k1->nr_hwtail;
+			k2->pipe_tail = k2->nr_hwtail;
+		}
+	}
+
+	return 0;
+
+del_krings1:
+	netmap_krings_delete(na);
+	return error;
+}
+
 /* netmap_pipe_krings_create.
  *
  * There are two cases:
@@ -336,46 +377,11 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
 	struct netmap_pipe_adapter *pna =
 		(struct netmap_pipe_adapter *)na;
 	struct netmap_adapter *ona = &pna->peer->up;
-	int error = 0;
-	enum txrx t;
 
-	if (pna->peer_ref) {
-		int i;
-
-		/* case 1) above */
-		ND("%p: case 1, create both ends", na);
-		error = netmap_krings_create(na, 0);
-		if (error)
-			goto err;
+	if (pna->peer_ref)
+		return netmap_pipe_krings_create_both(na, ona);
 
-		/* create the krings of the other end */
-		error = netmap_krings_create(ona, 0);
-		if (error)
-			goto del_krings1;
-
-		/* cross link the krings and initialize the pipe_tails */
-		for_rx_tx(t) {
-			enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *k1 = NMR(na, t)[i],
-					            *k2 = NMR(ona, r)[i];
-				k1->pipe = k2;
-				k2->pipe = k1;
-				/* mark all peer-adapter rings as fake */
-				k2->nr_kflags |= NKR_FAKERING;
-				/* init tails */
-				k1->pipe_tail = k1->nr_hwtail;
-				k2->pipe_tail = k2->nr_hwtail;
-			}
-		}
-
-	}
 	return 0;
-
-del_krings1:
-	netmap_krings_delete(na);
-err:
-	return error;
 }
 
 /* netmap_pipe_reg.

From c356a94c038ef092fa2138fc0a858b5675cf6b65 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 23:26:27 +0100
Subject: [PATCH 1592/2207] pipes, veth: share krings_delete implementation

---
 LINUX/netmap_linux.c         |  1 +
 LINUX/veth_netmap.h          | 48 +-----------------------
 sys/dev/netmap/netmap_kern.h |  2 +
 sys/dev/netmap/netmap_pipe.c | 71 ++++++++++++++++++++----------------
 4 files changed, 45 insertions(+), 77 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index ed5b38821..0d48eac6a 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2480,6 +2480,7 @@ EXPORT_SYMBOL(netmap_mem_rings_delete);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_txsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_rxsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_krings_create_both);
+EXPORT_SYMBOL(netmap_pipe_krings_delete_both);
 #endif /* WITH_PIPES */
 EXPORT_SYMBOL(netmap_verbose);
 EXPORT_SYMBOL(nm_set_native_flags);
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index c550ad427..24e4cb0f9 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -250,9 +250,7 @@ static void
 veth_netmap_krings_delete(struct netmap_adapter *na)
 {
 	struct netmap_veth_adapter *vna = (struct netmap_veth_adapter *)na;
-	struct netmap_adapter *peer_na, *sna;
-	enum txrx t;
-	int i;
+	struct netmap_adapter *peer_na;
 
 	if (!vna->peer_ref) {
 		return;
@@ -270,49 +268,7 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 		return;
 	}
 
-	sna = na;
-cleanup:
-	for_rx_tx(t) {
-		for (i = 0; i < nma_get_nrings(sna, t) + 1; i++) {
-			struct netmap_kring *kring = NMR(sna, t)[i];
-			struct netmap_ring *ring = kring->ring;
-			uint32_t j, lim = kring->nkr_num_slots - 1;
-
-			ND("%s ring %p hwtail %u hwcur %u",
-				kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
-
-			if (ring == NULL)
-				continue;
-
-			if (kring->tx == NR_RX)
-				ring->slot[kring->nr_hwtail].buf_idx = 0;
-
-			for (j = nm_next(kring->nr_hwtail, lim);
-			     j != kring->nr_hwcur;
-			     j = nm_next(j, lim))
-			{
-				ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
-				ring->slot[j].buf_idx = 0;
-			}
-			kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING);
-		}
-
-	}
-	if (sna != peer_na && peer_na->tx_rings) {
-		sna = peer_na;
-		goto cleanup;
-	}
-
-	netmap_mem_rings_delete(na);
-	netmap_krings_delete(na); /* also zeroes tx_rings etc. */
-
-	if (peer_na->tx_rings == NULL) {
-		/* already deleted, we must be on an
-		 * cleanup-after-error path */
-		return;
-	}
-	netmap_mem_rings_delete(peer_na);
-	netmap_krings_delete(peer_na);
+	netmap_pipe_krings_delete_both(na, peer_na);
 }
 
 static void
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f20f36025..a8bba1df3 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1996,6 +1996,8 @@ int netmap_pipe_txsync(struct netmap_kring *txkring, int flags);
 int netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags);
 int netmap_pipe_krings_create_both(struct netmap_adapter *na,
 				  struct netmap_adapter *ona);
+void netmap_pipe_krings_delete_both(struct netmap_adapter *na,
+				    struct netmap_adapter *ona);
 #endif /* WITH_PIPES */
 
 #ifdef WITH_MONITOR
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 74698595f..d5608dc5e 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -527,41 +527,15 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 	return error;
 }
 
-/* netmap_pipe_krings_delete.
- *
- * There are two cases:
- *
- * 1) state is
- *
- *                usr1 --> e1 --> e2
- *
- *    and we are e1 (e2 is not registered, so krings_delete cannot be
- *    called on it);
- *
- * 2) state is
- *
- *                usr1 --> e1     e2 <-- usr2
- *
- *    and we are either e1 or e2.
- *
- * In the former case we have to also delete the krings of e2;
- * in the latter case we do nothing.
- */
-static void
-netmap_pipe_krings_delete(struct netmap_adapter *na)
+void
+netmap_pipe_krings_delete_both(struct netmap_adapter *na,
+			       struct netmap_adapter *ona)
 {
-	struct netmap_pipe_adapter *pna =
-		(struct netmap_pipe_adapter *)na;
-	struct netmap_adapter *sna, *ona; /* na of the other end */
+	struct netmap_adapter *sna;
 	enum txrx t;
 	int i;
 
-	if (!pna->peer_ref) {
-		ND("%p: case 2, kept alive by peer",  na);
-		return;
-	}
-	ona = &pna->peer->up;
-	/* case 1) above */
+	/* case 1) below */
 	ND("%p: case 1, deleting everything", na);
 	/* To avoid double-frees we zero-out all the buffers in the kernel part
 	 * of each ring. The reason is this: If the user is behaving correctly,
@@ -615,6 +589,41 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 	netmap_krings_delete(ona);
 }
 
+/* netmap_pipe_krings_delete.
+ *
+ * There are two cases:
+ *
+ * 1) state is
+ *
+ *                usr1 --> e1 --> e2
+ *
+ *    and we are e1 (e2 is not registered, so krings_delete cannot be
+ *    called on it);
+ *
+ * 2) state is
+ *
+ *                usr1 --> e1     e2 <-- usr2
+ *
+ *    and we are either e1 or e2.
+ *
+ * In the former case we have to also delete the krings of e2;
+ * in the latter case we do nothing.
+ */
+static void
+netmap_pipe_krings_delete(struct netmap_adapter *na)
+{
+	struct netmap_pipe_adapter *pna =
+		(struct netmap_pipe_adapter *)na;
+	struct netmap_adapter *ona; /* na of the other end */
+
+	if (!pna->peer_ref) {
+		ND("%p: case 2, kept alive by peer",  na);
+		return;
+	}
+	ona = &pna->peer->up;
+	netmap_pipe_krings_delete_both(na, ona);
+}
+
 
 static void
 netmap_pipe_dtor(struct netmap_adapter *na)

From a5be8df0f0884b957048e99248ab052c28f90709 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 3 Feb 2019 23:35:16 +0100
Subject: [PATCH 1593/2207] pipes, veth: share nm_register implementation

---
 LINUX/netmap_linux.c         |   1 +
 LINUX/veth_netmap.h          |  69 +----------------
 sys/dev/netmap/netmap_kern.h |   2 +
 sys/dev/netmap/netmap_pipe.c | 140 +++++++++++++++++++----------------
 4 files changed, 85 insertions(+), 127 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0d48eac6a..cc7754f1e 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2481,6 +2481,7 @@ EXPORT_SYMBOL(netmap_pipe_txsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_rxsync);	/* used by veth module */
 EXPORT_SYMBOL(netmap_pipe_krings_create_both);
 EXPORT_SYMBOL(netmap_pipe_krings_delete_both);
+EXPORT_SYMBOL(netmap_pipe_reg_both);
 #endif /* WITH_PIPES */
 EXPORT_SYMBOL(netmap_verbose);
 EXPORT_SYMBOL(nm_set_native_flags);
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 24e4cb0f9..a7593c894 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -101,9 +101,7 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct netmap_adapter *peer_na;
 	struct ifnet *ifp = na->ifp;
 	bool was_up;
-	enum txrx t;
 	int error;
-	int i;
 
 	peer_na = veth_get_peer_na(na);
 	if (!peer_na) {
@@ -118,75 +116,18 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 
 	/* Enable or disable flags and callbacks in na and ifp. */
 	if (onoff) {
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_on(kring)) {
-					/* mark the peer ring as needed */
-					kring->pipe->nr_kflags |= NKR_NEEDRING;
-				}
-			}
-		}
-
-		/* create all missing needed rings on the other end.
-		 * They have all been marked as fake in the krings_create
-		 * above, so the will not be filled with buffers
-		 */
-
-		error = netmap_mem_rings_create(peer_na);
+		error = netmap_pipe_reg_both(na, peer_na);
 		if (error) {
 			return error;
 		}
-
-		/* In case of no error we put our rings in netmap mode */
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-				if (nm_kring_pending_on(kring)) {
-					struct netmap_kring *sring, *dring;
-
-					kring->nr_mode = NKR_NETMAP_ON;
-					if ((kring->nr_kflags & NKR_FAKERING) &&
-					    (kring->pipe->nr_kflags & NKR_FAKERING)) {
-						/* this is a re-open of a pipe
-						 * end-point kept alive by the other end.
-						 * We need to leave everything as it is
-						 */
-						continue;
-					}
-
-					/* copy the buffers from the non-fake ring */
-					if (kring->nr_kflags & NKR_FAKERING) {
-						sring = kring->pipe;
-						dring = kring;
-					} else {
-						sring = kring;
-						dring = kring->pipe;
-					}
-					memcpy(dring->ring->slot,
-					       sring->ring->slot,
-					       sizeof(struct netmap_slot) *
-							sring->nkr_num_slots);
-					/* mark both rings as fake and needed,
-					 * so that buffers will not be
-					 * deleted by the standard machinery
-					 * (we will delete them by ourselves in
-					 * veth_netmap_krings_delete)
-					 */
-					sring->nr_kflags |=
-						(NKR_FAKERING | NKR_NEEDRING);
-					dring->nr_kflags |=
-						(NKR_FAKERING | NKR_NEEDRING);
-					kring->nr_mode = NKR_NETMAP_ON;
-				}
-			}
-		}
 		nm_set_native_flags(na);
 		if (netmap_verbose) {
 			D("registered veth %s", na->name);
 		}
 	} else {
+		enum txrx t;
+		int i;
+
 		nm_clear_native_flags(na);
 
 		for_rx_tx(t) {
@@ -221,7 +162,6 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 	return 0;
 }
 
-/* See netmap_pipe_krings_create(). */
 static int
 veth_netmap_krings_create(struct netmap_adapter *na)
 {
@@ -245,7 +185,6 @@ veth_netmap_krings_create(struct netmap_adapter *na)
 	return 0;
 }
 
-/* See netmap_pipe_krings_delete(). */
 static void
 veth_netmap_krings_delete(struct netmap_adapter *na)
 {
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a8bba1df3..2b9cdfc89 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1998,6 +1998,8 @@ int netmap_pipe_krings_create_both(struct netmap_adapter *na,
 				  struct netmap_adapter *ona);
 void netmap_pipe_krings_delete_both(struct netmap_adapter *na,
 				    struct netmap_adapter *ona);
+int netmap_pipe_reg_both(struct netmap_adapter *na,
+			 struct netmap_adapter *ona);
 #endif /* WITH_PIPES */
 
 #ifdef WITH_MONITOR
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index d5608dc5e..1a54b70f6 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -384,6 +384,78 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
 	return 0;
 }
 
+int
+netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona)
+{
+	int i, error = 0;
+	enum txrx t;
+
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(na, t); i++) {
+			struct netmap_kring *kring = NMR(na, t)[i];
+
+			if (nm_kring_pending_on(kring)) {
+				/* mark the peer ring as needed */
+				kring->pipe->nr_kflags |= NKR_NEEDRING;
+			}
+		}
+	}
+
+	/* create all missing needed rings on the other end.
+	 * Either our end, or the other, has been marked as
+	 * fake, so the allocation will not be done twice.
+	 */
+	error = netmap_mem_rings_create(ona);
+	if (error)
+		return error;
+
+	/* In case of no error we put our rings in netmap mode */
+	for_rx_tx(t) {
+		for (i = 0; i < nma_get_nrings(na, t); i++) {
+			struct netmap_kring *kring = NMR(na, t)[i];
+			if (nm_kring_pending_on(kring)) {
+				struct netmap_kring *sring, *dring;
+
+				kring->nr_mode = NKR_NETMAP_ON;
+				if ((kring->nr_kflags & NKR_FAKERING) &&
+				    (kring->pipe->nr_kflags & NKR_FAKERING)) {
+					/* this is a re-open of a pipe
+					 * end-point kept alive by the other end.
+					 * We need to leave everything as it is
+					 */
+					continue;
+				}
+
+				/* copy the buffers from the non-fake ring */
+				if (kring->nr_kflags & NKR_FAKERING) {
+					sring = kring->pipe;
+					dring = kring;
+				} else {
+					sring = kring;
+					dring = kring->pipe;
+				}
+				memcpy(dring->ring->slot,
+				       sring->ring->slot,
+				       sizeof(struct netmap_slot) *
+						sring->nkr_num_slots);
+				/* mark both rings as fake and needed,
+				 * so that buffers will not be
+				 * deleted by the standard machinery
+				 * (we will delete them by ourselves in
+				 * netmap_pipe_krings_delete)
+				 */
+				sring->nr_kflags |=
+					(NKR_FAKERING | NKR_NEEDRING);
+				dring->nr_kflags |=
+					(NKR_FAKERING | NKR_NEEDRING);
+				kring->nr_mode = NKR_NETMAP_ON;
+			}
+		}
+	}
+
+	return 0;
+}
+
 /* netmap_pipe_reg.
  *
  * There are two cases on registration (onoff==1)
@@ -423,76 +495,20 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 	struct netmap_pipe_adapter *pna =
 		(struct netmap_pipe_adapter *)na;
 	struct netmap_adapter *ona = &pna->peer->up;
-	int i, error = 0;
-	enum txrx t;
+	int error = 0;
 
 	ND("%p: onoff %d", na, onoff);
 	if (onoff) {
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_on(kring)) {
-					/* mark the peer ring as needed */
-					kring->pipe->nr_kflags |= NKR_NEEDRING;
-				}
-			}
-		}
-
-		/* create all missing needed rings on the other end.
-		 * Either our end, or the other, has been marked as
-		 * fake, so the allocation will not be done twice.
-		 */
-		error = netmap_mem_rings_create(ona);
-		if (error)
+		error = netmap_pipe_reg_both(na, ona);
+		if (error) {
 			return error;
-
-		/* In case of no error we put our rings in netmap mode */
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-				if (nm_kring_pending_on(kring)) {
-					struct netmap_kring *sring, *dring;
-
-					kring->nr_mode = NKR_NETMAP_ON;
-					if ((kring->nr_kflags & NKR_FAKERING) &&
-					    (kring->pipe->nr_kflags & NKR_FAKERING)) {
-						/* this is a re-open of a pipe
-						 * end-point kept alive by the other end.
-						 * We need to leave everything as it is
-						 */
-						continue;
-					}
-
-					/* copy the buffers from the non-fake ring */
-					if (kring->nr_kflags & NKR_FAKERING) {
-						sring = kring->pipe;
-						dring = kring;
-					} else {
-						sring = kring;
-						dring = kring->pipe;
-					}
-					memcpy(dring->ring->slot,
-					       sring->ring->slot,
-					       sizeof(struct netmap_slot) *
-							sring->nkr_num_slots);
-					/* mark both rings as fake and needed,
-					 * so that buffers will not be
-					 * deleted by the standard machinery
-					 * (we will delete them by ourselves in
-					 * netmap_pipe_krings_delete)
-					 */
-					sring->nr_kflags |=
-						(NKR_FAKERING | NKR_NEEDRING);
-					dring->nr_kflags |=
-						(NKR_FAKERING | NKR_NEEDRING);
-					kring->nr_mode = NKR_NETMAP_ON;
-				}
-			}
 		}
 		if (na->active_fds == 0)
 			na->na_flags |= NAF_NETMAP_ON;
 	} else {
+		enum txrx t;
+		int i;
+
 		if (na->active_fds == 0)
 			na->na_flags &= ~NAF_NETMAP_ON;
 		for_rx_tx(t) {

From 4e73ca50e16ab1d1c1730051c3a418c2a3092b96 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 4 Feb 2019 14:54:32 +0100
Subject: [PATCH 1594/2207] legacy: reject requests with API < 11, as the code
 does not handle them

---
 sys/dev/netmap/netmap_legacy.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 9159c1bce..9774e03cb 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -365,7 +365,14 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		/* Request for the legacy control API. Convert it to a
 		 * NIOCCTRL request. */
 		struct nmreq *nmr = (struct nmreq *) data;
-		struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
+		struct nmreq_header *hdr;
+
+		if (nmr->nr_version < 11) {
+			nm_prerr("Minimum supported API is 11 (requested %u)",
+			    nmr->nr_version);
+			return EINVAL;
+		}
+		hdr = nmreq_from_legacy(nmr, cmd);
 		if (hdr == NULL) { /* out of memory */
 			return ENOMEM;
 		}

From 6f8b998c47deb5f5ba4c916e8d146983105fafc7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 4 Feb 2019 15:01:56 +0100
Subject: [PATCH 1595/2207] null: remove unnecessary code

---
 sys/dev/netmap/netmap_null.c | 22 ++++------------------
 1 file changed, 4 insertions(+), 18 deletions(-)

diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index b769ae7ed..e880304e7 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -74,15 +74,7 @@
 #ifdef WITH_NMNULL
 
 static int
-netmap_null_txsync(struct netmap_kring *kring, int flags)
-{
-	(void)kring;
-	(void)flags;
-	return 0;
-}
-
-static int
-netmap_null_rxsync(struct netmap_kring *kring, int flags)
+netmap_null_sync(struct netmap_kring *kring, int flags)
 {
 	(void)kring;
 	(void)flags;
@@ -95,12 +87,6 @@ netmap_null_krings_create(struct netmap_adapter *na)
 	return netmap_krings_create(na, 0);
 }
 
-static void
-netmap_null_krings_delete(struct netmap_adapter *na)
-{
-	netmap_krings_delete(na);
-}
-
 static int
 netmap_null_reg(struct netmap_adapter *na, int onoff)
 {
@@ -153,11 +139,11 @@ netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	}
 	snprintf(nna->up.name, sizeof(nna->up.name), "null:%s", hdr->nr_name);
 
-	nna->up.nm_txsync = netmap_null_txsync;
-	nna->up.nm_rxsync = netmap_null_rxsync;
+	nna->up.nm_txsync = netmap_null_sync;
+	nna->up.nm_rxsync = netmap_null_sync;
 	nna->up.nm_register = netmap_null_reg;
 	nna->up.nm_krings_create = netmap_null_krings_create;
-	nna->up.nm_krings_delete = netmap_null_krings_delete;
+	nna->up.nm_krings_delete = netmap_krings_delete;
 	nna->up.nm_bdg_attach = netmap_null_bdg_attach;
 	nna->up.nm_mem = netmap_mem_get(nmd);
 

From 0a02ad000071c7e7012985375113098ca24161d7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 4 Feb 2019 16:17:26 +0100
Subject: [PATCH 1596/2207] introduce netmap_krings_mode_commit() helper
 function

---
 LINUX/netmap_linux.c             |  1 +
 LINUX/netmap_ptnet.c             | 21 ++---------------
 LINUX/veth_netmap.h              | 29 +++++++++++++-----------
 LINUX/virtio_netmap.h            | 20 ++--------------
 sys/dev/netmap/if_ptnet.c        | 21 ++---------------
 sys/dev/netmap/if_vtnet_netmap.h | 39 +++-----------------------------
 sys/dev/netmap/netmap.c          | 19 ++++++++++++++++
 sys/dev/netmap/netmap_bdg.c      | 20 ++--------------
 sys/dev/netmap/netmap_generic.c  | 27 ++--------------------
 sys/dev/netmap/netmap_kern.h     |  2 ++
 sys/dev/netmap/netmap_pipe.c     | 13 +----------
 11 files changed, 52 insertions(+), 160 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index cc7754f1e..6b5d836b0 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2457,6 +2457,7 @@ EXPORT_SYMBOL(netmap_ring_reinit);	/* ring init on error */
 EXPORT_SYMBOL(netmap_reset);		/* ring init routines */
 EXPORT_SYMBOL(netmap_rx_irq);	        /* default irq handler */
 EXPORT_SYMBOL(netmap_no_pendintr);	/* XXX mitigation - should go away */
+EXPORT_SYMBOL(netmap_krings_mode_commit);
 #ifdef WITH_VALE
 EXPORT_SYMBOL(netmap_bdg_regops);	/* bridge configuration routine */
 EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 53391378d..956a886e7 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1070,7 +1070,6 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	int native = (na == &pi->ptna->hwup.up);
 	struct nm_csb_atok *atok;
 	struct nm_csb_ktoa *ktoa;
-	enum txrx t;
 	int ret = 0;
 	int i;
 
@@ -1131,30 +1130,14 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		/* If not native, don't call nm_set_native_flags, since we don't want
 		 * to replace ndo_start_xmit method, nor set NAF_NETMAP_ON */
 		if (native) {
-			for_rx_tx(t) {
-				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = NMR(na, t)[i];
-
-					if (nm_kring_pending_on(kring)) {
-						kring->nr_mode = NKR_NETMAP_ON;
-					}
-				}
-			}
+			netmap_krings_mode_commit(na, onoff);
 			nm_set_native_flags(na);
 		}
 
 	} else {
 		if (native) {
 			nm_clear_native_flags(na);
-			for_rx_tx(t) {
-				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = NMR(na, t)[i];
-
-					if (nm_kring_pending_off(kring)) {
-						kring->nr_mode = NKR_NETMAP_OFF;
-					}
-				}
-			}
+			netmap_krings_mode_commit(na, onoff);
 		}
 
 		if (pi->ptna->backend_users == 0) {
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index a7593c894..f2cb2197d 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -116,29 +116,32 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 
 	/* Enable or disable flags and callbacks in na and ifp. */
 	if (onoff) {
+		enum txrx t;
+
 		error = netmap_pipe_reg_both(na, peer_na);
 		if (error) {
 			return error;
 		}
-		nm_set_native_flags(na);
-		if (netmap_verbose) {
-			D("registered veth %s", na->name);
-		}
-	} else {
-		enum txrx t;
-		int i;
-
-		nm_clear_native_flags(na);
-
 		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
+			int i;
+
+			for (i = nma_get_nrings(na, t);
+			    i < netmap_real_rings(na, t); i++) {
 				struct netmap_kring *kring = NMR(na, t)[i];
 
-				if (nm_kring_pending_off(kring)) {
-					kring->nr_mode = NKR_NETMAP_OFF;
+				if (nm_kring_pending_on(kring)) {
+					/* mark the peer ring as needed */
+					kring->nr_mode |= NKR_NETMAP_ON	;
 				}
 			}
 		}
+		nm_set_native_flags(na);
+		if (netmap_verbose) {
+			D("registered veth %s", na->name);
+		}
+	} else {
+		nm_clear_native_flags(na);
+		netmap_krings_mode_commit(na, onoff);
 		if (netmap_verbose) {
 			D("unregistered veth %s", na->name);
 		}
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index a9f0cbfcd..8ee4008ce 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -339,27 +339,11 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 		}
 
 		/* enable netmap mode */
-		for_rx_tx(t) {
-			for (i = 0; i <= nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_on(kring)) {
-					kring->nr_mode = NKR_NETMAP_ON;
-				}
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
 		nm_set_native_flags(na);
 	} else {
 		nm_clear_native_flags(na);
-		for_rx_tx(t) {
-			for (i = 0; i <= nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_off(kring)) {
-					kring->nr_mode = NKR_NETMAP_OFF;
-				}
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
 
 		if (hwrings_pending) {
 			/* Get and free any used buffer. This is necessary
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 02f91ee3d..25ff96eb1 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1179,7 +1179,6 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	struct ptnet_softc *sc = if_getsoftc(ifp);
 	int native = (na == &sc->ptna->hwup.up);
 	struct ptnet_queue *pq;
-	enum txrx t;
 	int ret = 0;
 	int i;
 
@@ -1230,30 +1229,14 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 		/* If not native, don't call nm_set_native_flags, since we don't want
 		 * to replace if_transmit method, nor set NAF_NETMAP_ON */
 		if (native) {
-			for_rx_tx(t) {
-				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = NMR(na, t)[i];
-
-					if (nm_kring_pending_on(kring)) {
-						kring->nr_mode = NKR_NETMAP_ON;
-					}
-				}
-			}
+			netmap_krings_mode_commit(na, onoff);
 			nm_set_native_flags(na);
 		}
 
 	} else {
 		if (native) {
 			nm_clear_native_flags(na);
-			for_rx_tx(t) {
-				for (i = 0; i <= nma_get_nrings(na, t); i++) {
-					struct netmap_kring *kring = NMR(na, t)[i];
-
-					if (nm_kring_pending_off(kring)) {
-						kring->nr_mode = NKR_NETMAP_OFF;
-					}
-				}
-			}
+			netmap_krings_mode_commit(na, onoff);
 		}
 
 		if (sc->ptna->backend_users == 0) {
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index cbb9b72a9..0b3ac3f34 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -132,44 +132,11 @@ vtnet_netmap_reg(struct netmap_adapter *na, int state)
 	success = (ifp->if_drv_flags & IFF_DRV_RUNNING) ? 0 : ENXIO;
 
 	if (state) {
-		for_rx_tx(t) {
-			/* Hardware rings. */
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_on(kring))
-					kring->nr_mode = NKR_NETMAP_ON;
-			}
-
-			/* Host rings. */
-			for (i = 0; i < nma_get_host_nrings(na, t); i++) {
-				struct netmap_kring *kring =
-					NMR(na, t)[nma_get_nrings(na, t) + i];
-
-				if (nm_kring_pending_on(kring))
-					kring->nr_mode = NKR_NETMAP_ON;
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
+		nm_set_native_flags(na);
 	} else {
 		nm_clear_native_flags(na);
-		for_rx_tx(t) {
-			/* Hardware rings. */
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_off(kring))
-					kring->nr_mode = NKR_NETMAP_OFF;
-			}
-
-			/* Host rings. */
-			for (i = 0; i < nma_get_host_nrings(na, t); i++) {
-				struct netmap_kring *kring =
-					NMR(na, t)[nma_get_nrings(na, t) + i];
-
-				if (nm_kring_pending_off(kring))
-					kring->nr_mode = NKR_NETMAP_OFF;
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
 	}
 
 	VTNET_CORE_UNLOCK(sc);
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 61739bec5..c4e992d82 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4129,6 +4129,25 @@ nm_clear_native_flags(struct netmap_adapter *na)
 	na->na_flags &= ~NAF_NETMAP_ON;
 }
 
+void
+netmap_krings_mode_commit(struct netmap_adapter *na, int onoff)
+{
+	enum txrx t;
+
+	for_rx_tx(t) {
+		int i;
+
+		for (i = 0; i < netmap_real_rings(na, t); i++) {
+			struct netmap_kring *kring = NMR(na, t)[i];
+
+			if (onoff && nm_kring_pending_on(kring))
+				kring->nr_mode = NKR_NETMAP_ON;
+			else if (!onoff && nm_kring_pending_off(kring))
+				kring->nr_mode = NKR_NETMAP_OFF;
+		}
+	}
+}
+
 /*
  * Module loader and unloader
  *
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 1e41896ee..adee7bad6 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -920,8 +920,6 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 {
 	struct netmap_vp_adapter *vpna =
 		(struct netmap_vp_adapter*)na;
-	enum txrx t;
-	int i;
 
 	/* persistent ports may be put in netmap mode
 	 * before being attached to a bridge
@@ -929,14 +927,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 	if (vpna->na_bdg)
 		BDG_WLOCK(vpna->na_bdg);
 	if (onoff) {
-		for_rx_tx(t) {
-			for (i = 0; i < netmap_real_rings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_on(kring))
-					kring->nr_mode = NKR_NETMAP_ON;
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
 		if (na->active_fds == 0)
 			na->na_flags |= NAF_NETMAP_ON;
 		 /* XXX on FreeBSD, persistent VALE ports should also
@@ -945,14 +936,7 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff)
 	} else {
 		if (na->active_fds == 0)
 			na->na_flags &= ~NAF_NETMAP_ON;
-		for_rx_tx(t) {
-			for (i = 0; i < netmap_real_rings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_off(kring))
-					kring->nr_mode = NKR_NETMAP_OFF;
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
 	}
 	if (vpna->na_bdg)
 		BDG_WUNLOCK(vpna->na_bdg);
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 5925544dc..1e80bcd9c 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -237,18 +237,7 @@ generic_netmap_unregister(struct netmap_adapter *na)
 		nm_os_catch_tx(gna, 0);
 	}
 
-	for_each_rx_kring_h(r, kring, na) {
-		if (nm_kring_pending_off(kring)) {
-			nm_prinf("Emulated adapter: ring '%s' deactivated", kring->name);
-			kring->nr_mode = NKR_NETMAP_OFF;
-		}
-	}
-	for_each_tx_kring_h(r, kring, na) {
-		if (nm_kring_pending_off(kring)) {
-			kring->nr_mode = NKR_NETMAP_OFF;
-			nm_prinf("Emulated adapter: ring '%s' deactivated", kring->name);
-		}
-	}
+	netmap_krings_mode_commit(na, /*onoff=*/0);
 
 	for_each_rx_kring(r, kring, na) {
 		/* Free the mbufs still pending in the RX queues,
@@ -371,19 +360,7 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
 		}
 	}
 
-	for_each_rx_kring_h(r, kring, na) {
-		if (nm_kring_pending_on(kring)) {
-			nm_prinf("Emulated adapter: ring '%s' activated", kring->name);
-			kring->nr_mode = NKR_NETMAP_ON;
-		}
-
-	}
-	for_each_tx_kring_h(r, kring, na) {
-		if (nm_kring_pending_on(kring)) {
-			nm_prinf("Emulated adapter: ring '%s' activated", kring->name);
-			kring->nr_mode = NKR_NETMAP_ON;
-		}
-	}
+	netmap_krings_mode_commit(na, /*onoff=*/1);
 
 	for_each_tx_kring(r, kring, na) {
 		/* Initialize tx_pool and tx_event. */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 2b9cdfc89..c85db6fb3 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1375,6 +1375,8 @@ nm_update_hostrings_mode(struct netmap_adapter *na)
 void nm_set_native_flags(struct netmap_adapter *);
 void nm_clear_native_flags(struct netmap_adapter *);
 
+void netmap_krings_mode_commit(struct netmap_adapter *na, int onoff);
+
 /*
  * nm_*sync_prologue() functions are used in ioctl/poll and ptnetmap
  * kthreads.
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 1a54b70f6..b9665d816 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -506,20 +506,9 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 		if (na->active_fds == 0)
 			na->na_flags |= NAF_NETMAP_ON;
 	} else {
-		enum txrx t;
-		int i;
-
 		if (na->active_fds == 0)
 			na->na_flags &= ~NAF_NETMAP_ON;
-		for_rx_tx(t) {
-			for (i = 0; i < nma_get_nrings(na, t); i++) {
-				struct netmap_kring *kring = NMR(na, t)[i];
-
-				if (nm_kring_pending_off(kring)) {
-					kring->nr_mode = NKR_NETMAP_OFF;
-				}
-			}
-		}
+		netmap_krings_mode_commit(na, onoff);
 	}
 
 	if (na->active_fds) {

From 1ce7e77ff70c57446d733552cc47eeecfc169b7b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 4 Feb 2019 16:41:54 +0100
Subject: [PATCH 1597/2207] netmap_attach_ext: use nm_prinf rather than
 if_printf

---
 LINUX/bsd_glue.h        | 2 --
 WINDOWS/win_glue.h      | 1 -
 sys/dev/netmap/netmap.c | 3 ++-
 3 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 0c56323c6..6c5e1f458 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -532,8 +532,6 @@ void netmap_bns_unregister(void);
 #define NM_BNS_PUT(b)   do { (void)(b); } while (0)
 #endif
 
-#define if_printf(ifp, fmt, ...)  dev_info(&(ifp)->dev, fmt, ##__VA_ARGS__)
-
 #ifndef BIT_ULL
 #define BIT_ULL(nr)	(1ULL << (nr))
 #endif /* !BIT_ULL */
diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index 39523d194..70f3ba7cb 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -153,7 +153,6 @@ static void panic(const char *fmt, ...)
 	NT_ASSERT(1);
 }
 
-#define if_printf	DbgPrint
 #define __assert	NT_ASSERT
 #define assert		NT_ASSERT
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c4e992d82..6fefa6e08 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3711,7 +3711,8 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		hwna->up.nm_dtor = netmap_hw_dtor;
 	}
 
-	if_printf(ifp, "netmap queues/slots: TX %d/%d, RX %d/%d\n",
+	nm_prinf("%s: netmap queues/slots: TX %d/%d, RX %d/%d\n",
+	    hwna->up.name,
 	    hwna->up.num_tx_rings, hwna->up.num_tx_desc,
 	    hwna->up.num_rx_rings, hwna->up.num_rx_desc);
 	return 0;

From 07efc0f2d12e765c24324f7561c8d551fee68a6e Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 4 Feb 2019 16:58:28 +0100
Subject: [PATCH 1598/2207] clean up drivers to replace D,ND,RD with nm_pr*

---
 LINUX/i40e_netmap_linux.h        | 10 +++++-----
 LINUX/if_e1000_netmap.h          |  8 ++++----
 LINUX/if_e1000e_netmap.h         |  6 +++---
 LINUX/if_igb_netmap.h            | 14 +++----------
 LINUX/if_virtio_net_netmap.h     | 10 +++++-----
 LINUX/if_vmxnet3_netmap_v2.h     |  2 +-
 LINUX/ixgbe_netmap_linux.h       | 12 +++++------
 LINUX/mlx5_netmap_linux.h        |  6 +++---
 LINUX/netmap_ptnet.c             | 18 ++++++++---------
 LINUX/veth_netmap.h              |  8 ++++----
 LINUX/virtio_netmap.h            | 30 ++++++++++++++--------------
 sys/dev/netmap/if_lem_netmap.h   |  2 +-
 sys/dev/netmap/if_ptnet.c        | 34 ++++++++++++++++----------------
 sys/dev/netmap/if_vtnet_netmap.h |  6 +++---
 14 files changed, 79 insertions(+), 87 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 462d56d5c..1ce377557 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -96,7 +96,7 @@ set_crcstrip(struct ixgbe_hw *hw, int onoff)
 	hl = IXGBE_READ_REG(hw, IXGBE_HLREG0);
 	rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
 	if (netmap_verbose)
-		D("%s read  HLREG 0x%x rxc 0x%x",
+		nm_prinf("%s read  HLREG 0x%x rxc 0x%x",
 			onoff ? "enter" : "exit", hl, rxc);
 	/* hw requirements ... */
 	rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
@@ -111,7 +111,7 @@ set_crcstrip(struct ixgbe_hw *hw, int onoff)
 		rxc |= IXGBE_RDRXCTL_CRCSTRIP;
 	}
 	if (netmap_verbose)
-		D("%s write HLREG 0x%x rxc 0x%x",
+		nm_prinf("%s write HLREG 0x%x rxc 0x%x",
 			onoff ? "enter" : "exit", hl, rxc);
 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl);
 	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc);
@@ -320,7 +320,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 
 	txr = NM_I40E_TX_RING(vsi, kring->ring_id);
 	if (unlikely(!txr || !txr->desc)) {
-		RD(1, "ring %s is missing (txr=%p)", kring->name, txr);
+		nm_prlim(1, "ring %s is missing (txr=%p)", kring->name, txr);
 		return ENXIO;
 	}
 
@@ -487,7 +487,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 	rxr = NM_I40E_RX_RING(vsi, kring->ring_id);
 	if (unlikely(!rxr || !rxr->desc)) {
-		RD(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
+		nm_prlim(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
 		return ENXIO;
 	}
 
@@ -561,7 +561,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			rxr->next_to_clean = nic_i;
 			if (likely(ntail <= lim)) {
 				kring->nr_hwtail = ntail;
-				ND("%s: nic_i %u nm_i %u ntail %u n %u", ifp->if_xname, nic_i, nm_i, ntail, n);
+				nm_prdis("%s: nic_i %u nm_i %u ntail %u n %u", ifp->if_xname, nic_i, nm_i, ntail, n);
 			}
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index bc204b7aa..9b99aec6d 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -164,8 +164,8 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		/* record completed transmissions using TDH */
 		nic_i = readl(adapter->hw.hw_addr + txr->tdh);
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("TDH wrap %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -314,7 +314,7 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		struct e1000_rx_ring *rxr;
 		slot = netmap_reset(na, NR_RX, r, 0);
 		if (!slot) {
-			D("Skipping RX ring %d, netmap mode not requested", r);
+			nm_prinf("Skipping RX ring %d, netmap mode not requested", r);
 			continue;
 		}
 		rxr = &adapter->rx_ring[r];
@@ -338,7 +338,7 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 	for (r = 0; r < na->num_tx_rings; r++) {
 		slot = netmap_reset(na, NR_TX, r, 0);
 		if (!slot) {
-			D("Skipping TX ring %d, netmap mode not requested", r);
+			nm_prinf("Skipping TX ring %d, netmap mode not requested", r);
 			continue;
 		}
 
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 9cdaef5b7..0fba6c280 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -196,7 +196,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 		nic_i = NM_RD_TX_HEAD();
 		if (unlikely(nic_i >= kring->nkr_num_slots)) {
 			/* This should never happen. */
-			D("Warning: TDH wrap %d", nic_i);
+			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -327,7 +327,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 /* diagnostic routine to catch errors */
 static void e1000e_no_rx_alloc(struct SOFTC_T *a, int n)
 {
-	D("Error: alloc_rx_buf() should not be called");
+	nm_prerr("alloc_rx_buf() should not be called");
 }
 
 
@@ -356,7 +356,7 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 			si = netmap_idx_n2k(na->rx_rings[0], i);
 			PNMB(na, slot + si, &paddr);
 			if (bi->skb)
-				D("Warning: rx skb still set on slot #%d", i);
+				nm_prerr("Warning: rx skb still set on slot #%d", i);
 			E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr);
 		}
 		rxr->next_to_use = 0;
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index a4545e018..5c841c2b0 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -249,8 +249,8 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		/* record completed transmissions using TDH */
 		nic_i = READ_TDH(adapter, txr);
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -451,14 +451,6 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 		uint64_t paddr;
 		int si = netmap_idx_n2k(na->rx_rings[reg_idx], i);
 
-#if 0
-		// XXX the skb check can go away
-		struct igb_rx_buffer *bi = &rxr->rx_buffer_info[i];
-		if (bi->skb)
-			D("rx buf %d was set", i);
-		bi->skb = NULL; // XXX leak if set
-#endif /* useless */
-
 		PNMB(na, slot + si, &paddr);
 		rx_desc = E1000_RX_DESC_ADV(*rxr, i);
 		rx_desc->read.hdr_addr = 0;
@@ -468,7 +460,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[reg_idx]);
 
 	wmb();	/* Force memory writes to complete */
-	ND("%s rxr%d.tail %d", na->name, reg_idx, i);
+	nm_prdis("%s rxr%d.tail %d", na->name, reg_idx, i);
 	writel(i, rxr->tail);
 	return 1;	// success
 }
diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index e72e6875a..7578165f7 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -829,13 +829,13 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 				break;
 
 			if (unlikely(token != na)) {
-				RD(5, "Received unexpected virtqueue token %p\n",
+				nm_prlim(5, "Received unexpected virtqueue token %p\n",
 						token);
 			} else {
 				/* Skip the virtio-net header. */
 				len -= vnet_hdr_len;
 				if (unlikely(len < 0)) {
-					RD(1, "Truncated virtio-net-header, missing %d"
+					nm_prlim(1, "Truncated virtio-net-header, missing %d"
 							" bytes", -len);
 					len = 0;
 				}
@@ -849,7 +849,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 		kring->nr_hwtail = nm_i;
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
-	ND("[B] h %d c %d hwcur %d hwtail %d",
+	nm_prdis("[B] h %d c %d hwcur %d hwtail %d",
 			ring->head, ring->cur, kring->nr_hwcur,
 			kring->nr_hwtail);
 
@@ -875,7 +875,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 			sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na));
 			nospace = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC);
 			if (nospace) {
-				RD(3, "virtqueue_add_inbuf failed [err=%d]",
+				nm_prlim(2, "virtqueue_add_inbuf failed [err=%d]",
 				   nospace);
 				break;
 			}
@@ -892,7 +892,7 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 		virtqueue_enable_cb(vq);
 
 
-	ND("[C] h %d c %d t %d hwcur %d hwtail %d",
+	nm_prdis("[C] h %d c %d t %d hwcur %d hwtail %d",
 			ring->head, ring->cur, ring->tail,
 			kring->nr_hwcur, kring->nr_hwtail);
 
diff --git a/LINUX/if_vmxnet3_netmap_v2.h b/LINUX/if_vmxnet3_netmap_v2.h
index cebb5cbb9..d1f1de1c0 100644
--- a/LINUX/if_vmxnet3_netmap_v2.h
+++ b/LINUX/if_vmxnet3_netmap_v2.h
@@ -268,7 +268,7 @@ vmxnet3_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			/* device may have skipped some rx descs */
 			while (unlikely(nic_i != rx_idx)) {
-				D("%u skipped! rx_idx %u", nic_i, rx_idx);
+				nm_prinf("%u skipped! rx_idx %u", nic_i, rx_idx);
 				/* the nic has skipped some slots because who
 				 * knows why. To shelter the application from
 				 * this we would need to rotate the
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 96648e6e3..9649113ec 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -107,7 +107,7 @@ ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 static void
 ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 {
-	RD(5, "per-queue irq disable not supported");
+	nm_prlim(1, "per-queue irq disable not supported");
 }
 #endif /* NETMAP_LINUX_IXGBE_HAVE_DISABLE */
 
@@ -136,7 +136,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	 * (ixgbe datasheet - Section 7.1.9)
 	 */
 	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
-	ND("bufsz: %d srrctl: %x", NETMAP_BUF_SIZE(na), srrctl);
+	nm_prdis("bufsz: %d srrctl: %x", NETMAP_BUF_SIZE(na), srrctl);
 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
 }
 
@@ -181,14 +181,14 @@ static void
 ixgbe_netmap_intr(struct netmap_adapter *na, int onoff)
 {
 	// TODO
-	RD(5, "per-queue irq disable not supported");
+	nm_prlim(5, "per-queue irq disable not supported");
 }
 
 static void
 ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_RING *rx_ring)
 {
 	// TODO
-	D("not supported");
+	nm_prerr("not supported");
 }
 
 #ifdef NETMAP_LINUX_IXGBEVF_HAVE_NTA
@@ -423,7 +423,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	if ((flags & NAF_FORCE_RECLAIM) || nm_kr_txempty(kring)) {
 		nic_i = NM_ACCESS_ONCE(*ina->heads[ring_nr].phead);
 		nm_i = netmap_idx_n2k(kring, nic_i);
-		ND(5, "%s: h %d", kring->name, h);
+		nm_prdis(5, "%s: h %d", kring->name, h);
 		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 #else /* NM_IXGBE_USE_TDH */
@@ -779,7 +779,7 @@ ixgbe_netmap_create_heads(struct netmap_adapter *na)
 			goto err;
 		}
 		*h->phead = 0;
-		ND("%s: phead %p *phead %x", na->tx_rings[i].name, h->phead, *h->phead);
+		nm_prdis("%s: phead %p *phead %x", na->tx_rings[i].name, h->phead, *h->phead);
 	}
 	return 0;
 
diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index ba6263ddc..f163e5352 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -107,7 +107,7 @@ int mlx5e_netmap_reg(struct netmap_adapter *na, int onoff) {
   int err = 0;
   int was_opened;
 
-  D("mlx5e switching %s native netmap mode", onoff ? "into" : "out of");
+  nm_printf("mlx5e switching %s native netmap mode", onoff ? "into" : "out of");
 
   /* Should we check and wait for any reset in progress to complete? */
   mutex_lock(&adapter->state_lock);
@@ -198,7 +198,7 @@ int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags) {
 
   if (nm_i != head) { /* we have new packets to send */
 
-    /* D("TX ring %u sending slots %u to %u",
+    /* nm_prinf("TX ring %u sending slots %u to %u",
      *            ring_nr, nm_i, nm_prev(head, lim));
      */
 
@@ -663,7 +663,7 @@ int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr) {
     count++;
   }
 
-  D("populated %d WQEs in ring %d", count, ring_nr);
+  nm_prinf("populated %d WQEs in ring %d", count, ring_nr);
 
   /* tell netmap how many buffers we have prepared */
   na->rx_rings[ring_nr]->nr_hwcur = count;
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 956a886e7..7f8ce00af 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -221,7 +221,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	ptnet_sync_tail(ktoa, kring);
 
 	if (unlikely(ptnet_tx_slots(a.ring) < pi->min_tx_slots)) {
-		ND(1, "TX ring unexpected overflow, requeuing");
+		nm_prdis(1, "TX ring unexpected overflow, requeuing");
 
 		return NETDEV_TX_BUSY;
 	}
@@ -270,7 +270,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 		vh->num_buffers = 0; /* unused */
 
-		ND(1, "%s: vnet hdr: flags %x csum_start %u csum_ofs %u hdr_len = "
+		nm_prdis(1, "%s: vnet hdr: flags %x csum_start %u csum_ofs %u hdr_len = "
 		      "%u gso_size %u gso_type %x", __func__, vh->hdr.flags,
 		      vh->hdr.csum_start, vh->hdr.csum_offset, vh->hdr.hdr_len,
 		      vh->hdr.gso_size, vh->hdr.gso_type);
@@ -297,7 +297,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	a.ring->head = a.ring->cur = nm_next(a.head, a.lim);
 
 	if (skb_shinfo(skb)->nr_frags) {
-		ND(1, "TX frags #%u lfsz %u tsz %d gso_segs %d gso_size %d", skb_shinfo(skb)->nr_frags,
+		nm_prdis(1, "TX frags #%u lfsz %u tsz %d gso_segs %d gso_size %d", skb_shinfo(skb)->nr_frags,
 		skb_frag_size(&skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags-1]),
 		(int)skb->len, skb_shinfo(skb)->gso_segs, skb_shinfo(skb)->gso_size);
 	}
@@ -517,7 +517,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 
 		vh = nmbuf;
 		if (likely(have_vnet_hdr)) {
-			ND(1, "%s: vnet hdr: flags %x csum_start %u "
+			nm_prdis(1, "%s: vnet hdr: flags %x csum_start %u "
 			      "csum_ofs %u hdr_len = %u gso_size %u "
 			      "gso_type %x", __func__, vh->hdr.flags,
 			      vh->hdr.csum_start, vh->hdr.csum_offset,
@@ -546,7 +546,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 			head = nm_next(head, lim);
 			nns++;
 			if (unlikely(head == ring->tail)) {
-				ND(1, "Warning: truncated packet, retrying");
+				nm_prdis(1, "Warning: truncated packet, retrying");
 				dev_kfree_skb_any(skb);
 				work_done ++;
 				pi->netdev->stats.rx_frame_errors ++;
@@ -562,7 +562,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 			do {
 				if (!skbdata_avail) {
 					if (skbpage) {
-						ND(1, "add f #%u fsz %lu tsz %d", skb_shinfo(skb)->nr_frags,
+						nm_prdis(1, "add f #%u fsz %lu tsz %d", skb_shinfo(skb)->nr_frags,
 								PAGE_SIZE - skbdata_avail, (int)skb->len);
 						skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
 								skbpage, 0, PAGE_SIZE - skbdata_avail
@@ -599,7 +599,7 @@ ptnet_rx_poll(struct napi_struct *napi, int budget)
 					, PAGE_SIZE
 #endif
 					);
-			ND(1, "RX frags #%u lfsz %lu tsz %d nns %d",
+			nm_prdis(1, "RX frags #%u lfsz %lu tsz %d nns %d",
 			   skb_shinfo(skb)->nr_frags,
 			   PAGE_SIZE - skbdata_avail, (int)skb->len, nns);
 		}
@@ -1040,10 +1040,10 @@ ptnet_sync_from_csb(struct ptnet_info *pi, struct netmap_adapter *na)
 		kring->nr_hwtail = kring->rtail =
 			kring->ring->tail = ktoa->hwtail;
 
-		ND("%s: csb {hc %u h %u c %u ht %u}", kring->name,
+		nm_prdis("%s: csb {hc %u h %u c %u ht %u}", kring->name,
 		   ktoa->hwcur, atok->head, atok->cur,
 		   ktoa->hwtail);
-		ND("%s: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
+		nm_prdis("%s: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   kring->name, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
 		   kring->rtail, kring->ring->tail);
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index f2cb2197d..1f9e9bad0 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -137,13 +137,13 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		}
 		nm_set_native_flags(na);
 		if (netmap_verbose) {
-			D("registered veth %s", na->name);
+			nm_prinf("registered veth %s", na->name);
 		}
 	} else {
 		nm_clear_native_flags(na);
 		netmap_krings_mode_commit(na, onoff);
 		if (netmap_verbose) {
-			D("unregistered veth %s", na->name);
+			nm_prinf("unregistered veth %s", na->name);
 		}
 	}
 
@@ -199,14 +199,14 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 	}
 
 	if (netmap_verbose) {
-		D("Delete krings for %s and its peer", na->name);
+		nm_prinf("Delete krings for %s and its peer", na->name);
 	}
 
 	rcu_read_lock();
 	peer_na = veth_get_peer_na(na);
 	rcu_read_unlock();
 	if (!peer_na) {
-		D("veth peer not found");
+		nm_prinf("veth peer not found");
 		return;
 	}
 
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 8ee4008ce..bf5e37ff6 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -199,7 +199,7 @@ virtio_netmap_clean_used_rings(struct virtnet_info *vi,
 			}
 			n++;
 		}
-		D("got %d used bufs on queue tx-%d", n, i);
+		nm_prinf("got %d used bufs on queue tx-%d", n, i);
 	}
 
 	for (i = 0; i < DEV_NUM_RX_QUEUES(vi->dev); i++) {
@@ -212,7 +212,7 @@ virtio_netmap_clean_used_rings(struct virtnet_info *vi,
 			n++;
 			RXNUM_DEC(vi, i);
 		}
-		D("got %d used bufs on queue rx-%d", n, i);
+		nm_prinf("got %d used bufs on queue rx-%d", n, i);
 	}
 }
 
@@ -238,7 +238,7 @@ virtio_netmap_reclaim_unused(struct virtnet_info *vi)
 		while ((token = virtqueue_detach_unused_buf(vq)) != NULL) {
 			n++;
 		}
-		D("detached %d pending bufs on queue tx-%d", n, i);
+		nm_prinf("detached %d pending bufs on queue tx-%d", n, i);
 	}
 
 	for (i = 0; i < DEV_NUM_RX_QUEUES(vi->dev); i++) {
@@ -250,7 +250,7 @@ virtio_netmap_reclaim_unused(struct virtnet_info *vi)
 			RXNUM_DEC(vi, i);
 			n++;
 		}
-		D("detached %d pending bufs on queue rx-%d", n, i);
+		nm_prinf("detached %d pending bufs on queue rx-%d", n, i);
 	}
 }
 
@@ -284,7 +284,7 @@ virtio_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 
 	if (!(hwrings_pending == 0 || hwrings_pending == hwrings)) {
-		D("virtio-net native adapter can only open "
+		nm_prerr("virtio-net native adapter can only open "
 		  "all RX and TX hw rings");
 		return EINVAL;
 	}
@@ -417,7 +417,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags)
 			sg_set_buf(sg + 1, addr, len);
 			nospace = virtqueue_add_outbuf(vq, sg, 2, na, GFP_ATOMIC);
 			if (nospace) {
-				RD(3, "virtqueue_add_outbuf failed [err=%d]",
+				nm_prlim(2, "virtqueue_add_outbuf failed [err=%d]",
 				   nospace);
 				break;
 			}
@@ -516,13 +516,13 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 			RXNUM_DEC(vi, ring_nr);
 
 			if (unlikely(token != na)) {
-				RD(5, "Received unexpected virtqueue token %p\n",
+				nm_prlim(2, "Received unexpected virtqueue token %p\n",
 						token);
 			} else {
 				/* Skip the virtio-net header. */
 				len -= vnet_hdr_len;
 				if (unlikely(len < 0)) {
-					RD(5, "Truncated virtio-net-header, missing %d"
+					nm_prlim(2, "Truncated virtio-net-header, missing %d"
 							" bytes", -len);
 					len = 0;
 				}
@@ -536,7 +536,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 		kring->nr_hwtail = nm_i;
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
-	ND("[B] h %d c %d hwcur %d hwtail %d",
+	nm_prdis("[B] h %d c %d hwcur %d hwtail %d",
 			ring->head, ring->cur, kring->nr_hwcur,
 			kring->nr_hwtail);
 
@@ -563,7 +563,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 			sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na));
 			nospace = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC);
 			if (nospace) {
-				RD(3, "virtqueue_add_inbuf failed [err=%d]",
+				nm_prlim(2, "virtqueue_add_inbuf failed [err=%d]",
 				   nospace);
 				break;
 			}
@@ -583,7 +583,7 @@ virtio_netmap_rxsync(struct netmap_kring *kring, int flags)
 	}
 
 
-	ND("[C] h %d c %d t %d hwcur %d hwtail %d",
+	nm_prdis("[C] h %d c %d t %d hwcur %d hwtail %d",
 			ring->head, ring->cur, ring->tail,
 			kring->nr_hwcur, kring->nr_hwtail);
 
@@ -639,7 +639,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi)
 			sg_set_buf(sg + 1, addr, NETMAP_BUF_SIZE(na));
 			err = virtqueue_add_inbuf(vq, sg, 2, na, GFP_ATOMIC);
 			if (err < 0) {
-				D("virtqueue_add_inbuf failed");
+				nm_prerr("virtqueue_add_inbuf failed");
 
 				return 0;
 			}
@@ -648,7 +648,7 @@ virtio_netmap_init_buffers(struct virtnet_info *vi)
 			if (VQ_FULL(vq, err))
 				break;
 		}
-		D("added %d inbufs on queue %d", i, r);
+		nm_prinf("added %d inbufs on queue %d", i, r);
 		virtqueue_kick(vq);
 	}
 	return 1;
@@ -696,11 +696,11 @@ virtio_netmap_attach(struct virtnet_info *vi)
 
 	ret = netmap_attach_ext(&na, sizeof(struct netmap_virtio_adapter), 1);
 	if (ret) {
-		D("Failed to attach virtio-net interface");
+		nm_prerr("Failed to attach virtio-net interface");
 		return;
 	}
 
-	D("virtio attached txq=%d, txd=%d rxq=%d, rxd=%d",
+	nm_prinf("virtio attached txq=%d, txd=%d rxq=%d, rxd=%d",
 			na.num_tx_rings, na.num_tx_desc,
 			na.num_rx_rings, na.num_rx_desc);
 }
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index edbc666ea..3ddd278d6 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -228,7 +228,7 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags)
 				break;
 			len = le16toh(curr->length) - 4; // CRC
 			if (len < 0) {
-				RD(5, "bogus pkt (%d) size %d nic idx %d", n, len, nic_i);
+				nm_prlim(2, "bogus pkt (%d) size %d nic idx %d", n, len, nic_i);
 				len = 0;
 			}
 			ring->slot[nm_i].len = len;
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 25ff96eb1..5ba34aa67 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -1151,10 +1151,10 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
 		kring->nr_hwtail = kring->rtail =
 			kring->ring->tail = ktoa->hwtail;
 
-		ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
+		nm_prdis("%d,%d: csb {hc %u h %u c %u ht %u}", t, i,
 		   ktoa->hwcur, atok->head, atok->cur,
 		   ktoa->hwtail);
-		ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
+		nm_prdis("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}",
 		   t, i, kring->nr_hwcur, kring->rhead, kring->rcur,
 		   kring->ring->head, kring->ring->cur, kring->nr_hwtail,
 		   kring->rtail, kring->ring->tail);
@@ -1193,7 +1193,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 	 * in the RX rings, since we will not receive further interrupts
 	 * until these will be processed. */
 	if (native && !onoff && na->active_fds == 0) {
-		D("Exit netmap mode, re-enable interrupts");
+		nm_prinf("Exit netmap mode, re-enable interrupts");
 		for (i = 0; i < sc->num_rings; i++) {
 			pq = sc->queues + i;
 			pq->atok->appl_need_kick = 1;
@@ -1711,7 +1711,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 
 	if (!PTNET_Q_TRYLOCK(pq)) {
 		/* We failed to acquire the lock, schedule the taskqueue. */
-		RD(1, "Deferring TX work");
+		nm_prlim(1, "Deferring TX work");
 		if (may_resched) {
 			taskqueue_enqueue(pq->taskq, &pq->task);
 		}
@@ -1721,7 +1721,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 
 	if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
 		PTNET_Q_UNLOCK(pq);
-		RD(1, "Interface is down");
+		nm_prlim(1, "Interface is down");
 		return ENETDOWN;
 	}
 
@@ -1759,7 +1759,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 					break;
 				}
 
-				RD(1, "Found more slots by doublecheck");
+				nm_prlim(1, "Found more slots by doublecheck");
 				/* More slots were freed before reactivating
 				 * the interrupts. */
 				atok->appl_need_kick = 0;
@@ -1798,7 +1798,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 					continue;
 				}
 			}
-			ND(1, "%s: [csum_flags %lX] vnet hdr: flags %x "
+			nm_prdis(1, "%s: [csum_flags %lX] vnet hdr: flags %x "
 			      "csum_start %u csum_ofs %u hdr_len = %u "
 			      "gso_size %u gso_type %x", __func__,
 			      mhead->m_pkthdr.csum_flags, vh->flags,
@@ -1873,7 +1873,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 	}
 
 	if (count >= budget && may_resched) {
-		DBG(RD(1, "out of budget: resched, %d mbufs pending\n",
+		DBG(nm_prlim(1, "out of budget: resched, %d mbufs pending\n",
 					drbr_inuse(ifp, pq->bufring)));
 		taskqueue_enqueue(pq->taskq, &pq->task);
 	}
@@ -1915,7 +1915,7 @@ ptnet_transmit(if_t ifp, struct mbuf *m)
 	err = drbr_enqueue(ifp, pq->bufring, m);
 	if (err) {
 		/* ENOBUFS when the bufring is full */
-		RD(1, "%s: drbr_enqueue() failed %d\n",
+		nm_prlim(1, "%s: drbr_enqueue() failed %d\n",
 			__func__, err);
 		pq->stats.errors ++;
 		return err;
@@ -2060,13 +2060,13 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 				/* There is no good reason why host should
 				 * put the header in multiple netmap slots.
 				 * If this is the case, discard. */
-				RD(1, "Fragmented vnet-hdr: dropping");
+				nm_prlim(1, "Fragmented vnet-hdr: dropping");
 				head = ptnet_rx_discard(kring, head);
 				pq->stats.iqdrops ++;
 				deliver = 0;
 				goto skip;
 			}
-			ND(1, "%s: vnet hdr: flags %x csum_start %u "
+			nm_prdis(1, "%s: vnet hdr: flags %x csum_start %u "
 			      "csum_ofs %u hdr_len = %u gso_size %u "
 			      "gso_type %x", __func__, vh->flags,
 			      vh->csum_start, vh->csum_offset, vh->hdr_len,
@@ -2130,7 +2130,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 				/* The very last slot prepared by the host has
 				 * the NS_MOREFRAG set. Drop it and continue
 				 * the outer cycle (to do the double-check). */
-				RD(1, "Incomplete packet: dropping");
+				nm_prlim(1, "Incomplete packet: dropping");
 				m_freem(mhead);
 				pq->stats.iqdrops ++;
 				goto host_sync;
@@ -2168,7 +2168,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 					| VIRTIO_NET_HDR_F_DATA_VALID))) {
 			if (unlikely(ptnet_rx_csum(mhead, vh))) {
 				m_freem(mhead);
-				RD(1, "Csum offload error: dropping");
+				nm_prlim(1, "Csum offload error: dropping");
 				pq->stats.iqdrops ++;
 				deliver = 0;
 			}
@@ -2214,7 +2214,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 	if (count >= budget && may_resched) {
 		/* If we ran out of budget or the double-check found new
 		 * slots to process, schedule the taskqueue. */
-		DBG(RD(1, "out of budget: resched h %u t %u\n",
+		DBG(nm_prlim(1, "out of budget: resched h %u t %u\n",
 					head, ring->tail));
 		taskqueue_enqueue(pq->taskq, &pq->task);
 	}
@@ -2229,7 +2229,7 @@ ptnet_rx_task(void *context, int pending)
 {
 	struct ptnet_queue *pq = context;
 
-	DBG(RD(1, "%s: pq #%u\n", __func__, pq->kring_id));
+	DBG(nm_prlim(1, "%s: pq #%u\n", __func__, pq->kring_id));
 	ptnet_rx_eof(pq, PTNET_RX_BUDGET, true);
 }
 
@@ -2238,7 +2238,7 @@ ptnet_tx_task(void *context, int pending)
 {
 	struct ptnet_queue *pq = context;
 
-	DBG(RD(1, "%s: pq #%u\n", __func__, pq->kring_id));
+	DBG(nm_prlim(1, "%s: pq #%u\n", __func__, pq->kring_id));
 	ptnet_drain_transmit_queue(pq, PTNET_TX_BUDGET, true);
 }
 
@@ -2256,7 +2256,7 @@ ptnet_poll(if_t ifp, enum poll_cmd cmd, int budget)
 
 	KASSERT(sc->num_rings > 0, ("Found no queues in while polling ptnet"));
 	queue_budget = MAX(budget / sc->num_rings, 1);
-	RD(1, "Per-queue budget is %d", queue_budget);
+	nm_prlim(1, "Per-queue budget is %d", queue_budget);
 
 	while (budget) {
 		unsigned int rcnt = 0;
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 0b3ac3f34..abaed8ee7 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -363,7 +363,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 				/* Skip the virtio-net header. */
 				len -= sc->vtnet_hdr_size;
 				if (unlikely(len < 0)) {
-					RD(1, "Truncated virtio-net-header, "
+					nm_prlim(1, "Truncated virtio-net-header, "
 						"missing %d bytes", -len);
 					len = 0;
 				}
@@ -375,7 +375,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 		kring->nr_hwtail = nm_i;
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
-	ND("[B] h %d c %d hwcur %d hwtail %d", ring->head, ring->cur,
+	nm_prdis("[B] h %d c %d hwcur %d hwtail %d", ring->head, ring->cur,
 				kring->nr_hwcur, kring->nr_hwtail);
 
 	/*
@@ -390,7 +390,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 		virtqueue_notify(vq);
 	}
 
-	ND("[C] h %d c %d t %d hwcur %d hwtail %d", ring->head, ring->cur,
+	nm_prdis("[C] h %d c %d t %d hwcur %d hwtail %d", ring->head, ring->cur,
 		ring->tail, kring->nr_hwcur, kring->nr_hwtail);
 
 	return 0;

From db7ff629ae13a6b5d61ec2468d86e0b1df8ed87a Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 4 Feb 2019 21:26:08 +0100
Subject: [PATCH 1599/2207] remove D, RD and ND from kernel code

---
 LINUX/netmap_ptnet.c                |  4 +-
 WINDOWS/netmap_windows.c            | 12 +++---
 sys/dev/netmap/if_em_netmap.h       |  4 +-
 sys/dev/netmap/if_igb_netmap.h      |  4 +-
 sys/dev/netmap/if_lem_netmap.h      |  6 +--
 sys/dev/netmap/ixgbe_netmap.h       |  8 ++--
 sys/dev/netmap/netmap.c             | 60 ++++++++++++++--------------
 sys/dev/netmap/netmap_bdg.c         | 40 +++++++++----------
 sys/dev/netmap/netmap_kern.h        | 19 ++++-----
 sys/dev/netmap/netmap_legacy.c      |  4 +-
 sys/dev/netmap/netmap_mem2.c        | 62 ++++++++++++++---------------
 sys/dev/netmap/netmap_monitor.c     | 43 ++++++++++----------
 sys/dev/netmap/netmap_offloadings.c | 46 ++++++++++-----------
 sys/dev/netmap/netmap_pipe.c        | 61 ++++++++++++++--------------
 sys/dev/netmap/netmap_vale.c        | 51 ++++++++++++------------
 15 files changed, 210 insertions(+), 214 deletions(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 7f8ce00af..d5ccec819 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -45,9 +45,9 @@ module_param(ptnet_gso, bool, 0644);
 //#define HANGCTRL
 
 #if 0  /* Switch to 1 to enable per-packet logs. */
-#define DBG D
+#define DBG nm_prinf
 #else
-#define DBG ND
+#define DBG nm_prdis
 #endif
 
 #define PTNET_DRV_NAME "ptnet"
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 3c794eab1..63925458c 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -90,12 +90,12 @@ ioctlCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
 	    status = STATUS_INSUFFICIENT_RESOURCES;
 	} else {
 	    priv->np_refs = 1;
-	    D("Netmap.sys: ioctlCreate::priv->np_refcount = %i", priv->np_refs);
+	    nm_prinf("Netmap.sys: ioctlCreate::priv->np_refcount = %i", priv->np_refs);
 	    irpSp->FileObject->FsContext = priv;
 	}
     } else {
 	priv->np_refs += 1;
-	D("Netmap.sys: ioctlCreate::priv->np_refcount = %i", priv->np_refs);
+	nm_prinf("Netmap.sys: ioctlCreate::priv->np_refcount = %i", priv->np_refs);
     }
     NMG_UNLOCK();
 
@@ -611,7 +611,7 @@ ifunit_ref(const char* name)
     struct net_device *	ifp = NULL;
 
     if (strlen(name) < 4 || _strnicmp(name, "eth", 3) != 0) {
-	D("not a NIC");
+	nm_prerr("not a NIC");
 	return NULL;
     }
 	if (ndis_hooks.ndis_regif == NULL)
@@ -694,19 +694,19 @@ windows_netmap_mmap(PIRP Irp)
 	priv = irpSp->FileObject->FsContext;
 
 	if (priv == NULL) {
-		D("no priv");
+		nm_prerr("no priv");
 		return STATUS_DEVICE_DATA_ERROR;
 	}
 	na = priv->np_na;
 	if (na == NULL) {
-		D("na not attached");
+		nm_prerr("na not attached");
 		return STATUS_DEVICE_DATA_ERROR;
 	}
 	mb(); /* XXX really ? */
 
 	mdl = win32_build_user_vm_map(na->nm_mem);
 	if (mdl == NULL) {
-		D("failed building memory map");
+		nm_prerr("failed building memory map");
 		return STATUS_DEVICE_DATA_ERROR;
 	}
 
diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index 01a7a2971..766db141c 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -190,8 +190,8 @@ em_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
 		/* record completed transmissions using TDH */
 		nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(kring->ring_id));
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlilkely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		if (nic_i != txr->next_to_clean) {
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index b9f8f47b2..8ae54e54a 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -174,8 +174,8 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
 		/* record completed transmissions using TDH */
 		nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(kring->ring_id));
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		txr->next_to_clean = nic_i;
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index 3ddd278d6..46b168c40 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -174,8 +174,8 @@ lem_netmap_txsync(struct netmap_kring *kring, int flags)
 		kring->last_reclaim = ticks;
 		/* record completed transmissions using TDH */
 		nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(0));
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		adapter->next_tx_to_clean = nic_i;
@@ -240,7 +240,7 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags)
 			nic_i = nm_next(nic_i, lim);
 		}
 		if (n) { /* update the state variables */
-			ND("%d new packets at nic %d nm %d tail %d",
+			nm_prdis("%d new packets at nic %d nm %d tail %d",
 				n,
 				adapter->next_rx_desc_to_check,
 				netmap_idx_n2k(kring, adapter->next_rx_desc_to_check),
diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h
index c57adba71..feac9da1b 100644
--- a/sys/dev/netmap/ixgbe_netmap.h
+++ b/sys/dev/netmap/ixgbe_netmap.h
@@ -90,7 +90,7 @@ set_crcstrip(struct ixgbe_hw *hw, int onoff)
 	hl = IXGBE_READ_REG(hw, IXGBE_HLREG0);
 	rxc = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
 	if (netmap_verbose)
-		D("%s read  HLREG 0x%x rxc 0x%x",
+		nm_prinf("%s read  HLREG 0x%x rxc 0x%x",
 			onoff ? "enter" : "exit", hl, rxc);
 	/* hw requirements ... */
 	rxc &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
@@ -105,7 +105,7 @@ set_crcstrip(struct ixgbe_hw *hw, int onoff)
 		rxc |= IXGBE_RDRXCTL_CRCSTRIP;
 	}
 	if (netmap_verbose)
-		D("%s write HLREG 0x%x rxc 0x%x",
+		nm_prinf("%s write HLREG 0x%x rxc 0x%x",
 			onoff ? "enter" : "exit", hl, rxc);
 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hl);
 	IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc);
@@ -328,8 +328,8 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 		 */
 		nic_i = IXGBE_READ_REG(&adapter->hw, IXGBE_IS_VF(adapter) ?
 				IXGBE_VFTDH(kring->ring_id) : IXGBE_TDH(kring->ring_id));
-		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
-			D("TDH wrap %d", nic_i);
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
+			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
 		if (nic_i != txr->next_to_clean) {
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6fefa6e08..993c63da0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -893,7 +893,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 			kring->rtail = kring->nr_hwtail = (t == NR_TX ? ndesc - 1 : 0);
 			snprintf(kring->name, sizeof(kring->name) - 1, "%s %s%d", na->name,
 					nm_txrx2str(t), i);
-			ND("ktx %s h %d c %d t %d",
+			nm_prdis("ktx %s h %d c %d t %d",
 				kring->name, kring->rhead, kring->rcur, kring->rtail);
 			err = nm_os_selinfo_init(&kring->si, kring->name);
 			if (err) {
@@ -955,7 +955,7 @@ netmap_hw_krings_delete(struct netmap_adapter *na)
 
 	for (i = nma_get_nrings(na, NR_RX); i < lim; i++) {
 		struct mbq *q = &NMR(na, NR_RX)[i]->rx_queue;
-		ND("destroy sw mbq with len %d", mbq_len(q));
+		nm_prdis("destroy sw mbq with len %d", mbq_len(q));
 		mbq_purge(q);
 		mbq_safe_fini(q);
 	}
@@ -1176,7 +1176,7 @@ netmap_grab_packets(struct netmap_kring *kring, struct mbq *q, int force)
 		if ((slot->flags & NS_FORWARD) == 0 && !force)
 			continue;
 		if (slot->len < 14 || slot->len > NETMAP_BUF_SIZE(na)) {
-			RD(5, "bad pkt at %d len %d", n, slot->len);
+			nm_prlim(5, "bad pkt at %d len %d", n, slot->len);
 			continue;
 		}
 		slot->flags &= ~NS_FORWARD; // XXX needed ?
@@ -1290,7 +1290,7 @@ netmap_txsync_to_host(struct netmap_kring *kring, int flags)
 	 */
 	mbq_init(&q);
 	netmap_grab_packets(kring, &q, 1 /* force */);
-	ND("have %d pkts in queue", mbq_len(&q));
+	nm_prdis("have %d pkts in queue", mbq_len(&q));
 	kring->nr_hwcur = head;
 	kring->nr_hwtail = head + lim;
 	if (kring->nr_hwtail > lim)
@@ -1338,7 +1338,7 @@ netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 
 			m_copydata(m, 0, len, NMB(na, slot));
-			ND("nm %d len %d", nm_i, len);
+			nm_prdis("nm %d len %d", nm_i, len);
 			if (netmap_debug & NM_DEBUG_HOST)
 				nm_prinf("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
 
@@ -1603,7 +1603,7 @@ netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp)
 
 #define NM_FAIL_ON(t) do {						\
 	if (unlikely(t)) {						\
-		RD(5, "%s: fail '" #t "' "				\
+		nm_prlim(5, "%s: fail '" #t "' "				\
 			"h %d c %d t %d "				\
 			"rh %d rc %d rt %d "				\
 			"hc %d ht %d",					\
@@ -1635,7 +1635,7 @@ nm_txsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 	u_int cur = ring->cur; /* read only once */
 	u_int n = kring->nkr_num_slots;
 
-	ND(5, "%s kcur %d ktail %d head %d cur %d tail %d",
+	nm_prdis(5, "%s kcur %d ktail %d head %d cur %d tail %d",
 		kring->name,
 		kring->nr_hwcur, kring->nr_hwtail,
 		ring->head, ring->cur, ring->tail);
@@ -1671,7 +1671,7 @@ nm_txsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 		}
 	}
 	if (ring->tail != kring->rtail) {
-		RD(5, "%s tail overwritten was %d need %d", kring->name,
+		nm_prlim(5, "%s tail overwritten was %d need %d", kring->name,
 			ring->tail, kring->rtail);
 		ring->tail = kring->rtail;
 	}
@@ -1698,7 +1698,7 @@ nm_rxsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 	uint32_t const n = kring->nkr_num_slots;
 	uint32_t head, cur;
 
-	ND(5,"%s kc %d kt %d h %d c %d t %d",
+	nm_prdis(5,"%s kc %d kt %d h %d c %d t %d",
 		kring->name,
 		kring->nr_hwcur, kring->nr_hwtail,
 		ring->head, ring->cur, ring->tail);
@@ -1733,7 +1733,7 @@ nm_rxsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 		}
 	}
 	if (ring->tail != kring->rtail) {
-		RD(5, "%s tail overwritten was %d need %d",
+		nm_prlim(5, "%s tail overwritten was %d need %d",
 			kring->name,
 			ring->tail, kring->rtail);
 		ring->tail = kring->rtail;
@@ -1762,7 +1762,7 @@ netmap_ring_reinit(struct netmap_kring *kring)
 	int errors = 0;
 
 	// XXX KASSERT nm_kr_tryget
-	RD(10, "called for %s", kring->name);
+	nm_prlim(10, "called for %s", kring->name);
 	// XXX probably wrong to trust userspace
 	kring->rhead = ring->head;
 	kring->rcur  = ring->cur;
@@ -1778,17 +1778,17 @@ netmap_ring_reinit(struct netmap_kring *kring)
 		u_int idx = ring->slot[i].buf_idx;
 		u_int len = ring->slot[i].len;
 		if (idx < 2 || idx >= kring->na->na_lut.objtotal) {
-			RD(5, "bad index at slot %d idx %d len %d ", i, idx, len);
+			nm_prlim(5, "bad index at slot %d idx %d len %d ", i, idx, len);
 			ring->slot[i].buf_idx = 0;
 			ring->slot[i].len = 0;
 		} else if (len > NETMAP_BUF_SIZE(kring->na)) {
 			ring->slot[i].len = 0;
-			RD(5, "bad len at slot %d idx %d len %d", i, idx, len);
+			nm_prlim(5, "bad len at slot %d idx %d len %d", i, idx, len);
 		}
 	}
 	if (errors) {
-		RD(10, "total %d errors", errors);
-		RD(10, "%s reinit, cur %d -> %d tail %d -> %d",
+		nm_prlim(10, "total %d errors", errors);
+		nm_prlim(10, "%s reinit, cur %d -> %d tail %d -> %d",
 			kring->name,
 			ring->cur, kring->nr_hwcur,
 			ring->tail, kring->nr_hwtail);
@@ -1825,7 +1825,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 		case NR_REG_NULL:
 			priv->np_qfirst[t] = 0;
 			priv->np_qlast[t] = nma_get_nrings(na, t);
-			ND("ALL/PIPE: %s %d %d", nm_txrx2str(t),
+			nm_prdis("ALL/PIPE: %s %d %d", nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		case NR_REG_SW:
@@ -1837,7 +1837,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 			priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
 				nma_get_nrings(na, t) : 0);
 			priv->np_qlast[t] = netmap_all_rings(na, t);
-			ND("%s: %s %d %d", nr_mode == NR_REG_SW ? "SW" : "NIC+SW",
+			nm_prdis("%s: %s %d %d", nr_mode == NR_REG_SW ? "SW" : "NIC+SW",
 				nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
@@ -1853,7 +1853,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 				j = 0;
 			priv->np_qfirst[t] = j;
 			priv->np_qlast[t] = j + 1;
-			ND("ONE_NIC: %s %d %d", nm_txrx2str(t),
+			nm_prdis("ONE_NIC: %s %d %d", nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
 		default:
@@ -1962,7 +1962,7 @@ netmap_krings_get(struct netmap_priv_d *priv)
 			if ((kring->nr_kflags & NKR_EXCLUSIVE) ||
 			    (kring->users && excl))
 			{
-				ND("ring %s busy", kring->name);
+				nm_prdis("ring %s busy", kring->name);
 				return EBUSY;
 			}
 		}
@@ -1997,7 +1997,7 @@ netmap_krings_put(struct netmap_priv_d *priv)
 	int excl = (priv->np_flags & NR_EXCLUSIVE);
 	enum txrx t;
 
-	ND("%s: releasing tx [%d, %d) rx [%d, %d)",
+	nm_prdis("%s: releasing tx [%d, %d) rx [%d, %d)",
 			na->name,
 			priv->np_qfirst[NR_TX],
 			priv->np_qlast[NR_TX],
@@ -2262,7 +2262,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		error = netmap_mem_get_lut(na->nm_mem, &na->na_lut);
 		if (error)
 			goto err_drop_mem;
-		ND("lut %p bufs %u size %u", na->na_lut.lut, na->na_lut.objtotal,
+		nm_prdis("lut %p bufs %u size %u", na->na_lut.lut, na->na_lut.objtotal,
 					    na->na_lut.objsize);
 
 		/* ring configuration may have changed, fetch from the card */
@@ -2284,7 +2284,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 			/* This netmap adapter is attached to an ifnet. */
 			unsigned mtu = nm_os_ifnet_mtu(na->ifp);
 
-			ND("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",
+			nm_prdis("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",
 				na->name, mtu, na->rx_buf_maxsize, NETMAP_BUF_SIZE(na));
 
 			if (na->rx_buf_maxsize == 0) {
@@ -2381,7 +2381,7 @@ nm_sync_finalize(struct netmap_kring *kring)
 	 */
 	kring->ring->tail = kring->rtail = kring->nr_hwtail;
 
-	ND(5, "%s now hwcur %d hwtail %d head %d cur %d tail %d",
+	nm_prdis(5, "%s now hwcur %d hwtail %d head %d cur %d tail %d",
 		kring->name, kring->nr_hwcur, kring->nr_hwtail,
 		kring->rhead, kring->rcur, kring->rtail);
 }
@@ -3780,7 +3780,7 @@ netmap_hw_krings_create(struct netmap_adapter *na)
 		for (i = na->num_rx_rings; i < lim; i++) {
 			mbq_safe_init(&NMR(na, NR_RX)[i]->rx_queue);
 		}
-		ND("initialized sw rx queue %d", na->num_rx_rings);
+		nm_prdis("initialized sw rx queue %d", na->num_rx_rings);
 	}
 	return ret;
 }
@@ -3881,13 +3881,13 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 
 	if (!netmap_generic_hwcsum) {
 		if (nm_os_mbuf_has_csum_offld(m)) {
-			RD(1, "%s drop mbuf that needs checksum offload", na->name);
+			nm_prlim(1, "%s drop mbuf that needs checksum offload", na->name);
 			goto done;
 		}
 	}
 
 	if (nm_os_mbuf_has_seg_offld(m)) {
-		RD(1, "%s drop mbuf that needs generic segmentation offload", na->name);
+		nm_prlim(1, "%s drop mbuf that needs generic segmentation offload", na->name);
 		goto done;
 	}
 
@@ -3907,11 +3907,11 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	if (busy < 0)
 		busy += kring->nkr_num_slots;
 	if (busy + mbq_len(q) >= kring->nkr_num_slots - 1) {
-		RD(2, "%s full hwcur %d hwtail %d qlen %d", na->name,
+		nm_prlim(2, "%s full hwcur %d hwtail %d qlen %d", na->name,
 			kring->nr_hwcur, kring->nr_hwtail, mbq_len(q));
 	} else {
 		mbq_enqueue(q, m);
-		ND(2, "%s %d bufs in queue", na->name, mbq_len(q));
+		nm_prdis(2, "%s %d bufs in queue", na->name, mbq_len(q));
 		/* notify outside the lock */
 		m = NULL;
 		error = 0;
@@ -3947,7 +3947,7 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 	int new_hwofs, lim;
 
 	if (!nm_native_on(na)) {
-		ND("interface not in native netmap mode");
+		nm_prdis("interface not in native netmap mode");
 		return NULL;	/* nothing to reinitialize */
 	}
 
@@ -4089,7 +4089,7 @@ netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done)
 		return NM_IRQ_PASS;
 
 	if (na->na_flags & NAF_SKIP_INTR) {
-		ND("use regular interrupt");
+		nm_prdis("use regular interrupt");
 		return NM_IRQ_PASS;
 	}
 
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index adee7bad6..ad8d98afe 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -203,14 +203,14 @@ nm_find_bridge(const char *name, int create, struct netmap_bdg_ops *ops)
 		} else if (x->bdg_namelen != namelen) {
 			continue;
 		} else if (strncmp(name, x->bdg_basename, namelen) == 0) {
-			ND("found '%.*s' at %d", namelen, name, i);
+			nm_prdis("found '%.*s' at %d", namelen, name, i);
 			b = x;
 			break;
 		}
 	}
 	if (i == num_bridges && b) { /* name not found, can create entry */
 		/* initialize the bridge */
-		ND("create new bridge %s with ports %d", b->bdg_basename,
+		nm_prdis("create new bridge %s with ports %d", b->bdg_basename,
 			b->bdg_active_ports);
 		b->ht = nm_os_malloc(sizeof(struct nm_hash_ent) * NM_BDG_HASH);
 		if (b->ht == NULL) {
@@ -239,7 +239,7 @@ netmap_bdg_free(struct nm_bridge *b)
 		return EBUSY;
 	}
 
-	ND("marking bridge %s as free", b->bdg_basename);
+	nm_prdis("marking bridge %s as free", b->bdg_basename);
 	nm_os_free(b->ht);
 	memset(&b->bdg_ops, 0, sizeof(b->bdg_ops));
 	memset(&b->bdg_saved_ops, 0, sizeof(b->bdg_saved_ops));
@@ -312,13 +312,13 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	memcpy(b->tmp_bdg_port_index, b->bdg_port_index, sizeof(b->tmp_bdg_port_index));
 	for (i = 0; (hw >= 0 || sw >= 0) && i < lim; ) {
 		if (hw >= 0 && tmp[i] == hw) {
-			ND("detach hw %d at %d", hw, i);
+			nm_prdis("detach hw %d at %d", hw, i);
 			lim--; /* point to last active port */
 			tmp[i] = tmp[lim]; /* swap with i */
 			tmp[lim] = hw;	/* now this is inactive */
 			hw = -1;
 		} else if (sw >= 0 && tmp[i] == sw) {
-			ND("detach sw %d at %d", sw, i);
+			nm_prdis("detach sw %d at %d", sw, i);
 			lim--;
 			tmp[i] = tmp[lim];
 			tmp[lim] = sw;
@@ -342,7 +342,7 @@ netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw)
 	b->bdg_active_ports = lim;
 	BDG_WUNLOCK(b);
 
-	ND("now %d active ports", lim);
+	nm_prdis("now %d active ports", lim);
 	netmap_bdg_free(b);
 }
 
@@ -408,7 +408,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	b = nm_find_bridge(nr_name, create, ops);
 	if (b == NULL) {
-		ND("no bridges available for '%s'", nr_name);
+		nm_prdis("no bridges available for '%s'", nr_name);
 		return (create ? ENOMEM : ENXIO);
 	}
 	if (strlen(nr_name) < b->bdg_namelen) /* impossible */
@@ -425,10 +425,10 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	for (j = 0; j < b->bdg_active_ports; j++) {
 		i = b->bdg_port_index[j];
 		vpna = b->bdg_ports[i];
-		ND("checking %s", vpna->up.name);
+		nm_prdis("checking %s", vpna->up.name);
 		if (!strcmp(vpna->up.name, nr_name)) {
 			netmap_adapter_get(&vpna->up);
-			ND("found existing if %s refs %d", nr_name)
+			nm_prdis("found existing if %s refs %d", nr_name)
 			*na = &vpna->up;
 			return 0;
 		}
@@ -445,7 +445,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	/* record the next two ports available, but do not allocate yet */
 	cand = b->bdg_port_index[b->bdg_active_ports];
 	cand2 = b->bdg_port_index[b->bdg_active_ports + 1];
-	ND("+++ bridge %s port %s used %d avail %d %d",
+	nm_prdis("+++ bridge %s port %s used %d avail %d %d",
 		b->bdg_basename, ifname, b->bdg_active_ports, cand, cand2);
 
 	/*
@@ -515,7 +515,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	BDG_WLOCK(b);
 	vpna->bdg_port = cand;
-	ND("NIC  %p to bridge port %d", vpna, cand);
+	nm_prdis("NIC  %p to bridge port %d", vpna, cand);
 	/* bind the port to the bridge (virtual ports are not active) */
 	b->bdg_ports[cand] = vpna;
 	vpna->na_bdg = b;
@@ -526,9 +526,9 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		hostna->bdg_port = cand2;
 		hostna->na_bdg = b;
 		b->bdg_active_ports++;
-		ND("host %p to bridge port %d", hostna, cand2);
+		nm_prdis("host %p to bridge port %d", hostna, cand2);
 	}
-	ND("if %s refs %d", ifname, vpna->up.na_refcount);
+	nm_prdis("if %s refs %d", ifname, vpna->up.na_refcount);
 	BDG_WUNLOCK(b);
 	*na = &vpna->up;
 	netmap_adapter_get(*na);
@@ -1061,7 +1061,7 @@ netmap_bwrap_dtor(struct netmap_adapter *na)
 			    (bh ? bna->host.bdg_port : -1));
 	}
 
-	ND("na %p", na);
+	nm_prdis("na %p", na);
 	na->ifp = NULL;
 	bna->host.up.ifp = NULL;
 	hwna->na_vp = bna->saved_na_vp;
@@ -1166,7 +1166,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 	int error, i;
 	enum txrx t;
 
-	ND("%s %s", na->name, onoff ? "on" : "off");
+	nm_prdis("%s %s", na->name, onoff ? "on" : "off");
 
 	if (onoff) {
 		/* netmap_do_regif has been called on the bwrap na.
@@ -1371,7 +1371,7 @@ netmap_bwrap_krings_delete_common(struct netmap_adapter *na)
 	enum txrx t;
 	int i;
 
-	ND("%s", na->name);
+	nm_prdis("%s", na->name);
 
 	/* decrement the usage counter for all the hwna krings */
 	for_rx_tx(t) {
@@ -1398,7 +1398,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 	struct netmap_kring *hw_kring;
 	int error;
 
-	ND("%s: na %s hwna %s",
+	nm_prdis("%s: na %s hwna %s",
 			(kring ? kring->name : "NULL!"),
 			(na ? na->name : "NULL!"),
 			(hwna ? hwna->name : "NULL!"));
@@ -1410,7 +1410,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 
 	/* first step: simulate a user wakeup on the rx ring */
 	netmap_vp_rxsync(kring, flags);
-	ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
+	nm_prdis("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
 		na->name, ring_n,
 		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
 		kring->rhead, kring->rcur, kring->rtail,
@@ -1429,7 +1429,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
 
 	/* fourth step: the user goes to sleep again, causing another rxsync */
 	netmap_vp_rxsync(kring, flags);
-	ND("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
+	nm_prdis("%s[%d] PST rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)",
 		na->name, ring_n,
 		kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease,
 		kring->rhead, kring->rcur, kring->rtail,
@@ -1579,7 +1579,7 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 	if (hwna->na_flags & NAF_MOREFRAG)
 		na->na_flags |= NAF_MOREFRAG;
 
-	ND("%s<->%s txr %d txd %d rxr %d rxd %d",
+	nm_prdis("%s<->%s txr %d txd %d rxr %d rxd %d",
 		na->name, ifp->if_xname,
 		na->num_tx_rings, na->num_tx_desc,
 		na->num_rx_rings, na->num_rx_desc);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c85db6fb3..bc267cec4 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -271,7 +271,7 @@ typedef struct hrtimer{
 		__LINE__, __FUNCTION__, ##__VA_ARGS__);		\
 	} while (0)
 
-/* Disabled printf (used to be ND). */
+/* Disabled printf (used to be nm_prdis). */
 #define nm_prdis(format, ...)
 
 /* Rate limited, lps indicates how many per second. */
@@ -286,11 +286,6 @@ typedef struct hrtimer{
 			nm_prinf(format, ##__VA_ARGS__);	\
 	} while (0)
 
-/* Old macros. */
-#define ND	nm_prdis
-#define D	nm_prerr
-#define RD	nm_prlim
-
 struct netmap_adapter;
 struct nm_bdg_fwd;
 struct nm_bridge;
@@ -1149,7 +1144,7 @@ nm_kr_rxspace(struct netmap_kring *k)
 	int space = k->nr_hwtail - k->nr_hwcur;
 	if (space < 0)
 		space += k->nkr_num_slots;
-	ND("preserving %d rx slots %d -> %d", space, k->nr_hwcur, k->nr_hwtail);
+	nm_prdis("preserving %d rx slots %d -> %d", space, k->nr_hwcur, k->nr_hwtail);
 
 	return space;
 }
@@ -1404,7 +1399,7 @@ uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *);
 #if 1 /* debug version */
 #define	NM_CHECK_ADDR_LEN(_na, _a, _l)	do {				\
 	if (_a == NETMAP_BUF_BASE(_na) || _l > NETMAP_BUF_SIZE(_na)) {	\
-		RD(5, "bad addr/len ring %d slot %d idx %d len %d",	\
+		nm_prlim(5, "bad addr/len ring %d slot %d idx %d len %d",	\
 			kring->ring_id, nm_i, slot->buf_idx, len);	\
 		if (_l > NETMAP_BUF_SIZE(_na))				\
 			_l = NETMAP_BUF_SIZE(_na);			\
@@ -1566,7 +1561,7 @@ void __netmap_adapter_get(struct netmap_adapter *na);
 #define netmap_adapter_get(na) 				\
 	do {						\
 		struct netmap_adapter *__na = na;	\
-		D("getting %p:%s (%d)", __na, (__na)->name, (__na)->na_refcount);	\
+		nm_prinf("getting %p:%s (%d)", __na, (__na)->name, (__na)->na_refcount);	\
 		__netmap_adapter_get(__na);		\
 	} while (0)
 
@@ -1575,7 +1570,7 @@ int __netmap_adapter_put(struct netmap_adapter *na);
 #define netmap_adapter_put(na)				\
 	({						\
 		struct netmap_adapter *__na = na;	\
-		D("putting %p:%s (%d)", __na, (__na)->name, (__na)->na_refcount);	\
+		nm_prinf("putting %p:%s (%d)", __na, (__na)->name, (__na)->na_refcount);	\
 		__netmap_adapter_put(__na);		\
 	})
 
@@ -1737,7 +1732,7 @@ int nm_iommu_group_id(bus_dma_tag_t dev);
 			addr, NETMAP_BUF_SIZE, DMA_TO_DEVICE);
 
 	if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) {
-		D("dma mapping error");
+		nm_prerr("dma mapping error");
 		/* goto dma_error; See e1000_put_txbuf() */
 		/* XXX reset */
 	}
@@ -2336,7 +2331,7 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 		m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save
 		m->m_ext.ext_free = (void *)void_mbuf_dtor;
 		m->m_ext.ext_type = EXT_EXTREF;
-		ND(5, "create m %p refcnt %d", m, MBUF_REFCNT(m));
+		nm_prdis(5, "create m %p refcnt %d", m, MBUF_REFCNT(m));
 	}
 	return m;
 }
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 9774e03cb..afbd5ced8 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -397,14 +397,14 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 #ifdef __FreeBSD__
 	case FIONBIO:
 	case FIOASYNC:
-		ND("FIONBIO/FIOASYNC are no-ops");
+		/* FIONBIO/FIOASYNC are no-ops. */
 		break;
 
 	case BIOCIMMEDIATE:
 	case BIOCGHDRCMPLT:
 	case BIOCSHDRCMPLT:
 	case BIOCSSEESENT:
-		D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
+		/* Ignore these commands. */
 		break;
 
 	default:	/* allow device-specific ioctls */
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index dafdbc487..e8c5e6bf8 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -979,7 +979,7 @@ netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr)
 			continue;
 
 		ofs = ofs + relofs;
-		ND("%s: return offset %d (cluster %d) for pointer %p",
+		nm_prdis("%s: return offset %d (cluster %d) for pointer %p",
 		    p->name, ofs, i, vaddr);
 		return ofs;
 	}
@@ -1043,7 +1043,7 @@ netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_
 		if (index)
 			*index = i * 32 + j;
 	}
-	ND("%s allocator: allocated object @ [%d][%d]: vaddr %p",p->name, i, j, vaddr);
+	nm_prdis("%s allocator: allocated object @ [%d][%d]: vaddr %p",p->name, i, j, vaddr);
 
 	if (start)
 		*start = i;
@@ -1143,7 +1143,7 @@ netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n)
 			*head = cur; /* restore */
 			break;
 		}
-		ND(5, "allocate buffer %d -> %d", *head, cur);
+		nm_prdis(5, "allocate buffer %d -> %d", *head, cur);
 		*p = cur; /* link to previous head */
 	}
 
@@ -1160,7 +1160,7 @@ netmap_extra_free(struct netmap_adapter *na, uint32_t head)
 	struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL];
 	uint32_t i, cur, *buf;
 
-	ND("freeing the extra list");
+	nm_prdis("freeing the extra list");
 	for (i = 0; head >=2 && head < p->objtotal; i++) {
 		cur = head;
 		buf = lut[head].vaddr;
@@ -1197,7 +1197,7 @@ netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n)
 		slot[i].ptr = 0;
 	}
 
-	ND("%s: allocated %d buffers, %d available, first at %d", p->name, n, p->objfree, pos);
+	nm_prdis("%s: allocated %d buffers, %d available, first at %d", p->name, n, p->objfree, pos);
 	return (0);
 
 cleanup:
@@ -1245,7 +1245,7 @@ netmap_free_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n)
 		if (slot[i].buf_idx > 1)
 			netmap_free_buf(nmd, slot[i].buf_idx);
 	}
-	ND("%s: released some buffers, available: %u",
+	nm_prdis("%s: released some buffers, available: %u",
 			p->name, p->objfree);
 }
 
@@ -1539,7 +1539,7 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	(void)lut;
 	nm_prerr("unsupported on Windows");
 #else /* linux */
-	ND("unmapping and freeing plut for %s", na->name);
+	nm_prdis("unmapping and freeing plut for %s", na->name);
 	if (lut->plut == NULL)
 		return 0;
 	for (i = 0; i < lim; i += p->_clustentries) {
@@ -1577,11 +1577,11 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na)
 #else /* linux */
 
 	if (lut->plut != NULL) {
-		ND("plut already allocated for %s", na->name);
+		nm_prdis("plut already allocated for %s", na->name);
 		return 0;
 	}
 
-	ND("allocating physical lut for %s", na->name);
+	nm_prdis("allocating physical lut for %s", na->name);
 	lut->plut = nm_alloc_plut(lim);
 	if (lut->plut == NULL) {
 		nm_prerr("Failed to allocate physical lut for %s", na->name);
@@ -1775,7 +1775,7 @@ netmap_mem2_config(struct netmap_mem_d *nmd)
 	if (!netmap_mem_params_changed(nmd->params))
 		goto out;
 
-	ND("reconfiguring");
+	nm_prdis("reconfiguring");
 
 	if (nmd->flags & NETMAP_MEM_FINALIZED) {
 		/* reset previous allocation */
@@ -1870,10 +1870,10 @@ netmap_free_rings(struct netmap_adapter *na)
 			if (netmap_debug & NM_DEBUG_MEM)
 				nm_prinf("deleting ring %s", kring->name);
 			if (!(kring->nr_kflags & NKR_FAKERING)) {
-				ND("freeing bufs for %s", kring->name);
+				nm_prdis("freeing bufs for %s", kring->name);
 				netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots);
 			} else {
-				ND("NOT freeing bufs for %s", kring->name);
+				nm_prdis("NOT freeing bufs for %s", kring->name);
 			}
 			netmap_ring_free(na->nm_mem, ring);
 			kring->ring = NULL;
@@ -1918,7 +1918,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 				nm_prerr("Cannot allocate %s_ring", nm_txrx2str(t));
 				goto cleanup;
 			}
-			ND("txring at %p", ring);
+			nm_prdis("txring at %p", ring);
 			kring->ring = ring;
 			*(uint32_t *)(uintptr_t)&ring->num_slots = ndesc;
 			*(int64_t *)(uintptr_t)&ring->buf_ofs =
@@ -1932,9 +1932,9 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 			ring->tail = kring->rtail;
 			*(uint32_t *)(uintptr_t)&ring->nr_buf_size =
 				netmap_mem_bufsize(na->nm_mem);
-			ND("%s h %d c %d t %d", kring->name,
+			nm_prdis("%s h %d c %d t %d", kring->name,
 				ring->head, ring->cur, ring->tail);
-			ND("initializing slots for %s_ring", nm_txrx2str(t));
+			nm_prdis("initializing slots for %s_ring", nm_txrx2str(t));
 			if (!(kring->nr_kflags & NKR_FAKERING)) {
 				/* this is a real ring */
 				if (netmap_debug & NM_DEBUG_MEM)
@@ -2306,19 +2306,19 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 #if !defined(linux) && !defined(_WIN32)
 			p->lut[j].paddr = vtophys(p->lut[j].vaddr);
 #endif
-			ND("%s %d at %p", p->name, j, p->lut[j].vaddr);
+			nm_prdis("%s %d at %p", p->name, j, p->lut[j].vaddr);
 			noff = off + p->_objsize;
 			if (noff < PAGE_SIZE) {
 				off = noff;
 				continue;
 			}
-			ND("too big, recomputing offset...");
+			nm_prdis("too big, recomputing offset...");
 			while (noff >= PAGE_SIZE) {
 				char *old_clust = clust;
 				noff -= PAGE_SIZE;
 				clust = nm_os_extmem_nextpage(nme->os);
 				nr_pages--;
-				ND("noff %zu page %p nr_pages %d", noff,
+				nm_prdis("noff %zu page %p nr_pages %d", noff,
 						page_to_virt(*pages), nr_pages);
 				if (noff > 0 && !nm_isset(p->invalid_bitmap, j) &&
 					(nr_pages == 0 ||
@@ -2328,7 +2328,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 					 * drop this object
 					 * */
 					p->invalid_bitmap[ (j>>5) ] |= 1U << (j & 31U);
-					ND("non contiguous at off %zu, drop", noff);
+					nm_prdis("non contiguous at off %zu, drop", noff);
 				}
 				if (nr_pages == 0)
 					break;
@@ -2338,7 +2338,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		p->objtotal = j;
 		p->numclusters = p->objtotal;
 		p->memtotal = j * p->_objsize;
-		ND("%d memtotal %u", j, p->memtotal);
+		nm_prdis("%d memtotal %u", j, p->memtotal);
 	}
 
 	netmap_mem_ext_register(nme);
@@ -2442,7 +2442,7 @@ netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, struct ifnet *ifp)
 			} else {
 				ptnmd->pt_ifs = curr->next;
 			}
-			D("removed (ifp=%p,nifp_offset=%u)",
+			nm_prinf("removed (ifp=%p,nifp_offset=%u)",
 			  curr->ifp, curr->nifp_offset);
 			nm_os_free(curr);
 			ret = 0;
@@ -2498,7 +2498,7 @@ netmap_mem_pt_guest_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off)
 	vm_paddr_t paddr;
 	/* if the offset is valid, just return csb->base_addr + off */
 	paddr = (vm_paddr_t)(ptnmd->nm_paddr + off);
-	ND("off %lx padr %lx", off, (unsigned long)paddr);
+	nm_prdis("off %lx padr %lx", off, (unsigned long)paddr);
 	return paddr;
 }
 
@@ -2528,7 +2528,7 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 		goto out;
 
 	if (ptnmd->ptn_dev == NULL) {
-		D("ptnetmap memdev not attached");
+		nm_prerr("ptnetmap memdev not attached");
 		error = ENOMEM;
 		goto out;
 	}
@@ -2547,10 +2547,10 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 
 	/* allocate the lut */
 	if (ptnmd->buf_lut.lut == NULL) {
-		D("allocating lut");
+		nm_prinf("allocating lut");
 		ptnmd->buf_lut.lut = nm_alloc_lut(nbuffers);
 		if (ptnmd->buf_lut.lut == NULL) {
-			D("lut allocation failed");
+			nm_prerr("lut allocation failed");
 			return ENOMEM;
 		}
 	}
@@ -2615,11 +2615,11 @@ netmap_mem_pt_guest_delete(struct netmap_mem_d *nmd)
 	if (nmd == NULL)
 		return;
 	if (netmap_verbose)
-		D("deleting %p", nmd);
+		nm_prinf("deleting %p", nmd);
 	if (nmd->active > 0)
-		D("bug: deleting mem allocator with active=%d!", nmd->active);
+		nm_prerr("bug: deleting mem allocator with active=%d!", nmd->active);
 	if (netmap_verbose)
-		D("done deleting %p", nmd);
+		nm_prinf("done deleting %p", nmd);
 	NMA_LOCK_DESTROY(nmd);
 	nm_os_free(nmd);
 }
@@ -2633,7 +2633,7 @@ netmap_mem_pt_guest_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv
 
 	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
 	if (ptif == NULL) {
-		D("Error: interface %p is not in passthrough", na->ifp);
+		nm_prerr("interface %s is not in passthrough", na->name);
 		goto out;
 	}
 
@@ -2650,7 +2650,7 @@ netmap_mem_pt_guest_if_delete(struct netmap_adapter *na, struct netmap_if *nifp)
 
 	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
 	if (ptif == NULL) {
-		D("Error: interface %p is not in passthrough", na->ifp);
+		nm_prerr("interface %s is not in passthrough", na->name);
 	}
 }
 
@@ -2664,7 +2664,7 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 
 	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
 	if (ptif == NULL) {
-		D("Error: interface %p is not in passthrough", na->ifp);
+		nm_prerr("interface %s is not in passthrough", na->name);
 		goto out;
 	}
 
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index d7112a0d5..f0c1505d7 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -139,7 +139,7 @@ nm_is_zmon(struct netmap_adapter *na)
 static int
 netmap_monitor_txsync(struct netmap_kring *kring, int flags)
 {
-	RD(1, "%s %x", kring->name, flags);
+	nm_prlim(1, "%s %x", kring->name, flags);
 	return EIO;
 }
 
@@ -158,7 +158,7 @@ netmap_monitor_rxsync(struct netmap_kring *kring, int flags)
 		/* parent left netmap mode */
 		return EIO;
 	}
-	ND("%s %x", kring->name, flags);
+	nm_prdis("%s %x", kring->name, flags);
 	kring->nr_hwcur = kring->rhead;
 	mb();
 	return 0;
@@ -230,8 +230,8 @@ nm_monitor_dealloc(struct netmap_kring *kring)
 {
 	if (kring->monitors) {
 		if (kring->n_monitors > 0) {
-			D("freeing not empty monitor array for %s (%d dangling monitors)!", kring->name,
-					kring->n_monitors);
+			nm_prerr("freeing not empty monitor array for %s (%d dangling monitors)!",
+			    kring->name, kring->n_monitors);
 		}
 		nm_os_free(kring->monitors);
 		kring->monitors = NULL;
@@ -270,7 +270,7 @@ nm_monitor_dummycb(struct netmap_kring *kring, int flags)
 static void
 nm_monitor_intercept_callbacks(struct netmap_kring *kring)
 {
-	ND("intercept callbacks on %s", kring->name);
+	nm_prdis("intercept callbacks on %s", kring->name);
 	kring->mon_sync = kring->nm_sync != NULL ?
 		kring->nm_sync : nm_monitor_dummycb;
 	kring->mon_notify = kring->nm_notify;
@@ -286,7 +286,7 @@ nm_monitor_intercept_callbacks(struct netmap_kring *kring)
 static void
 nm_monitor_restore_callbacks(struct netmap_kring *kring)
 {
-	ND("restoring callbacks on %s", kring->name);
+	nm_prdis("restoring callbacks on %s", kring->name);
 	kring->nm_sync = kring->mon_sync;
 	kring->mon_sync = NULL;
 	if (kring->tx == NR_RX) {
@@ -333,7 +333,7 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int
 
 	if (nm_monitor_none(ikring)) {
 		/* this is the first monitor, intercept the callbacks */
-		ND("%s: intercept callbacks on %s", mkring->name, ikring->name);
+		nm_prdis("%s: intercept callbacks on %s", mkring->name, ikring->name);
 		nm_monitor_intercept_callbacks(ikring);
 	}
 
@@ -513,11 +513,11 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
 	int i;
 	enum txrx t, s;
 
-	ND("%p: onoff %d", na, onoff);
+	nm_prdis("%p: onoff %d", na, onoff);
 	if (onoff) {
 		if (pna == NULL) {
 			/* parent left netmap mode, fatal */
-			D("%s: internal error", na->name);
+			nm_prerr("%s: parent left netmap mode", na->name);
 			return ENXIO;
 		}
 		for_rx_tx(t) {
@@ -592,7 +592,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 	      mlim; // = mkring->nkr_num_slots - 1;
 
 	if (mkring == NULL) {
-		RD(5, "NULL monitor on %s", kring->name);
+		nm_prlim(5, "NULL monitor on %s", kring->name);
 		return 0;
 	}
 	mring = mkring->ring;
@@ -653,7 +653,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 		tmp = ms->buf_idx;
 		ms->buf_idx = s->buf_idx;
 		s->buf_idx = tmp;
-		ND(5, "beg %d buf_idx %d", beg, tmp);
+		nm_prdis(5, "beg %d buf_idx %d", beg, tmp);
 
 		tmp = ms->len;
 		ms->len = s->len;
@@ -770,7 +770,7 @@ netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_
 			     *dst = NMB(mkring->na, ms);
 
 			if (unlikely(copy_len > max_len)) {
-				RD(5, "%s->%s: truncating %d to %d", kring->name,
+				nm_prlim(5, "%s->%s: truncating %d to %d", kring->name,
 						mkring->name, copy_len, max_len);
 				copy_len = max_len;
 			}
@@ -849,7 +849,7 @@ static int
 netmap_monitor_parent_notify(struct netmap_kring *kring, int flags)
 {
 	int (*notify)(struct netmap_kring*, int);
-	ND(5, "%s %x", kring->name, flags);
+	nm_prdis(5, "%s %x", kring->name, flags);
 	/* ?xsync callbacks have tryget called by their callers
 	 * (NIOCREGIF and poll()), but here we have to call it
 	 * by ourself
@@ -909,12 +909,12 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
 	}
 	if ((req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
-		ND("not a monitor");
+		nm_prdis("not a monitor");
 		return 0;
 	}
 	/* this is a request for a monitor adapter */
 
-	ND("flags %lx", req->nr_flags);
+	nm_prdis("flags %lx", req->nr_flags);
 
 	/* First, try to find the adapter that we want to monitor.
 	 * We use the same req, after we have turned off the monitor flags.
@@ -927,24 +927,23 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
 	hdr->nr_body = (uintptr_t)req;
 	if (error) {
-		D("parent lookup failed: %d", error);
+		nm_prerr("parent lookup failed: %d", error);
 		return error;
 	}
-	ND("found parent: %s", pna->name);
+	nm_prdis("found parent: %s", pna->name);
 
 	if (!nm_netmap_on(pna)) {
 		/* parent not in netmap mode */
 		/* XXX we can wait for the parent to enter netmap mode,
 		 * by intercepting its nm_register callback (2014-03-16)
 		 */
-		D("%s not in netmap mode", pna->name);
+		nm_prerr("%s not in netmap mode", pna->name);
 		error = EINVAL;
 		goto put_out;
 	}
 
 	mna = nm_os_malloc(sizeof(*mna));
 	if (mna == NULL) {
-		D("memory error");
 		error = ENOMEM;
 		goto put_out;
 	}
@@ -954,7 +953,7 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	error = netmap_interp_ringid(&mna->priv, req->nr_mode, req->nr_ringid,
 					req->nr_flags);
 	if (error) {
-		D("ringid error");
+		nm_prerr("ringid error");
 		goto free_out;
 	}
 	snprintf(mna->up.name, sizeof(mna->up.name), "%s/%s%s%s#%lu", pna->name,
@@ -1013,7 +1012,7 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	error = netmap_attach_common(&mna->up);
 	if (error) {
-		D("attach_common error");
+		nm_prerr("netmap_attach_common failed");
 		goto mem_put_out;
 	}
 
@@ -1024,7 +1023,7 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	netmap_adapter_get(*na);
 
 	/* keep the reference to the parent */
-	ND("monitor ok");
+	nm_prdis("monitor ok");
 
 	/* drop the reference to the ifp, if any */
 	if (ifp)
diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index 688e0d674..b08a6f8f2 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -82,16 +82,16 @@ gso_fix_segment(uint8_t *pkt, size_t len, u_int ipv4, u_int iphlen, u_int tcp,
 	if (ipv4) {
 		/* Set the IPv4 "Total Length" field. */
 		iph->tot_len = htobe16(len);
-		ND("ip total length %u", be16toh(ip->tot_len));
+		nm_prdis("ip total length %u", be16toh(ip->tot_len));
 
 		/* Set the IPv4 "Identification" field. */
 		iph->id = htobe16(be16toh(iph->id) + idx);
-		ND("ip identification %u", be16toh(iph->id));
+		nm_prdis("ip identification %u", be16toh(iph->id));
 
 		/* Compute and insert the IPv4 header checksum. */
 		iph->check = 0;
 		iph->check = nm_os_csum_ipv4(iph);
-		ND("IP csum %x", be16toh(iph->check));
+		nm_prdis("IP csum %x", be16toh(iph->check));
 	} else {
 		/* Set the IPv6 "Payload Len" field. */
 		ip6h->payload_len = htobe16(len-iphlen);
@@ -102,13 +102,13 @@ gso_fix_segment(uint8_t *pkt, size_t len, u_int ipv4, u_int iphlen, u_int tcp,
 
 		/* Set the TCP sequence number. */
 		tcph->seq = htobe32(be32toh(tcph->seq) + segmented_bytes);
-		ND("tcp seq %u", be32toh(tcph->seq));
+		nm_prdis("tcp seq %u", be32toh(tcph->seq));
 
 		/* Zero the PSH and FIN TCP flags if this is not the last
 		   segment. */
 		if (!last_segment)
 			tcph->flags &= ~(0x8 | 0x1);
-		ND("last_segment %u", last_segment);
+		nm_prdis("last_segment %u", last_segment);
 
 		check = &tcph->check;
 		check_data = (uint8_t *)tcph;
@@ -129,7 +129,7 @@ gso_fix_segment(uint8_t *pkt, size_t len, u_int ipv4, u_int iphlen, u_int tcp,
 	else
 		nm_os_csum_tcpudp_ipv6(ip6h, check_data, len-iphlen, check);
 
-	ND("TCP/UDP csum %x", be16toh(*check));
+	nm_prdis("TCP/UDP csum %x", be16toh(*check));
 }
 
 static inline int
@@ -170,7 +170,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 	u_int dst_slots = 0;
 
 	if (unlikely(ft_p == ft_end)) {
-		RD(1, "No source slots to process");
+		nm_prlim(1, "No source slots to process");
 		return;
 	}
 
@@ -189,11 +189,11 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 		/* Initial sanity check on the source virtio-net header. If
 		 * something seems wrong, just drop the packet. */
 		if (src_len < na->up.virt_hdr_len) {
-			RD(1, "Short src vnet header, dropping");
+			nm_prlim(1, "Short src vnet header, dropping");
 			return;
 		}
 		if (unlikely(vnet_hdr_is_bad(vh))) {
-			RD(1, "Bad src vnet header, dropping");
+			nm_prlim(1, "Bad src vnet header, dropping");
 			return;
 		}
 	}
@@ -266,7 +266,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 			if (dst_slots >= *howmany) {
 				/* We still have work to do, but we've run out of
 				 * dst slots, so we have to drop the packet. */
-				ND(1, "Not enough slots, dropping GSO packet");
+				nm_prdis(1, "Not enough slots, dropping GSO packet");
 				return;
 			}
 
@@ -281,7 +281,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 				 * encapsulation. */
 				for (;;) {
 					if (src_len < ethhlen) {
-						RD(1, "Short GSO fragment [eth], dropping");
+						nm_prlim(1, "Short GSO fragment [eth], dropping");
 						return;
 					}
 					ethertype = be16toh(*((uint16_t *)
@@ -297,7 +297,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 									(gso_hdr + ethhlen);
 
 						if (src_len < ethhlen + 20) {
-							RD(1, "Short GSO fragment "
+							nm_prlim(1, "Short GSO fragment "
 							      "[IPv4], dropping");
 							return;
 						}
@@ -310,14 +310,14 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 						iphlen = 40;
 						break;
 					default:
-						RD(1, "Unsupported ethertype, "
+						nm_prlim(1, "Unsupported ethertype, "
 						      "dropping GSO packet");
 						return;
 				}
-				ND(3, "type=%04x", ethertype);
+				nm_prdis(3, "type=%04x", ethertype);
 
 				if (src_len < ethhlen + iphlen) {
-					RD(1, "Short GSO fragment [IP], dropping");
+					nm_prlim(1, "Short GSO fragment [IP], dropping");
 					return;
 				}
 
@@ -329,7 +329,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 								(gso_hdr + ethhlen + iphlen);
 
 					if (src_len < ethhlen + iphlen + 20) {
-						RD(1, "Short GSO fragment "
+						nm_prlim(1, "Short GSO fragment "
 								"[TCP], dropping");
 						return;
 					}
@@ -340,11 +340,11 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 				}
 
 				if (src_len < gso_hdr_len) {
-					RD(1, "Short GSO fragment [TCP/UDP], dropping");
+					nm_prlim(1, "Short GSO fragment [TCP/UDP], dropping");
 					return;
 				}
 
-				ND(3, "gso_hdr_len %u gso_mtu %d", gso_hdr_len,
+				nm_prdis(3, "gso_hdr_len %u gso_mtu %d", gso_hdr_len,
 								   dst_na->mfs);
 
 				/* Advance source pointers. */
@@ -386,7 +386,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 						gso_idx, segmented_bytes,
 						src_len == 0 && ft_p + 1 == ft_end);
 
-				ND("frame %u completed with %d bytes", gso_idx, (int)gso_bytes);
+				nm_prdis("frame %u completed with %d bytes", gso_idx, (int)gso_bytes);
 				dst_slot->len = gso_bytes;
 				dst_slot->flags = 0;
 				dst_slots++;
@@ -410,7 +410,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 				src_len = ft_p->ft_len;
 			}
 		}
-		ND(3, "%d bytes segmented", segmented_bytes);
+		nm_prdis(3, "%d bytes segmented", segmented_bytes);
 
 	} else {
 		/* Address of a checksum field into a destination slot. */
@@ -423,7 +423,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 		/* Init 'check' if necessary. */
 		if (vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
 			if (unlikely(vh->csum_offset + vh->csum_start > src_len))
-				D("invalid checksum request");
+				nm_prerr("invalid checksum request");
 			else
 				check = (uint16_t *)(dst + vh->csum_start +
 						vh->csum_offset);
@@ -468,7 +468,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 		if (check && vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
 			*check = nm_os_csum_fold(csum);
 		}
-		ND(3, "using %u dst_slots", dst_slots);
+		nm_prdis(3, "using %u dst_slots", dst_slots);
 
 		/* A second pass on the destination slots to set the slot flags,
 		 * using the right number of destination slots.
@@ -485,7 +485,7 @@ bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 	/* Update howmany and j. This is to commit the use of
 	 * those slots in the destination ring. */
 	if (unlikely(dst_slots > *howmany)) {
-		D("Slot allocation error: This is a bug");
+		nm_prerr("bug: slot allocation error");
 	}
 	*j = j_cur;
 	*howmany -= dst_slots;
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index b9665d816..c15a08319 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -118,8 +118,8 @@ netmap_pipe_dealloc(struct netmap_adapter *na)
 {
 	if (na->na_pipes) {
 		if (na->na_next_pipe > 0) {
-			D("freeing not empty pipe array for %s (%d dangling pipes)!", na->name,
-					na->na_next_pipe);
+			nm_prerr("freeing not empty pipe array for %s (%d dangling pipes)!",
+			    na->name, na->na_next_pipe);
 		}
 		nm_os_free(na->na_pipes);
 		na->na_pipes = NULL;
@@ -190,8 +190,8 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 	int complete; /* did we see a complete packet ? */
 	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
-	ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
-	ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
+	nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
+	nm_prdis(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
 		txkring->nr_hwcur, txkring->nr_hwtail,
 		txkring->rcur, txkring->rhead, txkring->rtail);
 
@@ -221,7 +221,7 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 
 	txkring->nr_hwcur = k;
 
-	ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
+	nm_prdis(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
 		txkring->nr_hwcur, txkring->nr_hwtail,
 		txkring->rcur, txkring->rhead, txkring->rtail, k);
 
@@ -242,8 +242,8 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 	int m; /* slots to release */
 	struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
 
-	ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
-	ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
+	nm_prdis("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
+	nm_prdis(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
 		rxkring->nr_hwcur, rxkring->nr_hwtail,
 		rxkring->rcur, rxkring->rhead, rxkring->rtail);
 
@@ -274,7 +274,7 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 	txkring->pipe_tail = nm_prev(k, lim);
 	rxkring->nr_hwcur = k;
 
-	ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
+	nm_prdis(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
 		rxkring->nr_hwcur, rxkring->nr_hwtail,
 		rxkring->rcur, rxkring->rhead, rxkring->rtail, k);
 
@@ -320,7 +320,7 @@ int netmap_pipe_krings_create_both(struct netmap_adapter *na,
 	int i;
 
 	/* case 1) below */
-	ND("%p: case 1, create both ends", na);
+	nm_prdis("%p: case 1, create both ends", na);
 	error = netmap_krings_create(na, 0);
 	if (error)
 		return error;
@@ -497,7 +497,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 	struct netmap_adapter *ona = &pna->peer->up;
 	int error = 0;
 
-	ND("%p: onoff %d", na, onoff);
+	nm_prdis("%p: onoff %d", na, onoff);
 	if (onoff) {
 		error = netmap_pipe_reg_both(na, ona);
 		if (error) {
@@ -512,20 +512,20 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
 	}
 
 	if (na->active_fds) {
-		ND("active_fds %d", na->active_fds);
+		nm_prdis("active_fds %d", na->active_fds);
 		return 0;
 	}
 
 	if (pna->peer_ref) {
-		ND("%p: case 1.a or 2.a, nothing to do", na);
+		nm_prdis("%p: case 1.a or 2.a, nothing to do", na);
 		return 0;
 	}
 	if (onoff) {
-		ND("%p: case 1.b, drop peer", na);
+		nm_prdis("%p: case 1.b, drop peer", na);
 		pna->peer->peer_ref = 0;
 		netmap_adapter_put(na);
 	} else {
-		ND("%p: case 2.b, grab peer", na);
+		nm_prdis("%p: case 2.b, grab peer", na);
 		netmap_adapter_get(na);
 		pna->peer->peer_ref = 1;
 	}
@@ -541,7 +541,7 @@ netmap_pipe_krings_delete_both(struct netmap_adapter *na,
 	int i;
 
 	/* case 1) below */
-	ND("%p: case 1, deleting everything", na);
+	nm_prdis("%p: case 1, deleting everything", na);
 	/* To avoid double-frees we zero-out all the buffers in the kernel part
 	 * of each ring. The reason is this: If the user is behaving correctly,
 	 * all buffers are found in exactly one slot in the userspace part of
@@ -557,7 +557,7 @@ netmap_pipe_krings_delete_both(struct netmap_adapter *na,
 			struct netmap_ring *ring = kring->ring;
 			uint32_t j, lim = kring->nkr_num_slots - 1;
 
-			ND("%s ring %p hwtail %u hwcur %u",
+			nm_prdis("%s ring %p hwtail %u hwcur %u",
 				kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
 
 			if (ring == NULL)
@@ -570,7 +570,7 @@ netmap_pipe_krings_delete_both(struct netmap_adapter *na,
 			     j != kring->nr_hwcur;
 			     j = nm_next(j, lim))
 			{
-				ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
+				nm_prdis("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
 				ring->slot[j].buf_idx = 0;
 			}
 			kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING);
@@ -622,7 +622,7 @@ netmap_pipe_krings_delete(struct netmap_adapter *na)
 	struct netmap_adapter *ona; /* na of the other end */
 
 	if (!pna->peer_ref) {
-		ND("%p: case 2, kept alive by peer",  na);
+		nm_prdis("%p: case 2, kept alive by peer",  na);
 		return;
 	}
 	ona = &pna->peer->up;
@@ -635,9 +635,9 @@ netmap_pipe_dtor(struct netmap_adapter *na)
 {
 	struct netmap_pipe_adapter *pna =
 		(struct netmap_pipe_adapter *)na;
-	ND("%p %p", na, pna->parent_ifp);
+	nm_prdis("%p %p", na, pna->parent_ifp);
 	if (pna->peer_ref) {
-		ND("%p: clean up peer", na);
+		nm_prdis("%p: clean up peer", na);
 		pna->peer_ref = 0;
 		netmap_adapter_put(&pna->peer->up);
 	}
@@ -671,7 +671,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		if (cbra != NULL) {
 			role = NM_PIPE_ROLE_SLAVE;
 		} else {
-			ND("not a pipe");
+			nm_prdis("not a pipe");
 			return 0;
 		}
 	}
@@ -702,10 +702,10 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
-			ND("parent lookup failed: %d", error);
+			nm_prdis("parent lookup failed: %d", error);
 			return error;
 		}
-		ND("try to create a persistent vale port");
+		nm_prdis("try to create a persistent vale port");
 		/* create a persistent vale port and try again */
 		*cbra = '\0';
 		NMG_UNLOCK();
@@ -714,14 +714,15 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
-				D("failed to create a persistent vale port: %d", create_error);
+				nm_prerr("failed to create a persistent vale port: %d",
+				    create_error);
 			}
 			return error;
 		}
 	}
 
 	if (NETMAP_OWNED_BY_KERN(pna)) {
-		ND("parent busy");
+		nm_prdis("parent busy");
 		error = EBUSY;
 		goto put_out;
 	}
@@ -731,10 +732,10 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	mna = netmap_pipe_find(pna, pipe_id);
 	if (mna) {
 		if (mna->role == role) {
-			ND("found %s directly at %d", pipe_id, mna->parent_slot);
+			nm_prdis("found %s directly at %d", pipe_id, mna->parent_slot);
 			reqna = mna;
 		} else {
-			ND("found %s indirectly at %d", pipe_id, mna->parent_slot);
+			nm_prdis("found %s indirectly at %d", pipe_id, mna->parent_slot);
 			reqna = mna->peer;
 		}
 		/* the pipe we have found already holds a ref to the parent,
@@ -743,7 +744,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		netmap_unget_na(pna, ifp);
 		goto found;
 	}
-	ND("pipe %s not found, create %d", pipe_id, create);
+	nm_prdis("pipe %s not found, create %d", pipe_id, create);
 	if (!create) {
 		error = ENODEV;
 		goto put_out;
@@ -834,10 +835,10 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		sna->peer_ref = 1;
 		netmap_adapter_get(&mna->up);
 	}
-	ND("created master %p and slave %p", mna, sna);
+	nm_prdis("created master %p and slave %p", mna, sna);
 found:
 
-	ND("pipe %s %s at %p", pipe_id,
+	nm_prdis("pipe %s %s at %p", pipe_id,
 		(reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna);
 	*na = &reqna->up;
 	netmap_adapter_get(*na);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index e4cb8ea01..3f96ef832 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -445,7 +445,7 @@ netmap_vale_attach(struct nmreq_header *hdr, void *auth_token)
 		error = na->nm_bdg_ctl(hdr, na);
 		if (error)
 			goto unref_exit;
-		ND("registered %s to netmap-mode", na->name);
+		nm_prdis("registered %s to netmap-mode", na->name);
 	}
 	vpna = (struct netmap_vp_adapter *)na;
 	req->port_index = vpna->bdg_port;
@@ -533,7 +533,7 @@ netmap_vale_vp_dtor(struct netmap_adapter *na)
 	struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na;
 	struct nm_bridge *b = vpna->na_bdg;
 
-	ND("%s has %d references", na->name, na->na_refcount);
+	nm_prdis("%s has %d references", na->name, na->na_refcount);
 
 	if (b) {
 		netmap_bdg_detach_common(b, vpna->bdg_port, -1);
@@ -542,7 +542,7 @@ netmap_vale_vp_dtor(struct netmap_adapter *na)
 	if (na->ifp != NULL && !nm_iszombie(na)) {
 		NM_DETACH_NA(na->ifp);
 		if (vpna->autodelete) {
-			ND("releasing %s", na->ifp->if_xname);
+			nm_prdis("releasing %s", na->ifp->if_xname);
 			NMG_UNLOCK();
 			nm_os_vi_detach(na->ifp);
 			NMG_LOCK();
@@ -628,12 +628,12 @@ nm_vale_preflush(struct netmap_kring *kring, u_int end)
 	 * shared lock, waiting if we can sleep (if the source port is
 	 * attached to a user process) or with a trylock otherwise (NICs).
 	 */
-	ND("wait rlock for %d packets", ((j > end ? lim+1 : 0) + end) - j);
+	nm_prdis("wait rlock for %d packets", ((j > end ? lim+1 : 0) + end) - j);
 	if (na->up.na_flags & NAF_BDG_MAYSLEEP)
 		BDG_RLOCK(b);
 	else if (!BDG_RTRYLOCK(b))
 		return j;
-	ND(5, "rlock acquired for %d packets", ((j > end ? lim+1 : 0) + end) - j);
+	nm_prdis(5, "rlock acquired for %d packets", ((j > end ? lim+1 : 0) + end) - j);
 	ft = kring->nkr_ft;
 
 	for (; likely(j != end); j = nm_next(j, lim)) {
@@ -644,7 +644,7 @@ nm_vale_preflush(struct netmap_kring *kring, u_int end)
 		ft[ft_i].ft_flags = slot->flags;
 		ft[ft_i].ft_offset = 0;
 
-		ND("flags is 0x%x", slot->flags);
+		nm_prdis("flags is 0x%x", slot->flags);
 		/* we do not use the buf changed flag, but we still need to reset it */
 		slot->flags &= ~NS_BUF_CHANGED;
 
@@ -667,7 +667,7 @@ nm_vale_preflush(struct netmap_kring *kring, u_int end)
 			continue;
 		}
 		if (unlikely(netmap_verbose && frags > 1))
-			RD(5, "%d frags at %d", frags, ft_i - frags);
+			nm_prlim(5, "%d frags at %d", frags, ft_i - frags);
 		ft[ft_i - frags].ft_frags = frags;
 		frags = 1;
 		if (unlikely((int)ft_i >= bridge_batch))
@@ -815,8 +815,9 @@ nm_kr_space(struct netmap_kring *k, int is_rx)
 		k->nr_tail >= k->nkr_num_slots ||
 		busy < 0 ||
 		busy >= k->nkr_num_slots) {
-		D("invalid kring, cur %d tail %d lease %d lease_idx %d lim %d",			k->nr_hwcur, k->nr_hwtail, k->nkr_hwlease,
-			k->nkr_lease_idx, k->nkr_num_slots);
+		nm_prerr("invalid kring, cur %d tail %d lease %d lease_idx %d lim %d",
+		    k->nr_hwcur, k->nr_hwtail, k->nkr_hwlease,
+		    k->nkr_lease_idx, k->nkr_num_slots);
 	}
 #endif
 	return space;
@@ -893,7 +894,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		struct nm_vale_q *d;
 		struct nm_bdg_fwd *start_ft = NULL;
 
-		ND("slot %d frags %d", i, ft[i].ft_frags);
+		nm_prdis("slot %d frags %d", i, ft[i].ft_frags);
 
 		if (na->up.virt_hdr_len < ft[i].ft_len) {
 			ft[i].ft_offset = na->up.virt_hdr_len;
@@ -909,7 +910,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		}
 		dst_port = b->bdg_ops.lookup(start_ft, &dst_ring, na, b->private_data);
 		if (netmap_verbose > 255)
-			RD(5, "slot %d port %d -> %d", i, me, dst_port);
+			nm_prlim(5, "slot %d port %d -> %d", i, me, dst_port);
 		if (dst_port >= NM_BDG_NOPORT)
 			continue; /* this packet is identified to be dropped */
 		else if (dst_port == NM_BDG_BROADCAST)
@@ -956,7 +957,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		}
 	}
 
-	ND(5, "pass 1 done %d pkts %d dsts", n, num_dsts);
+	nm_prdis(5, "pass 1 done %d pkts %d dsts", n, num_dsts);
 	/* second pass: scan destinations */
 	for (i = 0; i < num_dsts; i++) {
 		struct netmap_vp_adapter *dst_na;
@@ -971,7 +972,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		int virt_hdr_mismatch = 0;
 
 		d_i = dsts[i];
-		ND("second pass %d port %d", i, d_i);
+		nm_prdis("second pass %d port %d", i, d_i);
 		d = dst_ents + d_i;
 		// XXX fix the division
 		dst_na = b->bdg_ports[d_i/NM_BDG_MAXRINGS];
@@ -988,7 +989,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		 * - when na is being deactivated but is still attached.
 		 */
 		if (unlikely(!nm_netmap_on(&dst_na->up))) {
-			ND("not in netmap mode!");
+			nm_prdis("not in netmap mode!");
 			goto cleanup;
 		}
 
@@ -1006,7 +1007,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 
 		if (unlikely(dst_na->up.virt_hdr_len != na->up.virt_hdr_len)) {
 			if (netmap_verbose) {
-				RD(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len,
+				nm_prlim(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len,
 						dst_na->up.virt_hdr_len);
 			}
 			/* There is a virtio-net header/offloadings mismatch between
@@ -1028,11 +1029,11 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 				KASSERT(dst_na->mfs > 0, ("vpna->mfs is 0"));
 				needed = (needed * na->mfs) /
 						(dst_na->mfs - WORST_CASE_GSO_HEADER) + 1;
-				ND(3, "srcmtu=%u, dstmtu=%u, x=%u", na->mfs, dst_na->mfs, needed);
+				nm_prdis(3, "srcmtu=%u, dstmtu=%u, x=%u", na->mfs, dst_na->mfs, needed);
 			}
 		}
 
-		ND(5, "pass 2 dst %d is %x %s",
+		nm_prdis(5, "pass 2 dst %d is %x %s",
 			i, d_i, is_vp ? "virtual" : "nic/host");
 		dst_nr = d_i & (NM_BDG_MAXRINGS-1);
 		nrings = dst_na->up.num_rx_rings;
@@ -1098,7 +1099,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 			if (unlikely(cnt > howmany))
 			    break; /* no more space */
 			if (netmap_verbose && cnt > 1)
-				RD(5, "rx %d frags to %d", cnt, j);
+				nm_prlim(5, "rx %d frags to %d", cnt, j);
 			ft_end = ft_p + cnt;
 			if (unlikely(virt_hdr_mismatch)) {
 				bdg_mismatch_datapath(na, dst_na, ft_p, ring, &j, lim, &howmany);
@@ -1111,7 +1112,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 					slot = &ring->slot[j];
 					dst = NMB(&dst_na->up, slot);
 
-					ND("send [%d] %d(%d) bytes at %s:%d",
+					nm_prdis("send [%d] %d(%d) bytes at %s:%d",
 							i, (int)copy_len, (int)dst_len,
 							NM_IFPNAME(dst_ifp), j);
 					/* round to a multiple of 64 */
@@ -1119,7 +1120,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 
 					if (unlikely(copy_len > NETMAP_BUF_SIZE(&dst_na->up) ||
 						     copy_len > NETMAP_BUF_SIZE(&na->up))) {
-						RD(5, "invalid len %d, down to 64", (int)copy_len);
+						nm_prlim(5, "invalid len %d, down to 64", (int)copy_len);
 						copy_len = dst_len = 64; // XXX
 					}
 					if (ft_p->ft_flags & NS_INDIRECT) {
@@ -1155,10 +1156,10 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 			 * i can recover the slots, otherwise must
 			 * fill them with 0 to mark empty packets.
 			 */
-			ND("leftover %d bufs", howmany);
+			nm_prdis("leftover %d bufs", howmany);
 			if (nm_next(lease_idx, lim) == kring->nkr_lease_idx) {
 			    /* yes i am the last one */
-			    ND("roll back nkr_hwlease to %d", j);
+			    nm_prdis("roll back nkr_hwlease to %d", j);
 			    kring->nkr_hwlease = j;
 			} else {
 			    while (howmany-- > 0) {
@@ -1323,7 +1324,7 @@ netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	na->nm_krings_create = netmap_vale_vp_krings_create;
 	na->nm_krings_delete = netmap_vale_vp_krings_delete;
 	na->nm_dtor = netmap_vale_vp_dtor;
-	ND("nr_mem_id %d", req->nr_mem_id);
+	nm_prdis("nr_mem_id %d", req->nr_mem_id);
 	na->nm_mem = nmd ?
 		netmap_mem_get(nmd):
 		netmap_mem_private_new(
@@ -1594,11 +1595,11 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 	if (error) {
 		goto err_2;
 	}
-	ND("returning nr_mem_id %d", req->nr_mem_id);
+	nm_prdis("returning nr_mem_id %d", req->nr_mem_id);
 	if (nmd)
 		netmap_mem_put(nmd);
 	NMG_UNLOCK();
-	ND("created %s", ifp->if_xname);
+	nm_prdis("created %s", ifp->if_xname);
 	return 0;
 
 err_2:

From 1e8a73a96edc36f0ff9315d2ea49d7245b9e6705 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 5 Feb 2019 11:24:04 +0100
Subject: [PATCH 1600/2207] freebsd: import ixl updates from stable/11

---
 sys/dev/netmap/if_em_netmap.h  |  2 +-
 sys/dev/netmap/if_ixl_netmap.h | 17 ++++++++---------
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index 766db141c..a3987b92b 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -190,7 +190,7 @@ em_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
 		/* record completed transmissions using TDH */
 		nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(kring->ring_id));
-		if (unlilkely(nic_i >= kring->nkr_num_slots)) {
+		if (unlikely(nic_i >= kring->nkr_num_slots)) {
 			nm_prerr("TDH wrap at idx %d", nic_i);
 			nic_i -= kring->nkr_num_slots;
 		}
diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h
index 9309e0d10..547ed3d8a 100644
--- a/sys/dev/netmap/if_ixl_netmap.h
+++ b/sys/dev/netmap/if_ixl_netmap.h
@@ -24,7 +24,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_ixl_netmap.h 279232 2015-02-24 06:20:50Z luigi $
+ * $FreeBSD$
  *
  * netmap support for: ixl
  *
@@ -67,6 +67,7 @@ extern int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip;
  * ixl_rx_miss, ixl_rx_miss_bufs:
  *	count packets that might be missed due to lost interrupts.
  */
+int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip = 1;
 SYSCTL_DECL(_dev_netmap);
 /*
  * The xl driver by default strips CRCs and we do not override it.
@@ -128,12 +129,8 @@ ixl_netmap_attach(struct ixl_vsi *vsi)
 
 	na.ifp = vsi->ifp;
 	na.na_flags = NAF_BDG_MAYSLEEP;
-	// XXX check that queues is set.
-	nm_prinf("queues is %p", vsi->queues);
-	if (vsi->queues) {
-		na.num_tx_desc = vsi->queues[0].num_desc;
-		na.num_rx_desc = vsi->queues[0].num_desc;
-	}
+	na.num_tx_desc = vsi->num_tx_desc;
+	na.num_rx_desc = vsi->num_rx_desc;
 	na.nm_txsync = ixl_netmap_txsync;
 	na.nm_rxsync = ixl_netmap_rxsync;
 	na.nm_register = ixl_netmap_reg;
@@ -265,8 +262,10 @@ ixl_netmap_txsync(struct netmap_kring *kring, int flags)
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
-	nic_i = LE32_TO_CPU(*(volatile __le32 *)&txr->base[que->num_desc]);
-	if (nic_i != txr->next_to_clean) {
+	nic_i = LE32_TO_CPU(*(volatile __le32 *)&txr->base[que->num_tx_desc]);
+	if (unlikely(nic_i >= que->num_tx_desc)) {
+		nm_prerr("error: invalid value of hw head index %u", nic_i);
+	} else if (nic_i != txr->next_to_clean) {
 		/* some tx completed, increment avail */
 		txr->next_to_clean = nic_i;
 		kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);

From 0bc253a09a0af0400e10591f45bb38fa037ec567 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 5 Feb 2019 11:48:25 +0100
Subject: [PATCH 1601/2207] freebsd: if_vtnet_netmap.h: fix compilation issues

---
 sys/dev/netmap/if_vtnet_netmap.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index abaed8ee7..e0da855ef 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -90,7 +90,6 @@ vtnet_netmap_reg(struct netmap_adapter *na, int state)
 	struct ifnet *ifp = na->ifp;
 	struct vtnet_softc *sc = ifp->if_softc;
 	int success;
-	enum txrx t;
 	int i;
 
 	/* Drain the taskqueues to make sure that there are no worker threads
@@ -132,11 +131,11 @@ vtnet_netmap_reg(struct netmap_adapter *na, int state)
 	success = (ifp->if_drv_flags & IFF_DRV_RUNNING) ? 0 : ENXIO;
 
 	if (state) {
-		netmap_krings_mode_commit(na, onoff);
+		netmap_krings_mode_commit(na, state);
 		nm_set_native_flags(na);
 	} else {
 		nm_clear_native_flags(na);
-		netmap_krings_mode_commit(na, onoff);
+		netmap_krings_mode_commit(na, state);
 	}
 
 	VTNET_CORE_UNLOCK(sc);

From 5c80f480764917cb307abf9f7914bab756c51384 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 5 Feb 2019 16:21:17 +0100
Subject: [PATCH 1602/2207] linux: update virtio-net to run on 4.20

---
 .travis.yml                                   |   2 +
 LINUX/configure                               |  10 ++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 132 +++++++++++++++---
 WINDOWS/netmap_windows.c                      |   2 +-
 4 files changed, 123 insertions(+), 23 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 90f46056b..ec81d67de 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,6 +42,8 @@ env:
   - KERNEL_VERSION=4.16  ARCH=x86_64
   - KERNEL_VERSION=4.17  ARCH=x86_64
   - KERNEL_VERSION=4.18  ARCH=x86_64
+  - KERNEL_VERSION=4.19  ARCH=x86_64
+  - KERNEL_VERSION=4.20  ARCH=x86_64
   - KERNEL_VERSION=3.16  ARCH=i386
 script:
   - "./ci/build-linux $KERNEL_VERSION $ARCH"
diff --git a/LINUX/configure b/LINUX/configure
index 3bc2ceaa9..080c7ef85 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2065,6 +2065,16 @@ EOF
   	}
 EOF
   
+     add_test 'have GET_LINK_KSETTINGS' <
+
+	int
+	dummy(struct ethtool_ops *ops, struct ethtool_link_ksettings *l)
+	{
+		return ops->get_link_ksettings(NULL, l);
+	}
+EOF
+
   fi # virtio-net
   
   if drv enabled i40e; then
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 54228c829..68d841c70 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..b1528eb 100644
+index cbf1c61..6815f0b 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,12 @@
@@ -512,7 +512,95 @@ index cbf1c61..b1528eb 100644
  	}
  	put_online_cpus();
  
-@@ -1446,16 +1406,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1364,47 +1324,57 @@ static void virtnet_get_channels(struct net_device *dev,
+ }
+ 
+ /* Check if the user is trying to change anything besides speed/duplex */
+-static bool virtnet_validate_ethtool_cmd(const struct ethtool_cmd *cmd)
++static bool
++virtnet_validate_ethtool_cmd(const struct ethtool_link_ksettings *cmd)
+ {
+-	struct ethtool_cmd diff1 = *cmd;
+-	struct ethtool_cmd diff2 = {};
++	struct ethtool_link_ksettings diff1 = *cmd;
++	struct ethtool_link_ksettings diff2 = {};
+ 
+ 	/* cmd is always set so we need to clear it, validate the port type
+ 	 * and also without autonegotiation we can ignore advertising
+ 	 */
+-	ethtool_cmd_speed_set(&diff1, 0);
+-	diff2.port = PORT_OTHER;
+-	diff1.advertising = 0;
+-	diff1.duplex = 0;
+-	diff1.cmd = 0;
++	diff1.base.speed = 0;
++	diff2.base.port = PORT_OTHER;
++	ethtool_link_ksettings_zero_link_mode(&diff1, advertising);
++	diff1.base.duplex = 0;
++	diff1.base.cmd = 0;
++	diff1.base.link_mode_masks_nwords = 0;
+ 
+-	return !memcmp(&diff1, &diff2, sizeof(diff1));
++	return !memcmp(&diff1.base, &diff2.base, sizeof(diff1.base)) &&
++		bitmap_empty(diff1.link_modes.supported,
++			     __ETHTOOL_LINK_MODE_MASK_NBITS) &&
++		bitmap_empty(diff1.link_modes.advertising,
++			     __ETHTOOL_LINK_MODE_MASK_NBITS) &&
++		bitmap_empty(diff1.link_modes.lp_advertising,
++			     __ETHTOOL_LINK_MODE_MASK_NBITS);
+ }
+ 
+-static int virtnet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++static int virtnet_set_link_ksettings(struct net_device *dev,
++				      const struct ethtool_link_ksettings *cmd)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	u32 speed;
+ 
+-	speed = ethtool_cmd_speed(cmd);
++	speed = cmd->base.speed;
+ 	/* don't allow custom speed and duplex */
+ 	if (!ethtool_validate_speed(speed) ||
+-	    !ethtool_validate_duplex(cmd->duplex) ||
++	    !ethtool_validate_duplex(cmd->base.duplex) ||
+ 	    !virtnet_validate_ethtool_cmd(cmd))
+ 		return -EINVAL;
+ 	vi->speed = speed;
+-	vi->duplex = cmd->duplex;
++	vi->duplex = cmd->base.duplex;
+ 
+ 	return 0;
+ }
+ 
+-static int virtnet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++static int virtnet_get_link_ksettings(struct net_device *dev,
++				      struct ethtool_link_ksettings *cmd)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 
+-	ethtool_cmd_speed_set(cmd, vi->speed);
+-	cmd->duplex = vi->duplex;
+-	cmd->port = PORT_OTHER;
++	cmd->base.speed = vi->speed;
++	cmd->base.duplex = vi->duplex;
++	cmd->base.port = PORT_OTHER;
+ 
+ 	return 0;
+ }
+@@ -1424,8 +1394,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
+ 	.set_channels = virtnet_set_channels,
+ 	.get_channels = virtnet_get_channels,
+ 	.get_ts_info = ethtool_op_get_ts_info,
+-	.get_settings = virtnet_get_settings,
+-	.set_settings = virtnet_set_settings,
++#ifdef NETMAP_LINUX_HAVE_GET_LINK_KSETTINGS
++	.get_link_ksettings = virtnet_get_link_ksettings,
++	.set_link_ksettings = virtnet_set_link_ksettings,
++#endif  /* NETMAP_LINUX_HAVE_GET_LINK_KSETTINGS */
+ };
+ 
+ #define MIN_MTU 68
+@@ -1446,16 +1418,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -532,7 +620,7 @@ index cbf1c61..b1528eb 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1502,7 +1461,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+@@ -1502,7 +1473,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -542,7 +630,7 @@ index cbf1c61..b1528eb 100644
  		netif_napi_del(&vi->rq[i].napi);
  	}
  
-@@ -1565,8 +1526,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1538,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -551,7 +639,7 @@ index cbf1c61..b1528eb 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1574,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1586,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -568,7 +656,7 @@ index cbf1c61..b1528eb 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1656,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1668,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -579,7 +667,7 @@ index cbf1c61..b1528eb 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1664,6 @@ err:
+@@ -1701,33 +1676,6 @@ err:
  	return ret;
  }
  
@@ -613,7 +701,7 @@ index cbf1c61..b1528eb 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1704,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1716,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -624,7 +712,7 @@ index cbf1c61..b1528eb 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1743,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1755,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -632,7 +720,7 @@ index cbf1c61..b1528eb 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1751,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1763,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -641,7 +729,7 @@ index cbf1c61..b1528eb 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1761,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1773,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -661,7 +749,7 @@ index cbf1c61..b1528eb 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,16 +1802,21 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,16 +1814,21 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -685,7 +773,7 @@ index cbf1c61..b1528eb 100644
  	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
  		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
  	else
-@@ -1885,6 +1829,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1841,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -693,7 +781,7 @@ index cbf1c61..b1528eb 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1837,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1849,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -701,7 +789,7 @@ index cbf1c61..b1528eb 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1851,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1863,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -712,7 +800,7 @@ index cbf1c61..b1528eb 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1862,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1874,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -730,7 +818,7 @@ index cbf1c61..b1528eb 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1883,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1895,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -741,7 +829,7 @@ index cbf1c61..b1528eb 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1912,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1924,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -757,7 +845,7 @@ index cbf1c61..b1528eb 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1933,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1945,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -766,7 +854,7 @@ index cbf1c61..b1528eb 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1975,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1987,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -777,7 +865,7 @@ index cbf1c61..b1528eb 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1984,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1996,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -845,7 +933,7 @@ index cbf1c61..b1528eb 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2050,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2062,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 63925458c..133190836 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -100,7 +100,7 @@ ioctlCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
     NMG_UNLOCK();
 
     //--------------------------------------------------------
-    //D("Netmap.sys: Pid %i attached: memory allocated @%p", currentProcId, priv);
+    //nm_prinf("Netmap.sys: Pid %i attached: memory allocated @%p", currentProcId, priv);
 
     Irp->IoStatus.Status = status;
     IoCompleteRequest( Irp, IO_NO_INCREMENT );

From 8109cc22d17f0846f96a06f20f37d99a7dd837a5 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 5 Feb 2019 17:17:26 +0100
Subject: [PATCH 1603/2207] linux: virtio_net.c: add guards for ethtool link
 settings code

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 54 ++++++++++---------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index 68d841c70..d625baa0e 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..6815f0b 100644
+index cbf1c61..f9a8c2d 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,12 @@
@@ -512,9 +512,11 @@ index cbf1c61..6815f0b 100644
  	}
  	put_online_cpus();
  
-@@ -1364,47 +1324,57 @@ static void virtnet_get_channels(struct net_device *dev,
+@@ -1363,51 +1323,63 @@ static void virtnet_get_channels(struct net_device *dev,
+ 	channels->other_count = 0;
  }
  
++#ifdef NETMAP_LINUX_HAVE_GET_LINK_KSETTINGS
  /* Check if the user is trying to change anything besides speed/duplex */
 -static bool virtnet_validate_ethtool_cmd(const struct ethtool_cmd *cmd)
 +static bool
@@ -587,7 +589,11 @@ index cbf1c61..6815f0b 100644
  
  	return 0;
  }
-@@ -1424,8 +1394,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
++#endif  /* NETMAP_LINUX_HAVE_GET_LINK_KSETTINGS */
+ 
+ static void virtnet_init_settings(struct net_device *dev)
+ {
+@@ -1424,8 +1396,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
  	.set_channels = virtnet_set_channels,
  	.get_channels = virtnet_get_channels,
  	.get_ts_info = ethtool_op_get_ts_info,
@@ -600,7 +606,7 @@ index cbf1c61..6815f0b 100644
  };
  
  #define MIN_MTU 68
-@@ -1446,16 +1418,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1420,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -620,7 +626,7 @@ index cbf1c61..6815f0b 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1502,7 +1473,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+@@ -1502,7 +1475,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -630,7 +636,7 @@ index cbf1c61..6815f0b 100644
  		netif_napi_del(&vi->rq[i].napi);
  	}
  
-@@ -1565,8 +1538,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1540,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -639,7 +645,7 @@ index cbf1c61..6815f0b 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1586,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1588,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -656,7 +662,7 @@ index cbf1c61..6815f0b 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1668,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1670,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -667,7 +673,7 @@ index cbf1c61..6815f0b 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1676,6 @@ err:
+@@ -1701,33 +1678,6 @@ err:
  	return ret;
  }
  
@@ -701,7 +707,7 @@ index cbf1c61..6815f0b 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1716,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1718,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -712,7 +718,7 @@ index cbf1c61..6815f0b 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1755,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1757,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -720,7 +726,7 @@ index cbf1c61..6815f0b 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1763,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1765,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -729,7 +735,7 @@ index cbf1c61..6815f0b 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1773,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1775,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -749,7 +755,7 @@ index cbf1c61..6815f0b 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,16 +1814,21 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,16 +1816,21 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -773,7 +779,7 @@ index cbf1c61..6815f0b 100644
  	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
  		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
  	else
-@@ -1885,6 +1841,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1843,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -781,7 +787,7 @@ index cbf1c61..6815f0b 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1849,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1851,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -789,7 +795,7 @@ index cbf1c61..6815f0b 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1863,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1865,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -800,7 +806,7 @@ index cbf1c61..6815f0b 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1874,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1876,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -818,7 +824,7 @@ index cbf1c61..6815f0b 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1895,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1897,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -829,7 +835,7 @@ index cbf1c61..6815f0b 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1924,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1926,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -845,7 +851,7 @@ index cbf1c61..6815f0b 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1945,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1947,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -854,7 +860,7 @@ index cbf1c61..6815f0b 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1987,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1989,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -865,7 +871,7 @@ index cbf1c61..6815f0b 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1996,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +1998,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -933,7 +939,7 @@ index cbf1c61..6815f0b 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2062,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2064,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 5a02914ecdb5c2107c8a37316ac658113b56cc64 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 7 Feb 2019 11:51:32 +0100
Subject: [PATCH 1604/2207] Revert "netmap_attach_ext: use nm_prinf rather than
 if_printf"

This reverts commit 1ce7e77ff70c57446d733552cc47eeecfc169b7b.
---
 LINUX/bsd_glue.h        | 2 ++
 WINDOWS/win_glue.h      | 1 +
 sys/dev/netmap/netmap.c | 3 +--
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 6c5e1f458..0c56323c6 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -532,6 +532,8 @@ void netmap_bns_unregister(void);
 #define NM_BNS_PUT(b)   do { (void)(b); } while (0)
 #endif
 
+#define if_printf(ifp, fmt, ...)  dev_info(&(ifp)->dev, fmt, ##__VA_ARGS__)
+
 #ifndef BIT_ULL
 #define BIT_ULL(nr)	(1ULL << (nr))
 #endif /* !BIT_ULL */
diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index 70f3ba7cb..39523d194 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -153,6 +153,7 @@ static void panic(const char *fmt, ...)
 	NT_ASSERT(1);
 }
 
+#define if_printf	DbgPrint
 #define __assert	NT_ASSERT
 #define assert		NT_ASSERT
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 993c63da0..be7e636ae 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3711,8 +3711,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		hwna->up.nm_dtor = netmap_hw_dtor;
 	}
 
-	nm_prinf("%s: netmap queues/slots: TX %d/%d, RX %d/%d\n",
-	    hwna->up.name,
+	if_printf(ifp, "netmap queues/slots: TX %d/%d, RX %d/%d\n",
 	    hwna->up.num_tx_rings, hwna->up.num_tx_desc,
 	    hwna->up.num_rx_rings, hwna->up.num_rx_desc);
 	return 0;

From 6d3a00936a7dfae50d97b9f90d5f05bff235c86c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Feb 2019 17:36:15 +0100
Subject: [PATCH 1605/2207] testmmap: dump/accept null ports

---
 utils/testmmap.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index 425b4427b..a10114e62 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1407,6 +1407,9 @@ nmr_body_dump_register(void *b)
 	case NR_REG_PIPE_SLAVE:
 		printf("*PIPE_SLAVE(%d)", r->nr_ringid);
 		break;
+	case NR_REG_NULL:
+		printf("NULL");
+		break;
 	default:
 		printf("???");
 		break;
@@ -1465,6 +1468,8 @@ do_register_mode()
 		curr_register.nr_mode = NR_REG_PIPE_MASTER;
 	} else if (strcmp(mode, "pipe-slave") == 0) {
 		curr_register.nr_mode = NR_REG_PIPE_SLAVE;
+	} else if (strcmp(mode, "null") == 0) {
+		curr_register.nr_mode = NR_REG_NULL;
 	}
 
 out:

From 957acfc936906922daddaf8bcaee03d6ee255d05 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Feb 2019 23:11:34 +0100
Subject: [PATCH 1606/2207] extend nmreq_register to support multiple
 host-rings

---
 sys/dev/netmap/netmap.c        | 42 ++++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_legacy.c |  4 ++++
 sys/dev/netmap/netmap_mem2.c   |  2 ++
 sys/net/netmap.h               | 15 ++++++++----
 sys/net/netmap_user.h          |  3 ++-
 utils/testmmap.c               |  2 +-
 6 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index be7e636ae..43b383496 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1035,6 +1035,10 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 		}
 
 		na->nm_krings_delete(na);
+
+		/* restore the default number of host tx and rx rings */
+		na->num_host_tx_rings = 1;
+		na->num_host_rx_rings = 1;
 	}
 
 	/* possibily decrement counter of tx_si/rx_si users */
@@ -1575,6 +1579,19 @@ netmap_get_na(struct nmreq_header *hdr,
 	*na = ret;
 	netmap_adapter_get(ret);
 
+	/*
+	 * if the adapter supports the host rings and it is not alread open,
+	 * try to set the number of host rings as requested by the user
+	 */
+	if (((*na)->na_flags & NAF_HOST_RINGS) && (*na)->active_fds == 0) {
+		if (req->nr_host_tx_rings)
+			(*na)->num_host_tx_rings = req->nr_host_tx_rings;
+		if (req->nr_host_rx_rings)
+			(*na)->num_host_rx_rings = req->nr_host_rx_rings;
+	}
+	nm_prdis("%s: host tx %d rx %u", (*na)->name, (*na)->num_host_tx_rings,
+			(*na)->num_host_rx_rings);
+
 out:
 	if (error) {
 		if (ret)
@@ -1856,6 +1873,25 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
 			nm_prdis("ONE_NIC: %s %d %d", nm_txrx2str(t),
 				priv->np_qfirst[t], priv->np_qlast[t]);
 			break;
+		case NR_REG_ONE_SW:
+			if (!(na->na_flags & NAF_HOST_RINGS)) {
+				nm_prerr("host rings not supported");
+				return EINVAL;
+			}
+			if (nr_ringid >= na->num_host_tx_rings &&
+					nr_ringid >= na->num_host_rx_rings) {
+				nm_prerr("invalid ring id %d", nr_ringid);
+				return EINVAL;
+			}
+			/* if not enough rings, use the first one */
+			j = nr_ringid;
+			if (j >= nma_get_host_nrings(na, t))
+				j = 0;
+			priv->np_qfirst[t] = nma_get_nrings(na, t) + j;
+			priv->np_qlast[t] = nma_get_nrings(na, t) + j + 1;
+			nm_prdis("ONE_SW: %s %d %d", nm_txrx2str(t),
+				priv->np_qfirst[t], priv->np_qlast[t]);
+			break;
 		default:
 			nm_prerr("invalid regif type %d", nr_mode);
 			return EINVAL;
@@ -2546,6 +2582,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				req->nr_tx_rings = na->num_tx_rings;
 				req->nr_rx_slots = na->num_rx_desc;
 				req->nr_tx_slots = na->num_tx_desc;
+				req->nr_host_tx_rings = na->num_host_tx_rings;
+				req->nr_host_rx_rings = na->num_host_rx_rings;
 				error = netmap_mem_get_info(na->nm_mem, &req->nr_memsize, &memflags,
 					&req->nr_mem_id);
 				if (error) {
@@ -2610,6 +2648,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					regreq.nr_rx_slots = req->nr_rx_slots;
 					regreq.nr_tx_rings = req->nr_tx_rings;
 					regreq.nr_rx_rings = req->nr_rx_rings;
+					regreq.nr_host_tx_rings = req->nr_host_tx_rings;
+					regreq.nr_host_rx_rings = req->nr_host_rx_rings;
 					regreq.nr_mem_id = req->nr_mem_id;
 
 					/* get a refcount */
@@ -2647,6 +2687,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				req->nr_tx_rings = na->num_tx_rings;
 				req->nr_rx_slots = na->num_rx_desc;
 				req->nr_tx_slots = na->num_tx_desc;
+				req->nr_host_tx_rings = na->num_host_tx_rings;
+				req->nr_host_rx_rings = na->num_host_rx_rings;
 			} while (0);
 			netmap_unget_na(na, ifp);
 			NMG_UNLOCK();
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index afbd5ced8..e5ab66ade 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -68,6 +68,8 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
 	req->nr_rx_slots = nmr->nr_rx_slots;
 	req->nr_tx_rings = nmr->nr_tx_rings;
 	req->nr_rx_rings = nmr->nr_rx_rings;
+	req->nr_host_tx_rings = 0;
+	req->nr_host_rx_rings = 0;
 	req->nr_mem_id = nmr->nr_arg2;
 	req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
 	if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
@@ -249,6 +251,8 @@ nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
 			req->nr_rx_slots = nmr->nr_rx_slots;
 			req->nr_tx_rings = nmr->nr_tx_rings;
 			req->nr_rx_rings = nmr->nr_rx_rings;
+			req->nr_host_tx_rings = 0;
+			req->nr_host_rx_rings = 0;
 			req->nr_mem_id = nmr->nr_arg2;
 		}
 		break;
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index e8c5e6bf8..5cc8cbed5 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2012,6 +2012,8 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	/* initialize base fields -- override const */
 	*(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings;
 	*(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings;
+	*(u_int *)(uintptr_t)&nifp->ni_host_tx_rings = na->num_host_tx_rings;
+	*(u_int *)(uintptr_t)&nifp->ni_host_rx_rings = na->num_host_rx_rings;
 	strlcpy(nifp->ni_name, na->name, sizeof(nifp->ni_name));
 
 	/*
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 704c5162c..e15d28a99 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -41,9 +41,9 @@
 #ifndef _NET_NETMAP_H_
 #define _NET_NETMAP_H_
 
-#define	NETMAP_API	13		/* current API version */
+#define	NETMAP_API	14		/* current API version */
 
-#define	NETMAP_MIN_API	13		/* min and max versions accepted */
+#define	NETMAP_MIN_API	14		/* min and max versions accepted */
 #define	NETMAP_MAX_API	15
 /*
  * Some fields should be cache-aligned to reduce contention.
@@ -374,7 +374,9 @@ struct netmap_if {
 	const uint32_t	ni_rx_rings;	/* number of HW rx rings */
 
 	uint32_t	ni_bufs_head;	/* head index for extra bufs */
-	uint32_t	ni_spare1[5];
+	const uint32_t	ni_host_tx_rings; /* number of SW tx rings */
+	const uint32_t	ni_host_rx_rings; /* number of SW rx rings */
+	uint32_t	ni_spare1[3];
 	/*
 	 * The following array contains the offset of each netmap ring
 	 * from this structure, in the following order:
@@ -574,6 +576,8 @@ struct nmreq_register {
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
 	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_host_tx_rings; /* number of host tx rings */
+	uint16_t	nr_host_rx_rings; /* number of host rx rings */
 
 	uint16_t	nr_mem_id;	/* id of the memory allocator */
 	uint16_t	nr_ringid;	/* ring(s) we care about */
@@ -611,6 +615,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 	NR_REG_PIPE_MASTER = 5, /* deprecated, use "x{y" port name syntax */
 	NR_REG_PIPE_SLAVE = 6,  /* deprecated, use "x}y" port name syntax */
 	NR_REG_NULL     = 7,
+	NR_REG_ONE_SW	= 8,
 };
 
 /* A single ioctl number is shared by all the new API command.
@@ -640,8 +645,10 @@ struct nmreq_port_info_get {
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
 	uint16_t	nr_rx_rings;	/* number of rx rings */
+	uint16_t	nr_host_tx_rings; /* number of host tx rings */
+	uint16_t	nr_host_rx_rings; /* number of host rx rings */
 	uint16_t	nr_mem_id;	/* memory allocator id (in/out) */
-	uint16_t	pad1;
+	uint16_t	pad[3];
 };
 
 #define	NM_BDG_NAME		"vale"	/* prefix for bridge port name */
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index e9ce9c43e..923437d50 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -111,7 +111,8 @@
 	nifp, (nifp)->ring_ofs[index] )
 
 #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *,	\
-	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
+	nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 		\
+		(nifp)->ni_host_tx_rings] )
 
 #define NETMAP_BUF(ring, index)				\
 	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
diff --git a/utils/testmmap.c b/utils/testmmap.c
index a10114e62..a37a39bcb 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -603,7 +603,7 @@ do_if()
 	printf("tx_rings   %u\n", nifp->ni_tx_rings);
 	printf("rx_rings   %u\n", nifp->ni_rx_rings);
 	printf("bufs_head  %u\n", nifp->ni_bufs_head);
-	for (i = 0; i < 5; i++)
+	for (i = 0; i < 3; i++)
 		printf("spare1[%d]  %u\n", i, nifp->ni_spare1[i]);
 	for (i = 0; i < (nifp->ni_tx_rings + nifp->ni_rx_rings + 2); i++)
 		printf("ring_ofs[%d] %zd\n", i, nifp->ring_ofs[i]);

From 961f7054b60f25b4fab1ae5790ce20d45964c523 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 17 Jul 2018 16:26:44 +0200
Subject: [PATCH 1607/2207] libnetmap: a library for the CTRL API

---
 LINUX/configure            |   4 +
 LINUX/netmap.mak.in        |  35 +-
 apps/include/ctrs.h        |   2 +
 apps/pkt-gen/pkt-gen.c     |   5 +-
 libnetmap/GNUmakefile      |  29 ++
 libnetmap/libnetmap.h      | 645 +++++++++++++++++++++++++++++++++
 libnetmap/nmctx-pthreads.c |  46 +++
 libnetmap/nmctx.c          | 110 ++++++
 libnetmap/nmport.c         | 721 +++++++++++++++++++++++++++++++++++++
 libnetmap/nmreq.c          | 667 ++++++++++++++++++++++++++++++++++
 libnetmap/npopts.lds       |  13 +
 sys/net/netmap_user.h      |  97 ++---
 12 files changed, 2312 insertions(+), 62 deletions(-)
 create mode 100644 libnetmap/GNUmakefile
 create mode 100644 libnetmap/libnetmap.h
 create mode 100644 libnetmap/nmctx-pthreads.c
 create mode 100644 libnetmap/nmctx.c
 create mode 100644 libnetmap/nmport.c
 create mode 100644 libnetmap/nmreq.c
 create mode 100644 libnetmap/npopts.lds

diff --git a/LINUX/configure b/LINUX/configure
index 080c7ef85..ecb6bd1f7 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2189,6 +2189,10 @@ ln -s $SRCDIR/drv-subdir.mak || true
 
 report
 
+# create the build directory for libnetmap
+mkdir -p build-libnetmap
+ln -s $SRCDIR/../libnetmap/GNUmakefile build-libnetmap 2>/dev/null || true
+
 # create the build directory for the examples
 mkdir -p build-apps
 for a in $(app print); do
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index f1be117fd..8961d4778 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -75,7 +75,7 @@ endef
 .PHONY: $(foreach d,$(E_DRIVERS),build-$(d) clean-$(1) install-$(1)) netmap.ko
 
 
-all: $(S_DRIVERS:%=get-%) netmap.ko $(E_DRIVERS:%=build-%) apps utils
+all: $(S_DRIVERS:%=get-%) netmap.ko $(E_DRIVERS:%=build-%) libnetmap apps utils
 
 netmap.ko:
 	$(MAKE) $(COMMON_OPTS) CONFIG_NETMAP=m $(MOD_LIST) O_DRIVERS="$(patsubst %.c,%.o,$(filter-out $(DRIVERS_EXT),$(DRIVERS)))" NETMAP_DRIVER_SUFFIX=$(DRVSUFFIX)
@@ -88,8 +88,8 @@ netmap.ko:
 $(foreach d,$(S_DRIVERS),$(eval $(call common_driver,$(d))))
 $(foreach d,$(E_DRIVERS),$(eval $(call external_driver,$(d))))
 
-.PHONY: install install-netmap install-apps install-headers install-docs
-install: install-netmap $(E_DRIVERS:%=install-%) install-apps install-headers install-docs
+.PHONY: install install-netmap install-apps install-headers install-docs libnetmap
+install: install-netmap $(E_DRIVERS:%=install-%) install-apps install-headers install-docs install-libnetmap
 
 install-netmap:
 	$(MAKE) -C $(KSRC) M=$(BUILDDIR) CONFIG_NETMAP=m $(MOD_LIST) \
@@ -99,7 +99,7 @@ install-netmap:
 		$(if $(MODPATH),INSTALL_MOD_PATH=$(MODPATH)) \
 		modules_install
 
-clean: $(E_DRIVERS:%=clean-%) clean-apps clean-utils
+clean: $(E_DRIVERS:%=clean-%) clean-apps clean-utils clean-libnetmap
 	-@ $(MAKE) -C $(KSRC) M=$(BUILDDIR) clean 2> /dev/null
 
 APPS_LIST=@APPS_LIST@
@@ -117,20 +117,29 @@ clean-apps: $(APPS_LIST:%=clean-app-%)
 
 .PHONY: apps $(APPS_BUILD) install-apps $(APPS_INSTALL)
 define apps_actions
-build-app-$(1):
-	+$(MAKE) -C build-apps/$(1) SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)"
+build-app-$(1): libnetmap
+	+$(MAKE) -C build-apps/$(1) SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR) CC="$(APPS_CC)" LD="$(APPS_LD)"
 
 install-app-$(1):
-	$(MAKE) -C build-apps/$(1) install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
+	$(MAKE) -C build-apps/$(1) install SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR) DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
 
 clean-app-$(1):
-	$(MAKE) -C build-apps/$(1) clean SRCDIR=$(SRCDIR)/..
+	$(MAKE) -C build-apps/$(1) clean SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR)
 endef
 $(foreach a,$(APPS_LIST),$(eval $(call apps_actions,$(a))))
 
 +%:
 	@echo '$($*)'
 
+libnetmap:
+	+$(MAKE) -C build-libnetmap SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR) CC="$(APPS_CC)" LD="$(APPS_LD)"
+
+clean-libnetmap:
+	+$(MAKE) -C build-libnetmap clean SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR)
+
+install-libnetmap:
+	+$(MAKE) -C build-libnetmap install SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR) DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
+
 ifeq (,$(UTILS))
 utils:
 install-utils:
@@ -139,14 +148,14 @@ intest:
 unitest:
 else
 .PHONY: utils
-utils:
-	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. CC="$(APPS_CC)" LD="$(APPS_LD)" SUBSYS_FLAGS="$(SUBSYS_FLAGS)"
+utils: libnetmap
+	+$(MAKE) -C build-utils SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR) CC="$(APPS_CC)" LD="$(APPS_LD)" SUBSYS_FLAGS="$(SUBSYS_FLAGS)"
 
 install-utils:
-	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
+	$(MAKE) -C build-utils install SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR) DESTDIR="$(abspath $(DESTDIR))" PREFIX="$(PREFIX)"
 
 clean-utils:
-	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/..
+	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR)
 
 intest: utils
 	$(SRCDIR)/../utils/randomized_tests
@@ -161,6 +170,7 @@ install-headers:
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_user.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_user.h
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_virt.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_virt.h
 	install -m 0644 -D $(SRCDIR)/../sys/net/netmap_legacy.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/net/netmap_legacy.h
+	install -m 0644 -D $(SRCDIR)/../libnetmap/libnetmap.h $(DESTDIR)/$(INCLUDE_PREFIX)/include/libnetmap.h
 
 MAN_PREFIX := $(INCLUDE_PREFIX)
 
@@ -181,6 +191,7 @@ distclean: clean $(S_DRIVERS:%=distclean-%)
 	if [ -L tests ]; then rm tests; fi
 	rm -rf build-apps
 	rm -rf build-utils
+	rm -rf build-libnetmap
 
 format:
 	clang-format -i -style=file $(shell git ls-files "utils/*.[ch]" "apps/*.[ch]" "extra/*.[ch]" "LINUX/*.[ch]" "WINDOWS/*.[ch]" "sys/*.[ch]")
diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h
index a41ae6853..b8bb8c986 100644
--- a/apps/include/ctrs.h
+++ b/apps/include/ctrs.h
@@ -3,6 +3,8 @@
 
 /* $FreeBSD$ */
 
+#include 
+#include 
 #include 
 
 /* counters to accumulate statistics */
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 040992422..5ece1e347 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -626,10 +626,10 @@ parse_nmr_config(const char* conf, struct nmreq *nmr)
 	char *w, *tok;
 	int i, v;
 
-	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
-	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
 	if (conf == NULL || ! *conf)
 		return 0;
+	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
+	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
 	w = strdup(conf);
 	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
 		v = atoi(tok);
@@ -2973,6 +2973,7 @@ main(int arc, char **argv)
 			g.options |= OPT_DUMP;
 			break;
 		case 'C':
+			D("WARNING: the 'C' option is deprecated, use the '+conf:' libnetmap option instead");
 			g.nmr_config = strdup(optarg);
 			break;
 		case 'H':
diff --git a/libnetmap/GNUmakefile b/libnetmap/GNUmakefile
new file mode 100644
index 000000000..beb3d5e6e
--- /dev/null
+++ b/libnetmap/GNUmakefile
@@ -0,0 +1,29 @@
+CFLAGS=-O2 -pipe -Wall -Werror
+CFLAGS=-g
+CFLAGS += -I $(SRCDIR)/sys
+VPATH = $(SRCDIR)/libnetmap
+SRCS=$(notdir $(wildcard $(SRCDIR)/libnetmap/*.c))
+OBJS=$(filter-out nmport.o,$(SRCS:.c=.o)) nmport2.o
+
+all: libnetmap.a
+
+$(OBJS): libnetmap.h
+
+nmport2.o: nmport.o
+	$(LD) -r -T $(VPATH)/npopts.lds nmport.o -o $@
+
+libnetmap.a: $(OBJS)
+	$(AR) r $@ $^
+
+.PHONY: clean distclean install
+clean:
+	rm -f *.o
+
+distclean: clean
+	rm -f libnetmap.a
+
+install:
+	install -D libnetmap.a $(DESTDIR)/$(PREFIX)/lib/libnetmap.a
+
++%:
+	@echo $*=$($*)
diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
new file mode 100644
index 000000000..39ad9c0dc
--- /dev/null
+++ b/libnetmap/libnetmap.h
@@ -0,0 +1,645 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LIBNETMAP_H_
+#define LIBNETMAP_H_
+/* if thread-safety is not needed, define LIBNETMAP_NOTHREADSAFE before including
+ * this file.
+ */
+
+/* NOTE: we include net/netmap_user.h without defining NETMAP_WITH_LIBS, which
+ * is deprecated. If you still need it, please define NETMAP_WITH_LIBS and
+ * include net/netmap_user.h before including this file.
+ */
+#include 
+
+struct nmctx;
+struct nmport_d;
+struct nmem_d;
+
+/*
+ * A port open specification (portspec for brevity) has the following syntax
+ * (square brackets delimit optional parts):
+ *
+ *     subsystem:vpname[mode][options]
+ *
+ *  The "subsystem" is denoted by a prefix, possibly followed by an identifier.
+ *  There can be several kinds of subsystems, each one selected by a unique
+ *  prefix.  Currently defined subsystems are:
+ *
+ *  netmap 		(no id allowed)
+ *  			the standard subsystem
+ *
+ *  vale 		(followed by a possibily empty id)
+ *  			the vpname is connected to a VALE switch identified by
+ *  			the id (an empty id selects the default switch)
+ *
+ *  The "vpname" has the following syntax:
+ *
+ *     identifier			or
+ *     identifier1{identifier2		or
+ *     identifier1}identifier2
+ *
+ *  Identifiers are sequences of alphanumeric characters. The part that begins
+ *  with either '{' or '}', when present, denotes a netmap pipe opened in the
+ *  same memory region as the subsystem:indentifier1 port.
+ *
+ * The "mode" can be one of the following:
+ *
+ *	^		bind the host (sw) ring pair
+ *	*		bind host and NIC ring pairs
+ *	-NN		bind individual NIC ring pair
+ *	@NN		open the port in the NN memory region
+ *	a suffix starting with / and the following flags,
+ *	in any order:
+ *	x		exclusive access
+ *	z		zero copy monitor (both tx and rx)
+ *	t		monitor tx side (copy monitor)
+ *	r		monitor rx side (copy monitor)
+ *	R		bind only RX ring(s)
+ *	T		bind only TX ring(s)
+ *
+ *  The "options" start at the first '@' character not followed by a number.
+ *  Each option starts with '@' and has the following syntax:
+ *
+ *      option					(flag option)
+ *      option=value				(single key option)
+ *      option:key1=value1,key2=value2,...	(multi-key option)
+ *
+ *  For multi-key options, the keys can be assigned in any order, but they
+ *  cannot be assigned more than once. It is not necessary to assign all the
+ *  option keys: unmentioned keys will receive default values.  Some multi-key
+ *  options define a default key and also accept the single-key syntax, by
+ *  assigning the value to this key.
+ *
+ *  NOTE: Options may be silently ignored if the port is already open by some
+ *  other process.
+ *
+ *  The currently available options are (default keys, when defined, are marked
+ *  with '*'):
+ *
+ *  share (single-key)
+ *  			open the port in the same memory region used by the
+ *  			given port name (the port name must be given in
+ *  			subsystem:vpname form)
+ *
+ *  conf  (multi-key)
+ *  			specify the rings/slots numbers (effective only on
+ *  			ports that are created by the open operation itself,
+ *  			and ignored otherwise).
+ *
+ *			The keys are:
+ *
+ *  		       *rings		number of tx and rx rings
+ *  			tx-rings	number of tx rings
+ *  			rx-rings	number of rx rings
+ *  			slots		number of slots in each tx and rx
+ *  					ring
+ *  			tx-slots	number of slots in each tx ring
+ *  			rx-slots	numner of slots in each rx ring
+ *
+ *  			(more specific keys override the less specific ones)
+ *			All keys default to zero not assigned, and the
+ *			corresponding value will be chosen by netmap.
+ *
+ *  extmem (multi-key)
+ *			open the port in the memory region obtained by
+ *			mmap()ing the given file.
+ *
+ *			The keys are:
+ *
+ *		       *file		the file to mmap
+ *			if-num		number of pre-allocated netmap_if's
+ *			if-size		size of each netmap_if
+ *			ring-num	number of pre-allocated netmap_ring's
+ *			ring-size	size of each netmap_ring
+ *			buf-num		number of pre-allocated buffers
+ *			buf-size	size of each buffer
+ *
+ *			file must be assigned. The other keys default to zero,
+ *			causing netmap to take the corresponding values from
+ *			the priv_{if,ring,buf}_{num,size} sysctls.
+ */
+
+
+/* nmport manipulation */
+
+/* struct nmport_d - describes a netmap port */
+struct nmport_d {
+	/* see net/netmap.h for the definition of these fields */
+	struct nmreq_header hdr;
+	struct nmreq_register reg;
+
+	/* all the fields below should be considered read-only */
+
+	/* if the same context is used throughout the program, d1->mem ==
+	 * d2->mem iff d1 and d2 are using the memory region (i.e., zero
+	 * copy is possible between the two ports)
+	 */
+	struct nmem_d *mem;
+
+	/* the nmctx used when this nmport_d was created */
+	struct nmctx *ctx;
+
+	int register_done;	/* nmport_register() has been called */
+	int mmap_done;		/* nmport_mmap() has been called */
+	/* pointer to the extmem option contained in the hdr options, if any */
+	struct nmreq_opt_extmem *extmem;
+	int extmem_autounmap;	/* 1 if nmport_undo_extmem should also munmap */
+
+	/* the fields below are compatible with nm_open() */
+	int fd;				/* "/dev/netmap", -1 if not open */
+	struct netmap_if *nifp;		/* pointer to the netmap_if */
+	uint16_t first_tx_ring;
+	uint16_t last_tx_ring;
+	uint16_t first_rx_ring;
+	uint16_t last_rx_ring;
+	uint16_t cur_tx_ring;		/* used by nmport_inject */
+	uint16_t cur_rx_ring;
+};
+
+/* nmport_open - opens a port from a portspec
+ * @portspec	the port opening specification
+ *
+ * If successfull, the function returns a new nmport_d describing a netmap
+ * port, opened according to the port specification, ready to be used for rx
+ * and/or tx.
+ *
+ * The rings available for tx are in the [first_tx_ring, last_tx_ring]
+ * interval, and similarly for rx. One or both intervals may be empty.
+ *
+ * When done using it, the nmport_d descriptor must free closed using
+ * nmport_close().
+ *
+ * In case of error, NULL is returned, errno is set to some error, and an
+ * error message is sent through the error() method of the current context.
+ */
+struct nmport_d * nmport_open(const char *portspec);
+
+/* nport_close - close a netmap port
+ * @d		the port we want to close
+ *
+ * Undoes the actions performed by the nmport_open that created d, then
+ * frees the descriptor.
+ */
+void nmport_close(struct nmport_d *d);
+
+/* nmport_inject - sends a packet
+ * @d		the port through which we want to send
+ * @buf		base address of the packet
+ * @size	its size in bytes
+ *
+ * Sends a packet using the cur_tx_ring and updates the index
+ * to use all available tx rings in turn. Note: the packet is copied.
+ *
+ * Returns 0 on success an -1 on error.
+ */
+int nmport_inject(struct nmport_d *d, const void *buf, size_t size);
+
+/*
+ * the functions below can be used to split the functionality of
+ * nmport_open when special features (e.g., extra buffers) are needed
+ *
+ * The relation among the functions is as follows:
+ *
+ *				   |nmport_new
+ * 		|nport_prepare	 = |
+ *		|		   |nmport_parse
+ * nmport_open =|
+ *		|		   |nmport_register
+ *		|nport_open_desc = |
+ *				   |nmport_mmap
+ *
+ */
+
+/* nmport_new - create a new nmport_d
+ *
+ * Creates a new nmport_d using the malloc() method of the current default
+ * context. Returns NULL on error, setting errno to an error value.
+ */
+struct nmport_d *nmport_new(void);
+
+/* nmport_parse - fills the nmport_d netmap-register request
+ * @d		the nmport to be filled
+ * @portspec	the port opening specification
+ *
+ * This function parses the portspec and initizalizes the @d->hdr and @d->reg
+ * fields. It may need to allocate a list of options. If an extmem option is
+ * found, it may also mmap() the corresponding file.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_parse(struct nmport_d *d, const char *portspec);
+
+/* nmport_register - registers the port with netmap
+ * @d		the nmport to be registered
+ *
+ * This function obtains a netmap file descriptor and registers the port with
+ * netmap. The @d->hdr and @d->reg data structures must have been previously
+ * initialized (via nmport_parse() or otherwise).
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_register(struct nmport_d *);
+
+/* nmport_mmap - maps the port resources into the process memory
+ * @d		the nmport to be mapped
+ *
+ * The port must have been previosly been registered using nmport_register.
+ *
+ * Note that if extmem is used (either via an option or by calling an
+ * nmport_extmem_* function before nmport_register()), no new mmap() is issued.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_mmap(struct nmport_d *);
+
+/* the following functions undo the actions of nmport_new(), nmport_parse(),
+ * nmport_register() and nmport_mmap(), respectively.
+ */
+void nmport_delete(struct nmport_d *);
+void nmport_undo_parse(struct nmport_d *);
+void nmport_undo_register(struct nmport_d *);
+void nmport_undo_mmap(struct nmport_d *);
+
+/* nmport_prepare - create a port descriptor, but do not open it
+ * @portspec	the port opening specification
+ *
+ * This functions creates a new nmport_d and initializes it according to
+ * @portspec. It is equivalent to nmport_new() followed by nmport_parse().
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+struct nmport_d *nmport_prepare(const char *portspec);
+
+/* nmport_open_desc - open an initialized port descriptor
+ * @d		the descriptor we want to open
+ *
+ * Registers the port with netmap and maps the rings and buffers into the
+ * process memory. It is equivalent to nmport_register() followed by
+ * nmport_mmap().
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_open_desc(struct nmport_d *d);
+
+/* the following functions undo the actions of nmport_prepare()
+ * and nmport_open_desc(), respectively.
+ */
+void nmport_undo_prepare(struct nmport_d *);
+void nmport_undo_open_desc(struct nmport_d *);
+
+/* nmport_clone - copy an nmport_d
+ * @d		the nmport_d we want to copy
+ *
+ * Copying an nmport_d by hand should be avoided, since adjustments are needed
+ * and some part of the state cannot be easily duplicated. This function
+ * creates a copy of @d in a safe way. The returned nmport_d contains
+ * nmreq_header and nmreq_register structures equivalent to those contained in
+ * @d, except for the option list, which is ignored. The returned nmport_d is
+ * already nmport_prepare()d, but it must still be nmport_open_desc()ed. The
+ * new nmport_d uses the same nmctx as @d.
+ *
+ * If extmem was used for @d, then @d cannot be nmport_clone()d until it has
+ * been nmport_register()ed.
+ *
+ * In case of error, the function returns NULL, sets errno to an error value
+ * and sends an error message to the nmctx error() method.
+ */
+struct nmport_d *nmport_clone(struct nmport_d *);
+
+/* nmport_extmem - use extmem for this port
+ * @d		the port we want to use the extmem for
+ * @base	the base address of the extmem region
+ * @size	the size in bytes of the extmem region
+ *
+ * the memory that contains the netmap ifs, rings and buffers is usually
+ * allocated by netmap and later mmap()ed by the applications. It is sometimes
+ * useful to reverse this process, by having the applications allocate some
+ * memory (through mmap() or otherwise) and then let netmap use it.  The extmem
+ * option can be used to implement this latter strategy. The option can be
+ * passed through the portspec using the '@extmem:...' syntax, or
+ * programmatically by calling nmport_extmem() or nmport_extmem_from_file()
+ * between nmport_parse() and nmport_register() (or between nmport_prepare()
+ * and nmport_open_desc()).
+ *
+ * If @d was already using extmem the function fails. The previous extmem
+ * can be removed with nmport_extmem_undo(), if necessary.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_extmem(struct nmport_d *d, void *base, size_t size);
+
+/* nmport_extmem - use the extmem obtained by mapping a file
+ * @d		the port we want to use the extmem for
+ * @fname	path of the file we want to map
+ *
+ * This works like nmport_extmem, but the extmem memory is obtained
+ * by mmap()ping @fname. netmap_undo_extmem() and nmport_close()
+ * will also automatically munmap() the file.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_extmem_from_file(struct nmport_d *d, const char *fname);
+
+/* nmport_undo_extmem - remove the extmem option, if any
+ * @d		the port we want to remove the extmem from
+ *
+ * Removes the extmem option, if any was used in @d. It also munmap the
+ * extmem region if that was obtained via nmport_extmem_from_file().
+ */
+void nmport_undo_extmem(struct nmport_d *);
+
+/* enable/disable options
+ *
+ * These functions can be used to disable options that the application cannot
+ * or doesn't want to handle, or to enable options that require special support
+ * from the application and are, therefore, disabled by default. Disabled
+ * options will cause an error if encountered during option parsing.
+ *
+ * If the option is unknown, nmport_disable_option is a NOP, while
+ * nmport_enable_option returns -1 and sets errno to EOPNOTSUPP.
+ *
+ * These functions are not threadsafe and are ment to be used at the beginning
+ * of the program.
+ */
+void nmport_disable_option(const char *opt);
+int nmport_enable_option(const char *opt);
+
+/* nmreq manipulation
+ *
+ * nmreq_header_init - initialize an nmreq_header
+ * @hdr		the nmreq_header to initialize
+ * @reqtype	the kind of netmap request
+ * @body	the body of the request
+ *
+ * Initialize the nr_version, nr_reqtype and nr_body fields of *@hdr.
+ * The other fields are set to zero.
+ */
+void nmreq_header_init(struct nmreq_header *hdr, uint16_t reqtype, void *body);
+
+/*
+ * These functions allow for finer grained parsing of portspecs.  They are used
+ * internally by nmport_parse().
+ */
+
+/* nmreq_header_decode - initialize an nmreq_header
+ * @ppspec:	(in/out) pointer to a pointer to the portspec
+ * @hdr:	pointer to the nmreq_header to be initialized
+ * @ctx:	pointer to the nmctx to use (for errors)
+ *
+ * This function fills the @hdr the nr_name field with the port name extracted
+ * from *@pifname.  The other fields of *@hdr are unchanged. The @pifname is
+ * updated to point at the first char past the port name.
+ *
+ * Returns 0 on success.  In case of error, -1 is returned with errno set to
+ * EINVAL, @pifname is unchanged, *@hdr is also unchanged, and an error message
+ * is sent through @ctx->error().
+ */
+int nmreq_header_decode(const char **ppspec, struct nmreq_header *hdr,
+		struct nmctx *ctx);
+
+/* nmreq_regiter_decode - inizialize an nmreq_register
+ * @pmode:	(in/out) pointer to a pointer to an opening mode
+ * @reg:	pointer to the nmreq_register to be initialized
+ * @ctx:	pointer to the nmctx to use (for errors)
+ *
+ * This function fills the nr_mode, nr_ringid, nr_flags and nr_mem_id fields of
+ * the structure pointed by @reg, according to the opening mode specified by
+ * *@pmode. The other fields of *@reg are unchanged.  The @pmode is updated to
+ * point at the first char past the opening mode.
+ *
+ * If a '@' is encountered followed by something which is not a number, parsing
+ * stops (without error) and @pmode is left pointing at the '@' char. The
+ * nr_mode, nr_ringid and nr_flags fields are still updated, but nr_mem_id is
+ * not touched and the interpretation of the '@' field is left to the caller.
+ *
+ * Returns 0 on success.  In case of error, -1 is returned with errno set to
+ * EINVAL, @pmode is unchanged, *@reg is also unchanged, and an error message
+ * is sent through @ctx->error().
+ */
+int nmreq_register_decode(const char **pmode, struct nmreq_register *reg,
+		struct nmctx *ctx);
+
+/* nmreq_options_decode - parse the "options" part of the portspec
+ * @opt:	pointer to the option list
+ * @parsers:	list of option parsers
+ * @nr_parsers:	number of parsers in the list
+ * @token:	token to pass to each parser
+ * @ctx:	pointer to the nmctx to use (for errors and malloc/free)
+ *
+ * This function parses each option in @opt. Each option is matched (based on
+ * the "option" prefix) to a corresponding parser in @parsers. The function
+ * checks that the syntax is appropriate for the parser and it assignes all the
+ * keys mentioned in the option. It then passes control to the parser, to
+ * interpret the keys values.
+ *
+ * Returns 0 on success. In case of error, -1 is returned, errno is set to an
+ * error value and a message is sent to @ctx->error(). The effects of partially
+ * interpreted options may not be undone.
+ */
+struct nmreq_opt_parser;
+int nmreq_options_decode(const char *opt, struct nmreq_opt_parser *parsers,
+		int nr_parsers, void *token, struct nmctx *ctx);
+
+struct nmreq_parse_ctx;
+/* type of the option-parsers callbacks */
+typedef int (*nmreq_opt_parser_cb)(struct nmreq_parse_ctx *);
+
+#define NMREQ_OPT_MAXKEYS 16	/* max nr of recognized keys per option */
+
+/* struct nmreq_opt_key - describes an option key */
+struct nmreq_opt_key {
+	const char *key;	/* the key name */
+	int id;			/* its position in the parse context */
+	unsigned int flags;
+#define NMREQ_OPTK_ALLOWEMPTY 	(1U << 0) /* =value may be omitted */
+#define NMREQ_OPTK_NODEFAULT	(1U << 1) /* the key is mandatory */
+};
+
+/* struct nmreq_opt_parser - describes an option parser */
+struct nmreq_opt_parser {
+	const char *prefix;	/* matches one option prefix */
+	nmreq_opt_parser_cb parse;	/* the parse callback */
+	int default_key;	/* which option is the default if the
+				   parser is multi-key (-1 if none) */
+	int nr_keys;
+	unsigned int flags;
+#define NMREQ_OPTF_DISABLED     (1U << 0)
+#define NMREQ_OPTF_ALLOWEMPTY	(1U << 1)	/* =value can be omitted */
+
+	/* recognized keys */
+	struct nmreq_opt_key keys[NMREQ_OPT_MAXKEYS];
+} __attribute__((aligned(16)));
+
+/* struct nmreq_parse_ctx - the parse context received by the parse callback */
+struct nmreq_parse_ctx {
+	struct nmctx *ctx;	/* the nmctx for errors and malloc/free */
+	void *token;		/* the token passed to nmreq_options_parse */
+
+	/* the value (i.e., the part after the = sign) of each recognized key
+	 * is assigned to the corresponding entry in this array, based on the
+	 * key id. Unassigned keys are left at NULL.
+	 */
+	const char *keys[NMREQ_OPT_MAXKEYS];
+};
+
+/* nmreq_get_mem_id - get the mem_id of the given port
+ * @portname	pointer to a pointer to the portname
+ * @ctx		pointer to the nmctx to use (for errors)
+ *
+ * *@portname must point to a substem:vpname porname, possibily followed by
+ * something else.
+ *
+ * If successful, returns the mem_id of *@portname and moves @portname past the
+ * subsystem:vpname part of the input. In case of error it returns -1, sets
+ * errno to an error value and sends an error message to ctx->error().
+ */
+int32_t nmreq_get_mem_id(const char **portname, struct nmctx *ctx);
+
+/* option list manipulation */
+void nmreq_push_option(struct nmreq_header *, struct nmreq_option *);
+void nmreq_remove_option(struct nmreq_header *, struct nmreq_option *);
+struct nmreq_option *nmreq_find_option(struct nmreq_header *, uint32_t);
+void nmreq_free_options(struct nmreq_header *);
+
+/* nmctx manipulation */
+
+/* the nmctx serves a few purposes:
+ *
+ * - maintain a list of all memory regions open by the program, so that two
+ *   ports that are using the same region (as identified by the mem_id) will
+ *   point to the same nmem_d instance.
+ *
+ * - allow the user to specifiy how to lock accesses to the above list, if
+ *   needed (lock() callback)
+ *
+ * - allow the user to specifiy how error messages should be delivered (error()
+ *   callback)
+ *
+ * - select the verbosity of the library (verbose field); if verbose==0, no
+ *   errors are sent to the error() callback
+ *
+ * - allow the user to override the malloc/free functions used by the library
+ *   (malloc() and free() callbacks)
+ *
+ */
+typedef void  (*nmctx_error_cb)(struct nmctx *, const char *);
+typedef void *(*nmctx_malloc_cb)(struct nmctx *,size_t);
+typedef void  (*nmctx_free_cb)(struct nmctx *,void *);
+typedef void  (*nmctx_lock_cb)(struct nmctx *, int);
+
+struct nmctx {
+	int verbose;
+	nmctx_error_cb 	error;
+	nmctx_malloc_cb	malloc;
+	nmctx_free_cb	free;
+	nmctx_lock_cb	lock;
+
+	struct nmem_d  *mem_descs;
+};
+
+/* nmctx_get - obtain a pointer to the current default context */
+struct nmctx *nmctx_get(void);
+
+/* nmctx_set_default - change the default context
+ * @ctx		pointer to the new context
+ *
+ * Returns a pointer to the previous default context.
+ */
+struct nmctx *nmctx_set_default(struct nmctx *ctx);
+
+/* internal functions and data structures */
+
+/* struct nmem_d - describes a memory region currently used */
+struct nmem_d {
+	uint16_t mem_id;	/* the region netmap identifer */
+	int refcount;		/* how many nmport_d's point here */
+	void *mem;		/* memory region base address */
+	size_t size;		/* memory region size */
+	int is_extmem;		/* was it obtained via extmem? */
+
+	/* pointers for the circular list implementation.
+	 * The list head is the mem_descs filed in the nmctx
+	 */
+	struct nmem_d *next;
+	struct nmem_d *prev;
+};
+
+/* a trick to force the inclusion of libpthread only if requested. If
+ * LIBNETMAP_NOTHREADSAFE is defined, no pthread symbol is imported.
+ *
+ * There is no need to actually call this function: the ((used)) attribute is
+ * sufficient to include it in the image.
+ */
+static  __attribute__((used)) void libnetmap_init(void)
+{
+#ifndef LIBNETMAP_NOTHREADSAFE
+	extern int nmctx_threadsafe;
+	/* dummy assignment to link-in the nmctx-pthread.o object.  The proper
+	 * inizialization is performed only once in the library constructor
+	 * defined there.
+	 */
+	nmctx_threadsafe = 1;
+#endif /* LIBNETMAP_NOTHREADSAFE */
+}
+
+/* nmctx_set_threadsafe - install a threadsafe default context
+ *
+ * called by the contructor in nmctx-pthread.o to initialize a lock and install
+ * the lock() callback in the default context.
+ */
+void nmctx_set_threadsafe(void);
+
+/* nmctx_ferror - format and send an error message */
+void nmctx_ferror(struct nmctx *, const char *, ...);
+/* nmctx_malloc - allocate memory */
+void *nmctx_malloc(struct nmctx *, size_t);
+/* nmctx_free - free memory allocated via nmctx_malloc */
+void nmctx_free(struct nmctx *, void *);
+/* nmctx_lock - lock the list of nmem_d */
+void nmctx_lock(struct nmctx *);
+/* nmctx_unlock - unlock the list of nmem_d */
+void nmctx_unlock(struct nmctx *);
+
+#endif /* LIBNETMAP_H_ */
diff --git a/libnetmap/nmctx-pthreads.c b/libnetmap/nmctx-pthreads.c
new file mode 100644
index 000000000..7253abf9c
--- /dev/null
+++ b/libnetmap/nmctx-pthreads.c
@@ -0,0 +1,46 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "libnetmap.h"
+
+struct nmctx_pthread {
+	struct nmctx up;
+	pthread_mutex_t mutex;
+};
+
+static struct nmctx_pthread nmctx_pthreadsafe;
+
+static void
+nmctx_pthread_lock(struct nmctx *ctx, int lock)
+{
+	struct nmctx_pthread *ctxp =
+		(struct nmctx_pthread *)ctx;
+	if (lock) {
+		pthread_mutex_lock(&ctxp->mutex);
+	} else {
+		pthread_mutex_unlock(&ctxp->mutex);
+	}
+}
+
+void __attribute__ ((constructor))
+nmctx_set_threadsafe(void)
+{
+	struct nmctx *old;
+
+	pthread_mutex_init(&nmctx_pthreadsafe.mutex, NULL);
+	old = nmctx_set_default(&nmctx_pthreadsafe.up);
+	nmctx_pthreadsafe.up = *old;
+	nmctx_pthreadsafe.up.lock = nmctx_pthread_lock;
+}
+
+int nmctx_threadsafe;
diff --git a/libnetmap/nmctx.c b/libnetmap/nmctx.c
new file mode 100644
index 000000000..e9f9238fa
--- /dev/null
+++ b/libnetmap/nmctx.c
@@ -0,0 +1,110 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#define LIBNETMAP_NOTHREADSAFE
+#include "libnetmap.h"
+
+static void
+nmctx_default_error(struct nmctx *ctx, const char *errmsg)
+{
+	fprintf(stderr, "%s\n", errmsg);
+}
+
+static void *
+nmctx_default_malloc(struct nmctx *ctx, size_t sz)
+{
+	(void)ctx;
+	return malloc(sz);
+}
+
+static void
+nmctx_default_free(struct nmctx *ctx, void *p)
+{
+	(void)ctx;
+	free(p);
+}
+
+static struct nmctx nmctx_global = {
+	.verbose = 1,
+	.error = nmctx_default_error,
+	.malloc = nmctx_default_malloc,
+	.free = nmctx_default_free,
+	.lock = NULL,
+};
+
+static struct nmctx *nmctx_default = &nmctx_global;
+
+struct nmctx *
+nmctx_get(void)
+{
+	return nmctx_default;
+}
+
+struct nmctx *
+nmctx_set_default(struct nmctx *ctx)
+{
+	struct nmctx *old = nmctx_default;
+	nmctx_default = ctx;
+	return old;
+}
+
+#define MAXERRMSG 1000
+void
+nmctx_ferror(struct nmctx *ctx, const char *fmt, ...)
+{
+	char errmsg[MAXERRMSG];
+	va_list ap;
+	int rv;
+
+	if (!ctx->verbose)
+		return;
+
+	va_start(ap, fmt);
+	rv = vsnprintf(errmsg, MAXERRMSG, fmt, ap);
+	va_end(ap);
+
+	if (rv > 0) {
+		if (rv < MAXERRMSG) {
+			ctx->error(ctx, errmsg);
+		} else {
+			ctx->error(ctx, "error message too long");
+		}
+	} else {
+		ctx->error(ctx, "internal error");
+	}
+}
+
+void *
+nmctx_malloc(struct nmctx *ctx, size_t sz)
+{
+	return ctx->malloc(ctx, sz);
+}
+
+void
+nmctx_free(struct nmctx *ctx, void *p)
+{
+	ctx->free(ctx, p);
+}
+
+void
+nmctx_lock(struct nmctx *ctx)
+{
+	if (ctx->lock != NULL)
+		ctx->lock(ctx, 1);
+}
+
+void
+nmctx_unlock(struct nmctx *ctx)
+{
+	if (ctx->lock != NULL)
+		ctx->lock(ctx, 0);
+}
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
new file mode 100644
index 000000000..e504c17b5
--- /dev/null
+++ b/libnetmap/nmport.c
@@ -0,0 +1,721 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#define LIBNETMAP_NOTHREADSAFE
+#include "libnetmap.h"
+
+static struct nmport_d *
+nmport_new_with_ctx(struct nmctx *ctx)
+{
+	struct nmport_d *d;
+
+	/* allocate a descriptor */
+	d = nmctx_malloc(ctx, sizeof(*d));
+	if (d == NULL) {
+		nmctx_ferror(ctx, "cannot allocate nmport descriptor");
+		goto out;
+	}
+	memset(d, 0, sizeof(*d));
+
+	nmreq_header_init(&d->hdr, NETMAP_REQ_REGISTER, &d->reg);
+
+	d->ctx = ctx;
+	d->fd = -1;
+
+out:
+	return d;
+}
+
+struct nmport_d *
+nmport_new(void)
+{
+	struct nmctx *ctx = nmctx_get();
+	return nmport_new_with_ctx(ctx);
+}
+
+
+void
+nmport_delete(struct nmport_d *d)
+{
+	nmctx_free(d->ctx, d);
+}
+
+int
+nmport_extmem_from_mem(struct nmport_d *d, void *base, size_t size)
+{
+	struct nmctx *ctx = d->ctx;
+
+	if (d->register_done) {
+		nmctx_ferror(ctx, "%s: cannot set extmem of an already registered port", d->hdr.nr_name);
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (d->extmem != NULL) {
+		nmctx_ferror(ctx, "%s: extmem already in use", d->hdr.nr_name);
+		errno = EINVAL;
+		return -1;
+	}
+
+	d->extmem = nmctx_malloc(ctx, sizeof(*d->extmem));
+	if (d->extmem == NULL) {
+		nmctx_ferror(ctx, "%s: cannot allocate extmem option", d->hdr.nr_name);
+		errno = ENOMEM;
+		return -1;
+	}
+	memset(d->extmem, 0, sizeof(*d->extmem));
+	d->extmem->nro_usrptr = (uintptr_t)base;
+	d->extmem->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
+	d->extmem->nro_info.nr_memsize = size;
+	nmreq_push_option(&d->hdr, &d->extmem->nro_opt);
+	return 0;
+}
+
+int
+nmport_extmem_from_file(struct nmport_d *d, const char *fname)
+{
+	struct nmctx *ctx = d->ctx;
+	int fd = -1;
+	off_t mapsize;
+	void *p;
+
+	fd = open(fname, O_RDWR);
+	if (fd < 0) {
+		nmctx_ferror(ctx, "cannot open '%s': %s", fname, strerror(errno));
+		goto fail;
+	}
+	mapsize = lseek(fd, 0, SEEK_END);
+	if (mapsize < 0) {
+		nmctx_ferror(ctx, "failed to obtain filesize of '%s': %s", fname, strerror(errno));
+		goto fail;
+	}
+	p = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if (p == MAP_FAILED) {
+		nmctx_ferror(ctx, "cannot mmap '%s': %s", fname, strerror(errno));
+		goto fail;
+	}
+	d->extmem_autounmap = 1;
+
+	if (nmport_extmem_from_mem(d, p, mapsize) < 0)
+		goto fail;
+
+	close(fd);
+
+	return 0;
+
+fail:
+	if (fd >= 0)
+		close(fd);
+	nmport_undo_extmem(d);
+	return -1;
+}
+
+void
+nmport_undo_extmem(struct nmport_d *d)
+{
+	void *p;
+
+	if (d->extmem == NULL)
+		return;
+
+	p = (void *)d->extmem->nro_usrptr;
+	if (p != MAP_FAILED && d->extmem_autounmap)
+		munmap(p, d->extmem->nro_info.nr_memsize);
+	nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
+	nmctx_free(d->ctx, d->extmem);
+	d->extmem = NULL;
+	d->extmem_autounmap = 0;
+}
+
+#define NPOPT_PARSER(o)		nmport_opt_##o##_parser
+#define NPOPT_DESC(o)		nmport_opt_##o##_desc
+#define NPOPT_DECL(o, f, d)						\
+static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *);			\
+static struct nmreq_opt_parser __attribute__((section(".npopts"),used))	\
+	NPOPT_DESC(o) = {						\
+	.prefix = #o,							\
+	.parse = NPOPT_PARSER(o),					\
+	.flags = (f),							\
+	.default_key = (d),						\
+	.nr_keys = 0,							\
+};
+struct nmport_key_desc {
+	struct nmreq_opt_parser *option;
+	const char *key;
+	unsigned int flags;
+	int *id;
+};
+#define NPKEY_ID(o, k)		nmport_opt_##o##_key_##k##_id
+#define NPKEY_DESC(o, k)	nmport_opt_##o##_key_##k##_desc
+#define NPKEY_DECL(o, k, f)						\
+static int NPKEY_ID(o, k);						\
+static struct nmport_key_desc __attribute__((section(".npkeys"),used))	\
+	NPKEY_DESC(o, k) = {						\
+	.option = &NPOPT_DESC(o),					\
+	.key = #k,							\
+	.flags = (f),							\
+	.id = &NPKEY_ID(o, k),						\
+};
+#define nmport_key(p, o, k)	((p)->keys[NPKEY_ID(o, k)])
+#define nmport_defkey(p, o)	((p)->keys[NPOPT_DESC(o).default_key])
+
+NPOPT_DECL(share, 0, 0)
+NPOPT_DECL(extmem, 0, 0)
+	NPKEY_DECL(extmem, file, NMREQ_OPTK_NODEFAULT)
+	NPKEY_DECL(extmem, if_num, 0)
+	NPKEY_DECL(extmem, if_size, 0)
+	NPKEY_DECL(extmem, ring_num, 0)
+	NPKEY_DECL(extmem, ring_size, 0)
+	NPKEY_DECL(extmem, buf_num, 0)
+	NPKEY_DECL(extmem, buf_size, 0)
+NPOPT_DECL(conf, 0, -1)
+	NPKEY_DECL(conf, rings, 0)
+	NPKEY_DECL(conf, host_rings, 0)
+	NPKEY_DECL(conf, slots, 0)
+	NPKEY_DECL(conf, tx_rings, 0)
+	NPKEY_DECL(conf, rx_rings, 0)
+	NPKEY_DECL(conf, host_tx_rings, 0)
+	NPKEY_DECL(conf, host_rx_rings, 0)
+	NPKEY_DECL(conf, tx_slots, 0)
+	NPKEY_DECL(conf, rx_slots, 0)
+
+static struct nmreq_opt_parser *nmport_opt_parsers;
+static int nmport_opt_parsers_n;
+
+static int
+NPOPT_PARSER(share)(struct nmreq_parse_ctx *p)
+{
+	struct nmctx *ctx = p->ctx;
+	struct nmport_d *d = p->token;
+	int32_t mem_id;
+	const char *v = nmport_defkey(p, share);
+
+	mem_id = nmreq_get_mem_id(&v, ctx);
+	if (mem_id < 0)
+		return -1;
+	if (d->reg.nr_mem_id && d->reg.nr_mem_id != mem_id) {
+		nmctx_ferror(ctx, "cannot set mem_id to %"PRId32", already set to %"PRIu16"",
+				mem_id, d->reg.nr_mem_id);
+		errno = EINVAL;
+		return -1;
+	}
+	d->reg.nr_mem_id = mem_id;
+	return 0;
+}
+
+static int
+NPOPT_PARSER(extmem)(struct nmreq_parse_ctx *p)
+{
+	struct nmport_d *d;
+	struct nmreq_pools_info *pi;
+	int i;
+
+	d = p->token;
+
+	if (nmport_extmem_from_file(d, nmport_key(p, extmem, file)) < 0)
+		return -1;
+
+	pi = &d->extmem->nro_info;
+
+	for  (i = 1; i < 7; i++) {
+		const char *k = p->keys[i];
+		uint32_t v;
+
+		if (k == NULL)
+			continue;
+
+		v = atoi(k);
+		if (i == NPKEY_ID(extmem, if_num)) {
+			pi->nr_if_pool_objtotal = v;
+		} else if (i == NPKEY_ID(extmem, if_size)) {
+			pi->nr_if_pool_objsize = v;
+		} else if (i == NPKEY_ID(extmem, ring_num)) {
+			pi->nr_ring_pool_objtotal = v;
+		} else if (i == NPKEY_ID(extmem, ring_size)) {
+			pi->nr_ring_pool_objsize = v;
+		} else if (i == NPKEY_ID(extmem, buf_num)) {
+			pi->nr_buf_pool_objtotal = v;
+		} else if (i == NPKEY_ID(extmem, buf_size)) {
+			pi->nr_buf_pool_objsize = v;
+		}
+	}
+	return 0;
+}
+
+static int
+NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p)
+{
+	struct nmport_d *d;
+
+	d = p->token;
+
+	if (nmport_key(p, conf, rings) != NULL) {
+		uint16_t nr_rings = atoi(nmport_key(p, conf, rings));
+		d->reg.nr_tx_rings = nr_rings;
+		d->reg.nr_rx_rings = nr_rings;
+	}
+	if (nmport_key(p, conf, host_rings) != NULL) {
+		uint16_t nr_rings = atoi(nmport_key(p, conf, host_rings));
+		d->reg.nr_host_tx_rings = nr_rings;
+		d->reg.nr_host_rx_rings = nr_rings;
+	}
+	if (nmport_key(p, conf, slots) != NULL) {
+		uint32_t nr_slots = atoi(nmport_key(p, conf, slots));
+		d->reg.nr_tx_slots = nr_slots;
+		d->reg.nr_rx_slots = nr_slots;
+	}
+	if (nmport_key(p, conf, tx_rings) != NULL) {
+		d->reg.nr_tx_rings = atoi(nmport_key(p, conf, tx_rings));
+	}
+	if (nmport_key(p, conf, rx_rings) != NULL) {
+		d->reg.nr_rx_rings = atoi(nmport_key(p, conf, rx_rings));
+	}
+	if (nmport_key(p, conf, host_tx_rings) != NULL) {
+		d->reg.nr_host_tx_rings = atoi(nmport_key(p, conf, host_tx_rings));
+	}
+	if (nmport_key(p, conf, host_rx_rings) != NULL) {
+		d->reg.nr_host_rx_rings = atoi(nmport_key(p, conf, host_rx_rings));
+	}
+	if (nmport_key(p, conf, tx_slots) != NULL) {
+		d->reg.nr_tx_slots = atoi(nmport_key(p, conf, tx_slots));
+	}
+	if (nmport_key(p, conf, rx_slots) != NULL) {
+		d->reg.nr_rx_slots = atoi(nmport_key(p, conf, rx_slots));
+	}
+	return 0;
+}
+
+
+void
+nmport_disable_opt(const char *opt)
+{
+	int i;
+
+	for (i = 0; i < nmport_opt_parsers_n; i++) {
+		struct nmreq_opt_parser *p =
+			nmport_opt_parsers + i;
+		if (!strcmp(p->prefix, opt)) {
+			p->flags |= NMREQ_OPTF_DISABLED;
+		}
+	}
+}
+
+int
+nmport_enable_opt(const char *opt)
+{
+	int i;
+
+	for (i = 0; i < nmport_opt_parsers_n; i++) {
+		struct nmreq_opt_parser *p =
+			nmport_opt_parsers + i;
+		if (!strcmp(p->prefix, opt)) {
+			p->flags &= ~NMREQ_OPTF_DISABLED;
+			return 0;
+		}
+	}
+	errno = EOPNOTSUPP;
+	return -1;
+}
+
+
+int
+nmport_parse(struct nmport_d *d, const char *ifname)
+{
+	const char *scan = ifname;
+
+	if (nmreq_header_decode(&scan, &d->hdr, d->ctx) < 0) {
+		goto err;
+	}
+
+	/* parse the register request */
+	if (nmreq_register_decode(&scan, &d->reg, d->ctx) < 0) {
+		goto err;
+	}
+
+	/* parse the options, if any */
+	if (nmreq_options_decode(scan, nmport_opt_parsers,
+				nmport_opt_parsers_n, d, d->ctx) < 0) {
+		goto err;
+	}
+	return 0;
+
+err:
+	nmport_undo_parse(d);
+	return -1;
+}
+
+void
+nmport_undo_parse(struct nmport_d *d)
+{
+	nmport_undo_extmem(d);
+	memset(&d->reg, 0, sizeof(d->reg));
+	memset(&d->hdr, 0, sizeof(d->hdr));
+}
+
+struct nmport_d *
+nmport_prepare(const char *ifname)
+{
+	struct nmport_d *d;
+
+	/* allocate a descriptor */
+	d = nmport_new();
+	if (d == NULL)
+		goto err;
+
+	/* parse the header */
+	if (nmport_parse(d, ifname) < 0)
+		goto err;
+
+	return d;
+
+err:
+	nmport_undo_prepare(d);
+	return NULL;
+}
+
+void
+nmport_undo_prepare(struct nmport_d *d)
+{
+	if (d == NULL)
+		return;
+	nmport_undo_parse(d);
+	nmport_delete(d);
+}
+
+int
+nmport_register(struct nmport_d *d)
+{
+	struct nmctx *ctx = d->ctx;
+
+	if (d->register_done) {
+		errno = EINVAL;
+		nmctx_ferror(ctx, "%s: already registered", d->hdr.nr_name);
+		return -1;
+	}
+
+	d->fd = open("/dev/netmap", O_RDWR);
+	if (d->fd < 0) {
+		nmctx_ferror(ctx, "/dev/netmap: %s", strerror(errno));
+		goto err;
+	}
+
+	if (ioctl(d->fd, NIOCCTRL, &d->hdr) < 0) {
+		nmctx_ferror(ctx, "%s: %s", d->hdr.nr_name, strerror(errno));
+		if (d->extmem != NULL && d->extmem->nro_opt.nro_status) {
+			nmctx_ferror(ctx, "failed to allocate extmem: %s",
+					strerror(d->extmem->nro_opt.nro_status));
+		}
+		goto err;
+	}
+
+	d->register_done = 1;
+
+	return 0;
+
+err:
+	nmport_undo_register(d);
+	return -1;
+}
+
+void
+nmport_undo_register(struct nmport_d *d)
+{
+	if (d->fd >= 0)
+		close(d->fd);
+	d->fd = -1;
+	d->register_done = 0;
+}
+
+/* lookup the mem_id in the mem-list: do a new mmap() if
+ * not found, reuse existing otherwise
+ */
+int
+nmport_mmap(struct nmport_d *d)
+{
+	struct nmctx *ctx = d->ctx;
+	struct nmem_d *m = NULL;
+	u_int num_tx, num_rx;
+	int i;
+
+	if (d->mmap_done) {
+		errno = EINVAL;
+		nmctx_ferror(ctx, "%s: already mapped", d->hdr.nr_name);
+		return -1;
+	}
+
+	if (!d->register_done) {
+		errno = EINVAL;
+		nmctx_ferror(ctx, "cannot map unregistered port");
+		return -1;
+	}
+
+	nmctx_lock(ctx);
+
+	for (m = ctx->mem_descs; m != NULL; m = m->next)
+		if (m->mem_id == d->reg.nr_mem_id)
+			break;
+
+	if (m == NULL) {
+		m = nmctx_malloc(ctx, sizeof(*m));
+		if (m == NULL) {
+			nmctx_ferror(ctx, "cannot allocate memory descriptor");
+			goto err;
+		}
+		memset(m, 0, sizeof(*m));
+		if (d->extmem != NULL) {
+			m->mem = (void *)d->extmem->nro_usrptr;
+			m->size = d->extmem->nro_info.nr_memsize;
+			m->is_extmem = 1;
+		} else {
+			m->mem = mmap(NULL, d->reg.nr_memsize, PROT_READ|PROT_WRITE,
+					MAP_SHARED, d->fd, 0);
+			if (m->mem == MAP_FAILED) {
+				nmctx_ferror(ctx, "mmap: %s", strerror(errno));
+				goto err;
+			}
+			m->size = d->reg.nr_memsize;
+		}
+		m->mem_id = d->reg.nr_mem_id;
+		m->next = ctx->mem_descs;
+		if (ctx->mem_descs != NULL)
+			ctx->mem_descs->prev = m;
+		ctx->mem_descs = m;
+	}
+	m->refcount++;
+
+	nmctx_unlock(ctx);
+
+	d->mem = m;
+
+	d->nifp = NETMAP_IF(m->mem, d->reg.nr_offset);
+
+	num_tx = d->reg.nr_tx_rings + d->reg.nr_host_tx_rings;
+	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++)
+		;
+	d->first_tx_ring = i;
+	for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++)
+		;
+	d->last_tx_ring = i - 1;
+	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i + num_tx]; i++)
+		;
+	d->first_rx_ring = i;
+	num_rx = d->reg.nr_rx_rings + d->reg.nr_host_rx_rings;
+	for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++)
+		;
+	d->last_rx_ring = i - 1;
+
+	d->mmap_done = 1;
+
+	return 0;
+
+err:
+	nmctx_unlock(ctx);
+	nmport_undo_mmap(d);
+	return -1;
+}
+
+void
+nmport_undo_mmap(struct nmport_d *d)
+{
+	struct nmem_d *m;
+	struct nmctx *ctx = d->ctx;
+
+	m = d->mem;
+	if (m == NULL)
+		return;
+	nmctx_lock(ctx);
+	m->refcount--;
+	if (m->refcount <= 0) {
+		if (!m->is_extmem && m->mem != MAP_FAILED)
+			munmap(m->mem, m->size);
+		/* extract from the list and free */
+		if (m->next != NULL)
+			m->next->prev = m->prev;
+		if (m->prev != NULL)
+			m->prev->next = m->next;
+		else
+			ctx->mem_descs = m->next;
+		nmctx_free(ctx, m);
+		d->mem = NULL;
+	}
+	nmctx_unlock(ctx);
+	d->mmap_done = 0;
+	d->mem = NULL;
+	d->nifp = NULL;
+	d->first_tx_ring = 0;
+	d->last_tx_ring = 0;
+	d->first_rx_ring = 0;
+	d->last_rx_ring = 0;
+	d->cur_tx_ring = 0;
+	d->cur_rx_ring = 0;
+}
+
+int
+nmport_open_desc(struct nmport_d *d)
+{
+	if (nmport_register(d) < 0)
+		goto err;
+
+	if (nmport_mmap(d) < 0)
+		goto err;
+
+	return 0;
+err:
+	nmport_undo_open_desc(d);
+	return -1;
+}
+
+void
+nmport_undo_open_desc(struct nmport_d *d)
+{
+	nmport_undo_mmap(d);
+	nmport_undo_register(d);
+}
+
+
+struct nmport_d *
+nmport_open(const char *ifname)
+{
+	struct nmport_d *d;
+
+	/* prepare the descriptor */
+	d = nmport_prepare(ifname);
+	if (d == NULL)
+		goto err;
+
+	/* open netmap and register */
+	if (nmport_open_desc(d) < 0)
+		goto err;
+
+	return d;
+
+err:
+	nmport_close(d);
+	return NULL;
+}
+
+void
+nmport_close(struct nmport_d *d)
+{
+	if (d == NULL)
+		return;
+	nmport_undo_open_desc(d);
+	nmport_undo_prepare(d);
+}
+
+struct nmport_d *
+nmport_clone(struct nmport_d *d)
+{
+	struct nmport_d *c;
+	struct nmctx *ctx;
+
+	ctx = d->ctx;
+
+	if (d->extmem != NULL && !d->register_done) {
+		errno = EINVAL;
+		nmctx_ferror(ctx, "cannot clone unregistered port that is using extmem");
+		return NULL;
+	}
+
+	c = nmport_new_with_ctx(ctx);
+	if (c == NULL)
+		return NULL;
+	/* copy the output of parse */
+	c->hdr = d->hdr;
+	/* redirect the pointer to the body */
+	c->hdr.nr_body = (uintptr_t)&c->reg;
+	/* options are not cloned */
+	c->hdr.nr_options = 0;
+	c->reg = d->reg; /* this also copies the mem_id */
+	/* put the new port in an un-registered, unmapped state */
+	c->fd = -1;
+	c->nifp = NULL;
+	c->register_done = 0;
+	c->mem = NULL;
+	c->extmem = NULL;
+	c->extmem_autounmap = 0;
+	c->mmap_done = 0;
+	c->first_tx_ring = 0;
+	c->last_tx_ring = 0;
+	c->first_rx_ring = 0;
+	c->last_rx_ring = 0;
+	c->cur_tx_ring = 0;
+	c->cur_rx_ring = 0;
+
+	return c;
+}
+
+int
+nmport_inject(struct nmport_d *d, const void *buf, size_t size)
+{
+	u_int c, n = d->last_tx_ring - d->first_tx_ring + 1,
+		ri = d->cur_tx_ring;
+
+	for (c = 0; c < n ; c++, ri++) {
+		/* compute current ring to use */
+		struct netmap_ring *ring;
+		uint32_t i, j, idx;
+		size_t rem;
+
+		if (ri > d->last_tx_ring)
+			ri = d->first_tx_ring;
+		ring = NETMAP_TXRING(d->nifp, ri);
+		rem = size;
+		j = ring->cur;
+		while (rem > ring->nr_buf_size && j != ring->tail) {
+			rem -= ring->nr_buf_size;
+			j = nm_ring_next(ring, j);
+		}
+		if (j == ring->tail && rem > 0)
+			continue;
+		i = ring->cur;
+		while (i != j) {
+			idx = ring->slot[i].buf_idx;
+			ring->slot[i].len = ring->nr_buf_size;
+			ring->slot[i].flags = NS_MOREFRAG;
+			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
+			i = nm_ring_next(ring, i);
+			buf = (char *)buf + ring->nr_buf_size;
+		}
+		idx = ring->slot[i].buf_idx;
+		ring->slot[i].len = rem;
+		ring->slot[i].flags = 0;
+		nm_pkt_copy(buf, NETMAP_BUF(ring, idx), rem);
+		ring->head = ring->cur = nm_ring_next(ring, i);
+		d->cur_tx_ring = ri;
+		return size;
+	}
+	return 0; /* fail */
+}
+
+static void __attribute__((constructor)) nmport_init(void)
+{
+	extern struct nmreq_opt_parser npopts_start, npopts_end;
+	extern struct nmport_key_desc npkeys_start, npkeys_end;
+	struct nmport_key_desc *k;
+
+	nmport_opt_parsers = &npopts_start;
+	nmport_opt_parsers_n = &npopts_end - &npopts_start;
+	for (k = &npkeys_start; k != &npkeys_end; k++) {
+		struct nmreq_opt_parser *o = k->option;
+		struct nmreq_opt_key *ok;
+		int id = o->nr_keys;
+		//printf("key %s of option %s id %d\n", k->key, o->prefix, id);
+		*k->id = id;
+		ok = &o->keys[id];
+		ok->key = k->key;
+		ok->id = id;
+		ok->flags = k->flags;
+		o->nr_keys++;
+	}
+}
diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
new file mode 100644
index 000000000..aa09209ca
--- /dev/null
+++ b/libnetmap/nmreq.c
@@ -0,0 +1,667 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+//#define NMREQ_DEBUG
+#ifdef NMREQ_DEBUG
+#define NETMAP_WITH_LIBS
+#define ED(...)	D(__VA_ARGS__)
+#else
+#define ED(...)
+/* an identifier is a possibly empty sequence of alphanum characters and
+ * underscores
+ */
+static int
+nm_is_identifier(const char *s, const char *e)
+{
+	for (; s != e; s++) {
+		if (!isalnum(*s) && *s != '_') {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+#endif /* NMREQ_DEBUG */
+
+#include 
+#define LIBNETMAP_NOTHREADSAFE
+#include "libnetmap.h"
+
+void
+nmreq_push_option(struct nmreq_header *h, struct nmreq_option *o)
+{
+	o->nro_next = h->nr_options;
+	h->nr_options = (uintptr_t)o;
+}
+
+struct nmreq_prefix {
+	const char *prefix;		/* the constant part of the prefix */
+	size_t	    len;		/* its strlen() */
+	uint32_t    flags;
+#define	NR_P_ID		(1U << 0)	/* whether an identifier is needed */
+#define NR_P_SKIP	(1U << 1)	/* whether the scope must be passed to netmap */
+#define NR_P_EMPTYID	(1U << 2)	/* whether an empty identifier is allowed */
+};
+
+#define declprefix(prefix, flags)	{ (prefix), (sizeof(prefix) - 1), (flags) }
+
+static struct nmreq_prefix nmreq_prefixes[] = {
+	declprefix("netmap", NR_P_SKIP),
+	declprefix(NM_BDG_NAME,	NR_P_ID|NR_P_EMPTYID),
+	{ NULL } /* terminate the list */
+};
+
+void
+nmreq_header_init(struct nmreq_header *h, uint16_t reqtype, void *body)
+{
+	memset(h, 0, sizeof(*h));
+	h->nr_version = NETMAP_API;
+	h->nr_reqtype = reqtype;
+	h->nr_body = (uintptr_t)body;
+}
+
+int
+nmreq_header_decode(const char **pifname, struct nmreq_header *h, struct nmctx *ctx)
+{
+	const char *scan = NULL;
+	const char *vpname = NULL;
+	const char *pipesep = NULL;
+	u_int namelen;
+	const char *ifname = *pifname;
+	struct nmreq_prefix *p;
+
+	scan = ifname;
+	for (p = nmreq_prefixes; p->prefix != NULL; p++) {
+		if (!strncmp(scan, p->prefix, p->len))
+			break;
+	}
+	if (p->prefix == NULL) {
+		nmctx_ferror(ctx, "%s: invalid request, prefix unknown or missing", *pifname);
+		goto fail;
+	}
+	scan += p->len;
+
+	vpname = index(scan, ':');
+	if (vpname == NULL) {
+		nmctx_ferror(ctx, "%s: missing ':'", ifname);
+		goto fail;
+	}
+	if (vpname != scan) {
+		/* there is an identifier, can we accept it? */
+		if (!(p->flags & NR_P_ID)) {
+			nmctx_ferror(ctx, "%s: no identifier allowed between '%s' and ':'", *pifname, p->prefix);
+			goto fail;
+		}
+
+		if (!nm_is_identifier(scan, vpname)) {
+			nmctx_ferror(ctx, "%s: invalid identifier '%.*s'", *pifname, vpname - scan, scan);
+			goto fail;
+		}
+	} else {
+		if ((p->flags & NR_P_ID) && !(p->flags & NR_P_EMPTYID)) {
+			nmctx_ferror(ctx, "%s: identifier is missing between '%s' and ':'", *pifname, p->prefix);
+			goto fail;
+		}
+	}
+	++vpname; /* skip the colon */
+	if (p->flags & NR_P_SKIP)
+		ifname = vpname;
+	scan = vpname;
+
+	/* scan for a separator */
+	for (; *scan && !index("-*^/@", *scan); scan++)
+		;
+
+	/* search for possible pipe indicators */
+	for (pipesep = vpname; pipesep != scan && !index("{}", *pipesep); pipesep++)
+		;
+
+	if (!nm_is_identifier(vpname, pipesep)) {
+		nmctx_ferror(ctx, "%s: invalid port name '%.*s'", *pifname,
+				pipesep - vpname, vpname);
+		goto fail;
+	}
+	if (pipesep != scan) {
+		pipesep++;
+		if (*pipesep == '\0') {
+			nmctx_ferror(ctx, "%s: invalid empty pipe name", *pifname);
+			goto fail;
+		}
+		if (!nm_is_identifier(pipesep, scan)) {
+			nmctx_ferror(ctx, "%s: invalid pipe name '%.*s'", *pifname, scan - pipesep, pipesep);
+			goto fail;
+		}
+	}
+
+	namelen = scan - ifname;
+	if (namelen >= sizeof(h->nr_name)) {
+		nmctx_ferror(ctx, "name '%.*s' too long", namelen, ifname);
+		goto fail;
+	}
+	if (namelen == 0) {
+		nmctx_ferror(ctx, "%s: invalid empty port name", *pifname);
+		goto fail;
+	}
+
+	/* fill the header */
+	memcpy(h->nr_name, ifname, namelen);
+	h->nr_name[namelen] = '\0';
+	ED("name %s", h->nr_name);
+
+	*pifname = scan;
+
+	return 0;
+fail:
+	errno = EINVAL;
+	return -1;
+}
+
+
+/*
+ * 0 not recognized
+ * -1 error
+ *  >= 0 mem_id
+ */
+int32_t
+nmreq_get_mem_id(const char **pifname, struct nmctx *ctx)
+{
+	int fd = -1;
+	struct nmreq_header gh;
+	struct nmreq_port_info_get gb;
+	const char *ifname;
+
+	errno = 0;
+	ifname = *pifname;
+
+	if (ifname == NULL)
+		goto fail;
+
+	/* try to look for a netmap port with this name */
+	fd = open("/dev/netmap", O_RDWR);
+	if (fd < 0) {
+		nmctx_ferror(ctx, "cannot open /dev/netmap: %s", strerror(errno));
+		goto fail;
+	}
+	nmreq_header_init(&gh, NETMAP_REQ_PORT_INFO_GET, &gb);
+	if (nmreq_header_decode(&ifname, &gh, ctx) < 0) {
+		goto fail;
+	}
+	memset(&gb, 0, sizeof(gb));
+	if (ioctl(fd, NIOCCTRL, &gh) < 0) {
+		nmctx_ferror(ctx, "cannot get info for '%s': %s", *pifname, strerror(errno));
+		goto fail;
+	}
+	*pifname = ifname;
+	close(fd);
+	return gb.nr_mem_id;
+
+fail:
+	if (fd >= 0)
+		close(fd);
+	if (!errno)
+		errno = EINVAL;
+	return -1;
+}
+
+
+int
+nmreq_register_decode(const char **pifname, struct nmreq_register *r, struct nmctx *ctx)
+{
+	enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK, P_MEMID, P_ONESW } p_state;
+	long num;
+	const char *scan = *pifname;
+	uint32_t nr_mode;
+	uint16_t nr_mem_id;
+	uint16_t nr_ringid;
+	uint64_t nr_flags;
+
+	/* fill the request */
+
+	p_state = P_START;
+	/* defaults */
+	nr_mode = NR_REG_ALL_NIC; /* default for no suffix */
+	nr_mem_id = r->nr_mem_id; /* if non-zero, further updates are disabled */
+	nr_ringid = 0;
+	nr_flags = 0;
+	while (*scan) {
+		switch (p_state) {
+		case P_START:
+			switch (*scan) {
+			case '^': /* only SW ring */
+				nr_mode = NR_REG_SW;
+				p_state = P_ONESW;
+				break;
+			case '*': /* NIC and SW */
+				nr_mode = NR_REG_NIC_SW;
+				p_state = P_RNGSFXOK;
+				break;
+			case '-': /* one NIC ring pair */
+				nr_mode = NR_REG_ONE_NIC;
+				p_state = P_GETNUM;
+				break;
+			case '/': /* start of flags */
+				p_state = P_FLAGS;
+				break;
+			case '@': /* start of memid */
+				p_state = P_MEMID;
+				break;
+			default:
+				nmctx_ferror(ctx, "unknown modifier: '%c'", *scan);
+				goto fail;
+			}
+			scan++;
+			break;
+		case P_RNGSFXOK:
+			switch (*scan) {
+			case '/':
+				p_state = P_FLAGS;
+				break;
+			case '@':
+				p_state = P_MEMID;
+				break;
+			default:
+				nmctx_ferror(ctx, "unexpected character: '%c'", *scan);
+				goto fail;
+			}
+			scan++;
+			break;
+		case P_GETNUM:
+			if (!isdigit(*scan)) {
+				nmctx_ferror(ctx, "got '%s' while expecting a number", scan);
+				goto fail;
+			}
+			num = strtol(scan, (char **)&scan, 10);
+			if (num < 0 || num >= NETMAP_RING_MASK) {
+				nmctx_ferror(ctx, "'%ld' out of range [0, %d)",
+						num, NETMAP_RING_MASK);
+				goto fail;
+			}
+			nr_ringid = num & NETMAP_RING_MASK;
+			p_state = P_RNGSFXOK;
+			break;
+		case P_FLAGS:
+		case P_FLAGSOK:
+			switch (*scan) {
+			case '@':
+				p_state = P_MEMID;
+				scan++;
+				continue;
+			case 'x':
+				nr_flags |= NR_EXCLUSIVE;
+				break;
+			case 'z':
+				nr_flags |= NR_ZCOPY_MON;
+				break;
+			case 't':
+				nr_flags |= NR_MONITOR_TX;
+				break;
+			case 'r':
+				nr_flags |= NR_MONITOR_RX;
+				break;
+			case 'R':
+				nr_flags |= NR_RX_RINGS_ONLY;
+				break;
+			case 'T':
+				nr_flags |= NR_TX_RINGS_ONLY;
+				break;
+			default:
+				nmctx_ferror(ctx, "unrecognized flag: '%c'", *scan);
+				goto fail;
+			}
+			scan++;
+			p_state = P_FLAGSOK;
+			break;
+		case P_MEMID:
+			if (!isdigit(*scan)) {
+				scan--;	/* escape to options */
+				goto out;
+			}
+			num = strtol(scan, (char **)&scan, 10);
+			if (num <= 0) {
+				nmctx_ferror(ctx, "invalid mem_id: '%ld'", num);
+				goto fail;
+			}
+			if (nr_mem_id && nr_mem_id != num) {
+				nmctx_ferror(ctx, "invalid setting of mem_id to %ld (already set to %"PRIu16")", num, nr_mem_id);
+				goto fail;
+			}
+			nr_mem_id = num;
+			p_state = P_RNGSFXOK;
+			break;
+		case P_ONESW:
+			if (!isdigit(*scan)) {
+				p_state = P_RNGSFXOK;
+			} else {
+				nr_mode = NR_REG_ONE_SW;
+				p_state = P_GETNUM;
+			}
+			break;
+		}
+	}
+	if (p_state == P_MEMID && !*scan) {
+		nmctx_ferror(ctx, "invalid empty mem_id");
+		goto fail;
+	}
+	if (p_state != P_START && p_state != P_RNGSFXOK &&
+	    p_state != P_FLAGSOK && p_state != P_MEMID && p_state != P_ONESW) {
+		nmctx_ferror(ctx, "unexpected end of request");
+		goto fail;
+	}
+out:
+	ED("flags: %s %s %s %s %s %s",
+			(nr_flags & NR_EXCLUSIVE) ? "EXCLUSIVE" : "",
+			(nr_flags & NR_ZCOPY_MON) ? "ZCOPY_MON" : "",
+			(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
+			(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "",
+			(nr_flags & NR_RX_RINGS_ONLY) ? "RX_RINGS_ONLY" : "",
+			(nr_flags & NR_TX_RINGS_ONLY) ? "TX_RINGS_ONLY" : "");
+	r->nr_mode = nr_mode;
+	r->nr_ringid = nr_ringid;
+	r->nr_flags = nr_flags;
+	r->nr_mem_id = nr_mem_id;
+	*pifname = scan;
+	return 0;
+
+fail:
+	if (!errno)
+		errno = EINVAL;
+	return -1;
+}
+
+
+static int
+nmreq_option_parsekeys(const char *prefix, char *body, struct nmreq_opt_parser *p,
+		struct nmreq_parse_ctx *pctx)
+{
+	char *scan;
+	char delim1;
+	struct nmreq_opt_key *k;
+
+	scan = body;
+	delim1 = *scan;
+	while (delim1 != '\0') {
+		char *key, *value;
+		char delim;
+		size_t vlen;
+
+		key = scan;
+		for ( scan++; *scan != '\0' && *scan != '=' && *scan != ','; scan++) {
+			if (*scan == '-')
+				*scan = '_';
+		}
+		delim = *scan;
+		*scan = '\0';
+		scan++;
+		for (k = p->keys; (k - p->keys) < NMREQ_OPT_MAXKEYS && k->key != NULL;
+				k++) {
+			if (!strcmp(k->key, key))
+				goto found;
+
+		}
+		nmctx_ferror(pctx->ctx, "unknown key: '%s'", key);
+		errno = EINVAL;
+		return -1;
+	found:
+		if (pctx->keys[k->id] != NULL) {
+			nmctx_ferror(pctx->ctx, "option '%s': duplicate key '%s', already set to '%s'",
+					prefix, key, pctx->keys[k->id]);
+			errno = EINVAL;
+			return -1;
+		}
+		value = scan;
+		for ( ; *scan != '\0' && *scan != ','; scan++)
+			;
+		delim1 = *scan;
+		*scan = '\0';
+		vlen = scan - value;
+		scan++;
+		if (delim == '=') {
+			pctx->keys[k->id] = (vlen ? value : NULL);
+		} else {
+			if (!(k->flags & NMREQ_OPTK_ALLOWEMPTY)) {
+				nmctx_ferror(pctx->ctx, "option '%s': missing '=value' for key '%s'",
+						prefix, key);
+				errno = EINVAL;
+				return -1;
+			}
+			pctx->keys[k->id] = key;
+		}
+	}
+	/* now check that all no-default keys have been assigned */
+	for (k = p->keys; (k - p->keys) < NMREQ_OPT_MAXKEYS && k->key != NULL; k++) {
+		if ((k->flags & NMREQ_OPTK_NODEFAULT) && pctx->keys[k->id] == NULL) {
+			nmctx_ferror(pctx->ctx, "option '%s': mandatory key '%s' not assigned",
+					prefix, k->key);
+			errno = EINVAL;
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+static int
+nmreq_option_decode1(char *opt, struct nmreq_opt_parser parsers[], int nparsers,
+		void *token, struct nmctx *ctx)
+{
+	struct nmreq_opt_parser *p;
+	const char *prefix;
+	char *scan;
+	char delim;
+	int i;
+	struct nmreq_parse_ctx pctx;
+
+	prefix = opt;
+	/* find the delimiter */
+	for (scan = opt; *scan != '\0' && *scan != ':' && *scan != '='; scan++)
+		;
+	delim = *scan;
+	*scan = '\0';
+	scan++;
+	/* find the prefix */
+	for (i = 0; i < nparsers; i++) {
+		if (!strcmp(prefix, parsers[i].prefix))
+			break;
+	}
+	if (i == nparsers) {
+		nmctx_ferror(ctx, "unknown option: '%s'", prefix);
+		errno = EINVAL;
+		return -1;
+	}
+	p = parsers + i; /* shortcut */
+	if (p->flags & NMREQ_OPTF_DISABLED) {
+		nmctx_ferror(ctx, "option '%s' is not supported", prefix);
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+	/* prepare the parse context */
+	pctx.ctx = ctx;
+	pctx.token = token;
+	for (i = 0; i < NMREQ_OPT_MAXKEYS; i++)
+		pctx.keys[i] = NULL;
+	switch (delim) {
+	case '\0':
+		/* no body */
+		if (!(p->flags & NMREQ_OPTF_ALLOWEMPTY)) {
+			nmctx_ferror(ctx, "syntax error: missing body after '%s'",
+					prefix);
+			errno = EINVAL;
+			return -1;
+		}
+		break;
+	case '=': /* the body goes to the default option key, if any */
+		if (p->default_key < 0 || p->default_key >= NMREQ_OPT_MAXKEYS) {
+			nmctx_ferror(ctx, "syntax error: '=' not valid after '%s'",
+					prefix);
+			errno = EINVAL;
+			return -1;
+		}
+		if (*scan == '\0') {
+			nmctx_ferror(ctx, "missing value for option '%s'", prefix);
+			errno = EINVAL;
+			return -1;
+		}
+		pctx.keys[p->default_key] = scan;
+		break;
+	case ':': /* parse 'key=value' strings */
+		if (nmreq_option_parsekeys(prefix, scan, p, &pctx) < 0)
+			return -1;
+		break;
+	}
+	return p->parse(&pctx);
+}
+
+int
+nmreq_options_decode(const char *opt, struct nmreq_opt_parser parsers[],
+		int nparsers, void *token, struct nmctx *ctx)
+{
+	const char *scan, *opt1;
+	char *w;
+	size_t len;
+	int ret;
+
+	if (*opt == '\0')
+		return 0; /* empty list, OK */
+
+	if (*opt != '@') {
+		nmctx_ferror(ctx, "option list does not start with '@'");
+		errno = EINVAL;
+		return -1;
+	}
+
+	scan = opt;
+	do {
+		scan++; /* skip the plus */
+		opt1 = scan; /* start of option */
+		/* find the end of the option */
+		for ( ; *scan != '\0' && *scan != '@'; scan++)
+			;
+		len = scan - opt1;
+		if (len == 0) {
+			nmctx_ferror(ctx, "invalid empty option");
+			errno = EINVAL;
+			return -1;
+		}
+		w = nmctx_malloc(ctx, len + 1);
+		if (w == NULL) {
+			nmctx_ferror(ctx, "out of memory");
+			errno = ENOMEM;
+			return -1;
+		}
+		memcpy(w, opt1, len);
+		w[len] = '\0';
+		ret = nmreq_option_decode1(w, parsers, nparsers, token, ctx);
+		nmctx_free(ctx, w);
+		if (ret < 0)
+			return -1;
+	} while (*scan != '\0');
+
+	return 0;
+}
+
+struct nmreq_option *
+nmreq_find_option(struct nmreq_header *h, uint32_t t)
+{
+	struct nmreq_option *o;
+
+	for (o = (struct nmreq_option *)h->nr_options; o != NULL;
+			o = (struct nmreq_option *)o->nro_next) {
+		if (o->nro_reqtype == t)
+			break;
+	}
+	return o;
+}
+
+void
+nmreq_remove_option(struct nmreq_header *h, struct nmreq_option *o)
+{
+	uintptr_t *scan;
+
+	for (scan = &h->nr_options; *scan;
+			scan = &((struct nmreq_option *)*scan)->nro_next) {
+		if (*scan == (uintptr_t)o) {
+			*scan = o->nro_next;
+			o->nro_next = 0;
+			break;
+		}
+	}
+}
+
+void
+nmreq_free_options(struct nmreq_header *h)
+{
+	struct nmreq_option *o, *next;
+
+	for (o = (struct nmreq_option *)h->nr_options; o != NULL; o = next) {
+		next = (struct nmreq_option *)o->nro_next;
+		free(o);
+	}
+}
+
+#if 0
+#include 
+static void
+nmreq_dump(struct nmport_d *d)
+{
+	printf("header:\n");
+	printf("   nr_version:  %"PRIu16"\n", d->hdr.nr_version);
+	printf("   nr_reqtype:  %"PRIu16"\n", d->hdr.nr_reqtype);
+	printf("   nr_reserved: %"PRIu32"\n", d->hdr.nr_reserved);
+	printf("   nr_name:     %s\n", d->hdr.nr_name);
+	printf("   nr_options:  %lx\n", (unsigned long)d->hdr.nr_options);
+	printf("   nr_body:     %lx\n", (unsigned long)d->hdr.nr_body);
+	printf("\n");
+	printf("register (%p):\n", (void *)d->hdr.nr_body);
+	printf("   nr_mem_id:   %"PRIu16"\n", d->reg.nr_mem_id);
+	printf("   nr_ringid:   %"PRIu16"\n", d->reg.nr_ringid);
+	printf("   nr_mode:     %lx\n", (unsigned long)d->reg.nr_mode);
+	printf("   nr_flags:    %lx\n", (unsigned long)d->reg.nr_flags);
+	printf("\n");
+	if (d->hdr.nr_options) {
+		struct nmreq_opt_extmem *e = (struct nmreq_opt_extmem *)d->hdr.nr_options;
+		printf("opt_extmem (%p):\n", e);
+		printf("   nro_opt.nro_next:    %lx\n", (unsigned long)e->nro_opt.nro_next);
+		printf("   nro_opt.nro_reqtype: %"PRIu32"\n", e->nro_opt.nro_reqtype);
+		printf("   nro_usrptr:          %lx\n", (unsigned long)e->nro_usrptr);
+		printf("   nro_info.nr_memsize  %"PRIu64"\n", e->nro_info.nr_memsize);
+	}
+	printf("\n");
+	printf("mem (%p):\n", d->mem);
+	printf("   refcount:   %d\n", d->mem->refcount);
+	printf("   mem:        %p\n", d->mem->mem);
+	printf("   size:       %zu\n", d->mem->size);
+	printf("\n");
+	printf("rings:\n");
+	printf("   tx:   [%d, %d]\n", d->first_tx_ring, d->last_tx_ring);
+	printf("   rx:   [%d, %d]\n", d->first_rx_ring, d->last_rx_ring);
+}
+int
+main(int argc, char *argv[])
+{
+	struct nmport_d *d;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s netmap-expr\n", argv[0]);
+		return 1;
+	}
+
+	d = nmport_open(argv[1]);
+	if (d != NULL) {
+		nmreq_dump(d);
+		nmport_close(d);
+	}
+
+	return 0;
+}
+#endif
diff --git a/libnetmap/npopts.lds b/libnetmap/npopts.lds
new file mode 100644
index 000000000..7ad57a1f6
--- /dev/null
+++ b/libnetmap/npopts.lds
@@ -0,0 +1,13 @@
+SECTIONS
+{
+	.npopts ALIGN(16) : {
+		npopts_start = .;
+		*(.npopts)
+		npopts_end = .;
+	}
+	.npkeys ALIGN(16) : {
+		npkeys_start = .;
+		*(.npkeys)
+		npkeys_end = .;
+	}
+}
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 923437d50..0ed785158 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -93,6 +93,8 @@
 #include 		/* apple needs sockaddr */
 #include 		/* IFNAMSIZ */
 #include 
+#include 	/* memset */
+#include    /* gettimeofday */
 
 #ifndef likely
 #define likely(x)	__builtin_expect(!!(x), 1)
@@ -150,27 +152,6 @@ nm_ring_space(struct netmap_ring *ring)
         return ret;
 }
 
-
-#ifdef NETMAP_WITH_LIBS
-/*
- * Support for simple I/O libraries.
- * Include other system headers required for compiling this.
- */
-
-#ifndef HAVE_NETMAP_WITH_LIBS
-#define HAVE_NETMAP_WITH_LIBS
-
-#include 
-#include 
-#include 
-#include 	/* memset */
-#include 
-#include 	/* EINVAL */
-#include 	/* O_RDWR */
-#include 	/* close() */
-#include 
-#include 
-
 #ifndef ND /* debug macros */
 /* debug support */
 #define ND(_fmt, ...) do {} while(0)
@@ -199,6 +180,53 @@ nm_ring_space(struct netmap_ring *ring)
     } while (0)
 #endif
 
+/*
+ * this is a slightly optimized copy routine which rounds
+ * to multiple of 64 bytes and is often faster than dealing
+ * with other odd sizes. We assume there is enough room
+ * in the source and destination buffers.
+ */
+static inline void
+nm_pkt_copy(const void *_src, void *_dst, int l)
+{
+	const uint64_t *src = (const uint64_t *)_src;
+	uint64_t *dst = (uint64_t *)_dst;
+
+	if (unlikely(l >= 1024 || l % 64)) {
+		memcpy(dst, src, l);
+		return;
+	}
+	for (; likely(l > 0); l-=64) {
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+		*dst++ = *src++;
+	}
+}
+
+#ifdef NETMAP_WITH_LIBS
+/*
+ * Support for simple I/O libraries.
+ * Include other system headers required for compiling this.
+ */
+
+#ifndef HAVE_NETMAP_WITH_LIBS
+#define HAVE_NETMAP_WITH_LIBS
+
+#include 
+#include 
+#include 
+#include 
+#include 	/* EINVAL */
+#include 	/* O_RDWR */
+#include 	/* close() */
+#include 
+#include 
+
 struct nm_pkthdr {	/* first part is the same as pcap_pkthdr */
 	struct timeval	ts;
 	uint32_t	caplen;
@@ -269,33 +297,6 @@ struct nm_desc {
 #define NETMAP_FD(d)		(P2NMD(d)->fd)
 
 
-/*
- * this is a slightly optimized copy routine which rounds
- * to multiple of 64 bytes and is often faster than dealing
- * with other odd sizes. We assume there is enough room
- * in the source and destination buffers.
- */
-static inline void
-nm_pkt_copy(const void *_src, void *_dst, int l)
-{
-	const uint64_t *src = (const uint64_t *)_src;
-	uint64_t *dst = (uint64_t *)_dst;
-
-	if (unlikely(l >= 1024 || l % 64)) {
-		memcpy(dst, src, l);
-		return;
-	}
-	for (; likely(l > 0); l-=64) {
-		*dst++ = *src++;
-		*dst++ = *src++;
-		*dst++ = *src++;
-		*dst++ = *src++;
-		*dst++ = *src++;
-		*dst++ = *src++;
-		*dst++ = *src++;
-		*dst++ = *src++;
-	}
-}
 
 
 /*

From ba12ca6261f90b4f163ce026975c28ebc4234d75 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Feb 2019 14:58:12 +0100
Subject: [PATCH 1608/2207] ctrl-api-test: add libnetmap tests

---
 utils/GNUmakefile     |   4 +-
 utils/ctrl-api-test.c | 239 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 242 insertions(+), 1 deletion(-)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 68cc2b966..0e9bfa97e 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -14,6 +14,7 @@ NO_MAN=
 CFLAGS  = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys # -I/home/luigi/FreeBSD/head/sys -I../sys
+CFLAGS += -I $(SRCDIR)/libnetmap
 CFLAGS += -Wextra -g
 CFLAGS += $(SUBSYS_FLAGS)
 ifdef WITH_PCAP
@@ -23,7 +24,8 @@ else
 CFLAGS += -DNO_PCAP
 endif
 
-LDLIBS += -lpthread -lm
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+LDLIBS += -lnetmap -lpthread -lm
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt 	# on linux
 endif
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 37f5c230b..faeec2c90 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -47,6 +47,7 @@
 #include 
 #include 
 #include 
+#include "libnetmap.h"
 
 #ifdef __linux__
 #include 
@@ -152,6 +153,9 @@ struct TestContext {
 	void *csb;                    /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
 	sem_t *sem;	/* for thread synchronization */
+
+	struct nmctx *nmctx;
+	const char *ifparse;
 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
 };
 
@@ -1666,6 +1670,240 @@ null_port_sync(struct TestContext *ctx)
 	return 0;
 }
 
+struct nmreq_parse_test {
+	const char *ifname;
+	const char *exp_port;
+	const char *exp_suff;
+	int exp_error;
+	uint32_t exp_mode;
+	uint16_t exp_ringid;
+	uint64_t exp_flags;
+};
+
+static struct nmreq_parse_test nmreq_parse_tests[] = {
+	/* port spec is the input. The expected results are as follows:
+	 * - port: what should go into hdr.nr_name
+	 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
+	 * - err: the expected return value, interpreted as follows
+	 *       err > 0 => nmreq_header_parse should fail with the given error
+	 *       err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
+	 *       		   fail with error |err|
+	 *       err = 0 => should succeeed
+	 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
+	 *   	nmreq_register struct in case of success
+	 */
+
+	/*port spec*/			/*port*/	/*suff*/    /*err*/	/*mode*/    /*ringid*/ /*flags*/
+	{ "netmap:eth0",		"eth0",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
+	{ "netmap:eth0-1",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 1,	0 },
+	{ "netmap:eth0-",		"eth0",		"-",		-EINVAL,0,		0,	0 },
+	{ "netmap:eth0/x",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_EXCLUSIVE },
+	{ "netmap:eth0/z",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_ZCOPY_MON },
+	{ "netmap:eth0/r",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_RX },
+	{ "netmap:eth0/t",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_TX },
+	{ "netmap:eth0-2/Tx",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 2,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
+	{ "netmap:eth0*",		"eth0",		"",		0, 	NR_REG_NIC_SW,  0,	0 },
+	{ "netmap:eth0^",		"eth0",		"",		0, 	NR_REG_SW,	0,	0 },
+	{ "netmap:eth0@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:eth0@2/R",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
+	{ "netmap:eth0@netmap:lo/R",	"eth0",	        "@netmap:lo/R",	0,	NR_REG_ALL_NIC,	0,	0 },
+	{ "netmap:eth0/R@xxx",		"eth0",	        "@xxx",		0,	NR_REG_ALL_NIC,	0,	NR_RX_RINGS_ONLY },
+	{ "netmap:eth0@2/R@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
+	{ "netmap:eth0@2/R@3",		"eth0",	        "@2/R@3",	-EINVAL,0,		0,	0 },
+	{ "netmap:eth0@",		"eth0",	        "@",		-EINVAL,0,		0,	0 },
+	{ "netmap:",			"",		NULL,		EINVAL, 0,		0,	0 },
+	{ "netmap:^",			"",		NULL,		EINVAL,	0,		0,	0 },
+	{ "netmap:{",			"",		NULL,		EINVAL,	0,		0,	0 },
+	{ "netmap:vale0:0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
+	{ "eth0",			NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ "vale0:0",			"vale0:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "vale:0",			"vale:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "valeXXX:YYY",		"valeXXX:YYY",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "valeXXX:YYY-4",		"valeXXX:YYY",	"",		0,	NR_REG_ONE_NIC, 4,	0 },
+	{ "netmapXXX:eth0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
+	{ "netmap:14",			"14",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
+	{ "netmap:eth0&",		NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ "netmap:pipe{0",		"pipe{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:pipe{in",		"pipe{in",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:pipe{in-7",		"pipe{in",	"",		0,	NR_REG_ONE_NIC, 7,	0 },
+	{ "vale0:0{0",			"vale0:0{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:pipe{1}2",		NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ "vale0:0@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "vale0:0/Tx@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
+	{ "vale0:0-3@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ONE_NIC, 3,	0 },
+	{ "vale0:0@", 			"vale0:0",	"@",		-EINVAL,0,	        0,	0 },
+	{ "",				NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ NULL,				NULL,		NULL,		0, 	0,		0,	0 },
+};
+
+static void
+randomize(void *dst, size_t n)
+{
+	size_t i;
+	char *dst_ = dst;
+
+	for (i = 0; i < n; i++)
+		dst_[i] = (char)random();
+}
+
+static int
+nmreq_hdr_parsing(struct TestContext *ctx,
+		struct nmreq_parse_test *t,
+		struct nmreq_header *hdr)
+{
+	const char *save;
+	struct nmreq_header orig_hdr;
+
+	save = ctx->ifparse = t->ifname;
+	orig_hdr = *hdr;
+
+	printf("nmreq_header: \"%s\"\n", ctx->ifparse);
+	if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
+		if (t->exp_error > 0) {
+			if (errno != t->exp_error) {
+				printf("!!! got errno=%d, want %d\n",
+						errno, t->exp_error);
+				return -1;
+			}
+			if (ctx->ifparse != save) {
+				printf("!!! parse error, but first arg changed\n");
+				return -1;
+			}
+			if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
+				printf("!!! parse error, but header changed\n");
+				return -1;
+			}
+			return 0;
+		}
+		printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
+		return -1;
+	}
+	if (t->exp_error > 0) {
+		printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
+		return -1;
+	}
+	if (strcmp(t->exp_port, hdr->nr_name) != 0) {
+		printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
+		return -1;
+	}
+	if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
+	    hdr->nr_options != orig_hdr.nr_options ||
+	    hdr->nr_body    != orig_hdr.nr_body) {
+		printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+nmreq_reg_parsing(struct TestContext *ctx,
+		struct nmreq_parse_test *t,
+		struct nmreq_register *reg)
+{
+	const char *save;
+	struct nmreq_register orig_reg;
+
+
+	save = ctx->ifparse;
+	orig_reg = *reg;
+
+	printf("nmreq_register: \"%s\"\n", ctx->ifparse);
+	if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
+		if (t->exp_error < 0) {
+			if (errno != -t->exp_error) {
+				printf("!!! got errno=%d, want %d\n",
+						errno, -t->exp_error);
+				return -1;
+			}
+			if (ctx->ifparse != save) {
+				printf("!!! parse error, but first arg changed\n");
+				return -1;
+			}
+			if (memcmp(&orig_reg, reg, sizeof(*reg))) {
+				printf("!!! parse error, but nmreq_register changed\n");
+				return -1;
+			}
+			return 0;
+		}
+		printf ("!!! parse failed but it should have succeded\n");
+		return -1;
+	}
+	if (t->exp_error < 0) {
+		printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
+		return -1;
+	}
+	if (reg->nr_mode != t->exp_mode) {
+		printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
+		return -1;
+	}
+	if (reg->nr_ringid != t->exp_ringid) {
+		printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
+		return -1;
+	}
+	if (reg->nr_flags != t->exp_flags) {
+		printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
+				(unsigned long long)t->exp_flags);
+		return -1;
+	}
+	if (reg->nr_offset     != orig_reg.nr_offset     ||
+	    reg->nr_memsize    != orig_reg.nr_memsize    ||
+	    reg->nr_tx_slots   != orig_reg.nr_tx_slots   ||
+	    reg->nr_rx_slots   != orig_reg.nr_rx_slots   ||
+	    reg->nr_tx_rings   != orig_reg.nr_tx_rings   ||
+	    reg->nr_rx_rings   != orig_reg.nr_rx_rings   ||
+	    reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
+	{
+		printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
+		return -1;
+	}
+	return 0;
+}
+
+static void
+nmctx_parsing_error(struct nmctx *ctx, const char *msg)
+{
+	(void)ctx;
+	printf("    got message: %s\n", msg);
+}
+
+static int
+nmreq_parsing(struct TestContext *ctx)
+{
+	struct nmreq_parse_test *t;
+	struct nmreq_header hdr;
+	struct nmreq_register reg;
+	struct nmctx test_nmctx, *nmctx;
+	int ret = 0;
+
+	nmctx = nmctx_get();
+	if (nmctx == NULL) {
+		printf("Failed to aquire nmctx: %s", strerror(errno));
+		return -1;
+	}
+	test_nmctx = *nmctx;
+	test_nmctx.error = nmctx_parsing_error;
+	ctx->nmctx = &test_nmctx;
+	for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
+		const char *exp_suff = t->exp_suff != NULL ?
+			t->exp_suff : t->ifname;
+
+		randomize(&hdr, sizeof(hdr));
+		randomize(®, sizeof(reg));
+		reg.nr_mem_id = 0;
+		if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
+			ret = -1;
+		} else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, ®) < 0) {
+			ret = -1;
+		}
+		if (strcmp(ctx->ifparse, exp_suff) != 0) {
+			printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
+					ctx->ifparse, exp_suff);
+			ret = -1;
+		}
+	}
+	return ret;
+}
+
 static void
 usage(const char *prog)
 {
@@ -1732,6 +1970,7 @@ static struct mytest tests[] = {
 	decltest(legacy_regif_extra_bufs),
 	decltest(legacy_regif_extra_bufs_pipe),
 	decltest(legacy_regif_extra_bufs_pipe_vale),
+	decltest(nmreq_parsing),
 };
 
 static void

From 8caa1bbf2af51043041876beedba6303a5da5d63 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Feb 2019 23:12:07 +0100
Subject: [PATCH 1609/2207] testmmap: add commands for multiple host-rings

---
 utils/testmmap.c | 70 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 55 insertions(+), 15 deletions(-)

diff --git a/utils/testmmap.c b/utils/testmmap.c
index a37a39bcb..023f2f3cb 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -600,12 +600,14 @@ do_if()
 		printf(" ]");
 	}
 	printf("\n");
-	printf("tx_rings   %u\n", nifp->ni_tx_rings);
-	printf("rx_rings   %u\n", nifp->ni_rx_rings);
-	printf("bufs_head  %u\n", nifp->ni_bufs_head);
+	printf("tx_rings        %u\n", nifp->ni_tx_rings);
+	printf("rx_rings        %u\n", nifp->ni_rx_rings);
+	printf("bufs_head       %u\n", nifp->ni_bufs_head);
+	printf("host_tx_rings   %u\n", nifp->ni_host_tx_rings);
+	printf("host_rx_rings   %u\n", nifp->ni_host_rx_rings);
 	for (i = 0; i < 3; i++)
 		printf("spare1[%d]  %u\n", i, nifp->ni_spare1[i]);
-	for (i = 0; i < (nifp->ni_tx_rings + nifp->ni_rx_rings + 2); i++)
+	for (i = 0; i < (nifp->ni_tx_rings + nifp->ni_rx_rings + nifp->ni_host_tx_rings + nifp->ni_host_rx_rings); i++)
 		printf("ring_ofs[%d] %zd\n", i, nifp->ring_ofs[i]);
 }
 
@@ -1368,23 +1370,25 @@ nmr_body_dump_register(void *b)
 {
 	struct nmreq_register *r = b;
 	int flags		 = 0;
-	printf("offset:    %" PRIu64 "\n", r->nr_offset);
-	printf("memsize:   %" PRIu64 " [", r->nr_memsize);
+	printf("offset:         %" PRIu64 "\n", r->nr_offset);
+	printf("memsize:        %" PRIu64 " [", r->nr_memsize);
 	if (r->nr_memsize < (1 << 20)) {
 		printf("%" PRIu64 " KiB", r->nr_memsize >> 10);
 	} else {
 		printf("%" PRIu64 " MiB", r->nr_memsize >> 20);
 	}
 	printf("]\n");
-	printf("tx_slots:  %" PRIu16 "\n", r->nr_tx_slots);
-	printf("rx_slots:  %" PRIu16 "\n", r->nr_rx_slots);
-	printf("tx_rings:  %" PRIu16 "\n", r->nr_tx_rings);
-	printf("rx_rings:  %" PRIu16 "\n", r->nr_rx_rings);
-	printf("mem_id:    %" PRIu16 " [%s memory region]\n", r->nr_mem_id,
+	printf("tx_slots:       %" PRIu16 "\n", r->nr_tx_slots);
+	printf("rx_slots:       %" PRIu16 "\n", r->nr_rx_slots);
+	printf("tx_rings:       %" PRIu16 "\n", r->nr_tx_rings);
+	printf("rx_rings:       %" PRIu16 "\n", r->nr_rx_rings);
+	printf("host_tx_rings:  %" PRIu16 "\n", r->nr_host_tx_rings);
+	printf("host_rx_rings:  %" PRIu16 "\n", r->nr_host_rx_rings);
+	printf("mem_id:         %" PRIu16 " [%s memory region]\n", r->nr_mem_id,
 	       (r->nr_mem_id == 0 ? "default"
 				  : r->nr_mem_id == 1 ? "global" : "private"));
-	printf("ringid     %" PRIu16 "\n", r->nr_ringid);
-	printf("mode       %" PRIu32 " [", r->nr_mode);
+	printf("ringid          %" PRIu16 "\n", r->nr_ringid);
+	printf("mode            %" PRIu32 " [", r->nr_mode);
 	switch (r->nr_mode) {
 	case NR_REG_DEFAULT:
 		printf("*DEFAULT");
@@ -1410,6 +1414,9 @@ nmr_body_dump_register(void *b)
 	case NR_REG_NULL:
 		printf("NULL");
 		break;
+	case NR_REG_ONE_SW:
+		printf("ONE_SW(%d)", r->nr_ringid);
+		break;
 	default:
 		printf("???");
 		break;
@@ -1470,6 +1477,8 @@ do_register_mode()
 		curr_register.nr_mode = NR_REG_PIPE_SLAVE;
 	} else if (strcmp(mode, "null") == 0) {
 		curr_register.nr_mode = NR_REG_NULL;
+	} else if (strcmp(mode, "one-sw") == 0) {
+		curr_register.nr_mode = NR_REG_ONE_SW;
 	}
 
 out:
@@ -1549,6 +1558,7 @@ do_register()
 	if (register_update(offset) || register_update(memsize) ||
 	    register_update(tx_slots) || register_update(rx_slots) ||
 	    register_update(tx_rings) || register_update(rx_rings) ||
+	    register_update(host_tx_rings) || register_update(host_rx_rings) ||
 	    register_update(mem_id) || register_update(ringid) ||
 	    register_update(mode) || register_update(flags) ||
 	    register_update(extra_bufs))
@@ -1559,7 +1569,27 @@ do_register()
 static void
 nmr_body_dump_port_info_get(void *b)
 {
-	(void)b;
+	struct nmreq_port_info_get *r = b;
+	int i;
+
+	printf("memsize:        %" PRIu64 " [", r->nr_memsize);
+	if (r->nr_memsize < (1 << 20)) {
+		printf("%" PRIu64 " KiB", r->nr_memsize >> 10);
+	} else {
+		printf("%" PRIu64 " MiB", r->nr_memsize >> 20);
+	}
+	printf("]\n");
+	printf("tx_slots:       %" PRIu16 "\n", r->nr_tx_slots);
+	printf("rx_slots:       %" PRIu16 "\n", r->nr_rx_slots);
+	printf("tx_rings:       %" PRIu16 "\n", r->nr_tx_rings);
+	printf("rx_rings:       %" PRIu16 "\n", r->nr_rx_rings);
+	printf("host_tx_rings:  %" PRIu16 "\n", r->nr_host_tx_rings);
+	printf("host_rx_rings:  %" PRIu16 "\n", r->nr_host_rx_rings);
+	printf("mem_id:         %" PRIu16 " [%s memory region]\n", r->nr_mem_id,
+	       (r->nr_mem_id == 0 ? "default"
+				  : r->nr_mem_id == 1 ? "global" : "private"));
+	for (i = 0; i < 3; i++)
+		printf("pad[%d]         %" PRIu16 "\n", i, r->pad[i]);
 }
 
 static void
@@ -1871,9 +1901,19 @@ do_ctrl()
 		fd = last_fd;
 		goto doit;
 	}
-	fd = atoi(arg);
+	last_fd = fd = atoi(arg);
 doit:
 	ret = ioctl(fd, NIOCCTRL, &curr_hdr);
+	switch (curr_hdr.nr_reqtype) {
+	case NETMAP_REQ_REGISTER:
+		last_memsize = curr_register.nr_memsize;
+		break;
+	case NETMAP_REQ_PORT_INFO_GET:
+		last_memsize = curr_port_info_get.nr_memsize;
+		break;
+	default:
+		break;
+	}
 	output_err(ret, "ioctl(%d, NIOCCTL, %p)=%d", fd, &curr_hdr, ret);
 }
 

From a2b56f416cb1eff3f00a43fa2b44b2f03ffdf87c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Feb 2019 17:11:53 +0100
Subject: [PATCH 1610/2207] count the host rings even when they are fake

For compatibility reasons, the netmap_if always contains the
ring pointers for the host rings, even for ports that do not
support them. The new exposed fields, nr_host_tx_rings and
nr_host_rx_rings should always account for these pointers,
or the new NETMAP_RXRING will not work.
---
 sys/dev/netmap/netmap_mem2.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 5cc8cbed5..3f056c2ad 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2012,8 +2012,10 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	/* initialize base fields -- override const */
 	*(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings;
 	*(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings;
-	*(u_int *)(uintptr_t)&nifp->ni_host_tx_rings = na->num_host_tx_rings;
-	*(u_int *)(uintptr_t)&nifp->ni_host_rx_rings = na->num_host_rx_rings;
+	*(u_int *)(uintptr_t)&nifp->ni_host_tx_rings =
+		(na->num_host_tx_rings ? na->num_host_tx_rings : 1);
+	*(u_int *)(uintptr_t)&nifp->ni_host_rx_rings =
+		(na->num_host_rx_rings ? na->num_host_rx_rings : 1);
 	strlcpy(nifp->ni_name, na->name, sizeof(nifp->ni_name));
 
 	/*

From 2bf333c4cec6f52fb2dc205cb9338ac6d419d620 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Feb 2019 18:28:32 +0100
Subject: [PATCH 1611/2207] update documentation

---
 libnetmap/libnetmap.h | 10 +++++++---
 sys/net/netmap.h      |  3 ++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 39ad9c0dc..13d11854a 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -72,7 +72,8 @@ struct nmem_d;
  *
  * The "mode" can be one of the following:
  *
- *	^		bind the host (sw) ring pair
+ *	^		bind all host (sw) ring pairs
+ *	^NN		bind individual host ring pair
  *	*		bind host and NIC ring pairs
  *	-NN		bind individual NIC ring pair
  *	@NN		open the port in the NN memory region
@@ -119,13 +120,16 @@ struct nmem_d;
  *  		       *rings		number of tx and rx rings
  *  			tx-rings	number of tx rings
  *  			rx-rings	number of rx rings
+ *			host-rings	number of tx and rx host rings
+ *  			host-tx-rings	number of host tx rings
+ *  			host-rx-rings	number of host rx rings
  *  			slots		number of slots in each tx and rx
  *  					ring
  *  			tx-slots	number of slots in each tx ring
  *  			rx-slots	numner of slots in each rx ring
  *
  *  			(more specific keys override the less specific ones)
- *			All keys default to zero not assigned, and the
+ *			All keys default to zero if not assigned, and the
  *			corresponding value will be chosen by netmap.
  *
  *  extmem (multi-key)
@@ -194,7 +198,7 @@ struct nmport_d {
  * The rings available for tx are in the [first_tx_ring, last_tx_ring]
  * interval, and similarly for rx. One or both intervals may be empty.
  *
- * When done using it, the nmport_d descriptor must free closed using
+ * When done using it, the nmport_d descriptor must be closed using
  * nmport_close().
  *
  * In case of error, NULL is returned, errno is set to some error, and an
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index e15d28a99..cb6845ff2 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -424,7 +424,8 @@ struct netmap_if {
  * The request body (struct nmreq_register) has several arguments to
  * specify how the port is to be registered.
  *
- *	nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
+ *	nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings,
+ *	nr_host_tx_rings, nr_host_rx_rings (in/out)
  *		On input, non-zero values may be used to reconfigure the port
  *		according to the requested values, but this is not guaranteed.
  *		On output the actual values in use are reported.

From 49efa4ee205d60df0b52beb09c9384f5a7f4df64 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 15 Feb 2019 17:37:18 +0100
Subject: [PATCH 1612/2207] linux: mlx5: fix typo

---
 LINUX/mlx5_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index f163e5352..2170068e9 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -107,7 +107,7 @@ int mlx5e_netmap_reg(struct netmap_adapter *na, int onoff) {
   int err = 0;
   int was_opened;
 
-  nm_printf("mlx5e switching %s native netmap mode", onoff ? "into" : "out of");
+  nm_prinf("mlx5e switching %s native netmap mode", onoff ? "into" : "out of");
 
   /* Should we check and wait for any reset in progress to complete? */
   mutex_lock(&adapter->state_lock);

From 3a9e3a6e31a2cf1d85d537e9e3227d823364033f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Feb 2019 15:54:08 +0100
Subject: [PATCH 1613/2207] linux/e1000e: patch for Intel 3.4.2.3 version

---
 LINUX/final-patches/intel--e1000e--3.4.2.3 | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.4.2.3

diff --git a/LINUX/final-patches/intel--e1000e--3.4.2.3 b/LINUX/final-patches/intel--e1000e--3.4.2.3
new file mode 100644
index 000000000..1bc4e7487
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.4.2.3
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index d285219..4e011bd 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -15,7 +15,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -118,7 +118,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -324,6 +324,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index 740b1f6..c3bf9da 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -483,6 +483,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1013,6 +1017,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1330,6 +1345,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4262,6 +4282,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8467,6 +8491,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8568,6 +8596,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From c76ab8c6857ba0756ba348de9302d25b11c9c9d1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Feb 2019 16:19:18 +0100
Subject: [PATCH 1614/2207] linux/ixgbevf: patch for Intel 4.5.2 version

---
 LINUX/final-patches/intel--ixgbevf--4.5.2 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.5.2

diff --git a/LINUX/final-patches/intel--ixgbevf--4.5.2 b/LINUX/final-patches/intel--ixgbevf--4.5.2
new file mode 100644
index 000000000..72e94aedf
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.5.2
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index b37fbce..f3cdb26 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -69,9 +69,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 05fb3b2..2c86986 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -358,6 +375,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif /* HAVE_XDP_BUFF_RXQ */
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		struct ixgbevf_rx_buffer *rx_buffer;
+ 		union ixgbe_adv_rx_desc *rx_desc;
+@@ -2053,6 +2091,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2287,6 +2329,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5570,8 +5616,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5612,6 +5660,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 55205fa..6c3a181 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From f608a5e9236fb276b06041212816994eec898dd6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Feb 2019 11:11:28 +0000
Subject: [PATCH 1615/2207] FreeBSD: provide defaults to build without
 configure

---
 libnetmap/GNUmakefile | 2 ++
 utils/GNUmakefile     | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/libnetmap/GNUmakefile b/libnetmap/GNUmakefile
index beb3d5e6e..9cfc45c1c 100644
--- a/libnetmap/GNUmakefile
+++ b/libnetmap/GNUmakefile
@@ -1,3 +1,5 @@
+SRCDIR ?= ../
+PREFIX ?= usr/local
 CFLAGS=-O2 -pipe -Wall -Werror
 CFLAGS=-g
 CFLAGS += -I $(SRCDIR)/sys
diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 0e9bfa97e..7f17ce8ae 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -8,6 +8,7 @@ LIBNETMAP =
 CLEANFILES = $(PROGS) $(X86PROGS) *.o
 
 SRCDIR ?= ..
+PREFIX ?= usr/local
 VPATH   = $(SRCDIR)/utils
 
 NO_MAN=
@@ -24,7 +25,11 @@ else
 CFLAGS += -DNO_PCAP
 endif
 
+ifdef BULDDIR
 LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+else
+LDFLAGS += -L $(SRCDIR)/libnetmap
+endif
 LDLIBS += -lnetmap -lpthread -lm
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt 	# on linux

From a258e21ef6de708316e5410e776e26c9f052184c Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 18 Feb 2019 15:22:44 +0100
Subject: [PATCH 1616/2207] freebsd: don't schedule kqueue notify task when
 kqueue is not used

This change adds a counter (kqueue_users) to keep track of how many
kqueue users are referencing a given struct nm_selinfo.
In this way, nm_os_selwakeup() can schedule the kevent notification
task only when kqueue is actually being used.
This is important to avoid wasting CPU in the common case where
kqueue is not used.

Reviewed by:    Aleksandr Fedorov 
MFC after:      1 week
Differential Revision:  https://reviews.freebsd.org/D19177
---
 sys/dev/netmap/netmap_freebsd.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index b71210f8d..33925c7d4 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -105,6 +105,7 @@ int nm_os_selinfo_init(NM_SELINFO_T *si, const char *name) {
 	snprintf(si->mtxname, sizeof(si->mtxname), "nmkl%s", name);
 	mtx_init(&si->m, si->mtxname, NULL, MTX_DEF);
 	knlist_init_mtx(&si->si.si_note, &si->m);
+	si->kqueue_users = 0;
 
 	return (0);
 }
@@ -1351,7 +1352,9 @@ void
 nm_os_selwakeup(struct nm_selinfo *si)
 {
 	selwakeuppri(&si->si, PI_NET);
-	taskqueue_enqueue(si->ntfytq, &si->ntfytask);
+	if (si->kqueue_users > 0) {
+		taskqueue_enqueue(si->ntfytq, &si->ntfytask);
+	}
 }
 
 void
@@ -1364,20 +1367,28 @@ static void
 netmap_knrdetach(struct knote *kn)
 {
 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
-	struct selinfo *si = &priv->np_si[NR_RX]->si;
+	struct nm_selinfo *si = priv->np_si[NR_RX];
 
-	nm_prinf("remove selinfo %p", si);
-	knlist_remove(&si->si_note, kn, /*islocked=*/0);
+	knlist_remove(&si->si.si_note, kn, /*islocked=*/0);
+	NMG_LOCK();
+	KASSERT(si->kqueue_users > 0, ("kqueue_user underflow on %s",
+	    si->mtxname));
+	si->kqueue_users--;
+	nm_prinf("kqueue users for %s: %d", si->mtxname, si->kqueue_users);
+	NMG_UNLOCK();
 }
 
 static void
 netmap_knwdetach(struct knote *kn)
 {
 	struct netmap_priv_d *priv = (struct netmap_priv_d *)kn->kn_hook;
-	struct selinfo *si = &priv->np_si[NR_TX]->si;
+	struct nm_selinfo *si = priv->np_si[NR_TX];
 
-	nm_prinf("remove selinfo %p", si);
-	knlist_remove(&si->si_note, kn, /*islocked=*/0);
+	knlist_remove(&si->si.si_note, kn, /*islocked=*/0);
+	NMG_LOCK();
+	si->kqueue_users--;
+	nm_prinf("kqueue users for %s: %d", si->mtxname, si->kqueue_users);
+	NMG_UNLOCK();
 }
 
 /*
@@ -1465,6 +1476,10 @@ netmap_kqfilter(struct cdev *dev, struct knote *kn)
 	kn->kn_fop = (ev == EVFILT_WRITE) ?
 		&netmap_wfiltops : &netmap_rfiltops;
 	kn->kn_hook = priv;
+	NMG_LOCK();
+	si->kqueue_users++;
+	nm_prinf("kqueue users for %s: %d", si->mtxname, si->kqueue_users);
+	NMG_UNLOCK();
 	knlist_add(&si->si.si_note, kn, /*islocked=*/0);
 
 	return 0;

From ffc591bc411fd385dc50f2f980ee68ed1bbb7a49 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 18 Feb 2019 15:29:05 +0100
Subject: [PATCH 1617/2207] freebsd: add missing field in struct nm_selinfo

---
 sys/dev/netmap/netmap_kern.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index bc267cec4..0e7a3b755 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -132,11 +132,14 @@ struct netmap_adapter *netmap_getna(if_t ifp);
 #define MBUF_QUEUED(m)		1
 
 struct nm_selinfo {
+	/* Support for select(2) and poll(2). */
 	struct selinfo si;
+	/* Support for kqueue(9). See comments in netmap_freebsd.c */
 	struct taskqueue *ntfytq;
 	struct task ntfytask;
 	struct mtx m;
 	char mtxname[32];
+	int kqueue_users;
 };
 
 

From 8b3adfc90d3567830602e5df87f0f1d61f0cbf92 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 18 Feb 2019 15:57:16 +0100
Subject: [PATCH 1618/2207] linux: fix compilation issue in r8169

---
 LINUX/if_re_netmap_linux.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_re_netmap_linux.h b/LINUX/if_re_netmap_linux.h
index 30bc73f59..ff7cc0c6b 100644
--- a/LINUX/if_re_netmap_linux.h
+++ b/LINUX/if_re_netmap_linux.h
@@ -284,7 +284,7 @@ re_netmap_tx_init(struct SOFTC_T *sc)
 
 	/* l points in the netmap ring, i points in the NIC ring */
 	for (i = 0; i < na->num_tx_desc; i++) {
-		l = netmap_idx_n2k(&na->tx_rings[0], i);
+		l = netmap_idx_n2k(na->tx_rings[0], i);
 		PNMB(na, slot + l, &paddr);
 		desc[i].addr = htole64(paddr);
 	}
@@ -312,7 +312,7 @@ re_netmap_rx_init(struct SOFTC_T *sc)
 	 */
 	lim = na->num_rx_desc /* - 1 */ - nm_kr_rxspace(&na->rx_rings[0]);
 	for (i = 0; i < na->num_rx_desc; i++) {
-		l = netmap_idx_n2k(&na->rx_rings[0], i);
+		l = netmap_idx_n2k(na->rx_rings[0], i);
 		PNMB(na, slot + l, &paddr);
 		cmdstat = NETMAP_BUF_SIZE(na);
 		if (i == na->num_rx_desc - 1)

From c6a7e03f6107047fa8776210aab59d912e4c6a7d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 18 Feb 2019 16:09:32 +0100
Subject: [PATCH 1619/2207] utils: GNUMakefile: fix typo

---
 utils/GNUmakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index 7f17ce8ae..c9653372d 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -25,7 +25,7 @@ else
 CFLAGS += -DNO_PCAP
 endif
 
-ifdef BULDDIR
+ifdef BUILDDIR
 LDFLAGS += -L $(BUILDDIR)/build-libnetmap
 else
 LDFLAGS += -L $(SRCDIR)/libnetmap

From dc36365a569035acc1a60a9538482b4f58f537e6 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 18 Feb 2019 16:30:25 +0100
Subject: [PATCH 1620/2207] travis: switch to xenial

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index ec81d67de..cc5e15c28 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
-dist: trusty
+dist: xenial
 sudo: required
 language: c
 env:

From 93e24db72036b46c28bb606e3d2e59900c8e1e8d Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Feb 2019 09:48:28 +0100
Subject: [PATCH 1621/2207] small fixes to the python bindings

---
 extra/python/netmap_interface.c | 28 +++++++++++-----------------
 extra/python/netmap_ring.c      |  8 ++++----
 2 files changed, 15 insertions(+), 21 deletions(-)

diff --git a/extra/python/netmap_interface.c b/extra/python/netmap_interface.c
index 22650000e..2844bb0be 100644
--- a/extra/python/netmap_interface.c
+++ b/extra/python/netmap_interface.c
@@ -58,29 +58,23 @@ NetmapInterface_repr(NetmapInterface *self)
     }
 
     result = PyString_FromFormat(
-            "name: '%s'\n"
-            "version:    %u\n"
-            "flags:      0x%08x\n"
-            "tx_rings:   %u\n"
-            "rx_rings:   %u\n"
-            "bufs_head:  %u\n"
-            "spare1[0]:  0x%08x\n"
-            "spare1[1]:  0x%08x\n"
-            "spare1[2]:  0x%08x\n"
-            "spare1[3]:  0x%08x\n"
-            "spare1[4]:  0x%08x\n",
+            "name:           '%s'\n"
+            "version:        %u\n"
+            "flags:          0x%08x\n"
+            "tx_rings:       %u\n"
+            "rx_rings:       %u\n"
+            "bufs_head:      %u\n"
+            "host_tx_rings:  %u\n"
+            "host_rx_rings:  %u\n",
             nifp->ni_name,
             nifp->ni_version,
             nifp->ni_flags,
             nifp->ni_tx_rings,
             nifp->ni_rx_rings,
             nifp->ni_bufs_head,
-            nifp->ni_spare1[0],
-            nifp->ni_spare1[1],
-            nifp->ni_spare1[2],
-            nifp->ni_spare1[3],
-            nifp->ni_spare1[4]
-                );
+            nifp->ni_host_tx_rings,
+            nifp->ni_host_rx_rings
+            );
 
     return result;
 }
diff --git a/extra/python/netmap_ring.c b/extra/python/netmap_ring.c
index 5002679e9..124b6c149 100644
--- a/extra/python/netmap_ring.c
+++ b/extra/python/netmap_ring.c
@@ -73,7 +73,7 @@ NetmapRing_repr(NetmapRing *self)
                         sizeof(nr_flag_values)/sizeof(*nr_flag_values));
 
     result = PyString_FromFormat(
-            "buf_ofs:       0x%016x\n"
+            "buf_ofs:       0x%016lx\n"
             "num_slots:     %u\n"
             "nr_buf_size:   %u\n"
             "ringid:        %u\n"
@@ -82,10 +82,10 @@ NetmapRing_repr(NetmapRing *self)
             "cur:           %u\n"
             "tail:          %u\n"
             "flags:         [0x%08x] %s\n"
-            "tv_sec:        %u\n"
-            "tv_usec:       %u\n"
+            "tv_sec:        %ld\n"
+            "tv_usec:       %ld\n"
             /* TODO sem */,
-            ring->buf_ofs,
+            (long unsigned)ring->buf_ofs,
             ring->num_slots,
             ring->nr_buf_size,
             ring->ringid,

From 1ef987de891a3ab25b55951f789937edb01ea1cd Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Feb 2019 09:58:24 +0100
Subject: [PATCH 1622/2207] legacy ABI: stop accepting version 11, and require
 14

This is necessary because of the binary layout change introduced
by 957acfc936906922daddaf8bcaee03d6e.
---
 sys/dev/netmap/netmap_legacy.c | 4 ++--
 utils/ctrl-api-test.c          | 7 +++++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index e5ab66ade..dd875c80e 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -371,8 +371,8 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		struct nmreq *nmr = (struct nmreq *) data;
 		struct nmreq_header *hdr;
 
-		if (nmr->nr_version < 11) {
-			nm_prerr("Minimum supported API is 11 (requested %u)",
+		if (nmr->nr_version < 14) {
+			nm_prerr("Minimum supported API is 14 (requested %u)",
 			    nmr->nr_version);
 			return EINVAL;
 		}
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index faeec2c90..25eb91924 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -357,8 +357,11 @@ niocregif(struct TestContext *ctx, int netmap_api)
 
 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
  * ABI. The 11 ABI is useful to perform tests with legacy applications
- * (which use the 11 ABI) and new kernel (which uses 12, or higher). */
-#define NETMAP_API_NIOCREGIF	11
+ * (which use the 11 ABI) and new kernel (which uses 12, or higher).
+ * However, version 14 introduced a change in the layout of struct netmap_if,
+ * so that binary backward compatibility to 11 is not supported anymore.
+ */
+#define NETMAP_API_NIOCREGIF	14
 
 static int
 legacy_regif_default(struct TestContext *ctx)

From 37796fce10e8620d619f10367d2fd5fe07992644 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 19 Feb 2019 10:14:03 +0100
Subject: [PATCH 1623/2207] netmap.h: update comments about host TX/RX rings

---
 sys/net/netmap.h | 85 +++++++++++++++++++++++++-----------------------
 1 file changed, 45 insertions(+), 40 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index cb6845ff2..d2e981e49 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -64,34 +64,34 @@
    KERNEL (opaque, obviously)
 
   ====================================================================
-                                         |
-   USERSPACE                             |      struct netmap_ring
-                                         +---->+---------------+
-                                             / | head,cur,tail |
-   struct netmap_if (nifp, 1 per fd)        /  | buf_ofs       |
-    +---------------+                      /   | other fields  |
-    | ni_tx_rings   |                     /    +===============+
-    | ni_rx_rings   |                    /     | buf_idx, len  | slot[0]
-    |               |                   /      | flags, ptr    |
-    |               |                  /       +---------------+
-    +===============+                 /        | buf_idx, len  | slot[1]
-    | txring_ofs[0] | (rel.to nifp)--'         | flags, ptr    |
-    | txring_ofs[1] |                          +---------------+
-     (tx+1 entries)                           (num_slots entries)
-    | txring_ofs[t] |                          | buf_idx, len  | slot[n-1]
-    +---------------+                          | flags, ptr    |
-    | rxring_ofs[0] |                          +---------------+
-    | rxring_ofs[1] |
-     (rx+1 entries)
-    | rxring_ofs[r] |
-    +---------------+
+                                          |
+   USERSPACE                              |      struct netmap_ring
+                                          +---->+---------------+
+                                              / | head,cur,tail |
+   struct netmap_if (nifp, 1 per fd)         /  | buf_ofs       |
+    +----------------+                      /   | other fields  |
+    | ni_tx_rings    |                     /    +===============+
+    | ni_rx_rings    |                    /     | buf_idx, len  | slot[0]
+    |                |                   /      | flags, ptr    |
+    |                |                  /       +---------------+
+    +================+                 /        | buf_idx, len  | slot[1]
+    | txring_ofs[0]  | (rel.to nifp)--'         | flags, ptr    |
+    | txring_ofs[1]  |                          +---------------+
+     (tx+htx entries)                           (num_slots entries)
+    | txring_ofs[t]  |                          | buf_idx, len  | slot[n-1]
+    +----------------+                          | flags, ptr    |
+    | rxring_ofs[0]  |                          +---------------+
+    | rxring_ofs[1]  |
+     (rx+hrx entries)
+    | rxring_ofs[r]  |
+    +----------------+
 
  * For each "interface" (NIC, host stack, PIPE, VALE switch port) bound to
  * a file descriptor, the mmap()ed region contains a (logically readonly)
  * struct netmap_if pointing to struct netmap_ring's.
  *
- * There is one netmap_ring per physical NIC ring, plus one tx/rx ring
- * pair attached to the host stack (this pair is unused for non-NIC ports).
+ * There is one netmap_ring per physical NIC ring, plus at least one tx/rx ring
+ * pair attached to the host stack (these pairs are unused for non-NIC ports).
  *
  * All physical/host stack ports share the same memory region,
  * so that zero-copy can be implemented between them.
@@ -133,21 +133,22 @@
  *
  *   Extra flags in nr_flags support the above functions.
  *   Application libraries may use the following naming scheme:
- *	netmap:foo			all NIC ring pairs
- *	netmap:foo^			only host ring pair
- *	netmap:foo+			all NIC ring + host ring pairs
- *	netmap:foo-k			the k-th NIC ring pair
- *	netmap:foo{k			PIPE ring pair k, master side
- *	netmap:foo}k			PIPE ring pair k, slave side
+ *	netmap:foo			all NIC rings pairs
+ *	netmap:foo^			only host rings pairs
+ *	netmap:foo^k			the k-th host rings pair
+ *	netmap:foo+			all NIC rings + host rings pairs
+ *	netmap:foo-k			the k-th NIC rings pair
+ *	netmap:foo{k			PIPE rings pair k, master side
+ *	netmap:foo}k			PIPE rings pair k, slave side
  *
  * Some notes about host rings:
  *
- * + The RX host ring is used to store those packets that the host network
+ * + The RX host rings are used to store those packets that the host network
  *   stack is trying to transmit through a NIC queue, but only if that queue
  *   is currently in netmap mode. Netmap will not intercept host stack mbufs
  *   designated to NIC queues that are not in netmap mode. As a consequence,
  *   registering a netmap port with netmap:foo^ is not enough to intercept
- *   mbufs in the RX host ring; the netmap port should be registered with
+ *   mbufs in the RX host rings; the netmap port should be registered with
  *   netmap:foo*, or another registration should be done to open at least a
  *   NIC TX queue in netmap mode.
  *
@@ -157,7 +158,7 @@
  *   ifconfig on FreeBSD or ethtool -K on Linux) for an interface that is being
  *   used in netmap mode. If the offloadings are not disabled, GSO and/or
  *   unchecksummed packets may be dropped immediately or end up in the host RX
- *   ring, and will be dropped as soon as the packet reaches another netmap
+ *   rings, and will be dropped as soon as the packet reaches another netmap
  *   adapter.
  */
 
@@ -366,7 +367,7 @@ struct netmap_if {
 	/*
 	 * The number of packet rings available in netmap mode.
 	 * Physical NICs can have different numbers of tx and rx rings.
-	 * Physical NICs also have a 'host' ring pair.
+	 * Physical NICs also have at least a 'host' rings pair.
 	 * Additionally, clients can request additional ring pairs to
 	 * be used for internal communication.
 	 */
@@ -380,10 +381,14 @@ struct netmap_if {
 	/*
 	 * The following array contains the offset of each netmap ring
 	 * from this structure, in the following order:
-	 * NIC tx rings (ni_tx_rings); host tx ring (1); extra tx rings;
-	 * NIC rx rings (ni_rx_rings); host tx ring (1); extra rx rings.
+	 *     - NIC tx rings (ni_tx_rings);
+	 *     - host tx rings (ni_host_tx_rings);
+	 *     - extra tx rings;
+	 *     - NIC rx rings (ni_rx_rings);
+	 *     - host rx ring (ni_host_rx_rings);
+	 *     - extra rx rings.
 	 *
-	 * The area is filled up by the kernel on NIOCREGIF,
+	 * The area is filled up by the kernel on NETMAP_REQ_REGISTER,
 	 * and then only read by userspace code.
 	 */
 	const ssize_t	ring_ofs[0];
@@ -597,9 +602,9 @@ struct nmreq_register {
 #define NR_TX_RINGS_ONLY	0x4000
 /* Applications set this flag if they are able to deal with virtio-net headers,
  * that is send/receive frames that start with a virtio-net header.
- * If not set, NIOCREGIF will fail with netmap ports that require applications
- * to use those headers. If the flag is set, the application can use the
- * NETMAP_VNET_HDR_GET command to figure out the header length. */
+ * If not set, NETMAP_REQ_REGISTER will fail with netmap ports that require
+ * applications to use those headers. If the flag is set, the application can
+ * use the NETMAP_VNET_HDR_GET command to figure out the header length. */
 #define NR_ACCEPT_VNET_HDR	0x8000
 /* The following two have the same meaning of NETMAP_NO_TX_POLL and
  * NETMAP_DO_RX_POLL. */
@@ -628,7 +633,7 @@ enum {	NR_REG_DEFAULT	= 0,	/* backward compat, should not be used. */
 
 /* The ioctl commands to sync TX/RX netmap rings.
  * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
- *	whose identity is set in NIOCREGIF through nr_ringid.
+ *	whose identity is set in NETMAP_REQ_REGISTER through nr_ringid.
  *	These are non blocking and take no argument. */
 #define NIOCTXSYNC	_IO('i', 148) /* sync tx queues */
 #define NIOCRXSYNC	_IO('i', 149) /* sync rx queues */

From 33a5d236f488865abf116aed3a5b7fc66faaee29 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 21 Feb 2019 10:05:03 +0100
Subject: [PATCH 1624/2207] remove obsolete references to extra rings

---
 sys/net/netmap.h        |  7 -------
 sys/net/netmap_legacy.h | 11 ++---------
 utils/testmmap.c        |  3 +--
 3 files changed, 3 insertions(+), 18 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d2e981e49..d126d8b38 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -117,11 +117,6 @@
  *   as the index. On close, ni_bufs_head must point to the list of
  *   buffers to be released.
  *
- * + NIOCREGIF can request space for extra rings (and buffers)
- *   allocated in the same memory space. The number of extra rings
- *   is in nr_arg1, and is advisory. This is a no-op on NICs where
- *   the size of the memory space is fixed.
- *
  * + NIOCREGIF can attach to PIPE rings sharing the same memory
  *   space with a parent device. The ifname indicates the parent device,
  *   which must already exist. Flags in nr_flags indicate if we want to
@@ -383,10 +378,8 @@ struct netmap_if {
 	 * from this structure, in the following order:
 	 *     - NIC tx rings (ni_tx_rings);
 	 *     - host tx rings (ni_host_tx_rings);
-	 *     - extra tx rings;
 	 *     - NIC rx rings (ni_rx_rings);
 	 *     - host rx ring (ni_host_rx_rings);
-	 *     - extra rx rings.
 	 *
 	 * The area is filled up by the kernel on NETMAP_REQ_REGISTER,
 	 * and then only read by userspace code.
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index c7b0dffde..f1dd7d625 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -99,14 +99,7 @@
  * nr_flags	is the recommended mode to indicate which rings should
  *		be bound to a file descriptor. Values are NR_REG_*
  *
- * nr_arg1 (in)	The number of extra rings to be reserved.
- *		Especially when allocating a VALE port the system only
- *		allocates the amount of memory needed for the port.
- *		If more shared memory rings are desired (e.g. for pipes),
- *		the first invocation for the same basename/allocator
- *		should specify a suitable number. Memory cannot be
- *		extended after the first allocation without closing
- *		all ports on the same region.
+ * nr_arg1 (in)	Reserved.
  *
  * nr_arg2 (in/out) The identity of the memory region used.
  *		On input, 0 means the system decides autonomously,
@@ -188,7 +181,7 @@ struct nmreq {
 #define NETMAP_BDG_POLLING_ON	10	/* delete polling kthread */
 #define NETMAP_BDG_POLLING_OFF	11	/* delete polling kthread */
 #define NETMAP_VNET_HDR_GET	12      /* get the port virtio-net-hdr length */
-	uint16_t	nr_arg1;	/* reserve extra rings in NIOCREGIF */
+	uint16_t	nr_arg1;	/* extra arguments */
 #define NETMAP_BDG_HOST		1	/* nr_arg1 value for NETMAP_BDG_ATTACH */
 
 	uint16_t	nr_arg2;	/* id of the memory allocator */
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 023f2f3cb..89cbe4196 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1016,8 +1016,7 @@ nmr_arg_error()
 void
 nmr_arg_extra()
 {
-	printf("arg1:      %d [%sextra rings]\n", curr_nmr.nr_arg1,
-	       (curr_nmr.nr_arg1 ? "" : "no "));
+	printf("arg1:      %d [reserved]\n", curr_nmr.nr_arg1);
 	printf("arg2:      %d [%s memory allocator]\n", curr_nmr.nr_arg2,
 	       (curr_nmr.nr_arg2 == 0
 			? "default"

From 2c4fc1d5fa186b32965c723c1c68aa117f0d8b0b Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 25 Feb 2019 10:43:38 +0100
Subject: [PATCH 1625/2207] freebsd: virtio-net: remove redundant
 nm_set_native_flags()

---
 sys/dev/netmap/if_vtnet_netmap.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index e0da855ef..6e0bc60b9 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -132,7 +132,6 @@ vtnet_netmap_reg(struct netmap_adapter *na, int state)
 
 	if (state) {
 		netmap_krings_mode_commit(na, state);
-		nm_set_native_flags(na);
 	} else {
 		nm_clear_native_flags(na);
 		netmap_krings_mode_commit(na, state);

From fbeeaeea43be8858be0895f19170377f06e77dd3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 1 Mar 2019 09:38:07 +0100
Subject: [PATCH 1626/2207] pkt-gen: fix bug in send_packets()

The send_packets() function was using ring->cur as index to scan
the transmit ring. This function may also set ring->cur ahead of
ring->head, in case no more slots are available. However, the function
also uses nm_ring_space() which looks at ring->head to check how many
slots are available. If ring->head and ring->cur are different, this
results in pkt-gen advancing ring->cur beyond tail.

This patch fixes send_packets() (and similar source locations) to
use ring->head as a index, rather than using ring->cur.
---
 apps/pkt-gen/pkt-gen.c | 62 +++++++++++++++++++++---------------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 5ece1e347..01f08a210 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1158,22 +1158,22 @@ static int
 send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		int size, struct targ *t, u_int count, int options)
 {
-	u_int n, sent, cur = ring->cur;
+	u_int n, sent, head = ring->head;
 	u_int frags = t->frags;
 	u_int frag_size = t->frag_size;
-	struct netmap_slot *slot = &ring->slot[cur];
+	struct netmap_slot *slot = &ring->slot[head];
 
 	n = nm_ring_space(ring);
 #if 0
 	if (options & (OPT_COPY | OPT_PREFETCH) ) {
 		for (sent = 0; sent < count; sent++) {
-			struct netmap_slot *slot = &ring->slot[cur];
+			struct netmap_slot *slot = &ring->slot[head];
 			char *p = NETMAP_BUF(ring, slot->buf_idx);
 
 			__builtin_prefetch(p);
-			cur = nm_ring_next(ring, cur);
+			head = nm_ring_next(ring, head);
 		}
-		cur = ring->cur;
+		head = ring->head;
 	}
 #endif
 	for (sent = 0; sent < count && n >= frags; sent++, n--) {
@@ -1181,7 +1181,7 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		int buf_changed;
 		u_int tosend = size;
 
-		slot = &ring->slot[cur];
+		slot = &ring->slot[head];
 		p = NETMAP_BUF(ring, slot->buf_idx);
 		buf_changed = slot->flags & NS_BUF_CHANGED;
 
@@ -1200,11 +1200,11 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 				slot->len = frag_size;
 				slot->flags = NS_MOREFRAG;
 				if (options & OPT_DUMP)
-					dump_payload(fp, frag_size, ring, cur);
+					dump_payload(fp, frag_size, ring, head);
 				tosend -= frag_size;
 				f += frag_size;
-				cur = nm_ring_next(ring, cur);
-				slot = &ring->slot[cur];
+				head = nm_ring_next(ring, head);
+				slot = &ring->slot[head];
 				fp = NETMAP_BUF(ring, slot->buf_idx);
 			}
 			n -= (frags - 1);
@@ -1223,12 +1223,12 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 		}
 		slot->len = tosend;
 		if (options & OPT_DUMP)
-			dump_payload(p, tosend, ring, cur);
-		cur = nm_ring_next(ring, cur);
+			dump_payload(p, tosend, ring, head);
+		head = nm_ring_next(ring, head);
 	}
 	if (sent) {
 		slot->flags |= NS_REPORT;
-		ring->head = ring->cur = cur;
+		ring->head = ring->cur = head;
 	}
 	if (sent < count) {
 		/* tell netmap that we need more slots */
@@ -1329,7 +1329,7 @@ ping_body(void *data)
 		if (n > 0 && n - sent < limit)
 			limit = n - sent;
 		for (m = 0; (unsigned)m < limit; m++) {
-			slot = &ring->slot[ring->cur];
+			slot = &ring->slot[ring->head];
 			slot->len = size;
 			p = NETMAP_BUF(ring, slot->buf_idx);
 
@@ -1345,7 +1345,7 @@ ping_body(void *data)
 				tp->sec = (uint32_t)ts.tv_sec;
 				tp->nsec = (uint32_t)ts.tv_nsec;
 				sent++;
-				ring->head = ring->cur = nm_ring_next(ring, ring->cur);
+				ring->head = ring->cur = nm_ring_next(ring, ring->head);
 			}
 		}
 		if (m > 0)
@@ -1381,7 +1381,7 @@ ping_body(void *data)
 				struct tstamp *tp;
 				int pos;
 
-				slot = &ring->slot[ring->cur];
+				slot = &ring->slot[ring->head];
 				p = NETMAP_BUF(ring, slot->buf_idx);
 
 				clock_gettime(CLOCK_REALTIME_PRECISE, &now);
@@ -1406,7 +1406,7 @@ ping_body(void *data)
 				pos = msb64(t_cur);
 				buckets[pos]++;
 				/* now store it in a bucket */
-				ring->head = ring->cur = nm_ring_next(ring, ring->cur);
+				ring->head = ring->cur = nm_ring_next(ring, ring->head);
 				rx++;
 			}
 		}
@@ -1486,7 +1486,7 @@ pong_body(void *data)
 		D("understood ponger %llu but don't know how to do it",
 			(unsigned long long)n);
 	while (!targ->cancel && (n == 0 || sent < n)) {
-		uint32_t txcur, txavail;
+		uint32_t txhead, txavail;
 //#define BUSYWAIT
 #ifdef BUSYWAIT
 		ioctl(pfd.fd, NIOCRXSYNC, NULL);
@@ -1499,24 +1499,24 @@ pong_body(void *data)
 		}
 #endif
 		txring = NETMAP_TXRING(nifp, targ->nmd->first_tx_ring);
-		txcur = txring->cur;
+		txhead = txring->head;
 		txavail = nm_ring_space(txring);
 		/* see what we got back */
 		for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) {
 			rxring = NETMAP_RXRING(nifp, i);
 			while (!nm_ring_empty(rxring)) {
 				uint16_t *spkt, *dpkt;
-				uint32_t cur = rxring->cur;
-				struct netmap_slot *slot = &rxring->slot[cur];
+				uint32_t head = rxring->head;
+				struct netmap_slot *slot = &rxring->slot[head];
 				char *src, *dst;
 				src = NETMAP_BUF(rxring, slot->buf_idx);
 				//D("got pkt %p of size %d", src, slot->len);
-				rxring->head = rxring->cur = nm_ring_next(rxring, cur);
+				rxring->head = rxring->cur = nm_ring_next(rxring, head);
 				rx++;
 				if (txavail == 0)
 					continue;
 				dst = NETMAP_BUF(txring,
-				    txring->slot[txcur].buf_idx);
+				    txring->slot[txhead].buf_idx);
 				/* copy... */
 				dpkt = (uint16_t *)dst;
 				spkt = (uint16_t *)src;
@@ -1528,13 +1528,13 @@ pong_body(void *data)
 				dpkt[3] = spkt[0];
 				dpkt[4] = spkt[1];
 				dpkt[5] = spkt[2];
-				txring->slot[txcur].len = slot->len;
-				txcur = nm_ring_next(txring, txcur);
+				txring->slot[txhead].len = slot->len;
+				txhead = nm_ring_next(txring, txhead);
 				txavail--;
 				sent++;
 			}
 		}
-		txring->head = txring->cur = txcur;
+		txring->head = txring->cur = txhead;
 		targ->ctr.pkts = sent;
 #ifdef BUSYWAIT
 		ioctl(pfd.fd, NIOCTXSYNC, NULL);
@@ -1760,30 +1760,30 @@ receive_pcap(u_char *user, const struct pcap_pkthdr * h,
 static int
 receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes)
 {
-	u_int cur, rx, n;
+	u_int head, rx, n;
 	uint64_t b = 0;
 	u_int complete = 0;
 
 	if (bytes == NULL)
 		bytes = &b;
 
-	cur = ring->cur;
+	head = ring->head;
 	n = nm_ring_space(ring);
 	if (n < limit)
 		limit = n;
 	for (rx = 0; rx < limit; rx++) {
-		struct netmap_slot *slot = &ring->slot[cur];
+		struct netmap_slot *slot = &ring->slot[head];
 		char *p = NETMAP_BUF(ring, slot->buf_idx);
 
 		*bytes += slot->len;
 		if (dump)
-			dump_payload(p, slot->len, ring, cur);
+			dump_payload(p, slot->len, ring, head);
 		if (!(slot->flags & NS_MOREFRAG))
 			complete++;
 
-		cur = nm_ring_next(ring, cur);
+		head = nm_ring_next(ring, head);
 	}
-	ring->head = ring->cur = cur;
+	ring->head = ring->cur = head;
 
 	return (complete);
 }

From 15790f70cc554c15fd68a9d26fd4006e995fb2b3 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 1 Mar 2019 09:58:25 +0100
Subject: [PATCH 1627/2207] apps: bridge: use ring->head as ring index

Convert bridge to use ring->head as a ring index, rather than
using ring->cur. This is not strictly necessary in this case, as
for this program ring->cur == ring->head. However, should this
assumption become false in the future, using ring->cur would
be a bug, because ring->cur is the wake up point, and ring->head
is the next packet to process (also see nm_ring_space()).
---
 apps/bridge/bridge.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 967fc850b..f43adf077 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -61,8 +61,8 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 	if (rxring->flags || txring->flags)
 		D("%s rxflags %x txflags %x",
 			msg, rxring->flags, txring->flags);
-	j = rxring->cur; /* RX */
-	k = txring->cur; /* TX */
+	j = rxring->head; /* RX */
+	k = txring->head; /* TX */
 	m = nm_ring_space(rxring);
 	if (m < limit)
 		limit = m;
@@ -320,12 +320,12 @@ main(int argc, char **argv)
 				pollfd[0].events,
 				pollfd[0].revents,
 				pkt_queued(pa, 0),
-				NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->cur,
+				NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->head,
 				pkt_queued(pa, 1),
 				pollfd[1].events,
 				pollfd[1].revents,
 				pkt_queued(pb, 0),
-				NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->cur,
+				NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->head,
 				pkt_queued(pb, 1)
 			);
 		if (ret < 0)

From 625e4d97f518d1ed458491f888976bcbc768da38 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 1 Mar 2019 11:45:28 +0100
Subject: [PATCH 1628/2207] apps: lb: use ring->head as ring index

Convert lb to use ring->head as a ring index, rather than
using ring->cur. This is not strictly necessary in this case, as
for this program ring->cur == ring->head. However, should this
assumption become false in the future, using ring->cur would
be a bug, because ring->cur is the wake up point, and ring->head
is the next packet to process (also see nm_ring_space()).
---
 apps/lb/lb.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 73fcf20f7..de4cde688 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -948,8 +948,8 @@ int main(int argc, char **argv)
 			struct netmap_ring *rxring = NETMAP_RXRING(rxport->nmd->nifp, i);
 
 			//D("prepare to scan rings");
-			int next_cur = rxring->cur;
-			struct netmap_slot *next_slot = &rxring->slot[next_cur];
+			int next_head = rxring->head;
+			struct netmap_slot *next_slot = &rxring->slot[next_head];
 			const char *next_buf = NETMAP_BUF(rxring, next_slot->buf_idx);
 			while (!nm_ring_empty(rxring)) {
 				struct netmap_slot *rs = next_slot;
@@ -963,14 +963,14 @@ int main(int argc, char **argv)
 					non_ip++; // XXX ??
 				}
 				// prefetch the buffer for the next round
-				next_cur = nm_ring_next(rxring, next_cur);
-				next_slot = &rxring->slot[next_cur];
+				next_head = nm_ring_next(rxring, next_head);
+				next_slot = &rxring->slot[next_head];
 				next_buf = NETMAP_BUF(rxring, next_slot->buf_idx);
 				__builtin_prefetch(next_buf);
 				// 'B' is just a hashing seed
 				rs->buf_idx = forward_packet(g, rs);
 				rs->flags |= NS_BUF_CHANGED;
-				rxring->head = rxring->cur = next_cur;
+				rxring->head = rxring->cur = next_head;
 
 				batch++;
 				if (unlikely(batch >= glob_arg.batch)) {

From 8c2370b5d37e3f96df1f6009d08035675c03777c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Mar 2019 09:47:27 +0100
Subject: [PATCH 1629/2207] linux: check for do_gettimeofday

---
 LINUX/bsd_glue.h | 11 ++++++++++-
 LINUX/configure  |  9 +++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 0c56323c6..8dc75b3cb 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -441,7 +441,16 @@ struct nm_linux_selrecord_t;
 #define	tsleep(a, b, c, t)	msleep(10)
 
 #define microtime		do_gettimeofday		/* debugging */
-
+#ifndef NETMAP_LINUX_HAVE_DO_GETTIMEOFDAY
+#define do_gettimeofday(tv_)					\
+	do {							\
+		struct timespec64 now_;				\
+								\
+		ktime_get_real_ts64(&now_);			\
+		(tv_)->tv_sec = now_.tv_sec;			\
+		(tv_)->tv_usec = now_.tv_nsec/1000;		\
+	} while (0)
+#endif /* !NETMAP_LINUX_HAVE_DO_GETTIMEOFDAY */
 
 /*
  * The following trick is to map a struct cdev into a struct miscdevice
diff --git a/LINUX/configure b/LINUX/configure
index ecb6bd1f7..fb573f6aa 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1652,6 +1652,15 @@ EOF
 	}
 EOF
 
+  add_test 'have DO_GETTIMEOFDAY' <
+
+	void
+	dummy(struct timeval *tv) {
+		do_gettimeofday(tv);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################

From b2f768b42e19acbc73e539f50021d1099c4cdaa6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Mar 2019 13:18:04 +0100
Subject: [PATCH 1630/2207] linux/configure: pass EXTRA_CFLAGS to tests

---
 LINUX/configure | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index fb573f6aa..fe5581cf3 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -451,14 +451,14 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS :=
+EXTRA_CFLAGS := -Werror
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)
 all: \$(S_DRIVERS:%=get-%) \$(E_DRIVERS:%=build-%) \$(I_DRIVERS:%=patch-%) tests
 
 tests:
-	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS=-Werror $kopts
+	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(EXTRA_CFLAGS)" $kopts
 
 -include $BUILDDIR/extdrv-versions.mak
 -include $BUILDDIR/default-config.mak

From 5f080436b455da87ec1a52d552a34213583d3844 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Mar 2019 13:23:14 +0100
Subject: [PATCH 1631/2207] linux/configure: avoid false negatives due to
 unuset-but-set-variable

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index fe5581cf3..3b5722656 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -451,7 +451,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS := -Werror
+EXTRA_CFLAGS := -Werror -Wno-error=unused-but-set-variable
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)

From ae021089102c47475cd223c2854a2f97ef606e38 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Mar 2019 15:55:26 +0100
Subject: [PATCH 1632/2207] linux/ixgbe: patch for recent vanilla kernels

---
 .../vanilla--ixgbe--41400--99999              | 126 ++++++++++++++++++
 1 file changed, 126 insertions(+)
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--41400--99999

diff --git a/LINUX/final-patches/vanilla--ixgbe--41400--99999 b/LINUX/final-patches/vanilla--ixgbe--41400--99999
new file mode 100644
index 000000000..502721dbb
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--41400--99999
@@ -0,0 +1,126 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 113b38e0defb..15079a88fbb2 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -457,6 +457,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1119,6 +1135,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2283,6 +2310,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	while (likely(total_rx_packets < budget)) {
+@@ -3540,6 +3577,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3554,7 +3595,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+ 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
+@@ -4147,6 +4188,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ 	else
+@@ -5631,6 +5676,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -11119,6 +11167,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
+ 			true);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11164,6 +11216,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
+ 	set_bit(__IXGBE_REMOVING, &adapter->state);

From 71318f758721c56f24545ad742741f6d300f4979 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 7 Mar 2019 13:14:28 +0100
Subject: [PATCH 1633/2207] libnetmap: simplify options initialization

---
 libnetmap/GNUmakefile |  5 +--
 libnetmap/libnetmap.h |  5 +--
 libnetmap/nmport.c    | 84 +++++++++++++++++++++----------------------
 libnetmap/nmreq.c     | 15 ++++----
 libnetmap/npopts.lds  | 13 -------
 5 files changed, 51 insertions(+), 71 deletions(-)
 delete mode 100644 libnetmap/npopts.lds

diff --git a/libnetmap/GNUmakefile b/libnetmap/GNUmakefile
index 9cfc45c1c..1b9e4f075 100644
--- a/libnetmap/GNUmakefile
+++ b/libnetmap/GNUmakefile
@@ -5,15 +5,12 @@ CFLAGS=-g
 CFLAGS += -I $(SRCDIR)/sys
 VPATH = $(SRCDIR)/libnetmap
 SRCS=$(notdir $(wildcard $(SRCDIR)/libnetmap/*.c))
-OBJS=$(filter-out nmport.o,$(SRCS:.c=.o)) nmport2.o
+OBJS=$(SRCS:.c=.o)
 
 all: libnetmap.a
 
 $(OBJS): libnetmap.h
 
-nmport2.o: nmport.o
-	$(LD) -r -T $(VPATH)/npopts.lds nmport.o -o $@
-
 libnetmap.a: $(OBJS)
 	$(AR) r $@ $^
 
diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 13d11854a..3dff95f5a 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -468,7 +468,6 @@ int nmreq_register_decode(const char **pmode, struct nmreq_register *reg,
 /* nmreq_options_decode - parse the "options" part of the portspec
  * @opt:	pointer to the option list
  * @parsers:	list of option parsers
- * @nr_parsers:	number of parsers in the list
  * @token:	token to pass to each parser
  * @ctx:	pointer to the nmctx to use (for errors and malloc/free)
  *
@@ -484,7 +483,7 @@ int nmreq_register_decode(const char **pmode, struct nmreq_register *reg,
  */
 struct nmreq_opt_parser;
 int nmreq_options_decode(const char *opt, struct nmreq_opt_parser *parsers,
-		int nr_parsers, void *token, struct nmctx *ctx);
+		void *token, struct nmctx *ctx);
 
 struct nmreq_parse_ctx;
 /* type of the option-parsers callbacks */
@@ -512,6 +511,8 @@ struct nmreq_opt_parser {
 #define NMREQ_OPTF_DISABLED     (1U << 0)
 #define NMREQ_OPTF_ALLOWEMPTY	(1U << 1)	/* =value can be omitted */
 
+	struct nmreq_opt_parser *next;	/* list of options */
+
 	/* recognized keys */
 	struct nmreq_opt_key keys[NMREQ_OPT_MAXKEYS];
 } __attribute__((aligned(16)));
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index e504c17b5..c0956c9cd 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -137,35 +137,60 @@ nmport_undo_extmem(struct nmport_d *d)
 	d->extmem_autounmap = 0;
 }
 
+/* head of the list of options */
+static struct nmreq_opt_parser *nmport_opt_parsers;
+
 #define NPOPT_PARSER(o)		nmport_opt_##o##_parser
 #define NPOPT_DESC(o)		nmport_opt_##o##_desc
 #define NPOPT_DECL(o, f, d)						\
 static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *);			\
-static struct nmreq_opt_parser __attribute__((section(".npopts"),used))	\
-	NPOPT_DESC(o) = {						\
+static struct nmreq_opt_parser NPOPT_DESC(o) = {			\
 	.prefix = #o,							\
 	.parse = NPOPT_PARSER(o),					\
 	.flags = (f),							\
 	.default_key = (d),						\
 	.nr_keys = 0,							\
-};
+	.next = NULL,							\
+};									\
+static void __attribute__((constructor))				\
+nmport_opt_##o##_ctor(void)						\
+{									\
+	NPOPT_DESC(o).next = nmport_opt_parsers;			\
+	nmport_opt_parsers = &NPOPT_DESC(o);				\
+}
 struct nmport_key_desc {
 	struct nmreq_opt_parser *option;
 	const char *key;
 	unsigned int flags;
-	int *id;
+	int id;
 };
-#define NPKEY_ID(o, k)		nmport_opt_##o##_key_##k##_id
+static void
+nmport_opt_key_ctor(struct nmport_key_desc *k)
+{
+	struct nmreq_opt_parser *o = k->option;
+	struct nmreq_opt_key *ok;
+
+	k->id = o->nr_keys;
+	ok = &o->keys[k->id];
+	ok->key = k->key;
+	ok->id = k->id;
+	ok->flags = k->flags;
+	o->nr_keys++;
+}
 #define NPKEY_DESC(o, k)	nmport_opt_##o##_key_##k##_desc
+#define NPKEY_ID(o, k)		(NPKEY_DESC(o, k).id)
 #define NPKEY_DECL(o, k, f)						\
-static int NPKEY_ID(o, k);						\
-static struct nmport_key_desc __attribute__((section(".npkeys"),used))	\
-	NPKEY_DESC(o, k) = {						\
+static struct nmport_key_desc NPKEY_DESC(o, k) = {			\
 	.option = &NPOPT_DESC(o),					\
 	.key = #k,							\
 	.flags = (f),							\
-	.id = &NPKEY_ID(o, k),						\
-};
+	.id = -1,							\
+};									\
+static void __attribute__((constructor))				\
+nmport_opt_##o##_key_##k##_ctor(void)					\
+{									\
+	nmport_opt_key_ctor(&NPKEY_DESC(o, k));				\
+}
 #define nmport_key(p, o, k)	((p)->keys[NPKEY_ID(o, k)])
 #define nmport_defkey(p, o)	((p)->keys[NPOPT_DESC(o).default_key])
 
@@ -189,8 +214,6 @@ NPOPT_DECL(conf, 0, -1)
 	NPKEY_DECL(conf, tx_slots, 0)
 	NPKEY_DECL(conf, rx_slots, 0)
 
-static struct nmreq_opt_parser *nmport_opt_parsers;
-static int nmport_opt_parsers_n;
 
 static int
 NPOPT_PARSER(share)(struct nmreq_parse_ctx *p)
@@ -299,11 +322,9 @@ NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p)
 void
 nmport_disable_opt(const char *opt)
 {
-	int i;
+	struct nmreq_opt_parser *p;
 
-	for (i = 0; i < nmport_opt_parsers_n; i++) {
-		struct nmreq_opt_parser *p =
-			nmport_opt_parsers + i;
+	for (p = nmport_opt_parsers; p != NULL; p = p->next) {
 		if (!strcmp(p->prefix, opt)) {
 			p->flags |= NMREQ_OPTF_DISABLED;
 		}
@@ -313,11 +334,9 @@ nmport_disable_opt(const char *opt)
 int
 nmport_enable_opt(const char *opt)
 {
-	int i;
+	struct nmreq_opt_parser *p;
 
-	for (i = 0; i < nmport_opt_parsers_n; i++) {
-		struct nmreq_opt_parser *p =
-			nmport_opt_parsers + i;
+	for (p = nmport_opt_parsers; p != NULL; p = p->next) {
 		if (!strcmp(p->prefix, opt)) {
 			p->flags &= ~NMREQ_OPTF_DISABLED;
 			return 0;
@@ -343,8 +362,7 @@ nmport_parse(struct nmport_d *d, const char *ifname)
 	}
 
 	/* parse the options, if any */
-	if (nmreq_options_decode(scan, nmport_opt_parsers,
-				nmport_opt_parsers_n, d, d->ctx) < 0) {
+	if (nmreq_options_decode(scan, nmport_opt_parsers, d, d->ctx) < 0) {
 		goto err;
 	}
 	return 0;
@@ -697,25 +715,3 @@ nmport_inject(struct nmport_d *d, const void *buf, size_t size)
 	}
 	return 0; /* fail */
 }
-
-static void __attribute__((constructor)) nmport_init(void)
-{
-	extern struct nmreq_opt_parser npopts_start, npopts_end;
-	extern struct nmport_key_desc npkeys_start, npkeys_end;
-	struct nmport_key_desc *k;
-
-	nmport_opt_parsers = &npopts_start;
-	nmport_opt_parsers_n = &npopts_end - &npopts_start;
-	for (k = &npkeys_start; k != &npkeys_end; k++) {
-		struct nmreq_opt_parser *o = k->option;
-		struct nmreq_opt_key *ok;
-		int id = o->nr_keys;
-		//printf("key %s of option %s id %d\n", k->key, o->prefix, id);
-		*k->id = id;
-		ok = &o->keys[id];
-		ok->key = k->key;
-		ok->id = id;
-		ok->flags = k->flags;
-		o->nr_keys++;
-	}
-}
diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index aa09209ca..e2c839e24 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -452,15 +452,15 @@ nmreq_option_parsekeys(const char *prefix, char *body, struct nmreq_opt_parser *
 
 
 static int
-nmreq_option_decode1(char *opt, struct nmreq_opt_parser parsers[], int nparsers,
+nmreq_option_decode1(char *opt, struct nmreq_opt_parser *parsers,
 		void *token, struct nmctx *ctx)
 {
 	struct nmreq_opt_parser *p;
 	const char *prefix;
 	char *scan;
 	char delim;
-	int i;
 	struct nmreq_parse_ctx pctx;
+	int i;
 
 	prefix = opt;
 	/* find the delimiter */
@@ -470,16 +470,15 @@ nmreq_option_decode1(char *opt, struct nmreq_opt_parser parsers[], int nparsers,
 	*scan = '\0';
 	scan++;
 	/* find the prefix */
-	for (i = 0; i < nparsers; i++) {
-		if (!strcmp(prefix, parsers[i].prefix))
+	for (p = parsers; p != NULL; p = p->next) {
+		if (!strcmp(prefix, p->prefix))
 			break;
 	}
-	if (i == nparsers) {
+	if (p == NULL) {
 		nmctx_ferror(ctx, "unknown option: '%s'", prefix);
 		errno = EINVAL;
 		return -1;
 	}
-	p = parsers + i; /* shortcut */
 	if (p->flags & NMREQ_OPTF_DISABLED) {
 		nmctx_ferror(ctx, "option '%s' is not supported", prefix);
 		errno = EOPNOTSUPP;
@@ -524,7 +523,7 @@ nmreq_option_decode1(char *opt, struct nmreq_opt_parser parsers[], int nparsers,
 
 int
 nmreq_options_decode(const char *opt, struct nmreq_opt_parser parsers[],
-		int nparsers, void *token, struct nmctx *ctx)
+		void *token, struct nmctx *ctx)
 {
 	const char *scan, *opt1;
 	char *w;
@@ -561,7 +560,7 @@ nmreq_options_decode(const char *opt, struct nmreq_opt_parser parsers[],
 		}
 		memcpy(w, opt1, len);
 		w[len] = '\0';
-		ret = nmreq_option_decode1(w, parsers, nparsers, token, ctx);
+		ret = nmreq_option_decode1(w, parsers, token, ctx);
 		nmctx_free(ctx, w);
 		if (ret < 0)
 			return -1;
diff --git a/libnetmap/npopts.lds b/libnetmap/npopts.lds
deleted file mode 100644
index 7ad57a1f6..000000000
--- a/libnetmap/npopts.lds
+++ /dev/null
@@ -1,13 +0,0 @@
-SECTIONS
-{
-	.npopts ALIGN(16) : {
-		npopts_start = .;
-		*(.npopts)
-		npopts_end = .;
-	}
-	.npkeys ALIGN(16) : {
-		npkeys_start = .;
-		*(.npkeys)
-		npkeys_end = .;
-	}
-}

From 8b5bc8541630e577a960e682043a2eb55dcc7565 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Mar 2019 10:37:29 +0100
Subject: [PATCH 1634/2207] index options and auto-check for duplicates

---
 sys/dev/netmap/netmap.c       | 164 +++++++++++++++++++++++++---------
 sys/dev/netmap/netmap_kern.h  |   3 +-
 sys/dev/netmap/netmap_kloop.c |  11 +--
 sys/net/netmap.h              |   4 +
 4 files changed, 127 insertions(+), 55 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 43b383496..44eebbfa1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2505,17 +2505,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				}
 
 #ifdef WITH_EXTMEM
-				opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-						NETMAP_REQ_OPT_EXTMEM);
+				opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_EXTMEM);
 				if (opt != NULL) {
 					struct nmreq_opt_extmem *e =
 						(struct nmreq_opt_extmem *)opt;
 
-					error = nmreq_checkduplicate(opt);
-					if (error) {
-						opt->nro_status = error;
-						break;
-					}
 					nmd = netmap_mem_ext_create(e->nro_usrptr,
 							&e->nro_info, &error);
 					opt->nro_status = error;
@@ -2559,15 +2553,11 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					break;
 				}
 
-				opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-							NETMAP_REQ_OPT_CSB);
+				opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_CSB);
 				if (opt != NULL) {
 					struct nmreq_opt_csb *csbo =
 						(struct nmreq_opt_csb *)opt;
-					error = nmreq_checkduplicate(opt);
-					if (!error) {
-						error = netmap_csb_validate(priv, csbo);
-					}
+					error = netmap_csb_validate(priv, csbo);
 					opt->nro_status = error;
 					if (error) {
 						netmap_do_unregif(priv);
@@ -2841,19 +2831,15 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		case NETMAP_REQ_CSB_ENABLE: {
 			struct nmreq_option *opt;
 
-			opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-						NETMAP_REQ_OPT_CSB);
+			opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_CSB);
 			if (opt == NULL) {
 				error = EINVAL;
 			} else {
 				struct nmreq_opt_csb *csbo =
 					(struct nmreq_opt_csb *)opt;
-				error = nmreq_checkduplicate(opt);
-				if (!error) {
-					NMG_LOCK();
-					error = netmap_csb_validate(priv, csbo);
-					NMG_UNLOCK();
-				}
+				NMG_LOCK();
+				error = netmap_csb_validate(priv, csbo);
+				NMG_UNLOCK();
 				opt->nro_status = error;
 			}
 			break;
@@ -3021,13 +3007,72 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 	return rv - sizeof(struct nmreq_option);
 }
 
+/*
+ * nmreq_copyin: create an in-kernel version of the request.
+ *
+ * We build the following data structure:
+ *
+ * hdr -> +-------+                buf
+ *        |       |          +---------------+
+ *        +-------+          |usr body ptr   |
+ *        |options|-.        +---------------+
+ *        +-------+ |        |usr options ptr|
+ *        |body   |--------->+---------------+
+ *        +-------+ |        |               |
+ *                  |        |  copy of body |
+ *                  |        |               |
+ *                  |        +---------------+
+ *                  |        |    NULL       |
+ *                  |        +---------------+
+ *                  |    .---|               |\
+ *                  |    |   +---------------+ |
+ *                  | .------|               | |
+ *                  | |  |   +---------------+  \ option table
+ *                  | |  |   |      ...      |  / indexed by option
+ *                  | |  |   +---------------+ |  type
+ *                  | |  |   |               | |
+ *                  | |  |   +---------------+/
+ *                  | |  |   |usr next ptr 1 |
+ *                  `-|----->+---------------+
+ *                    |  |   | copy of opt 1 |
+ *                    |  |   |               |
+ *                    |  | .-| nro_next      |
+ *                    |  | | +---------------+
+ *                    |  | | |usr next ptr 2 |
+ *                    |  `-`>+---------------+
+ *                    |      | copy of opt 2 |
+ *                    |      |               |
+ *                    |    .-| nro_next      |
+ *                    |    | +---------------+
+ *                    |    | |               |
+ *                    ~    ~ ~      ...      ~
+ *                    |    .-|               |
+ *                    `----->+---------------+
+ *                         | |usr next ptr n |
+ *                         `>+---------------+
+ *                           | copy of opt n |
+ *                           |               |
+ *                           | nro_next(NULL)|
+ *                           +---------------+
+ *
+ * The options and body fields of the hdr structure are overwritten
+ * with in-kernel valid pointers inside the buf. The original user
+ * pointers are saved in the buf and restored on copyout.
+ * The list of options is copied and the pointers adjusted. The
+ * original pointers are saved before the option they belonged.
+ *
+ * The option table has an entry for every availabe option.  Entries
+ * for options that have not been passed contain NULL.
+ *
+ */
+
 int
 nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
 	size_t rqsz, optsz, bufsz;
-	int error;
+	int error = 0;
 	char *ker = NULL, *p;
-	struct nmreq_option **next, *src;
+	struct nmreq_option **next, *src, **opt_tab;
 	struct nmreq_option buf;
 	uint64_t *ptrs;
 
@@ -3058,7 +3103,13 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		goto out_err;
 	}
 
-	bufsz = 2 * sizeof(void *) + rqsz;
+	bufsz = 2 * sizeof(void *) + rqsz +
+		NETMAP_REQ_OPT_MAX * sizeof(opt_tab);
+	/* compute the size of the buf below the option table.
+	 * It must contain a copy of every received option structure.
+	 * For every option we also need to store a copy of the user
+	 * list pointer.
+	 */
 	optsz = 0;
 	for (src = (struct nmreq_option *)(uintptr_t)hdr->nr_options; src;
 	     src = (struct nmreq_option *)(uintptr_t)buf.nro_next)
@@ -3072,15 +3123,16 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 			error = EMSGSIZE;
 			goto out_err;
 		}
-		bufsz += optsz + sizeof(void *);
+		bufsz += sizeof(void *);
 	}
+	bufsz += optsz;
 
 	ker = nm_os_malloc(bufsz);
 	if (ker == NULL) {
 		error = ENOMEM;
 		goto out_err;
 	}
-	p = ker;
+	p = ker;	/* write pointer into the buffer */
 
 	/* make a copy of the user pointers */
 	ptrs = (uint64_t*)p;
@@ -3095,6 +3147,9 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	/* overwrite the user pointer with the in-kernel one */
 	hdr->nr_body = (uintptr_t)p;
 	p += rqsz;
+	/* start of the options table */
+	opt_tab = (struct nmreq_option **)p;
+	p += sizeof(opt_tab) * NETMAP_REQ_OPT_MAX;
 
 	/* copy the options */
 	next = (struct nmreq_option **)&hdr->nr_options;
@@ -3118,6 +3173,34 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		 */
 		opt->nro_status = EOPNOTSUPP;
 
+		/* check for invalid types */
+		if (opt->nro_reqtype < 1) {
+			if (netmap_verbose)
+				nm_prinf("invalid option type: %u", opt->nro_reqtype);
+			opt->nro_status = EINVAL;
+			error = EINVAL;
+			goto next;
+		}
+
+		if (opt->nro_reqtype >= NETMAP_REQ_OPT_MAX) {
+			/* opt->nro_status is already EOPNOTSUPP */
+			error = EOPNOTSUPP;
+			goto next;
+		}
+
+		/* if the type is valid, index the option in the table
+		 * unless it is a duplicate.
+		 */
+		if (opt_tab[opt->nro_reqtype] != NULL) {
+			if (netmap_verbose)
+				nm_prinf("duplicate option: %u", opt->nro_reqtype);
+			opt->nro_status = EINVAL;
+			opt_tab[opt->nro_reqtype]->nro_status = EINVAL;
+			error = EINVAL;
+			goto next;
+		}
+		opt_tab[opt->nro_reqtype] = opt;
+
 		p = (char *)(opt + 1);
 
 		/* copy the option body */
@@ -3131,11 +3214,14 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 			p += optsz;
 		}
 
+	next:
 		/* move to next option */
 		next = (struct nmreq_option **)&opt->nro_next;
 		src = *next;
 	}
-	return 0;
+	if (error)
+		nmreq_copyout(hdr, error);
+	return error;
 
 out_restore:
 	ptrs = (uint64_t *)ker;
@@ -3218,25 +3304,15 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 }
 
 struct nmreq_option *
-nmreq_findoption(struct nmreq_option *opt, uint16_t reqtype)
+nmreq_getoption(struct nmreq_header *hdr, uint16_t reqtype)
 {
-	for ( ; opt; opt = (struct nmreq_option *)(uintptr_t)opt->nro_next)
-		if (opt->nro_reqtype == reqtype)
-			return opt;
-	return NULL;
-}
+	struct nmreq_option **opt_tab;
 
-int
-nmreq_checkduplicate(struct nmreq_option *opt) {
-	uint16_t type = opt->nro_reqtype;
-	int dup = 0;
-
-	while ((opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)opt->nro_next,
-			type))) {
-		dup++;
-		opt->nro_status = EINVAL;
-	}
-	return (dup ? EINVAL : 0);
+	if (!hdr->nr_options)
+		return NULL;
+
+	opt_tab = (struct nmreq_option **)(hdr->nr_options) - (NETMAP_REQ_OPT_MAX + 1);
+	return opt_tab[reqtype];
 }
 
 static int
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0e7a3b755..13ed80580 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2390,8 +2390,7 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 #endif /* __FreeBSD_version >= 1100000 */
 #endif /* __FreeBSD__ */
 
-struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
-int nmreq_checkduplicate(struct nmreq_option *);
+struct nmreq_option * nmreq_getoption(struct nmreq_header *, uint16_t);
 
 int netmap_init_bridges(void);
 void netmap_uninit_bridges(void);
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 2bd3685a2..0b89d89bf 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -649,8 +649,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	}
 
 	/* Validate notification options. */
-	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-				NETMAP_REQ_OPT_SYNC_KLOOP_MODE);
+	opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_SYNC_KLOOP_MODE);
 	if (opt != NULL) {
 		struct nmreq_opt_sync_kloop_mode *mode_opt =
 		    (struct nmreq_opt_sync_kloop_mode *)opt;
@@ -664,14 +663,8 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 		}
 		opt->nro_status = 0;
 	}
-	opt = nmreq_findoption((struct nmreq_option *)(uintptr_t)hdr->nr_options,
-				NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
+	opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS);
 	if (opt != NULL) {
-		err = nmreq_checkduplicate(opt);
-		if (err) {
-			opt->nro_status = err;
-			goto out;
-		}
 		if (opt->nro_size != sizeof(*eventfds_opt) +
 			sizeof(eventfds_opt->eventfds[0]) * num_rings) {
 			/* Option size not consistent with the number of
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index d126d8b38..6e302cff8 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -562,6 +562,10 @@ enum {
 	 * This requires the 'ioeventfd' fields to be valid (cannot be < 0).
 	 */
 	NETMAP_REQ_OPT_SYNC_KLOOP_MODE,
+
+	/* This is a marker to count the number of available options.
+	 * New options must be added above it. */
+	NETMAP_REQ_OPT_MAX,
 };
 
 /*

From 14fa9dad8b65a5e49eae5c408e091919b9e6f501 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Mar 2019 16:43:20 +0100
Subject: [PATCH 1635/2207] ctrl-api-test: restore EXTMEM tests

---
 utils/ctrl-api-test.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 25eb91924..e6c16d669 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1121,7 +1121,7 @@ bad_extmem_option(struct TestContext *ctx)
 	pools_info_fill(&pools_info);
 	/* Request a large ring size, to make sure that the kernel
 	 * rejects our request. */
-	pools_info.nr_ring_pool_objsize = (1 << 16);
+	pools_info.nr_ring_pool_objsize = (1 << 20);
 
 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
 }
@@ -1148,6 +1148,10 @@ duplicate_extmem_options(struct TestContext *ctx)
 	save1 = e1;
 	save2 = e2;
 
+	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
+	ctx->nr_tx_slots = 16;
+	ctx->nr_rx_slots = 16;
+
 	ret = port_register_hwall(ctx);
 	if (ret >= 0) {
 		printf("duplicate option not detected\n");

From 9f26177dd071414e1e78e9fff8040427398f6056 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Mar 2019 15:39:14 +0100
Subject: [PATCH 1636/2207] e1000: subtract the CRC size only from the last
 fragment length

---
 LINUX/if_e1000_netmap.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 9b99aec6d..b04297241 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -237,8 +237,12 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			slot = ring->slot + nm_i;
 			PNMB(na, slot, &paddr);
-			slot->len = le16toh(curr->length) - 4;
-			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
+			slot->len = le16toh(curr->length);
+			slot->flags = NS_MOREFRAG;
+			if (staterr & E1000_RXD_STAT_EOP) {
+				slot->len -= 4; /* exclude the CRC */
+				slot->flags = 0;
+			}
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);

From b3de0703caae4c4b29a06871ea32b0bf545661de Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 12:23:05 +0100
Subject: [PATCH 1637/2207] rename enable/disable option functions

---
 libnetmap/nmport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index c0956c9cd..9f872595b 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -320,7 +320,7 @@ NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p)
 
 
 void
-nmport_disable_opt(const char *opt)
+nmport_disable_option(const char *opt)
 {
 	struct nmreq_opt_parser *p;
 
@@ -332,7 +332,7 @@ nmport_disable_opt(const char *opt)
 }
 
 int
-nmport_enable_opt(const char *opt)
+nmport_enable_option(const char *opt)
 {
 	struct nmreq_opt_parser *p;
 

From 8e02fe3145358e548a93355530af08c0e57c6700 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 13:40:55 +0100
Subject: [PATCH 1638/2207] libnetmap: fix selection of default option key

---
 libnetmap/libnetmap.h |  3 ++-
 libnetmap/nmport.c    | 14 ++++++++------
 libnetmap/nmreq.c     |  2 +-
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 3dff95f5a..bbca3bd27 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -497,7 +497,8 @@ struct nmreq_opt_key {
 	int id;			/* its position in the parse context */
 	unsigned int flags;
 #define NMREQ_OPTK_ALLOWEMPTY 	(1U << 0) /* =value may be omitted */
-#define NMREQ_OPTK_NODEFAULT	(1U << 1) /* the key is mandatory */
+#define NMREQ_OPTK_MUSTSET	(1U << 1) /* the key is mandatory */
+#define NMREQ_OPTK_DEFAULT	(1U << 2) /* this is the default key */
 };
 
 /* struct nmreq_opt_parser - describes an option parser */
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 9f872595b..87714aff0 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -142,13 +142,13 @@ static struct nmreq_opt_parser *nmport_opt_parsers;
 
 #define NPOPT_PARSER(o)		nmport_opt_##o##_parser
 #define NPOPT_DESC(o)		nmport_opt_##o##_desc
-#define NPOPT_DECL(o, f, d)						\
+#define NPOPT_DECL(o, f)						\
 static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *);			\
 static struct nmreq_opt_parser NPOPT_DESC(o) = {			\
 	.prefix = #o,							\
 	.parse = NPOPT_PARSER(o),					\
 	.flags = (f),							\
-	.default_key = (d),						\
+	.default_key = -1,						\
 	.nr_keys = 0,							\
 	.next = NULL,							\
 };									\
@@ -176,6 +176,8 @@ nmport_opt_key_ctor(struct nmport_key_desc *k)
 	ok->id = k->id;
 	ok->flags = k->flags;
 	o->nr_keys++;
+	if (ok->flags & NMREQ_OPTK_DEFAULT)
+		o->default_key = ok->id;
 }
 #define NPKEY_DESC(o, k)	nmport_opt_##o##_key_##k##_desc
 #define NPKEY_ID(o, k)		(NPKEY_DESC(o, k).id)
@@ -194,16 +196,16 @@ nmport_opt_##o##_key_##k##_ctor(void)					\
 #define nmport_key(p, o, k)	((p)->keys[NPKEY_ID(o, k)])
 #define nmport_defkey(p, o)	((p)->keys[NPOPT_DESC(o).default_key])
 
-NPOPT_DECL(share, 0, 0)
-NPOPT_DECL(extmem, 0, 0)
-	NPKEY_DECL(extmem, file, NMREQ_OPTK_NODEFAULT)
+NPOPT_DECL(share, 0)
+NPOPT_DECL(extmem, 0)
+	NPKEY_DECL(extmem, file, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
 	NPKEY_DECL(extmem, if_num, 0)
 	NPKEY_DECL(extmem, if_size, 0)
 	NPKEY_DECL(extmem, ring_num, 0)
 	NPKEY_DECL(extmem, ring_size, 0)
 	NPKEY_DECL(extmem, buf_num, 0)
 	NPKEY_DECL(extmem, buf_size, 0)
-NPOPT_DECL(conf, 0, -1)
+NPOPT_DECL(conf, 0)
 	NPKEY_DECL(conf, rings, 0)
 	NPKEY_DECL(conf, host_rings, 0)
 	NPKEY_DECL(conf, slots, 0)
diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index e2c839e24..71f420df5 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -440,7 +440,7 @@ nmreq_option_parsekeys(const char *prefix, char *body, struct nmreq_opt_parser *
 	}
 	/* now check that all no-default keys have been assigned */
 	for (k = p->keys; (k - p->keys) < NMREQ_OPT_MAXKEYS && k->key != NULL; k++) {
-		if ((k->flags & NMREQ_OPTK_NODEFAULT) && pctx->keys[k->id] == NULL) {
+		if ((k->flags & NMREQ_OPTK_MUSTSET) && pctx->keys[k->id] == NULL) {
 			nmctx_ferror(pctx->ctx, "option '%s': mandatory key '%s' not assigned",
 					prefix, k->key);
 			errno = EINVAL;

From 64dddf252648dea0a8a79e10070f53b9f74fce8e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 19:14:39 +0100
Subject: [PATCH 1639/2207] libnetmap: fix wrong variable used as loop limit

---
 libnetmap/nmport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 87714aff0..d54ea310a 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -526,7 +526,7 @@ nmport_mmap(struct nmport_d *d)
 	for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++)
 		;
 	d->last_tx_ring = i - 1;
-	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i + num_tx]; i++)
+	for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++)
 		;
 	d->first_rx_ring = i;
 	num_rx = d->reg.nr_rx_rings + d->reg.nr_host_rx_rings;

From 328fcc2c933208ae2d6ba9127ab2c1a55daef016 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 19:15:22 +0100
Subject: [PATCH 1640/2207] libnetmap: use the number of host rings exposed in
 the ring header

When looping over the ring_ofs in the netmap_if, one should use
the number of host rings as exposed in the netmap_if fields,
since only those take into account the number of legacy slots.
---
 libnetmap/nmport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index d54ea310a..34e1e9ca2 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -519,7 +519,7 @@ nmport_mmap(struct nmport_d *d)
 
 	d->nifp = NETMAP_IF(m->mem, d->reg.nr_offset);
 
-	num_tx = d->reg.nr_tx_rings + d->reg.nr_host_tx_rings;
+	num_tx = d->reg.nr_tx_rings + d->nifp->ni_host_tx_rings;
 	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++)
 		;
 	d->first_tx_ring = i;
@@ -529,7 +529,7 @@ nmport_mmap(struct nmport_d *d)
 	for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++)
 		;
 	d->first_rx_ring = i;
-	num_rx = d->reg.nr_rx_rings + d->reg.nr_host_rx_rings;
+	num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings;
 	for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++)
 		;
 	d->last_rx_ring = i - 1;

From cb7cbe2a216ca8bf5f890a64d598f8718ff38469 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 19:18:20 +0100
Subject: [PATCH 1641/2207] properly restore the number of host rings on
 unregif

---
 sys/dev/netmap/netmap.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 44eebbfa1..5eda4019c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1037,8 +1037,13 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 		na->nm_krings_delete(na);
 
 		/* restore the default number of host tx and rx rings */
-		na->num_host_tx_rings = 1;
-		na->num_host_rx_rings = 1;
+		if (na->na_flags & NAF_HOST_RINGS) {
+			na->num_host_tx_rings = 1;
+			na->num_host_rx_rings = 1;
+		} else {
+			na->num_host_tx_rings = 0;
+			na->num_host_rx_rings = 0;
+		}
 	}
 
 	/* possibily decrement counter of tx_si/rx_si users */

From 9425dd9a21cb69d83edda8d4a8fe40eff9ce1d77 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Thu, 21 Mar 2019 09:53:07 +0100
Subject: [PATCH 1642/2207] utils: ctrl-api-test: add some tests for multiple
 host rings

---
 utils/ctrl-api-test.c | 67 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 50 insertions(+), 17 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index e6c16d669..d38be8536 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -139,6 +139,8 @@ struct TestContext {
 	uint32_t nr_rx_slots;   /* slots in rx rings */
 	uint16_t nr_tx_rings;   /* number of tx rings */
 	uint16_t nr_rx_rings;   /* number of rx rings */
+	uint16_t nr_host_tx_rings;   /* number of host tx rings */
+	uint16_t nr_host_rx_rings;   /* number of host rx rings */
 	uint16_t nr_mem_id;     /* id of the memory allocator */
 	uint16_t nr_ringid;     /* ring(s) we care about */
 	uint32_t nr_mode;       /* specify NR_REG_* modes */
@@ -241,6 +243,8 @@ port_register(struct TestContext *ctx)
 	req.nr_tx_slots   = ctx->nr_tx_slots;
 	req.nr_rx_slots   = ctx->nr_rx_slots;
 	req.nr_tx_rings   = ctx->nr_tx_rings;
+	req.nr_host_tx_rings = ctx->nr_host_tx_rings;
+	req.nr_host_rx_rings = ctx->nr_host_rx_rings;
 	req.nr_rx_rings   = ctx->nr_rx_rings;
 	req.nr_extra_bufs = ctx->nr_extra_bufs;
 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
@@ -254,23 +258,29 @@ port_register(struct TestContext *ctx)
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
+	printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
+	printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
 
 	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
-	                       (ctx->nr_ringid == req.nr_ringid) &&
-	                       (ctx->nr_flags == req.nr_flags) &&
-	                       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
-	                        (ctx->nr_tx_slots == req.nr_tx_slots)) &&
-	                       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
-	                        (ctx->nr_rx_slots == req.nr_rx_slots)) &&
-	                       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
-	                        (ctx->nr_tx_rings == req.nr_tx_rings)) &&
-	                       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
-	                        (ctx->nr_rx_rings == req.nr_rx_rings)) &&
-	                       ((!ctx->nr_mem_id && req.nr_mem_id) ||
-	                        (ctx->nr_mem_id == req.nr_mem_id)) &&
-	                       (ctx->nr_extra_bufs == req.nr_extra_bufs);
+		       (ctx->nr_ringid == req.nr_ringid) &&
+		       (ctx->nr_flags == req.nr_flags) &&
+		       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
+			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
+		       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
+			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
+		       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
+			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
+		       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
+			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
+		       ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
+			(ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
+		       ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
+			(ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
+		       ((!ctx->nr_mem_id && req.nr_mem_id) ||
+			(ctx->nr_mem_id == req.nr_mem_id)) &&
+		       (ctx->nr_extra_bufs == req.nr_extra_bufs);
 	if (!success) {
 		return -1;
 	}
@@ -280,6 +290,8 @@ port_register(struct TestContext *ctx)
 	ctx->nr_rx_slots   = req.nr_rx_slots;
 	ctx->nr_tx_rings   = req.nr_tx_rings;
 	ctx->nr_rx_rings   = req.nr_rx_rings;
+	ctx->nr_host_tx_rings = req.nr_host_tx_rings;
+	ctx->nr_host_rx_rings = req.nr_host_rx_rings;
 	ctx->nr_mem_id     = req.nr_mem_id;
 	ctx->nr_extra_bufs = req.nr_extra_bufs;
 
@@ -447,7 +459,7 @@ port_register_hwall_host(struct TestContext *ctx)
 }
 
 static int
-port_register_host(struct TestContext *ctx)
+port_register_hostall(struct TestContext *ctx)
 {
 	ctx->nr_mode = NR_REG_SW;
 	return port_register(ctx);
@@ -461,13 +473,32 @@ port_register_hwall(struct TestContext *ctx)
 }
 
 static int
-port_register_single_ring_couple(struct TestContext *ctx)
+port_register_single_hw_pair(struct TestContext *ctx)
 {
 	ctx->nr_mode   = NR_REG_ONE_NIC;
 	ctx->nr_ringid = 0;
 	return port_register(ctx);
 }
 
+static int
+port_register_single_host_pair(struct TestContext *ctx)
+{
+	ctx->nr_mode   = NR_REG_ONE_SW;
+	ctx->nr_host_tx_rings = 2;
+	ctx->nr_host_rx_rings = 2;
+	ctx->nr_ringid = 1;
+	return port_register(ctx);
+}
+
+static int
+port_register_hostall_many(struct TestContext *ctx)
+{
+	ctx->nr_mode   = NR_REG_SW;
+	ctx->nr_host_tx_rings = 5;
+	ctx->nr_host_rx_rings = 4;
+	return port_register(ctx);
+}
+
 static int
 port_register_hwall_tx(struct TestContext *ctx)
 {
@@ -1934,8 +1965,10 @@ static struct mytest tests[] = {
 	decltest(port_info_get),
 	decltest(port_register_hwall_host),
 	decltest(port_register_hwall),
-	decltest(port_register_host),
-	decltest(port_register_single_ring_couple),
+	decltest(port_register_hostall),
+	decltest(port_register_single_hw_pair),
+	decltest(port_register_single_host_pair),
+	decltest(port_register_hostall_many),
 	decltest(vale_attach_detach),
 	decltest(vale_attach_detach_host_rings),
 	decltest(vale_ephemeral_port_hdr_manipulation),

From 14e70804a46683ec78c2b2a2ce5da3877e0b6f06 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Apr 2019 15:01:14 +0200
Subject: [PATCH 1643/2207] linux/ixgbe: patch for Intel v5.5.5

---
 LINUX/final-patches/intel--ixgbe--5.5.5 | 171 ++++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.5.5

diff --git a/LINUX/final-patches/intel--ixgbe--5.5.5 b/LINUX/final-patches/intel--ixgbe--5.5.5
new file mode 100644
index 000000000..8dba94d53
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.5.5
@@ -0,0 +1,171 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 934a9ee..a375068 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -28,24 +28,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 2f1eb02..d29547d 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -694,6 +694,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -713,6 +730,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2192,6 +2220,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3624,6 +3662,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4245,6 +4287,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
+ }
+ 
+@@ -12099,6 +12145,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12148,6 +12198,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 597f6023bd56fbc85ae0e0ca47f9e2a1476bf49b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Apr 2019 15:01:50 +0200
Subject: [PATCH 1644/2207] linux/e1000e: patch for Intel v3.4.2.4

---
 LINUX/final-patches/intel--e1000e--3.4.2.4 | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.4.2.4

diff --git a/LINUX/final-patches/intel--e1000e--3.4.2.4 b/LINUX/final-patches/intel--e1000e--3.4.2.4
new file mode 100644
index 000000000..de3343d94
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.4.2.4
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index d285219..4e011bd 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -15,7 +15,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -118,7 +118,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -324,6 +324,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index 7f1abff..7a86734 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -483,6 +483,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1013,6 +1017,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1330,6 +1345,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4262,6 +4282,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8467,6 +8491,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8568,6 +8596,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From e9fd9c0065b6245a96f1a365914b552ebd48f768 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Tue, 2 Apr 2019 09:20:29 +0200
Subject: [PATCH 1645/2207] linux: use skb_get() to increment skb reference
 counter

---
 LINUX/netmap_linux.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 6b5d836b0..fdb436e1c 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -984,11 +984,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 
 	/* Hold a reference on this, we are going to recycle mbufs as
 	 * much as possible. */
-#ifdef NETMAP_LINUX_HAVE_REFCOUNT_T
-	refcount_inc(&m->users);
-#else  /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
-	atomic_inc(&m->users);
-#endif /* !NETMAP_LINUX_HAVE_REFCOUNT_T */
+	skb_get(m);
 
 	/* On linux m->dev is not reliable, since it can be changed by the
 	 * ndo_start_xmit() callback. This happens, for instance, with veth

From 993a3c6bcbdbf759416b8ca5a636a602d7bebfe8 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Fri, 12 Apr 2019 14:40:46 +0200
Subject: [PATCH 1646/2207] utils: ctrl-api-test: import improvements from
 FreeBSD

---
 utils/ctrl-api-test.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index d38be8536..ba423f536 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -2104,6 +2104,11 @@ main(int argc, char **argv)
 	int opt;
 	int i;
 
+#ifdef __FreeBSD__
+	PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
+	PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
+#endif
+
 	memset(&ctx_, 0, sizeof(ctx_));
 
 	{

From 58f74a05d2654524d2ee15fca4567e8dbe04c6bc Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 14 Apr 2019 10:00:17 +0200
Subject: [PATCH 1647/2207] utils: ctrl-api-test: add some comments

---
 utils/ctrl-api-test.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index ba423f536..31f9997dc 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -27,6 +27,16 @@
  * $FreeBSD$
  */
 
+/*
+ * This program contains a suite of unit tests for the netmap control device.
+ *
+ * On FreeBSD, you can run these tests with Kyua once installed in the system:
+ *     # kyua test -k /usr/tests/sys/netmap/Kyuafile
+ *
+ * On Linux, you can run them directly:
+ *     # ./ctrl-api-test
+ */
+
 #include 
 #include 
 #include 

From c6822267d3c59a0ab7ed060ff5b28c849613afb4 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Mon, 15 Apr 2019 17:24:54 +0200
Subject: [PATCH 1648/2207] ctrl-api-test: import small changes from FreeBSD

---
 utils/ctrl-api-test.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 31f9997dc..a75e21cca 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -59,16 +59,18 @@
 #include 
 #include "libnetmap.h"
 
-#ifdef __linux__
-#include 
-#else
+#ifdef __FreeBSD__
+#include "freebsd_test_suite/macros.h"
+
 static int
 eventfd(int x __unused, int y __unused)
 {
 	errno = ENODEV;
 	return -1;
 }
-#endif /* __linux__ */
+#else /* __linux__ */
+#include 
+#endif
 
 static int
 exec_command(int argc, const char *const argv[])

From 3fb20fba62dc95248b2993941aa68c430b89fdee Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 19 Apr 2019 14:26:23 +0200
Subject: [PATCH 1649/2207] linux/ixgbevf: patch for Intel v4.5.3

---
 LINUX/final-patches/intel--ixgbevf--4.5.3 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.5.3

diff --git a/LINUX/final-patches/intel--ixgbevf--4.5.3 b/LINUX/final-patches/intel--ixgbevf--4.5.3
new file mode 100644
index 000000000..9ff1cbb35
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.5.3
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index b37fbce..f3cdb26 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -69,9 +69,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 65645fb..f5d8e7b 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -358,6 +375,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif /* HAVE_XDP_BUFF_RXQ */
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		struct ixgbevf_rx_buffer *rx_buffer;
+ 		union ixgbe_adv_rx_desc *rx_desc;
+@@ -2053,6 +2091,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2287,6 +2329,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5578,8 +5624,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5620,6 +5668,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 55205fa..6c3a181 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 963cddc20fc7b0e7c74817cdd5b24040533e853d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 19 Apr 2019 14:32:31 +0200
Subject: [PATCH 1650/2207] linux/scripts: workaround for old kernels and gcc-8

---
 LINUX/scripts/np | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 5bd961d74..48a7feac0 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -382,6 +382,8 @@ function build-prep()
 			ln -s compiler-gcc5.h include/linux/compiler-gcc6.h
 		[ -e include/linux/compiler-gcc7.h ] ||
 			ln -s compiler-gcc6.h include/linux/compiler-gcc7.h
+		[ -e include/linux/compiler-gcc8.h ] ||
+			ln -s compiler-gcc7.h include/linux/compiler-gcc8.h
 		# force disabling PIE
 		sed -i -e '/^all: vmlinux/a\
 \

From a675eb3677337331e7fdd462aaaad299c67075be Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 19 Apr 2019 14:42:16 +0200
Subject: [PATCH 1651/2207] linux/configure: avoid false negatives with gcc8

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 3b5722656..9c34b66a1 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -451,7 +451,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS := -Werror -Wno-error=unused-but-set-variable
+EXTRA_CFLAGS := -Werror -Wno-error=unused-but-set-variable -Wno-error=attributes -Wno-error=packed-not-aligned
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)

From f19f286581b4a52c087071fac64737ce9087f6a0 Mon Sep 17 00:00:00 2001
From: Jeff Davey 
Date: Tue, 30 Apr 2019 16:04:55 -0600
Subject: [PATCH 1652/2207] Make sure num_rx is correctly initialized

---
 libnetmap/nmport.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 34e1e9ca2..21dc7cbff 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -526,10 +526,11 @@ nmport_mmap(struct nmport_d *d)
 	for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++)
 		;
 	d->last_tx_ring = i - 1;
+
+	num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings;
 	for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++)
 		;
 	d->first_rx_ring = i;
-	num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings;
 	for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++)
 		;
 	d->last_rx_ring = i - 1;

From 94f66067889e385d169bba38918ecc62f4da819c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 6 May 2019 12:52:06 +0200
Subject: [PATCH 1653/2207] linux: check for vm_fault_t

---
 LINUX/configure      | 9 +++++++++
 LINUX/netmap_linux.c | 4 ++++
 2 files changed, 13 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 9c34b66a1..0c6560346 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1661,6 +1661,15 @@ EOF
 	}
 EOF
 
+   # is vm_fault_t defined?
+   add_test 'have VMFAULT_T' <
+
+	vm_fault_t dummy(void) {
+		return 0;
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index fdb436e1c..2c873f72d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1209,7 +1209,11 @@ linux_netmap_poll(struct file *file, struct poll_table_struct *pwait)
 	return netmap_poll(priv, events, &sr);
 }
 
+#ifdef NETMAP_LINUX_HAVE_VMFAULT_T
+static vm_fault_t
+#else
 static int
+#endif /* NETMAP_LINUX_HAVE_VMFAULT_T */
 #ifdef NETMAP_LINUX_HAVE_FAULT_VMA_ARG
 linux_netmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {

From 42bb49dedc9c645ef7f9a5a239604323b7ac4bd0 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 18 May 2019 00:31:37 +0200
Subject: [PATCH 1654/2207] freebsd: import if_ptnet change from upstream

Align if_ptnet to the changes introduced by r347233

This removes non-functional SCTP checksum offload support.
More information in the log message of r347233.
---
 sys/dev/netmap/if_ptnet.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 5ba34aa67..468ebabe9 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -68,7 +68,6 @@
 #include 
 #include 
 #include 
-#include 
 
 #include 
 #include 
@@ -281,9 +280,8 @@ static inline void ptnet_kick(struct ptnet_queue *pq)
 #define PTNET_HDR_SIZE		sizeof(struct virtio_net_hdr_mrg_rxbuf)
 #define PTNET_MAX_PKT_SIZE	65536
 
-#define PTNET_CSUM_OFFLOAD	(CSUM_TCP | CSUM_UDP | CSUM_SCTP)
-#define PTNET_CSUM_OFFLOAD_IPV6	(CSUM_TCP_IPV6 | CSUM_UDP_IPV6 |\
-				 CSUM_SCTP_IPV6)
+#define PTNET_CSUM_OFFLOAD	(CSUM_TCP | CSUM_UDP)
+#define PTNET_CSUM_OFFLOAD_IPV6	(CSUM_TCP_IPV6 | CSUM_UDP_IPV6)
 #define PTNET_ALL_OFFLOAD	(CSUM_TSO | PTNET_CSUM_OFFLOAD |\
 				 PTNET_CSUM_OFFLOAD_IPV6)
 
@@ -1539,9 +1537,6 @@ ptnet_rx_csum_by_offset(struct mbuf *m, uint16_t eth_type, int ip_start,
 		m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
 		m->m_pkthdr.csum_data = 0xFFFF;
 		break;
-	case offsetof(struct sctphdr, checksum):
-		m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
-		break;
 	default:
 		/* Here we should increment the rx_csum_bad_offset counter. */
 		return (1);
@@ -1596,11 +1591,6 @@ ptnet_rx_csum_by_parse(struct mbuf *m, uint16_t eth_type, int ip_start,
 		m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
 		m->m_pkthdr.csum_data = 0xFFFF;
 		break;
-	case IPPROTO_SCTP:
-		if (__predict_false(m->m_len < offset + sizeof(struct sctphdr)))
-			return (1);
-		m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
-		break;
 	default:
 		/*
 		 * For the remaining protocols, FreeBSD does not support

From 4347493e853b0f78b03264e8160665a25a75d994 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 May 2019 12:07:43 +0200
Subject: [PATCH 1655/2207] linux/configure: automatically find out which
 warnings are recognized by cc

---
 LINUX/configure | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 0c6560346..2ce3f1f75 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -446,12 +446,17 @@ EOF
 #   success/failure actions for each one.
 run_tests() {
 	ln -s $BUILDDIR/patches $TMPDIR
+	echo 'int main(){return 0;}' > $TMPDIR/dummy.c
+	echo 'gcc -Wno-error=$1 dummy.c >/dev/null 2>&1 && echo ok' > $TMPDIR/dummy.sh
+	chmod +x $TMPDIR/dummy.sh
 	cat > $TMPDIR/Makefile <
Date: Mon, 20 May 2019 13:58:26 +0200
Subject: [PATCH 1656/2207] linux/configure: move buildsystem-related tests to
 a preliminary phase

---
 LINUX/configure | 116 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 90 insertions(+), 26 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 2ce3f1f75..458de0537 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -442,21 +442,69 @@ reset_tests() {
 EOF
 }
 
+# run_preliminary_tests: this must be run before run_tests. It checks some
+# options related to the build system itself and sets some variables later
+# used by run_tests.
+run_preliminary_tests() {
+	{
+		cat < $TMPDIR/Makefile
+	NPROC=$(grep -c processor /proc/cpuinfo)
+	MAKE_OPT=-O
+	{
+		cat <> config.log
+	(
+		cd $TMPDIR
+		LANG=C make $MAKE_OPT -k -j $NPROC
+	) >> config.log
+	if grep -q ": invalid option -- 'O'" config.log; then
+		MAKE_OPT=
+		# let us try again without -O
+		(
+			cd $TMPDIR
+			make -k -j $NPROC
+		) >> config.log
+	fi
+	eval "$TESTPOSTPROC"
+	cat >> config.log < $TMPDIR/dummy.c
-	echo 'gcc -Wno-error=$1 dummy.c >/dev/null 2>&1 && echo ok' > $TMPDIR/dummy.sh
-	chmod +x $TMPDIR/dummy.sh
 	cat > $TMPDIR/Makefile <> config.log
-	NPROC=$(grep -c processor /proc/cpuinfo)
 	(
 		cd $TMPDIR
-		LANG=C make -O -k -j $NPROC
+		make $MAKE_OPT -k -j $NPROC
 	) >> config.log
-	if grep -q ": invalid option -- 'O'" config.log; then
-		# let us try again without -O
-		(
-			cd $TMPDIR
-			make -k -j $NPROC
-		) >> config.log
-	fi
 	eval "$TESTPOSTPROC"
 	cat >> config.log <> $TMPDIR/extra.mk
+	i=$(($i+1))
+done
+
+  message " NOTE  " <
Date: Tue, 28 May 2019 09:50:47 +0200
Subject: [PATCH 1657/2207] linux/scripts: ignore missing netmap_linux_config.h

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 48a7feac0..cd111d24d 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -504,7 +504,7 @@ function check-patch()
 			(make get-$driver && make -j $PARALLEL_MAKE) >>$log 2>&1 && ok=true
 			grep -q warning: $log && { warn=true; echo $warn > $cwarn; }
 			cat config.log >>$log
-			cat netmap_linux_config.h >>$log
+			cat netmap_linux_config.h >>$log 2>/dev/null
 			popd >/dev/null
 			cp $log $clog
 		fi

From 689fbe079f4713b1adac9b2791764e775f79d621 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 May 2019 09:52:49 +0200
Subject: [PATCH 1658/2207] linux/configure: fix indentation in generated tests

---
 LINUX/configure | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 458de0537..8e0c6aeb0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -396,9 +396,9 @@ EOF
 add_named_test() {
 	{
 		cat <
-			#include 
-			#include 
+	#include 
+	#include 
+	#include 
 EOF
 		cat	# output the test code read from stdin
 	} > $TMPDIR/$1.c

From 3bdd5a38200ffbab9b3bbf390c21ec744dbe9760 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 May 2019 09:56:48 +0200
Subject: [PATCH 1659/2207] linux/configure: more robust preliminary tests

---
 LINUX/configure | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 8e0c6aeb0..1134e19d0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -454,7 +454,6 @@ EOF
 		if [ -e $TMPDIR/extra.mk ]; then cat $TMPDIR/extra.mk; fi
 		cat <
Date: Tue, 28 May 2019 09:57:34 +0200
Subject: [PATCH 1660/2207] linux/i40e: patch for Intel 2.8.43 version

---
 LINUX/final-patches/intel--i40e--2.8.43 | 167 ++++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.8.43

diff --git a/LINUX/final-patches/intel--i40e--2.8.43 b/LINUX/final-patches/intel--i40e--2.8.43
new file mode 100644
index 000000000..e133f8578
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.8.43
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 5b3ca74..79db7aa 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 54940ba..f9e79b7 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -136,6 +136,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3481,6 +3486,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3534,6 +3543,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3562,6 +3575,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13729,6 +13747,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14101,6 +14124,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index c3ebcd7..dba28f9 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2558,6 +2567,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 24cd91273f6f0c30c0808ba6b26bfa91787839a1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 May 2019 10:32:20 +0200
Subject: [PATCH 1661/2207] linux/i40e: fix warning

---
 LINUX/final-patches/intel--i40e--2.7.11 | 15 +++++++--------
 LINUX/final-patches/intel--i40e--2.7.12 | 15 +++++++--------
 LINUX/final-patches/intel--i40e--2.7.26 | 15 +++++++--------
 LINUX/final-patches/intel--i40e--2.7.29 | 15 +++++++--------
 LINUX/final-patches/intel--i40e--2.8.43 | 15 +++++++--------
 5 files changed, 35 insertions(+), 40 deletions(-)

diff --git a/LINUX/final-patches/intel--i40e--2.7.11 b/LINUX/final-patches/intel--i40e--2.7.11
index dbb9b6d03..1cb4da058 100644
--- a/LINUX/final-patches/intel--i40e--2.7.11
+++ b/LINUX/final-patches/intel--i40e--2.7.11
@@ -123,7 +123,7 @@ index 86d76c0..5629a97 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..ea1be59 100644
+index 1859d78..4d19c85 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -149,9 +149,9 @@ index 1859d78..ea1be59 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false, xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -161,7 +161,6 @@ index 1859d78..ea1be59 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.7.12 b/LINUX/final-patches/intel--i40e--2.7.12
index 8d8cd2530..81e19cf01 100644
--- a/LINUX/final-patches/intel--i40e--2.7.12
+++ b/LINUX/final-patches/intel--i40e--2.7.12
@@ -123,7 +123,7 @@ index 6f8e9b4..a62aadd 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..ea1be59 100644
+index 1859d78..4d19c85 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -149,9 +149,9 @@ index 1859d78..ea1be59 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false, xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -161,7 +161,6 @@ index 1859d78..ea1be59 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.7.26 b/LINUX/final-patches/intel--i40e--2.7.26
index 242a42fe2..c61a0cc0e 100644
--- a/LINUX/final-patches/intel--i40e--2.7.26
+++ b/LINUX/final-patches/intel--i40e--2.7.26
@@ -123,7 +123,7 @@ index 6d2e21d..9845b9d 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..ea1be59 100644
+index 1859d78..4d19c85 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -149,9 +149,9 @@ index 1859d78..ea1be59 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false, xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -161,7 +161,6 @@ index 1859d78..ea1be59 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.7.29 b/LINUX/final-patches/intel--i40e--2.7.29
index 09ab66da8..e40bd4d3f 100644
--- a/LINUX/final-patches/intel--i40e--2.7.29
+++ b/LINUX/final-patches/intel--i40e--2.7.29
@@ -123,7 +123,7 @@ index 1914934..c1dcee9 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..ea1be59 100644
+index 1859d78..4d19c85 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -149,9 +149,9 @@ index 1859d78..ea1be59 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false, xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -161,7 +161,6 @@ index 1859d78..ea1be59 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.8.43 b/LINUX/final-patches/intel--i40e--2.8.43
index e133f8578..0ee33c6e9 100644
--- a/LINUX/final-patches/intel--i40e--2.8.43
+++ b/LINUX/final-patches/intel--i40e--2.8.43
@@ -123,7 +123,7 @@ index 54940ba..f9e79b7 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index c3ebcd7..dba28f9 100644
+index c3ebcd7..ea86118 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -149,9 +149,9 @@ index c3ebcd7..dba28f9 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2558,6 +2567,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2554,6 +2563,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -161,7 +161,6 @@ index c3ebcd7..dba28f9 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From edde1d8028b152e02864f84307e20440dfcd42bc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 28 May 2019 11:09:07 +0200
Subject: [PATCH 1662/2207] linux/ixgbevf: fix warning

---
 LINUX/final-patches/intel--ixgbevf--4.5.1 | 14 +++++++-------
 LINUX/final-patches/intel--ixgbevf--4.5.2 | 14 +++++++-------
 LINUX/final-patches/intel--ixgbevf--4.5.3 | 14 +++++++-------
 3 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/LINUX/final-patches/intel--ixgbevf--4.5.1 b/LINUX/final-patches/intel--ixgbevf--4.5.1
index e9dc8b724..6acdca530 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.5.1
+++ b/LINUX/final-patches/intel--ixgbevf--4.5.1
@@ -46,7 +46,7 @@ index 18d35f3..c4ae238 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 139aaf7..5df106d 100644
+index 139aaf7..c03cb9e 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -91,9 +91,9 @@ index 139aaf7..5df106d 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif /* HAVE_XDP_BUFF_RXQ */
+@@ -1355,6 +1383,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -105,9 +105,9 @@ index 139aaf7..5df106d 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		struct ixgbevf_rx_buffer *rx_buffer;
- 		union ixgbe_adv_rx_desc *rx_desc;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -2053,6 +2091,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
  	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
  	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
diff --git a/LINUX/final-patches/intel--ixgbevf--4.5.2 b/LINUX/final-patches/intel--ixgbevf--4.5.2
index 72e94aedf..38d9cfd79 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.5.2
+++ b/LINUX/final-patches/intel--ixgbevf--4.5.2
@@ -46,7 +46,7 @@ index b37fbce..f3cdb26 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 05fb3b2..2c86986 100644
+index 05fb3b2..a3896de 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -91,9 +91,9 @@ index 05fb3b2..2c86986 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif /* HAVE_XDP_BUFF_RXQ */
+@@ -1355,6 +1383,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -105,9 +105,9 @@ index 05fb3b2..2c86986 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		struct ixgbevf_rx_buffer *rx_buffer;
- 		union ixgbe_adv_rx_desc *rx_desc;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -2053,6 +2091,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
  	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
  	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
diff --git a/LINUX/final-patches/intel--ixgbevf--4.5.3 b/LINUX/final-patches/intel--ixgbevf--4.5.3
index 9ff1cbb35..9de45aa16 100644
--- a/LINUX/final-patches/intel--ixgbevf--4.5.3
+++ b/LINUX/final-patches/intel--ixgbevf--4.5.3
@@ -46,7 +46,7 @@ index b37fbce..f3cdb26 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 65645fb..f5d8e7b 100644
+index 65645fb..4ab32c4 100644
 --- a/ixgbevf/ixgbevf_main.c
 +++ b/ixgbevf/ixgbevf_main.c
 @@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
@@ -91,9 +91,9 @@ index 65645fb..f5d8e7b 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif /* HAVE_XDP_BUFF_RXQ */
+@@ -1355,6 +1383,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -105,9 +105,9 @@ index 65645fb..f5d8e7b 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		struct ixgbevf_rx_buffer *rx_buffer;
- 		union ixgbe_adv_rx_desc *rx_desc;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -2053,6 +2091,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
  	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
  	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);

From f392508fc896ecac11b4561ac7c9830403c956f7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Wed, 29 May 2019 00:33:20 +0200
Subject: [PATCH 1663/2207] utils: randomized_tests: check for bc program

---
 utils/randomized_tests | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/utils/randomized_tests b/utils/randomized_tests
index 49b12f40d..0d870ef62 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -90,6 +90,12 @@ if [ "$?" != "0" ]; then
 	exit 1
 fi
 
+which bc
+if [ "$?" != "0" ]; then
+	echo "bc program not not found"
+	exit 1
+fi
+
 random_num="$((65 + $RANDOM % 58))"
 # https://stackoverflow.com/a/10503163
 random_fill=$(printf \\$(printf '%03o' $random_num))

From 042a0ea114038dca72457e4c30027d4d13c68d8f Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 29 May 2019 15:03:19 +0200
Subject: [PATCH 1664/2207] linux/e1000: use wmb instead of mmiowb

---
 LINUX/if_e1000_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index b04297241..fc5afcaba 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -153,7 +153,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 		txr->next_to_use = nic_i; /* XXX what for ? */
 		/* (re)start the tx unit up to slot nic_i (excluded) */
 		writel(nic_i, adapter->hw.hw_addr + txr->tdt);
-		mmiowb(); // XXX where do we need this ?
+		wmb(); // XXX where do we need this ?
 	}
 
 	/*

From eb5f79fba13224c707feb10afb5d77ad749f1bf7 Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sun, 2 Jun 2019 20:41:19 +0200
Subject: [PATCH 1665/2207] virtio-net: remove leftover memory barrier

---
 LINUX/if_virtio_net_netmap.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/if_virtio_net_netmap.h b/LINUX/if_virtio_net_netmap.h
index 7578165f7..5a526c1de 100644
--- a/LINUX/if_virtio_net_netmap.h
+++ b/LINUX/if_virtio_net_netmap.h
@@ -807,7 +807,6 @@ virtio_net_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 	virtqueue_disable_cb(vq);
 
-	rmb();
 	/*
 	 * First part: import newly received packets.
 	 * Only accept our own buffers (matching the token). We should only get

From 70e8684fc5f022ab2285e231d50e52c0bf8bc592 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jul 2019 10:27:19 +0200
Subject: [PATCH 1666/2207] linux/e1000e: use wmb() instead of mmiowb()

---
 LINUX/if_e1000e_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 0fba6c280..7c69018dc 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -181,7 +181,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		txr->next_to_use = nic_i; /* for consistency */
 		NM_WR_TX_TAIL(nic_i);
-		mmiowb(); /* needed after writing to TX ring tail */
+		wmb(); /* needed after writing to TX ring tail */
 	}
 
 	/*

From 3aa7d13aca4df66c744ff5868856d41951dda975 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jul 2019 10:27:40 +0200
Subject: [PATCH 1667/2207] linux/igb: use wmb() instead of mmiowb()

---
 LINUX/if_igb_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 5c841c2b0..4db19f1f8 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -238,7 +238,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		/* (re)start the tx unit up to slot nic_i (excluded) */
 		writel(nic_i, txr->tail);
-		mmiowb();
+		wmb();
 	}
 
 	/*

From 77e568625198df39676a07b868db5b2d4b3ed265 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jul 2019 11:11:46 +0200
Subject: [PATCH 1668/2207] linux/ixgbe: patch for Intel 5.6.1 version

---
 LINUX/configure                         |   3 +-
 LINUX/default-config.mak.in_            |   1 +
 LINUX/final-patches/intel--ixgbe--5.6.1 | 173 ++++++++++++++++++++++++
 3 files changed, 176 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.6.1

diff --git a/LINUX/configure b/LINUX/configure
index 1134e19d0..300544eb0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -280,6 +280,7 @@ replace_vars()
 		-e "s|@DESTDIR@|$DESTDIR|g" \
 		-e "s|@DEBUG@|$DEBUG|g" \
 		-e "s|@UTILS@|$UTILS|g" \
+		-e "s|@REC_DISABLED_WARNINGS@|$REC_DISABLED_WARNINGS|g" \
 		$1
 }
 
@@ -981,7 +982,7 @@ EOF
 
   add_test true broken_buildsystem < /dev/null
 
-DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned"
+DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index d0e7e0e75..7d4d22a2f 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -78,6 +78,7 @@ endef
 # some additional, driver-specific CFLAGS (used in the @build variable above)
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
+ixgbe@cflags := @REC_DISABLED_WARNINGS@
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))
diff --git a/LINUX/final-patches/intel--ixgbe--5.6.1 b/LINUX/final-patches/intel--ixgbe--5.6.1
new file mode 100644
index 000000000..75fc830ed
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.6.1
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index e613859..8ca5eaa 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index c2bcd19..72bcd0f 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -706,6 +706,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -725,6 +742,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2195,6 +2223,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3656,6 +3694,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4332,6 +4374,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12896,6 +12944,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12951,6 +13003,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From a1f1b3d76a629ae0d53a9f375666a277616fccc1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jul 2019 11:12:13 +0200
Subject: [PATCH 1669/2207] linux/ixgbevf: patch for Intel 4.6.1 version

---
 LINUX/final-patches/intel--ixgbevf--4.6.1 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.6.1

diff --git a/LINUX/final-patches/intel--ixgbevf--4.6.1 b/LINUX/final-patches/intel--ixgbevf--4.6.1
new file mode 100644
index 000000000..5d7ad559a
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.6.1
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index b37fbce..f3cdb26 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -69,9 +69,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 15480dc..494d9e8 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -358,6 +375,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1356,6 +1384,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2054,6 +2092,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2288,6 +2330,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5582,8 +5628,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5624,6 +5672,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 2d1b428..e98c520 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 6ba47efcacae98930b6c8960ae0a766993728036 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 8 Jul 2019 11:12:37 +0200
Subject: [PATCH 1670/2207] linux/igb: patch for Intel 5.3.5.36 version

---
 LINUX/final-patches/intel--igb--5.3.5.36 | 138 +++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.36

diff --git a/LINUX/final-patches/intel--igb--5.3.5.36 b/LINUX/final-patches/intel--igb--5.3.5.36
new file mode 100644
index 000000000..06d8999cc
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.36
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 924ae5b..0a5f720 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 79a3c38..a9a8be5 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -237,6 +237,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3178,6 +3182,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3383,6 +3391,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3795,6 +3807,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7467,6 +7482,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8483,6 +8503,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8802,6 +8827,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 42270fcabc11a0a72b8b8674e5104f60086a3eab Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 18 Jul 2019 15:57:27 +0200
Subject: [PATCH 1671/2207] pkt-gen: fix small error in bw computation

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 01f08a210..eacd42769 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2634,7 +2634,7 @@ main_thread(struct glob_arg *g)
 		D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space",
 			norm(b1, pps, normalize), b4,
 			norm(b2, (double)x.pkts, normalize),
-			norm(b3, (double)x.bytes*8+(double)x.pkts*g->framing, normalize),
+			norm(b3, 1000000*((double)x.bytes*8+(double)x.pkts*g->framing)/usec, normalize),
 			(unsigned long long)usec,
 			abs, (int)cur.min_space);
 		prev = cur;

From fa36d8bbcfe00a95a5dfd52a880f23c427422dd1 Mon Sep 17 00:00:00 2001
From: Jeff Davey 
Date: Tue, 30 Jul 2019 11:24:02 -0600
Subject: [PATCH 1672/2207] Use size_t instead of u_int for total memory.

In testing, when using buf_num over 420,000 or so, with the default
clusternumbers, we run into integer overflow and segfault.

In our environment, we have 40 core servers (20+20) with the nics using
40 tx/rx rings, with the ring slot size set to 4096. We have to set the
buf_num to about 750000 in order to allocate enough memory for our
application to load with around 100000 extra buffers.

This segfaults without this change.

This is basically adapted from issue #602. I left the max buffers at the
default of 1_000_000 and changed some %lu and %ld to %zu %zd
---
 extra/python/netmap_manager.c |  2 +-
 share/man/man4/netmap.4       |  2 +-
 sys/dev/netmap/netmap_mem2.c  | 29 +++++++++++++++--------------
 sys/net/netmap_legacy.h       |  2 +-
 sys/net/netmap_user.h         |  4 ++--
 utils/ctrl-api-test.c         |  6 +++---
 utils/testmmap.c              |  6 +++---
 7 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/extra/python/netmap_manager.c b/extra/python/netmap_manager.c
index c8ba3af07..8bfd749d0 100644
--- a/extra/python/netmap_manager.c
+++ b/extra/python/netmap_manager.c
@@ -154,7 +154,7 @@ NetmapManager_repr(NetmapManager *self)
             "dev_name:  '%s'\n"
             "if_name:   '%s'\n"
             "version:   %d\n"
-            "memsize:   %u KiB\n"
+            "memsize:   %zu KiB\n"
             "offset:    %u\n"
             "tx_slots:  %d\n"
             "rx_slots:  %d\n"
diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index cbdd55435..e7b6e1671 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -552,7 +552,7 @@ struct nmreq {
     char      nr_name[IFNAMSIZ]; /* (i) port name                  */
     uint32_t  nr_version;        /* (i) API version                */
     uint32_t  nr_offset;         /* (o) nifp offset in mmap region */
-    uint32_t  nr_memsize;        /* (o) size of the mmap region    */
+    size_t    nr_memsize;        /* (o) size of the mmap region    */
     uint32_t  nr_tx_slots;       /* (i/o) slots in tx rings        */
     uint32_t  nr_rx_slots;       /* (i/o) slots in rx rings        */
     uint16_t  nr_tx_rings;       /* (i/o) number of tx rings       */
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 3f056c2ad..2d3221b81 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -100,16 +100,17 @@ struct netmap_obj_pool {
 	/* ---------------------------------------------------*/
 	/* these are only meaningful if the pool is finalized */
 	/* (see 'finalized' field in netmap_mem_d)            */
-	u_int objtotal;         /* actual total number of objects. */
-	u_int memtotal;		/* actual total memory space */
-	u_int numclusters;	/* actual number of clusters */
-
-	u_int objfree;          /* number of free objects. */
+	size_t memtotal;	/* actual total memory space */
 
 	struct lut_entry *lut;  /* virt,phys addresses, objtotal entries */
 	uint32_t *bitmap;       /* one bit per buffer, 1 means free */
 	uint32_t *invalid_bitmap;/* one bit per buffer, 1 means invalid */
 	uint32_t bitmap_slots;	/* number of uint32 entries in bitmap */
+
+	u_int objtotal;         /* actual total number of objects. */
+	u_int numclusters;	/* actual number of clusters */
+	u_int objfree;          /* number of free objects. */
+
 	int	alloc_done;	/* we have allocated the memory */
 	/* ---------------------------------------------------*/
 
@@ -159,7 +160,7 @@ struct netmap_mem_ops {
 
 struct netmap_mem_d {
 	NMA_LOCK_T nm_mtx;  /* protect the allocator */
-	u_int nm_totalsize; /* shorthand */
+	size_t nm_totalsize; /* shorthand */
 
 	u_int flags;
 #define NETMAP_MEM_FINALIZED	0x1	/* preallocation done */
@@ -817,7 +818,7 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
 		return pa;
 	}
 	/* this is only in case of errors */
-	nm_prerr("invalid ofs 0x%x out of 0x%x 0x%x 0x%x", (u_int)o,
+	nm_prerr("invalid ofs 0x%x out of 0x%zx 0x%zx 0x%zx", (u_int)o,
 		p[NETMAP_IF_POOL].memtotal,
 		p[NETMAP_IF_POOL].memtotal
 			+ p[NETMAP_RING_POOL].memtotal,
@@ -947,7 +948,7 @@ netmap_mem2_get_info(struct netmap_mem_d* nmd, uint64_t* size,
 			*size = 0;
 			for (i = 0; i < NETMAP_POOLS_NR; i++) {
 				struct netmap_obj_pool *p = nmd->pools + i;
-				*size += (p->_numclusters * p->_clustsize);
+				*size += ((size_t)p->_numclusters * (size_t)p->_clustsize);
 			}
 		}
 	}
@@ -1476,9 +1477,9 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 #endif
 		}
 	}
-	p->memtotal = p->numclusters * p->_clustsize;
+	p->memtotal = (size_t)p->numclusters * (size_t)p->_clustsize;
 	if (netmap_verbose)
-		nm_prinf("Pre-allocated %d clusters (%d/%dKB) for '%s'",
+		nm_prinf("Pre-allocated %d clusters (%d/%zuKB) for '%s'",
 		    p->numclusters, p->_clustsize >> 10,
 		    p->memtotal >> 10, p->name);
 
@@ -1639,7 +1640,7 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
 	nmd->flags |= NETMAP_MEM_FINALIZED;
 
 	if (netmap_verbose)
-		nm_prinf("interfaces %d KB, rings %d KB, buffers %d MB",
+		nm_prinf("interfaces %zd KB, rings %zd KB, buffers %zd MB",
 		    nmd->pools[NETMAP_IF_POOL].memtotal >> 10,
 		    nmd->pools[NETMAP_RING_POOL].memtotal >> 10,
 		    nmd->pools[NETMAP_BUF_POOL].memtotal >> 20);
@@ -2341,8 +2342,8 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		}
 		p->objtotal = j;
 		p->numclusters = p->objtotal;
-		p->memtotal = j * p->_objsize;
-		nm_prdis("%d memtotal %u", j, p->memtotal);
+		p->memtotal = j * (size_t)p->_objsize;
+		nm_prdis("%d memtotal %zu", j, p->memtotal);
 	}
 
 	netmap_mem_ext_register(nme);
@@ -2573,7 +2574,7 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 
 	ptnmd->buf_lut.objtotal = nbuffers;
 	ptnmd->buf_lut.objsize = bufsize;
-	nmd->nm_totalsize = (unsigned int)mem_size;
+	nmd->nm_totalsize = mem_size;
 
 	/* Initialize these fields as are needed by
 	 * netmap_mem_bufsize().
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index f1dd7d625..531434427 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -152,7 +152,7 @@ struct nmreq {
 	char		nr_name[IFNAMSIZ];
 	uint32_t	nr_version;	/* API version */
 	uint32_t	nr_offset;	/* nifp offset in the shared region */
-	uint32_t	nr_memsize;	/* size of the shared region */
+	size_t	        nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 0ed785158..bf50afcbc 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -117,7 +117,7 @@
 		(nifp)->ni_host_tx_rings] )
 
 #define NETMAP_BUF(ring, index)				\
-	((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
+	((char *)(ring) + (ring)->buf_ofs + ((size_t)(index)*(ring)->nr_buf_size))
 
 #define NETMAP_BUF_IDX(ring, buf)			\
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
@@ -254,7 +254,7 @@ struct nm_desc {
 	struct nm_desc *self; /* point to self if netmap. */
 	int fd;
 	void *mem;
-	uint32_t memsize;
+	size_t memsize;
 	int done_mmap;	/* set if mem is the result of mmap */
 	struct netmap_if * const nifp;
 	uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a75e21cca..1b12ea187 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -206,7 +206,7 @@ port_info_get(struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
-	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
+	printf("nr_memsize %zu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
@@ -265,7 +265,7 @@ port_register(struct TestContext *ctx)
 		return ret;
 	}
 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
-	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
+	printf("nr_memsize %zu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
@@ -339,7 +339,7 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	}
 
 	printf("nr_offset 0x%x\n", req.nr_offset);
-	printf("nr_memsize  %u\n", req.nr_memsize);
+	printf("nr_memsize  %zu\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 89cbe4196..544c7dc26 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1036,11 +1036,11 @@ do_nmr_legacy_dump()
 	printf("name:      %s\n", nmr_name);
 	printf("version:   %d\n", curr_nmr.nr_version);
 	printf("offset:    %d\n", curr_nmr.nr_offset);
-	printf("memsize:   %d [", curr_nmr.nr_memsize);
+	printf("memsize:   %zu [", curr_nmr.nr_memsize);
 	if (curr_nmr.nr_memsize < (1 << 20)) {
-		printf("%d KiB", curr_nmr.nr_memsize >> 10);
+		printf("%zu KiB", curr_nmr.nr_memsize >> 10);
 	} else {
-		printf("%d MiB", curr_nmr.nr_memsize >> 20);
+		printf("%zu MiB", curr_nmr.nr_memsize >> 20);
 	}
 	printf("]\n");
 	printf("tx_slots:  %d\n", curr_nmr.nr_tx_slots);

From 453070d0d29046826a46b0674c539e10d3c15c8e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Jul 2019 09:24:18 +0200
Subject: [PATCH 1673/2207] linux/e1000e: patch for Intel 3.5.1 version

---
 LINUX/final-patches/intel--e1000e--3.5.1 | 110 +++++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.5.1

diff --git a/LINUX/final-patches/intel--e1000e--3.5.1 b/LINUX/final-patches/intel--e1000e--3.5.1
new file mode 100644
index 000000000..967c5b550
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.5.1
@@ -0,0 +1,110 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index 7e6d8c8..639da1a 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -15,7 +15,7 @@ ifeq (,$(BUILD_KERNEL))
+ BUILD_KERNEL=$(shell uname -r)
+ endif
+ 
+-DRIVER_NAME = e1000e
++DRIVER_NAME = e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ###########################################################################
+ # Environment tests
+@@ -118,7 +118,7 @@ ifeq ($(ARCH),ppc64)
+ endif
+ 
+ # extra flags for module builds
+-EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
++EXTRA_CFLAGS += -DDRIVER_$(shell echo $(DRIVER_NAME) | tr '[a-z-]' '[A-Z_]')
+ EXTRA_CFLAGS += -DDRIVER_NAME=$(DRIVER_NAME)
+ EXTRA_CFLAGS += -DDRIVER_NAME_CAPS=$(shell echo $(DRIVER_NAME) | tr '[a-z]' '[A-Z]')
+ # standard flags for module builds
+@@ -324,6 +324,9 @@ DEPVER := $(shell /sbin/depmod -V 2>/dev/null | \
+ $(MANFILE).gz: ../$(MANFILE)
+ 	gzip -c $< > $@
+ 
++../$(MANFILE):
++	touch $@
++
+ install: default $(MANFILE).gz
+ 	# remove all old versions of the driver
+ 	find $(INSTALL_MOD_PATH)/lib/modules/$(KVER) -name $(TARGET) -exec rm -f {} \; || true
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index 7402857..ec84246 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -483,6 +483,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1013,6 +1017,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1330,6 +1345,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4262,6 +4282,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8473,6 +8497,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8574,6 +8602,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 13c73a82d3702023d0c89a76ca2db02191f7d980 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Aug 2019 17:35:15 +0200
Subject: [PATCH 1674/2207] linux/configure: recognize new 3-parms
 ndo_select_queue

---
 LINUX/configure      | 21 ++++++++++++++++++++-
 LINUX/netmap_linux.c |  4 ++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 300544eb0..5ec19efac 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1155,7 +1155,8 @@ EOF
   done
 
   # type of the 3rd param of ndo_select_queue
-  add_test 'define SELECT_QUEUE_PARM3 "struct net_device*"' 'define SELECT_QUEUE_PARM3 "void*"' <
 
 	static u16 myselect(struct net_device *dev, struct sk_buff *skb,
@@ -1172,6 +1173,24 @@ EOF
 	};
 EOF
 
+  # type of the 3rd param of ndo_select_queue
+  # defaults to void* if not defined
+  add_test 'define SELECT_QUEUE_PARM3 "struct net_device*"' <
+
+	static u16 myselect(struct net_device *dev, struct sk_buff *skb,
+		struct net_device *sb_dev)
+	{
+		(void)dev;
+		(void)skb;
+		(void)sb_dev;
+		return 0;
+	}
+	struct net_device_ops ndo = {
+		.ndo_select_queue = myselect,
+	};
+EOF
+
   # ethtool get_ringparam
   add_test 'have GET_RINGPARAM' <
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 2c873f72d..bcc187ee0 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -599,6 +599,10 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 #endif /* HAVE_RX_REGISTER */
 }
 
+#ifndef NETMAP_LINUX_SELECT_QUEUE_PARM3
+#define NETMAP_LINUX_SELECT_QUEUE_PARM3 void*
+#endif /*! NETMAP_LINUX_SELECT_QUEUE_PARM3 */
+
 #ifdef NETMAP_LINUX_SELECT_QUEUE
 static u16
 generic_ndo_select_queue(struct ifnet *ifp, struct mbuf *m

From 27452be91cd4ec7e6a06bc7ee59c97d5fd94ac00 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 25 Aug 2019 18:00:19 +0200
Subject: [PATCH 1675/2207] import changes from freebsd head

---
 apps/lb/lb.c                    | 2 +-
 sys/dev/netmap/netmap_freebsd.c | 6 +++++-
 sys/dev/netmap/netmap_generic.c | 5 +++--
 sys/dev/netmap/netmap_mem2.c    | 4 ++--
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index de4cde688..f162cc4f5 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -652,7 +652,7 @@ int main(int argc, char **argv)
 	/* extract the base name */
 	char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ?
 			glob_arg.ifname : glob_arg.ifname + 7;
-	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN-1);
+	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
 	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
 		;
 	*nscan = '\0';
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 33925c7d4..59837840e 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -25,13 +25,14 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD: head/sys/dev/netmap/netmap_freebsd.c 307706 2016-10-21 06:32:45Z sephe $ */
+/* $FreeBSD$ */
 #include "opt_inet.h"
 #include "opt_inet6.h"
 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include   /* POLLIN, POLLOUT */
 #include  /* types used in module initialization */
@@ -443,6 +444,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	m->m_ext.ext_size = len;
 #endif /* __FreeBSD_version >= 1100000 */
 
+	m->m_flags |= M_PKTHDR;
 	m->m_len = m->m_pkthdr.len = len;
 
 	/* mbuf refcnt is not contended, no need to use atomic
@@ -451,7 +453,9 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 	m->m_pkthdr.flowid = a->ring_nr;
 	m->m_pkthdr.rcvif = ifp; /* used for tx notification */
+	CURVNET_SET(ifp->if_vnet);
 	ret = NA(ifp)->if_transmit(ifp, m);
+	CURVNET_RESTORE();
 	return ret ? -1 : 0;
 }
 
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 1e80bcd9c..330f1d2c2 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1024,7 +1024,7 @@ generic_netmap_dtor(struct netmap_adapter *na)
 		         */
 		        netmap_adapter_put(prev_na);
 		}
-		nm_prinf("Native netmap adapter %p restored", prev_na);
+		nm_prinf("Native netmap adapter for %s restored", prev_na->name);
 	}
 	NM_RESTORE_NA(ifp, prev_na);
 	/*
@@ -1126,7 +1126,8 @@ generic_netmap_attach(struct ifnet *ifp)
 
 	nm_os_generic_set_features(gna);
 
-	nm_prinf("Emulated adapter for %s created (prev was %p)", na->name, gna->prev);
+	nm_prinf("Emulated adapter for %s created (prev was %s)", na->name,
+	    gna->prev ? gna->prev->name : "NULL");
 
 	return retval;
 }
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 2d3221b81..2f2c022c9 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2447,8 +2447,8 @@ netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, struct ifnet *ifp)
 			} else {
 				ptnmd->pt_ifs = curr->next;
 			}
-			nm_prinf("removed (ifp=%p,nifp_offset=%u)",
-			  curr->ifp, curr->nifp_offset);
+			nm_prinf("removed (ifp=%s,nifp_offset=%u)",
+			  curr->ifp->if_xname, curr->nifp_offset);
 			nm_os_free(curr);
 			ret = 0;
 			break;

From 1418c788eebc7f16960e5abf7277a4eefe261d7d Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 25 Aug 2019 18:05:50 +0200
Subject: [PATCH 1676/2207] pkt-gen: ignore -Waddress-of-packed-member warning

---
 apps/pkt-gen/GNUmakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/GNUmakefile b/apps/pkt-gen/GNUmakefile
index d5a55b894..a261876bc 100644
--- a/apps/pkt-gen/GNUmakefile
+++ b/apps/pkt-gen/GNUmakefile
@@ -12,7 +12,7 @@ NO_MAN=
 CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
-CFLAGS += -Wextra
+CFLAGS += -Wextra -Wno-address-of-packed-member
 
 LDLIBS += -lpthread -lm
 ifeq ($(shell uname),Linux)

From 137f537eae513f02d5d6871d1f91c049e6345803 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 1 Sep 2019 16:06:41 +0200
Subject: [PATCH 1677/2207] revert changes from fa36d8bbcfe00a95a5dfd52 that
 broke backward compatibility

---
 extra/python/netmap_manager.c | 2 +-
 share/man/man4/netmap.4       | 2 +-
 sys/net/netmap_legacy.h       | 2 +-
 utils/ctrl-api-test.c         | 6 +++---
 utils/testmmap.c              | 6 +++---
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/extra/python/netmap_manager.c b/extra/python/netmap_manager.c
index 8bfd749d0..c8ba3af07 100644
--- a/extra/python/netmap_manager.c
+++ b/extra/python/netmap_manager.c
@@ -154,7 +154,7 @@ NetmapManager_repr(NetmapManager *self)
             "dev_name:  '%s'\n"
             "if_name:   '%s'\n"
             "version:   %d\n"
-            "memsize:   %zu KiB\n"
+            "memsize:   %u KiB\n"
             "offset:    %u\n"
             "tx_slots:  %d\n"
             "rx_slots:  %d\n"
diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index e7b6e1671..cbdd55435 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -552,7 +552,7 @@ struct nmreq {
     char      nr_name[IFNAMSIZ]; /* (i) port name                  */
     uint32_t  nr_version;        /* (i) API version                */
     uint32_t  nr_offset;         /* (o) nifp offset in mmap region */
-    size_t    nr_memsize;        /* (o) size of the mmap region    */
+    uint32_t  nr_memsize;        /* (o) size of the mmap region    */
     uint32_t  nr_tx_slots;       /* (i/o) slots in tx rings        */
     uint32_t  nr_rx_slots;       /* (i/o) slots in rx rings        */
     uint16_t  nr_tx_rings;       /* (i/o) number of tx rings       */
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 531434427..f1dd7d625 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -152,7 +152,7 @@ struct nmreq {
 	char		nr_name[IFNAMSIZ];
 	uint32_t	nr_version;	/* API version */
 	uint32_t	nr_offset;	/* nifp offset in the shared region */
-	size_t	        nr_memsize;	/* size of the shared region */
+	uint32_t	nr_memsize;	/* size of the shared region */
 	uint32_t	nr_tx_slots;	/* slots in tx rings */
 	uint32_t	nr_rx_slots;	/* slots in rx rings */
 	uint16_t	nr_tx_rings;	/* number of tx rings */
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 1b12ea187..a75e21cca 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -206,7 +206,7 @@ port_info_get(struct TestContext *ctx)
 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
 		return ret;
 	}
-	printf("nr_memsize %zu\n", req.nr_memsize);
+	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
@@ -265,7 +265,7 @@ port_register(struct TestContext *ctx)
 		return ret;
 	}
 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
-	printf("nr_memsize %zu\n", req.nr_memsize);
+	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
@@ -339,7 +339,7 @@ niocregif(struct TestContext *ctx, int netmap_api)
 	}
 
 	printf("nr_offset 0x%x\n", req.nr_offset);
-	printf("nr_memsize  %zu\n", req.nr_memsize);
+	printf("nr_memsize  %u\n", req.nr_memsize);
 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 544c7dc26..8c59ee77a 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1036,11 +1036,11 @@ do_nmr_legacy_dump()
 	printf("name:      %s\n", nmr_name);
 	printf("version:   %d\n", curr_nmr.nr_version);
 	printf("offset:    %d\n", curr_nmr.nr_offset);
-	printf("memsize:   %zu [", curr_nmr.nr_memsize);
+	printf("memsize:   %u [", curr_nmr.nr_memsize);
 	if (curr_nmr.nr_memsize < (1 << 20)) {
-		printf("%zu KiB", curr_nmr.nr_memsize >> 10);
+		printf("%u KiB", curr_nmr.nr_memsize >> 10);
 	} else {
-		printf("%zu MiB", curr_nmr.nr_memsize >> 20);
+		printf("%u MiB", curr_nmr.nr_memsize >> 20);
 	}
 	printf("]\n");
 	printf("tx_slots:  %d\n", curr_nmr.nr_tx_slots);

From e115e4c15365d8550854f5749da9e28a25aa87cb Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 10 Sep 2019 22:03:41 +0200
Subject: [PATCH 1678/2207] linux: reset magic priority when driver fails with
 NETDEV_TX_BUSY

Fixes #648.
---
 LINUX/netmap_linux.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index bcc187ee0..f3750f854 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -633,10 +633,21 @@ generic_ndo_start_xmit(struct mbuf *m, struct ifnet *ifp)
 		(struct netmap_generic_adapter *)NA(ifp);
 
 	if (likely(m->priority == NM_MAGIC_PRIORITY_TX)) {
+		netdev_tx_t ret;
+
 		/* Reset priority, so that generic_netmap_tx_clean()
 		 * knows that it can reclaim this mbuf. */
 		m->priority = 0;
-		return gna->save_start_xmit(m, ifp); /* To the driver. */
+		ret = gna->save_start_xmit(m, ifp); /* To the driver. */
+		if (unlikely(ret == NETDEV_TX_BUSY)) {
+			/* The driver is busy, so the packet has not
+			 * been consumed and will be resubmitted
+			 * later. Set the priority again to our
+			 * magic value, so that it hits again
+			 * this code path. */
+			m->priority = NM_MAGIC_PRIORITY_TX;
+		}
+		return ret;
 	}
 
 	/* To a netmap RX ring. */

From b316518f5174d13fccc1203a38dffea62e79a634 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 11 Sep 2019 13:25:20 +0200
Subject: [PATCH 1679/2207] linux/ixgbe: patch for Intel 5.6.3 version

---
 LINUX/final-patches/intel--ixgbe--5.6.3 | 173 ++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.6.3

diff --git a/LINUX/final-patches/intel--ixgbe--5.6.3 b/LINUX/final-patches/intel--ixgbe--5.6.3
new file mode 100644
index 000000000..53de6fedb
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.6.3
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index e613859..8ca5eaa 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index af1af52..2744f7b 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -706,6 +706,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -725,6 +742,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2195,6 +2223,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3656,6 +3694,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4332,6 +4374,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12894,6 +12942,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12949,6 +13001,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 9959dacb85c2ebc769b8b3ff812f03f7e7debdb3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 19 Jun 2019 14:30:58 +0200
Subject: [PATCH 1680/2207] linux/configure: lazy binding of driver cflags

---
 LINUX/default-config.mak.in_ | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 7d4d22a2f..17a7766e5 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -63,9 +63,9 @@ $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sour
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
 $(1)@prepare	:=
-$(1)@build 	:= make -C $(1) CFLAGS_EXTRA="$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
-$(1)@install 	:= make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
-$(1)@clean 	:= if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
+$(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+$(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+$(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
 $(1)@distclean	:= rm -rf $(1)-$(2)
 $(1)@force	:= 1
 endef

From ff6fbe0123b0a502a4bc03616798cdb501680a8e Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 29 Sep 2019 09:44:22 +0000
Subject: [PATCH 1681/2207] LINUX: fix compilation on 32 bit systems

Related to #651
---
 LINUX/netmap_linux.c    |  9 +++++----
 LINUX/netmap_ptnet.c    | 21 ++++++++++++++-------
 sys/dev/netmap/netmap.c |  3 ++-
 3 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index f3750f854..d7f12b45d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -26,6 +26,7 @@
 #include "bsd_glue.h"
 #include    /* fget(int fd) */
 
+#include 
 #include 
 #include 
 #include 
@@ -1826,10 +1827,10 @@ nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr,
 		(*mem_size << 32);
 
 	nm_prinf("=== BAR %d start %llx len %llx mem_size %lx ===",
-			PTNETMAP_MEM_PCI_BAR,
-			pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
-			pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR),
-			(unsigned long)(*mem_size));
+	    PTNETMAP_MEM_PCI_BAR,
+	    (unsigned long long)pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR),
+	    (unsigned long long)pci_resource_len(pdev, PTNETMAP_MEM_PCI_BAR),
+	    (unsigned long)(*mem_size));
 
 	/* map memory allocator */
 	mem_paddr = pci_resource_start(pdev, PTNETMAP_MEM_PCI_BAR);
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index d5ccec819..a91b9256d 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1271,9 +1271,10 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	err = -EIO;
 	pr_info("%s: IO BAR (registers): start 0x%llx, len %llu, flags 0x%lx\n",
-		__func__, pci_resource_start(pdev, PTNETMAP_IO_PCI_BAR),
-		pci_resource_len(pdev, PTNETMAP_IO_PCI_BAR),
-		pci_resource_flags(pdev, PTNETMAP_IO_PCI_BAR));
+	    __func__,
+	    (unsigned long long)pci_resource_start(pdev, PTNETMAP_IO_PCI_BAR),
+	    (unsigned long long)pci_resource_len(pdev, PTNETMAP_IO_PCI_BAR),
+	    pci_resource_flags(pdev, PTNETMAP_IO_PCI_BAR));
 
 	ioaddr = pci_iomap(pdev, PTNETMAP_IO_PCI_BAR, 0);
 	if (!ioaddr) {
@@ -1352,14 +1353,20 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		/* CSB allocation protocol. Write to GH_BAH first, then
 		 * to GH_BAL. Same for HG_BAH and HG_BAL. */
 		phys_addr_t paddr = virt_to_phys(pi->csb_gh);
-		iowrite32((paddr >> 32) & 0xffffffff,
-				ioaddr + PTNET_IO_CSB_GH_BAH);
+		phys_addr_t hipa = 0;
+
+#if BITS_PER_LONG == 64
+		hipa = (paddr >> 32) & 0xffffffff;
+#endif
+		iowrite32(hipa, ioaddr + PTNET_IO_CSB_GH_BAH);
 		iowrite32(paddr & 0xffffffff,
 				ioaddr + PTNET_IO_CSB_GH_BAL);
 
 		paddr = virt_to_phys(pi->csb_hg);
-		iowrite32((paddr >> 32) & 0xffffffff,
-				ioaddr + PTNET_IO_CSB_HG_BAH);
+#if BITS_PER_LONG == 64
+		hipa = (paddr >> 32) & 0xffffffff;
+#endif
+		iowrite32(hipa, ioaddr + PTNET_IO_CSB_HG_BAH);
 		iowrite32(paddr & 0xffffffff,
 				ioaddr + PTNET_IO_CSB_HG_BAL);
 	}
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5eda4019c..982f76d45 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3316,7 +3316,8 @@ nmreq_getoption(struct nmreq_header *hdr, uint16_t reqtype)
 	if (!hdr->nr_options)
 		return NULL;
 
-	opt_tab = (struct nmreq_option **)(hdr->nr_options) - (NETMAP_REQ_OPT_MAX + 1);
+	opt_tab = (struct nmreq_option **)((uintptr_t)hdr->nr_options) -
+	    (NETMAP_REQ_OPT_MAX + 1);
 	return opt_tab[reqtype];
 }
 

From 8912e869336eef1a7f02ac554557fb0803a277ce Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 27 May 2019 16:51:41 +0200
Subject: [PATCH 1682/2207] fix strncat() warning

---
 sys/dev/netmap/netmap_legacy.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index dd875c80e..55b10a547 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -100,7 +100,7 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
 			/* No space for the pipe suffix. */
 			return ENOBUFS;
 		}
-		strncat(hdr->nr_name, suffix, strlen(suffix));
+		strlcat(hdr->nr_name, suffix, sizeof(hdr->nr_name));
 		req->nr_mode = NR_REG_ALL_NIC;
 		req->nr_ringid = 0;
 	}

From f7860194517852f04d2a90a2f1bd9f5a6e8f6eba Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Oct 2019 15:54:38 +0200
Subject: [PATCH 1683/2207] lb: fix strncpy possible missing terminator

---
 apps/lb/lb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index f162cc4f5..771cf6f18 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -652,7 +652,7 @@ int main(int argc, char **argv)
 	/* extract the base name */
 	char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ?
 			glob_arg.ifname : glob_arg.ifname + 7;
-	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
+	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN - 1);
 	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
 		;
 	*nscan = '\0';

From 782e8a39380d94aaac76a43112fd2583f6d415f4 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 20 Oct 2019 16:00:52 +0200
Subject: [PATCH 1684/2207] freebsd: align netmap_dev_pager_fault() from
 freebsd repo

---
 sys/dev/netmap/netmap_freebsd.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 59837840e..2580144ab 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1052,13 +1052,11 @@ netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
 		VM_OBJECT_WUNLOCK(object);
 		page = vm_page_getfake(paddr, memattr);
 		VM_OBJECT_WLOCK(object);
-		vm_page_lock(*mres);
 		vm_page_free(*mres);
-		vm_page_unlock(*mres);
 		*mres = page;
 		vm_page_insert(page, object, pidx);
 	}
-	page->valid = VM_PAGE_BITS_ALL;
+	vm_page_valid(page);
 	return (VM_PAGER_OK);
 }
 

From f546cd06c437e06632402de9970c2b0d244f251e Mon Sep 17 00:00:00 2001
From: Andrew Bonney 
Date: Mon, 21 Oct 2019 13:07:23 +0100
Subject: [PATCH 1685/2207] Update mlx5 driver to v4.6

---
 LINUX/final-patches/mellanox--mlx5--4.6 | 350 ++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--4.6

diff --git a/LINUX/final-patches/mellanox--mlx5--4.6 b/LINUX/final-patches/mellanox--mlx5--4.6
new file mode 100644
index 000000000..d591daec5
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--4.6
@@ -0,0 +1,350 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 1c4e92b..64553a8 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -6,12 +6,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o srq.o srq_exp.o alloc.o qp.o port.o mr.o pd.o \
+ 		mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
+ 		fs_counters.o rl.o lag.o dev.o wq.o lib/gid.o  \
+@@ -19,50 +19,49 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		devcom.o en_diag.o params.o fs_debugfs.o nvmf.o crdump.o icmd.o capi.o diag/tracer.o diag/diag_cnt.o \
+ 		eswitch_devlink_compat.o
+ 
+-
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o \
+ 		en_selftest.o en/port.o en_debugfs.o en_sniffer.o
+ 
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o lag_mp.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o lag_mp.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o ecpf.o
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o ecpf.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
+ 			fpga/ipsec.o fpga/tls.o fpga/trans.o fpga/xfer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
+ 
+ CFLAGS_tracepoint.o := -I$(src)
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index ca7eb20..27dc8e4 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -57,6 +57,16 @@
+ #include "en/port.h"
+ #include "en/xdp.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ struct mlx5e_rq_param {
+ 	u32			rqc[MLX5_ST_SZ_DW(rqc)];
+ 	struct mlx5_wq_param	wq;
+@@ -89,6 +99,9 @@ struct mlx5e_channel_param {
+ 
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -877,6 +890,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ 		rq->dim_obj.dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_free:
+@@ -1098,6 +1115,12 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 	struct mlx5e_channel *c = rq->channel;
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(c->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1140,6 +1163,10 @@ static void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->channel->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1252,6 +1279,9 @@ static void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ 
+ 	u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->channel->netdev)) || NA(rq->channel->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	sq->db.ico_wqe[pi].opcode     = MLX5_OPCODE_NOP;
+ 	nopwqe = mlx5e_post_nop(wq, sq->sqn, &sq->pc);
+@@ -1471,6 +1501,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1685,6 +1720,9 @@ static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	netif_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1702,6 +1740,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 	struct mlx5_rate_limit rl = {0};
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -1720,6 +1764,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->channel->netdev,
+@@ -3539,6 +3587,10 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 	if (priv->profile->update_carrier)
+ 		priv->profile->update_carrier(priv);
+ 
++#ifdef DEV_NETMAP
++	netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -3583,6 +3635,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++	netmap_disable_all_rings(netdev);
++#endif
++
+ 	if (MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER)) {
+ 		mlx5e_sniffer_stop(priv);
+ 		MLX5E_SET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER, 0);
+@@ -6405,6 +6461,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ 	const struct mlx5e_profile *profile = priv->profile;
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	if (profile->cleanup)
+ 		profile->cleanup(priv);
+ 	free_netdev(netdev);
+@@ -6505,6 +6565,11 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
+ 	mlx5e_dcbnl_init_app(priv);
+ #endif
+ #endif
++
++#ifdef DEV_NETMAP
++	mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return priv;
+ 
+ err_unregister_netdev:
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index c4e7420..b61fd09 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -49,6 +49,14 @@
+ #include "lib/clock.h"
+ #include "en/xdp.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -154,7 +162,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5e_cq *cq,
+ 					      int budget_rem)
+ {
+@@ -1630,6 +1638,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index b54766b..fe80042 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -38,6 +38,15 @@
+ #include "en_accel/en_accel.h"
+ #include "lib/clock.h"
+ 
++
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ #define MLX5E_SQ_NOPS_ROOM  MLX5_SEND_WQE_MAX_WQEBBS
+ 
+ #if defined(CONFIG_MLX5_EN_TLS) && defined(HAVE_UAPI_LINUX_TLS_H)
+@@ -630,6 +639,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->channel->netdev, sq->channel->ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -760,15 +774,17 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 			continue;
+ 		}
+ 
+-		for (i = 0; i < wi->num_dma; i++) {
+-			struct mlx5e_sq_dma *dma =
+-				mlx5e_dma_get(sq, sq->dma_fifo_cc++);
++		if (!nm_netmap_on(NA(sq->txq->dev))) {
++			/* do not free skbs in netmap mode */
++			for (i = 0; i < wi->num_dma; i++) {
++				struct mlx5e_sq_dma *dma =
++					mlx5e_dma_get(sq, sq->dma_fifo_cc++);
+ 
+-			mlx5e_tx_dma_unmap(sq->pdev, dma);
++				mlx5e_tx_dma_unmap(sq->pdev, dma);
++			}
++			dev_kfree_skb_any(skb);
+ 		}
+-
+-		dev_kfree_skb_any(skb);
+-		sq->cc += wi->num_wqebbs;
++        sq->cc += wi->num_wqebbs;
+ 	}
+ }
+ 

From 519a5794efd726baaf19aa3b6f319722b6723089 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Thu, 24 Oct 2019 22:15:32 +0200
Subject: [PATCH 1686/2207] vale-ctl: make parse_nmr_config() static

---
 apps/vale-ctl/vale-ctl.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index fc909144a..80a3642e7 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -42,10 +42,8 @@
 #include 	/* basename */
 #include 	/* atoi, free */
 
-/* XXX cut and paste from pkt-gen.c because I'm not sure whether this
- * program may include nm_util.h
- */
-void parse_nmr_config(const char* conf, struct nmreq *nmr)
+static void
+parse_nmr_config(const char* conf, struct nmreq *nmr)
 {
 	char *w, *tok;
 	int i, v;

From 70a1e83e9b9f95753f5da6d0e95ba09e79790059 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Nov 2019 10:34:51 +0100
Subject: [PATCH 1687/2207] linux/e1000e: patch for Intel 3.6.0 version

---
 LINUX/final-patches/intel--e1000e--3.6.0 | 91 ++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.6.0

diff --git a/LINUX/final-patches/intel--e1000e--3.6.0 b/LINUX/final-patches/intel--e1000e--3.6.0
new file mode 100644
index 000000000..7467099b4
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.6.0
@@ -0,0 +1,91 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index f300712..d8ca5dd 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -36,7 +36,7 @@ e1000e-y += kcompat.o
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := e1000e
++DRIVER := e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index 081ca43..12f992c 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -483,6 +483,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1013,6 +1017,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1330,6 +1345,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4262,6 +4282,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8674,6 +8698,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8775,6 +8803,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 422d981125cc0757cf0d5b53a5eca5655f5cbbc7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Nov 2019 10:39:08 +0100
Subject: [PATCH 1688/2207] linux/i40e: patch for Intel 2.9.21 version

---
 LINUX/final-patches/intel--i40e--2.9.21 | 166 ++++++++++++++++++++++++
 1 file changed, 166 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.9.21

diff --git a/LINUX/final-patches/intel--i40e--2.9.21 b/LINUX/final-patches/intel--i40e--2.9.21
new file mode 100644
index 000000000..720abcdbc
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.9.21
@@ -0,0 +1,166 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 5b3ca74..79db7aa 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 47f8b5f..58f65de 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -136,6 +136,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3481,6 +3486,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3534,6 +3543,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3562,6 +3575,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13750,6 +13768,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14122,6 +14145,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index b1987c8..816b129 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From 67a1649c3dc7940437b3f3f5516b29ce3cc66e0b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Nov 2019 10:39:32 +0100
Subject: [PATCH 1689/2207] linux/i40e: patch for Intel 2.10.19.30 version

---
 LINUX/final-patches/intel--i40e--2.10.19.30 | 166 ++++++++++++++++++++
 1 file changed, 166 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.10.19.30

diff --git a/LINUX/final-patches/intel--i40e--2.10.19.30 b/LINUX/final-patches/intel--i40e--2.10.19.30
new file mode 100644
index 000000000..79cdecf96
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.10.19.30
@@ -0,0 +1,166 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 5b3ca74..79db7aa 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 4452767..93b47d2 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -136,6 +136,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3480,6 +3485,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3533,6 +3542,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3561,6 +3574,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13732,6 +13750,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14104,6 +14127,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index d90951f..eb3c4f5 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From 361a6c8cc26116fb31f8430b3eef632a7a6e3d7f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 1 Nov 2019 10:41:20 +0100
Subject: [PATCH 1690/2207] linux/igb: patch for Intel 5.3.5.39 version

---
 LINUX/final-patches/intel--igb--5.3.5.39 | 138 +++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.39

diff --git a/LINUX/final-patches/intel--igb--5.3.5.39 b/LINUX/final-patches/intel--igb--5.3.5.39
new file mode 100644
index 000000000..c8762a71e
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.39
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 924ae5b..0a5f720 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index afb92bc..33a6a74 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -237,6 +237,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3183,6 +3187,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3388,6 +3396,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3800,6 +3812,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7480,6 +7495,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8496,6 +8516,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8815,6 +8840,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From fab49c6b9ab185bb95c172f4beafc9114238849f Mon Sep 17 00:00:00 2001
From: Carl Smith 
Date: Mon, 4 Nov 2019 11:08:34 +1300
Subject: [PATCH 1691/2207] Record mapped netmap memory as RssShmem rather than
 RssFile

 VmRSS     size of memory portions. It contains the three
           following parts (VmRSS = RssAnon + RssFile + RssShmem)
 RssAnon   size of resident anonymous memory
 RssFile   size of resident file mappings
 RssShmem  size of resident shmem memory (includes SysV shm,
           mapping of tmpfs and shared anonymous mappings)

The kernel differentiates between RssFile and RssShmem by
checking the PG_swapbacked flag on the page. By setting this
flag the netmp memory will be recorded as RssShmem.
---
 LINUX/netmap_linux.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d7f12b45d..b54940cb0 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1252,6 +1252,7 @@ linux_netmap_fault(struct vm_fault *vmf)
 	if (!pfn_valid(pfn))
 		return VM_FAULT_SIGBUS;
 	page = pfn_to_page(pfn);
+	SetPageSwapBacked(page);
 	get_page(page);
 	vmf->page = page;
 	return 0;

From aff615285f1937e9c499a922b7b8cfa47c4f7bc2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Nov 2019 10:42:59 +0100
Subject: [PATCH 1692/2207] lb: fix warning found by gcc 9

---
 apps/lb/lb.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 771cf6f18..9efc71524 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -90,8 +90,8 @@ struct compact_ipv6_hdr {
 #define STAT_MSG_MAXSIZE 1024
 
 struct {
-	char ifname[MAX_IFNAMELEN];
-	char base_name[MAX_IFNAMELEN];
+	char ifname[MAX_IFNAMELEN + 1];
+	char base_name[MAX_IFNAMELEN + 1];
 	int netmap_fd;
 	uint16_t output_rings;
 	uint16_t num_groups;
@@ -652,7 +652,11 @@ int main(int argc, char **argv)
 	/* extract the base name */
 	char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ?
 			glob_arg.ifname : glob_arg.ifname + 7;
-	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN - 1);
+	if (strlen(nscan) > MAX_IFNAMELEN) {
+		D("name too long: %s (max %d)", nscan, MAX_IFNAMELEN);
+		return 1;
+	}
+	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
 	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
 		;
 	*nscan = '\0';

From 9b7bbe8898fd0d7dfedf0f2f41a31ef022230baa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Nov 2019 10:44:02 +0100
Subject: [PATCH 1693/2207] linux/pkt-gen: don't include deprecated sysctl.h

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index eacd42769..1021dbb4f 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -47,7 +47,7 @@
 #include 	// sysconf()
 #include 
 #include 	/* ntohs */
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(linux)
 #include 	/* sysctl */
 #endif
 #include 	/* getifaddrs */

From 3ac35dc46e875c6fe5da7f251f5e6f26a32f2fd8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Nov 2019 11:08:56 +0100
Subject: [PATCH 1694/2207] linux/configure: run integration tests from any
 build directory

---
 LINUX/netmap.mak.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 8961d4778..eadce9760 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -158,7 +158,7 @@ clean-utils:
 	$(MAKE) -C build-utils clean SRCDIR=$(SRCDIR)/.. BUILDDIR=$(BUILDDIR)
 
 intest: utils
-	$(SRCDIR)/../utils/randomized_tests
+	PATH=$(BUILDDIR)/build-utils:$$PATH $(SRCDIR)/../utils/randomized_tests
 unitest: utils
 	build-utils/ctrl-api-test
 endif

From 1029de102ae1046a024d1a00b67afda083e074cb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Nov 2019 11:45:39 +0100
Subject: [PATCH 1695/2207] pkt-gen: close temporary socket in get_if_mtu()

---
 apps/pkt-gen/pkt-gen.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 1021dbb4f..0be2c781e 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -541,6 +541,8 @@ get_if_mtu(const struct glob_arg *g)
 			D("ioctl(SIOCGIFMTU) failed: %s", strerror(errno));
 		}
 
+		close(s);
+
 		return ifreq.ifr_mtu;
 	}
 

From 4201df65603a8e6c763cebf4bf00c0201ca7474b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Feb 2019 14:13:26 +0100
Subject: [PATCH 1696/2207] vale-ctl: use new API

---
 apps/vale-ctl/GNUmakefile |  15 +-
 apps/vale-ctl/vale-ctl.c  | 427 ++++++++++++++++++++++++++------------
 2 files changed, 299 insertions(+), 143 deletions(-)

diff --git a/apps/vale-ctl/GNUmakefile b/apps/vale-ctl/GNUmakefile
index 8ee0e40be..d6e6acb56 100644
--- a/apps/vale-ctl/GNUmakefile
+++ b/apps/vale-ctl/GNUmakefile
@@ -11,20 +11,11 @@ VPATH = $(SRCDIR)/apps/vale-ctl
 NO_MAN=
 CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
-CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I $(SRCDIR)/libnetmap
 CFLAGS += -Wextra
 
-LDLIBS += -lpthread -lm
-ifeq ($(shell uname),Linux)
-	LDLIBS += -lrt	# on linux
-endif
-
-ifdef WITH_PCAP
-LDLIBS += -lpcap
-else
-CFLAGS += -DNO_PCAP
-endif
-
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+LDLIBS = -lnetmap
 PREFIX ?= /usr/local
 MAN_PREFIX = $(if $(filter-out /,$(PREFIX)),$(PREFIX),/usr)/share/man
 
diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index 80a3642e7..7e219e2df 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -25,9 +25,8 @@
 
 /* $FreeBSD$ */
 
-#define NETMAP_WITH_LIBS
-#include 
-#include 
+#define LIBNETMAP_NOTHREADSAFE
+#include 
 
 #include 
 #include 
@@ -42,14 +41,58 @@
 #include 	/* basename */
 #include 	/* atoi, free */
 
+int verbose;
+
+struct args {
+	const char *name;
+	const char *config;
+	const char *mem_id;
+
+	uint16_t nr_reqtype;
+	uint32_t nr_mode;
+};
+
+static void
+dump_port_info(struct nmreq_port_info_get *v)
+{
+	printf("memsize:    %"PRIu64"\n", v->nr_memsize);
+	printf("tx_slots:   %"PRIu32"\n", v->nr_tx_slots);
+	printf("rx_slots:   %"PRIu32"\n", v->nr_rx_slots);
+	printf("tx_rings:   %"PRIu16"\n", v->nr_tx_rings);
+	printf("rx_rings    %"PRIu16"\n", v->nr_rx_rings);
+	printf("mem_id:     %"PRIu16"\n", v->nr_mem_id);
+}
+
 static void
-parse_nmr_config(const char* conf, struct nmreq *nmr)
+dump_newif(struct nmreq_vale_newif *v)
+{
+	printf("tx_slots:   %"PRIu32"\n", v->nr_tx_slots);
+	printf("rx_slots:   %"PRIu32"\n", v->nr_rx_slots);
+	printf("tx_rings:   %"PRIu16"\n", v->nr_tx_rings);
+	printf("rx_ring:    %"PRIu16"\n", v->nr_rx_rings);
+	printf("mem_id:     %"PRIu16"\n", v->nr_mem_id);
+}
+
+static void
+dump_vale_list(struct nmreq_vale_list *v)
+{
+	printf("bridge_idx: %"PRIu16"\n", v->nr_bridge_idx);
+	printf("port_idx:   %"PRIu16"\n", v->nr_port_idx);
+}
+
+
+static void
+parse_ring_config(const char* conf,
+		uint32_t *nr_tx_slots,
+		uint32_t *nr_rx_slots,
+		uint16_t *nr_tx_rings,
+		uint16_t *nr_rx_rings)
 {
 	char *w, *tok;
 	int i, v;
 
-	nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
-	nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
+	*nr_tx_rings = *nr_rx_rings = 0;
+	*nr_tx_slots = *nr_rx_slots = 0;
 	if (conf == NULL || ! *conf)
 		return;
 	w = strdup(conf);
@@ -57,137 +100,235 @@ parse_nmr_config(const char* conf, struct nmreq *nmr)
 		v = atoi(tok);
 		switch (i) {
 		case 0:
-			nmr->nr_tx_slots = nmr->nr_rx_slots = v;
+			*nr_tx_slots = *nr_rx_slots = v;
 			break;
 		case 1:
-			nmr->nr_rx_slots = v;
+			*nr_rx_slots = v;
 			break;
 		case 2:
-			nmr->nr_tx_rings = nmr->nr_rx_rings = v;
+			*nr_tx_rings = *nr_rx_rings = v;
 			break;
 		case 3:
-			nmr->nr_rx_rings = v;
+			*nr_rx_rings = v;
 			break;
 		default:
-			D("ignored config: %s", tok);
+			fprintf(stderr, "ignored config: %s", tok);
 			break;
 		}
 	}
-	D("txr %d txd %d rxr %d rxd %d",
-			nmr->nr_tx_rings, nmr->nr_tx_slots,
-			nmr->nr_rx_rings, nmr->nr_rx_slots);
+	ND("txr %d txd %d rxr %d rxd %d",
+			*nr_tx_rings, *nr_tx_slots,
+			*nr_rx_rings, *nr_rx_slots);
 	free(w);
 }
 
 static int
-bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2)
+parse_poll_config(const char *conf, struct nmreq_vale_polling *v)
 {
-	struct nmreq nmr;
-	int error = 0;
-	int fd = open("/dev/netmap", O_RDWR);
+	char *w, *tok;
+	int i, p;
 
-	if (fd == -1) {
-		D("Unable to open /dev/netmap");
+	if (conf == NULL || ! *conf) {
+		fprintf(stderr, "invalid null/empty config\n");
 		return -1;
 	}
+	w = strdup(conf);
+	for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
+		p = atoi(tok);
+		switch (i) {
+		case 0:
+			v->nr_mode = p ? NETMAP_POLLING_MODE_MULTI_CPU :
+				NETMAP_POLLING_MODE_SINGLE_CPU;
+			break;
+		case 1:
+			v->nr_first_cpu_id = p;
+			break;
+		case 2:
+			if (v->nr_mode != NETMAP_POLLING_MODE_MULTI_CPU) {
+				fprintf(stderr, "too many numbers in '%s'\n", conf);
+				return -1;
+			}
+			v->nr_num_polling_cpus = p;
+			break;
+		case 3:
+			fprintf(stderr, "too many numbers in '%s'\n", conf);
+			return -1;
+		}
+	}
+	free(w);
+	return 0;
+}
 
-	bzero(&nmr, sizeof(nmr));
-	nmr.nr_version = NETMAP_API;
-	if (name != NULL) /* might be NULL */
-		strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)-1);
-	nmr.nr_cmd = nr_cmd;
-	parse_nmr_config(nmr_config, &nmr);
-	nmr.nr_arg2 = nr_arg2;
-
-	switch (nr_cmd) {
-	case NETMAP_BDG_DELIF:
-	case NETMAP_BDG_NEWIF:
-		error = ioctl(fd, NIOCREGIF, &nmr);
-		if (error == -1) {
-			ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name);
-			perror(name);
-		} else {
-			ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name);
+static int32_t
+parse_mem_id(const char *mem_id)
+{
+	int32_t id;
+
+	if (mem_id == NULL)
+		return 0;
+	if (isdigit(*mem_id))
+		return atoi(mem_id);
+	id = nmreq_get_mem_id(&mem_id, nmctx_get());
+	if (id == 0) {
+		fprintf(stderr, "invalid format in '-m %s' (missing 'netmap:'?)\n", mem_id);
+		return -1;
+	}
+	return id;
+}
+
+static int
+list_all(int fd, struct nmreq_header *hdr)
+{
+	int error;
+	struct nmreq_vale_list *vale_list =
+		(struct nmreq_vale_list *)hdr->nr_body;
+
+	for (;;) {
+		hdr->nr_name[0] = '\0';
+		error = ioctl(fd, NIOCCTRL, hdr);
+		if (error < 0) {
+			if (errno == ENOENT)
+				break;
+
+			fprintf(stderr, "failed to list all: %s\n", strerror(errno));
+			return 1;
 		}
+		printf("%s bridge_idx %"PRIu16" port_idx %"PRIu32"\n", hdr->nr_name,
+				vale_list->nr_bridge_idx, vale_list->nr_port_idx);
+		vale_list->nr_port_idx++;
+	}
+	return 1;
+}
+
+static int
+bdg_ctl(struct args *a)
+{
+	struct nmreq_header hdr;
+	struct nmreq_vale_attach   vale_attach;
+	struct nmreq_vale_detach   vale_detach;
+	struct nmreq_vale_newif    vale_newif;
+	struct nmreq_vale_list     vale_list;
+	struct nmreq_vale_polling  vale_polling;
+	struct nmreq_port_info_get port_info_get;
+	int error = 0;
+	int fd;
+	int32_t mem_id;
+	const char *action = NULL;
+
+	fd = open("/dev/netmap", O_RDWR);
+	if (fd == -1) {
+		perror("/dev/netmap");
+		return 1;
+	}
+
+	bzero(&hdr, sizeof(hdr));
+	hdr.nr_version = NETMAP_API;
+	if (a->name != NULL) { /* might be NULL */
+		strncpy(hdr.nr_name, a->name, NETMAP_REQ_IFNAMSIZ - 1);
+		hdr.nr_name[NETMAP_REQ_IFNAMSIZ - 1] = '\0';
+	}
+	hdr.nr_reqtype = a->nr_reqtype;
+
+	switch (a->nr_reqtype) {
+	case NETMAP_REQ_VALE_DELIF:
+		/* no body */
+		action = "remove";
 		break;
-	case NETMAP_BDG_ATTACH:
-	case NETMAP_BDG_DETACH:
-		nmr.nr_flags = NR_REG_ALL_NIC;
-		if (nr_arg && nr_arg != NETMAP_BDG_HOST) {
-			nmr.nr_flags = NR_REG_NIC_SW;
-			nr_arg = 0;
+
+	case NETMAP_REQ_VALE_NEWIF:
+		memset(&vale_newif, 0, sizeof(vale_newif));
+		hdr.nr_body = (uintptr_t)&vale_newif;
+		parse_ring_config(a->config,
+				&vale_newif.nr_tx_slots,
+				&vale_newif.nr_rx_slots,
+				&vale_newif.nr_tx_rings,
+				&vale_newif.nr_rx_rings);
+		mem_id = parse_mem_id(a->mem_id);
+		if (mem_id < 0)
+			return 1;
+		vale_newif.nr_mem_id = mem_id;
+		action = "create";
+		break;
+
+	case NETMAP_REQ_VALE_ATTACH:
+		memset(&vale_attach, 0, sizeof(vale_attach));
+		hdr.nr_body = (uintptr_t)&vale_attach;
+		vale_attach.reg.nr_mode = a->nr_mode;
+		parse_ring_config(a->config,
+				&vale_attach.reg.nr_tx_slots,
+				&vale_attach.reg.nr_rx_slots,
+				&vale_attach.reg.nr_tx_rings,
+				&vale_attach.reg.nr_rx_rings);
+		mem_id = parse_mem_id(a->mem_id);
+		if (mem_id < 0)
+			return 1;
+		vale_attach.reg.nr_mem_id = mem_id;
+		action = "attach";
+		break;
+
+	case NETMAP_REQ_VALE_DETACH:
+		memset(&vale_detach, 0, sizeof(vale_detach));
+		hdr.nr_body = (uintptr_t)&vale_detach;
+		action = "detach";
+		break;
+
+	case NETMAP_REQ_VALE_LIST:
+		memset(&vale_list, 0, sizeof(vale_list));
+		hdr.nr_body = (uintptr_t)&vale_list;
+		if (a->name == NULL) {
+			return list_all(fd, &hdr);
 		}
-		nmr.nr_arg1 = nr_arg;
-		error = ioctl(fd, NIOCREGIF, &nmr);
-		if (error == -1) {
-			ND("Unable to %s %s to the bridge", nr_cmd ==
-			    NETMAP_BDG_DETACH?"detach":"attach", name);
-			perror(name);
-		} else
-			ND("Success to %s %s to the bridge", nr_cmd ==
-			    NETMAP_BDG_DETACH?"detach":"attach", name);
+		action = "list";
 		break;
 
-	case NETMAP_BDG_LIST:
-		if (strlen(nmr.nr_name)) { /* name to bridge/port info */
-			error = ioctl(fd, NIOCGINFO, &nmr);
-			if (error) {
-				ND("Unable to obtain info for %s", name);
-				perror(name);
-			} else
-				D("%s at bridge:%d port:%d", name, nmr.nr_arg1,
-				    nmr.nr_arg2);
-			break;
+	case NETMAP_REQ_VALE_POLLING_ENABLE:
+		action = "enable polling on";
+		/* fall through */
+	case NETMAP_REQ_VALE_POLLING_DISABLE:
+		memset(&vale_polling, 0, sizeof(vale_polling));
+		hdr.nr_body = (uintptr_t)&vale_polling;
+		parse_poll_config(a->config, &vale_polling);
+		if (action == NULL)
+			action ="disable polling on";
+		break;
+
+	case NETMAP_REQ_PORT_INFO_GET:
+		memset(&port_info_get, 0, sizeof(port_info_get));
+		hdr.nr_body = (uintptr_t)&port_info_get;
+		action = "obtain info for";
+		break;
+	}
+	error = ioctl(fd, NIOCCTRL, &hdr);
+	if (error < 0) {
+		fprintf(stderr, "failed to %s %s: %s\n",
+				action, a->name, strerror(errno));
+		return 1;
+	}
+	switch (hdr.nr_reqtype) {
+	case NETMAP_REQ_VALE_NEWIF:
+		if (verbose) {
+			dump_newif(&vale_newif);
 		}
+		break;
 
-		/* scan all the bridges and ports */
-		nmr.nr_arg1 = nmr.nr_arg2 = 0;
-		for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) {
-			D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2,
-			    nmr.nr_name);
-			nmr.nr_name[0] = '\0';
+	case NETMAP_REQ_VALE_ATTACH:
+		if (verbose) {
+			printf("port_index: %"PRIu32"\n", vale_attach.port_index);
 		}
+		break;
 
+	case NETMAP_REQ_VALE_DETACH:
+		if (verbose) {
+			printf("port_index: %"PRIu32"\n", vale_detach.port_index);
+		}
 		break;
 
-	case NETMAP_BDG_POLLING_ON:
-	case NETMAP_BDG_POLLING_OFF:
-		/* We reuse nmreq fields as follows:
-		 *   nr_tx_slots: 0 and non-zero indicate REG_ALL_NIC
-		 *                REG_ONE_NIC, respectively.
-		 *   nr_rx_slots: CPU core index. This also indicates the
-		 *                first queue in the case of REG_ONE_NIC
-		 *   nr_tx_rings: (REG_ONE_NIC only) indicates the
-		 *                number of CPU cores or the last queue
-		 */
-		nmr.nr_flags |= nmr.nr_tx_slots ?
-			NR_REG_ONE_NIC : NR_REG_ALL_NIC;
-		nmr.nr_ringid = nmr.nr_rx_slots;
-		/* number of cores/rings */
-		if (nmr.nr_flags == NR_REG_ALL_NIC)
-			nmr.nr_arg1 = 1;
-		else
-			nmr.nr_arg1 = nmr.nr_tx_rings;
-
-		error = ioctl(fd, NIOCREGIF, &nmr);
-		if (!error)
-			D("polling on %s %s", nmr.nr_name,
-				nr_cmd == NETMAP_BDG_POLLING_ON ?
-				"started" : "stopped");
-		else
-			D("polling on %s %s (err %d)", nmr.nr_name,
-				nr_cmd == NETMAP_BDG_POLLING_ON ?
-				"couldn't start" : "couldn't stop", error);
+	case NETMAP_REQ_VALE_LIST:
+		dump_vale_list(&vale_list);
 		break;
 
-	default: /* GINFO */
-		nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0;
-		error = ioctl(fd, NIOCGINFO, &nmr);
-		if (error) {
-			ND("Unable to get if info for %s", name);
-			perror(name);
-		} else
-			D("%s: %d queues.", name, nmr.nr_rx_rings);
+	case NETMAP_REQ_PORT_INFO_GET:
+		dump_port_info(&port_info_get);
 		break;
 	}
 	close(fd);
@@ -199,82 +340,106 @@ usage(int errcode)
 {
 	fprintf(stderr,
 	    "Usage:\n"
-	    "vale-ctl arguments\n"
+	    "vale-ctl [arguments]\n"
 	    "\t-g interface	interface name to get info\n"
 	    "\t-d interface	interface name to be detached\n"
 	    "\t-a interface	interface name to be attached\n"
 	    "\t-h interface	interface name to be attached with the host stack\n"
 	    "\t-n interface	interface name to be created\n"
 	    "\t-r interface	interface name to be deleted\n"
-	    "\t-l list all or specified bridge's interfaces (default)\n"
+	    "\t-l vale-port	show bridge and port indices\n"
 	    "\t-C string ring/slot setting of an interface creating by -n\n"
 	    "\t-p interface start polling. Additional -C x,y,z configures\n"
 	    "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n"
 	    "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n"
 	    "\t\t z: (ONE_NIC only) num of total cores/rings\n"
 	    "\t-P interface stop polling\n"
-	    "\t-m memid to use when creating a new interface\n");
+	    "\t-m memid to use when creating a new interface\n"
+	    "\t-v increase verbosity\n"
+	    "with no arguments: list all existing vale ports\n");
 	exit(errcode);
 }
 
 int
 main(int argc, char *argv[])
 {
-	int ch, nr_cmd = 0, nr_arg = 0;
-	char *name = NULL, *nmr_config = NULL;
-	int nr_arg2 = 0;
+	int ch;
+	struct args a = {
+		.name = NULL,
+		.config = NULL,
+		.mem_id = NULL,
+		.nr_reqtype = 0,
+		.nr_mode = NR_REG_ALL_NIC,
+	};
 
-	while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:")) != -1) {
-		if (ch != 'C' && ch != 'm')
-			name = optarg; /* default */
+	while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:v")) != -1) {
 		switch (ch) {
 		default:
 			fprintf(stderr, "bad option %c %s", ch, optarg);
-			usage(-1);
+			usage(1);
 			break;
 		case 'd':
-			nr_cmd = NETMAP_BDG_DETACH;
+			a.nr_reqtype = NETMAP_REQ_VALE_DETACH;
+			a.name = optarg;
 			break;
 		case 'a':
-			nr_cmd = NETMAP_BDG_ATTACH;
+			a.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			a.nr_mode = NR_REG_ALL_NIC;
+			a.name = optarg;
 			break;
 		case 'h':
-			nr_cmd = NETMAP_BDG_ATTACH;
-			nr_arg = NETMAP_BDG_HOST;
+			a.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
+			a.nr_mode = NR_REG_NIC_SW;
+			a.name = optarg;
 			break;
 		case 'n':
-			nr_cmd = NETMAP_BDG_NEWIF;
+			a.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
+			a.name = optarg;
 			break;
 		case 'r':
-			nr_cmd = NETMAP_BDG_DELIF;
+			a.nr_reqtype = NETMAP_REQ_VALE_DELIF;
+			a.name = optarg;
 			break;
 		case 'g':
-			nr_cmd = 0;
+			a.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
+			a.name = optarg;
 			break;
 		case 'l':
-			nr_cmd = NETMAP_BDG_LIST;
+			a.nr_reqtype = NETMAP_REQ_VALE_LIST;
+			a.name = optarg;
+			if (strncmp(a.name, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
+				fprintf(stderr, "invalid vale port name: '%s'\n", a.name);
+				usage(1);
+			}
 			break;
 		case 'C':
-			nmr_config = strdup(optarg);
+			a.config = optarg;
 			break;
 		case 'p':
-			nr_cmd = NETMAP_BDG_POLLING_ON;
+			a.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
+			a.name = optarg;
 			break;
 		case 'P':
-			nr_cmd = NETMAP_BDG_POLLING_OFF;
+			a.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
+			a.name = optarg;
 			break;
 		case 'm':
-			nr_arg2 = atoi(optarg);
+			a.mem_id = optarg;
+			break;
+		case 'v':
+			verbose++;
 			break;
 		}
 	}
 	if (optind != argc) {
-		// fprintf(stderr, "optind %d argc %d\n", optind, argc);
-		usage(-1);
+		usage(1);
 	}
 	if (argc == 1) {
-		nr_cmd = NETMAP_BDG_LIST;
-		name = NULL;
+		a.nr_reqtype = NETMAP_REQ_VALE_LIST;
+		a.name = NULL;
+	}
+	if (!a.nr_reqtype) {
+		usage(1);
 	}
-	return bdg_ctl(name, nr_cmd, nr_arg, nmr_config, nr_arg2) ? 1 : 0;
+	return bdg_ctl(&a);
 }

From 11e0119aae9e970a700ed25c0e574f5b5ccf16c8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 23 Nov 2018 17:36:10 +0100
Subject: [PATCH 1697/2207] tlem: use the new API

---
 apps/tlem/GNUmakefile |  5 +++--
 apps/tlem/tlem.c      | 36 ++++++++++++++++++++++--------------
 2 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/apps/tlem/GNUmakefile b/apps/tlem/GNUmakefile
index cbd180b00..45613a38d 100644
--- a/apps/tlem/GNUmakefile
+++ b/apps/tlem/GNUmakefile
@@ -11,10 +11,11 @@ VPATH = $(SRCDIR)/apps/tlem
 NO_MAN=
 CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
-CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I$(SRCDIR)/libnetmap
 CFLAGS += -Wextra
 
-LDLIBS += -lpthread
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+LDLIBS += -lnetmap -lpthread
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt	# on linux
 endif
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index c41919e1f..57db9449e 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -135,9 +135,12 @@ prod()
 
 #define _GNU_SOURCE	// for CPU_SET() etc
 #include 
-#define NETMAP_WITH_LIBS
-#include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 
 int verbose = 0;
@@ -307,7 +310,7 @@ struct _qs { /* shared queue */
 	uint64_t	prod_max_gap;	/* rx round duration */
 
 	/* parameters for reading from the netmap port */
-	struct nm_desc *src_port;		/* netmap descriptor */
+	struct nmport_d *src_port;		/* netmap descriptor */
 	const char *	prod_ifname;	/* interface name */
 	struct netmap_ring *rxring;	/* current ring being handled */
 	uint32_t	si;		/* ring index */
@@ -382,8 +385,8 @@ struct pipe_args {
 	int		cons_core;	/* core for cons() */
 	int		prod_core;	/* core for prod() */
 
-	struct nm_desc *pa;		/* netmap descriptor */
-	struct nm_desc *pb;
+	struct nmport_d *pa;		/* netmap descriptor */
+	struct nmport_d *pb;
 
 	struct _qs	q;
 };
@@ -567,7 +570,7 @@ enq(struct _qs *q)
 
 
 int
-rx_queued(struct nm_desc *d)
+rx_queued(struct nmport_d *d)
 {
     u_int tot = 0, i;
     for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
@@ -669,7 +672,7 @@ scan_ring(struct _qs *q, int next /* bool */)
 {
     struct netmap_slot *rs;
     struct netmap_ring *rxr = q->rxring; /* invalid if next == 0 */
-    struct nm_desc *pa = q->src_port;
+    struct nmport_d *pa = q->src_port;
 
     /* fast path for the first two */
     if (likely(next != 0)) { /* current ring */
@@ -843,7 +846,7 @@ cons(void *_pa)
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
                 p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
         /* XXX inefficient but simple */
-        if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
+        if (nmport_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
             ND(5, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
                     (int)p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
             ioctl(pa->pb->fd, NIOCTXSYNC, 0);
@@ -881,16 +884,19 @@ tlem_main(void *_a)
     setaffinity(a->cons_core);
     set_tns_now(&q->t0, 0); /* starting reference */
 
-    a->pa = nm_open(q->prod_ifname, NULL, NETMAP_NO_TX_POLL, NULL);
+    a->pa = nmport_prepare(q->prod_ifname);
     if (a->pa == NULL) {
         ED("cannot open %s", q->prod_ifname);
         return NULL;
     }
-    // XXX use a single mmap ?
-    a->pb = nm_open(q->cons_ifname, NULL, NM_OPEN_NO_MMAP, a->pa);
+    a->pa->reg.nr_flags |= NETMAP_NO_TX_POLL;
+    if (nmport_open_desc(a->pa) < 0) {
+	ED("cannot open %s", q->prod_ifname);
+    }
+    a->pb = nmport_open(q->cons_ifname);
     if (a->pb == NULL) {
         ED("cannot open %s", q->cons_ifname);
-        nm_close(a->pa);
+        nmport_close(a->pa);
         return NULL;
     }
     a->zerocopy = a->zerocopy && (a->pa->mem == a->pb->mem);
@@ -920,8 +926,8 @@ tlem_main(void *_a)
     q->buf = calloc(1, need);
     if (q->buf == NULL) {
         ED("alloc %lld bytes for queue failed, exiting", (long long)need);
-        nm_close(a->pa);
-        nm_close(a->pb);
+        nmport_close(a->pa);
+        nmport_close(a->pb);
         return(NULL);
     }
     q->buflen = need;
@@ -1096,6 +1102,8 @@ main(int argc, char **argv)
     int ncpus;
     int cores[4];
 
+    nmctx_set_threadsafe();
+
     bzero(d, sizeof(d));
     bzero(b, sizeof(b));
     bzero(l, sizeof(l));

From 6f1985a0fb02365fc4ae70ecc74d3a4f43945a4f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 24 Nov 2018 14:51:12 +0100
Subject: [PATCH 1698/2207] nmreplay: use the new API

---
 apps/nmreplay/GNUmakefile |  5 +++--
 apps/nmreplay/nmreplay.c  | 18 ++++++++++--------
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/apps/nmreplay/GNUmakefile b/apps/nmreplay/GNUmakefile
index 72a75c9e5..0c2fc7839 100644
--- a/apps/nmreplay/GNUmakefile
+++ b/apps/nmreplay/GNUmakefile
@@ -11,10 +11,11 @@ VPATH = $(SRCDIR)/apps/nmreplay
 NO_MAN=
 CFLAGS = -O2 # -pipe -g
 CFLAGS += -Werror -Wall -Wunused-function
-CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I $(SRCDIR)/libnetmap
 CFLAGS += -Wextra
 
-LDLIBS += -lpthread
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+LDLIBS += -lnetmap -lpthread
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt	# on linux
 endif
diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index d4857a3f7..c72a659d6 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -107,9 +107,11 @@
 
 #define _GNU_SOURCE	// for CPU_SET() etc
 #include 
-#define NETMAP_WITH_LIBS
-#include 
+#include 
 #include 
+#include 
+#include 
+#include 
 
 
 /*
@@ -566,7 +568,7 @@ struct _qs { /* shared queue */
 	struct nm_pcap_file	*pcap;		/* the pcap struct */
 
 	/* parameters for reading from the netmap port */
-	struct nm_desc *src_port;		/* netmap descriptor */
+	struct nmport_d *src_port;		/* netmap descriptor */
 	const char *	prod_ifname;	/* interface name or pcap file */
 	struct netmap_ring *rxring;	/* current ring being handled */
 	uint32_t	si;		/* ring index */
@@ -640,8 +642,8 @@ struct pipe_args {
 	int		cons_core;	/* core for cons() */
 	int		prod_core;	/* core for prod() */
 
-	struct nm_desc *pa;		/* netmap descriptor */
-	struct nm_desc *pb;
+	struct nmport_d *pa;		/* netmap descriptor */
+	struct nmport_d *pb;
 
 	struct _qs	q;
 };
@@ -843,7 +845,7 @@ pcap_prod(void *_pa)
     if (q->buf != NULL) {
 	free(q->buf);
     }
-    nm_close(pa->pb);
+    nmport_close(pa->pb);
     return (NULL);
 }
 
@@ -893,7 +895,7 @@ cons(void *_pa)
 	    continue;
 	}
 	/* XXX copy is inefficient but simple */
-	if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
+	if (nmport_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
 	    RD(1, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
 		(int)p->pktlen, (u_long)q->cons_now, (u_long)p->pt_tx,
 		(u_long)q->_head, (u_long)q->_tail, (u_long)p->next);
@@ -939,7 +941,7 @@ nmreplay_main(void *_a)
     pcap_prod((void*)a);
     destroy_pcap(q->pcap);
     q->pcap = NULL;
-    a->pb = nm_open(q->cons_ifname, NULL, 0, NULL);
+    a->pb = nmport_open(q->cons_ifname);
     if (a->pb == NULL) {
 	EEE("cannot open netmap on %s", q->cons_ifname);
 	do_abort = 1; // XXX any better way ?

From d02e4563570c2785cb4d67ce7281f020b475f345 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 24 Nov 2018 14:46:07 +0100
Subject: [PATCH 1699/2207] lb: use the new API

---
 apps/lb/GNUmakefile |  5 ++--
 apps/lb/lb.c        | 56 +++++++++++++++++++--------------------------
 2 files changed, 26 insertions(+), 35 deletions(-)

diff --git a/apps/lb/GNUmakefile b/apps/lb/GNUmakefile
index 5979ed6bb..347ab8bd1 100644
--- a/apps/lb/GNUmakefile
+++ b/apps/lb/GNUmakefile
@@ -11,10 +11,11 @@ VPATH = $(SRCDIR)/apps/lb
 NO_MAN=
 CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
-CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I $(SRCDIR)/libnetmap
 CFLAGS += -Wextra
 
-LDLIBS += -lpthread -lm
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+LDLIBS += -lnetmap -lpthread -lm
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt	# on linux
 endif
diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 9efc71524..26a64e67f 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -28,11 +28,13 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 
-#define NETMAP_WITH_LIBS
-#include 
+#include 
 #include 
+#include 
 
 #include 		/* htonl */
 
@@ -173,7 +175,7 @@ struct port_des {
 	unsigned int last_sync;
 	uint32_t last_tail;
 	struct overflow_queue *oq;
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	struct netmap_ring *ring;
 	struct group_des *group;
 };
@@ -375,7 +377,7 @@ free_buffers(void)
 	D("added %d buffers to netmap free list", tot);
 
 	for (i = 0; i < glob_arg.output_rings + 1; ++i) {
-		nm_close(ports[i].nmd);
+		nmport_close(ports[i].nmd);
 	}
 }
 
@@ -649,18 +651,6 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	/* extract the base name */
-	char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ?
-			glob_arg.ifname : glob_arg.ifname + 7;
-	if (strlen(nscan) > MAX_IFNAMELEN) {
-		D("name too long: %s (max %d)", nscan, MAX_IFNAMELEN);
-		return 1;
-	}
-	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
-	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
-		;
-	*nscan = '\0';
-
 	if (glob_arg.num_groups == 0)
 		parse_pipes("");
 
@@ -680,6 +670,15 @@ int main(int argc, char **argv)
 		return 1;
 	}
 	struct port_des *rxport = &ports[npipes];
+
+	rxport->nmd = nmport_prepare(glob_arg.ifname);
+	if (rxport->nmd == NULL) {
+		D("cannot parse %s", glob_arg.ifname);
+		return (1);
+	}
+	/* extract the base name */
+	strncpy(glob_arg.base_name, rxport->nmd->hdr.nr_name, MAX_IFNAMELEN);
+
 	init_groups();
 
 	memset(&counters_buf, 0, sizeof(counters_buf));
@@ -689,24 +688,15 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	/* we need base_req to specify pipes and extra bufs */
-	struct nmreq base_req;
-	memset(&base_req, 0, sizeof(base_req));
-
-	base_req.nr_arg1 = npipes;
-	base_req.nr_arg3 = glob_arg.extra_bufs;
+	rxport->nmd->reg.nr_extra_bufs = glob_arg.extra_bufs;
 
-	rxport->nmd = nm_open(glob_arg.ifname, &base_req, 0, NULL);
-
-	if (rxport->nmd == NULL) {
+	if (nmport_open_desc(rxport->nmd) < 0) {
 		D("cannot open %s", glob_arg.ifname);
 		return (1);
-	} else {
-		D("successfully opened %s (tx rings: %u)", glob_arg.ifname,
-		  rxport->nmd->req.nr_tx_slots);
 	}
+	D("successfully opened %s", glob_arg.ifname);
 
-	uint32_t extra_bufs = rxport->nmd->req.nr_arg3;
+	uint32_t extra_bufs = rxport->nmd->reg.nr_extra_bufs;
 	struct overflow_queue *oq = NULL;
 	/* reference ring to access the buffers */
 	rxport->ring = NETMAP_RXRING(rxport->nmd->nifp, 0);
@@ -774,15 +764,15 @@ int main(int argc, char **argv)
 			snprintf(p->interface, MAX_PORTNAMELEN, "%s%s{%d/xT@%d",
 					(strncmp(g->pipename, "vale", 4) ? "netmap:" : ""),
 					g->pipename, g->first_id + k,
-					rxport->nmd->req.nr_arg2);
+					rxport->nmd->reg.nr_mem_id);
 			D("opening pipe named %s", p->interface);
 
-			p->nmd = nm_open(p->interface, NULL, 0, rxport->nmd);
+			p->nmd = nmport_open(p->interface);
 
 			if (p->nmd == NULL) {
 				D("cannot open %s", p->interface);
 				return (1);
-			} else if (p->nmd->req.nr_arg2 != rxport->nmd->req.nr_arg2) {
+			} else if (p->nmd->mem != rxport->nmd->mem) {
 				D("failed to open pipe #%d in zero-copy mode, "
 					"please close any application that uses either pipe %s}%d, "
 				        "or %s{%d, and retry",
@@ -790,7 +780,7 @@ int main(int argc, char **argv)
 				return (1);
 			} else {
 				D("successfully opened pipe #%d %s (tx slots: %d)",
-				  k + 1, p->interface, p->nmd->req.nr_tx_slots);
+				  k + 1, p->interface, p->nmd->reg.nr_tx_slots);
 				p->ring = NETMAP_TXRING(p->nmd->nifp, 0);
 				p->last_tail = nm_ring_next(p->ring, p->ring->tail);
 			}

From 7829456c12e8dd97fbf04a85be6f9aa130c035b9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 23 Nov 2018 17:09:50 +0100
Subject: [PATCH 1700/2207] bridge: use the new API

---
 apps/bridge/GNUmakefile |  5 +++--
 apps/bridge/bridge.c    | 29 ++++++++++++++++-------------
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/apps/bridge/GNUmakefile b/apps/bridge/GNUmakefile
index 22238d521..042fc5db9 100644
--- a/apps/bridge/GNUmakefile
+++ b/apps/bridge/GNUmakefile
@@ -11,10 +11,11 @@ VPATH = $(SRCDIR)/apps/bridge
 NO_MAN=
 CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
-CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I$(SRCDIR)/libnetmap
 CFLAGS += -Wextra
 
-LDLIBS += -lpthread
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
+LDLIBS += -lnetmap
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt	# on linux
 endif
diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index f43adf077..e826f2498 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -10,9 +10,12 @@
  */
 
 #include 
-#define NETMAP_WITH_LIBS
-#include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 int verbose = 0;
 
@@ -32,7 +35,7 @@ sigint_h(int sig)
  * how many packets on this set of queues ?
  */
 int
-pkt_queued(struct nm_desc *d, int tx)
+pkt_queued(struct nmport_d *d, int tx)
 {
 	u_int i, tot = 0;
 
@@ -115,11 +118,11 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 
 /* move packts from src to destination */
 static int
-move(struct nm_desc *src, struct nm_desc *dst, u_int limit)
+move(struct nmport_d *src, struct nmport_d *dst, u_int limit)
 {
 	struct netmap_ring *txring, *rxring;
 	u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring;
-	const char *msg = (src->req.nr_flags == NR_REG_SW) ?
+	const char *msg = (src->reg.nr_flags == NR_REG_SW) ?
 		"host->net" : "net->host";
 
 	while (si <= src->last_rx_ring && di <= dst->last_tx_ring) {
@@ -175,7 +178,7 @@ main(int argc, char **argv)
 	struct pollfd pollfd[2];
 	int ch;
 	u_int burst = 1024, wait_link = 4;
-	struct nm_desc *pa = NULL, *pb = NULL;
+	struct nmport_d *pa = NULL, *pb = NULL;
 	char *ifa = NULL, *ifb = NULL;
 	char ifabuf[64] = { 0 };
 	int loopback = 0;
@@ -252,16 +255,16 @@ main(int argc, char **argv)
 	} else {
 		/* two different interfaces. Take all rings on if1 */
 	}
-	pa = nm_open(ifa, NULL, 0, NULL);
+	pa = nmport_open(ifa);
 	if (pa == NULL) {
 		D("cannot open %s", ifa);
 		return (1);
 	}
 	/* try to reuse the mmap() of the first interface, if possible */
-	pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa);
+	pb = nmport_open(ifb);
 	if (pb == NULL) {
 		D("cannot open %s", ifb);
-		nm_close(pa);
+		nmport_close(pa);
 		return (1);
 	}
 	zerocopy = zerocopy && (pa->mem == pb->mem);
@@ -275,8 +278,8 @@ main(int argc, char **argv)
 	D("Wait %d secs for link to come up...", wait_link);
 	sleep(wait_link);
 	D("Ready to go, %s 0x%x/%d <-> %s 0x%x/%d.",
-		pa->req.nr_name, pa->first_rx_ring, pa->req.nr_rx_rings,
-		pb->req.nr_name, pb->first_rx_ring, pb->req.nr_rx_rings);
+		pa->hdr.nr_name, pa->first_rx_ring, pa->reg.nr_rx_rings,
+		pb->hdr.nr_name, pb->first_rx_ring, pb->reg.nr_rx_rings);
 
 	/* main loop */
 	signal(SIGINT, sigint_h);
@@ -349,8 +352,8 @@ main(int argc, char **argv)
 		/* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here,
 		 * kernel will txsync on next poll(). */
 	}
-	nm_close(pb);
-	nm_close(pa);
+	nmport_close(pb);
+	nmport_close(pa);
 
 	return (0);
 }

From 33c9d7655f8a0fda53ad2dfde13c0ecb247145ae Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 23 Nov 2018 14:38:05 +0100
Subject: [PATCH 1701/2207] pkt-gen: use new API

---
 apps/pkt-gen/GNUmakefile |   5 +-
 apps/pkt-gen/pkt-gen.c   | 148 ++++++++++++++++++---------------------
 2 files changed, 73 insertions(+), 80 deletions(-)

diff --git a/apps/pkt-gen/GNUmakefile b/apps/pkt-gen/GNUmakefile
index a261876bc..62d6d5b2b 100644
--- a/apps/pkt-gen/GNUmakefile
+++ b/apps/pkt-gen/GNUmakefile
@@ -11,10 +11,11 @@ VPATH = $(SRCDIR)/apps/pkt-gen
 NO_MAN=
 CFLAGS = -O2 -pipe
 CFLAGS += -Werror -Wall -Wunused-function
-CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include
+CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I $(SRCDIR)/libnetmap
 CFLAGS += -Wextra -Wno-address-of-packed-member
 
-LDLIBS += -lpthread -lm
+LDFLAGS = -L $(BUILDDIR)/build-libnetmap
+LDLIBS += -lpthread -lm -lnetmap
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt	# on linux
 endif
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 0be2c781e..56ef4b608 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -39,13 +39,18 @@
 
 #define _GNU_SOURCE	/* for CPU_SET() */
 #include 
-#define NETMAP_WITH_LIBS
-#include 
+#include 
 
 
+#include 
+#include 
+#include 
 #include 	// isprint()
+#include 
 #include 	// sysconf()
 #include 
+#include 
+#include 
 #include 	/* ntohs */
 #if !defined(_WIN32) && !defined(linux)
 #include 	/* sysctl */
@@ -237,7 +242,8 @@ struct mac_range {
 };
 
 /* ifname can be netmap:foo-xxxx */
-#define MAX_IFNAMELEN	64	/* our buffer for ifname */
+#define MAX_IFNAMELEN	512	/* our buffer for ifname */
+//#define MAX_PKTSIZE	1536
 #define MAX_PKTSIZE	MAX_BODYSIZE	/* XXX: + IP_HDR + ETH_HDR */
 
 /* compact timestamp to fit into 60 byte packet. (enough to obtain RTT) */
@@ -289,7 +295,7 @@ struct glob_arg {
 
 	int affinity;
 	int main_fd;
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	int report_interval;		/* milliseconds between prints */
 	void *(*td_body)(void *);
 	int td_type;
@@ -323,7 +329,7 @@ struct targ {
 	int completed;
 	int cancel;
 	int fd;
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	/* these ought to be volatile, but they are
 	 * only sampled and errors should not accumulate
 	 */
@@ -516,16 +522,20 @@ extract_mac_range(struct mac_range *r)
 static int
 get_if_mtu(const struct glob_arg *g)
 {
-	char ifname[IFNAMSIZ];
 	struct ifreq ifreq;
 	int s, ret;
+	const char *ifname = g->nmd->hdr.nr_name;
+	size_t len;
 
-	if (!strncmp(g->ifname, "netmap:", 7) && !strchr(g->ifname, '{')
-			&& !strchr(g->ifname, '}')) {
-		/* Parse the interface name and ask the kernel for the
-		 * MTU value. */
-		strncpy(ifname, g->ifname+7, IFNAMSIZ-1);
-		ifname[strcspn(ifname, "-*^{}/@")] = '\0';
+	if (!strncmp(g->ifname, "netmap:", 7) && !strchr(ifname, '{')
+			&& !strchr(ifname, '}')) {
+
+		len = strlen(ifname);
+
+		if (len > IFNAMSIZ) {
+			D("'%s' too long, cannot ask for MTU", ifname);
+			return -1;
+		}
 
 		s = socket(AF_INET, SOCK_DGRAM, 0);
 		if (s < 0) {
@@ -534,7 +544,7 @@ get_if_mtu(const struct glob_arg *g)
 		}
 
 		memset(&ifreq, 0, sizeof(ifreq));
-		strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
+		memcpy(ifreq.ifr_name, ifname, len);
 
 		ret = ioctl(s, SIOCGIFMTU, &ifreq);
 		if (ret) {
@@ -623,7 +633,7 @@ system_ncpus(void)
  * and #rx-rings.
  */
 int
-parse_nmr_config(const char* conf, struct nmreq *nmr)
+parse_nmr_config(const char* conf, struct nmreq_register *nmr)
 {
 	char *w, *tok;
 	int i, v;
@@ -657,9 +667,7 @@ parse_nmr_config(const char* conf, struct nmreq *nmr)
 			nmr->nr_tx_rings, nmr->nr_tx_slots,
 			nmr->nr_rx_rings, nmr->nr_rx_slots);
 	free(w);
-	return (nmr->nr_tx_rings || nmr->nr_tx_slots ||
-		nmr->nr_rx_rings || nmr->nr_rx_slots) ?
-		NM_OPEN_RING_CFG : 0;
+	return 0;
 }
 
 
@@ -1111,20 +1119,22 @@ initialize_packet(struct targ *targ)
 static void
 get_vnet_hdr_len(struct glob_arg *g)
 {
-	struct nmreq req;
+	struct nmreq_header hdr;
+	struct nmreq_port_hdr ph;
 	int err;
 
-	memset(&req, 0, sizeof(req));
-	bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
-	req.nr_version = NETMAP_API;
-	req.nr_cmd = NETMAP_VNET_HDR_GET;
-	err = ioctl(g->main_fd, NIOCREGIF, &req);
+	hdr = g->nmd->hdr; /* copy name and version */
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
+	hdr.nr_options = 0;
+	memset(&ph, 0, sizeof(ph));
+	hdr.nr_body = (uintptr_t)&ph;
+	err = ioctl(g->main_fd, NIOCCTRL, &hdr);
 	if (err) {
 		D("Unable to get virtio-net header length");
 		return;
 	}
 
-	g->virt_header = req.nr_arg1;
+	g->virt_header = ph.nr_hdr_len;
 	if (g->virt_header) {
 		D("Port requires virtio-net header, length = %d",
 		  g->virt_header);
@@ -1135,17 +1145,18 @@ static void
 set_vnet_hdr_len(struct glob_arg *g)
 {
 	int err, l = g->virt_header;
-	struct nmreq req;
+	struct nmreq_header hdr;
+	struct nmreq_port_hdr ph;
 
 	if (l == 0)
 		return;
 
-	memset(&req, 0, sizeof(req));
-	bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name));
-	req.nr_version = NETMAP_API;
-	req.nr_cmd = NETMAP_BDG_VNET_HDR;
-	req.nr_arg1 = l;
-	err = ioctl(g->main_fd, NIOCREGIF, &req);
+	hdr = g->nmd->hdr; /* copy name and version */
+	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
+	hdr.nr_options = 0;
+	memset(&ph, 0, sizeof(ph));
+	hdr.nr_body = (uintptr_t)&ph;
+	err = ioctl(g->main_fd, NIOCCTRL, &hdr);
 	if (err) {
 		D("Unable to set virtio-net header length %d", l);
 	}
@@ -2483,7 +2494,7 @@ usage(int errcode)
 	exit(errcode);
 }
 
-static void
+static int
 start_threads(struct glob_arg *g) {
 	int i;
 
@@ -2503,31 +2514,23 @@ start_threads(struct glob_arg *g) {
 		memcpy(t->seed, &seed, sizeof(t->seed));
 
 		if (g->dev_type == DEV_NETMAP) {
-			struct nm_desc nmd = *g->nmd; /* copy, we overwrite ringid */
-			uint64_t nmd_flags = 0;
-			nmd.self = &nmd;
-
 			if (i > 0) {
 				/* the first thread uses the fd opened by the main
 				 * thread, the other threads re-open /dev/netmap
 				 */
-				if (g->nthreads > 1) {
-					nmd.req.nr_flags =
-						g->nmd->req.nr_flags & ~NR_REG_MASK;
-					nmd.req.nr_flags |= NR_REG_ONE_NIC;
-					nmd.req.nr_ringid = i;
-				}
+				t->nmd = nmport_clone(g->nmd);
+				if (t->nmd == NULL)
+					return -1;
+				t->nmd->reg.nr_ringid = i & NETMAP_RING_MASK;
 				/* Only touch one of the rings (rx is already ok) */
 				if (g->td_type == TD_TYPE_RECEIVER)
-					nmd_flags |= NETMAP_NO_TX_POLL;
+					t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL;
 
 				/* register interface. Override ifname and ringid etc. */
-				t->nmd = nm_open(t->g->ifname, NULL, nmd_flags |
-						NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd);
-				if (t->nmd == NULL) {
-					D("Unable to open %s: %s",
-							t->g->ifname, strerror(errno));
-					continue;
+				if (nmport_open_desc(t->nmd) < 0) {
+					nmport_undo_prepare(t->nmd);
+					t->nmd = NULL;
+					return -1;
 				}
 			} else {
 				t->nmd = g->nmd;
@@ -2559,6 +2562,7 @@ start_threads(struct glob_arg *g) {
 			t->used = 0;
 		}
 	}
+	return 0;
 }
 
 static void
@@ -2658,7 +2662,7 @@ main_thread(struct glob_arg *g)
 		if (targs[i].used)
 			pthread_join(targs[i].thread, NULL); /* blocking */
 		if (g->dev_type == DEV_NETMAP) {
-			nm_close(targs[i].nmd);
+			nmport_close(targs[i].nmd);
 			targs[i].nmd = NULL;
 		} else {
 			close(targs[i].fd);
@@ -3081,20 +3085,13 @@ main(int arc, char **argv)
     } else if (g.dummy_send) { /* but DEV_NETMAP */
 	D("using a dummy send routine");
     } else {
-	struct nm_desc base_nmd;
-	char errmsg[MAXERRMSG];
-	u_int flags;
-
-	bzero(&base_nmd, sizeof(base_nmd));
+	g.nmd = nmport_prepare(g.ifname);
+	if (g.nmd == NULL)
+		goto out;
 
-	parse_nmr_config(g.nmr_config, &base_nmd.req);
+	parse_nmr_config(g.nmr_config, &g.nmd->reg);
 
-	base_nmd.req.nr_flags |= NR_ACCEPT_VNET_HDR;
-
-	if (nm_parse(g.ifname, &base_nmd, errmsg) < 0) {
-		D("Invalid name '%s': %s", g.ifname, errmsg);
-		goto out;
-	}
+	g.nmd->reg.nr_flags |= NR_ACCEPT_VNET_HDR;
 
 	/*
 	 * Open the netmap device using nm_open().
@@ -3103,20 +3100,14 @@ main(int arc, char **argv)
 	 * which in turn may take some time for the PHY to
 	 * reconfigure. We do the open here to have time to reset.
 	 */
-	flags = NM_OPEN_IFNAME | NM_OPEN_ARG1 | NM_OPEN_ARG2 |
-		NM_OPEN_ARG3 | NM_OPEN_RING_CFG;
 	if (g.nthreads > 1) {
-		base_nmd.req.nr_flags &= ~NR_REG_MASK;
-		base_nmd.req.nr_flags |= NR_REG_ONE_NIC;
-		base_nmd.req.nr_ringid = 0;
+		g.nmd->reg.nr_mode = NR_REG_ONE_NIC;
+		g.nmd->reg.nr_ringid = 0;
 	}
-	g.nmd = nm_open(g.ifname, NULL, flags, &base_nmd);
-	if (g.nmd == NULL) {
-		D("Unable to open %s: %s", g.ifname, strerror(errno));
+	if (nmport_open_desc(g.nmd) < 0)
 		goto out;
-	}
 	g.main_fd = g.nmd->fd;
-	D("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
+	ND("mapped %luKB at %p", (unsigned long)(g.nmd->req.nr_memsize>>10),
 				g.nmd->mem);
 
 	if (g.virt_header) {
@@ -3131,9 +3122,9 @@ main(int arc, char **argv)
 
 	/* get num of queues in tx or rx */
 	if (g.td_type == TD_TYPE_SENDER)
-		devqueues = g.nmd->req.nr_tx_rings;
+		devqueues = g.nmd->reg.nr_tx_rings;
 	else
-		devqueues = g.nmd->req.nr_rx_rings;
+		devqueues = g.nmd->reg.nr_rx_rings;
 
 	/* validate provided nthreads. */
 	if (g.nthreads < 1 || g.nthreads > devqueues) {
@@ -3153,11 +3144,11 @@ main(int arc, char **argv)
 
 	if (verbose) {
 		struct netmap_if *nifp = g.nmd->nifp;
-		struct nmreq *req = &g.nmd->req;
+		struct nmreq_register *req = &g.nmd->reg;
 
-		D("nifp at offset %d, %d tx %d rx region %d",
+		D("nifp at offset %"PRIu64", %d tx %d rx region %d",
 		    req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
-		    req->nr_arg2);
+		    req->nr_mem_id);
 		for (i = 0; i <= req->nr_tx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
 			D("   TX%d at 0x%p slots %d", i,
@@ -3233,7 +3224,8 @@ main(int arc, char **argv)
 	if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) {
 		D("failed to block SIGINT: %s", strerror(errno));
 	}
-	start_threads(&g);
+	if (start_threads(&g) < 0)
+		return 1;
 	/* Install the handler and re-enable SIGINT for the main thread */
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = sigint_h;

From 81b7a0d89b80d30efa083b079206742832f08958 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Feb 2019 14:57:48 +0100
Subject: [PATCH 1702/2207] pkt-gen: add support for multiple host-rings

---
 apps/pkt-gen/pkt-gen.c | 44 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 56ef4b608..ef876f4fd 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -296,6 +296,7 @@ struct glob_arg {
 	int affinity;
 	int main_fd;
 	struct nmport_d *nmd;
+	uint32_t orig_mode;
 	int report_interval;		/* milliseconds between prints */
 	void *(*td_body)(void *);
 	int td_type;
@@ -2514,14 +2515,34 @@ start_threads(struct glob_arg *g) {
 		memcpy(t->seed, &seed, sizeof(t->seed));
 
 		if (g->dev_type == DEV_NETMAP) {
+			int m = -1;
+
+			/*
+			 * if the user wants both HW and SW rings, we need to
+			 * know when to switch from NR_REG_ONE_NIC to NR_REG_ONE_SW
+			 */
+			if (g->orig_mode == NR_REG_NIC_SW) {
+				m = (g->td_type == TD_TYPE_RECEIVER ?
+						g->nmd->reg.nr_rx_rings :
+						g->nmd->reg.nr_tx_rings);
+			}
+
 			if (i > 0) {
+				int j;
 				/* the first thread uses the fd opened by the main
 				 * thread, the other threads re-open /dev/netmap
 				 */
 				t->nmd = nmport_clone(g->nmd);
 				if (t->nmd == NULL)
 					return -1;
-				t->nmd->reg.nr_ringid = i & NETMAP_RING_MASK;
+
+				j = i;
+				if (m > 0 && j >= m) {
+					/* switch to the software rings */
+					t->nmd->reg.nr_mode = NR_REG_ONE_SW;
+					j -= m;
+				}
+				t->nmd->reg.nr_ringid = j & NETMAP_RING_MASK;
 				/* Only touch one of the rings (rx is already ok) */
 				if (g->td_type == TD_TYPE_RECEIVER)
 					t->nmd->reg.nr_flags |= NETMAP_NO_TX_POLL;
@@ -3100,8 +3121,19 @@ main(int arc, char **argv)
 	 * which in turn may take some time for the PHY to
 	 * reconfigure. We do the open here to have time to reset.
 	 */
+	g.orig_mode = g.nmd->reg.nr_mode;
 	if (g.nthreads > 1) {
-		g.nmd->reg.nr_mode = NR_REG_ONE_NIC;
+		switch (g.orig_mode) {
+		case NR_REG_ALL_NIC:
+		case NR_REG_NIC_SW:
+			g.nmd->reg.nr_mode = NR_REG_ONE_NIC;
+			break;
+		case NR_REG_SW:
+			g.nmd->reg.nr_mode = NR_REG_ONE_SW;
+			break;
+		default:
+			break;
+		}
 		g.nmd->reg.nr_ringid = 0;
 	}
 	if (nmport_open_desc(g.nmd) < 0)
@@ -3122,9 +3154,9 @@ main(int arc, char **argv)
 
 	/* get num of queues in tx or rx */
 	if (g.td_type == TD_TYPE_SENDER)
-		devqueues = g.nmd->reg.nr_tx_rings;
+		devqueues = g.nmd->reg.nr_tx_rings + g.nmd->reg.nr_host_tx_rings;
 	else
-		devqueues = g.nmd->reg.nr_rx_rings;
+		devqueues = g.nmd->reg.nr_rx_rings + g.nmd->reg.nr_host_rx_rings;
 
 	/* validate provided nthreads. */
 	if (g.nthreads < 1 || g.nthreads > devqueues) {
@@ -3149,12 +3181,12 @@ main(int arc, char **argv)
 		D("nifp at offset %"PRIu64", %d tx %d rx region %d",
 		    req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
 		    req->nr_mem_id);
-		for (i = 0; i <= req->nr_tx_rings; i++) {
+		for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
 			D("   TX%d at 0x%p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
 		}
-		for (i = 0; i <= req->nr_rx_rings; i++) {
+		for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
 			D("   RX%d at 0x%p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);

From 1d515239f2feb4ec2f1b48824d9376b6421fbdc4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Nov 2019 16:44:28 +0100
Subject: [PATCH 1703/2207] intest: run all tests on the new and legacy APIs

---
 utils/GNUmakefile                             |    1 +
 utils/fd_server-legacy.c                      |  349 ++++
 utils/fd_server-legacy.h                      |   28 +
 utils/fd_server.c                             |  118 +-
 utils/fd_server.h                             |    7 +-
 utils/functional-legacy.c                     | 1461 +++++++++++++++++
 utils/functional.c                            |   99 +-
 utils/randomized_tests                        |   51 +-
 utils/test_lib                                |    8 +-
 ...01_exclusive_open_ephemeral_vale_port_test |    6 +-
 ...2_exclusive_open_persistent_vale_port_test |    6 +-
 utils/tests/003_exclusive_open_pipe_test      |    6 +-
 ...tra_buf_send_rec_ephemeral_vale_ports_test |   10 +-
 ...ra_buf_send_rec_persistent_vale_ports_test |   10 +-
 utils/tests/006_extra_buf_send_rec_pipe_test  |    6 +-
 utils/tests/007_learning_bridge_test          |   18 +-
 utils/tests/008_partial_read_pipe_test        |   10 +-
 .../012_rec_cp_mon_ephemeral_vale_port_test   |   12 +-
 .../013_rec_cp_mon_persistent_vale_port_test  |   12 +-
 utils/tests/014_rec_cp_mon_pipe_test          |   12 +-
 .../015_rec_zcp_mon_ephemeral_vale_port_test  |   14 +-
 .../016_rec_zcp_mon_persistent_vale_port_test |   14 +-
 utils/tests/017_rec_zcp_mon_pipe_test         |   14 +-
 .../018_send_cp_mon_ephemeral_vale_port_test  |   12 +-
 .../019_send_cp_mon_persistent_vale_port_test |   12 +-
 utils/tests/020_send_cp_mon_pipe_test         |   12 +-
 .../021_send_rec_ephemeral_vale_ports_test    |   18 +-
 .../022_send_rec_persistent_vale_ports_test   |   18 +-
 utils/tests/023_send_rec_pipe_test            |   12 +-
 utils/tests/024_send_rec_veth_test            |   12 +-
 .../025_send_zcp_mon_ephemeral_vale_port_test |   12 +-
 ...026_send_zcp_mon_persistent_vale_port_test |   12 +-
 utils/tests/027_send_zcp_mon_pipe_test        |   16 +-
 33 files changed, 2135 insertions(+), 273 deletions(-)
 create mode 100644 utils/fd_server-legacy.c
 create mode 100644 utils/fd_server-legacy.h
 create mode 100644 utils/functional-legacy.c

diff --git a/utils/GNUmakefile b/utils/GNUmakefile
index c9653372d..2249ae7cd 100644
--- a/utils/GNUmakefile
+++ b/utils/GNUmakefile
@@ -1,6 +1,7 @@
 # For multiple programs using a single source file each,
 # we can just define 'progs' and create custom targets.
 PROGS	  = test_select testmmap test_nm functional ctrl-api-test fd_server
+PROGS	 += functional-legacy fd_server-legacy
 PROGS    += get_avail_tx_packets get_max_tx_packets extmem-example sync_kloop_test
 X86PROGS  = testlock testcsum producer
 LIBNETMAP =
diff --git a/utils/fd_server-legacy.c b/utils/fd_server-legacy.c
new file mode 100644
index 000000000..3ac01baee
--- /dev/null
+++ b/utils/fd_server-legacy.c
@@ -0,0 +1,349 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+
+#include "fd_server.h"
+
+struct nmd_entry {
+	char if_name[NETMAP_REQ_IFNAMSIZ];
+	struct nm_desc *nmd;
+	uint8_t is_in_use;
+	uint8_t is_open;
+};
+
+#define printf(format, ...) syslog(LOG_NOTICE, format, ##__VA_ARGS__)
+
+#define MAX_OPEN_IF 128
+struct nmd_entry entries[MAX_OPEN_IF];
+int num_entries = 0;
+
+static void
+print_request(struct fd_request *req)
+{
+
+	printf("action: %s, if_name: '%s'\n",
+	       req->action == FD_GET
+	               ? "FD_GET"
+	               : req->action == FD_RELEASE
+	                         ? "FD_RELEASE"
+	                         : req->action == FD_CLOSE ? "FD_CLOSE"
+	                                                   : "FD_STOP",
+	       req->if_name);
+}
+
+struct nmd_entry *
+search_des(const char *if_name)
+{
+	int i;
+
+	// printf("searching %s\n", if_name);
+	for (i = 0; i < num_entries; ++i) {
+		struct nmd_entry *entry = &entries[i];
+
+		// printf("i=%d, is_open=%d, is_in_use=%d, if_name=%s\n",
+		// 	i, entry->is_open, entry->is_in_use, entry->if_name);
+
+		if (entry->is_open == 0) {
+			continue;
+		}
+
+		if (strncmp(entry->if_name, if_name, IFNAMSIZ) == 0) {
+			// printf("finished searching with a match\n");
+			return entry;
+		}
+	}
+
+	// printf("finished searching without a match\n");
+	return NULL;
+}
+
+struct nmd_entry *
+get_free_des(void)
+{
+	if (num_entries == MAX_OPEN_IF) {
+		return NULL;
+	}
+
+	return &entries[num_entries++];
+}
+
+int
+get_fd(const char *if_name, struct fd_response *res)
+{
+	struct nmd_entry *entry;
+
+	entry = search_des(if_name);
+	if (entry != NULL) {
+		if (entry->is_in_use == 1) {
+			printf("if_name %s is in use\n", if_name);
+			res->result = EBUSY;
+			return -1;
+		}
+		memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
+		return entry->nmd->fd;
+	}
+
+	entry = get_free_des();
+	if (entry == NULL) {
+		printf("Out of memory\n");
+		res->result = ENOMEM;
+		return -1;
+	}
+
+	entry->nmd = nm_open(if_name, NULL, 0, NULL);
+	if (entry->nmd == NULL) {
+		printf("Failed to nm_open(%s) with error %d\n", if_name, errno);
+		res->result = errno;
+		return -1;
+	}
+	strncpy(entry->if_name, if_name, sizeof(entry->if_name));
+	entry->if_name[sizeof(entry->if_name) - 1] = '\0';
+
+	memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
+	entry->is_in_use = 1;
+	entry->is_open   = 1;
+	return entry->nmd->fd;
+}
+
+void
+release_fd(const char *if_name, struct fd_response *res)
+{
+	struct nmd_entry *entry;
+
+	entry = search_des(if_name);
+	if (entry == NULL) {
+		printf("if_name %s isn't open\n", if_name);
+		res->result = ENOENT;
+		return;
+	}
+
+	entry->is_in_use = 0;
+}
+
+void
+close_fd(const char *if_name, struct fd_response *res)
+{
+	struct nmd_entry *entry;
+	int ret;
+
+	if (if_name == NULL || strnlen(if_name, NETMAP_REQ_IFNAMSIZ) == 0) {
+		res->result = EINVAL;
+		return;
+	}
+
+	entry = search_des(if_name);
+	if (entry == NULL) {
+		res->result = ENOENT;
+		printf("if_name %s hasn't been opened\n", if_name);
+		return;
+	}
+
+	ret         = nm_close(entry->nmd);
+	res->result = ret;
+	if (ret != 0) {
+		printf("error while close interface %s\n", if_name);
+		return;
+	}
+	entry->is_in_use = 0;
+	entry->is_open   = 0;
+}
+
+int
+send_fd(int socket, int fd, void *buf, size_t buf_size)
+{
+	union {
+		char buf[CMSG_SPACE(sizeof(int))];
+		struct cmsghdr align;
+	} ancillary;
+	struct cmsghdr *cmsg;
+	struct iovec iov[1];
+	struct msghdr msg;
+	int ret;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len  = buf_size;
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_iov    = iov;
+	msg.msg_iovlen = 1;
+
+	if (fd >= 0) {
+		/* We need the ancillary data only when we're sending a file
+		 * descriptor, and a file descriptor cannot be negative.
+		 */
+		printf("sending a file descriptor\n");
+		msg.msg_control         = ancillary.buf;
+		msg.msg_controllen      = sizeof(ancillary.buf);
+		cmsg                    = CMSG_FIRSTHDR(&msg);
+		cmsg->cmsg_level        = SOL_SOCKET;
+		cmsg->cmsg_type         = SCM_RIGHTS;
+		cmsg->cmsg_len          = CMSG_LEN(sizeof(int));
+		memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+	}
+
+	ret = sendmsg(socket, &msg, 0);
+	return ret;
+}
+
+int
+handle_request(int accept_socket, int listen_socket)
+{
+	struct fd_response res;
+	struct fd_request req;
+	int fd = -1;
+	int amount;
+	int ret;
+
+	memset(&req, 0, sizeof(req));
+	amount = recv(accept_socket, &req, sizeof(struct fd_request), 0);
+	if (amount == -1) {
+		printf("error while receiving the request\n");
+		return -1;
+	}
+
+	print_request(&req);
+	memset(&res, 0, sizeof(res));
+	switch (req.action) {
+	case FD_GET:
+		fd = get_fd(req.if_name, &res);
+		break;
+	case FD_RELEASE:
+		release_fd(req.if_name, &res);
+		return 0;
+	case FD_CLOSE:
+		close_fd(req.if_name, &res);
+		return 0;
+	case FD_STOP:
+		printf("shutting down\n");
+		close(listen_socket);
+		close(accept_socket);
+		exit(EXIT_SUCCESS);
+		break;
+	default:
+		res.result = EOPNOTSUPP;
+	}
+
+	ret = send_fd(accept_socket, fd, &res, sizeof(struct fd_response));
+	if (ret == -1) {
+		printf("error while sending the reponse\n");
+	}
+	return ret;
+}
+
+void
+main_loop(void)
+{
+	struct sockaddr_un name;
+	int socket_fd;
+	int ret;
+
+	printf("starting up.\n");
+	if (unlink(SOCKET_NAME) == -1 && errno != ENOENT) {
+		printf("error %d during unlink()", errno);
+		exit(EXIT_FAILURE);
+	}
+	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+	if (socket_fd == -1) {
+		printf("error during socket()\n");
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&name, 0, sizeof(struct sockaddr_un));
+	name.sun_family = AF_UNIX;
+	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
+	ret = bind(socket_fd, (const struct sockaddr *)&name,
+	           sizeof(struct sockaddr_un));
+	if (ret == -1) {
+		printf("error during bind()\n");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = listen(socket_fd, 2);
+	if (ret == -1) {
+		printf("error during listen()");
+		exit(EXIT_FAILURE);
+	}
+
+	printf("listening\n");
+	for (;;) {
+		int conn_fd;
+		int ret;
+
+		conn_fd = accept(socket_fd, NULL, NULL);
+		if (conn_fd == -1) {
+			printf("error during accept(), shutting down\n");
+			exit(EXIT_FAILURE);
+		}
+
+		ret = handle_request(conn_fd, socket_fd);
+		if (ret == -1) {
+			printf("error while handling a request\n");
+		}
+		(void)ret;
+		close(conn_fd);
+	}
+}
+
+void
+daemonize(void)
+{
+	pid_t pid;
+	int i;
+
+	pid = fork();
+	if (pid < 0) {
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		exit(EXIT_SUCCESS);
+	}
+
+	if (setsid() == -1) {
+		exit(EXIT_FAILURE);
+	}
+
+	signal(SIGCHLD, SIG_IGN);
+	signal(SIGHUP, SIG_IGN);
+
+	pid = fork();
+	if (pid < 0) {
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		exit(EXIT_SUCCESS);
+	}
+
+	umask(0);
+
+	if (chdir("/") == -1) {
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
+		close(i);
+	}
+
+	openlog("nm_fd_server", LOG_PID, LOG_DAEMON);
+}
+
+int
+main()
+{
+	daemonize();
+	main_loop();
+	return 0;
+}
diff --git a/utils/fd_server-legacy.h b/utils/fd_server-legacy.h
new file mode 100644
index 000000000..3345b54f9
--- /dev/null
+++ b/utils/fd_server-legacy.h
@@ -0,0 +1,28 @@
+#ifndef FD_LIB_H
+#define FD_LIB_H
+
+#include 
+#include 
+#include 
+
+#define SOCKET_NAME "/tmp/netmap-fdserver-legacy"
+
+struct fd_request {
+#define FD_GET 1
+#define FD_RELEASE 2
+#define FD_CLOSE 3
+#define FD_STOP 4
+	uint8_t action;
+	char if_name[NETMAP_REQ_IFNAMSIZ];
+};
+
+struct fd_response {
+	int32_t result;
+	struct nmreq req;
+};
+
+int send_fd(int socket, int fd, void *buf, size_t buf_size);
+
+int recv_fd(int socket, int *fd, void *buf, size_t buf_size);
+
+#endif /* FD_LIB_H */
diff --git a/utils/fd_server.c b/utils/fd_server.c
index 3ac01baee..eee3a6cf1 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -12,21 +12,28 @@
 #include 
 #include 
 #include 
+#include 
 
-#include 
-#define NETMAP_WITH_LIBS
-#include 
+#include 
 
 #include "fd_server.h"
 
 struct nmd_entry {
 	char if_name[NETMAP_REQ_IFNAMSIZ];
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	uint8_t is_in_use;
 	uint8_t is_open;
 };
 
-#define printf(format, ...) syslog(LOG_NOTICE, format, ##__VA_ARGS__)
+int foreground = 0;
+
+#define msg(format, ...) do {					\
+	if (foreground) {					\
+		printf(format, ##__VA_ARGS__);			\
+	} else {						\
+		syslog(LOG_NOTICE, format, ##__VA_ARGS__);	\
+	}							\
+} while(0)
 
 #define MAX_OPEN_IF 128
 struct nmd_entry entries[MAX_OPEN_IF];
@@ -36,7 +43,7 @@ static void
 print_request(struct fd_request *req)
 {
 
-	printf("action: %s, if_name: '%s'\n",
+	msg("action: %s, if_name: '%s'\n",
 	       req->action == FD_GET
 	               ? "FD_GET"
 	               : req->action == FD_RELEASE
@@ -51,11 +58,11 @@ search_des(const char *if_name)
 {
 	int i;
 
-	// printf("searching %s\n", if_name);
+	// msg("searching %s\n", if_name);
 	for (i = 0; i < num_entries; ++i) {
 		struct nmd_entry *entry = &entries[i];
 
-		// printf("i=%d, is_open=%d, is_in_use=%d, if_name=%s\n",
+		// msg("i=%d, is_open=%d, is_in_use=%d, if_name=%s\n",
 		// 	i, entry->is_open, entry->is_in_use, entry->if_name);
 
 		if (entry->is_open == 0) {
@@ -63,12 +70,12 @@ search_des(const char *if_name)
 		}
 
 		if (strncmp(entry->if_name, if_name, IFNAMSIZ) == 0) {
-			// printf("finished searching with a match\n");
+			// msg("finished searching with a match\n");
 			return entry;
 		}
 	}
 
-	// printf("finished searching without a match\n");
+	// msg("finished searching without a match\n");
 	return NULL;
 }
 
@@ -82,6 +89,24 @@ get_free_des(void)
 	return &entries[num_entries++];
 }
 
+int
+marshal(struct fd_response *res, struct nmd_entry *entry)
+{
+	if (entry->nmd->hdr.nr_options) {
+		msg("options are not supported\n");
+		res->result = EOPNOTSUPP;
+		return -1;
+	}
+
+	// copy the header
+	res->hdr = entry->nmd->hdr;
+	res->hdr.nr_options = 0;
+	res->hdr.nr_body = 0;
+	// copy the body
+	res->reg = entry->nmd->reg;
+	return 0;
+}
+
 int
 get_fd(const char *if_name, struct fd_response *res)
 {
@@ -90,31 +115,34 @@ get_fd(const char *if_name, struct fd_response *res)
 	entry = search_des(if_name);
 	if (entry != NULL) {
 		if (entry->is_in_use == 1) {
-			printf("if_name %s is in use\n", if_name);
+			msg("if_name %s is in use\n", if_name);
 			res->result = EBUSY;
 			return -1;
 		}
-		memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
+		if (marshal(res, entry) < 0)
+			return -1;
 		return entry->nmd->fd;
 	}
 
 	entry = get_free_des();
 	if (entry == NULL) {
-		printf("Out of memory\n");
+		msg("Out of memory\n");
 		res->result = ENOMEM;
 		return -1;
 	}
 
-	entry->nmd = nm_open(if_name, NULL, 0, NULL);
+	entry->nmd = nmport_open(if_name);
 	if (entry->nmd == NULL) {
-		printf("Failed to nm_open(%s) with error %d\n", if_name, errno);
+		msg("Failed to nm_open(%s) with error %d\n", if_name, errno);
 		res->result = errno;
 		return -1;
 	}
 	strncpy(entry->if_name, if_name, sizeof(entry->if_name));
 	entry->if_name[sizeof(entry->if_name) - 1] = '\0';
 
-	memcpy(&res->req, &entry->nmd->req, sizeof(entry->nmd->req));
+	if (marshal(res, entry) < 0)
+		return -1;
+	res->result = 0;
 	entry->is_in_use = 1;
 	entry->is_open   = 1;
 	return entry->nmd->fd;
@@ -127,7 +155,7 @@ release_fd(const char *if_name, struct fd_response *res)
 
 	entry = search_des(if_name);
 	if (entry == NULL) {
-		printf("if_name %s isn't open\n", if_name);
+		msg("if_name %s isn't open\n", if_name);
 		res->result = ENOENT;
 		return;
 	}
@@ -139,7 +167,6 @@ void
 close_fd(const char *if_name, struct fd_response *res)
 {
 	struct nmd_entry *entry;
-	int ret;
 
 	if (if_name == NULL || strnlen(if_name, NETMAP_REQ_IFNAMSIZ) == 0) {
 		res->result = EINVAL;
@@ -149,16 +176,12 @@ close_fd(const char *if_name, struct fd_response *res)
 	entry = search_des(if_name);
 	if (entry == NULL) {
 		res->result = ENOENT;
-		printf("if_name %s hasn't been opened\n", if_name);
+		msg("if_name %s hasn't been opened\n", if_name);
 		return;
 	}
 
-	ret         = nm_close(entry->nmd);
-	res->result = ret;
-	if (ret != 0) {
-		printf("error while close interface %s\n", if_name);
-		return;
-	}
+	nmport_close(entry->nmd);
+	res->result = 0;
 	entry->is_in_use = 0;
 	entry->is_open   = 0;
 }
@@ -185,7 +208,7 @@ send_fd(int socket, int fd, void *buf, size_t buf_size)
 		/* We need the ancillary data only when we're sending a file
 		 * descriptor, and a file descriptor cannot be negative.
 		 */
-		printf("sending a file descriptor\n");
+		msg("sending a file descriptor\n");
 		msg.msg_control         = ancillary.buf;
 		msg.msg_controllen      = sizeof(ancillary.buf);
 		cmsg                    = CMSG_FIRSTHDR(&msg);
@@ -211,12 +234,11 @@ handle_request(int accept_socket, int listen_socket)
 	memset(&req, 0, sizeof(req));
 	amount = recv(accept_socket, &req, sizeof(struct fd_request), 0);
 	if (amount == -1) {
-		printf("error while receiving the request\n");
+		msg("error while receiving the request\n");
 		return -1;
 	}
 
 	print_request(&req);
-	memset(&res, 0, sizeof(res));
 	switch (req.action) {
 	case FD_GET:
 		fd = get_fd(req.if_name, &res);
@@ -228,7 +250,7 @@ handle_request(int accept_socket, int listen_socket)
 		close_fd(req.if_name, &res);
 		return 0;
 	case FD_STOP:
-		printf("shutting down\n");
+		msg("shutting down\n");
 		close(listen_socket);
 		close(accept_socket);
 		exit(EXIT_SUCCESS);
@@ -237,9 +259,9 @@ handle_request(int accept_socket, int listen_socket)
 		res.result = EOPNOTSUPP;
 	}
 
-	ret = send_fd(accept_socket, fd, &res, sizeof(struct fd_response));
+	ret = send_fd(accept_socket, fd, &res, sizeof(res));
 	if (ret == -1) {
-		printf("error while sending the reponse\n");
+		msg("error while sending the reponse\n");
 	}
 	return ret;
 }
@@ -251,14 +273,14 @@ main_loop(void)
 	int socket_fd;
 	int ret;
 
-	printf("starting up.\n");
+	msg("starting up.\n");
 	if (unlink(SOCKET_NAME) == -1 && errno != ENOENT) {
-		printf("error %d during unlink()", errno);
+		msg("error %d during unlink()", errno);
 		exit(EXIT_FAILURE);
 	}
 	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
 	if (socket_fd == -1) {
-		printf("error during socket()\n");
+		msg("error during socket()\n");
 		exit(EXIT_FAILURE);
 	}
 
@@ -268,30 +290,30 @@ main_loop(void)
 	ret = bind(socket_fd, (const struct sockaddr *)&name,
 	           sizeof(struct sockaddr_un));
 	if (ret == -1) {
-		printf("error during bind()\n");
+		msg("error during bind()\n");
 		exit(EXIT_FAILURE);
 	}
 
 	ret = listen(socket_fd, 2);
 	if (ret == -1) {
-		printf("error during listen()");
+		msg("error during listen()");
 		exit(EXIT_FAILURE);
 	}
 
-	printf("listening\n");
+	msg("listening\n");
 	for (;;) {
 		int conn_fd;
 		int ret;
 
 		conn_fd = accept(socket_fd, NULL, NULL);
 		if (conn_fd == -1) {
-			printf("error during accept(), shutting down\n");
+			msg("error during accept(), shutting down\n");
 			exit(EXIT_FAILURE);
 		}
 
 		ret = handle_request(conn_fd, socket_fd);
 		if (ret == -1) {
-			printf("error while handling a request\n");
+			msg("error while handling a request\n");
 		}
 		(void)ret;
 		close(conn_fd);
@@ -341,9 +363,23 @@ daemonize(void)
 }
 
 int
-main()
+main(int argc, char *argv[])
 {
-	daemonize();
+	int opt;
+
+	while ( (opt = getopt(argc, argv, "f")) != -1) {
+		switch (opt) {
+		case 'f':
+			foreground = 1;
+			break;
+		default:
+			fprintf(stderr, "Unknown option: %c\n", opt);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	if (!foreground)
+		daemonize();
 	main_loop();
 	return 0;
 }
diff --git a/utils/fd_server.h b/utils/fd_server.h
index 197d93505..825318dea 100644
--- a/utils/fd_server.h
+++ b/utils/fd_server.h
@@ -5,7 +5,7 @@
 #include 
 #include 
 
-#define SOCKET_NAME "/tmp/my_unix_socket"
+#define SOCKET_NAME "/tmp/netmap-fdserver"
 
 struct fd_request {
 #define FD_GET 1
@@ -18,11 +18,12 @@ struct fd_request {
 
 struct fd_response {
 	int32_t result;
-	struct nmreq req;
+	struct nmreq_header hdr;
+	struct nmreq_register reg;
 };
 
 int send_fd(int socket, int fd, void *buf, size_t buf_size);
 
 int recv_fd(int socket, int *fd, void *buf, size_t buf_size);
 
-#endif /* FD_LIB_H */
\ No newline at end of file
+#endif /* FD_LIB_H */
diff --git a/utils/functional-legacy.c b/utils/functional-legacy.c
new file mode 100644
index 000000000..6c6c6eec2
--- /dev/null
+++ b/utils/functional-legacy.c
@@ -0,0 +1,1461 @@
+/*
+ * A tool for functional testing netmap transmission and reception.
+ *
+ * Copyright (C) 2018 Vincenzo Maffione. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#define NETMAP_WITH_LIBS
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "fd_server-legacy.h"
+
+#define ETH_ADDR_LEN 6
+
+struct Event {
+	unsigned evtype;
+#define EVENT_TYPE_RX 0x1
+#define EVENT_TYPE_TX 0x2
+#define EVENT_TYPE_PAUSE 0x3
+	unsigned num; /* > 1 if repeated event */
+
+	/* Tx and Rx event. */
+	unsigned pkt_len;
+	char filler;
+
+	/* Pause event. */
+	unsigned long long usecs;
+};
+
+struct extra_buffer {
+	uint32_t buf_idx;
+	TAILQ_ENTRY(extra_buffer) list_entry;
+};
+
+;
+
+struct Global {
+	struct nm_desc *nmd;
+	const char *ifname;
+	unsigned wait_link_secs;    /* wait for link */
+	unsigned timeout_secs;      /* transmit/receive timeout */
+	int ignore_if_not_matching; /* ignore certain received packets */
+	int success_if_no_receive;  /* exit status 0 if we receive no packets */
+	int sequential_fill;        /* increment fill char for multi-packets
+	                            operations */
+	int request_from_fd_server; /* false --> directly open the interface */
+
+#define LV_ERROR_MSG 1
+#define LV_DEBUG_SEND_RECV 2
+#define LV_DEBUG_EXTRA_BUF 3
+#define LV_DEBUG_BUILD_PACKET 4
+#define LV_DEBUG_PARSE_ARGS 5
+	int verbosity_level;
+
+	/* List of currently not in use normal buffers. */
+	TAILQ_HEAD(extra_buf_head, extra_buffer) extra_buffers_head;
+	unsigned extra_buffers_num; /* number of granted extra buffers */
+
+#define MAX_PKT_SIZE 65536
+	char pktm[MAX_PKT_SIZE]; /* packet model */
+	unsigned pktm_len;       /* packet model length */
+	char pktr[MAX_PKT_SIZE]; /* packet received */
+	unsigned pktr_len;       /* length of received packet */
+	unsigned max_frag_size;  /* max bytes per netmap TX slot */
+
+	char src_mac[ETH_ADDR_LEN];
+	char dst_mac[ETH_ADDR_LEN];
+	uint32_t src_ip;
+	uint32_t dst_ip;
+	uint16_t src_port;
+	uint16_t dst_port;
+	char filler;
+
+#define MAX_EVENTS 64
+	unsigned num_events;
+	struct Event events[MAX_EVENTS];
+	unsigned num_loops;
+};
+
+void release_if_fd(struct Global *, const char *);
+void release_extra_buffers(struct Global *);
+
+void
+verbose_print(int current_verbosity, int required_verbosity, char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	if (current_verbosity >= required_verbosity) {
+		vprintf(format, args);
+	}
+
+	va_end(args);
+}
+
+void
+verbose_perror(int current_verbosity, int required_verbosity, char *str)
+{
+	if (current_verbosity >= required_verbosity) {
+		perror(str);
+	}
+}
+
+void
+cleanup(struct Global *g)
+{
+	if (g->extra_buffers_num > 0) {
+		release_extra_buffers(g);
+	}
+
+	if (g->request_from_fd_server) {
+		release_if_fd(g, g->ifname);
+	} else {
+		nm_close(g->nmd);
+	}
+}
+
+static void
+fill_packet_field(struct Global *g, unsigned offset, const char *content,
+                  unsigned content_len)
+{
+	if (offset + content_len > sizeof(g->pktm)) {
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Packet layout overflow: %u + %u > %lu\n", offset,
+		              content_len, sizeof(g->pktm));
+		cleanup(g);
+		exit(EXIT_FAILURE);
+	}
+
+	memcpy(g->pktm + offset, content, content_len);
+}
+
+static void
+fill_packet_8bit(struct Global *g, unsigned offset, uint8_t val)
+{
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_16bit(struct Global *g, unsigned offset, uint16_t val)
+{
+	val = htons(val);
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+static void
+fill_packet_32bit(struct Global *g, unsigned offset, uint32_t val)
+{
+	val = htonl(val);
+	fill_packet_field(g, offset, (const char *)&val, sizeof(val));
+}
+
+/* Compute the checksum of the given ip header. */
+static uint32_t
+checksum(const void *data, uint16_t len, uint32_t sum /* host endianness */)
+{
+	const uint8_t *addr = data;
+	uint32_t i;
+
+	/* Checksum all the pairs of bytes first... */
+	for (i = 0; i < (len & ~1U); i += 2) {
+		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
+		if (sum > 0xFFFF) {
+			sum -= 0xFFFF;
+		}
+	}
+	/*
+	 * If there's a single byte left over, checksum it, too.
+	 * Network byte order is big-endian, so the remaining byte is
+	 * the high byte.
+	 */
+	if (i < len) {
+		sum += addr[i] << 8;
+		if (sum > 0xFFFF) {
+			sum -= 0xFFFF;
+		}
+	}
+	return sum;
+}
+
+static uint16_t
+wrapsum(uint32_t sum /* host endianness */)
+{
+	sum = ~sum & 0xFFFF;
+	return sum; /* host endianness */
+}
+
+static void
+build_packet(struct Global *g)
+{
+	unsigned ofs = 0;
+	unsigned ethofs;
+	unsigned ipofs;
+	unsigned udpofs;
+	unsigned pldofs;
+
+	memset(g->pktm, 0, sizeof(g->pktm));
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: starting at ofs %u\n", __func__, ofs);
+
+	ethofs = ofs;
+	(void)ethofs;
+	/* Ethernet destination and source MAC address plus ethertype. */
+	fill_packet_field(g, ofs, g->dst_mac, ETH_ADDR_LEN);
+	ofs += ETH_ADDR_LEN;
+	fill_packet_field(g, ofs, g->src_mac, ETH_ADDR_LEN);
+	ofs += ETH_ADDR_LEN;
+	fill_packet_16bit(g, ofs, ETHERTYPE_IP);
+	ofs += 2;
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: eth done, ofs %u\n", __func__, ofs);
+
+	ipofs = ofs;
+	/* First byte of IP header. */
+	fill_packet_8bit(g, ofs, (IPVERSION << 4) | ((sizeof(struct ip)) >> 2));
+	ofs += 1;
+	/* Skip QoS byte. */
+	ofs += 1;
+	/* Total length. */
+	fill_packet_16bit(g, ofs, g->pktm_len - ipofs);
+	ofs += 2;
+	/* Skip identification field. */
+	ofs += 2;
+	/* Offset (and flags) field. */
+	fill_packet_16bit(g, ofs, IP_DF);
+	ofs += 2;
+	/* TTL. */
+	fill_packet_8bit(g, ofs, IPDEFTTL);
+	ofs += 1;
+	/* Protocol. */
+	fill_packet_8bit(g, ofs, IPPROTO_UDP);
+	ofs += 1;
+	/* Skip checksum for now. */
+	ofs += 2;
+	/* Source IP address. */
+	fill_packet_32bit(g, ofs, g->src_ip);
+	ofs += 4;
+	/* Dst IP address. */
+	fill_packet_32bit(g, ofs, g->dst_ip);
+	ofs += 4;
+	/* Now put the checksum. */
+	fill_packet_16bit(
+	        g, ipofs + 10,
+	        wrapsum(checksum(g->pktm + ipofs, sizeof(struct ip), 0)));
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: ip done, ofs %u\n", __func__, ofs);
+
+	udpofs = ofs;
+	/* UDP source port. */
+	fill_packet_16bit(g, ofs, g->src_port);
+	ofs += 2;
+	/* UDP source port. */
+	fill_packet_16bit(g, ofs, g->dst_port);
+	ofs += 2;
+	/* UDP length (UDP header + data). */
+	fill_packet_16bit(g, ofs, g->pktm_len - udpofs);
+	ofs += 2;
+	/* Skip the UDP checksum for now. */
+	ofs += 2;
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: udp done, ofs %u\n", __func__, ofs);
+
+	/* Fill UDP payload. */
+	pldofs = ofs;
+	for (; ofs < g->pktm_len; ofs++) {
+		fill_packet_8bit(g, ofs, g->filler);
+	}
+	verbose_print(g->verbosity_level, LV_DEBUG_BUILD_PACKET,
+	              "%s: payload done, ofs %u\n", __func__, ofs);
+
+	/* Put the UDP checksum now.
+	 * Magic: taken from sbin/dhclient/packet.c */
+	fill_packet_16bit(
+	        g, udpofs + 6,
+	        wrapsum(checksum(
+	                /* udp header */ g->pktm + udpofs,
+	                sizeof(struct udphdr),
+	                checksum(/* udp payload */ g->pktm + pldofs,
+	                         g->pktm_len - pldofs,
+	                         checksum(/* pseudo header */ g->pktm + ipofs +
+	                                          12,
+	                                  2 * sizeof(g->src_ip),
+	                                  IPPROTO_UDP + (uint32_t)(g->pktm_len -
+	                                                           udpofs))))));
+}
+
+static int
+tx_flush(struct Global *g)
+{
+	struct nm_desc *nmd = g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	int i;
+
+	for (;;) {
+		int pending = 0;
+		for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+			struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+			pending += nm_tx_pending(ring);
+		}
+
+		if (!pending) {
+			return 0;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+}
+
+uint64_t
+ring_avail_packets(struct netmap_ring *ring, unsigned pkt_len)
+{
+	uint64_t slot_per_packet;
+
+	slot_per_packet = ceil((double)pkt_len / (double)ring->nr_buf_size);
+	return nm_ring_space(ring) / slot_per_packet;
+}
+
+uint64_t
+adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t sends_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+
+		sends_available += ring_avail_packets(ring, pkt_len);
+	}
+
+	return sends_available;
+}
+
+void
+put_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+	unsigned head  = ring->head;
+	unsigned frags = 0;
+	unsigned ofs   = 0;
+
+	for (;;) {
+		struct netmap_slot *slot = &ring->slot[head];
+		char *buf                = NETMAP_BUF(ring, slot->buf_idx);
+		unsigned copysize        = g->pktm_len - ofs;
+
+		if (copysize > ring->nr_buf_size) {
+			copysize = ring->nr_buf_size;
+		}
+		if (copysize > g->max_frag_size) {
+			copysize = g->max_frag_size;
+		}
+
+		memcpy(buf, g->pktm + ofs, copysize);
+		ofs += copysize;
+		slot->len   = copysize;
+		slot->flags = NS_MOREFRAG;
+		head        = nm_ring_next(ring, head);
+		frags++;
+		if (ofs >= g->pktm_len) {
+			/* Last fragment. */
+			assert(ofs == g->pktm_len);
+			slot->flags = NS_REPORT;
+			break;
+		}
+	}
+
+	ring->head = ring->cur = head;
+	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+	              "packet (%u bytes, %u frags) placed to TX\n", g->pktm_len,
+	              frags);
+}
+
+/* Used for multi-packets sequential send/receive actions */
+char
+next_fill(char cur_fill)
+{
+	if (cur_fill == 'z')
+		return 'a';
+	if (cur_fill == 'Z')
+		return 'A';
+	return ++cur_fill;
+}
+
+/* Transmit packets_num packets using any combination of TX rings. */
+static int
+tx(struct Global *g, unsigned packets_num)
+{
+	struct nm_desc *nmd = g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	unsigned int i;
+
+	/* We cycle here until either we timeout or we find enough space. */
+	for (;;) {
+		if (adapter_avail_sends(nmd, g->pktm_len) >= packets_num) {
+			break;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		/* Retry after a short while. */
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+		ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	}
+
+	/* Once we have enough space, we start filling slots. We might use
+	 * multiple rings.
+	 */
+	for (i = nmd->first_tx_ring; i <= nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(nmd->nifp, i);
+		uint64_t ring_sends_num;
+
+		for (ring_sends_num = ring_avail_packets(ring, g->pktm_len);
+		     ring_sends_num > 0 && packets_num > 0;
+		     --ring_sends_num, --packets_num) {
+			put_one_packet(g, ring);
+
+			if (g->sequential_fill == 1) {
+				g->filler = next_fill(g->filler);
+				build_packet(g);
+			}
+		}
+
+		if (packets_num == 0) {
+			break;
+		}
+	}
+
+	assert(packets_num == 0);
+	/* Once we're done we sync, sending all packets at once. */
+	ioctl(nmd->fd, NIOCTXSYNC, NULL);
+	return 0;
+}
+
+/* If -I option is specified, we want to ignore frames that don't match
+ * our expected ethernet header.
+ * This function currently assumes that Ethernet header starts from
+ * the beginning of the packet buffers. */
+static int
+ignore_received_frame(struct Global *g)
+{
+	if (!g->ignore_if_not_matching) {
+		return 0; /* don't ignore */
+	}
+
+	if (g->pktr_len < 14 || memcmp(g->pktm, g->pktr, 14) != 0) {
+		return 1; /* ignore */
+	}
+
+	return 0; /* don't ignore */
+}
+
+uint64_t
+adapter_avail_receives(struct nm_desc *nmd, unsigned pkt_len)
+{
+	uint64_t receives_available = 0;
+	unsigned int i;
+
+	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+
+		receives_available += ring_avail_packets(ring, pkt_len);
+	}
+
+	return receives_available;
+}
+
+static int
+rx_check(struct Global *g)
+{
+	unsigned i;
+
+	if (g->pktr_len != g->pktm_len) {
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Received packet length (%u) different from "
+		              "expected (%u bytes)\n",
+		              g->pktr_len, g->pktm_len);
+		return -1;
+	}
+
+	for (i = 0; i < g->pktr_len; i++) {
+		if (g->pktr[i] != g->pktm[i]) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Received packet differs from model at "
+			              "offset %u (0x%02x!=0x%02x)\n",
+			              i, g->pktr[i], (uint8_t)g->pktm[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int
+read_one_packet(struct Global *g, struct netmap_ring *ring)
+{
+	unsigned head = ring->head;
+	int frags     = 0;
+
+	g->pktr_len = 0;
+	for (;;) {
+		struct netmap_slot *slot = &ring->slot[head];
+		char *buf                = NETMAP_BUF(ring, slot->buf_idx);
+
+		if (g->pktr_len + slot->len > sizeof(g->pktr)) {
+			/* Sanity check. */
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Error: received packet too "
+			              "large "
+			              "(>= %u bytes) ",
+			              g->pktr_len + slot->len);
+			cleanup(g);
+			exit(EXIT_FAILURE);
+		}
+
+		memcpy(g->pktr + g->pktr_len, buf, slot->len);
+		g->pktr_len += slot->len;
+		head = nm_ring_next(ring, head);
+		frags++;
+		if (!(slot->flags & NS_MOREFRAG)) {
+			break;
+		}
+
+		if (head == ring->tail) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "warning: truncated packet "
+			              "(len=%u)\n",
+			              g->pktr_len);
+			frags = -1;
+			break;
+		}
+	}
+
+	ring->head = ring->cur = head;
+	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+	              "packet (%u bytes, %d frags) received "
+	              "from RX\n",
+	              g->pktr_len, frags);
+	return frags;
+}
+
+/* Receive packets_num packets from any combination of RX rings. */
+static int
+rx(struct Global *g, unsigned packets_num)
+{
+	struct nm_desc *nmd = g->nmd;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	unsigned int i;
+
+	/* We cycle here until either we timeout or we find enough space. */
+	for (;;) {
+	again:
+		if (adapter_avail_receives(nmd, g->pktm_len) >= packets_num) {
+			break;
+		}
+
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
+			/* -n flag */
+			return g->success_if_no_receive == 1 ? 0 : -1;
+		}
+
+		/* Retry after a short while. */
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+		ioctl(nmd->fd, NIOCRXSYNC, NULL);
+	}
+
+	/* Once we have enough space, we start reading packets. We might use
+	 * multiple rings.
+	 */
+	for (i = nmd->first_rx_ring; i <= nmd->last_rx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_RXRING(nmd->nifp, i);
+		uint64_t ring_receives_num;
+
+		for (ring_receives_num = ring_avail_packets(ring, g->pktm_len);
+		     ring_receives_num > 0 && packets_num > 0;
+		     --ring_receives_num, --packets_num) {
+			int frags = 0;
+
+			frags = read_one_packet(g, ring);
+			if (frags == -1) {
+				break; /* Truncated packet, skip this ring. */
+			}
+
+			if (ignore_received_frame(g)) {
+				verbose_print(g->verbosity_level,
+				              LV_DEBUG_SEND_RECV,
+				              "(ignoring packet with %u bytes "
+				              "and "
+				              "%d frags received from RX ring "
+				              "#%d)\n",
+				              g->pktr_len, frags, i);
+				elapsed_ms = 0;
+				/* We can go back there, because we're
+				 * decrementing packets_num each time, therefore
+				 * the we will wait only for the remaining
+				 * packets.
+				 */
+				goto again;
+			}
+
+			/* As soon as we find a packet wich doesn't match our
+			 * packet model we exit with status EXIT_FAILURE.
+			 */
+			if (rx_check(g)) {
+				cleanup(g);
+				exit(EXIT_FAILURE);
+			}
+
+			if (g->sequential_fill == 1) {
+				g->filler = next_fill(g->filler);
+				build_packet(g);
+			}
+		}
+
+		if (packets_num == 0) {
+			break;
+		}
+	}
+
+	assert(packets_num == 0);
+	/* Once we're done we sync, freeing all slots at once. */
+	ioctl(nmd->fd, NIOCRXSYNC, NULL);
+	return 0;
+}
+
+static int
+parse_txrx_event(const char *opt, unsigned event_type, struct Event *event,
+                 int verbosity_level)
+{
+	char *strbuf = strdup(opt);
+	char *save   = strbuf;
+	int more;
+	char *c;
+	int ret = -1;
+
+	if (!strbuf || strlen(strbuf) == 0) {
+		goto out;
+	}
+
+	event->evtype = event_type;
+	event->filler = 'a';
+	event->num    = 1;
+
+	for (c = strbuf; *c != '\0' && *c != ':'; c++) {
+	}
+	more           = (*c == ':');
+	*c             = '\0';
+	event->pkt_len = atoi(strbuf);
+	if (event->pkt_len == 0) {
+		goto out;
+	}
+	if (more) {
+		strbuf = c + 1;
+		for (c = strbuf; *c != '\0' && *c != ':'; c++) {
+		}
+		more          = (*c == ':');
+		*c            = '\0';
+		event->filler = strbuf[0];
+	}
+	if (more) {
+		strbuf = c + 1;
+		for (c = strbuf; *c != '\0'; c++) {
+		}
+		event->num = atoi(strbuf);
+		if (event->num == 0) {
+			goto out;
+		}
+	}
+
+	ret = 0;
+	verbose_print(verbosity_level, LV_DEBUG_PARSE_ARGS, "parsed %u:%c:%u\n",
+	              event->pkt_len, event->filler, event->num);
+out:
+	if (save) {
+		free(save);
+	}
+	return ret;
+}
+
+static int
+parse_pause_event(const char *opt, struct Event *event, int verbosity_level)
+{
+	char *strbuf = strdup(opt);
+	char *save   = strbuf;
+	unsigned mul = 1000000;
+	int ret      = -1;
+
+	while (*strbuf != '\0' && isdigit(*strbuf)) {
+		strbuf++;
+	}
+	if (!strcmp(strbuf, "us")) {
+		mul = 1;
+	} else if (!strcmp(strbuf, "ms")) {
+		mul = 1000;
+	} else if (strcmp(strbuf, "s") && strcmp(strbuf, "")) {
+		goto out;
+	}
+
+	event->evtype = EVENT_TYPE_PAUSE;
+	event->usecs  = atoi(save);
+	if (event->usecs == 0) {
+		goto out;
+	}
+
+	event->usecs *= mul;
+	event->num = 1;
+	ret        = 0;
+	verbose_print(verbosity_level, LV_DEBUG_PARSE_ARGS,
+	              "parsed %llu usecs\n", event->usecs);
+out:
+	free(save);
+	return ret;
+}
+
+static struct Global _g;
+
+static void
+usage(FILE *stream)
+{
+	fprintf(stream,
+	        "usage: ./functional {-c | -o | -i | -I}\n"
+	        "Required:\n"
+	        "    -c (shuts down the fd server),\n"
+	        "    -o (starts the fd server),\n"
+	        "    -i NETMAP_PORT (requests the interface from the fd "
+	        "server),\n"
+	        "    -I NETMAP_PORT (directly opens the interface)\n"
+	        "Optional:\n"
+	        "    [-s SOURCE MAC ADDRESS (=0:0:0:0:0:0)]\n"
+	        "    [-d DESTINATION MAC ADDRESS (=FF:FF:FF:FF:FF:FF)]\n"
+	        "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
+	        "    [-T TIMEOUT_SECS (=1)]\n"
+	        "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
+	        "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
+	        "LEN bytes)]\n"
+	        "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
+	        "with size LEN bytes)]\n"
+	        "    [-p NUM[us|ms|s]] (pause for NUM us/ms/s)]\n"
+	        "    [-g (ignore ethernet frames with unmatching Ethernet "
+	        "header)]\n"
+	        "    [-n (exit status = 0 <==> no frames were received)]\n"
+	        "    [-q (during multi-packets send/receive increments fill "
+	        "character after each operation)]\n"
+	        "    [-e NUM (use NUM extra buffers to send packets, "
+	        "can only be used when with -I)]\n"
+	        "    [-v (increment verbosity level)]\n"
+	        "    [-C [NUM (=1)] (how many times to run the events)]\n"
+	        "\nExample:\n"
+	        "    $ ./functional -i netmap:lo -t 100 -r 100 -t 40:b:2 -r "
+	        "40:b:2\n");
+}
+
+/* TODO: Move functions to communicate to the fd_server to another file */
+/* Copied from nm_open() */
+void
+fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
+{
+	uint32_t nr_reg;
+
+	memset(des, 0, sizeof(*des));
+	des->self = des;
+	des->fd   = fd;
+	memcpy(&des->req, req, sizeof(des->req));
+	nr_reg = req->nr_flags & NR_REG_MASK;
+
+	if (nr_reg == NR_REG_SW) { /* host stack */
+		des->first_tx_ring = des->last_tx_ring = des->req.nr_tx_rings;
+		des->first_rx_ring = des->last_rx_ring = des->req.nr_rx_rings;
+	} else if (nr_reg == NR_REG_ALL_NIC) { /* only nic */
+		des->first_tx_ring = 0;
+		des->first_rx_ring = 0;
+		des->last_tx_ring  = des->req.nr_tx_rings - 1;
+		des->last_rx_ring  = des->req.nr_rx_rings - 1;
+	} else if (nr_reg == NR_REG_NIC_SW) {
+		des->first_tx_ring = 0;
+		des->first_rx_ring = 0;
+		des->last_tx_ring  = des->req.nr_tx_rings;
+		des->last_rx_ring  = des->req.nr_rx_rings;
+	} else if (nr_reg == NR_REG_ONE_NIC) {
+		/* XXX check validity */
+		des->first_tx_ring = des->last_tx_ring = des->first_rx_ring =
+		        des->last_rx_ring =
+		                des->req.nr_ringid & NETMAP_RING_MASK;
+	} else { /* pipes */
+		des->first_tx_ring = des->last_tx_ring = 0;
+		des->first_rx_ring = des->last_rx_ring = 0;
+	}
+}
+
+int
+connect_to_fd_server(struct Global *g)
+{
+	struct sockaddr_un name;
+	unsigned elapsed_ms = 0;
+	unsigned wait_ms    = 100;
+	int socket_fd;
+
+	socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+	if (socket_fd == -1) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "socket()");
+		return -1;
+	}
+
+	memset(&name, 0, sizeof(name));
+	name.sun_family = AF_UNIX;
+	strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
+	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
+	while (connect(socket_fd, (const struct sockaddr *)&name,
+	               sizeof(struct sockaddr_un)) == -1) {
+		if (elapsed_ms > g->timeout_secs * 1000) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "%s: Timeout\n", __func__);
+			return -1;
+		}
+
+		usleep(wait_ms * 1000);
+		elapsed_ms += wait_ms;
+	}
+
+	return socket_fd;
+}
+
+void
+start_fd_server(struct Global *g)
+{
+	int socket_fd;
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "fork()");
+		exit(EXIT_FAILURE);
+	}
+	if (pid > 0) {
+		wait(NULL);
+		return;
+	}
+
+	if (execlp("fd_server-legacy", "fd_server-legacy", (char *)NULL)) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "exec()");
+		exit(EXIT_FAILURE);
+	}
+
+	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Can't connect to fd_server\n");
+		exit(EXIT_FAILURE);
+	}
+	close(socket_fd);
+}
+
+int
+recv_fd(int socket, int *fd, void *buf, size_t buf_size)
+{
+	union {
+		char buf[CMSG_SPACE(sizeof(int))];
+		struct cmsghdr align;
+	} ancillary;
+	struct fd_response *res;
+	struct cmsghdr *cmsg;
+	struct iovec iov[1];
+	struct msghdr msg;
+	int amount;
+
+	errno           = 0;
+	iov[0].iov_base = buf;
+	iov[0].iov_len  = buf_size;
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov    = iov;
+	msg.msg_iovlen = 1;
+	memset(ancillary.buf, 0, sizeof(ancillary.buf));
+	msg.msg_control    = ancillary.buf;
+	msg.msg_controllen = sizeof(ancillary.buf);
+	cmsg               = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level   = SOL_SOCKET;
+	cmsg->cmsg_type    = SCM_RIGHTS;
+	cmsg->cmsg_len     = CMSG_LEN(sizeof(int));
+	amount             = recvmsg(socket, &msg, 0);
+	if (amount == -1) {
+		return -1;
+	}
+
+	res = iov[0].iov_base;
+	if (res->result != 0) {
+		errno = res->result;
+		return -1;
+	}
+
+	/* If res->result == 0, we know for sure that a file descriptor has been
+	 * sent through the ancillary data.
+	 */
+	cmsg = CMSG_FIRSTHDR(&msg);
+	memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
+
+	return amount;
+}
+
+struct nm_desc *
+get_if_fd(struct Global *g, const char *if_name)
+{
+	struct fd_response res;
+	struct fd_request req;
+	struct nm_desc *nmd;
+	int socket_fd;
+	int new_fd;
+	int ret;
+
+	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&req, 0, sizeof(req));
+	req.action = FD_GET;
+	strncpy(req.if_name, if_name, sizeof(req.if_name)-1);
+	ret = send(socket_fd, &req, sizeof(req), 0);
+	if (ret < 0) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
+		return NULL;
+	}
+
+	memset(&res, 0, sizeof(res));
+	ret = recv_fd(socket_fd, &new_fd, &res, sizeof(res));
+	if (ret == -1) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "recv_fd()");
+		return NULL;
+	}
+	close(socket_fd);
+
+	nmd = malloc(sizeof(*nmd));
+	if (nmd == NULL) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "malloc()");
+		return NULL;
+	}
+
+	fill_nm_desc(nmd, &res.req, new_fd);
+	if (nm_mmap(nmd, NULL) != 0) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "nm_mmap()");
+		return NULL;
+	}
+
+	return nmd;
+}
+
+void
+release_if_fd(struct Global *g, const char *if_name)
+{
+	struct fd_request req;
+	int socket_fd;
+	int ret;
+
+	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&req, 0, sizeof(req));
+	req.action = FD_RELEASE;
+	strncpy(req.if_name, if_name, sizeof(req.if_name)-1);
+
+	ret = send(socket_fd, &req, sizeof(req), 0);
+	if (ret <= 0) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
+	}
+
+	close(socket_fd);
+}
+
+void
+stop_fd_server(struct Global *g)
+{
+	struct fd_request req;
+	int socket_fd;
+	int ret;
+
+	socket_fd = connect_to_fd_server(g);
+	if (socket_fd == -1) {
+		verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+		              "fd_server alredy down\n");
+		return;
+	}
+	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
+	              "Shutting down fd_server\n");
+
+	memset(&req, 0, sizeof(req));
+	req.action = FD_STOP;
+	ret        = send(socket_fd, &req, sizeof(req), 0);
+	if (ret == -1) {
+		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "send()");
+	}
+	/* By calling recv() we synchronize with the fd_server closing the
+	 * socket.
+	 * This way we're sure that during the next call to ./functional
+	 * the fd_server has alredy closed its end and we avoid a possible race
+	 * condition. Otherwise the call to functional might connect to the
+	 * previous fd_server backlog.
+	 */
+	recv(socket_fd, &req, sizeof(req), 0);
+	close(socket_fd);
+}
+
+int
+parse_mac_address(const char *opt, char *mac)
+{
+	if (6 == sscanf(opt, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1],
+	                &mac[2], &mac[3], &mac[4], &mac[5])) {
+		return 0;
+	}
+	return -1;
+}
+
+/* Uses the first adapter slot (any will do) to save the extra buffers indexes.
+ */
+int
+parse_extra_buffers_indexes(struct Global *g)
+{
+	struct netmap_if *nifp   = g->nmd->nifp;
+	struct netmap_ring *ring = NETMAP_TXRING(nifp, g->nmd->first_tx_ring);
+	struct netmap_slot *slot = &ring->slot[ring->head];
+	uint32_t extra_buf_index = nifp->ni_bufs_head;
+	uint32_t real_index      = slot->buf_idx;
+	struct extra_buffer *u_buf;
+	unsigned i;
+
+	verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Parsing %u extra buffers:\n", g->extra_buffers_num);
+	for (i = 0; i < g->extra_buffers_num; i++) {
+		if (extra_buf_index == 0) {
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "   error, index = 0\n");
+			return -1;
+		}
+		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "   index = %u\n", extra_buf_index);
+
+		u_buf = malloc(sizeof(*u_buf));
+		if (u_buf == NULL) {
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG,
+			               "malloc()");
+			return -1;
+		}
+		u_buf->buf_idx = extra_buf_index;
+		TAILQ_INSERT_HEAD(&g->extra_buffers_head, u_buf, list_entry);
+		slot->buf_idx   = extra_buf_index;
+		extra_buf_index = *(uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+	}
+	slot->buf_idx = real_index;
+
+	return 0;
+}
+
+/* Loops through the adapter slots, swapping the default buffers with the
+ * extra buffers. Keeps going until we run out of extra buffers, or adapter
+ * slots.
+ */
+int
+swap_in_extra_buffers(struct Global *g)
+{
+	unsigned extra_buffers_num = g->extra_buffers_num;
+	unsigned int i;
+
+	for (i = g->nmd->first_tx_ring; i <= g->nmd->last_tx_ring; i++) {
+		struct netmap_ring *ring = NETMAP_TXRING(g->nmd->nifp, i);
+		unsigned head;
+
+		for (head = ring->head; head != ring->tail;
+		     head = nm_ring_next(ring, head)) {
+			struct extra_buffer *u_buf =
+			        TAILQ_FIRST(&g->extra_buffers_head);
+			struct netmap_slot *slot = &ring->slot[head];
+			uint32_t real_index      = slot->buf_idx;
+
+			if (u_buf == NULL) {
+				/* We finished swapping in extra buffers */
+				return 0;
+			}
+
+			slot->buf_idx = u_buf->buf_idx;
+			slot->flags |= NS_BUF_CHANGED;
+			u_buf->buf_idx = real_index;
+			TAILQ_REMOVE(&g->extra_buffers_head, u_buf, list_entry);
+			TAILQ_INSERT_TAIL(&g->extra_buffers_head, u_buf,
+			                 list_entry);
+
+			if (--extra_buffers_num == 0) {
+				return 0;
+			}
+		}
+	}
+
+	/* This is reached if the adapter has less slots than the number of
+	 * requested extra buffers. Nevertheless this is not a problem as the
+	 * not in use extra buffers will will be released during cleanup().
+	 */
+	return 0;
+}
+
+/* We only re-build the extra buffers list, as requested from netmap. We don't
+ * undo the swapping that we did at the start of the program to swap in the
+ * extra buffer. This probably leaves the netmap adapter in an incosistent
+ * state, that's why we only support this option for interfaces requested
+ * directly.
+ */
+void
+release_extra_buffers(struct Global *g)
+{
+	struct netmap_if *nifp   = g->nmd->nifp;
+	struct netmap_ring *ring = NETMAP_TXRING(nifp, g->nmd->first_tx_ring);
+	struct netmap_slot *slot = &ring->slot[ring->head];
+	uint32_t real_index      = slot->buf_idx;
+	struct extra_buffer *u_buf;
+	uint32_t *next_extra_buffer;
+
+	verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Releasing %u extra buffers:\n", g->extra_buffers_num);
+	if (TAILQ_EMPTY(&g->extra_buffers_head)) {
+		return;
+	}
+
+	u_buf = TAILQ_FIRST(&g->extra_buffers_head);
+	nifp->ni_bufs_head = u_buf->buf_idx;
+	verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "   head index %u\n", nifp->ni_bufs_head);
+	slot->buf_idx = u_buf->buf_idx;
+	TAILQ_REMOVE(&g->extra_buffers_head, u_buf, list_entry);
+	free(u_buf);
+
+	while (!TAILQ_EMPTY(&g->extra_buffers_head)) {
+		next_extra_buffer = (uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+		u_buf = TAILQ_FIRST(&g->extra_buffers_head);
+		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "   index = %u\n", u_buf->buf_idx);
+		*next_extra_buffer = u_buf->buf_idx;
+		slot->buf_idx = u_buf->buf_idx;
+		TAILQ_REMOVE(&g->extra_buffers_head, u_buf, list_entry);
+		free(u_buf);
+	}
+	next_extra_buffer = (uint32_t *)NETMAP_BUF(ring, slot->buf_idx);
+	*next_extra_buffer = 0;
+	slot->buf_idx = real_index;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct Global *g = &_g;
+	unsigned int i, c;
+	int opt;
+	int ret;
+
+	g->nmd            = NULL;
+	g->ifname         = NULL;
+	g->wait_link_secs = 0;
+	g->timeout_secs   = 1;
+	g->pktm_len       = 60;
+	g->max_frag_size  = ~0U; /* unlimited */
+	for (i = 0; i < ETH_ADDR_LEN; i++) {
+		g->src_mac[i] = 0x00;
+	}
+	for (i = 0; i < ETH_ADDR_LEN; i++) {
+		g->dst_mac[i] = 0xFF;
+	}
+	g->src_ip                 = 0x0A000005; /* 10.0.0.5 */
+	g->dst_ip                 = 0x0A000007; /* 10.0.0.7 */
+	g->filler                 = 'a';
+	g->num_events             = 0;
+	g->ignore_if_not_matching = /*false=*/0;
+	g->success_if_no_receive  = /*false=*/0;
+	g->request_from_fd_server = /*true=*/1;
+	g->sequential_fill        = /*false=*/0;
+	g->extra_buffers_num      = 0;
+	g->verbosity_level        = 0;
+	g->num_loops              = 1;
+	g->extra_buffers_num      = 0;
+	TAILQ_INIT(&g->extra_buffers_head);
+
+	while ((opt = getopt(argc, argv, "hconqe:s:d:i:I:w:F:T:t:r:gvp:C:")) !=
+	       -1) {
+		switch (opt) {
+		case 'h':
+			usage(stdout);
+			return 0;
+
+		/* TODO: move this option to fd_server */
+		case 'c':
+			stop_fd_server(g);
+			return 0;
+
+		/* TODO: move this option to fd_server */
+		case 'o':
+			start_fd_server(g);
+			return 0;
+
+		case 'n':
+			g->success_if_no_receive = /*true=*/1;
+			break;
+
+		case 'q':
+			g->sequential_fill = /*true=*/1;
+			break;
+
+		case 'e':
+			g->extra_buffers_num = atoi(optarg);
+			if (g->extra_buffers_num <= 0) {
+				verbose_print(
+				        g->verbosity_level, LV_ERROR_MSG,
+				        "Invalid number of extra buffers\n");
+				exit(EXIT_FAILURE);
+			};
+			verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Requesting %u extra buffers\n", g->extra_buffers_num);
+			break;
+
+		case 's':
+			ret = parse_mac_address(optarg, g->src_mac);
+			if (ret == -1) {
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Invalid source MAC address\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+
+		case 'd':
+			ret = parse_mac_address(optarg, g->dst_mac);
+			if (ret == -1) {
+				verbose_print(
+				        g->verbosity_level, LV_ERROR_MSG,
+				        "Invalid destination MAC address\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+
+		case 'i':
+			g->ifname = optarg;
+			break;
+
+		case 'I':
+			g->ifname                 = optarg;
+			g->request_from_fd_server = /*false=*/0;
+			break;
+
+		case 'F':
+			g->max_frag_size = atoi(optarg);
+			break;
+
+		case 'w':
+			g->wait_link_secs = atoi(optarg);
+			break;
+
+		case 'T':
+			g->timeout_secs = atoi(optarg);
+			break;
+
+		case 't':
+		case 'r':
+		case 'p': {
+			int ret = 0;
+
+			if (g->num_events >= MAX_EVENTS) {
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Too many events\n");
+				exit(EXIT_FAILURE);
+			}
+
+			if (opt == 'p') {
+				ret = parse_pause_event(
+				        optarg, g->events + g->num_events,
+				        g->verbosity_level);
+			} else {
+				ret = parse_txrx_event(
+				        optarg,
+				        (opt == 't') ? EVENT_TYPE_TX
+				                     : EVENT_TYPE_RX,
+				        g->events + g->num_events,
+				        g->verbosity_level);
+			}
+			if (ret) {
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Invalid event syntax '%s'\n",
+				              optarg);
+				usage(stderr);
+				exit(EXIT_FAILURE);
+			}
+			g->num_events++;
+			break;
+		}
+
+		case 'g':
+			g->ignore_if_not_matching = 1;
+			break;
+
+		case 'v':
+			g->verbosity_level++;
+			break;
+
+		case 'C':
+			g->num_loops = atoi(optarg);
+			if (g->num_loops == 0) {
+				verbose_print(g->verbosity_level, LV_ERROR_MSG,
+				              "Invalid -C option '%s'\n",
+				              optarg);
+				exit(EXIT_FAILURE);
+			}
+			break;
+
+		default:
+			verbose_print(g->verbosity_level, LV_ERROR_MSG,
+			              "Unrecognized option %c\n", optopt);
+			usage(stderr);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (g->ifname == NULL) {
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Missing ifname\n");
+		usage(stderr);
+		exit(EXIT_FAILURE);
+	}
+
+	if (g->request_from_fd_server == 1 && g->extra_buffers_num > 0) {
+		verbose_print(
+		        g->verbosity_level, LV_ERROR_MSG,
+		        "Extra buffers can only be used when requesting an "
+		        "interface directly\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (g->request_from_fd_server == 0) {
+		/* We directly open the file descriptor. */
+		if (g->extra_buffers_num > 0) {
+			struct nmreq req;
+
+			memset(&req, 0, sizeof(req));
+			req.nr_arg3 = g->extra_buffers_num;
+			g->nmd      = nm_open(g->ifname, &req, 0, NULL);
+		} else {
+			g->nmd = nm_open(g->ifname, NULL, 0, NULL);
+		}
+	} else {
+		g->nmd = get_if_fd(g, g->ifname);
+	}
+	if (g->nmd == NULL) {
+		verbose_print(g->verbosity_level, LV_ERROR_MSG,
+		              "Failed to nm_open(%s)\n", g->ifname);
+		exit(EXIT_FAILURE);
+	}
+
+	if (g->extra_buffers_num > 0) {
+		/* Stores the real number of extra buffers. */
+		g->extra_buffers_num = g->nmd->req.nr_arg3;
+		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Received %u extra buffers\n", g->extra_buffers_num);
+		ret = parse_extra_buffers_indexes(g);
+		if (ret == -1) {
+			cleanup(g);
+			exit(EXIT_FAILURE);
+		}
+
+		swap_in_extra_buffers(g);
+	}
+
+	if (g->wait_link_secs > 0) {
+		sleep(g->wait_link_secs);
+	}
+
+	for (c = 0; c < g->num_loops; c++) {
+		for (i = 0; i < g->num_events; i++) {
+			const struct Event *e = g->events + i;
+
+			if (e->evtype == EVENT_TYPE_TX ||
+			    e->evtype == EVENT_TYPE_RX) {
+				g->filler   = e->filler;
+				g->pktm_len = e->pkt_len;
+				build_packet(g);
+			}
+
+			switch (e->evtype) {
+			case EVENT_TYPE_TX:
+				if (tx(g, e->num)) {
+					cleanup(g);
+					exit(EXIT_FAILURE);
+				}
+				break;
+
+			case EVENT_TYPE_RX:
+				if (rx(g, e->num)) {
+					cleanup(g);
+					exit(EXIT_FAILURE);
+				}
+				break;
+
+			case EVENT_TYPE_PAUSE:
+				usleep(e->usecs);
+				break;
+			}
+		}
+	}
+
+	/* if we have sent something, wait for all tx to complete */
+	tx_flush(g);
+	cleanup(g);
+	return 0;
+}
diff --git a/utils/functional.c b/utils/functional.c
index 4d9b100bb..231a271a6 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -35,11 +35,10 @@
 #include 
 #include 
 #include 
-#define NETMAP_WITH_LIBS
 #include 
 #include 
 #include 
-#include 
+#include 
 #include 
 #include 
 #include 
@@ -51,6 +50,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "fd_server.h"
 
@@ -76,10 +76,8 @@ struct extra_buffer {
 	TAILQ_ENTRY(extra_buffer) list_entry;
 };
 
-;
-
 struct Global {
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	const char *ifname;
 	unsigned wait_link_secs;    /* wait for link */
 	unsigned timeout_secs;      /* transmit/receive timeout */
@@ -125,7 +123,7 @@ void release_if_fd(struct Global *, const char *);
 void release_extra_buffers(struct Global *);
 
 void
-verbose_print(int current_verbosity, int required_verbosity, char *format, ...)
+verbose_print(int current_verbosity, int required_verbosity, const char *format, ...)
 {
 	va_list args;
 
@@ -138,7 +136,7 @@ verbose_print(int current_verbosity, int required_verbosity, char *format, ...)
 }
 
 void
-verbose_perror(int current_verbosity, int required_verbosity, char *str)
+verbose_perror(int current_verbosity, int required_verbosity, const char *str)
 {
 	if (current_verbosity >= required_verbosity) {
 		perror(str);
@@ -155,7 +153,7 @@ cleanup(struct Global *g)
 	if (g->request_from_fd_server) {
 		release_if_fd(g, g->ifname);
 	} else {
-		nm_close(g->nmd);
+		nmport_close(g->nmd);
 	}
 }
 
@@ -331,7 +329,7 @@ build_packet(struct Global *g)
 static int
 tx_flush(struct Global *g)
 {
-	struct nm_desc *nmd = g->nmd;
+	struct nmport_d *nmd = g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	int i;
@@ -371,7 +369,7 @@ ring_avail_packets(struct netmap_ring *ring, unsigned pkt_len)
 }
 
 uint64_t
-adapter_avail_sends(struct nm_desc *nmd, unsigned pkt_len)
+adapter_avail_sends(struct nmport_d *nmd, unsigned pkt_len)
 {
 	uint64_t sends_available = 0;
 	unsigned int i;
@@ -439,7 +437,7 @@ next_fill(char cur_fill)
 static int
 tx(struct Global *g, unsigned packets_num)
 {
-	struct nm_desc *nmd = g->nmd;
+	struct nmport_d *nmd = g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	unsigned int i;
@@ -510,7 +508,7 @@ ignore_received_frame(struct Global *g)
 }
 
 uint64_t
-adapter_avail_receives(struct nm_desc *nmd, unsigned pkt_len)
+adapter_avail_receives(struct nmport_d *nmd, unsigned pkt_len)
 {
 	uint64_t receives_available = 0;
 	unsigned int i;
@@ -602,7 +600,7 @@ read_one_packet(struct Global *g, struct netmap_ring *ring)
 static int
 rx(struct Global *g, unsigned packets_num)
 {
-	struct nm_desc *nmd = g->nmd;
+	struct nmport_d *nmd = g->nmd;
 	unsigned elapsed_ms = 0;
 	unsigned wait_ms    = 100;
 	unsigned int i;
@@ -813,43 +811,6 @@ usage(FILE *stream)
 	        "40:b:2\n");
 }
 
-/* TODO: Move functions to communicate to the fd_server to another file */
-/* Copied from nm_open() */
-void
-fill_nm_desc(struct nm_desc *des, struct nmreq *req, int fd)
-{
-	uint32_t nr_reg;
-
-	memset(des, 0, sizeof(*des));
-	des->self = des;
-	des->fd   = fd;
-	memcpy(&des->req, req, sizeof(des->req));
-	nr_reg = req->nr_flags & NR_REG_MASK;
-
-	if (nr_reg == NR_REG_SW) { /* host stack */
-		des->first_tx_ring = des->last_tx_ring = des->req.nr_tx_rings;
-		des->first_rx_ring = des->last_rx_ring = des->req.nr_rx_rings;
-	} else if (nr_reg == NR_REG_ALL_NIC) { /* only nic */
-		des->first_tx_ring = 0;
-		des->first_rx_ring = 0;
-		des->last_tx_ring  = des->req.nr_tx_rings - 1;
-		des->last_rx_ring  = des->req.nr_rx_rings - 1;
-	} else if (nr_reg == NR_REG_NIC_SW) {
-		des->first_tx_ring = 0;
-		des->first_rx_ring = 0;
-		des->last_tx_ring  = des->req.nr_tx_rings;
-		des->last_rx_ring  = des->req.nr_rx_rings;
-	} else if (nr_reg == NR_REG_ONE_NIC) {
-		/* XXX check validity */
-		des->first_tx_ring = des->last_tx_ring = des->first_rx_ring =
-		        des->last_rx_ring =
-		                des->req.nr_ringid & NETMAP_RING_MASK;
-	} else { /* pipes */
-		des->first_tx_ring = des->last_tx_ring = 0;
-		des->first_rx_ring = des->last_rx_ring = 0;
-	}
-}
-
 int
 connect_to_fd_server(struct Global *g)
 {
@@ -941,6 +902,7 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	cmsg->cmsg_len     = CMSG_LEN(sizeof(int));
 	amount             = recvmsg(socket, &msg, 0);
 	if (amount == -1) {
+		printf("recv_fd(): recvmsg failed\n");
 		return -1;
 	}
 
@@ -959,12 +921,12 @@ recv_fd(int socket, int *fd, void *buf, size_t buf_size)
 	return amount;
 }
 
-struct nm_desc *
+struct nmport_d *
 get_if_fd(struct Global *g, const char *if_name)
 {
 	struct fd_response res;
 	struct fd_request req;
-	struct nm_desc *nmd;
+	struct nmport_d *nmd;
 	int socket_fd;
 	int new_fd;
 	int ret;
@@ -991,14 +953,20 @@ get_if_fd(struct Global *g, const char *if_name)
 	}
 	close(socket_fd);
 
-	nmd = malloc(sizeof(*nmd));
+	nmd = nmport_new();
 	if (nmd == NULL) {
 		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "malloc()");
 		return NULL;
 	}
 
-	fill_nm_desc(nmd, &res.req, new_fd);
-	if (nm_mmap(nmd, NULL) != 0) {
+	// unmarshal the response
+	nmd->hdr = res.hdr;
+	nmd->reg = res.reg;
+	nmd->hdr.nr_body = (uintptr_t)&nmd->reg;
+	nmd->fd = new_fd;
+	nmd->register_done = 1;
+
+	if (nmport_mmap(nmd) != 0) {
 		verbose_perror(g->verbosity_level, LV_ERROR_MSG, "nm_mmap()");
 		return NULL;
 	}
@@ -1386,27 +1354,30 @@ main(int argc, char **argv)
 
 	if (g->request_from_fd_server == 0) {
 		/* We directly open the file descriptor. */
+		g->nmd = nmport_prepare(g->ifname);
+		if (g->nmd == NULL) {
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG, g->ifname);
+			exit(EXIT_FAILURE);
+		}
 		if (g->extra_buffers_num > 0) {
-			struct nmreq req;
-
-			memset(&req, 0, sizeof(req));
-			req.nr_arg3 = g->extra_buffers_num;
-			g->nmd      = nm_open(g->ifname, &req, 0, NULL);
-		} else {
-			g->nmd = nm_open(g->ifname, NULL, 0, NULL);
+			g->nmd->reg.nr_extra_bufs = g->extra_buffers_num;
+		}
+		if (nmport_open_desc(g->nmd) < 0) {
+			verbose_perror(g->verbosity_level, LV_ERROR_MSG, g->ifname);
+			exit(EXIT_FAILURE);
 		}
 	} else {
 		g->nmd = get_if_fd(g, g->ifname);
 	}
 	if (g->nmd == NULL) {
 		verbose_print(g->verbosity_level, LV_ERROR_MSG,
-		              "Failed to nm_open(%s)\n", g->ifname);
+		              "Failed to nmport_open(%s)\n", g->ifname);
 		exit(EXIT_FAILURE);
 	}
 
 	if (g->extra_buffers_num > 0) {
 		/* Stores the real number of extra buffers. */
-		g->extra_buffers_num = g->nmd->req.nr_arg3;
+		g->extra_buffers_num = g->nmd->reg.nr_extra_bufs;
 		verbose_print(g->verbosity_level, LV_DEBUG_EXTRA_BUF, "Received %u extra buffers\n", g->extra_buffers_num);
 		ret = parse_extra_buffers_indexes(g);
 		if (ret == -1) {
diff --git a/utils/randomized_tests b/utils/randomized_tests
index 0d870ef62..32a60c21a 100755
--- a/utils/randomized_tests
+++ b/utils/randomized_tests
@@ -12,12 +12,15 @@ randomized_tests:
 	-j ID		Run only the test specified by ID
 	-l		List available tests and exit
 	-v		Increase verbosity of the tests
+	-L		Skip legacy API
 EOF
 }
 
+functionals="functional functional-legacy"
+
 # Option parsing
 OUTPUT="/dev/null"
-while getopts "hlvj:" opt; do
+while getopts "hlvj:L" opt; do
 	case $opt in
 	"h")
 		usage
@@ -49,6 +52,9 @@ while getopts "hlvj:" opt; do
 		VERB="${VERB}v"
 		OUTPUT="/dev/stdout"
 		;;
+	"L")
+		functionals="functional"
+		;;
 
 	\?)
 		echo "Unknown option '$opt'"
@@ -130,25 +136,30 @@ netmap_load
 
 RET=0
 i=0
-for t in tests/* ; do
-	i=$((i + 1))
-
-	# Possibly filter tests by TESTID
-	[ -n "$TESTID" ] && [ "$i" != "$TESTID" ] && continue
-
-	# Run this test
-	echo -e "${ORANGE}>>> Running test #${i}: ${CYAN}\"${t}\"${NOC}"
-	restart_fd_server
-	$t $VERB -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>${OUTPUT}
-	res="$?"
-	close_fd_server
-	if [ "$res" == 0 ]; then
-		echo -e "${GREEN}>>> Test #${i} PASSED${NOC}"
-	else
-		echo -e "${RED}>>> Test #${i} FAILED${NOC}"
-		RET="1"
-		break
-	fi
+for f in $functionals; do
+	export FUNCTIONAL=$f
+	echo -e "${ORANGE}>>> Running tests using $FUNCTIONAL"
+	for t in tests/* ; do
+		i=$((i + 1))
+
+		# Possibly filter tests by TESTID
+		[ -n "$TESTID" ] && [ "$i" != "$TESTID" ] && continue
+
+		# Run this test
+		echo -e "${ORANGE}>>> Running test #${i}: ${CYAN}\"${t}\"${NOC}"
+		restart_fd_server
+		$t $VERB -n $random_packet_num -l $random_len -f $random_fill "$seq_check" 2>${OUTPUT}
+		res="$?"
+		close_fd_server
+		if [ "$res" == 0 ]; then
+			echo -e "${GREEN}>>> Test #${i} PASSED${NOC}"
+		else
+			echo -e "${RED}>>> Test #${i} FAILED${NOC}"
+			RET="1"
+			break
+		fi
+	done
+	[ "$RET" == 0 ] || break
 done
 
 # Wait for the fd_server to terminate and release its references
diff --git a/utils/test_lib b/utils/test_lib
index b7d3bd63f..059730413 100755
--- a/utils/test_lib
+++ b/utils/test_lib
@@ -1,4 +1,8 @@
 #!/usr/bin/env bash
+
+FUNCTIONAL=${FUNCTIONAL:-functional}
+export FUNCTIONAL
+
 ################################################################################
 # Creates the new file descriptor "3" and redirects it to stdout, then redirects
 # stderr e stdout to /dev/null. This way only the stuff we redirect to fd 3 is
@@ -28,7 +32,7 @@ function stdout_echo() {
 #   None
 ################################################################################
 function close_fd_server() {
-	functional -c
+	$FUNCTIONAL -c
 	check_success "$?" "close_fd_server"
 }
 
@@ -38,7 +42,7 @@ function close_fd_server() {
 #   None
 ################################################################################
 function start_fd_server() {
-	functional -o
+	$FUNCTIONAL -o
 	check_success "$?" "start_fd_server"
 }
 
diff --git a/utils/tests/001_exclusive_open_ephemeral_vale_port_test b/utils/tests/001_exclusive_open_ephemeral_vale_port_test
index b280ea507..7f8598fc5 100755
--- a/utils/tests/001_exclusive_open_ephemeral_vale_port_test
+++ b/utils/tests/001_exclusive_open_ephemeral_vale_port_test
@@ -12,14 +12,14 @@ bridge="vale0"
 port="v0"
 
 # We open ${bridge}:${port} with the exclusive flag from the file descriptor.
-functional $verbosity -i "${bridge}:${port}/x"
+$FUNCTIONAL $verbosity -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional $verbosity -I "${bridge}:${port}"
+$FUNCTIONAL $verbosity -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-functional $verbosity -I "${bridge}:${port}/x"
+$FUNCTIONAL $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
diff --git a/utils/tests/002_exclusive_open_persistent_vale_port_test b/utils/tests/002_exclusive_open_persistent_vale_port_test
index 258b944fd..04a6bc762 100755
--- a/utils/tests/002_exclusive_open_persistent_vale_port_test
+++ b/utils/tests/002_exclusive_open_persistent_vale_port_test
@@ -15,14 +15,14 @@ create_vale_persistent_port "$port"
 attach_to_vale_bridge "$bridge" "$port"
 
 # We open the persistent port with the exclusive flag from the file descriptor.
-functional $verbosity -i "${bridge}:${port}/x"
+$FUNCTIONAL $verbosity -i "${bridge}:${port}/x"
 check_success $? "exclusive-open ${bridge}:${port}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional $verbosity -I "${bridge}:${port}"
+$FUNCTIONAL $verbosity -I "${bridge}:${port}"
 check_failure $? "no-open ${bridge}:${port}"
 
 # Check that another exclusive open request fails.
-functional $verbosity -I "${bridge}:${port}/x"
+$FUNCTIONAL $verbosity -I "${bridge}:${port}/x"
 check_failure $? "no-open ${bridge}:${port}/x"
diff --git a/utils/tests/003_exclusive_open_pipe_test b/utils/tests/003_exclusive_open_pipe_test
index 8750afa16..bf627651d 100755
--- a/utils/tests/003_exclusive_open_pipe_test
+++ b/utils/tests/003_exclusive_open_pipe_test
@@ -11,14 +11,14 @@ verbosity="${verbosity:-}"
 pipe="pipeA{1"
 
 # We open pipeA{1 with the exclusive flag from the file descriptor.
-functional $verbosity -i "netmap:${pipe}/x"
+$FUNCTIONAL $verbosity -i "netmap:${pipe}/x"
 check_success $? "exclusive-open netmap:${pipe}/x"
 
 # Then we open the same interface again, this time without requesting it from
 # the file descriptor, causing a second nm_open().
-functional $verbosity -I "netmap:${pipe}"
+$FUNCTIONAL $verbosity -I "netmap:${pipe}"
 check_failure $? "no-open netmap:${pipe}"
 
 # Check that another exclusive open request fails.
-functional $verbosity -I "netmap:${pipe}/x"
+$FUNCTIONAL $verbosity -I "netmap:${pipe}/x"
 check_failure $? "no-open netmap:${pipe}/x"
diff --git a/utils/tests/004_extra_buf_send_rec_ephemeral_vale_ports_test b/utils/tests/004_extra_buf_send_rec_ephemeral_vale_ports_test
index 0759e8f5d..05c256f35 100755
--- a/utils/tests/004_extra_buf_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/004_extra_buf_send_rec_ephemeral_vale_ports_test
@@ -19,17 +19,17 @@ e_buf_num="${e_buf_num:-12}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "vale0:v1"
+$FUNCTIONAL $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional $verbosity -i "vale0:v2"
+$FUNCTIONAL $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v0 ---> v1, v2
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -I "vale0:v0" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
+$FUNCTIONAL $verbosity -I "vale0:v0" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/005_extra_buf_send_rec_persistent_vale_ports_test b/utils/tests/005_extra_buf_send_rec_persistent_vale_ports_test
index c92c2e863..878b35643 100755
--- a/utils/tests/005_extra_buf_send_rec_persistent_vale_ports_test
+++ b/utils/tests/005_extra_buf_send_rec_persistent_vale_ports_test
@@ -26,17 +26,17 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "vale0:v0"
+$FUNCTIONAL $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i "vale0:v1"
+$FUNCTIONAL $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # v2 ---> v0, v1
-functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -I "vale0:v2" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
+$FUNCTIONAL $verbosity -I "vale0:v2" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
 e3=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/006_extra_buf_send_rec_pipe_test b/utils/tests/006_extra_buf_send_rec_pipe_test
index 349eff49b..469988002 100755
--- a/utils/tests/006_extra_buf_send_rec_pipe_test
+++ b/utils/tests/006_extra_buf_send_rec_pipe_test
@@ -19,13 +19,13 @@ e_buf_num="${e_buf_num:-12}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:pipeA{1"
+$FUNCTIONAL $verbosity -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
 
 # pipeA}1 ---> pipeA{1
-functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
+$FUNCTIONAL $verbosity -I "netmap:pipeA}1" -t "${len}:${fill}:${num}" -e "$e_buf_num" $seq
 e2=$?
 wait $p1
 e1=$?
diff --git a/utils/tests/007_learning_bridge_test b/utils/tests/007_learning_bridge_test
index f9d9ddc81..29708562e 100755
--- a/utils/tests/007_learning_bridge_test
+++ b/utils/tests/007_learning_bridge_test
@@ -20,19 +20,19 @@ d_MAC="FF:FF:FF:FF:FF:FF"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
-functional $verbosity -i vale0:v2
+$FUNCTIONAL $verbosity -i vale0:v2
 check_success $? "pre-open vale0:v2"
 
 # First send, every port should receive the frame.
-functional $verbosity -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+$FUNCTIONAL $verbosity -i vale0:v0 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p1=$!
-functional $verbosity -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
+$FUNCTIONAL $verbosity -i vale0:v1 -r "${len}:${fill}" -s "$s_MAC" -d "$d_MAC" &
 p2=$!
-functional $verbosity -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
+$FUNCTIONAL $verbosity -i vale0:v2 -t "${len}:${fill}" -s "$s_MAC" -d "$d_MAC"
 e3=$?
 wait $p1
 e1=$?
@@ -43,11 +43,11 @@ check_success $e2 "receive vale0:v1"
 check_success $e3 "send vale0:v2"
 
 # Second send, only v2 should receive the frame.
-functional $verbosity -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
+$FUNCTIONAL $verbosity -i vale0:v2 -r "${len}:${fill}" -d "$s_MAC"    &
 p4=$!
-functional $verbosity -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
+$FUNCTIONAL $verbosity -i vale0:v1 -r "${len}:${fill}" -d "$s_MAC" -n &
 p5=$!
-functional $verbosity -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
+$FUNCTIONAL $verbosity -i vale0:v0 -t "${len}:${fill}" -d "$s_MAC"
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/008_partial_read_pipe_test b/utils/tests/008_partial_read_pipe_test
index f67496d16..7e8ec038b 100755
--- a/utils/tests/008_partial_read_pipe_test
+++ b/utils/tests/008_partial_read_pipe_test
@@ -22,14 +22,14 @@ pipe="pipeA"
 
 # Pre-open netmap ports for the test. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:${pipe}{1"
+$FUNCTIONAL $verbosity -i "netmap:${pipe}{1"
 check_success $? "pre-open netmap:${pipe}{1"
-functional $verbosity -i "netmap:${pipe}}1"
+$FUNCTIONAL $verbosity -i "netmap:${pipe}}1"
 check_success $? "pre-open netmap:${pipe}}1"
 
-functional $verbosity -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:${pipe}{1" -r "${len}:${fill}:${num_recv}" $seq &
 p1=$!
-functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
+$FUNCTIONAL $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -63,5 +63,5 @@ fi
 check_exit $pending_transmissions $pending_packets "pending_transmissions=pending_packets"
 
 num_send="$(($avail_packets + 1))"
-functional $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
+$FUNCTIONAL $verbosity -i "netmap:${pipe}}1" -t "${len}:${fill}:${num_send}" $seq
 check_failure $? "send-${num_send} netmap:${pipe}}1"
diff --git a/utils/tests/012_rec_cp_mon_ephemeral_vale_port_test b/utils/tests/012_rec_cp_mon_ephemeral_vale_port_test
index 288b160c5..6e58966c9 100755
--- a/utils/tests/012_rec_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/012_rec_cp_mon_ephemeral_vale_port_test
@@ -20,17 +20,17 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i vale0:v0/r
+$FUNCTIONAL $verbosity -i vale0:v0/r
 check_success $? "pre-open vale0:v0/r"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional $verbosity -i vale0:v0/r -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i vale0:v0/r -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -38,6 +38,6 @@ check_success $e1 "receive-${num} vale0:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
diff --git a/utils/tests/013_rec_cp_mon_persistent_vale_port_test b/utils/tests/013_rec_cp_mon_persistent_vale_port_test
index 28af6ac8a..72e1c82a7 100755
--- a/utils/tests/013_rec_cp_mon_persistent_vale_port_test
+++ b/utils/tests/013_rec_cp_mon_persistent_vale_port_test
@@ -23,17 +23,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i netmap:v0/r
+$FUNCTIONAL $verbosity -i netmap:v0/r
 check_success $? "pre-open netmap:v0/r"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v0
-functional $verbosity -i netmap:v0/r -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i netmap:v0/r -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -41,6 +41,6 @@ check_success $e1 "receive-${num} netmap:v0/r"
 check_success $e2 "send-${num} vale0:v1"
 
 # Then we read from v0
-functional $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v0 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v0"
diff --git a/utils/tests/014_rec_cp_mon_pipe_test b/utils/tests/014_rec_cp_mon_pipe_test
index 608dcad0b..7c9e17c63 100755
--- a/utils/tests/014_rec_cp_mon_pipe_test
+++ b/utils/tests/014_rec_cp_mon_pipe_test
@@ -21,17 +21,17 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:pipe{1"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional $verbosity -i "netmap:pipe{1/r"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/r"
 check_success $? "pre-open netmap:pipe{1/r"
-functional $verbosity -i "netmap:pipe}1"
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe{1
-functional $verbosity -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/r" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -39,6 +39,6 @@ check_success $e1 "receive-${num}${seq} netmap:pipe{1/r"
 check_success $e2 "send-${num}${seq} netmap:pipe}1"
 
 # Then we read from pipe{1
-functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num}${seq} netmap:pipe{1"
diff --git a/utils/tests/015_rec_zcp_mon_ephemeral_vale_port_test b/utils/tests/015_rec_zcp_mon_ephemeral_vale_port_test
index cc5af56b6..78b9a5fc0 100755
--- a/utils/tests/015_rec_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/015_rec_zcp_mon_ephemeral_vale_port_test
@@ -20,18 +20,18 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "vale0:v0"
+$FUNCTIONAL $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i "vale0:v0/z"
+$FUNCTIONAL $verbosity -i "vale0:v0/z"
 check_success $? "pre-open vale0:v0/z"
-functional $verbosity -i "vale0:v1"
+$FUNCTIONAL $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" $seq -n &
+$FUNCTIONAL $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -40,9 +40,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v0"   -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "vale0:v0/z" -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "vale0:v0/z" -r "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/016_rec_zcp_mon_persistent_vale_port_test b/utils/tests/016_rec_zcp_mon_persistent_vale_port_test
index 4844c8c5f..0edbe9460 100755
--- a/utils/tests/016_rec_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/016_rec_zcp_mon_persistent_vale_port_test
@@ -23,18 +23,18 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "vale0:v0"
+$FUNCTIONAL $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i "netmap:v0/z"
+$FUNCTIONAL $verbosity -i "netmap:v0/z"
 check_success $? "pre-open netmap:v0/z"
-functional $verbosity -i "vale0:v1"
+$FUNCTIONAL $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
 
 # Initially we don't receive with the monitored VALE port v0, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" $seq -n &
+$FUNCTIONAL $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -43,9 +43,9 @@ check_success $e2 "send-${num} vale0:v0"
 
 # Now we receive with the monitored VALE port v0, therefore the monitor should
 # receive the frame.
-functional $verbosity -i "vale0:v0"    -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v0"    -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:v0/z" -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:v0/z" -r "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/017_rec_zcp_mon_pipe_test b/utils/tests/017_rec_zcp_mon_pipe_test
index 4b0bc5cf7..f44929015 100755
--- a/utils/tests/017_rec_zcp_mon_pipe_test
+++ b/utils/tests/017_rec_zcp_mon_pipe_test
@@ -20,18 +20,18 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:pipe{1"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional $verbosity -i "netmap:pipe{1/z"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-functional $verbosity -i "netmap:pipe}1"
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the monitored pipe pipe{1, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq -n &
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -40,9 +40,9 @@ check_success $e2 "send-${num} netmap:pipe{1"
 
 # Now we receive with the monitored pipe pipe{1, therefore the monitor should
 # receive the frame.
-functional $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"   -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/018_send_cp_mon_ephemeral_vale_port_test b/utils/tests/018_send_cp_mon_ephemeral_vale_port_test
index 6fe0540eb..17b8309c4 100755
--- a/utils/tests/018_send_cp_mon_ephemeral_vale_port_test
+++ b/utils/tests/018_send_cp_mon_ephemeral_vale_port_test
@@ -18,17 +18,17 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i vale0:v0/t
+$FUNCTIONAL $verbosity -i vale0:v0/t
 check_success $? "pre-open vale0:v0/t"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i vale0:v0/t  -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i vale0:v0/t  -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -36,6 +36,6 @@ check_success $e1 "receive-${num} vale0:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
diff --git a/utils/tests/019_send_cp_mon_persistent_vale_port_test b/utils/tests/019_send_cp_mon_persistent_vale_port_test
index 911be00f1..52f17f6ee 100755
--- a/utils/tests/019_send_cp_mon_persistent_vale_port_test
+++ b/utils/tests/019_send_cp_mon_persistent_vale_port_test
@@ -21,17 +21,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i netmap:v0/t
+$FUNCTIONAL $verbosity -i netmap:v0/t
 check_success $? "pre-open netmap:v0/t"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i netmap:v0/t -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i netmap:v0/t -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -39,6 +39,6 @@ check_success $e1 "receive-${num} netmap:v0/t"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
diff --git a/utils/tests/020_send_cp_mon_pipe_test b/utils/tests/020_send_cp_mon_pipe_test
index f1c7d9933..9b12b7ff9 100755
--- a/utils/tests/020_send_cp_mon_pipe_test
+++ b/utils/tests/020_send_cp_mon_pipe_test
@@ -21,17 +21,17 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:pipe{1"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional $verbosity -i "netmap:pipe{1/t"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/t"
 check_success $? "pre-open netmap:pipe{1/t"
-functional $verbosity -i "netmap:pipe}1"
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # First we send without reading from pipe}1
-functional $verbosity -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/t" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -39,6 +39,6 @@ check_success $e1 "receive-${num} netmap:pipe{1/t"
 check_success $e2 "send-${num} netmap:pipe{1"
 
 # Then we read from pipe}1
-functional $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe}1" -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} netmap:pipe}1"
diff --git a/utils/tests/021_send_rec_ephemeral_vale_ports_test b/utils/tests/021_send_rec_ephemeral_vale_ports_test
index 253e0cd41..720758135 100755
--- a/utils/tests/021_send_rec_ephemeral_vale_ports_test
+++ b/utils/tests/021_send_rec_ephemeral_vale_ports_test
@@ -17,19 +17,19 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "vale0:v0"
+$FUNCTIONAL $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i "vale0:v1"
+$FUNCTIONAL $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional $verbosity -i "vale0:v2"
+$FUNCTIONAL $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" $seq
 e3=$?
 wait $p1
 e1=$?
@@ -40,11 +40,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p4=$!
-functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
 p5=$!
-functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" $seq
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/022_send_rec_persistent_vale_ports_test b/utils/tests/022_send_rec_persistent_vale_ports_test
index e467b11d2..7683572ee 100755
--- a/utils/tests/022_send_rec_persistent_vale_ports_test
+++ b/utils/tests/022_send_rec_persistent_vale_ports_test
@@ -24,19 +24,19 @@ attach_to_vale_bridge "vale0" "v1"
 attach_to_vale_bridge "vale0" "v2"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "vale0:v0"
+$FUNCTIONAL $verbosity -i "vale0:v0"
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i "vale0:v1"
+$FUNCTIONAL $verbosity -i "vale0:v1"
 check_success $? "pre-open vale0:v1"
-functional $verbosity -i "vale0:v2"
+$FUNCTIONAL $verbosity -i "vale0:v2"
 check_success $? "pre-open vale0:v2"
 
 # v2 ---> v0, v1
-functional $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v0" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p2=$!
-functional $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "vale0:v2" -t "${len}:${fill}:${num}" $seq
 e3=$?
 wait $p1
 e1=$?
@@ -47,11 +47,11 @@ check_success $e2 "receive-${num} vale0:v1"
 check_success $e3 "send-${num} vale0:v2"
 
 # v0 ---> v1, v2
-functional $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v1" -r "${len}:${fill}:${num}" $seq &
 p4=$!
-functional $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "vale0:v2" -r "${len}:${fill}:${num}" $seq &
 p5=$!
-functional $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "vale0:v0" -t "${len}:${fill}:${num}" $seq
 e6=$?
 wait $p4
 e4=$?
diff --git a/utils/tests/023_send_rec_pipe_test b/utils/tests/023_send_rec_pipe_test
index cc905b57b..d7845e6bd 100755
--- a/utils/tests/023_send_rec_pipe_test
+++ b/utils/tests/023_send_rec_pipe_test
@@ -17,15 +17,15 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:pipeA{1"
+$FUNCTIONAL $verbosity -i "netmap:pipeA{1"
 check_success $? "pre-open netmap:pipeA{1"
-functional $verbosity -i "netmap:pipeA}1"
+$FUNCTIONAL $verbosity -i "netmap:pipeA}1"
 check_success $? "pre-open netmap:pipeA}1"
 
 # pipeA}1 ---> pipeA{1
-functional $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipeA{1" -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipeA}1" -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -33,9 +33,9 @@ check_success $e1 "receive-${num} netmap:pipeA{1"
 check_success $e2 "send-${num} netmap:pipeA}1"
 
 # pipeA{1 ---> pipeA}1
-functional $verbosity -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipeA}1" -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipeA{1" -t "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e2=$?
diff --git a/utils/tests/024_send_rec_veth_test b/utils/tests/024_send_rec_veth_test
index 86ba2e882..4888b1f46 100755
--- a/utils/tests/024_send_rec_veth_test
+++ b/utils/tests/024_send_rec_veth_test
@@ -20,15 +20,15 @@ seq="${seq:-}"
 create_veth_interfaces "veth1"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i netmap:veth1A
+$FUNCTIONAL $verbosity -i netmap:veth1A
 check_success $? "pre-open netmap:veth1A"
-functional $verbosity -i netmap:veth1B
+$FUNCTIONAL $verbosity -i netmap:veth1B
 check_success $? "pre-open netmap:veth1B"
 
 # veth1B --> veth1A
-functional $verbosity -i netmap:veth1A -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i netmap:veth1A -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i netmap:veth1B -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i netmap:veth1B -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -36,9 +36,9 @@ check_success $e1 "receive-${num} netmap:veth1A"
 check_success $e2 "send-${num} netmap:veth1B"
 
 # veth1A --> veth1B
-functional $verbosity -i netmap:veth1B -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i netmap:veth1B -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i netmap:veth1A -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i netmap:veth1A -t "${len}:${fill}:${num}" $seq
 e4=$?
 wait $p3
 e3=$?
diff --git a/utils/tests/025_send_zcp_mon_ephemeral_vale_port_test b/utils/tests/025_send_zcp_mon_ephemeral_vale_port_test
index 93b296b5b..c81d123ae 100755
--- a/utils/tests/025_send_zcp_mon_ephemeral_vale_port_test
+++ b/utils/tests/025_send_zcp_mon_ephemeral_vale_port_test
@@ -21,17 +21,17 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i vale0:v0/z
+$FUNCTIONAL $verbosity -i vale0:v0/z
 check_success $? "pre-open vale0:v0/z"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i vale0:v0/z -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v0   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -39,6 +39,6 @@ check_success $e1 "receive-${num} vale0:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
diff --git a/utils/tests/026_send_zcp_mon_persistent_vale_port_test b/utils/tests/026_send_zcp_mon_persistent_vale_port_test
index 2b56bc75e..95b2f54c7 100755
--- a/utils/tests/026_send_zcp_mon_persistent_vale_port_test
+++ b/utils/tests/026_send_zcp_mon_persistent_vale_port_test
@@ -24,17 +24,17 @@ create_vale_persistent_port "v0"
 attach_to_vale_bridge "vale0" "v0"
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i vale0:v0
+$FUNCTIONAL $verbosity -i vale0:v0
 check_success $? "pre-open vale0:v0"
-functional $verbosity -i netmap:v0/z
+$FUNCTIONAL $verbosity -i netmap:v0/z
 check_success $? "pre-open netmap:v0/z"
-functional $verbosity -i vale0:v1
+$FUNCTIONAL $verbosity -i vale0:v1
 check_success $? "pre-open vale0:v1"
 
 # First we send without reading from v1
-functional $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i netmap:v0/z -r "${len}:${fill}:${num}" $seq &
 p1=$!
-functional $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v0    -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -42,6 +42,6 @@ check_success $e1 "receive-${num} netmap:v0/z"
 check_success $e2 "send-${num} vale0:v0"
 
 # Then we read from v1
-functional $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i vale0:v1 -r "${len}:${fill}:${num}" $seq
 e3=$?
 check_success $e3 "receive-${num} vale0:v1"
diff --git a/utils/tests/027_send_zcp_mon_pipe_test b/utils/tests/027_send_zcp_mon_pipe_test
index 2882f0646..75318fb1e 100755
--- a/utils/tests/027_send_zcp_mon_pipe_test
+++ b/utils/tests/027_send_zcp_mon_pipe_test
@@ -22,18 +22,18 @@ seq="${seq:-}"
 
 # Pre-opening interface that will be needed. This is needed to avoid a race
 # condition between the sending and receiving ports.
-functional $verbosity -i "netmap:pipe{1"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"
 check_success $? "pre-open netmap:pipe{1"
-functional $verbosity -i "netmap:pipe{1/z"
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/z"
 check_success $? "pre-open netmap:pipe{1/z"
-functional $verbosity -i "netmap:pipe}1"
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"
 check_success $? "pre-open netmap:pipe}1"
 
 # Initially we don't receive with the non-monitored pipe end, therefore the
 # monitor should not receive the frame.
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq -n &
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq -n &
 p1=$!
-functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
 e2=$?
 wait $p1
 e1=$?
@@ -44,11 +44,11 @@ check_success $e2 "send-${num} netmap:pipe{1"
 # monitored pipe otherwise the zero-copy monitor won't be able to see the
 # packet, as the slot is returned to the monitored pipe only during a txsync
 # action.
-functional $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq &
+$FUNCTIONAL $verbosity -i "netmap:pipe{1/z" -r "${len}:${fill}:${num}" $seq &
 p3=$!
-functional $verbosity -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe}1"   -r "${len}:${fill}:${num}" $seq
 e4=$?
-functional $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
+$FUNCTIONAL $verbosity -i "netmap:pipe{1"   -t "${len}:${fill}:${num}" $seq
 e5=$?
 wait $p3
 e3=$?

From 95ef45d15c243d33172dc15f8468ee98152cbbf0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 6 Nov 2019 10:59:27 +0100
Subject: [PATCH 1704/2207] intest: fix included header of fd_server-legacy

---
 utils/fd_server-legacy.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/fd_server-legacy.c b/utils/fd_server-legacy.c
index 3ac01baee..b895b99ed 100644
--- a/utils/fd_server-legacy.c
+++ b/utils/fd_server-legacy.c
@@ -17,7 +17,7 @@
 #define NETMAP_WITH_LIBS
 #include 
 
-#include "fd_server.h"
+#include "fd_server-legacy.h"
 
 struct nmd_entry {
 	char if_name[NETMAP_REQ_IFNAMSIZ];

From 6920798a9b3f89a36f50bbdcfff6aee6b331b82b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 25 Nov 2019 09:54:37 +0100
Subject: [PATCH 1705/2207] linux/scripts: default gcc9 config

---
 LINUX/scripts/np | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index cd111d24d..c4e892862 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -371,20 +371,19 @@ function build-prep()
 	get-params "version" "$@"
 
 	local dst=$(get-kernel $version)
+	local last
 
 	[ -f $dst/.build-prep ] && { echo $dst; return; }
 
 	(
 		cd $dst
-		[ -e include/linux/compiler-gcc5.h ] ||
-			ln -s compiler-gcc4.h include/linux/compiler-gcc5.h
-		[ -e include/linux/compiler-gcc6.h ] ||
-			ln -s compiler-gcc5.h include/linux/compiler-gcc6.h
-		[ -e include/linux/compiler-gcc7.h ] ||
-			ln -s compiler-gcc6.h include/linux/compiler-gcc7.h
-		[ -e include/linux/compiler-gcc8.h ] ||
-			ln -s compiler-gcc7.h include/linux/compiler-gcc8.h
-		# force disabling PIE
+		last=compiler-gcc.h
+		for i in $(seq 9); do
+			[ -e include/linux/compiler-gcc$i.h ] ||
+				ln -s $last include/linux/compiler-gcc$i.h
+			last=compiler-gcc$i.h
+		done
+		# force disabling PIE and fcf-protection
 		sed -i -e '/^all: vmlinux/a\
 \
 KBUILD_CFLAGS += $(call cc-option, -fno-pie)\

From 828d73e06fb8e9059e752854683d10c7d34bc3c8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 25 Nov 2019 17:55:53 +0100
Subject: [PATCH 1706/2207] linux/scripts: compile old kernels with gcc9

---
 LINUX/scripts/np | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index c4e892862..b7985cdb9 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -388,6 +388,7 @@ function build-prep()
 \
 KBUILD_CFLAGS += $(call cc-option, -fno-pie)\
 KBUILD_CFLAGS += $(call cc-option, -no-pie)\
+KBUILD_CFLAGS += $(call cc-option, -fcf-protection=none)\
 KBUILD_AFLAGS += $(call cc-option, -fno-pie)\
 KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		if [ -f $LINUX_CONFIGS/config-$version ]; then
@@ -396,6 +397,11 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		else
 			make allmodconfig
 		fi
+		# old kernels' selinux causes compilation failures with gcc >= 9
+		echo "CONFIG_SECURITY_SELINUX=n" >> .config
+		yes '' | make oldconfig
+		# some tools do not compile with -Werror and gcc >= 9
+		sed -i 's/-Werror/-Wno-error/g' $(grep -Rl -- -Werror tools)
 		make modules_prepare
 		touch .build-prep
 	) >$dst.log 2>&1 || error "build-prep failed for linux $version. Please check $dst.log"

From 9ad61404466cb39db1d0082f2c79be13dd44f4e8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 25 Nov 2019 22:35:11 +0100
Subject: [PATCH 1707/2207] linux/configure: disable missing-attributes during
 feature-testing

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 5ec19efac..cd63cb908 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -982,7 +982,7 @@ EOF
 
   add_test true broken_buildsystem < /dev/null
 
-DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation"
+DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation missing-attributes"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"

From ae5e9ee5379faa782044b4e511c32c8f0fbee294 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 9 Dec 2019 14:04:39 +0100
Subject: [PATCH 1708/2207] linux/igb: patch for Intel 5.3.5.42 version

---
 LINUX/final-patches/intel--igb--5.3.5.42 | 138 +++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.42

diff --git a/LINUX/final-patches/intel--igb--5.3.5.42 b/LINUX/final-patches/intel--igb--5.3.5.42
new file mode 100644
index 000000000..ce7ad797b
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.42
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 924ae5b..0a5f720 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index a8ad07b..60568f1 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -237,6 +237,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3180,6 +3184,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3385,6 +3393,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3797,6 +3809,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7477,6 +7492,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8493,6 +8513,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8812,6 +8837,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 9ec13dc130d339c364025a16075c33ae99d52e8c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 9 Dec 2019 14:05:06 +0100
Subject: [PATCH 1709/2207] linux/ixgbe: patch for Intel 5.6.5 version

---
 LINUX/final-patches/intel--ixgbe--5.6.5 | 173 ++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.6.5

diff --git a/LINUX/final-patches/intel--ixgbe--5.6.5 b/LINUX/final-patches/intel--ixgbe--5.6.5
new file mode 100644
index 000000000..82c2d74dd
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.6.5
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index e613859..8ca5eaa 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index a6971c3..6cee6ed 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -706,6 +706,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -725,6 +742,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2195,6 +2223,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3656,6 +3694,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4332,6 +4374,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12900,6 +12948,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12955,6 +13007,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From cb68f3db681cc60b8e05bed7027425dfdd027a04 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 9 Dec 2019 14:05:31 +0100
Subject: [PATCH 1710/2207] linux/ixgbevf: patch for Intel 4.6.3 version

---
 LINUX/final-patches/intel--ixgbevf--4.6.3 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.6.3

diff --git a/LINUX/final-patches/intel--ixgbevf--4.6.3 b/LINUX/final-patches/intel--ixgbevf--4.6.3
new file mode 100644
index 000000000..cce068531
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.6.3
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index b37fbce..f3cdb26 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -69,9 +69,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index e7bd791..c845e6c 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -338,6 +338,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -358,6 +375,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1356,6 +1384,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2054,6 +2092,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2288,6 +2330,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5581,8 +5627,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5623,6 +5671,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 785e735..56246ec 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 8b4627c451b2de09ba4cfbac537e35dc695af4b2 Mon Sep 17 00:00:00 2001
From: Konstantin Kogdenko 
Date: Tue, 7 Jan 2020 22:18:27 +0300
Subject: [PATCH 1711/2207] veth: fix segfault at access to not created adapter
 rings

Remove peer in veth_netmap_krings_delete(vna) because without that
subsequent call of veth_netmap_krings_create(vna->peer) do not create rings.
---
 LINUX/veth_netmap.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 1f9e9bad0..fdd1126e8 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -81,6 +81,7 @@ veth_netmap_dtor(struct netmap_adapter *na)
 		(struct netmap_veth_adapter *)na;
 	if (vna->peer_ref) {
 		vna->peer_ref = 0;
+		vna->peer->peer = NULL;
 		netmap_adapter_put(&vna->peer->up.up);
 	}
 }
@@ -211,6 +212,11 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 	}
 
 	netmap_pipe_krings_delete_both(na, peer_na);
+
+	netmap_adapter_put(&vna->peer->up.up);
+	vna->peer_ref = 0;
+	vna->peer->peer = NULL;
+	vna->peer = NULL;
 }
 
 static void

From 07b07a2ab8ccc831f345d8a0d41e724f735af2f8 Mon Sep 17 00:00:00 2001
From: Vadim YR 
Date: Mon, 13 Jan 2020 16:50:55 +0200
Subject: [PATCH 1712/2207] check na before using

---
 sys/dev/netmap/netmap_mem2.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 2f2c022c9..88e715d3a 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1523,10 +1523,13 @@ static int
 netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 {
 	int i, lim = p->objtotal;
-	struct netmap_lut *lut = &na->na_lut;
-
+	struct netmap_lut *lut;
 	if (na == NULL || na->pdev == NULL)
 		return 0;
+	
+	lut = &na->na_lut;
+
+	
 
 #if defined(__FreeBSD__)
 	/* On FreeBSD mapping and unmapping is performed by the txsync

From ee56d6e1e8919db48a21238e4e3eec8fd341a497 Mon Sep 17 00:00:00 2001
From: Vadim YR 
Date: Tue, 14 Jan 2020 00:50:07 +0200
Subject: [PATCH 1713/2207] Update netmap_ptnet.c

---
 LINUX/netmap_ptnet.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index a91b9256d..22b24c1ff 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1477,7 +1477,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	return 0;
 
-	pr_info("%s: failed to probe device\n", __func__);
+	
 err_netreg:
 	ptnet_irqs_fini(pi);
 err_irqs:
@@ -1490,6 +1490,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	pci_release_selected_regions(pdev, bars);
 err_pci_reg:
 	pci_disable_device(pdev);
+	pr_info("%s: failed to probe device\n", __func__);
 	return err;
 }
 

From 37e03c49f96558df25c36e3abc7536c2a3a5a751 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 Jan 2020 16:28:45 +0100
Subject: [PATCH 1714/2207] ptnet: use skb_frag_t

---
 LINUX/netmap_ptnet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 22b24c1ff..bc7f10420 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -284,7 +284,7 @@ ptnet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 	/* Third step: Copy in the sk_buffs frags. */
 	for (f = 0; f < nfrags; f++) {
-		const struct skb_frag_struct *frag;
+		const skb_frag_t *frag;
 
 		frag = &skb_shinfo(skb)->frags[f];
 		ptnet_copy_to_ring(&a, skb_frag_address(frag),

From f879d17ef133625940489a4795bdd29d8c83d4a3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 Jan 2020 16:29:00 +0100
Subject: [PATCH 1715/2207] ptnet: fix whitespace

---
 LINUX/netmap_ptnet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index bc7f10420..0ffd7ddf3 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1477,7 +1477,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	return 0;
 
-	
+
 err_netreg:
 	ptnet_irqs_fini(pi);
 err_irqs:

From 46d532f35ecbd454d0269532ac17b6be7ca12fda Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 30 Jan 2020 10:19:57 +0100
Subject: [PATCH 1716/2207] linux/i40e: patch for Intel 2.10.19.82 version

---
 LINUX/final-patches/intel--i40e--2.10.19.82 | 166 ++++++++++++++++++++
 1 file changed, 166 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.10.19.82

diff --git a/LINUX/final-patches/intel--i40e--2.10.19.82 b/LINUX/final-patches/intel--i40e--2.10.19.82
new file mode 100644
index 000000000..5e87f25b9
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.10.19.82
@@ -0,0 +1,166 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 5b3ca74..79db7aa 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 3588ce8..b5def2e 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -136,6 +136,11 @@ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3482,6 +3487,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3535,6 +3544,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3563,6 +3576,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13773,6 +13791,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14145,6 +14168,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index b6b1a78..28a970c 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From 48438b468e454a2eb21c27ba7fff795c0717c1d3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Feb 2020 17:12:08 +0100
Subject: [PATCH 1717/2207] tlem: fix check for missing interface name

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 57db9449e..a43c62ada 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1224,7 +1224,7 @@ main(int argc, char **argv)
     /*
      * consistency checks for common arguments
      */
-    if (!ifname[0] || !ifname[0]) {
+    if (!ifname[0] || !ifname[1]) {
         ED("missing interface(s)");
         usage();
     }

From 69455ef2f18c6d03a850200552d05655daaa65db Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 24 Jan 2017 17:08:10 +0100
Subject: [PATCH 1718/2207] tlem: route-mode

---
 apps/tlem/GNUmakefile |   4 +-
 apps/tlem/tlem.8      |  21 ++
 apps/tlem/tlem.c      | 594 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 610 insertions(+), 9 deletions(-)

diff --git a/apps/tlem/GNUmakefile b/apps/tlem/GNUmakefile
index 45613a38d..611c1e42d 100644
--- a/apps/tlem/GNUmakefile
+++ b/apps/tlem/GNUmakefile
@@ -9,8 +9,8 @@ SRCDIR ?= ../..
 VPATH = $(SRCDIR)/apps/tlem
 
 NO_MAN=
-CFLAGS = -O2 -pipe
-CFLAGS += -Werror -Wall -Wunused-function
+CFLAGS = -O2 -pipe -g
+CFLAGS += -Werror -Wall -Wunused-function -Wno-address-of-packed-member
 CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I$(SRCDIR)/libnetmap
 CFLAGS += -Wextra
 
diff --git a/apps/tlem/tlem.8 b/apps/tlem/tlem.8
index 3cba7574a..495f1d251 100644
--- a/apps/tlem/tlem.8
+++ b/apps/tlem/tlem.8
@@ -40,9 +40,11 @@
 .Op Fl L Ar loss
 .Op Fl Q Ar queue size
 .Op Fl C Ar cpu-placement
+.Op Fl G Ar gateway
 .Op Fl b Ar batch size
 .Op Fl w Ar wait-link
 .Op Fl v
+.Op Fl r
 .Sh DESCRIPTION
 .Nm
 implements a high speed bidirectional link emulator between netmap ports,
@@ -127,6 +129,8 @@ limitations are applied.
 .It Fl C Ar a Ns Op , Ns Ar b Ns Op , Ns Ar c,d
 Indicates the cores on which the four threads should be placed.
 One, two or four values can be specified.
+.It Fl G Ar ipv4-address
+Indicates the optional default gateways to be used in route-mode.
 .It Fl w Ar wait-link
 indicates the number of seconds to wait before transmitting.
 It defaults to 2, and may be useful when talking to physical
@@ -139,6 +143,8 @@ Maximum batch size to use during transmissions.
 normally transmits packets one at a time, but it may use
 larger batches, up to the value specified with this option,
 when running at high rates.
+.It Fl r
+Enable route-mode.
 .El
 .Sh OPERATION
 .Nm
@@ -156,6 +162,21 @@ computes the transmit time applying the additional delay.
 Packets annotated with their transmit time are copied in
 a large in-memory buffer. The output thread spins on the buffer,
 doing short sleeps, until packets reach their transmit time.
+.Sh ROUTE-MODE
+In route-mode
+.Nm
+operates as an IPv4 router between the two subnets at its ends,
+replying to and sending the necessary ARP messages and updating
+the destination MAC addresses. The IP addresses and subnets are
+obtained from the ports, so this mode cannot be used with
+software-only netmap ports like ephemeral VALE ports and pipes.
+
+There are some limitations: unresolved destinations are sent as broadcasts
+until resolution; packets destined to the same subnet as their incoming
+port are dropped; TTL is not decremented.  Each subnet may also optionally
+have a default gateway: for each direction, incoming packets not destined
+to either of the two known subnets are sent to the default gateway of
+the output port, if specified, and dropped otherwise.
 .Sh PERFORMANCE
 We have measured speeds in excess of 20 Mpps and 40 Gbit/s per
 direction on a modern i7 CPU with 4 cores.  The accuracy in delays
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index a43c62ada..1836533d0 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -152,15 +152,25 @@ static int do_abort = 0;
 #include 
 #include 
 
+// for route-mode
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
 #include  // setpriority
 
 #ifdef __FreeBSD__
+#include 	/* sokcaddr_dl */
 #include  /* pthread w/ affinity */
 #include  /* cpu_set */
 #endif /* __FreeBSD__ */
 
 #ifdef linux
 #define cpuset_t        cpu_set_t
+#include 
 #endif
 
 #ifdef __APPLE__
@@ -374,9 +384,233 @@ struct _qs { /* shared queue */
 	volatile uint64_t head ALIGN_CACHE ;	/* consumer reads from here */
 };
 
+/* route-mode data structures and helper functions
+ *
+ * In route-mode TLEM acts as a router between the two subnets at its ends.
+ * This is implemented as follows:
+ * - there are two arp tables, one for each subnet
+ * - arp tables are private to the cons() process
+ * - the prod() processes extract the relevant info from any received ARP
+ *   message and pass them down to the cons() process insisting on the same
+ *   port, as illustrated in the following diagram:
+ *
+ *         |---> prod1 --------------------------> cons1 --->|
+ *         |       |                                 ^       |
+ *         | ARP req/repl info                       |       |
+ *         |       |                                 |       |
+ * port1<->+       |                                 |       +<->port2
+ *         |       |                                 |       |
+ *         |       |                       ARP req/repl info |
+ *         |       V                                 |       |
+ *         |<--- cons2 <-------------------------- prod2 <---|
+ *
+ * - the cons() processes react to these infos by sending ARP replies/
+ *   updating their private ARP table as needed
+ * - the cons() processes change the outgoing packets destination addresses
+ *   before injecting them, sending ARP requests when needed.
+ * - TTL decrement is not implemented, for performance reasons.
+ *
+ * Delegating all the heavy work to the cons() has the advantage that the only
+ * new inter-thread interactions are prod1->cons1 and prod2->cons2; these can
+ * be implemented by lockless and barrier-less mailboxes. Since writes into the
+ * mailbox are rare, the consumer can bring it into its local cache and poll it
+ * as often as needed, without incurring too much of a performance hit.
+ *
+ */
+
+/* the arp table is implemented as a sparse array indexed by
+ * the host part of the ip address.
+ *
+ * The array is in virtual memory (mmap) and is left uninitialized, so that the
+ * kernel will allocate and zero-fill pages on demand.  The ether_addr is
+ * stored in negated form and therefore it is always valid: uninitialized
+ * entries will give the broadcast address.  A new arp request will be sent
+ * when 'now' is after 'next_req'. The initial zero value of 'next_req' will
+ * trigger an arp request the first time the entry is read.
+ */
+struct arp_table_entry {
+	uint64_t	next_req;	/* when to send next arp request */
+	union {
+		uint8_t		ether_addr[6 + 2]; /* size + padding */
+		struct {
+			uint32_t eth1;
+			uint16_t eth2;
+			uint16_t pad;
+		};
+	};
+} __attribute__((packed));
+
+void
+arp_table_entry_dump(int idx, struct arp_table_entry *e)
+{
+    ED("%d: next %lu addr %02x:%02x:%02x:%02x:%02x:%02x",
+            idx, e->next_req,
+            (uint8_t)~e->ether_addr[0],
+            (uint8_t)~e->ether_addr[1],
+            (uint8_t)~e->ether_addr[2],
+            (uint8_t)~e->ether_addr[3],
+            (uint8_t)~e->ether_addr[4],
+            (uint8_t)~e->ether_addr[5]);
+}
+
+struct arp_table_entry *
+arp_table_new(in_addr_t mask)
+{
+    // XXX this only works if mask is in CIDR form */
+    size_t s = (~ntohl(mask) + 1) * sizeof(struct arp_table_entry);
+    struct arp_table_entry *e;
+    D("allocating %zu bytes for arp table", s);
+    e = mmap(NULL, s, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+    if (e == MAP_FAILED)
+        return NULL;
+    return e;
+}
+
+static inline int
+arp_idx(in_addr_t addr, in_addr_t mask)
+{
+    return ntohl(addr & ~mask);
+}
+
+
+/* arp commands are sent by the producer to the consumer that insists on
+ * the same port. The commands are sent when the producer receives an ARP
+ * message, as follows:
+ * - when an ARP request is received, ask the consumer to send an ARP
+ *   reply
+ * - when an ARP reply is received, ask the consumer to update its
+ *   ARP table
+ * The commands also contain the ethernet and IP address of the sender
+ * of the received ARP message.
+ */
+struct arp_cmd {
+	union {
+		uint8_t		ether_addr[6];
+		struct {
+			uint32_t eth1;
+			uint16_t eth2;
+		};
+	};
+	uint8_t		valid; /* 0: empty, 1: new, 2: seen */
+	uint8_t		cmd;   /* ARPOP_REQUEST or ARPOP_REPLY */
+	in_addr_t	ip_addr;
+	uint8_t		pad[4];
+} __attribute__((packed));
+
+/* the commands are sent in a small mailbox shared between the producer and the
+ * consumer. The head and tail pointers are not shared, and the synchronization
+ * is enforced by the 'valid' fields inside the commands themselves.  This
+ * saves some cache misses and eliminates the need for memory barriers.
+ */
+#define ARP_CMD_QSIZE 16
+struct arp_cmd_q {
+	struct arp_cmd	q[ARP_CMD_QSIZE] ALIGN_CACHE;
+	uint64_t	head ALIGN_CACHE; /* private to the consumer */
+	uint64_t	toclean;	  /* private to the consumer */
+	uint64_t	tail ALIGN_CACHE; /* private to the producer */
+};
+
+/* consumer: extract a new command.  The command slot is not immediatly
+ * released, so that at most ARP_CMD_QSIZE messages are read for each
+ * cons() loop.
+ */
+static inline struct arp_cmd *
+arpq_get_cmd(struct arp_cmd_q *a)
+{
+    int h = a->head & (ARP_CMD_QSIZE - 1);
+    if (unlikely(a->q[h].valid == 1)) {
+        a->q[h].valid = 2; /* mark as seen */
+        a->head++;
+        return &a->q[h];
+    }
+    return NULL;
+}
+
+/* consumer: release all seen slots */
+static inline void
+arpq_release(struct arp_cmd_q *a)
+{
+    if (likely(a->q[a->toclean].valid != 2))
+        return;
+    while (a->q[a->toclean].valid == 2) {
+        a->q[a->toclean].valid = 0;
+        a->toclean++;
+    }
+}
+
+struct arp_cmd *
+arpq_new_cmd(struct arp_cmd_q *a)
+{
+    int t = a->tail & (ARP_CMD_QSIZE - 1);
+    struct arp_cmd *c = &a->q[t];
+
+    return (c->valid ? NULL : c);
+}
+
+void
+arpq_push(struct arp_cmd_q *a, struct arp_cmd *c)
+{
+    c->valid = 1;
+    a->tail++;
+}
+
+static inline int
+is_arp(const void *pkt)
+{
+    const struct ether_header *h = pkt;
+    return h->ether_type == htons(ETHERTYPE_ARP);
+}
+
+struct arp_cmd_q arpq[2];
+
+/* IPv4 info for a port. Shared between the producer and the consumer that
+ * insist on the same port
+ */
+struct ipv4_info {
+	char		name[IFNAMSIZ + 1];
+	in_addr_t	ip_addr;
+	in_addr_t	ip_mask;
+	in_addr_t	ip_subnet;
+	in_addr_t	ip_bcast;
+	in_addr_t	ip_gw;
+	uint8_t		ether_addr[6];
+	/* pre-formatted arp messages */
+	union {
+		uint8_t pkt[60];
+		struct {
+			struct ether_header eh;
+			struct ether_arp    ah;
+		} arp __attribute__((packed));
+	} arp_reply, arp_request;
+
+	struct arp_table_entry *arp_table;
+};
+
+void
+ipv4_dump(const struct ipv4_info *i)
+{
+    const uint8_t *ipa = (uint8_t *)&i->ip_addr,
+          *ipm = (uint8_t *)&i->ip_mask,
+          *ipb = (uint8_t *)&i->ip_bcast,
+          *ipc = (uint8_t *)&i->ip_gw,
+          *ea = i->ether_addr;
+
+    ED("%s: ip %u.%u.%u.%u/%u.%u.%u.%u bcast %u.%u.%u.%u gw %u.%u.%u.%u mac %02x:%02x:%02x:%02x:%02x:%02x",
+            i->name,
+            ipa[0], ipa[1], ipa[2], ipa[3],
+            ipm[0], ipm[1], ipm[2], ipm[3],
+            ipb[0], ipb[1], ipb[2], ipb[3],
+            ipc[0], ipc[1], ipc[2], ipc[3],
+            ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
+}
+
+struct ipv4_info ipv4[2];
+
+
 struct pipe_args {
 	int		zerocopy;
 	int		wait_link;
+	int		route_mode;
 
 	pthread_t	cons_tid;	/* main thread */
 	pthread_t	prod_tid;	/* producer thread */
@@ -388,6 +622,12 @@ struct pipe_args {
 	struct nmport_d *pa;		/* netmap descriptor */
 	struct nmport_d *pb;
 
+	/* route-mode */
+	struct arp_cmd_q *cons_arpq;	/* out mailbox for cons */
+	struct arp_cmd_q *prod_arpq;	/* in mailbox for prod */
+	struct ipv4_info *cons_ipv4;	/* mac addr etc. */
+	struct ipv4_info *prod_ipv4;	/* mac addr etc. */
+
 	struct _qs	q;
 };
 
@@ -734,6 +974,38 @@ drop_after(struct _qs *q)
     return 0;
 }
 
+/* poducer: send the proper command depending on the contents of the received
+ * ARP message in pkt
+ */
+void
+prod_push_arp(const struct pipe_args *pa, const void *pkt)
+{
+    const struct ether_header *eh = pkt;
+    const struct ether_arp *arp = (const struct ether_arp *)(eh + 1);
+    const struct ipv4_info *ip = pa->prod_ipv4;
+    struct arp_cmd_q *a = pa->prod_arpq;
+    struct arp_cmd *c;
+    in_addr_t ip_saddr, ip_taddr;
+    uint16_t arpop = ntohs(arp->ea_hdr.ar_op);
+
+    memcpy(&ip_saddr, arp->arp_spa, 4);
+    memcpy(&ip_taddr, arp->arp_tpa, 4);
+    if (ip_taddr != ip->ip_addr ||
+            ((ip_saddr & ip->ip_mask) != ip->ip_subnet) ||
+            (arpop != ARPOP_REQUEST && arpop != ARPOP_REPLY)) {
+        /* not for us, drop */
+        return;
+    }
+    c = arpq_new_cmd(a);
+    if (c == NULL) {
+        /* no space left in the mailbox */
+        return;
+    }
+    c->cmd = arpop; /* just the low byte */
+    memcpy(c->ether_addr, arp->arp_sha, 6);
+    c->ip_addr = ip_saddr;
+    arpq_push(a, c);
+}
 
 static void *
 prod(void *_pa)
@@ -759,6 +1031,11 @@ prod(void *_pa)
                 RD(5, "short packet len %d", q->cur_len);
                 continue; // short frame
             }
+            if (pa->route_mode && unlikely(is_arp(q->cur_pkt))) {
+                /* pass it to the consumer in the other direction */
+                prod_push_arp(pa, q->cur_pkt);
+                continue;
+            }
             q->c_loss.run(q, &q->c_loss);
             if (q->cur_drop)
                 continue;
@@ -787,6 +1064,99 @@ prod(void *_pa)
     return NULL;
 }
 
+/* react to a command sent by the producer in the other direction.
+ * returns the number of packets injected.
+ */
+int
+cons_handle_arp(struct pipe_args *pa, struct arp_cmd *c)
+{
+    struct ipv4_info *ip = pa->cons_ipv4;
+    struct ether_header *eh = &ip->arp_reply.arp.eh;
+    struct ether_arp *ah = &ip->arp_reply.arp.ah;
+    struct arp_table_entry *e;
+    int rv = 0;
+
+    switch (c->cmd) {
+        case ARPOP_REQUEST:
+            /* send reply */
+            memcpy(eh->ether_dhost, c->ether_addr, 6);
+            memcpy(ah->arp_tha, c->ether_addr, 6);
+            memcpy(ah->arp_tpa, &c->ip_addr, 4);
+            if (nmport_inject(pa->pb, eh, sizeof(ip->arp_reply)) == 0) {
+                RD(1, "failed to inject arp reply");
+                break;
+            }
+            /* force the reply out */
+            rv = pa->q.burst;
+            break;
+        case ARPOP_REPLY:
+            e = ip->arp_table + arp_idx(c->ip_addr, ip->ip_mask);
+            set_tns_now(&e->next_req, pa->q.cons_now);
+            e->next_req += 5000000000;
+            e->eth1 = ~c->eth1;
+            e->eth2 = ~c->eth2;
+            break;
+        default:
+            /* we don't handle these ones */
+            RD(1, "unknown/unsupported ARP operation: %x", c->cmd);
+            break;
+    }
+    return rv;
+}
+
+/* change the ethernet target address according to the local ARP table.
+ * may send an ARP request.
+ * returns the number of packets injected, or < 0 if the packet
+ * needs to be dropped
+ */
+static inline int
+cons_update_dst(struct pipe_args *pa, void *pkt)
+{
+    struct ether_header *eh = pkt;
+    struct ip *iph = (struct ip *)(eh + 1);
+    in_addr_t dst = iph->ip_dst.s_addr;
+    struct arp_table_entry *e;
+    struct ipv4_info *ipv4 = pa->cons_ipv4;
+    int idx;
+    int injected = 0;
+    //uint8_t *d = (uint8_t *)&dst;
+
+    ND("dst %u.%u.%u.%u", d[0], d[1], d[2], d[3]);
+    if (unlikely(!(eh->ether_type == ntohs(ETHERTYPE_IP))))
+        return -1; /* drop */
+    if (unlikely(dst == ipv4->ip_bcast || dst == 0xffffffff))
+        return -1; /* drop */
+    if ((dst & ipv4->ip_mask) != ipv4->ip_subnet) {
+        if (ipv4->ip_gw) {
+            /* send to the default gateway */
+            dst = ipv4->ip_gw;
+        } else {
+            return -1; /* drop */
+        }
+    }
+    idx = arp_idx(dst, ipv4->ip_mask);
+    e = ipv4->arp_table + idx;
+    ND("idx %d e %p", idx, e);
+    //arp_table_entry_dump(idx, e);
+    if (unlikely(ts_cmp(pa->q.cons_now, e->next_req) > 0)) {
+        /* send arp request for this client */
+        struct ether_arp *ah = &ipv4->arp_request.arp.ah;
+        ND("sending arp request");
+        memcpy(ah->arp_tpa, &dst, 4);
+        set_tns_now(&e->next_req, pa->q.cons_now);
+        e->next_req += 5000000000; /* 5s */
+        if (nmport_inject(pa->pb, &ipv4->arp_request,
+                    sizeof(ipv4->arp_request)) == 0) {
+            RD(1, "failed to inject arp request");
+        } else {
+            injected = 1;
+        }
+    }
+    /* copy negated dst into eh (either brodcast or unicast) */
+    *(uint32_t *)eh = ~e->eth1;
+    *(uint16_t *)((char *)eh + 4) = ~e->eth2;
+    return injected;
+}
 
 /*
  * the consumer reads from the queue using head,
@@ -797,7 +1167,7 @@ cons(void *_pa)
 {
     struct pipe_args *pa = _pa;
     struct _qs *q = &pa->q;
-    int pending = 0;
+    int pending = 0, retrying = 0;
 #if 0
     int cycles = 0;
     const char *pre_start, *pre_end; /* prefetch limits */
@@ -815,6 +1185,7 @@ cons(void *_pa)
         uint64_t h = q->head; /* read only once */
         uint64_t t = q->tail; /* read only once */
         struct q_pkt *p = (struct q_pkt *)(q->buf + h);
+        struct arp_cmd *arpc;
 #if 0
         struct q_pkt *p = (struct q_pkt *)(q->buf + q->head);
         if (p->next < q->head) { /* wrap around prefetch */
@@ -832,12 +1203,34 @@ cons(void *_pa)
         for (; pre_start < pre_end; pre_start += 64)
             __builtin_prefetch(pre_start);
 #endif
+        if (pa->route_mode) {
+            while (unlikely(arpc = arpq_get_cmd(pa->cons_arpq))) {
+                // uint8_t *ip_addr = (uint8_t *)&arpc->ip_addr;
+                ND("arp %x ether %02x:%02x:%02x:%02x:%02x:%02x ip %u.%u.%u.%u",
+                        arpc->cmd,
+                        arpc->ether_addr[0],
+                        arpc->ether_addr[1],
+                        arpc->ether_addr[2],
+                        arpc->ether_addr[3],
+                        arpc->ether_addr[4],
+                        arpc->ether_addr[5],
+                        ip_addr[0],
+                        ip_addr[1],
+                        ip_addr[2],
+                        ip_addr[3]);
+                pending += cons_handle_arp(pa, arpc);
+            }
+            arpq_release(pa->cons_arpq);
+        }
 
         if (h == t || ts_cmp(p->pt_tx, q->cons_now) > 0) {
             ND(4, "                 >>>> TXSYNC, pkt not ready yet h %ld t %ld now %ld tx %ld",
                     h, t, q->cons_now, p->pt_tx);
             q->rx_wait++;
-            ioctl(pa->pb->fd, NIOCTXSYNC, 0); // XXX just in case
+            /* this also sends any pending arp messages from this or
+             * previous loop iterations
+             */
+            ioctl(pa->pb->fd, NIOCTXSYNC, 0);
             pending = 0;
             usleep(5);
             set_tns_now(&q->cons_now, q->t0);
@@ -845,20 +1238,32 @@ cons(void *_pa)
         }
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
                 p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
+        if (pa->route_mode && !retrying) {
+            int injected = cons_update_dst(pa, p + 1);
+            if (unlikely(injected < 0)) {
+                /* drop this packet. Any pending arp message
+                 * will be sent in the next iteration
+                 */
+                goto next;
+            }
+            pending += injected;
+        }
         /* XXX inefficient but simple */
         if (nmport_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0) {
             ND(5, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
                     (int)p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
             ioctl(pa->pb->fd, NIOCTXSYNC, 0);
             pending = 0;
+            retrying = 1;
             continue;
         }
+        retrying = 0;
         pending++;
         if (pending > q->burst) {
             ioctl(pa->pb->fd, NIOCTXSYNC, 0);
             pending = 0;
         }
-
+next:
         q->head = p->next;
         /* drain packets from the queue */
         q->rx++;
@@ -963,7 +1368,7 @@ usage(void)
 {
     fprintf(stderr,
             "usage: tlem [-v] [-D delay] [-B bps] [-L loss] [-Q qsize] \n"
-            "\t[-b burst] [-w wait_time] -i ifa -i ifb\n");
+            "\t[-b burst] [-w wait_time] [-G gateway] -i ifa -i ifb\n");
     exit(1);
 }
 
@@ -1098,7 +1503,8 @@ main(int argc, char **argv)
 
 #define	N_OPTS	2
     struct pipe_args bp[N_OPTS];
-    const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS];
+    const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS],
+    *gw[N_OPTS];
     int ncpus;
     int cores[4];
 
@@ -1108,6 +1514,7 @@ main(int argc, char **argv)
     bzero(b, sizeof(b));
     bzero(l, sizeof(l));
     bzero(q, sizeof(q));
+    bzero(gw, sizeof(gw));
     bzero(ifname, sizeof(ifname));
 
     fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
@@ -1146,8 +1553,9 @@ main(int argc, char **argv)
     // i	interface name (two mandatory)
     // v	verbose
     // b	batch size
+    // r	route mode
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:b:ci:vw:")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:r")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -1197,7 +1605,9 @@ main(int argc, char **argv)
             case 'L': /* loss probability */
                 add_to(l, N_OPTS, optarg, "-L too many times");
                 break;
-
+            case 'G': /* default gateway */
+                add_to(gw, N_OPTS, optarg, "-G too many times");
+                break;
             case 'b':	/* burst */
                 bp[0].q.burst = atoi(optarg);
                 break;
@@ -1214,6 +1624,9 @@ main(int argc, char **argv)
             case 'w':
                 bp[0].wait_link = atoi(optarg);
                 break;
+            case 'r':
+                bp[0].route_mode = 1;
+                break;
         }
 
     }
@@ -1241,9 +1654,170 @@ main(int argc, char **argv)
         bp[0].wait_link = 4;
     }
 
+    if (bp[0].route_mode) {
+        int fd;
+        struct ifreq ifr;
+#ifdef __FreeBSD__
+        struct ifaddrs *ifap, *p;
+
+        if (getifaddrs(&ifap) < 0) {
+            ED("failed to get interface list: %s", strerror(errno));
+            usage();
+        }
+#endif /* __FreeBSD__ */
+
+        fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+        if (fd < 0) {
+            ED("failed to open SOCK_DGRAM socket: %s", strerror(errno));
+            usage();
+        }
+
+        for (i = 0; i < 2; i++) {
+            struct ipv4_info *ip = &ipv4[i];
+            char *dst = ip->name;
+            const char *scan;
+            struct ether_header *eh;
+            struct ether_arp *ah;
+            void *hwaddr = NULL;
+
+            /* try to extract the port name */
+            if (!strncmp("vale", ifname[i], 4)) {
+                ED("route mode not supported for VALE port %s", ifname[i]);
+                usage();
+            }
+            if (strncmp("netmap:", ifname[i], 7)) {
+                ED("missing netmap: prefix in %s", ifname[i]);
+                usage();
+            }
+            scan = ifname[i] + 7;
+            if (strlen(scan) >= IFNAMSIZ) {
+                ED("name too long: %s", scan);
+                usage();
+            }
+            while (*scan && isalnum(*scan))
+                *dst++ = *scan++;
+            *dst = '\0';
+            ED("trying to get configuration for %s", ip->name);
+
+            /* MAC address */
+#ifdef linux
+            memset(&ifr, 0, sizeof(ifr));
+            strcpy(ifr.ifr_name, ip->name);
+            if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) {
+                hwaddr = ifr.ifr_addr.sa_data;
+            }
+#elif defined (__FreeBSD__)
+            errno = ENOENT;
+            for (p = ifap; p; p = p->ifa_next) {
+
+                if (!strcmp(p->ifa_name, ip->name) &&
+                        p->ifa_addr != NULL &&
+                        p->ifa_addr->sa_family == AF_LINK)
+                {
+                    struct sockaddr_dl *sdp =
+                        (struct sockaddr_dl *)p->ifa_addr;
+                    hwaddr = sdp->sdl_data + sdp->sdl_nlen;
+                    break;
+                }
+            }
+#endif /* __FreeBSD__ */
+            if (hwaddr == NULL) {
+                ED("failed to get MAC address for %s: %s",
+                        ip->name, strerror(errno));
+                usage();
+            }
+            memcpy(ip->ether_addr, hwaddr, 6);
+
+#define get_ip_info(_c, _f, _m) 								\
+            memset(&ifr, 0, sizeof(ifr));						\
+            strcpy(ifr.ifr_name, ip->name);						\
+            ifr.ifr_addr.sa_family = AF_INET;					\
+            if (ioctl(fd, _c, &ifr) < 0) {						\
+                ED("failed to get IPv4 " _m " for %s: %s",			\
+                        ip->name, strerror(errno));			\
+                usage();							\
+            }									\
+            memcpy(&ip->_f, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, 4);	\
+
+
+            /* IP address */
+            get_ip_info(SIOCGIFADDR, ip_addr, "address");
+            /* netmask */
+            get_ip_info(SIOCGIFNETMASK, ip_mask, "netmask");
+            /* broadcast */
+            get_ip_info(SIOCGIFBRDADDR, ip_bcast, "broadcast");
+#undef get_ip_info
+
+            /* do we have an IP address? */
+            if (ip->ip_addr == 0) {
+                ED("no IPv4 address found for %s", ip->name);
+                usage();
+            }
+
+            /* cache the subnet */
+            ip->ip_subnet = ip->ip_addr & ip->ip_mask;
+
+            /* default gateway, if any */
+            if (gw[i]) {
+                struct ipv4_info *ip = &ipv4[i];
+                struct in_addr a;
+                if (!inet_aton(gw[i], &a)) {
+                    ED("not a valid IP address: %s", gw[i]);
+                    usage();
+                }
+                if ((a.s_addr & ip->ip_mask) != ip->ip_subnet) {
+                    ED("gateway %s unreachable", gw[i]);
+                    usage();
+                }
+                ip->ip_gw = a.s_addr;
+            }
+
+            ipv4_dump(ip);
+
+            /* precompute the arp reply for this interface */
+            eh = &ip->arp_reply.arp.eh;
+            ah = &ip->arp_reply.arp.ah;
+            memset(&ip->arp_reply, 0, sizeof(ip->arp_reply));
+            memcpy(eh->ether_shost, ip->ether_addr, 6);
+            eh->ether_type = htons(ETHERTYPE_ARP);
+            ah->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+            ah->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+            ah->ea_hdr.ar_hln = 6;
+            ah->ea_hdr.ar_pln = 4;
+            ah->ea_hdr.ar_op = htons(ARPOP_REPLY);
+            memcpy(ah->arp_sha, ip->ether_addr, 6);
+            memcpy(ah->arp_spa, &ip->ip_addr, 4);
+
+            /* precompute the arp request for this interface */
+            eh = &ip->arp_request.arp.eh;
+            ah = &ip->arp_request.arp.ah;
+            memcpy(&ip->arp_request, &ip->arp_reply,
+                    sizeof(ip->arp_reply));
+            memset(eh->ether_dhost, 0xff, 6);
+            ah->ea_hdr.ar_op = htons(ARPOP_REQUEST);
+
+            /* allocate the arp table */
+            ip->arp_table = arp_table_new(ip->ip_mask);
+            if (ip->arp_table == NULL) {
+                ED("failed to allocate the arp table for %s: %s", ip->name,
+                        strerror(errno));
+                usage();
+            }
+        }
+
+        close(fd);
+#ifdef __FreeBSD__
+        freeifaddrs(ifap);
+#endif /* __FreeBSD__ */
+    }
+
     bp[1] = bp[0]; /* copy parameters, but swap interfaces */
     bp[0].q.prod_ifname = bp[1].q.cons_ifname = ifname[0];
     bp[1].q.prod_ifname = bp[0].q.cons_ifname = ifname[1];
+    bp[0].prod_ipv4 = bp[1].cons_ipv4 = &ipv4[0];
+    bp[0].cons_ipv4 = bp[1].prod_ipv4 = &ipv4[1];
+
 
     /* assign cores. prod and cons work better if on the same HT */
     bp[0].cons_core = cores[0];
@@ -1284,6 +1858,12 @@ main(int argc, char **argv)
         bp[1].q.qsize = 50000;
     }
 
+    /* assign arp command queues for route mode */
+    bp[0].prod_arpq = &arpq[0];
+    bp[0].cons_arpq = &arpq[1];
+    bp[1].prod_arpq = &arpq[1];
+    bp[1].cons_arpq = &arpq[0];
+
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
 

From 808915a8471042f1047a3b95f2819e20683276b8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Mar 2017 12:03:55 +0100
Subject: [PATCH 1719/2207] tlem: pin buffer in memory

---
 apps/tlem/tlem.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 1836533d0..efb671d34 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1328,13 +1328,16 @@ tlem_main(void *_a)
      */
     need *= 3; /* room for descriptors and padding */
 
-    q->buf = calloc(1, need);
-    if (q->buf == NULL) {
+    q->buf = mmap(0, need, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (q->buf == MAP_FAILED) {
         ED("alloc %lld bytes for queue failed, exiting", (long long)need);
         nmport_close(a->pa);
         nmport_close(a->pb);
         return(NULL);
     }
+    if (mlock(q->buf, need) < 0) {
+        ED("(not fatal) failed to pin buffer memory: %s", strerror(errno));
+    }
     q->buflen = need;
     ED("----\n\t%s -> %s :  bps %lld delay %s loss %s queue %lld bytes"
             "\n\tbuffer %llu bytes",

From 78fa94e7a9a76c8c5ed4a7ad441bde432fabaa82 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Mar 2017 13:52:01 +0100
Subject: [PATCH 1720/2207] tlem: optionally drop packets when tx are too late

---
 apps/tlem/tlem.c | 57 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 48 insertions(+), 9 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index efb671d34..e9a4cbaea 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -377,6 +377,7 @@ struct _qs { /* shared queue */
 //	uint64_t	cons_tail;	/* cached copy */
 	uint64_t	cons_now;	/* most recent producer timestamp */
 	uint64_t	cons_lag;	/* tail - head */
+	uint64_t	cons_drop;	/* drop packet count */
 	uint64_t	rx_wait;	/* stats */
 
 	/* shared fields */
@@ -628,6 +629,9 @@ struct pipe_args {
 	struct ipv4_info *cons_ipv4;	/* mac addr etc. */
 	struct ipv4_info *prod_ipv4;	/* mac addr etc. */
 
+	/* max delay before the consumer starts dropping packets */
+	int64_t		max_lag;
+
 	struct _qs	q;
 };
 
@@ -1186,6 +1190,7 @@ cons(void *_pa)
         uint64_t t = q->tail; /* read only once */
         struct q_pkt *p = (struct q_pkt *)(q->buf + h);
         struct arp_cmd *arpc;
+        int64_t delta;
 #if 0
         struct q_pkt *p = (struct q_pkt *)(q->buf + q->head);
         if (p->next < q->head) { /* wrap around prefetch */
@@ -1222,8 +1227,7 @@ cons(void *_pa)
             }
             arpq_release(pa->cons_arpq);
         }
-
-        if (h == t || ts_cmp(p->pt_tx, q->cons_now) > 0) {
+        if ( h == t || (delta = ts_cmp(p->pt_tx, q->cons_now) ) > 0) {
             ND(4, "                 >>>> TXSYNC, pkt not ready yet h %ld t %ld now %ld tx %ld",
                     h, t, q->cons_now, p->pt_tx);
             q->rx_wait++;
@@ -1236,6 +1240,10 @@ cons(void *_pa)
             set_tns_now(&q->cons_now, q->t0);
             continue;
         }
+        if (delta < -pa->max_lag) {
+            q->cons_drop++;
+            goto next;
+        }
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
                 p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
         if (pa->route_mode && !retrying) {
@@ -1253,6 +1261,7 @@ cons(void *_pa)
             ND(5, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld",
                     (int)p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
             ioctl(pa->pb->fd, NIOCTXSYNC, 0);
+            set_tns_now(&q->cons_now, q->t0);
             pending = 0;
             retrying = 1;
             continue;
@@ -1263,10 +1272,11 @@ cons(void *_pa)
             ioctl(pa->pb->fd, NIOCTXSYNC, 0);
             pending = 0;
         }
+
+        q->rx++;
 next:
         q->head = p->next;
         /* drain packets from the queue */
-        q->rx++;
         // XXX barrier
     }
     D("exiting on abort");
@@ -1499,6 +1509,10 @@ add_to(const char ** v, int l, const char *arg, const char *msg)
     *v = arg;
 }
 
+#define U_PARSE_ERR ~(0ULL)
+
+static uint64_t parse_time(const char *arg); // forward
+
 int
 main(int argc, char **argv)
 {
@@ -1507,9 +1521,10 @@ main(int argc, char **argv)
 #define	N_OPTS	2
     struct pipe_args bp[N_OPTS];
     const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS],
-    *gw[N_OPTS];
+    *gw[N_OPTS], *cd[N_OPTS];
     int ncpus;
     int cores[4];
+    uint64_t old_drop0 = 0, old_drop1 = 0, drop0, drop1;
 
     nmctx_set_threadsafe();
 
@@ -1518,6 +1533,7 @@ main(int argc, char **argv)
     bzero(l, sizeof(l));
     bzero(q, sizeof(q));
     bzero(gw, sizeof(gw));
+    bzero(cd, sizeof(cd));
     bzero(ifname, sizeof(ifname));
 
     fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
@@ -1557,8 +1573,9 @@ main(int argc, char **argv)
     // v	verbose
     // b	batch size
     // r	route mode
+    // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:r")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:rd:")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -1630,6 +1647,8 @@ main(int argc, char **argv)
             case 'r':
                 bp[0].route_mode = 1;
                 break;
+            case 'd':
+                add_to(cd, N_OPTS, optarg, "-d too many times");
         }
 
     }
@@ -1836,6 +1855,8 @@ main(int argc, char **argv)
         b[1] = b[0];
     if (l[1] == NULL)
         l[1] = l[0];
+    if (cd[1] == NULL)
+        cd[1] = cd[0];
 
     /* apply commands */
     for (i = 0; i < N_OPTS; i++) { /* once per queue */
@@ -1843,6 +1864,14 @@ main(int argc, char **argv)
         err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
         err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
         err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
+        if (cd[i] != NULL) {
+            unsigned long max_lag = parse_time(cd[i]);
+            if (max_lag == U_PARSE_ERR) {
+                err++;
+            } else {
+                bp[i].max_lag = max_lag;
+            }
+        }
     }
 
     if (q[0] == NULL)
@@ -1861,6 +1890,12 @@ main(int argc, char **argv)
         bp[1].q.qsize = 50000;
     }
 
+    for (i = 0; i < N_OPTS; i++) {
+        if (bp[i].max_lag == 0) {
+            bp[i].max_lag = 100000; /* 100 us */
+        }
+    }
+
     /* assign arp command queues for route mode */
     bp[0].prod_arpq = &arpq[0];
     bp[0].cons_arpq = &arpq[1];
@@ -1877,11 +1912,15 @@ main(int argc, char **argv)
         struct _qs *q0 = &bp[0].q, *q1 = &bp[1].q;
 
         sleep(1);
-        ED("%lld -> %lld maxq %d round %lld, %lld <- %lld maxq %d round %lld",
+        drop0 = q0->cons_drop;
+        drop1 = q1->cons_drop;
+        ED("%lld -> %lld maxq %d round %lld drop %lld, %lld <- %lld maxq %d round %lld drop %lld",
                 (long long)(q0->rx - olda.rx), (long long)(q0->tx - olda.tx),
                 q0->rx_qmax, (long long)q0->prod_max_gap,
+                (long long)(drop0 - old_drop0),
                 (long long)(q1->rx - oldb.rx), (long long)(q1->tx - oldb.tx),
-                q1->rx_qmax, (long long)q1->prod_max_gap
+                q1->rx_qmax, (long long)q1->prod_max_gap,
+                (long long)(drop1 - old_drop1)
           );
         ED("plr nominal %le actual %le",
                 (double)(q0->c_loss.d[0])/(1<<24),
@@ -1891,6 +1930,8 @@ main(int argc, char **argv)
         bp[0].q.prod_max_gap = (bp[0].q.prod_max_gap * 7)/8; // ewma
         bp[1].q.rx_qmax = (bp[1].q.rx_qmax * 7)/8; // ewma
         bp[1].q.prod_max_gap = (bp[1].q.prod_max_gap * 7)/8; // ewma
+        old_drop0 = drop0;
+        old_drop1 = drop1;
     }
     D("exiting on abort");
     sleep(1);
@@ -1952,8 +1993,6 @@ parse_gen(const char *arg, const struct _sm *conv, int *err)
     return d;
 }
 
-#define U_PARSE_ERR ~(0ULL)
-
 /* returns a value in nanoseconds */
 static uint64_t
 parse_time(const char *arg)

From 03fb0a484dfa404e974d9ba9ea9055cec9961f30 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Apr 2017 17:15:43 +0200
Subject: [PATCH 1721/2207] tlem: optionally use hugepages

---
 apps/tlem/tlem.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index e9a4cbaea..6e0fff472 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -166,11 +166,15 @@ static int do_abort = 0;
 #include 	/* sokcaddr_dl */
 #include  /* pthread w/ affinity */
 #include  /* cpu_set */
+#define MAP_HUGETLB 0	/* not supported */
 #endif /* __FreeBSD__ */
 
 #ifdef linux
 #define cpuset_t        cpu_set_t
 #include 
+#ifndef MAP_HUGETLB
+#define MAP_HUGETLB 0x40000
+#endif
 #endif
 
 #ifdef __APPLE__
@@ -612,6 +616,7 @@ struct pipe_args {
 	int		zerocopy;
 	int		wait_link;
 	int		route_mode;
+	int		hugepages;
 
 	pthread_t	cons_tid;	/* main thread */
 	pthread_t	prod_tid;	/* producer thread */
@@ -1283,7 +1288,6 @@ cons(void *_pa)
     return NULL;
 }
 
-
 /*
  * main thread for each direction.
  * Allocates memory for the queues, creates the prod() thread,
@@ -1295,6 +1299,7 @@ tlem_main(void *_a)
     struct pipe_args *a = _a;
     struct _qs *q = &a->q;
     uint64_t need;
+    int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
 
     setaffinity(a->cons_core);
     set_tns_now(&q->t0, 0); /* starting reference */
@@ -1314,6 +1319,11 @@ tlem_main(void *_a)
         nmport_close(a->pa);
         return NULL;
     }
+
+    if (a->hugepages) {
+        mmap_flags |= MAP_HUGETLB;
+    }
+
     a->zerocopy = a->zerocopy && (a->pa->mem == a->pb->mem);
     ND("------- zerocopy %ssupported", a->zerocopy ? "" : "NOT ");
     /* allocate space for the queue:
@@ -1338,7 +1348,7 @@ tlem_main(void *_a)
      */
     need *= 3; /* room for descriptors and padding */
 
-    q->buf = mmap(0, need, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    q->buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
     if (q->buf == MAP_FAILED) {
         ED("alloc %lld bytes for queue failed, exiting", (long long)need);
         nmport_close(a->pa);
@@ -1525,6 +1535,7 @@ main(int argc, char **argv)
     int ncpus;
     int cores[4];
     uint64_t old_drop0 = 0, old_drop1 = 0, drop0, drop1;
+    int hugepages = 0;
 
     nmctx_set_threadsafe();
 
@@ -1575,7 +1586,7 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:rd:")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:rd:H")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -1649,6 +1660,10 @@ main(int argc, char **argv)
                 break;
             case 'd':
                 add_to(cd, N_OPTS, optarg, "-d too many times");
+                break;
+            case 'H':
+                hugepages = 1;
+                break;
         }
 
     }
@@ -1902,6 +1917,17 @@ main(int argc, char **argv)
     bp[1].prod_arpq = &arpq[1];
     bp[1].cons_arpq = &arpq[0];
 
+    /* hugepages */
+    if (hugepages) {
+#ifdef MAP_HUGETLB
+        ED("using hugepages");
+        bp[0].hugepages = bp[1].hugepages = 1;
+#else /* !MAP_HUGETLB */
+        ED("WARNING: hugepages not supported");
+        hugepages = 0;
+#endif /* MAP_HUGETLB */
+    }
+
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
 

From e5814b0565a3e40380a7c2f21e0dbd9e590773a5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 19 Apr 2017 22:43:04 +0200
Subject: [PATCH 1722/2207] tlem: do not continue if any allocation has failed

---
 apps/tlem/tlem.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 6e0fff472..d7e13fd8f 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1304,22 +1304,6 @@ tlem_main(void *_a)
     setaffinity(a->cons_core);
     set_tns_now(&q->t0, 0); /* starting reference */
 
-    a->pa = nmport_prepare(q->prod_ifname);
-    if (a->pa == NULL) {
-        ED("cannot open %s", q->prod_ifname);
-        return NULL;
-    }
-    a->pa->reg.nr_flags |= NETMAP_NO_TX_POLL;
-    if (nmport_open_desc(a->pa) < 0) {
-	ED("cannot open %s", q->prod_ifname);
-    }
-    a->pb = nmport_open(q->cons_ifname);
-    if (a->pb == NULL) {
-        ED("cannot open %s", q->cons_ifname);
-        nmport_close(a->pa);
-        return NULL;
-    }
-
     if (a->hugepages) {
         mmap_flags |= MAP_HUGETLB;
     }
@@ -1928,6 +1912,27 @@ main(int argc, char **argv)
 #endif /* MAP_HUGETLB */
     }
 
+    for (i = 0; i < 2; i++) {
+        struct pipe_args *a = &bp[i];
+
+        a->pa = nmport_prepare(a->q.prod_ifname);
+        if (a->pa == NULL) {
+            ED("cannot open %s", a->q.prod_ifname);
+            exit(1);
+        }
+        a->pa->reg.nr_flags |= NETMAP_NO_TX_POLL;
+        if (nmport_open_desc(a->pa) < 0) {
+            ED("cannot open %s", a->q.prod_ifname);
+	    exit(1);
+        }
+        a->pb = nmport_open(a->q.cons_ifname);
+        if (a->pb == NULL) {
+            ED("cannot open %s", a->q.cons_ifname);
+            exit(1);
+        }
+
+    }
+
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
 

From b1aa0ff72dba83c37bf1b4584f6d792343538b5a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 9 Feb 2018 17:40:52 +0100
Subject: [PATCH 1723/2207] tlem: output stats to mmap()ed file

---
 apps/tlem/tlem.c | 121 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 93 insertions(+), 28 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index d7e13fd8f..bac0edbe1 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -135,11 +135,14 @@ prod()
 
 #define _GNU_SOURCE	// for CPU_SET() etc
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 
 
@@ -297,6 +300,13 @@ pointer, prod_tail_1, used to check for expired packets. This is done lazily.
 
 #define ALIGN_CACHE	__attribute__ ((aligned (MY_CACHELINE)))
 
+struct stats {
+	uint64_t	packets;
+	uint64_t	bytes;
+	uint64_t	drop_packets;
+	uint64_t	drop_bytes;
+} ALIGN_CACHE;
+
 struct _qs { /* shared queue */
 	uint64_t	t0;	/* start of times */
 
@@ -314,14 +324,13 @@ struct _qs { /* shared queue */
 	struct _cfg	c_loss;
 
 	/* producer's fields */
-	uint64_t	tx ALIGN_CACHE;	/* tx counter */
-	uint64_t	prod_tail_1;	/* head of queue */
+	uint64_t	prod_tail_1 ALIGN_CACHE; /* head of queue */
 	uint64_t	prod_queued;	/* queued bytes */
 	uint64_t	prod_head;	/* cached copy */
 	uint64_t	prod_tail;	/* cached copy */
 	uint64_t	prod_now;	/* most recent producer timestamp */
-	uint64_t	prod_drop;	/* drop packet count */
 	uint64_t	prod_max_gap;	/* rx round duration */
+	struct stats	_txstats, *txstats;
 
 	/* parameters for reading from the netmap port */
 	struct nmport_d *src_port;		/* netmap descriptor */
@@ -375,14 +384,13 @@ struct _qs { /* shared queue */
 
 
 	/* consumer's fields */
-	const char *		cons_ifname;
-	uint64_t rx ALIGN_CACHE;	/* rx counter */
 //	uint64_t	cons_head;	/* cached copy */
 //	uint64_t	cons_tail;	/* cached copy */
-	uint64_t	cons_now;	/* most recent producer timestamp */
+	uint64_t	cons_now ALIGN_CACHE;	/* most recent producer timestamp */
 	uint64_t	cons_lag;	/* tail - head */
-	uint64_t	cons_drop;	/* drop packet count */
 	uint64_t	rx_wait;	/* stats */
+	const char *	cons_ifname;
+	struct stats	_rxstats, *rxstats;
 
 	/* shared fields */
 	volatile uint64_t tail ALIGN_CACHE ;	/* producer writes here */
@@ -611,7 +619,6 @@ ipv4_dump(const struct ipv4_info *i)
 
 struct ipv4_info ipv4[2];
 
-
 struct pipe_args {
 	int		zerocopy;
 	int		wait_link;
@@ -634,6 +641,9 @@ struct pipe_args {
 	struct ipv4_info *cons_ipv4;	/* mac addr etc. */
 	struct ipv4_info *prod_ipv4;	/* mac addr etc. */
 
+	/* raw stats */
+	struct stats	*stats;
+
 	/* max delay before the consumer starts dropping packets */
 	int64_t		max_lag;
 
@@ -771,9 +781,8 @@ no_room(struct _qs *q)
     if (q->prod_queued > q->qsize) {
         q_reclaim(q);
         if (q->prod_queued > q->qsize) {
-            q->prod_drop++;
             RD(1, "too many bytes queued %llu, drop %llu",
-                    (unsigned long long)q->prod_queued, (unsigned long long)q->prod_drop);
+                    (unsigned long long)q->prod_queued, (unsigned long long)q->txstats->drop_packets);
             return 1;
         }
     }
@@ -810,7 +819,6 @@ enq(struct _qs *q)
             q->cur_len, (int)q->prod_tail, p->next,
             p->pt_qout, p->pt_tx);
     q->prod_tail = p->next;
-    q->tx++;
     if (q->max_bps)
         q->prod_queued += p->pktlen;
     /* XXX update timestamps ? */
@@ -1046,26 +1054,37 @@ prod(void *_pa)
                 continue;
             }
             q->c_loss.run(q, &q->c_loss);
-            if (q->cur_drop)
+            if (q->cur_drop) {
+                q->txstats->drop_packets++;
+                q->txstats->drop_bytes += q->cur_len;
                 continue;
+            }
             if (no_room(q)) {
                 q->tail = q->prod_tail; /* notify */
                 usleep(1); // XXX give cons a chance to run ?
-                if (no_room(q)) /* try to run drop-free once */
+                if (no_room(q)) {/* try to run drop-free once */
+                    q->txstats->drop_packets++;
+                    q->txstats->drop_bytes += q->cur_len;
                     continue;
+                }
             }
             // XXX possibly implement c_tt for transmission time emulation
             q->c_bw.run(q, &q->c_bw);
             tt = q->cur_tt;
             q->qt_qout += tt;
-            if (drop_after(q))
+            if (drop_after(q)) {
+                q->txstats->drop_packets++;
+                q->txstats->drop_bytes += q->cur_len;
                 continue;
+            }
             q->c_delay.run(q, &q->c_delay); /* compute delay */
             t_tx = q->qt_qout + q->cur_delay;
             ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
             /* insure no reordering and spacing by transmission time */
             q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt;
             enq(q);
+            q->txstats->packets++;
+            q->txstats->bytes += q->cur_len;
         }
         q->tail = q->prod_tail; /* notify */
     }
@@ -1246,7 +1265,8 @@ cons(void *_pa)
             continue;
         }
         if (delta < -pa->max_lag) {
-            q->cons_drop++;
+            q->rxstats->drop_packets++;
+            q->rxstats->drop_bytes += p->pktlen;
             goto next;
         }
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
@@ -1257,6 +1277,7 @@ cons(void *_pa)
                 /* drop this packet. Any pending arp message
                  * will be sent in the next iteration
                  */
+                q->rxstats->drop_packets++;
                 goto next;
             }
             pending += injected;
@@ -1278,7 +1299,8 @@ cons(void *_pa)
             pending = 0;
         }
 
-        q->rx++;
+        q->rxstats->packets++;
+        q->rxstats->bytes += p->pktlen;
 next:
         q->head = p->next;
         /* drain packets from the queue */
@@ -1518,8 +1540,10 @@ main(int argc, char **argv)
     *gw[N_OPTS], *cd[N_OPTS];
     int ncpus;
     int cores[4];
-    uint64_t old_drop0 = 0, old_drop1 = 0, drop0, drop1;
     int hugepages = 0;
+    char *statsfname = NULL;
+    int statsfd;
+    struct stats *stats = NULL;
 
     nmctx_set_threadsafe();
 
@@ -1570,7 +1594,7 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:rd:H")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:rd:Hs:")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -1648,8 +1672,18 @@ main(int argc, char **argv)
             case 'H':
                 hugepages = 1;
                 break;
+            case 's':
+                if (statsfname != NULL) {
+                    D("option 's' duplicated");
+                    usage();
+                }
+                statsfname = strdup(optarg);
+                if (statsfname == NULL) {
+                    D("out of memory");
+                    exit(1);
+                }
+                break;
         }
-
     }
 
     argc -= optind;
@@ -1933,25 +1967,58 @@ main(int argc, char **argv)
 
     }
 
+    if (statsfname != NULL) {
+        size_t statsz = 4 * sizeof(struct stats);
+        statsfd = open(statsfname, O_RDWR | O_CREAT, 0666);
+        if (statsfd < 0) {
+            D("cannot open %s: %s", statsfname, strerror(errno));
+            exit(1);
+        }
+        if (ftruncate(statsfd, statsz) < 0) {
+            D("cannot truncate(%s, %zu): %s",
+                    statsfname, statsz, strerror(errno));
+            exit(1);
+        }
+        stats = mmap(NULL, statsz,
+                PROT_READ | PROT_WRITE,
+                MAP_SHARED, statsfd, 0);
+        if (stats == MAP_FAILED) {
+            D("cannot mmap %s: %s", statsfname, strerror(errno));
+            exit(1);
+        }
+        bp[0].q.txstats = stats;
+        bp[0].q.rxstats = stats + 1;
+        bp[1].q.txstats = stats + 2;
+        bp[1].q.rxstats = stats + 3;
+    } else {
+        bp[0].q.txstats = &bp[0].q._txstats;
+        bp[0].q.rxstats = &bp[0].q._rxstats;
+        bp[1].q.txstats = &bp[1].q._txstats;
+        bp[1].q.rxstats = &bp[1].q._rxstats;
+    }
+
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
 
     signal(SIGINT, sigint_h);
     sleep(1);
     while (!do_abort) {
-        struct _qs olda = bp[0].q, oldb = bp[1].q;
+        struct stats old0tx = *bp[0].q.txstats,
+                     old0rx = *bp[0].q.rxstats,
+                     old1tx = *bp[1].q.txstats,
+                     old1rx = *bp[1].q.rxstats;
         struct _qs *q0 = &bp[0].q, *q1 = &bp[1].q;
 
         sleep(1);
-        drop0 = q0->cons_drop;
-        drop1 = q1->cons_drop;
         ED("%lld -> %lld maxq %d round %lld drop %lld, %lld <- %lld maxq %d round %lld drop %lld",
-                (long long)(q0->rx - olda.rx), (long long)(q0->tx - olda.tx),
+                (long long)(q0->rxstats->packets - old0rx.packets),
+                (long long)(q0->txstats->packets - old0tx.packets),
                 q0->rx_qmax, (long long)q0->prod_max_gap,
-                (long long)(drop0 - old_drop0),
-                (long long)(q1->rx - oldb.rx), (long long)(q1->tx - oldb.tx),
+                (long long)(q0->rxstats->drop_packets - old0rx.drop_packets),
+                (long long)(q1->rxstats->packets - old1rx.packets),
+                (long long)(q1->txstats->packets - old1tx.packets),
                 q1->rx_qmax, (long long)q1->prod_max_gap,
-                (long long)(drop1 - old_drop1)
+                (long long)(q1->rxstats->drop_packets - old1rx.drop_packets)
           );
         ED("plr nominal %le actual %le",
                 (double)(q0->c_loss.d[0])/(1<<24),
@@ -1961,8 +2028,6 @@ main(int argc, char **argv)
         bp[0].q.prod_max_gap = (bp[0].q.prod_max_gap * 7)/8; // ewma
         bp[1].q.rx_qmax = (bp[1].q.rx_qmax * 7)/8; // ewma
         bp[1].q.prod_max_gap = (bp[1].q.prod_max_gap * 7)/8; // ewma
-        old_drop0 = drop0;
-        old_drop1 = drop1;
     }
     D("exiting on abort");
     sleep(1);

From 7f38d0d2f5e551e852a525ddfc20ef4aa495bd98 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 15 Mar 2018 17:33:34 +0100
Subject: [PATCH 1724/2207] tlem: packet reordering

---
 apps/tlem/tlem.8 |  13 +-
 apps/tlem/tlem.c | 301 ++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 270 insertions(+), 44 deletions(-)

diff --git a/apps/tlem/tlem.8 b/apps/tlem/tlem.8
index 495f1d251..14ce43461 100644
--- a/apps/tlem/tlem.8
+++ b/apps/tlem/tlem.8
@@ -38,6 +38,7 @@
 .Op Fl B Ar bandwidth
 .Op Fl D Ar delay
 .Op Fl L Ar loss
+.Op Fl R Ar reordering
 .Op Fl Q Ar queue size
 .Op Fl C Ar cpu-placement
 .Op Fl G Ar gateway
@@ -45,6 +46,7 @@
 .Op Fl w Ar wait-link
 .Op Fl v
 .Op Fl r
+.El
 .Sh DESCRIPTION
 .Nm
 implements a high speed bidirectional link emulator between netmap ports,
@@ -119,6 +121,14 @@ Optional packet or bit error rate, defaults to 0.
 Simulates packet or bit errors, causing offending packets to be dropped.
 .Ar x
 is a floating point number indicating the packet or bit error rate.
+.It Fl R Cm const, Ns Ar p, Ns Ar t
+Optional packet reordering, defaults to none.
+With probability
+.Ar p
+incoming packets are hold for the given
+.Ar t
+amount of time. The probability and time are expressed as in
+the loss and delay arguments.
 .It Fl Q Ar size
 Queue size,
 .Ar size
@@ -170,7 +180,7 @@ replying to and sending the necessary ARP messages and updating
 the destination MAC addresses. The IP addresses and subnets are
 obtained from the ports, so this mode cannot be used with
 software-only netmap ports like ephemeral VALE ports and pipes.
-
+.Pp
 There are some limitations: unresolved destinations are sent as broadcasts
 until resolution; packets destined to the same subnet as their incoming
 port are dropped; TTL is not decremented.  Each subnet may also optionally
@@ -184,7 +194,6 @@ is in the order of 30-50us provided that C states higher than C1
 are disabled, and the CPU clock is set to the maximum speed.
 Performance depends heavily on memory speed and suitable
 NICs with native netmap drivers. See the paper below for more details.
-of good network interf
 .Sh SEE ALSO
 .Pa http://info.iet.unipi.it/~luigi/netmap/
 .Pp
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index bac0edbe1..1808e795e 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -88,7 +88,7 @@ prod()
 			in nanoseconds. A batch of packets may
 			have the same value q->prod_now
 
-    Four functions are then called in sequence:
+    Five functions are then called in sequence:
 
     q->c_loss (set with the -L command line option) decides
     	whether the packet should be dropped before even queuing.
@@ -96,6 +96,12 @@ prod()
 	The function is supposed to set q->c_drop = 1 if the
 	packet should be dropped, or leave it to 0 otherwise.
 
+    q-c_reorder (set with the -R command line option) decides
+        whether the packet should be temporary hold to emulate
+	packet reordering. To hold a packet, it shuld set
+	q->cur_hold_delay to a non-zero value. The packet will
+	reenter the stream once the cur_hold_delay has expired.
+
     no_room (not configurable) checks whether there is space
     	in the queue, enforcing both the queue size set with -Q
 	and the space allocated for the delay line.
@@ -289,6 +295,15 @@ To simulate bandwidth limitations efficiently, the producer has a second
 pointer, prod_tail_1, used to check for expired packets. This is done lazily.
 
  */
+
+/* for packets hold for reorderind we only record their size and
+ * hold time.
+ */
+struct h_pkt {
+	uint64_t	pktlen;
+	uint64_t	releasetime;
+};
+
 /*
  * When sizing the buffer, we must assume some value for the bandwidth.
  * INFINITE_BW is supposed to be faster than what we support
@@ -305,6 +320,8 @@ struct stats {
 	uint64_t	bytes;
 	uint64_t	drop_packets;
 	uint64_t	drop_bytes;
+	uint64_t	reorder_packets;
+	uint64_t	reorder_bytes;
 } ALIGN_CACHE;
 
 struct _qs { /* shared queue */
@@ -316,12 +333,14 @@ struct _qs { /* shared queue */
 	/* the queue has at least 1 empty position */
 	uint64_t	max_bps;	/* bits per second */
 	uint64_t	max_delay;	/* nanoseconds */
+	uint64_t	max_hold_delay; /* nanoseconds */
 	uint64_t	qsize;	/* queue size in bytes */
 
 	/* handlers for various options */
 	struct _cfg	c_delay;
 	struct _cfg	c_bw;
 	struct _cfg	c_loss;
+	struct _cfg	c_reorder;
 
 	/* producer's fields */
 	uint64_t	prod_tail_1 ALIGN_CACHE; /* head of queue */
@@ -382,6 +401,15 @@ struct _qs { /* shared queue */
 		 * bumps the output time as needed.
 		 */
 
+	/* producers's fields for reordering */
+	uint64_t	cur_hold_delay; /* reordering delay (ns) from c_reorder.run() */
+	uint64_t	hold_tail, hold_head; /* pointers in the reorder queue */
+	char	       *hold_buf;	/* the reorder queue */
+	uint64_t	hold_buflen;	/* and its size */
+	uint64_t	hold_next_rt;	/* release time of the first hold packet */
+	uint64_t	hold_tail_rt;	/* release time of the last hold packet */
+	int		hold_release;   /* there are packets ready to be released */
+
 
 	/* consumer's fields */
 //	uint64_t	cons_head;	/* cached copy */
@@ -826,7 +854,7 @@ enq(struct _qs *q)
 }
 
 
-int
+static int
 rx_queued(struct nmport_d *d)
 {
     u_int tot = 0, i;
@@ -840,6 +868,18 @@ rx_queued(struct nmport_d *d)
     return tot;
 }
 
+static inline int
+hold_update_release(struct _qs *q)
+{
+    if (q->hold_release)
+        return 1;
+    if (q->hold_next_rt && ts_cmp(q->hold_next_rt, q->prod_now) <= 0) {
+        q->hold_release = 1;
+        return 1;
+    }
+    return 0;
+}
+
 /*
  * wait for packets, then compute a timestamp in 64-bit ns
  */
@@ -851,7 +891,8 @@ wait_for_packets(struct _qs *q)
 
     ioctl(q->src_port->fd, NIOCRXSYNC, 0); /* forced */
     while (!do_abort) {
-
+        if (hold_update_release(q))
+            break;
         n0 = rx_queued(q->src_port);
         if (n0 > (int)q->rx_qmax) {
             q->rx_qmax = n0;
@@ -862,6 +903,7 @@ wait_for_packets(struct _qs *q)
         if (1) {
             usleep(5);
             ioctl(q->src_port->fd, NIOCRXSYNC, 0);
+            set_tns_now(&q->prod_now, q->t0);
         } else {
             struct pollfd pfd;
             struct netmap_ring *rx;
@@ -972,6 +1014,65 @@ scan_ring(struct _qs *q, int next /* bool */)
     ND(10, "-------- slot %d tail %d len %d buf %p", rxr->cur, rxr->tail, q->cur_len, q->cur_pkt);
 }
 
+/*
+ * Packet reordering.
+ *
+ * Packets subject to reordering are hold in a separate FIFO queue,
+ * local to the producer thread. Note that cur_hold_delay may then be
+ * increased to make sure that no further reording is necessary
+ * in the FIFO.
+ *
+ * Once out of the queue, the hold packets reenter the stream
+ * and go through the normal processing.
+ */
+
+static inline void
+reorder_hold(struct _qs *q)
+{
+    struct h_pkt *nh;
+
+    nh = (struct h_pkt *)(q->hold_buf + q->hold_tail);
+    nm_pkt_copy(q->cur_pkt, (char *)(nh + 1), q->cur_len);
+    nh->pktlen = q->cur_len;
+    nh->releasetime = q->cur_hold_delay;
+    if (!q->hold_next_rt) {
+        q->hold_next_rt = nh->releasetime;
+    } else {
+        /* not empty, prevent further reordering */
+        if (nh->releasetime < q->hold_tail_rt)
+            nh->releasetime = q->hold_tail_rt;
+    }
+    q->hold_tail_rt = nh->releasetime;
+    q->hold_tail += sizeof(*nh) + nh->pktlen;
+    if (unlikely(q->hold_tail >= q->hold_buflen))
+        q->hold_tail = 0;
+}
+
+static int
+reorder_release(struct _qs *q)
+{
+    struct h_pkt *h;
+    if (!q->hold_release)
+        return 0;
+    h = (struct h_pkt *)(q->hold_buf + q->hold_head);
+    q->cur_pkt = q->hold_buf + q->hold_head + sizeof(*h);
+    q->cur_len = h->pktlen;
+    q->hold_head += sizeof(*h) + q->cur_len;
+    if (unlikely(q->hold_head >= q->hold_buflen))
+        q->hold_head = 0;
+    q->hold_release = 0;
+    if (q->hold_head != q->hold_tail) {
+        h = (struct h_pkt *)(q->hold_buf + q->hold_head);
+        q->hold_next_rt = h->releasetime;
+        if (ts_cmp(q->hold_next_rt, q->prod_now) < 0)
+            q->hold_release = 1;
+    } else {
+        q->hold_next_rt = 0;
+    }
+    return 1;
+}
+
+
 /*
  * simple handler for parameters not supplied
  */
@@ -1024,6 +1125,45 @@ prod_push_arp(const struct pipe_args *pa, const void *pkt)
     arpq_push(a, c);
 }
 
+static void
+prod_procpkt(struct _qs *q)
+{
+    uint64_t t_tx, tt;	/* output and transmission time */
+
+    q->c_loss.run(q, &q->c_loss);
+    if (q->cur_drop) {
+        q->txstats->drop_packets++;
+        q->txstats->drop_bytes += q->cur_len;
+        return;
+    }
+    if (no_room(q)) {
+        q->tail = q->prod_tail; /* notify */
+        usleep(1); // XXX give cons a chance to run ?
+        if (no_room(q)) {/* try to run drop-free once */
+            q->txstats->drop_packets++;
+            q->txstats->drop_bytes += q->cur_len;
+            return;
+        }
+    }
+    // XXX possibly implement c_tt for transmission time emulation
+    q->c_bw.run(q, &q->c_bw);
+    tt = q->cur_tt;
+    q->qt_qout += tt;
+    if (drop_after(q)) {
+        q->txstats->drop_packets++;
+        q->txstats->drop_bytes += q->cur_len;
+        return;
+    }
+    q->c_delay.run(q, &q->c_delay); /* compute delay */
+    t_tx = q->qt_qout + q->cur_delay;
+    ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
+    /* insure no reordering and spacing by transmission time */
+    q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt;
+    enq(q);
+    q->txstats->packets++;
+    q->txstats->bytes += q->cur_len;
+}
+
 static void *
 prod(void *_pa)
 {
@@ -1038,12 +1178,13 @@ prod(void *_pa)
         int count;
 
         wait_for_packets(q);	/* also updates prod_now */
+
+        for (count = 0; count < q->burst && reorder_release(q); count++) {
+            prod_procpkt(q);
+        }
         // XXX optimize to flush frequently
-        for (count = 0, scan_ring(q, 0); count < q->burst && !nm_ring_empty(q->rxring);
+        for (scan_ring(q, 0); count < q->burst && !nm_ring_empty(q->rxring);
                 count++, scan_ring(q, 1)) {
-            // transmission time
-            uint64_t t_tx, tt;	/* output and transmission time */
-
             if (q->cur_len < 60) {
                 RD(5, "short packet len %d", q->cur_len);
                 continue; // short frame
@@ -1053,38 +1194,15 @@ prod(void *_pa)
                 prod_push_arp(pa, q->cur_pkt);
                 continue;
             }
-            q->c_loss.run(q, &q->c_loss);
-            if (q->cur_drop) {
-                q->txstats->drop_packets++;
-                q->txstats->drop_bytes += q->cur_len;
+            q->c_reorder.run(q, &q->c_reorder);
+            if (q->cur_hold_delay) {
+                q->cur_hold_delay += q->prod_now;
+                q->txstats->reorder_packets++;
+                q->txstats->reorder_bytes += q->cur_len;
+                reorder_hold(q);
                 continue;
             }
-            if (no_room(q)) {
-                q->tail = q->prod_tail; /* notify */
-                usleep(1); // XXX give cons a chance to run ?
-                if (no_room(q)) {/* try to run drop-free once */
-                    q->txstats->drop_packets++;
-                    q->txstats->drop_bytes += q->cur_len;
-                    continue;
-                }
-            }
-            // XXX possibly implement c_tt for transmission time emulation
-            q->c_bw.run(q, &q->c_bw);
-            tt = q->cur_tt;
-            q->qt_qout += tt;
-            if (drop_after(q)) {
-                q->txstats->drop_packets++;
-                q->txstats->drop_bytes += q->cur_len;
-                continue;
-            }
-            q->c_delay.run(q, &q->c_delay); /* compute delay */
-            t_tx = q->qt_qout + q->cur_delay;
-            ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
-            /* insure no reordering and spacing by transmission time */
-            q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt;
-            enq(q);
-            q->txstats->packets++;
-            q->txstats->bytes += q->cur_len;
+            prod_procpkt(q);
         }
         q->tail = q->prod_tail; /* notify */
     }
@@ -1365,11 +1483,41 @@ tlem_main(void *_a)
         ED("(not fatal) failed to pin buffer memory: %s", strerror(errno));
     }
     q->buflen = need;
+
+    /* Now we allocate the hold buffer for reordering, if needed.  Since this
+     * is accessed from only one thread (the producer), there are no caching
+     * issues and no need for padding.  The header is only 8 bytes, so the
+     * worst case overhead (all minimally sized packets) is 8/64;
+     */
+    if (q->max_hold_delay) {
+        need = q->max_bps ? q->max_bps : INFINITE_BW;
+        need *= q->max_hold_delay + 1000000;
+        need /= TIME_UNITS;
+        need /= 8;
+        need *= (1 + 1.0*sizeof(struct h_pkt)/64);
+        need += 3 * MAX_PKT;
+
+        q->hold_buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
+        if (q->hold_buf == MAP_FAILED) {
+            ED("alloc %lld bytes for  failed, exiting", (long long)need);
+            nmport_close(a->pa);
+            nmport_close(a->pb);
+            do_abort = 1;
+            return(NULL);
+        }
+        if (mlock(q->hold_buf, need) < 0) {
+            ED("(not fatal) failed to pin hold buffer memory: %s", strerror(errno));
+        }
+        q->hold_buflen = need - (sizeof(struct h_pkt) + MAX_PKT);
+    }
+
     ED("----\n\t%s -> %s :  bps %lld delay %s loss %s queue %lld bytes"
-            "\n\tbuffer %llu bytes",
+            "\n\tbuffer   %10llu bytes\n\thold-buf %10lld bytes",
             q->prod_ifname, q->cons_ifname,
             (long long)q->max_bps, q->c_delay.optarg, q->c_loss.optarg,
-            (long long)q->qsize, (unsigned long long)q->buflen);
+            (long long)q->qsize, (unsigned long long)q->buflen,
+            (unsigned long long)q->hold_buflen);
+
 
     q->src_port = a->pa;
 
@@ -1504,6 +1652,7 @@ cmd_apply(const struct _cfg *a, const char *arg, struct _qs *q, struct _cfg *dst
 static struct _cfg delay_cfg[];
 static struct _cfg bw_cfg[];
 static struct _cfg loss_cfg[];
+static struct _cfg reorder_cfg[];
 
 static uint64_t parse_bw(const char *arg);
 static uint64_t parse_qsize(const char *arg);
@@ -1536,8 +1685,8 @@ main(int argc, char **argv)
 
 #define	N_OPTS	2
     struct pipe_args bp[N_OPTS];
-    const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS],
-    *gw[N_OPTS], *cd[N_OPTS];
+    const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *r[N_OPTS],
+    *ifname[N_OPTS], *gw[N_OPTS], *cd[N_OPTS];
     int ncpus;
     int cores[4];
     int hugepages = 0;
@@ -1551,6 +1700,7 @@ main(int argc, char **argv)
     bzero(b, sizeof(b));
     bzero(l, sizeof(l));
     bzero(q, sizeof(q));
+    bzero(r, sizeof(r));
     bzero(gw, sizeof(gw));
     bzero(cd, sizeof(cd));
     bzero(ifname, sizeof(ifname));
@@ -1567,6 +1717,8 @@ main(int argc, char **argv)
         q->c_loss.run = null_run_fn;
         q->c_bw.optarg = "0";
         q->c_bw.run = null_run_fn;
+        q->c_reorder.optarg = "0";
+        q->c_reorder.run = null_run_fn;
     }
 
     ncpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -1588,13 +1740,14 @@ main(int argc, char **argv)
     // D	delay in seconds
     // Q	qsize in bytes
     // L	loss probability
+    // R	reordering probability and delay min/max
     // i	interface name (two mandatory)
     // v	verbose
     // b	batch size
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:Q:G:b:ci:vw:rd:Hs:")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:b:ci:vw:rd:Hs:")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -1644,6 +1797,9 @@ main(int argc, char **argv)
             case 'L': /* loss probability */
                 add_to(l, N_OPTS, optarg, "-L too many times");
                 break;
+            case 'R': /* reordering */
+                add_to(r, N_OPTS, optarg, "-R too many times");
+                break;
             case 'G': /* default gateway */
                 add_to(gw, N_OPTS, optarg, "-G too many times");
                 break;
@@ -1890,6 +2046,8 @@ main(int argc, char **argv)
         l[1] = l[0];
     if (cd[1] == NULL)
         cd[1] = cd[0];
+    if (r[1] == NULL)
+        r[1] = r[0];
 
     /* apply commands */
     for (i = 0; i < N_OPTS; i++) { /* once per queue */
@@ -1897,6 +2055,7 @@ main(int argc, char **argv)
         err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
         err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
         err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
+        err += cmd_apply(reorder_cfg, r[i], q, &q->c_reorder);
         if (cd[i] != NULL) {
             unsigned long max_lag = parse_time(cd[i]);
             if (max_lag == U_PARSE_ERR) {
@@ -2261,6 +2420,20 @@ BANDWIDTH emulation	-B option_arguments
     ether,b		constant bw, including ethernet framing
 			(20 bytes framing + 4 bytes crc)
 
+REORDERING emulation 	-R option_arguments
+
+    NOTE: The config function should store, in q->max_hold_delay,
+    a reasonable estimate of the maximum hold delay applied to the packets
+    as this is needed to size the memory buffer used to hold reordered
+    packets.
+
+    If the option is not supplied, the system does not reorder packets.
+
+    Currently implemented options
+
+    const,p,t		hold packets for t ns, with probability t
+
+
 #endif /* end of comment block */
 
 /*
@@ -2566,3 +2739,47 @@ static struct _cfg loss_cfg[] = {
 		"ber,prob # 0 <= prob <= 1", TLEM_CFG_END },
 	{ NULL, NULL, NULL, TLEM_CFG_END }
 };
+
+
+/*
+ * reordering
+ */
+static int
+const_reorder_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
+{
+    double prob;
+    uint64_t delay;
+    int err;
+
+    (void)q;
+    if (strcmp(av[0], "const") != 0 && ac > 2)
+        return 2; /* not recognized */
+    if (ac > 3)
+        return 1; /* error */
+    prob = parse_gen(av[ac - 2], NULL, &err);
+    if (err || prob < 0 || prob > 1)
+        return 1;
+    dst->d[0] = prob * (1<<24);
+    if (prob != 0 && dst->d[0] == 0)
+        ED("WWW warning,  rounding %le down to 0", prob);
+    delay = parse_time(av[ac - 1]);
+    if (delay == U_PARSE_ERR)
+        return 1;
+    dst->d[1] = delay;
+    q->max_hold_delay = delay;
+    return 0;
+}
+
+static int
+const_reorder_run(struct _qs *q, struct _cfg *arg)
+{
+    uint64_t r = my_random24();
+    q->cur_hold_delay = (r < arg->d[0] ? arg->d[1] : 0);
+    return 0;
+}
+
+static struct _cfg reorder_cfg[] = {
+	{ const_reorder_parse, const_reorder_run,
+		"const,prob,delay # 0 <= prob <= 1", TLEM_CFG_END },
+	{ NULL, NULL, NULL, TLEM_CFG_END }
+};

From de6847b5a02621f667c09d9d03662d355ec862fe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 7 Apr 2018 12:26:44 +0200
Subject: [PATCH 1725/2207] tlem: dynamic emulation parameters

TLEM may now be used in a client-server configuration:

server: tlem -l  -i port1 -i port2 [other args]
client  tlem -t  [config args]

If using the same , the client will pass the new
[config args] to the corresponing server.

Advisory locks are used auto-detect whether tlem should run as server or
client, and to protect concurrent updates from several clients.

Limitations: the new max-delay and bandwidth can only be lower
than the original ones passed to the server, since these are
used to compute the size of the queue, which is not reallocated
on configuration change. The -M option can be used the pre-set
the maximum values.
---
 apps/tlem/tlem.c | 991 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 692 insertions(+), 299 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 1808e795e..ecf712553 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -50,7 +50,7 @@ The producer can either wait for traffic using a blocking poll(),
 or periodically check the input around short usleep().
 The latter mechanism is the preferred one as it allows a controlled
 latency with a low interrupt load and a modest system load.
-
+/
 The queue is sized so that overflows can occur only if the consumer
 is severely backlogged, hence the only appropriate option is drop
 traffic rather than wait for space.  The case of an empty queue is
@@ -158,6 +158,7 @@ static int do_abort = 0;
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -214,6 +215,25 @@ static inline void CPU_SET(uint32_t i, cpuset_t *p)
 #define	_P64	uint64_t
 #endif /* print stuff */
 
+#define	MY_CACHELINE	(128ULL)
+#define ALIGN_CACHE	__attribute__ ((aligned (MY_CACHELINE)))
+
+struct stats {
+	uint64_t	packets;
+	uint64_t	bytes;
+	uint64_t	drop_packets;
+	uint64_t	drop_bytes;
+	uint64_t	reorder_packets;
+	uint64_t	reorder_bytes;
+} ALIGN_CACHE;
+
+/* external configuration for each impairment (bw, delay, loss, reorder, ...) */
+struct _ec {
+        uint8_t         ec_valid;       /* 1 iff the other fields are valid */
+        uint8_t         ec_index;       /* impairment sub-type */
+        uint16_t        ec_datasz;      /* size of the parameters */
+        uint32_t        ec_dataoff;     /* offset of the parameters */
+};
 
 struct _qs;	/* forward */
 /*
@@ -230,10 +250,51 @@ struct _cfg {
 
     const char *optarg;	/* command line argument. Initial value is the error message */
     /* placeholders for common values */
-    void *arg;		/* allocated memory if any */
-    int arg_len;	/* size of *arg in case a realloc is needed */
-    uint64_t d[16];	/* static storage for simple cases */
+    void *arg;		/* allocated memory */
+    struct _ec *ec;     /* external configuration */
+};
+
+
+/* configuration instance. There may be one or more of these
+ * for direction. One of them is the active one, currently
+ * used by the server. Clients prepare an instance not in use,
+ * then make it active when ready.
+ */
+struct _eci {
+        struct _ec      ec_delay;
+        struct _ec      ec_bw;
+        struct _ec      ec_loss;
+        struct _ec      ec_reorder;
+#define EC_DATASZ       (1U << 14)
+        char            ec_data[EC_DATASZ];
+};
+
+/* set of configuration instances. One set per direction */
+struct _ecs {
+        /* fields only written by the server */
+	uint64_t	max_bps;	/* bits per second */
+	uint64_t	max_delay;	/* nanoseconds */
+	uint64_t	max_hold_delay; /* nanoseconds */
+        /* fields written by the server on startup, and then by
+         * the clients in mutual exclusion among themselves.
+         * The communication among the clients and the server
+         * is lockless, and based on ordered updates to the
+         * active field.
+         */
+        volatile uint64_t active; /* active configuration instance */
+#define EC_NINST      2
+        struct _eci    instances[EC_NINST];
+};
+
+/* contents of the external configuration */
+struct _ecf {
+#define EC_NOPTS      2
+	struct stats	stats[2 * EC_NOPTS];
+        uint32_t        version;
+#define EC_VERSION    1
+        struct _ecs     sets[EC_NOPTS];
 };
+#define EC_HDRSZ (offsetof(struct _ecf, sets))
 
 /*
  *
@@ -309,31 +370,19 @@ struct h_pkt {
  * INFINITE_BW is supposed to be faster than what we support
  */
 #define INFINITE_BW	(200ULL*1000000*1000)
-#define	MY_CACHELINE	(128ULL)
 #define PKT_PAD		(32)	/* padding on packets */
 #define MAX_PKT		(9200)	/* max packet size */
 
-#define ALIGN_CACHE	__attribute__ ((aligned (MY_CACHELINE)))
-
-struct stats {
-	uint64_t	packets;
-	uint64_t	bytes;
-	uint64_t	drop_packets;
-	uint64_t	drop_bytes;
-	uint64_t	reorder_packets;
-	uint64_t	reorder_bytes;
-} ALIGN_CACHE;
-
 struct _qs { /* shared queue */
 	uint64_t	t0;	/* start of times */
 
 	uint64_t 	buflen;	/* queue length */
 	char *buf;
 
+        struct _ecs    *ec;             /* external configuration set */
+        uint32_t        ec_active;      /* active instance in the set */
+        size_t          ec_nta[EC_NINST]; /* allocated byes in each instance */
 	/* the queue has at least 1 empty position */
-	uint64_t	max_bps;	/* bits per second */
-	uint64_t	max_delay;	/* nanoseconds */
-	uint64_t	max_hold_delay; /* nanoseconds */
 	uint64_t	qsize;	/* queue size in bytes */
 
 	/* handlers for various options */
@@ -349,7 +398,7 @@ struct _qs { /* shared queue */
 	uint64_t	prod_tail;	/* cached copy */
 	uint64_t	prod_now;	/* most recent producer timestamp */
 	uint64_t	prod_max_gap;	/* rx round duration */
-	struct stats	_txstats, *txstats;
+	struct stats	*txstats;
 
 	/* parameters for reading from the netmap port */
 	struct nmport_d *src_port;		/* netmap descriptor */
@@ -418,13 +467,185 @@ struct _qs { /* shared queue */
 	uint64_t	cons_lag;	/* tail - head */
 	uint64_t	rx_wait;	/* stats */
 	const char *	cons_ifname;
-	struct stats	_rxstats, *rxstats;
+	struct stats	*rxstats;
 
 	/* shared fields */
 	volatile uint64_t tail ALIGN_CACHE ;	/* producer writes here */
 	volatile uint64_t head ALIGN_CACHE ;	/* consumer reads from here */
 };
 
+static int
+ec_next(int i)
+{
+    return (i + 1) % EC_NINST;
+}
+
+/* if fname is NULL tlem will run standalone, i.e., in server mode
+ * with no possibility for clients to change the configuration.
+ * Otherwise, the first tlem instance that successully locks the
+ * first four bytes of the configuration file becomes the server.
+ * Clients write-lock the rest of the file, to guarantee mutual
+ * exclusive configuration updates among them.
+ */
+static int ecf_fd = -1;
+static struct _ecf *
+ec_map(const char *fname, int *server)
+{
+    size_t sz;
+    struct _ecf *ecf;
+    int mmap_flags;
+
+    sz = sizeof(struct _ecf);
+    if (fname) {
+        ecf_fd = open(fname, O_RDWR | O_CREAT, 0664);
+        if (ecf_fd < 0) {
+            ED("cannot open %s: %s", fname, strerror(errno));
+            return NULL;
+        }
+        if (ftruncate(ecf_fd, sz) < 0) {
+            ED("cannot truncate(%s, %zu): %s",
+                    fname, sz, strerror(errno));
+            return NULL;
+        }
+        mmap_flags = MAP_SHARED;
+
+        /* try to lock the entire file.
+         * If we succeed, we are the server.
+         */
+        if (lockf(ecf_fd, F_TLOCK, 0) == 0) {
+            *server = 1;
+            /* we will release the non-header part when
+             * we are done with the initial configuration
+             */
+        } else {
+            if (errno != EACCES && errno != EAGAIN) {
+                ED("failed to lock %s: %s", fname, strerror(errno));
+                return NULL;
+            }
+            /* we are a client. Skip the header and wait
+             * for exclusive access to the rest.
+             */
+            *server = 0;
+            if (lseek(ecf_fd, EC_HDRSZ, SEEK_SET) < 0) {
+                ED("failed to skip the header of %s: %s",
+                        fname, strerror(errno));
+                return NULL;
+            }
+            if (lockf(ecf_fd, F_LOCK, 0) < 0) {
+                ED("failed to lock the client area of %s: %s",
+                        fname, strerror(errno));
+                return NULL;
+            }
+        }
+    } else {
+        mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE;
+    }
+    ecf = mmap(NULL, sz,
+            PROT_READ | PROT_WRITE,
+            mmap_flags, ecf_fd, 0);
+    /* errors are all fatal. Locks will be released on exit */
+    if (ecf == MAP_FAILED) {
+        D("cannot mmap %s: %s", fname, strerror(errno));
+        return NULL;
+    }
+    if (*server) {
+        memset(ecf, 0, sz);
+        ecf->version = EC_VERSION;
+    } else {
+        if (ecf->version != EC_VERSION) {
+            ED("Expected version %d, got %d",
+                    EC_VERSION, ecf->version);
+            return NULL;
+        }
+    }
+    return ecf;
+}
+
+static int
+ec_allowclients()
+{
+    if (ecf_fd < 0) {
+        /* OK, standalone mode */
+        return 0;
+    }
+    if (lseek(ecf_fd, EC_HDRSZ, SEEK_SET) < 0) {
+        ED("failed to skip the header: %s",
+                strerror(errno));
+        return 1;
+    }
+    if (lockf(ecf_fd, F_ULOCK, 0) < 0) {
+        ED("failed to unlock the client area: %s",
+                strerror(errno));
+        return 1;
+    }
+    return 0;
+}
+
+static void ec_activate(struct _qs *q); // foward
+static int
+ec_init(struct _qs *q, struct _ecs *ec, int server)
+{
+    int i;
+    struct _eci *ci;
+
+    q->ec = ec;
+    for (i = 0; i < EC_NINST; i++)
+        q->ec_nta[i] = 0;
+    q->ec_active = server ? 0 : ec_next(q->ec->active);
+    ci = &q->ec->instances[q->ec_active];
+    ci->ec_delay.ec_valid = 0;
+    q->c_delay.ec = &ci->ec_delay;
+    ci->ec_bw.ec_valid = 0;
+    q->c_bw.ec = &ci->ec_bw;
+    ci->ec_loss.ec_valid = 0;
+    q->c_loss.ec = &ci->ec_loss;
+    ci->ec_reorder.ec_valid = 0;
+    q->c_reorder.ec = &ci->ec_reorder;
+    return 0;
+}
+
+/* allocate sz bytes in the non-active config instance */
+static void *
+ec_alloc(struct _qs *q, struct _ec *ec, size_t sz)
+{
+    int i = q->ec_active;
+    struct _eci *a = &q->ec->instances[i];
+    size_t nta = q->ec_nta[i];
+
+    if (sz + nta >= EC_DATASZ) {
+        ED("no room for %zu bytes in external config instance %d", sz, i);
+        return NULL;
+    }
+    q->ec_nta[i] += sz;
+    ec->ec_dataoff = nta;
+    ec->ec_datasz = sz;
+    return &a->ec_data[nta];
+}
+
+static inline void
+ec_checkactive(struct _qs *q)
+{
+    uint64_t i = q->ec->active;
+    if (i != q->ec_active) {
+        asm volatile("" ::: "memory");
+        __sync_synchronize();
+        ND("switching to configuration %i", i);
+        q->ec_active = i;
+        ec_activate(q);
+    }
+}
+
+static void
+ec_switchactive(struct _qs *q)
+{
+    if (q->ec_active != q->ec->active) {
+        asm volatile("" ::: "memory");
+        __sync_synchronize();
+        ND("switching to configuration %i", q->ec_active);
+        q->ec->active = q->ec_active;
+    }
+}
+
 /* route-mode data structures and helper functions
  *
  * In route-mode TLEM acts as a router between the two subnets at its ends.
@@ -847,7 +1068,7 @@ enq(struct _qs *q)
             q->cur_len, (int)q->prod_tail, p->next,
             p->pt_qout, p->pt_tx);
     q->prod_tail = p->next;
-    if (q->max_bps)
+    if (q->ec->max_bps)
         q->prod_queued += p->pktlen;
     /* XXX update timestamps ? */
     return 0;
@@ -890,6 +1111,7 @@ wait_for_packets(struct _qs *q)
     uint64_t prev = q->prod_now;
 
     ioctl(q->src_port->fd, NIOCRXSYNC, 0); /* forced */
+    ec_checkactive(q);
     while (!do_abort) {
         if (hold_update_release(q))
             break;
@@ -903,6 +1125,7 @@ wait_for_packets(struct _qs *q)
         if (1) {
             usleep(5);
             ioctl(q->src_port->fd, NIOCRXSYNC, 0);
+            ec_checkactive(q);
             set_tns_now(&q->prod_now, q->t0);
         } else {
             struct pollfd pfd;
@@ -1456,8 +1679,8 @@ tlem_main(void *_a)
      * to the packet expansion for padding
      */
 
-    need = q->max_bps ? q->max_bps : INFINITE_BW;
-    need *= q->max_delay + 1000000;	/* delay is in nanoseconds */
+    need = q->ec->max_bps ? q->ec->max_bps : INFINITE_BW;
+    need *= q->ec->max_delay + 1000000;	/* delay is in nanoseconds */
     need /= TIME_UNITS; /* total bits */
     need /= 8; /* in bytes */
     need += q->qsize; /* in bytes */
@@ -1489,9 +1712,9 @@ tlem_main(void *_a)
      * issues and no need for padding.  The header is only 8 bytes, so the
      * worst case overhead (all minimally sized packets) is 8/64;
      */
-    if (q->max_hold_delay) {
-        need = q->max_bps ? q->max_bps : INFINITE_BW;
-        need *= q->max_hold_delay + 1000000;
+    if (q->ec->max_hold_delay) {
+        need = q->ec->max_bps ? q->ec->max_bps : INFINITE_BW;
+        need *= q->ec->max_hold_delay + 1000000;
         need /= TIME_UNITS;
         need /= 8;
         need *= (1 + 1.0*sizeof(struct h_pkt)/64);
@@ -1514,7 +1737,7 @@ tlem_main(void *_a)
     ED("----\n\t%s -> %s :  bps %lld delay %s loss %s queue %lld bytes"
             "\n\tbuffer   %10llu bytes\n\thold-buf %10lld bytes",
             q->prod_ifname, q->cons_ifname,
-            (long long)q->max_bps, q->c_delay.optarg, q->c_loss.optarg,
+            (long long)q->ec->max_bps, q->c_delay.optarg, q->c_loss.optarg,
             (long long)q->qsize, (unsigned long long)q->buflen,
             (unsigned long long)q->hold_buflen);
 
@@ -1603,7 +1826,6 @@ split_arg(const char *src, int *_ac)
     return av;
 }
 
-
 /*
  * apply a command against a set of functions,
  * install a handler in *dst
@@ -1616,22 +1838,21 @@ cmd_apply(const struct _cfg *a, const char *arg, struct _qs *q, struct _cfg *dst
     int i;
 
     if (arg == NULL || *arg == '\0')
-        return 1; /* no argument may be ok */
+        return 0; /* no argument may be ok */
     if (a == NULL || dst == NULL) {
         ED("program error - invalid arguments");
         exit(1);
     }
     av = split_arg(arg, &ac);
     if (av == NULL)
-        return 1; /* error */
+        goto out; /* error */
     for (i = 0; a[i].parse; i++) {
         struct _cfg x = a[i];
         const char *errmsg = x.optarg;
         int ret;
 
         x.arg = NULL;
-        x.arg_len = 0;
-        bzero(&x.d, sizeof(x.d));
+        x.ec = dst->ec;
         ret = x.parse(q, &x, ac, av);
         if (ret == 2) /* not recognised */
             continue;
@@ -1642,10 +1863,14 @@ cmd_apply(const struct _cfg *a, const char *arg, struct _qs *q, struct _cfg *dst
         }
         x.optarg = arg;
         *dst = x;
+        dst->ec->ec_index = i;
+        dst->ec->ec_valid = 1;
         return 0;
     }
     ED("arguments %s not recognised", arg);
     free(av);
+out:
+    dst->ec->ec_valid = 0;
     return 1;
 }
 
@@ -1678,21 +1903,66 @@ add_to(const char ** v, int l, const char *arg, const char *msg)
 
 static uint64_t parse_time(const char *arg); // forward
 
+/* set the maximum values for delay, bw and hold-time */
+static int
+set_max(const char *arg, struct _qs *q)
+{
+    int ac = 0;
+    char **av;
+    uint64_t delay = 0, bps = 0, hold = 0;
+
+    av = split_arg(arg, &ac);
+    if (av == NULL || ac < 1 || ac > 3) {
+        D("arg %p av %p ac %d", arg, av, ac);
+        ED("invalid parameters for -M: need max-delay[,max-bps[,max-hold-time]]]");
+        return 1;
+    }
+    /* first argument: max delay */
+    delay = parse_time(av[0]);
+    if (delay == U_PARSE_ERR) {
+        ED("invalid max-delay: %s", av[0]);
+        return 1;
+    }
+    if (ac > 1) {
+        /* second argument: max bw */
+        bps = parse_bw(av[1]);
+        if (bps == U_PARSE_ERR) {
+            ED("invalid max-bps: %s", av[1]);
+            return 1;
+        }
+    }
+    if (ac > 2) {
+        /* third argument: max hold time */
+        hold = parse_time(av[2]);
+        if (hold == U_PARSE_ERR) {
+            ED("invalid max-hold-time: %s", av[2]);
+            return 1;
+        }
+    }
+    if (delay > q->ec->max_delay)
+        q->ec->max_delay = delay;
+    if (bps > q->ec->max_bps)
+        q->ec->max_bps = bps;
+    if (hold > q->ec->max_hold_delay)
+        q->ec->max_hold_delay = hold;
+    return 0;
+}
+
+
 int
 main(int argc, char **argv)
 {
-    int ch, i, err=0;
+    int ch, i, j, err=0;
 
-#define	N_OPTS	2
-    struct pipe_args bp[N_OPTS];
-    const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *r[N_OPTS],
-    *ifname[N_OPTS], *gw[N_OPTS], *cd[N_OPTS];
+    struct pipe_args bp[EC_NOPTS];
+    const char *d[EC_NOPTS], *b[EC_NOPTS], *l[EC_NOPTS], *q[EC_NOPTS], *r[EC_NOPTS],
+    *ifname[EC_NOPTS], *gw[EC_NOPTS], *cd[EC_NOPTS], *m[EC_NOPTS];
     int ncpus;
     int cores[4];
     int hugepages = 0;
-    char *statsfname = NULL;
-    int statsfd;
-    struct stats *stats = NULL;
+    char *sfname = NULL; /* session file name */
+    int server = 1;
+    struct _ecf *ecf;
 
     nmctx_set_threadsafe();
 
@@ -1703,13 +1973,14 @@ main(int argc, char **argv)
     bzero(r, sizeof(r));
     bzero(gw, sizeof(gw));
     bzero(cd, sizeof(cd));
+    bzero(m, sizeof(m));
     bzero(ifname, sizeof(ifname));
 
     fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
 
     bzero(&bp, sizeof(bp));	/* all data initially go here */
 
-    for (i = 0; i < N_OPTS; i++) {
+    for (i = 0; i < EC_NOPTS; i++) {
         struct _qs *q = &bp[i].q;
         q->c_delay.optarg = "0";
         q->c_delay.run = null_run_fn;
@@ -1747,7 +2018,7 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:b:ci:vw:rd:Hs:")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:b:ci:vw:rd:Hs:l:")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -1783,32 +2054,35 @@ main(int argc, char **argv)
                 break;
 
             case 'B': /* bandwidth in bps */
-                add_to(b, N_OPTS, optarg, "-B too many times");
+                add_to(b, EC_NOPTS, optarg, "-B too many times");
                 break;
 
             case 'D': /* delay in seconds (float) */
-                add_to(d, N_OPTS, optarg, "-D too many times");
+                add_to(d, EC_NOPTS, optarg, "-D too many times");
                 break;
 
             case 'Q': /* qsize in bytes */
-                add_to(q, N_OPTS, optarg, "-Q too many times");
+                add_to(q, EC_NOPTS, optarg, "-Q too many times");
                 break;
 
             case 'L': /* loss probability */
-                add_to(l, N_OPTS, optarg, "-L too many times");
+                add_to(l, EC_NOPTS, optarg, "-L too many times");
                 break;
             case 'R': /* reordering */
-                add_to(r, N_OPTS, optarg, "-R too many times");
+                add_to(r, EC_NOPTS, optarg, "-R too many times");
                 break;
             case 'G': /* default gateway */
-                add_to(gw, N_OPTS, optarg, "-G too many times");
+                add_to(gw, EC_NOPTS, optarg, "-G too many times");
+                break;
+            case 'M': /* max bw, delay and hold-time */
+                add_to(m, EC_NOPTS, optarg, "-M too many times");
                 break;
             case 'b':	/* burst */
                 bp[0].q.burst = atoi(optarg);
                 break;
 
             case 'i':	/* interface */
-                add_to(ifname, N_OPTS, optarg, "-i too many times");
+                add_to(ifname, EC_NOPTS, optarg, "-i too many times");
                 break;
             case 'c':
                 bp[0].zerocopy = 0; /* do not zerocopy */
@@ -1823,21 +2097,17 @@ main(int argc, char **argv)
                 bp[0].route_mode = 1;
                 break;
             case 'd':
-                add_to(cd, N_OPTS, optarg, "-d too many times");
+                add_to(cd, EC_NOPTS, optarg, "-d too many times");
                 break;
             case 'H':
                 hugepages = 1;
                 break;
             case 's':
-                if (statsfname != NULL) {
+                if (sfname != NULL) {
                     D("option 's' duplicated");
                     usage();
                 }
-                statsfname = strdup(optarg);
-                if (statsfname == NULL) {
-                    D("out of memory");
-                    exit(1);
-                }
+                sfname = optarg;
                 break;
         }
     }
@@ -1845,197 +2115,205 @@ main(int argc, char **argv)
     argc -= optind;
     argv += optind;
 
+    /* map the session area and auto-detect wether we are server or client */
+    ecf = ec_map(sfname, &server);
+    if (ecf == NULL)
+        exit(1);
+
     /*
      * consistency checks for common arguments
      */
-    if (!ifname[0] || !ifname[1]) {
-        ED("missing interface(s)");
-        usage();
-    }
-    if (strcmp(ifname[0], ifname[1]) == 0) {
-        ED("must specify two different interfaces %s %s", ifname[0], ifname[1]);
-        usage();
-    }
-    if (bp[0].q.burst < 1 || bp[0].q.burst > 8192) {
-        ED("invalid burst %d, set to 1024", bp[0].q.burst);
-        bp[0].q.burst = 1024; // XXX 128 is probably better
-    }
-    if (bp[0].wait_link > 100) {
-        ED("invalid wait_link %d, set to 4", bp[0].wait_link);
-        bp[0].wait_link = 4;
-    }
-
-    if (bp[0].route_mode) {
-        int fd;
-        struct ifreq ifr;
-#ifdef __FreeBSD__
-        struct ifaddrs *ifap, *p;
-
-        if (getifaddrs(&ifap) < 0) {
-            ED("failed to get interface list: %s", strerror(errno));
+    if (server) {
+        if (!ifname[0] || !ifname[1]) {
+            ED("missing interface(s)");
             usage();
         }
-#endif /* __FreeBSD__ */
-
-        fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-
-        if (fd < 0) {
-            ED("failed to open SOCK_DGRAM socket: %s", strerror(errno));
+        if (strcmp(ifname[0], ifname[1]) == 0) {
+            ED("must specify two different interfaces %s %s", ifname[0], ifname[1]);
             usage();
         }
+        if (bp[0].q.burst < 1 || bp[0].q.burst > 8192) {
+            ED("invalid burst %d, set to 1024", bp[0].q.burst);
+            bp[0].q.burst = 1024; // XXX 128 is probably better
+        }
+        if (bp[0].wait_link > 100) {
+            ED("invalid wait_link %d, set to 4", bp[0].wait_link);
+            bp[0].wait_link = 4;
+        }
 
-        for (i = 0; i < 2; i++) {
-            struct ipv4_info *ip = &ipv4[i];
-            char *dst = ip->name;
-            const char *scan;
-            struct ether_header *eh;
-            struct ether_arp *ah;
-            void *hwaddr = NULL;
-
-            /* try to extract the port name */
-            if (!strncmp("vale", ifname[i], 4)) {
-                ED("route mode not supported for VALE port %s", ifname[i]);
-                usage();
-            }
-            if (strncmp("netmap:", ifname[i], 7)) {
-                ED("missing netmap: prefix in %s", ifname[i]);
+        if (bp[0].route_mode) {
+            int fd;
+            struct ifreq ifr;
+#ifdef __FreeBSD__
+            struct ifaddrs *ifap, *p;
+
+            if (getifaddrs(&ifap) < 0) {
+                ED("failed to get interface list: %s", strerror(errno));
                 usage();
             }
-            scan = ifname[i] + 7;
-            if (strlen(scan) >= IFNAMSIZ) {
-                ED("name too long: %s", scan);
+#endif /* __FreeBSD__ */
+
+            fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+            if (fd < 0) {
+                ED("failed to open SOCK_DGRAM socket: %s", strerror(errno));
                 usage();
             }
-            while (*scan && isalnum(*scan))
-                *dst++ = *scan++;
-            *dst = '\0';
-            ED("trying to get configuration for %s", ip->name);
 
-            /* MAC address */
+            for (i = 0; i < 2; i++) {
+                struct ipv4_info *ip = &ipv4[i];
+                char *dst = ip->name;
+                const char *scan;
+                struct ether_header *eh;
+                struct ether_arp *ah;
+                void *hwaddr = NULL;
+
+                /* try to extract the port name */
+                if (!strncmp("vale", ifname[i], 4)) {
+                    ED("route mode not supported for VALE port %s", ifname[i]);
+                    usage();
+                }
+                if (strncmp("netmap:", ifname[i], 7)) {
+                    ED("missing netmap: prefix in %s", ifname[i]);
+                    usage();
+                }
+                scan = ifname[i] + 7;
+                if (strlen(scan) >= IFNAMSIZ) {
+                    ED("name too long: %s", scan);
+                    usage();
+                }
+                while (*scan && isalnum(*scan))
+                    *dst++ = *scan++;
+                *dst = '\0';
+                ED("trying to get configuration for %s", ip->name);
+
+                /* MAC address */
 #ifdef linux
-            memset(&ifr, 0, sizeof(ifr));
-            strcpy(ifr.ifr_name, ip->name);
-            if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) {
-                hwaddr = ifr.ifr_addr.sa_data;
-            }
+                memset(&ifr, 0, sizeof(ifr));
+                strcpy(ifr.ifr_name, ip->name);
+                if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) {
+                    hwaddr = ifr.ifr_addr.sa_data;
+                }
 #elif defined (__FreeBSD__)
-            errno = ENOENT;
-            for (p = ifap; p; p = p->ifa_next) {
-
-                if (!strcmp(p->ifa_name, ip->name) &&
-                        p->ifa_addr != NULL &&
-                        p->ifa_addr->sa_family == AF_LINK)
-                {
-                    struct sockaddr_dl *sdp =
-                        (struct sockaddr_dl *)p->ifa_addr;
-                    hwaddr = sdp->sdl_data + sdp->sdl_nlen;
-                    break;
+                errno = ENOENT;
+                for (p = ifap; p; p = p->ifa_next) {
+
+                    if (!strcmp(p->ifa_name, ip->name) &&
+                            p->ifa_addr != NULL &&
+                            p->ifa_addr->sa_family == AF_LINK)
+                    {
+                        struct sockaddr_dl *sdp =
+                            (struct sockaddr_dl *)p->ifa_addr;
+                        hwaddr = sdp->sdl_data + sdp->sdl_nlen;
+                        break;
+                    }
                 }
-            }
 #endif /* __FreeBSD__ */
-            if (hwaddr == NULL) {
-                ED("failed to get MAC address for %s: %s",
-                        ip->name, strerror(errno));
-                usage();
-            }
-            memcpy(ip->ether_addr, hwaddr, 6);
+                if (hwaddr == NULL) {
+                    ED("failed to get MAC address for %s: %s",
+                            ip->name, strerror(errno));
+                    usage();
+                }
+                memcpy(ip->ether_addr, hwaddr, 6);
 
 #define get_ip_info(_c, _f, _m) 								\
-            memset(&ifr, 0, sizeof(ifr));						\
-            strcpy(ifr.ifr_name, ip->name);						\
-            ifr.ifr_addr.sa_family = AF_INET;					\
-            if (ioctl(fd, _c, &ifr) < 0) {						\
-                ED("failed to get IPv4 " _m " for %s: %s",			\
-                        ip->name, strerror(errno));			\
-                usage();							\
-            }									\
-            memcpy(&ip->_f, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, 4);	\
-
-
-            /* IP address */
-            get_ip_info(SIOCGIFADDR, ip_addr, "address");
-            /* netmask */
-            get_ip_info(SIOCGIFNETMASK, ip_mask, "netmask");
-            /* broadcast */
-            get_ip_info(SIOCGIFBRDADDR, ip_bcast, "broadcast");
+                memset(&ifr, 0, sizeof(ifr));						\
+                strcpy(ifr.ifr_name, ip->name);						\
+                ifr.ifr_addr.sa_family = AF_INET;					\
+                if (ioctl(fd, _c, &ifr) < 0) {						\
+                    ED("failed to get IPv4 " _m " for %s: %s",			\
+                            ip->name, strerror(errno));			\
+                    usage();							\
+                }									\
+                memcpy(&ip->_f, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, 4);	\
+
+
+                /* IP address */
+                get_ip_info(SIOCGIFADDR, ip_addr, "address");
+                /* netmask */
+                get_ip_info(SIOCGIFNETMASK, ip_mask, "netmask");
+                /* broadcast */
+                get_ip_info(SIOCGIFBRDADDR, ip_bcast, "broadcast");
 #undef get_ip_info
 
-            /* do we have an IP address? */
-            if (ip->ip_addr == 0) {
-                ED("no IPv4 address found for %s", ip->name);
-                usage();
-            }
+                /* do we have an IP address? */
+                if (ip->ip_addr == 0) {
+                    ED("no IPv4 address found for %s", ip->name);
+                    usage();
+                }
 
-            /* cache the subnet */
-            ip->ip_subnet = ip->ip_addr & ip->ip_mask;
+                /* cache the subnet */
+                ip->ip_subnet = ip->ip_addr & ip->ip_mask;
 
-            /* default gateway, if any */
-            if (gw[i]) {
-                struct ipv4_info *ip = &ipv4[i];
-                struct in_addr a;
-                if (!inet_aton(gw[i], &a)) {
-                    ED("not a valid IP address: %s", gw[i]);
-                    usage();
+                /* default gateway, if any */
+                if (gw[i]) {
+                    struct ipv4_info *ip = &ipv4[i];
+                    struct in_addr a;
+                    if (!inet_aton(gw[i], &a)) {
+                        ED("not a valid IP address: %s", gw[i]);
+                        usage();
+                    }
+                    if ((a.s_addr & ip->ip_mask) != ip->ip_subnet) {
+                        ED("gateway %s unreachable", gw[i]);
+                        usage();
+                    }
+                    ip->ip_gw = a.s_addr;
                 }
-                if ((a.s_addr & ip->ip_mask) != ip->ip_subnet) {
-                    ED("gateway %s unreachable", gw[i]);
+
+                ipv4_dump(ip);
+
+                /* precompute the arp reply for this interface */
+                eh = &ip->arp_reply.arp.eh;
+                ah = &ip->arp_reply.arp.ah;
+                memset(&ip->arp_reply, 0, sizeof(ip->arp_reply));
+                memcpy(eh->ether_shost, ip->ether_addr, 6);
+                eh->ether_type = htons(ETHERTYPE_ARP);
+                ah->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+                ah->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+                ah->ea_hdr.ar_hln = 6;
+                ah->ea_hdr.ar_pln = 4;
+                ah->ea_hdr.ar_op = htons(ARPOP_REPLY);
+                memcpy(ah->arp_sha, ip->ether_addr, 6);
+                memcpy(ah->arp_spa, &ip->ip_addr, 4);
+
+                /* precompute the arp request for this interface */
+                eh = &ip->arp_request.arp.eh;
+                ah = &ip->arp_request.arp.ah;
+                memcpy(&ip->arp_request, &ip->arp_reply,
+                        sizeof(ip->arp_reply));
+                memset(eh->ether_dhost, 0xff, 6);
+                ah->ea_hdr.ar_op = htons(ARPOP_REQUEST);
+
+                /* allocate the arp table */
+                ip->arp_table = arp_table_new(ip->ip_mask);
+                if (ip->arp_table == NULL) {
+                    ED("failed to allocate the arp table for %s: %s", ip->name,
+                            strerror(errno));
                     usage();
                 }
-                ip->ip_gw = a.s_addr;
             }
 
-            ipv4_dump(ip);
-
-            /* precompute the arp reply for this interface */
-            eh = &ip->arp_reply.arp.eh;
-            ah = &ip->arp_reply.arp.ah;
-            memset(&ip->arp_reply, 0, sizeof(ip->arp_reply));
-            memcpy(eh->ether_shost, ip->ether_addr, 6);
-            eh->ether_type = htons(ETHERTYPE_ARP);
-            ah->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
-            ah->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
-            ah->ea_hdr.ar_hln = 6;
-            ah->ea_hdr.ar_pln = 4;
-            ah->ea_hdr.ar_op = htons(ARPOP_REPLY);
-            memcpy(ah->arp_sha, ip->ether_addr, 6);
-            memcpy(ah->arp_spa, &ip->ip_addr, 4);
-
-            /* precompute the arp request for this interface */
-            eh = &ip->arp_request.arp.eh;
-            ah = &ip->arp_request.arp.ah;
-            memcpy(&ip->arp_request, &ip->arp_reply,
-                    sizeof(ip->arp_reply));
-            memset(eh->ether_dhost, 0xff, 6);
-            ah->ea_hdr.ar_op = htons(ARPOP_REQUEST);
-
-            /* allocate the arp table */
-            ip->arp_table = arp_table_new(ip->ip_mask);
-            if (ip->arp_table == NULL) {
-                ED("failed to allocate the arp table for %s: %s", ip->name,
-                        strerror(errno));
-                usage();
-            }
-        }
-
-        close(fd);
+            close(fd);
 #ifdef __FreeBSD__
-        freeifaddrs(ifap);
+            freeifaddrs(ifap);
 #endif /* __FreeBSD__ */
-    }
+        }
 
-    bp[1] = bp[0]; /* copy parameters, but swap interfaces */
-    bp[0].q.prod_ifname = bp[1].q.cons_ifname = ifname[0];
-    bp[1].q.prod_ifname = bp[0].q.cons_ifname = ifname[1];
-    bp[0].prod_ipv4 = bp[1].cons_ipv4 = &ipv4[0];
-    bp[0].cons_ipv4 = bp[1].prod_ipv4 = &ipv4[1];
+        bp[1] = bp[0]; /* copy parameters, but swap interfaces */
+        bp[0].q.prod_ifname = bp[1].q.cons_ifname = ifname[0];
+        bp[1].q.prod_ifname = bp[0].q.cons_ifname = ifname[1];
+        bp[0].prod_ipv4 = bp[1].cons_ipv4 = &ipv4[0];
+        bp[0].cons_ipv4 = bp[1].prod_ipv4 = &ipv4[1];
 
 
-    /* assign cores. prod and cons work better if on the same HT */
-    bp[0].cons_core = cores[0];
-    bp[0].prod_core = cores[1];
-    bp[1].cons_core = cores[2];
-    bp[1].prod_core = cores[3];
-    ED("running on cores %d %d %d %d", cores[0], cores[1], cores[2], cores[3]);
+        /* assign cores. prod and cons work better if on the same HT */
+        bp[0].cons_core = cores[0];
+        bp[0].prod_core = cores[1];
+        bp[1].cons_core = cores[2];
+        bp[1].prod_core = cores[3];
+        ED("running on cores %d %d %d %d", cores[0], cores[1], cores[2], cores[3]);
+
+    }
 
     /* use same parameters for both directions if needed */
     if (d[1] == NULL)
@@ -2050,8 +2328,11 @@ main(int argc, char **argv)
         r[1] = r[0];
 
     /* apply commands */
-    for (i = 0; i < N_OPTS; i++) { /* once per queue */
+    j = 0;
+    for (i = 0; i < EC_NOPTS; i++) { /* once per queue */
         struct _qs *q = &bp[i].q;
+        if (ec_init(q, &ecf->sets[i], server))
+            exit(1);
         err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
         err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
         err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
@@ -2064,6 +2345,32 @@ main(int argc, char **argv)
                 bp[i].max_lag = max_lag;
             }
         }
+        bp[i].q.txstats = &ecf->stats[j++];
+        bp[i].q.rxstats = &ecf->stats[j++];
+    }
+
+    if (err) {
+        ED("exiting due to %d error(s)", err);
+        exit(1);
+    }
+
+    if (server) {
+        /* set the maximum values */
+        if (m[0] == NULL)
+            m[0] = "0";
+        if (m[1] == NULL)
+            m[1] = m[0];
+        for (i = 0; i < EC_NOPTS; i++) {
+            if (set_max(m[i], &bp[i].q))
+                exit(1);
+        }
+        /* now the clients may send new configurations */
+        if (ec_allowclients())
+            exit(1);
+    } else {
+        for (i = 0; i < EC_NOPTS; i++)
+            ec_switchactive(&bp[i].q);
+        exit(0);
     }
 
     if (q[0] == NULL)
@@ -2082,7 +2389,7 @@ main(int argc, char **argv)
         bp[1].q.qsize = 50000;
     }
 
-    for (i = 0; i < N_OPTS; i++) {
+    for (i = 0; i < EC_NOPTS; i++) {
         if (bp[i].max_lag == 0) {
             bp[i].max_lag = 100000; /* 100 us */
         }
@@ -2126,36 +2433,6 @@ main(int argc, char **argv)
 
     }
 
-    if (statsfname != NULL) {
-        size_t statsz = 4 * sizeof(struct stats);
-        statsfd = open(statsfname, O_RDWR | O_CREAT, 0666);
-        if (statsfd < 0) {
-            D("cannot open %s: %s", statsfname, strerror(errno));
-            exit(1);
-        }
-        if (ftruncate(statsfd, statsz) < 0) {
-            D("cannot truncate(%s, %zu): %s",
-                    statsfname, statsz, strerror(errno));
-            exit(1);
-        }
-        stats = mmap(NULL, statsz,
-                PROT_READ | PROT_WRITE,
-                MAP_SHARED, statsfd, 0);
-        if (stats == MAP_FAILED) {
-            D("cannot mmap %s: %s", statsfname, strerror(errno));
-            exit(1);
-        }
-        bp[0].q.txstats = stats;
-        bp[0].q.rxstats = stats + 1;
-        bp[1].q.txstats = stats + 2;
-        bp[1].q.rxstats = stats + 3;
-    } else {
-        bp[0].q.txstats = &bp[0].q._txstats;
-        bp[0].q.rxstats = &bp[0].q._rxstats;
-        bp[1].q.txstats = &bp[1].q._txstats;
-        bp[1].q.rxstats = &bp[1].q._rxstats;
-    }
-
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
 
@@ -2179,7 +2456,7 @@ main(int argc, char **argv)
                 q1->rx_qmax, (long long)q1->prod_max_gap,
                 (long long)(q1->rxstats->drop_packets - old1rx.drop_packets)
           );
-        ED("plr nominal %le actual %le",
+        ND("plr nominal %le actual %le",
                 (double)(q0->c_loss.d[0])/(1<<24),
                 q0->c_loss.d[1] == 0 ? 0 :
                 (double)(q0->c_loss.d[2])/q0->c_loss.d[1]);
@@ -2443,11 +2720,26 @@ REORDERING emulation 	-R option_arguments
  * as this is used to size the queue.
  */
 
+static int
+update_max_delay(struct _qs *q, uint64_t delay)
+{
+    if (q->ec->max_delay) {
+        if (q->ec->max_delay < delay) {
+            ED("invalid new delay %lld (max %lld)",
+                    (long long)delay, (long long)q->ec->max_delay);
+            return 1;
+        }
+    } else {
+        q->ec->max_delay = delay;
+    }
+    return 0;
+}
+
 /* constant delay, also accepts just a number */
 static int
 const_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-    uint64_t delay;
+    uint64_t delay, *d;
 
     if (strncmp(av[0], "const", 5) != 0 && ac > 1)
         return 2; /* unrecognised */
@@ -2456,8 +2748,13 @@ const_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     delay = parse_time(av[ac - 1]);
     if (delay == U_PARSE_ERR)
         return 1; /* error */
-    dst->d[0] = delay;
-    q->max_delay = delay;
+    if (update_max_delay(q, delay))
+        return 1;
+    dst->arg = ec_alloc(q, dst->ec, sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1;
+    d = dst->arg;
+    d[0] = delay;
     return 0;	/* success */
 }
 
@@ -2465,16 +2762,16 @@ const_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_delay_run(struct _qs *q, struct _cfg *arg)
 {
-    q->cur_delay = arg->d[0]; /* the delay */
+    uint64_t *d = arg->arg;
+    q->cur_delay = d[0]; /* the delay */
     return 0;
 }
 
 static int
 uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-    uint64_t dmin, dmax;
+    uint64_t dmin, dmax, *d;
 
-    (void)q;
     if (strcmp(av[0], "uniform") != 0)
         return 2; /* not recognised */
     if (ac != 3)
@@ -2484,18 +2781,23 @@ uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax)
         return 1;
     D("dmin %lld dmax %lld", (long long)dmin, (long long)dmax);
-    dst->d[0] = dmin;
-    dst->d[1] = dmax;
-    dst->d[2] = dmax - dmin;
-    q->max_delay = dmax;
+    if (update_max_delay(q, dmax))
+        return 1;
+    dst->arg = ec_alloc(q, dst->ec, 3 * sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1;
+    d = dst->arg;
+    d[0] = dmin;
+    d[1] = dmax;
+    d[2] = dmax - dmin;
     return 0;
 }
 
 static int
 uniform_delay_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t x = my_random24();
-    q->cur_delay = arg->d[0] + ((arg->d[2] * x) >> 24);
+    uint64_t x = my_random24(), *d = arg->arg;
+    q->cur_delay = d[0] + ((d[2] * x) >> 24);
 #if 0 /* COMPUTE_STATS */
 #endif /* COMPUTE_STATS */
     return 0;
@@ -2516,9 +2818,8 @@ static int
 exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
 #define	PTS_D_EXP	512
-    uint64_t i, d_av, d_min, *t; /*table of values */
+    uint64_t i, d_av, d_min, d_max, *t; /*table of values */
 
-    (void)q;
     if (strcmp(av[0], "exp") != 0)
         return 2; /* not recognised */
     if (ac != 3)
@@ -2527,13 +2828,14 @@ exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     d_av = parse_time(av[2]);
     if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min)
         return 1; /* error */
+    d_max = d_av * 4 + d_min; /* exp(-4) */
+    if (update_max_delay(q, d_max))
+        return 1;
     d_av -= d_min;
-    dst->arg_len = PTS_D_EXP * sizeof(uint64_t);
-    dst->arg = calloc(1, dst->arg_len);
+    dst->arg = ec_alloc(q, dst->ec, PTS_D_EXP * sizeof(uint64_t));
     if (dst->arg == NULL)
         return 1; /* no memory */
     t = (uint64_t *)dst->arg;
-    q->max_delay = d_av * 4 + d_min; /* exp(-4) */
     /* tabulate -ln(1-n)*delay  for n in 0..1 */
     for (i = 0; i < PTS_D_EXP; i++) {
         double d = -log ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min;
@@ -2553,7 +2855,7 @@ exp_delay_run(struct _qs *q, struct _cfg *arg)
 }
 
 
-#define TLEM_CFG_END	NULL, 0, {0}
+#define TLEM_CFG_END	NULL, NULL
 
 static struct _cfg delay_cfg[] = {
 	{ const_delay_parse, const_delay_run,
@@ -2565,11 +2867,26 @@ static struct _cfg delay_cfg[] = {
 	{ NULL, NULL, NULL, TLEM_CFG_END }
 };
 
+static int
+update_max_bw(struct _qs *q, uint64_t bw)
+{
+    if (q->ec->max_bps) {
+        if (q->ec->max_bps < bw) {
+            ED("invalid new bandwidth %lld (max %lld)",
+                    (long long)bw, (long long)q->ec->max_bps);
+            return 1;
+        }
+    } else {
+        q->ec->max_bps = bw;	/* bw used to determine queue size */
+    }
+    return 0;
+}
+
 /* standard bandwidth, also accepts just a number */
 static int
 const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-    uint64_t bw;
+    uint64_t bw, *d;
 
     if (strncmp(av[0], "const", 5) != 0 && ac > 1)
         return 2; /* unrecognised */
@@ -2579,8 +2896,13 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     if (bw == U_PARSE_ERR) {
         return (ac == 2) ? 1 /* error */ : 2 /* unrecognised */;
     }
-    dst->d[0] = bw;
-    q->max_bps = bw;	/* bw used to determine queue size */
+    dst->arg = ec_alloc(q, dst->ec, sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1;
+    if (update_max_bw(q, bw))
+        return 1;
+    d = dst->arg;
+    d[0] = bw;
     return 0;	/* success */
 }
 
@@ -2589,7 +2911,7 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_bw_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t bps = arg->d[0];
+    uint64_t *d = arg->arg, bps = d[0];
     q->cur_tt = bps ? 8ULL* TIME_UNITS * q->cur_len / bps : 0 ;
     return 0;
 }
@@ -2598,9 +2920,8 @@ const_bw_run(struct _qs *q, struct _cfg *arg)
 static int
 ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-    uint64_t bw;
+    uint64_t bw, *d;
 
-    (void)q;
     if (strcmp(av[0], "ether") != 0)
         return 2; /* unrecognised */
     if (ac != 2)
@@ -2608,8 +2929,13 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     bw = parse_bw(av[ac - 1]);
     if (bw == U_PARSE_ERR)
         return 1; /* error */
-    dst->d[0] = bw;
-    q->max_bps = bw;	/* bw used to determine queue size */
+    if (update_max_bw(q, bw))
+        return 1;
+    dst->arg = ec_alloc(q, dst->ec, sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1;
+    d = dst->arg;
+    d[0] = bw;
     return 0;	/* success */
 }
 
@@ -2618,7 +2944,7 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 ether_bw_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t bps = arg->d[0];
+    uint64_t *d = arg->arg, bps = d[0];
     q->cur_tt = bps ? 8ULL * TIME_UNITS * (q->cur_len + 24) / bps : 0 ;
     return 0;
 }
@@ -2639,6 +2965,7 @@ const_plr_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
     double plr;
     int err;
+    uint64_t *d;
 
     (void)q;
     if (strcmp(av[0], "plr") != 0 && ac > 1)
@@ -2649,8 +2976,12 @@ const_plr_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     plr = parse_gen(av[ac-1], NULL, &err);
     if (err || plr < 0 || plr > 1)
         return 1;
-    dst->d[0] = plr * (1<<24); /* scale is 16m */
-    if (plr != 0 && dst->d[0] == 0)
+    dst->arg = ec_alloc(q, dst->ec, 3 * sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1;
+    d = dst->arg;
+    d[0] = plr * (1<<24); /* scale is 16m */
+    if (plr != 0 && d[0] == 0)
         ED("WWW warning,  rounding %le down to 0", plr);
     return 0;	/* success */
 }
@@ -2658,12 +2989,11 @@ const_plr_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_plr_run(struct _qs *q, struct _cfg *arg)
 {
-    (void)arg;
-    uint64_t r = my_random24();
-    q->cur_drop = r < arg->d[0];
+    uint64_t *d = arg->arg, r = my_random24();
+    q->cur_drop = r < d[0];
 #if 1	/* keep stats */
-    arg->d[1]++;
-    arg->d[2] += q->cur_drop;
+    d[1]++;
+    d[2] += q->cur_drop;
 #endif
     return 0;
 }
@@ -2680,6 +3010,7 @@ const_ber_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     double ber, ber8, cur;
     int i, err;
     uint32_t *plr;
+    uint64_t *d;
     const uint32_t mask = (1<<24) - 1;
 
     (void)q;
@@ -2690,11 +3021,12 @@ const_ber_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     ber = parse_gen(av[ac-1], NULL, &err);
     if (err || ber < 0 || ber > 1)
         return 1;
-    dst->arg_len = MAX_PKT * sizeof(uint32_t);
-    plr = calloc(1, dst->arg_len);
-    if (plr == NULL)
+    dst->arg = ec_alloc(q, dst->ec,
+            3 * sizeof(uint64_t) + MAX_PKT * sizeof(uint32_t));
+    if (dst->arg == NULL)
         return 1; /* no memory */
-    dst->arg = plr;
+    d = dst->arg;
+    plr = (uint32_t *)(d + 3);
     ber8 = 1 - ber;
     ber8 *= ber8; /* **2 */
     ber8 *= ber8; /* **4 */
@@ -2709,7 +3041,7 @@ const_ber_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
             RD(50,"%4d: %le %ld", i, 1.0 - cur, (_P64)plr[i]);
 #endif
     }
-    dst->d[0] = ber * (mask + 1);
+    d[0] = ber * (mask + 1);
     return 0;	/* success */
 }
 
@@ -2717,8 +3049,8 @@ static int
 const_ber_run(struct _qs *q, struct _cfg *arg)
 {
     int l = q->cur_len;
-    uint64_t r = my_random24();
-    uint32_t *plr = arg->arg;
+    uint64_t r = my_random24(), *d = arg->arg;
+    uint32_t *plr = (uint32_t *)(d + 3);
 
     if (l >= MAX_PKT) {
         RD(5, "pkt len %d too large, trim to %d", l, MAX_PKT-1);
@@ -2726,8 +3058,8 @@ const_ber_run(struct _qs *q, struct _cfg *arg)
     }
     q->cur_drop = r < plr[l];
 #if 1	/* keep stats */
-    arg->d[1] += l * 8;
-    arg->d[2] += q->cur_drop;
+    d[1] += l * 8;
+    d[2] += q->cur_drop;
 #endif
     return 0;
 }
@@ -2744,37 +3076,58 @@ static struct _cfg loss_cfg[] = {
 /*
  * reordering
  */
+
+static int
+update_max_hold_delay(struct _qs *q, uint64_t delay)
+{
+    if (q->ec->max_hold_delay) {
+        if (q->ec->max_hold_delay < delay) {
+            ED("invalid new hold delay %lld (max %lld)",
+                    (long long)delay,
+                    (long long)q->ec->max_hold_delay);
+            return 1;
+        }
+    } else {
+        q->ec->max_hold_delay = delay;
+    }
+    return 0;
+}
+
 static int
 const_reorder_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
     double prob;
-    uint64_t delay;
+    uint64_t delay, *d;
     int err;
 
-    (void)q;
     if (strcmp(av[0], "const") != 0 && ac > 2)
         return 2; /* not recognized */
     if (ac > 3)
         return 1; /* error */
+    dst->arg = ec_alloc(q, dst->ec, 2 * sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1; /* no memory */
     prob = parse_gen(av[ac - 2], NULL, &err);
     if (err || prob < 0 || prob > 1)
         return 1;
-    dst->d[0] = prob * (1<<24);
-    if (prob != 0 && dst->d[0] == 0)
+    d = dst->arg;
+    d[0] = prob * (1<<24);
+    if (prob != 0 && d[0] == 0)
         ED("WWW warning,  rounding %le down to 0", prob);
     delay = parse_time(av[ac - 1]);
     if (delay == U_PARSE_ERR)
         return 1;
-    dst->d[1] = delay;
-    q->max_hold_delay = delay;
+    if (update_max_hold_delay(q, delay))
+        return 1;
+    d[1] = delay;
     return 0;
 }
 
 static int
 const_reorder_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t r = my_random24();
-    q->cur_hold_delay = (r < arg->d[0] ? arg->d[1] : 0);
+    uint64_t r = my_random24(), *d = arg->arg;
+    q->cur_hold_delay = (r < d[0] ? d[1] : 0);
     return 0;
 }
 
@@ -2783,3 +3136,43 @@ static struct _cfg reorder_cfg[] = {
 		"const,prob,delay # 0 <= prob <= 1", TLEM_CFG_END },
 	{ NULL, NULL, NULL, TLEM_CFG_END }
 };
+
+void
+ec_activate(struct _qs *q)
+{
+    int i = q->ec_active;
+    struct _eci *a = &q->ec->instances[i];
+
+    if (a->ec_bw.ec_valid) {
+        q->c_bw = bw_cfg[a->ec_bw.ec_index];
+        q->c_bw.arg = &a->ec_data[a->ec_bw.ec_dataoff];
+    } else {
+        q->cur_tt = 0;
+        q->c_bw.run = null_run_fn;
+    }
+    q->c_bw.ec = &a->ec_bw;
+    if (a->ec_delay.ec_valid) {
+        q->c_delay = delay_cfg[a->ec_delay.ec_index];
+        q->c_delay.arg = &a->ec_data[a->ec_delay.ec_dataoff];
+    } else {
+        q->cur_delay = 0;
+        q->c_delay.run = null_run_fn;
+    }
+    q->c_delay.ec = &a->ec_delay;
+    if (a->ec_loss.ec_valid) {
+        q->c_loss = loss_cfg[a->ec_loss.ec_index];
+        q->c_loss.arg = &a->ec_data[a->ec_loss.ec_dataoff];
+    } else {
+        q->cur_drop = 0;
+        q->c_loss.run = null_run_fn;
+    }
+    q->c_loss.ec = &a->ec_loss;
+    if (a->ec_reorder.ec_valid) {
+        q->c_reorder = reorder_cfg[a->ec_reorder.ec_index];
+        q->c_reorder.arg = &a->ec_data[a->ec_reorder.ec_dataoff];
+    } else {
+        q->cur_hold_delay = 0;
+        q->c_reorder.run = null_run_fn;
+    }
+    q->c_reorder.ec = &a->ec_reorder;
+}

From 9e24ecdd05e5866deb66568ce3842af2d61e9d3e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 16 Apr 2018 12:30:29 -0400
Subject: [PATCH 1726/2207] tlem: quiet option

---
 apps/tlem/tlem.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index ecf712553..a9c19aa07 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -132,11 +132,13 @@ prod()
 #define NED(_fmt, ...)	do {} while (0)
 #define ED(_fmt, ...)						\
 	do {							\
+	   if (verbose > 0) {					\
 		struct timeval _t0;				\
 		gettimeofday(&_t0, NULL);			\
 		fprintf(stderr, "%03d.%03d [%5d] \t" _fmt "\n", \
 		(int)(_t0.tv_sec % 1000), (int)_t0.tv_usec/1000, \
 		__LINE__, ##__VA_ARGS__);     \
+	   }							\
 	} while (0)
 
 #define _GNU_SOURCE	// for CPU_SET() etc
@@ -152,7 +154,7 @@ prod()
 #include 
 
 
-int verbose = 0;
+int verbose = 1;
 
 static int do_abort = 0;
 
@@ -721,7 +723,7 @@ arp_table_new(in_addr_t mask)
     // XXX this only works if mask is in CIDR form */
     size_t s = (~ntohl(mask) + 1) * sizeof(struct arp_table_entry);
     struct arp_table_entry *e;
-    D("allocating %zu bytes for arp table", s);
+    ED("allocating %zu bytes for arp table", s);
     e = mmap(NULL, s, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
     if (e == MAP_FAILED)
         return NULL;
@@ -1137,7 +1139,7 @@ wait_for_packets(struct _qs *q)
             pfd.events = POLLIN;
             ND(1, "prepare for poll on %s", q->prod_ifname);
             ret = poll(&pfd, 1, 10000);
-            if (ret <= 0 || verbose) {
+            if (ret <= 0 || verbose > 1) {
                 D("poll %s ev %x %x rx %d@%d",
                         ret <= 0 ? "timeout" : "ok",
                         pfd.events,
@@ -1819,7 +1821,8 @@ split_arg(const char *src, int *_ac)
             break;
         }
     }
-    for (i = 0; i < ac; i++) fprintf(stderr, "%d: <%s>\n", i, av[i]);
+    if (verbose > 2)
+        for (i = 0; i < ac; i++) fprintf(stderr, "%d: <%s>\n", i, av[i]);
     av[i++] = NULL;
     av[i++] = my;
     *_ac = ac;
@@ -1913,7 +1916,7 @@ set_max(const char *arg, struct _qs *q)
 
     av = split_arg(arg, &ac);
     if (av == NULL || ac < 1 || ac > 3) {
-        D("arg %p av %p ac %d", arg, av, ac);
+        ND("arg %p av %p ac %d", arg, av, ac);
         ED("invalid parameters for -M: need max-delay[,max-bps[,max-hold-time]]]");
         return 1;
     }
@@ -2018,7 +2021,7 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:b:ci:vw:rd:Hs:l:")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:b:ci:vw:rd:Hs:l:q")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -2090,6 +2093,10 @@ main(int argc, char **argv)
             case 'v':
                 verbose++;
                 break;
+            case 'q':
+                if (verbose > 0)
+                    verbose--;
+                break;
             case 'w':
                 bp[0].wait_link = atoi(optarg);
                 break;
@@ -2417,17 +2424,17 @@ main(int argc, char **argv)
 
         a->pa = nmport_prepare(a->q.prod_ifname);
         if (a->pa == NULL) {
-            ED("cannot open %s", a->q.prod_ifname);
+            D("cannot open %s", a->q.prod_ifname);
             exit(1);
         }
         a->pa->reg.nr_flags |= NETMAP_NO_TX_POLL;
         if (nmport_open_desc(a->pa) < 0) {
-            ED("cannot open %s", a->q.prod_ifname);
+            D("cannot open %s", a->q.prod_ifname);
 	    exit(1);
         }
         a->pb = nmport_open(a->q.cons_ifname);
         if (a->pb == NULL) {
-            ED("cannot open %s", a->q.cons_ifname);
+            D("cannot open %s", a->q.cons_ifname);
             exit(1);
         }
 
@@ -2465,7 +2472,7 @@ main(int argc, char **argv)
         bp[1].q.rx_qmax = (bp[1].q.rx_qmax * 7)/8; // ewma
         bp[1].q.prod_max_gap = (bp[1].q.prod_max_gap * 7)/8; // ewma
     }
-    D("exiting on abort");
+    ED("exiting on abort");
     sleep(1);
 
     return (0);
@@ -2780,7 +2787,7 @@ uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     dmax = parse_time(av[2]);
     if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax)
         return 1;
-    D("dmin %lld dmax %lld", (long long)dmin, (long long)dmax);
+    ED("dmin %lld dmax %lld", (long long)dmin, (long long)dmax);
     if (update_max_delay(q, dmax))
         return 1;
     dst->arg = ec_alloc(q, dst->ec, 3 * sizeof(uint64_t));

From bca3e12f5d494e0d613b196b1a42619b64ce87ff Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 26 Apr 2018 18:21:42 +0200
Subject: [PATCH 1727/2207] tlem: option for clients to terminate the server

---
 apps/tlem/tlem.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 52 insertions(+), 2 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index a9c19aa07..e38d377d1 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -563,6 +563,24 @@ ec_map(const char *fname, int *server)
     return ecf;
 }
 
+static int
+ec_waitterminate()
+{
+    if (ecf_fd < 0)
+        return 0;
+    if (lseek(ecf_fd, 0, SEEK_SET) < 0) {
+        ED("failed to rewind the session file: %s",
+                strerror(errno));
+        return 1;
+    }
+    if (lockf(ecf_fd, F_LOCK, 0) < 0) {
+        ED("failed to lock the session file %s",
+                strerror(errno));
+        return 1;
+    }
+    return 0;
+}
+
 static int
 ec_allowclients()
 {
@@ -606,6 +624,12 @@ ec_init(struct _qs *q, struct _ecs *ec, int server)
     return 0;
 }
 
+static void
+ec_terminate(struct _ecs *ec)
+{
+    ec->active = EC_NINST;
+}
+
 /* allocate sz bytes in the non-active config instance */
 static void *
 ec_alloc(struct _qs *q, struct _ec *ec, size_t sz)
@@ -628,6 +652,13 @@ static inline void
 ec_checkactive(struct _qs *q)
 {
     uint64_t i = q->ec->active;
+    if (unlikely(i >= EC_NINST)) {
+        /* setting ec_active to an out-of-bounds value is
+         * interpreted as an exit request
+         */
+        do_abort = 1;
+        return;
+    }
     if (i != q->ec_active) {
         asm volatile("" ::: "memory");
         __sync_synchronize();
@@ -1964,7 +1995,7 @@ main(int argc, char **argv)
     int cores[4];
     int hugepages = 0;
     char *sfname = NULL; /* session file name */
-    int server = 1;
+    int server = 1, terminate = 0;
     struct _ecf *ecf;
 
     nmctx_set_threadsafe();
@@ -2021,7 +2052,7 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:b:ci:vw:rd:Hs:l:q")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:b:ci:vw:rd:Hs:l:qa")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -2116,6 +2147,9 @@ main(int argc, char **argv)
                 }
                 sfname = optarg;
                 break;
+            case 'a':
+                terminate = 1;
+                break;
         }
     }
 
@@ -2127,6 +2161,9 @@ main(int argc, char **argv)
     if (ecf == NULL)
         exit(1);
 
+    if (terminate)
+        goto skip_args;
+
     /*
      * consistency checks for common arguments
      */
@@ -2334,12 +2371,17 @@ main(int argc, char **argv)
     if (r[1] == NULL)
         r[1] = r[0];
 
+skip_args:
     /* apply commands */
     j = 0;
     for (i = 0; i < EC_NOPTS; i++) { /* once per queue */
         struct _qs *q = &bp[i].q;
         if (ec_init(q, &ecf->sets[i], server))
             exit(1);
+        if (terminate) {
+            ec_terminate(&ecf->sets[i]);
+            continue;
+        }
         err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
         err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
         err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
@@ -2356,6 +2398,14 @@ main(int argc, char **argv)
         bp[i].q.rxstats = &ecf->stats[j++];
     }
 
+    if (terminate) {
+        int rv = 0;
+        ED("exiting due to -a");
+        if (!server)
+            rv = ec_waitterminate();
+        exit(rv);
+    }
+
     if (err) {
         ED("exiting due to %d error(s)", err);
         exit(1);

From 9212ca5cb9bace76ae54bf0b2cf8ac36d9325932 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 May 2018 15:33:04 +0200
Subject: [PATCH 1728/2207] tlem: reduce padding and buffer size

---
 apps/tlem/tlem.c | 57 +++++++++++++++++++++---------------------------
 1 file changed, 25 insertions(+), 32 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index e38d377d1..00c436629 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -372,7 +372,7 @@ struct h_pkt {
  * INFINITE_BW is supposed to be faster than what we support
  */
 #define INFINITE_BW	(200ULL*1000000*1000)
-#define PKT_PAD		(32)	/* padding on packets */
+#define PKT_PAD		(8)	/* padding on packets */
 #define MAX_PKT		(9200)	/* max packet size */
 
 struct _qs { /* shared queue */
@@ -1684,6 +1684,26 @@ cons(void *_pa)
     return NULL;
 }
 
+static uint64_t get_bufsize(uint64_t max_bps, uint64_t max_delay, uint64_t qsize, size_t hdrsz)
+{
+    uint64_t need;
+
+    /* allocate space for the queue:
+     * compute required bw*delay (adding 1ms for good measure),
+     * then add the queue size in bytes, then account for the headers
+     * and the packet expansion for padding
+     */
+
+    need = max_bps ? max_bps : INFINITE_BW;
+    need *= max_delay + 1000000;	/* delay is in nanoseconds */
+    need /= TIME_UNITS; /* total bits */
+    need /= 8; /* in bytes */
+    need += qsize; /* in bytes */
+    need += 3 * MAX_PKT; // safety
+    need *= (1 + 1.0 * (hdrsz + PKT_PAD) / 64);
+    return need;
+}
+
 /*
  * main thread for each direction.
  * Allocates memory for the queues, creates the prod() thread,
@@ -1706,27 +1726,9 @@ tlem_main(void *_a)
 
     a->zerocopy = a->zerocopy && (a->pa->mem == a->pb->mem);
     ND("------- zerocopy %ssupported", a->zerocopy ? "" : "NOT ");
-    /* allocate space for the queue:
-     * compute required bw*delay (adding 1ms for good measure),
-     * then add the queue size i bytes, then multiply by three due
-     * to the packet expansion for padding
-     */
 
-    need = q->ec->max_bps ? q->ec->max_bps : INFINITE_BW;
-    need *= q->ec->max_delay + 1000000;	/* delay is in nanoseconds */
-    need /= TIME_UNITS; /* total bits */
-    need /= 8; /* in bytes */
-    need += q->qsize; /* in bytes */
-    need += 3 * MAX_PKT; // safety
-
-    /*
-     * This is the memory strictly for packets.
-     * The size can increase a lot if we account for descriptors and
-     * rounding.
-     * In fact, the expansion factor can be up to a factor of 3
-     * for particularly bad situations (65-byte packets)
-     */
-    need *= 3; /* room for descriptors and padding */
+    need = get_bufsize(q->ec->max_bps, q->ec->max_delay,
+            q->qsize, sizeof(struct q_pkt));
 
     q->buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
     if (q->buf == MAP_FAILED) {
@@ -1740,18 +1742,9 @@ tlem_main(void *_a)
     }
     q->buflen = need;
 
-    /* Now we allocate the hold buffer for reordering, if needed.  Since this
-     * is accessed from only one thread (the producer), there are no caching
-     * issues and no need for padding.  The header is only 8 bytes, so the
-     * worst case overhead (all minimally sized packets) is 8/64;
-     */
     if (q->ec->max_hold_delay) {
-        need = q->ec->max_bps ? q->ec->max_bps : INFINITE_BW;
-        need *= q->ec->max_hold_delay + 1000000;
-        need /= TIME_UNITS;
-        need /= 8;
-        need *= (1 + 1.0*sizeof(struct h_pkt)/64);
-        need += 3 * MAX_PKT;
+        need = get_bufsize(q->ec->max_bps, q->ec->max_hold_delay,
+                0, sizeof(struct h_pkt));
 
         q->hold_buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
         if (q->hold_buf == MAP_FAILED) {

From 0c3bfce8c6a387ccde668d66d79c0de39c7cc367 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 10 May 2018 13:11:32 -0400
Subject: [PATCH 1729/2207] tlem: macro to compile out the max_lag option

---
 apps/tlem/tlem.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 00c436629..f5d02e341 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -24,6 +24,8 @@
  * SUCH DAMAGE.
  */
 
+#define WITH_MAX_LAG
+
 #if 0 /* COMMENT */
 
 This program implements TLEM, a bandwidth and delay emulator between two
@@ -926,8 +928,10 @@ struct pipe_args {
 	/* raw stats */
 	struct stats	*stats;
 
+#ifdef WITH_MAX_LAG
 	/* max delay before the consumer starts dropping packets */
 	int64_t		max_lag;
+#endif /* WITH_MAX_LAG */
 
 	struct _qs	q;
 };
@@ -1638,11 +1642,13 @@ cons(void *_pa)
             set_tns_now(&q->cons_now, q->t0);
             continue;
         }
+#ifdef WITH_MAX_LAG
         if (delta < -pa->max_lag) {
             q->rxstats->drop_packets++;
             q->rxstats->drop_bytes += p->pktlen;
             goto next;
         }
+#endif /* WITH_MAX_LAG */
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
                 p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
         if (pa->route_mode && !retrying) {
@@ -1983,7 +1989,10 @@ main(int argc, char **argv)
 
     struct pipe_args bp[EC_NOPTS];
     const char *d[EC_NOPTS], *b[EC_NOPTS], *l[EC_NOPTS], *q[EC_NOPTS], *r[EC_NOPTS],
-    *ifname[EC_NOPTS], *gw[EC_NOPTS], *cd[EC_NOPTS], *m[EC_NOPTS];
+    *ifname[EC_NOPTS], *gw[EC_NOPTS], *m[EC_NOPTS];
+#ifdef WITH_MAX_LAG
+    const char *cd[EC_NOPTS];
+#endif /* WITH_MAX_LAG */
     int ncpus;
     int cores[4];
     int hugepages = 0;
@@ -1999,7 +2008,9 @@ main(int argc, char **argv)
     bzero(q, sizeof(q));
     bzero(r, sizeof(r));
     bzero(gw, sizeof(gw));
+#ifdef WITH_MAX_LAG
     bzero(cd, sizeof(cd));
+#endif /* WITH_MAX_LAG */
     bzero(m, sizeof(m));
     bzero(ifname, sizeof(ifname));
 
@@ -2127,9 +2138,15 @@ main(int argc, char **argv)
             case 'r':
                 bp[0].route_mode = 1;
                 break;
+#ifdef WITH_MAX_LAG
             case 'd':
                 add_to(cd, EC_NOPTS, optarg, "-d too many times");
                 break;
+#else /* WITH_MAX_LAG */
+            case 'd':
+                ED("option 'd' ignored");
+                break;
+#endif /* WITH_MAX_LAG */
             case 'H':
                 hugepages = 1;
                 break;
@@ -2359,8 +2376,10 @@ main(int argc, char **argv)
         b[1] = b[0];
     if (l[1] == NULL)
         l[1] = l[0];
+#ifdef WITH_MAX_LAG
     if (cd[1] == NULL)
         cd[1] = cd[0];
+#endif /* WITH_MAX_LAG */
     if (r[1] == NULL)
         r[1] = r[0];
 
@@ -2379,6 +2398,7 @@ main(int argc, char **argv)
         err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
         err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
         err += cmd_apply(reorder_cfg, r[i], q, &q->c_reorder);
+#ifdef WITH_MAX_LAG
         if (cd[i] != NULL) {
             unsigned long max_lag = parse_time(cd[i]);
             if (max_lag == U_PARSE_ERR) {
@@ -2387,6 +2407,7 @@ main(int argc, char **argv)
                 bp[i].max_lag = max_lag;
             }
         }
+#endif /* WITH_MAX_LAG */
         bp[i].q.txstats = &ecf->stats[j++];
         bp[i].q.rxstats = &ecf->stats[j++];
     }
@@ -2439,11 +2460,13 @@ main(int argc, char **argv)
         bp[1].q.qsize = 50000;
     }
 
+#ifdef WITH_MAX_LAG
     for (i = 0; i < EC_NOPTS; i++) {
         if (bp[i].max_lag == 0) {
             bp[i].max_lag = 100000; /* 100 us */
         }
     }
+#endif /* WITH_MAX_LAG */
 
     /* assign arp command queues for route mode */
     bp[0].prod_arpq = &arpq[0];

From 260efd161155d3d3e9db60a3c999d21607f4fd0a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 10 May 2018 14:37:39 -0400
Subject: [PATCH 1730/2207] tlem: update producer time before dropping packets

Before this patch, tlem was not updating the producer current time
when trying to remove packets from a full bandwidth-limitation queue.
Packets would then stay in the queue for too much time, causing al lot
of other packets to be unduly dropped. This was breaking the bandwidh
emulation, unless the queue was set to a large enough size to store the
packets arrived between two current-time updates.
---
 apps/tlem/tlem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index f5d02e341..a0a8e8433 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1399,6 +1399,7 @@ prod_procpkt(struct _qs *q)
     if (no_room(q)) {
         q->tail = q->prod_tail; /* notify */
         usleep(1); // XXX give cons a chance to run ?
+        set_tns_now(&q->prod_now, q->t0);
         if (no_room(q)) {/* try to run drop-free once */
             q->txstats->drop_packets++;
             q->txstats->drop_bytes += q->cur_len;

From 41334a50dc5c5371f1c2337c97e09f20fc914087 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 14 May 2018 14:15:43 -0400
Subject: [PATCH 1731/2207] tlem: fix wrong index used in split_arg

---
 apps/tlem/tlem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index a0a8e8433..edbeea6a7 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1854,8 +1854,8 @@ split_arg(const char *src, int *_ac)
     }
     if (verbose > 2)
         for (i = 0; i < ac; i++) fprintf(stderr, "%d: <%s>\n", i, av[i]);
-    av[i++] = NULL;
-    av[i++] = my;
+    av[ac] = NULL;
+    av[ac+1] = my;
     *_ac = ac;
     return av;
 }

From fa702ba739dc0231944e6fe4a374810a5c18d55f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 15 May 2018 13:57:27 -0400
Subject: [PATCH 1732/2207] tlem: increase the config size to accomodate ber

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index edbeea6a7..92a162847 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -269,7 +269,7 @@ struct _eci {
         struct _ec      ec_bw;
         struct _ec      ec_loss;
         struct _ec      ec_reorder;
-#define EC_DATASZ       (1U << 14)
+#define EC_DATASZ       (1U << 16)
         char            ec_data[EC_DATASZ];
 };
 

From beb064baa6ccb0cb0e9694a0505f0d8b2c041648 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 18 May 2018 03:36:36 -0400
Subject: [PATCH 1733/2207] tlem: print buffer sizes in human readable form

---
 apps/tlem/tlem.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 92a162847..d4f1ac6fc 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -191,6 +191,8 @@ static int do_abort = 0;
 #endif
 #endif
 
+#include "ctrs.h"	/* norm() */
+
 #ifdef __APPLE__
 #define cpuset_t        uint64_t        // XXX
 static inline void CPU_ZERO(cpuset_t *p)
@@ -1723,6 +1725,7 @@ tlem_main(void *_a)
     struct _qs *q = &a->q;
     uint64_t need;
     int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+    char b1[40], b2[40] = "0";
 
     setaffinity(a->cons_core);
     set_tns_now(&q->t0, 0); /* starting reference */
@@ -1736,12 +1739,14 @@ tlem_main(void *_a)
 
     need = get_bufsize(q->ec->max_bps, q->ec->max_delay,
             q->qsize, sizeof(struct q_pkt));
+    norm(b1, need, 1);
 
     q->buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
     if (q->buf == MAP_FAILED) {
-        ED("alloc %lld bytes for queue failed, exiting", (long long)need);
+        ED("alloc %s bytes for queue failed, exiting", b1);
         nmport_close(a->pa);
         nmport_close(a->pb);
+        do_abort = 1;
         return(NULL);
     }
     if (mlock(q->buf, need) < 0) {
@@ -1752,10 +1757,11 @@ tlem_main(void *_a)
     if (q->ec->max_hold_delay) {
         need = get_bufsize(q->ec->max_bps, q->ec->max_hold_delay,
                 0, sizeof(struct h_pkt));
+        norm(b2, need, 1);
 
         q->hold_buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
         if (q->hold_buf == MAP_FAILED) {
-            ED("alloc %lld bytes for  failed, exiting", (long long)need);
+            ED("alloc %s bytes for  failed, exiting", b2);
             nmport_close(a->pa);
             nmport_close(a->pb);
             do_abort = 1;
@@ -1768,11 +1774,11 @@ tlem_main(void *_a)
     }
 
     ED("----\n\t%s -> %s :  bps %lld delay %s loss %s queue %lld bytes"
-            "\n\tbuffer   %10llu bytes\n\thold-buf %10lld bytes",
+            "\n\tbuffer   %s bytes\n\thold-buf %s bytes",
             q->prod_ifname, q->cons_ifname,
             (long long)q->ec->max_bps, q->c_delay.optarg, q->c_loss.optarg,
-            (long long)q->qsize, (unsigned long long)q->buflen,
-            (unsigned long long)q->hold_buflen);
+            (long long)q->qsize, b1,
+            b2);
 
 
     q->src_port = a->pa;

From 20df3393a4131b00eaca3f16e1ad12cd3f3e0f59 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 18 May 2018 04:00:23 -0400
Subject: [PATCH 1734/2207] tlem: fix overflow in buffer size computation

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index d4f1ac6fc..8d7d4d3cf 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1695,7 +1695,7 @@ cons(void *_pa)
 
 static uint64_t get_bufsize(uint64_t max_bps, uint64_t max_delay, uint64_t qsize, size_t hdrsz)
 {
-    uint64_t need;
+    double need;
 
     /* allocate space for the queue:
      * compute required bw*delay (adding 1ms for good measure),

From c03d3a853b0aa44e3e38f33a4281907e016aa50e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 18 May 2018 04:19:04 -0400
Subject: [PATCH 1735/2207] tlem: drop hugepages if allocation fails, and retry

---
 apps/tlem/tlem.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 8d7d4d3cf..a8b6f6d5b 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1741,9 +1741,15 @@ tlem_main(void *_a)
             q->qsize, sizeof(struct q_pkt));
     norm(b1, need, 1);
 
+retry:
     q->buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
     if (q->buf == MAP_FAILED) {
         ED("alloc %s bytes for queue failed, exiting", b1);
+        if (mmap_flags & MAP_HUGETLB) {
+            ED("trying again without hugepages");
+            mmap_flags &= ~MAP_HUGETLB;
+            goto retry;
+        }
         nmport_close(a->pa);
         nmport_close(a->pb);
         do_abort = 1;
@@ -1759,9 +1765,15 @@ tlem_main(void *_a)
                 0, sizeof(struct h_pkt));
         norm(b2, need, 1);
 
+retry2:
         q->hold_buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
         if (q->hold_buf == MAP_FAILED) {
-            ED("alloc %s bytes for  failed, exiting", b2);
+            ED("alloc %s bytes for hold-buf failed, exiting", b2);
+            if (mmap_flags & MAP_HUGETLB) {
+                ED("trying again without hugepages");
+                mmap_flags &= ~MAP_HUGETLB;
+                goto retry2;
+            }
             nmport_close(a->pa);
             nmport_close(a->pb);
             do_abort = 1;

From 6fc172749f4f6de0a1728e10b881e5cea8dc9535 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 20 May 2018 14:51:57 +0200
Subject: [PATCH 1736/2207] tlem: support NS_MOREFRAG

---
 apps/tlem/tlem.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index a8b6f6d5b..35aa51c07 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -378,6 +378,12 @@ struct h_pkt {
 #define INFINITE_BW	(200ULL*1000000*1000)
 #define PKT_PAD		(8)	/* padding on packets */
 #define MAX_PKT		(9200)	/* max packet size */
+#define MAX_FRAGS       (1000)  /* max number of fragments */
+
+struct _frag {
+       char           *buf;
+       unsigned int    len;
+};
 
 struct _qs { /* shared queue */
 	uint64_t	t0;	/* start of times */
@@ -432,6 +438,8 @@ struct _qs { /* shared queue */
 	/* producer's fields controlling the queueing */
 	char *		cur_pkt;	/* current packet being analysed */
 	uint32_t	cur_len;	/* length of current packet */
+        struct _frag    cur_frags[MAX_FRAGS];
+        int             cur_nfrags;
 
 	int		cur_drop;	/* 1 if current  packet should be dropped. */
 		/*
@@ -1097,9 +1105,19 @@ static inline int
 enq(struct _qs *q)
 {
     struct q_pkt *p = pkt_at(q, q->prod_tail);
+    char *dst = (char *)(p + 1);
+    unsigned int len = q->cur_frags[0].len;
+    int i;
 
     /* hopefully prefetch has been done ahead */
-    nm_pkt_copy(q->cur_pkt, (char *)(p+1), q->cur_len);
+    nm_pkt_copy(q->cur_pkt, dst, len);
+    /* copy the fragments, if any */
+    for (i = 1; i < q->cur_nfrags; i++) {
+        dst += len;
+        len = q->cur_frags[i].len;
+        /* we cannot use nm_pkt_copy, since dst may be unaligned */
+        memcpy(dst, q->cur_frags[i].buf, len);
+    }
     p->pktlen = q->cur_len;
     p->pt_qout = q->qt_qout;
     p->pt_tx = q->qt_tx;
@@ -1234,6 +1252,7 @@ scan_ring(struct _qs *q, int next /* bool */)
     struct netmap_slot *rs;
     struct netmap_ring *rxr = q->rxring; /* invalid if next == 0 */
     struct nmport_d *pa = q->src_port;
+    int nfrags;
 
     /* fast path for the first two */
     if (likely(next != 0)) { /* current ring */
@@ -1268,8 +1287,27 @@ scan_ring(struct _qs *q, int next /* bool */)
         D("wrong len rx[%d] len %d", rxr->cur, rs->len);
         rs->len = 0;
     }
-    q->cur_pkt = NETMAP_BUF(rxr, rs->buf_idx);
-    q->cur_len = rs->len;
+    /* netmap makes sure that we do not receive incomplete packets */
+    nfrags = 0;
+    q->cur_len = 0;
+    do {
+        struct _frag *f = &q->cur_frags[nfrags];
+        f->buf = NETMAP_BUF(rxr, rs->buf_idx);
+        f->len = rs->len;
+        q->cur_len += f->len;
+        nfrags++;
+        if (!(rs->flags & NS_MOREFRAG))
+            break;
+        rxr->cur = nm_ring_next(rxr, rxr->cur);
+        rs = &rxr->slot[rxr->cur];
+    } while (nfrags < MAX_FRAGS);
+    if (unlikely(nfrags >= MAX_FRAGS)) {
+        RD(5, "WARNING: too many fragments: truncating packet");
+        // XXX do something here
+    }
+    q->cur_pkt = q->cur_frags[0].buf;
+    q->cur_nfrags = nfrags;
+    rxr->head = rxr->cur;
     //prefetch_packet(rxr, 1); not much better than prefetching q->cur_pkt, one line
     __builtin_prefetch(q->cur_pkt);
     __builtin_prefetch(rs+1); /* one row ahead ? */
@@ -1319,6 +1357,9 @@ reorder_release(struct _qs *q)
     h = (struct h_pkt *)(q->hold_buf + q->hold_head);
     q->cur_pkt = q->hold_buf + q->hold_head + sizeof(*h);
     q->cur_len = h->pktlen;
+    q->cur_frags[0].buf = q->cur_pkt;
+    q->cur_frags[0].len = q->cur_len;
+    q->cur_nfrags = 1;
     q->hold_head += sizeof(*h) + q->cur_len;
     if (unlikely(q->hold_head >= q->hold_buflen))
         q->hold_head = 0;

From af9a5985c1b1ee9b40a1f08c3bc0b1a89781f98d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 6 Jun 2018 10:57:29 +0200
Subject: [PATCH 1737/2207] tlem: allow_drop option

---
 apps/tlem/tlem.c | 54 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 50 insertions(+), 4 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 35aa51c07..b5f38bbd8 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -271,6 +271,7 @@ struct _eci {
         struct _ec      ec_bw;
         struct _ec      ec_loss;
         struct _ec      ec_reorder;
+	int		ec_allow_drop;
 #define EC_DATASZ       (1U << 16)
         char            ec_data[EC_DATASZ];
 };
@@ -463,6 +464,21 @@ struct _qs { /* shared queue */
 		 * The code makes sure that there is no reordering and possibly
 		 * bumps the output time as needed.
 		 */
+	int		allow_drop;	/* improve delay accuracy by dropping packets */
+		/*
+		 * by default, TLEM adjusts the cur_delay of each packet to
+		 * avoid reordering, thus sacrificing the delay emulation
+		 * accuracy.  In 'allow_drop' mode we try to improve the
+		 * accuracy by dropping the packets that should be reordered,
+		 * instead of queueing them.
+		 */
+	int		reuse_delay;	/* reuse the last computed delay */
+		/*
+		 * In 'allow_drop' mode we reuse the last computed delay until
+		 * we find a packet that can be sent in order. If we kept
+		 * recomputing the delay, instead, we would skew the
+		 * distribution towards larger values.
+		 */
 
 	/* producers's fields for reordering */
 	uint64_t	cur_hold_delay; /* reordering delay (ns) from c_reorder.run() */
@@ -1458,11 +1474,23 @@ prod_procpkt(struct _qs *q)
         q->txstats->drop_bytes += q->cur_len;
         return;
     }
-    q->c_delay.run(q, &q->c_delay); /* compute delay */
+    if (!q->reuse_delay)
+        q->c_delay.run(q, &q->c_delay); /* compute delay */
     t_tx = q->qt_qout + q->cur_delay;
     ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
     /* insure no reordering and spacing by transmission time */
-    q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt;
+    if (t_tx < q->qt_tx + tt) {
+        if (q->allow_drop) {
+            q->qt_qout -= tt;
+            q->txstats->drop_packets++;
+            q->txstats->drop_bytes += q->cur_len;
+            q->reuse_delay = 1;
+            return;
+        }
+        t_tx = q->qt_tx + tt;
+    }
+    q->reuse_delay = 0;
+    q->qt_tx = t_tx;
     enq(q);
     q->txstats->packets++;
     q->txstats->bytes += q->cur_len;
@@ -2049,7 +2077,7 @@ main(int argc, char **argv)
 
     struct pipe_args bp[EC_NOPTS];
     const char *d[EC_NOPTS], *b[EC_NOPTS], *l[EC_NOPTS], *q[EC_NOPTS], *r[EC_NOPTS],
-    *ifname[EC_NOPTS], *gw[EC_NOPTS], *m[EC_NOPTS];
+    *ifname[EC_NOPTS], *gw[EC_NOPTS], *m[EC_NOPTS], *p[EC_NOPTS];
 #ifdef WITH_MAX_LAG
     const char *cd[EC_NOPTS];
 #endif /* WITH_MAX_LAG */
@@ -2072,6 +2100,7 @@ main(int argc, char **argv)
     bzero(cd, sizeof(cd));
 #endif /* WITH_MAX_LAG */
     bzero(m, sizeof(m));
+    bzero(p, sizeof(p));
     bzero(ifname, sizeof(ifname));
 
     fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
@@ -2116,7 +2145,7 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:b:ci:vw:rd:Hs:l:qa")) != -1) {
+    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:P:b:ci:vw:rd:Hs:l:qap")) != -1) {
         switch (ch) {
             default:
                 D("bad option %c %s", ch, optarg);
@@ -2175,6 +2204,9 @@ main(int argc, char **argv)
             case 'M': /* max bw, delay and hold-time */
                 add_to(m, EC_NOPTS, optarg, "-M too many times");
                 break;
+            case 'P': /* allow dropping to obtain precise delay */
+                add_to(p, EC_NOPTS, optarg, "-P too many times");
+                break;
             case 'b':	/* burst */
                 bp[0].q.burst = atoi(optarg);
                 break;
@@ -2442,6 +2474,8 @@ main(int argc, char **argv)
 #endif /* WITH_MAX_LAG */
     if (r[1] == NULL)
         r[1] = r[0];
+    if (p[1] == NULL)
+        p[1] = p[0];
 
 skip_args:
     /* apply commands */
@@ -2468,6 +2502,17 @@ main(int argc, char **argv)
             }
         }
 #endif /* WITH_MAX_LAG */
+        if (p[i] != NULL) {
+            int j = bp[i].q.ec_active;
+            struct _eci *a = &bp[i].q.ec->instances[j];
+            if (!strcmp(p[i], "0") || !strcmp(p[i], "1")) {
+                a->ec_allow_drop = atoi(p[i]);
+                bp[i].q.allow_drop = a->ec_allow_drop;
+            } else {
+                ED("-P expects either 0 or 1");
+                err++;
+            }
+        }
         bp[i].q.txstats = &ecf->stats[j++];
         bp[i].q.rxstats = &ecf->stats[j++];
     }
@@ -3308,4 +3353,5 @@ ec_activate(struct _qs *q)
         q->c_reorder.run = null_run_fn;
     }
     q->c_reorder.ec = &a->ec_reorder;
+    q->allow_drop = a->ec_allow_drop;
 }

From dbedaf97998ed60b70e49bd90392f328d85c7d84 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jun 2018 14:10:09 -0400
Subject: [PATCH 1738/2207] tlem: show core roles

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index b5f38bbd8..a64d70f03 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2457,7 +2457,7 @@ main(int argc, char **argv)
         bp[0].prod_core = cores[1];
         bp[1].cons_core = cores[2];
         bp[1].prod_core = cores[3];
-        ED("running on cores %d %d %d %d", cores[0], cores[1], cores[2], cores[3]);
+        ED("running on cores %d->%d %d->%d", cores[1], cores[0], cores[3], cores[2]);
 
     }
 

From 3d969cd876ee04547778075d1563d18e43b17d5c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 12 Jul 2018 17:27:10 +0200
Subject: [PATCH 1739/2207] tlem: uniform handling of per-dir options

---
 apps/tlem/tlem.c | 182 +++++++++++++++++++++--------------------------
 1 file changed, 83 insertions(+), 99 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index a64d70f03..8ae5a19e9 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2010,11 +2010,11 @@ static uint64_t parse_qsize(const char *arg);
  */
 
 static void
-add_to(const char ** v, int l, const char *arg, const char *msg)
+add_to(const char ** v, int l, const char *arg, char opt)
 {
     for (; l > 0 && *v != NULL ; l--, v++);
     if (l == 0) {
-        ED("%s %s", msg, arg);
+        ED("-%c too many times: %s", opt, arg);
         exit(1);
     }
     *v = arg;
@@ -2032,6 +2032,9 @@ set_max(const char *arg, struct _qs *q)
     char **av;
     uint64_t delay = 0, bps = 0, hold = 0;
 
+    if (arg == NULL)
+        return 0;
+
     av = split_arg(arg, &ac);
     if (av == NULL || ac < 1 || ac > 3) {
         ND("arg %p av %p ac %d", arg, av, ac);
@@ -2069,6 +2072,16 @@ set_max(const char *arg, struct _qs *q)
     return 0;
 }
 
+/* otions that can be specified for each direction */
+struct dir_opt {
+    char opt;
+    int  flags;
+#define DOPT_CLONE  1	/* clone if only one is given */
+#define DOPT_IGNOR  2	/* ignore the option */
+    const char *arg[EC_NOPTS];
+};
+#define MAXOPTS 1024
+#define DOPT(a, f)  { .opt = a, .flags = f, .arg = { NULL, NULL } }
 
 int
 main(int argc, char **argv)
@@ -2076,32 +2089,44 @@ main(int argc, char **argv)
     int ch, i, j, err=0;
 
     struct pipe_args bp[EC_NOPTS];
-    const char *d[EC_NOPTS], *b[EC_NOPTS], *l[EC_NOPTS], *q[EC_NOPTS], *r[EC_NOPTS],
-    *ifname[EC_NOPTS], *gw[EC_NOPTS], *m[EC_NOPTS], *p[EC_NOPTS];
+    struct dir_opt dopt[] = {
+        DOPT('B', DOPT_CLONE), /* bandwidth in bps */
+        DOPT('D', DOPT_CLONE), /* delay in seconds (float) */
+        DOPT('Q', DOPT_CLONE), /* qsize in bytes */
+        DOPT('L', DOPT_CLONE), /* loss probability */
+        DOPT('R', DOPT_CLONE), /* reordering */
+        DOPT('G', 0),	       /* default gateway */
+        DOPT('M', DOPT_CLONE), /* max bw, delay and hold-time */
+        DOPT('P', DOPT_CLONE), /* allow dropping to obtain precise delay */
+        DOPT('i', 0),	       /* interface */
 #ifdef WITH_MAX_LAG
-    const char *cd[EC_NOPTS];
+        DOPT('d', DOPT_CLONE),
+#else
+        DOPT('d', DOPT_IGNOR),
 #endif /* WITH_MAX_LAG */
+        DOPT(0, 0)  /* end of options */
+    };
+    struct dir_opt *invdopt[256], *scandopt;
     int ncpus;
     int cores[4];
     int hugepages = 0;
     char *sfname = NULL; /* session file name */
     int server = 1, terminate = 0;
     struct _ecf *ecf;
+    char doptstr[MAXOPTS], *strp = doptstr;
+    const char **ifname;
 
     nmctx_set_threadsafe();
 
-    bzero(d, sizeof(d));
-    bzero(b, sizeof(b));
-    bzero(l, sizeof(l));
-    bzero(q, sizeof(q));
-    bzero(r, sizeof(r));
-    bzero(gw, sizeof(gw));
-#ifdef WITH_MAX_LAG
-    bzero(cd, sizeof(cd));
-#endif /* WITH_MAX_LAG */
-    bzero(m, sizeof(m));
-    bzero(p, sizeof(p));
-    bzero(ifname, sizeof(ifname));
+    bzero(invdopt, sizeof(invdopt));
+    for (scandopt = dopt; scandopt->opt; scandopt++) {
+        bzero(scandopt->arg, sizeof(scandopt->arg));
+        invdopt[(unsigned int)scandopt->opt] = scandopt;
+        *strp++ = scandopt->opt;
+        *strp++ = ':';
+    }
+    *strp = '\0';
+    ifname = invdopt['i']->arg;
 
     fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
 
@@ -2145,13 +2170,12 @@ main(int argc, char **argv)
     // r	route mode
     // d	max consumer delay
 
-    while ( (ch = getopt(argc, argv, "B:C:D:L:R:Q:G:M:P:b:ci:vw:rd:Hs:l:qap")) != -1) {
+    strcat(doptstr, "C:b:cvw:rHs:qa");
+    while ( (ch = getopt(argc, argv, doptstr)) != -1) {
         switch (ch) {
-            default:
-                D("bad option %c %s", ch, optarg);
-                usage();
+            case '?':
+                ED("unknown option '-%c'", optopt);
                 break;
-
             case 'C': /* CPU placement, up to 4 arguments */
                 {
                     int ac = 0;
@@ -2180,40 +2204,10 @@ main(int argc, char **argv)
                 }
                 break;
 
-            case 'B': /* bandwidth in bps */
-                add_to(b, EC_NOPTS, optarg, "-B too many times");
-                break;
-
-            case 'D': /* delay in seconds (float) */
-                add_to(d, EC_NOPTS, optarg, "-D too many times");
-                break;
-
-            case 'Q': /* qsize in bytes */
-                add_to(q, EC_NOPTS, optarg, "-Q too many times");
-                break;
-
-            case 'L': /* loss probability */
-                add_to(l, EC_NOPTS, optarg, "-L too many times");
-                break;
-            case 'R': /* reordering */
-                add_to(r, EC_NOPTS, optarg, "-R too many times");
-                break;
-            case 'G': /* default gateway */
-                add_to(gw, EC_NOPTS, optarg, "-G too many times");
-                break;
-            case 'M': /* max bw, delay and hold-time */
-                add_to(m, EC_NOPTS, optarg, "-M too many times");
-                break;
-            case 'P': /* allow dropping to obtain precise delay */
-                add_to(p, EC_NOPTS, optarg, "-P too many times");
-                break;
             case 'b':	/* burst */
                 bp[0].q.burst = atoi(optarg);
                 break;
 
-            case 'i':	/* interface */
-                add_to(ifname, EC_NOPTS, optarg, "-i too many times");
-                break;
             case 'c':
                 bp[0].zerocopy = 0; /* do not zerocopy */
                 break;
@@ -2230,15 +2224,6 @@ main(int argc, char **argv)
             case 'r':
                 bp[0].route_mode = 1;
                 break;
-#ifdef WITH_MAX_LAG
-            case 'd':
-                add_to(cd, EC_NOPTS, optarg, "-d too many times");
-                break;
-#else /* WITH_MAX_LAG */
-            case 'd':
-                ED("option 'd' ignored");
-                break;
-#endif /* WITH_MAX_LAG */
             case 'H':
                 hugepages = 1;
                 break;
@@ -2252,6 +2237,17 @@ main(int argc, char **argv)
             case 'a':
                 terminate = 1;
                 break;
+            default:
+                if (invdopt[ch]) {
+                    struct dir_opt *o = invdopt[ch];
+                    if (!(o->flags & DOPT_IGNOR)) {
+                        add_to(o->arg, EC_NOPTS, optarg, o->opt);
+                    } else {
+                        ED("option '-%c' ignored", o->opt);
+                    }
+                } else {
+                    ED("unknown option '-%c'", ch);
+                }
         }
     }
 
@@ -2392,15 +2388,16 @@ main(int argc, char **argv)
                 ip->ip_subnet = ip->ip_addr & ip->ip_mask;
 
                 /* default gateway, if any */
-                if (gw[i]) {
+                if (invdopt['G']->arg[i]) {
+                    const char *gw = invdopt['G']->arg[i];
                     struct ipv4_info *ip = &ipv4[i];
                     struct in_addr a;
-                    if (!inet_aton(gw[i], &a)) {
-                        ED("not a valid IP address: %s", gw[i]);
+                    if (!inet_aton(gw, &a)) {
+                        ED("not a valid IP address: %s", gw);
                         usage();
                     }
                     if ((a.s_addr & ip->ip_mask) != ip->ip_subnet) {
-                        ED("gateway %s unreachable", gw[i]);
+                        ED("gateway %s unreachable", gw);
                         usage();
                     }
                     ip->ip_gw = a.s_addr;
@@ -2462,20 +2459,14 @@ main(int argc, char **argv)
     }
 
     /* use same parameters for both directions if needed */
-    if (d[1] == NULL)
-        d[1] = d[0];
-    if (b[1] == NULL)
-        b[1] = b[0];
-    if (l[1] == NULL)
-        l[1] = l[0];
-#ifdef WITH_MAX_LAG
-    if (cd[1] == NULL)
-        cd[1] = cd[0];
-#endif /* WITH_MAX_LAG */
-    if (r[1] == NULL)
-        r[1] = r[0];
-    if (p[1] == NULL)
-        p[1] = p[0];
+    if (invdopt['Q']->arg[0] == NULL)
+        invdopt['Q']->arg[0] = "0";
+    for (scandopt = dopt; scandopt->opt; scandopt++) {
+        if (!(scandopt->flags & DOPT_CLONE))
+            continue;
+        if (scandopt->arg[1] == NULL)
+            scandopt->arg[1] = scandopt->arg[0];
+    }
 
 skip_args:
     /* apply commands */
@@ -2488,13 +2479,13 @@ main(int argc, char **argv)
             ec_terminate(&ecf->sets[i]);
             continue;
         }
-        err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
-        err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
-        err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
-        err += cmd_apply(reorder_cfg, r[i], q, &q->c_reorder);
+        err += cmd_apply(delay_cfg, invdopt['D']->arg[i], q, &q->c_delay);
+        err += cmd_apply(bw_cfg, invdopt['B']->arg[i], q, &q->c_bw);
+        err += cmd_apply(loss_cfg, invdopt['L']->arg[i], q, &q->c_loss);
+        err += cmd_apply(reorder_cfg, invdopt['R']->arg[i], q, &q->c_reorder);
 #ifdef WITH_MAX_LAG
-        if (cd[i] != NULL) {
-            unsigned long max_lag = parse_time(cd[i]);
+        if (invdopt['d']->arg[i] != NULL) {
+            unsigned long max_lag = parse_time(invdopt[(int)'d']->arg[i]);
             if (max_lag == U_PARSE_ERR) {
                 err++;
             } else {
@@ -2502,11 +2493,12 @@ main(int argc, char **argv)
             }
         }
 #endif /* WITH_MAX_LAG */
-        if (p[i] != NULL) {
+        if (invdopt['P']->arg[i] != NULL) {
+            const char *p = invdopt['P']->arg[i];
             int j = bp[i].q.ec_active;
             struct _eci *a = &bp[i].q.ec->instances[j];
-            if (!strcmp(p[i], "0") || !strcmp(p[i], "1")) {
-                a->ec_allow_drop = atoi(p[i]);
+            if (!strcmp(p, "0") || !strcmp(p, "1")) {
+                a->ec_allow_drop = atoi(p);
                 bp[i].q.allow_drop = a->ec_allow_drop;
             } else {
                 ED("-P expects either 0 or 1");
@@ -2532,12 +2524,8 @@ main(int argc, char **argv)
 
     if (server) {
         /* set the maximum values */
-        if (m[0] == NULL)
-            m[0] = "0";
-        if (m[1] == NULL)
-            m[1] = m[0];
         for (i = 0; i < EC_NOPTS; i++) {
-            if (set_max(m[i], &bp[i].q))
+            if (set_max(invdopt['M']->arg[i], &bp[i].q))
                 exit(1);
         }
         /* now the clients may send new configurations */
@@ -2549,12 +2537,8 @@ main(int argc, char **argv)
         exit(0);
     }
 
-    if (q[0] == NULL)
-        q[0] = "0";
-    if (q[1] == NULL)
-        q[1] = q[0];
-    bp[0].q.qsize = parse_qsize(q[0]);
-    bp[1].q.qsize = parse_qsize(q[1]);
+    bp[0].q.qsize = parse_qsize(invdopt['Q']->arg[0]);
+    bp[1].q.qsize = parse_qsize(invdopt['Q']->arg[1]);
 
     if (bp[0].q.qsize == 0) {
         ED("qsize= 0 is not valid, set to 50k");

From c6b6865c6954a18eb907cf33faa6f23e6fdae8a8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 16 Jul 2018 16:16:06 +0200
Subject: [PATCH 1740/2207] tlem: optional delay offsets

---
 apps/tlem/tlem.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 8ae5a19e9..e361df04e 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -271,7 +271,8 @@ struct _eci {
         struct _ec      ec_bw;
         struct _ec      ec_loss;
         struct _ec      ec_reorder;
-	int		ec_allow_drop;
+	uint64_t	ec_delay_offset;
+	long		ec_allow_drop;
 #define EC_DATASZ       (1U << 16)
         char            ec_data[EC_DATASZ];
 };
@@ -479,6 +480,7 @@ struct _qs { /* shared queue */
 		 * recomputing the delay, instead, we would skew the
 		 * distribution towards larger values.
 		 */
+	uint64_t	delay_offset;	/* to be subtracted from cur_delay */
 
 	/* producers's fields for reordering */
 	uint64_t	cur_hold_delay; /* reordering delay (ns) from c_reorder.run() */
@@ -1474,8 +1476,14 @@ prod_procpkt(struct _qs *q)
         q->txstats->drop_bytes += q->cur_len;
         return;
     }
-    if (!q->reuse_delay)
+    if (!q->reuse_delay) {
         q->c_delay.run(q, &q->c_delay); /* compute delay */
+        if (q->delay_offset > q->cur_delay) {
+            q->cur_delay = 0;
+        } else {
+            q->cur_delay -= q->delay_offset;
+        }
+    }
     t_tx = q->qt_qout + q->cur_delay;
     ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
     /* insure no reordering and spacing by transmission time */
@@ -2099,6 +2107,7 @@ main(int argc, char **argv)
         DOPT('M', DOPT_CLONE), /* max bw, delay and hold-time */
         DOPT('P', DOPT_CLONE), /* allow dropping to obtain precise delay */
         DOPT('i', 0),	       /* interface */
+        DOPT('O', DOPT_CLONE), /* delay offset */
 #ifdef WITH_MAX_LAG
         DOPT('d', DOPT_CLONE),
 #else
@@ -2473,12 +2482,15 @@ main(int argc, char **argv)
     j = 0;
     for (i = 0; i < EC_NOPTS; i++) { /* once per queue */
         struct _qs *q = &bp[i].q;
+        struct _eci *a;
+
         if (ec_init(q, &ecf->sets[i], server))
             exit(1);
         if (terminate) {
             ec_terminate(&ecf->sets[i]);
             continue;
         }
+        a = &q->ec->instances[q->ec_active];
         err += cmd_apply(delay_cfg, invdopt['D']->arg[i], q, &q->c_delay);
         err += cmd_apply(bw_cfg, invdopt['B']->arg[i], q, &q->c_bw);
         err += cmd_apply(loss_cfg, invdopt['L']->arg[i], q, &q->c_loss);
@@ -2495,16 +2507,18 @@ main(int argc, char **argv)
 #endif /* WITH_MAX_LAG */
         if (invdopt['P']->arg[i] != NULL) {
             const char *p = invdopt['P']->arg[i];
-            int j = bp[i].q.ec_active;
-            struct _eci *a = &bp[i].q.ec->instances[j];
             if (!strcmp(p, "0") || !strcmp(p, "1")) {
                 a->ec_allow_drop = atoi(p);
-                bp[i].q.allow_drop = a->ec_allow_drop;
+                q->allow_drop = a->ec_allow_drop;
             } else {
                 ED("-P expects either 0 or 1");
                 err++;
             }
         }
+        if (invdopt['O']->arg[i] != NULL) {
+            a->ec_delay_offset = parse_time(invdopt['O']->arg[i]);
+            q->delay_offset = a->ec_delay_offset;
+        }
         bp[i].q.txstats = &ecf->stats[j++];
         bp[i].q.rxstats = &ecf->stats[j++];
     }
@@ -3338,4 +3352,5 @@ ec_activate(struct _qs *q)
     }
     q->c_reorder.ec = &a->ec_reorder;
     q->allow_drop = a->ec_allow_drop;
+    q->delay_offset = a->ec_delay_offset;
 }

From b5be7087855081c41452002a34a52a137a93ff5c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 22 Jul 2018 19:01:18 +0200
Subject: [PATCH 1741/2207] tlem: avoid filtering of random delays

---
 apps/tlem/tlem.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index e361df04e..645bf81da 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1488,16 +1488,17 @@ prod_procpkt(struct _qs *q)
     ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx);
     /* insure no reordering and spacing by transmission time */
     if (t_tx < q->qt_tx + tt) {
+        q->reuse_delay = 1;
         if (q->allow_drop) {
             q->qt_qout -= tt;
             q->txstats->drop_packets++;
             q->txstats->drop_bytes += q->cur_len;
-            q->reuse_delay = 1;
             return;
         }
         t_tx = q->qt_tx + tt;
+    } else {
+        q->reuse_delay = 0;
     }
-    q->reuse_delay = 0;
     q->qt_tx = t_tx;
     enq(q);
     q->txstats->packets++;

From 8b8a8f23b0dc615dfe3c8b876c80f973fcee5d4d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 30 Jul 2018 13:15:41 +0200
Subject: [PATCH 1742/2207] tlem: accept 'none' to disable impairments

---
 apps/tlem/tlem.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 645bf81da..3aa533532 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1973,6 +1973,10 @@ cmd_apply(const struct _cfg *a, const char *arg, struct _qs *q, struct _cfg *dst
         ED("program error - invalid arguments");
         exit(1);
     }
+    if (!strcmp(arg, "none")) {
+        dst->ec->ec_valid = 0; /* use default */
+        return 0;
+    }
     av = split_arg(arg, &ac);
     if (av == NULL)
         goto out; /* error */

From 11dcc696d32846c6d5371f5c9ec7631458b4fb90 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 30 Jul 2018 16:23:22 +0200
Subject: [PATCH 1743/2207] tlem: inter-packet delay

---
 apps/tlem/tlem.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 3aa533532..6b8f74509 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -3035,6 +3035,48 @@ exp_delay_run(struct _qs *q, struct _cfg *arg)
     return 0;
 }
 
+static int
+interpacket_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
+{
+    uint64_t delay, gmin, gmax, *d;
+    if (strcmp(av[0], "inter-packet") != 0)
+        return 2; /* not recognized */
+    if (ac != 4)
+        return 1; /* error */
+    gmin = parse_time(av[1]);
+    gmax = parse_time(av[2]);
+    delay = parse_time(av[3]);
+    if (gmin == U_PARSE_ERR || gmax == U_PARSE_ERR || delay == U_PARSE_ERR
+            || gmin > gmax)
+        return 1;
+    ED("min-gap %lld max-gap %lld delay %lld",
+            (long long)gmin, (long long)gmax, (long long)delay);
+    if (update_max_delay(q, delay))
+        return 1;
+    dst->arg = ec_alloc(q, dst->ec, 4 * sizeof(uint64_t));
+    if (dst->arg == NULL)
+        return 1;
+    d = dst->arg;
+    d[0] = gmin;
+    d[1] = gmax;
+    d[2] = gmax - gmin;
+    d[3] = delay;
+    return 0;
+}
+
+static int
+interpacket_delay_run(struct _qs *q, struct _cfg *arg)
+{
+    uint64_t x = my_random24(), *d = arg->arg;
+    uint64_t gap = d[0] + ((d[2] * x) >> 24);
+    uint64_t base = q->qt_tx;
+    if (base < q->prod_now) {
+        base = q->prod_now;
+        gap = d[3];
+    }
+    q->cur_delay = (base - q->prod_now) + gap;
+    return 0;
+}
 
 #define TLEM_CFG_END	NULL, NULL
 
@@ -3045,6 +3087,8 @@ static struct _cfg delay_cfg[] = {
 		"uniform,dmin,dmax # dmin <= dmax", TLEM_CFG_END },
 	{ exp_delay_parse, exp_delay_run,
 		"exp,dmin,davg # dmin <= davg", TLEM_CFG_END },
+	{ interpacket_delay_parse, interpacket_delay_run,
+	        "inter-packet,min-gap,max-gap,delay # min-gap <= max-gap", TLEM_CFG_END },
 	{ NULL, NULL, NULL, TLEM_CFG_END }
 };
 

From e65ea65482630efda9350a4380cabf9813c652f7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 29 Aug 2018 15:02:42 +0200
Subject: [PATCH 1744/2207] tlem: show drops from all threads

---
 apps/tlem/tlem.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 6b8f74509..fdbce1e68 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2627,14 +2627,16 @@ main(int argc, char **argv)
         struct _qs *q0 = &bp[0].q, *q1 = &bp[1].q;
 
         sleep(1);
-        ED("%lld -> %lld maxq %d round %lld drop %lld, %lld <- %lld maxq %d round %lld drop %lld",
+        ED("%lld -> %lld maxq %d round %lld drop %lld/%lld, %lld <- %lld maxq %d round %lld drop %lld/%lld",
                 (long long)(q0->rxstats->packets - old0rx.packets),
                 (long long)(q0->txstats->packets - old0tx.packets),
                 q0->rx_qmax, (long long)q0->prod_max_gap,
+                (long long)(q0->txstats->drop_packets - old0tx.drop_packets),
                 (long long)(q0->rxstats->drop_packets - old0rx.drop_packets),
                 (long long)(q1->rxstats->packets - old1rx.packets),
                 (long long)(q1->txstats->packets - old1tx.packets),
                 q1->rx_qmax, (long long)q1->prod_max_gap,
+                (long long)(q1->txstats->drop_packets - old1tx.drop_packets),
                 (long long)(q1->rxstats->drop_packets - old1rx.drop_packets)
           );
         ND("plr nominal %le actual %le",

From 43118e223ef03754e41599c89ffebae8a8875933 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 1 Sep 2018 05:10:46 -0400
Subject: [PATCH 1745/2207] tlem: actually obey -w wait_link

---
 apps/tlem/tlem.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index fdbce1e68..881ac3a93 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2613,6 +2613,7 @@ main(int argc, char **argv)
         }
 
     }
+    sleep(bp[0].wait_link);
 
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);

From bd676d77b91486769451bb72187707e91f7dbde4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Sep 2018 11:10:22 +0200
Subject: [PATCH 1746/2207] tlem: fix computation of packet tx start time

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 881ac3a93..31c1c6858 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1138,7 +1138,7 @@ enq(struct _qs *q)
     }
     p->pktlen = q->cur_len;
     p->pt_qout = q->qt_qout;
-    p->pt_tx = q->qt_tx;
+    p->pt_tx = q->qt_tx - q->cur_tt;
     ND(1, "enqueue len %d at %d new tail %ld qout %ld tx %ld",
             q->cur_len, (int)q->prod_tail, p->next,
             p->pt_qout, p->pt_tx);

From 8f7f3f601995af1fd72b538a1848e679c91a74a1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 11 Sep 2018 08:13:34 -0400
Subject: [PATCH 1747/2207] tlem: use a lockless and thread-safe RNG

---
 apps/tlem/tlem.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 31c1c6858..052a80641 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -412,6 +412,7 @@ struct _qs { /* shared queue */
 	uint64_t	prod_tail;	/* cached copy */
 	uint64_t	prod_now;	/* most recent producer timestamp */
 	uint64_t	prod_max_gap;	/* rx round duration */
+	unsigned short	prod_seed[3];
 	struct stats	*txstats;
 
 	/* parameters for reading from the netmap port */
@@ -2148,6 +2149,8 @@ main(int argc, char **argv)
 
     for (i = 0; i < EC_NOPTS; i++) {
         struct _qs *q = &bp[i].q;
+        uint64_t seed = time(0);
+        memcpy(q->prod_seed, &seed, sizeof(q->prod_seed));
         q->c_delay.optarg = "0";
         q->c_delay.run = null_run_fn;
         q->c_loss.optarg = "0";
@@ -2761,9 +2764,9 @@ parse_qsize(const char *arg)
 
 #include  /* log, exp etc. */
 static inline uint64_t
-my_random24(void)	/* 24 useful bits */
+my_random24(struct _qs *q)	/* 24 useful bits */
 {
-    return random() & ((1<<24) - 1);
+    return nrand48(q->prod_seed) & ((1<<24) - 1);
 }
 
 
@@ -2980,7 +2983,7 @@ uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 uniform_delay_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t x = my_random24(), *d = arg->arg;
+    uint64_t x = my_random24(q), *d = arg->arg;
     q->cur_delay = d[0] + ((d[2] * x) >> 24);
 #if 0 /* COMPUTE_STATS */
 #endif /* COMPUTE_STATS */
@@ -3033,7 +3036,7 @@ static int
 exp_delay_run(struct _qs *q, struct _cfg *arg)
 {
     uint64_t *t = (uint64_t *)arg->arg;
-    q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)];
+    q->cur_delay = t[my_random24(q) & (PTS_D_EXP - 1)];
     ND(5, "delay %llu", (unsigned long long)q->cur_delay);
     return 0;
 }
@@ -3070,7 +3073,7 @@ interpacket_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 interpacket_delay_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t x = my_random24(), *d = arg->arg;
+    uint64_t x = my_random24(q), *d = arg->arg;
     uint64_t gap = d[0] + ((d[2] * x) >> 24);
     uint64_t base = q->qt_tx;
     if (base < q->prod_now) {
@@ -3217,7 +3220,7 @@ const_plr_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_plr_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t *d = arg->arg, r = my_random24();
+    uint64_t *d = arg->arg, r = my_random24(q);
     q->cur_drop = r < d[0];
 #if 1	/* keep stats */
     d[1]++;
@@ -3277,7 +3280,7 @@ static int
 const_ber_run(struct _qs *q, struct _cfg *arg)
 {
     int l = q->cur_len;
-    uint64_t r = my_random24(), *d = arg->arg;
+    uint64_t r = my_random24(q), *d = arg->arg;
     uint32_t *plr = (uint32_t *)(d + 3);
 
     if (l >= MAX_PKT) {
@@ -3354,7 +3357,7 @@ const_reorder_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_reorder_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t r = my_random24(), *d = arg->arg;
+    uint64_t r = my_random24(q), *d = arg->arg;
     q->cur_hold_delay = (r < d[0] ? d[1] : 0);
     return 0;
 }

From 2020e96370ee088a5c5e6b3c03644bc51d41c40f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 12:22:07 +0200
Subject: [PATCH 1748/2207] tlem: in linux, switch to poll=idle during
 operation

---
 apps/tlem/tlem.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 052a80641..3ea045c9c 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -160,6 +160,34 @@ int verbose = 1;
 
 static int do_abort = 0;
 
+#ifdef linux
+static int latency_fd = -1;
+static void latency_reduction_start(void)
+{
+    uint32_t target = 0;
+
+    if (latency_fd >= 0)
+        return;
+    latency_fd = open("/dev/cpu_dma_latency", O_RDWR);
+    if (latency_fd < 0) {
+        ED("WARNING: failed to setup low latency: %s", strerror(errno));
+        return;
+    }
+    if (write(latency_fd, &target, sizeof(target)) < 0) {
+        ED("WARNING: failed to setup low latency: %s", strerror(errno));
+    }
+    ED("latency reduction started");
+}
+static void latency_reduction_stop(void)
+{
+    if (latency_fd >= 0)
+        close(latency_fd);
+}
+#else
+#define latency_reduction_start()
+#define latency_reduction_stop()
+#endif /* linux */
+
 #include 
 #include 
 #include 
@@ -2618,6 +2646,8 @@ main(int argc, char **argv)
     }
     sleep(bp[0].wait_link);
 
+    latency_reduction_start();
+
     pthread_create(&bp[0].cons_tid, NULL, tlem_main, (void*)&bp[0]);
     pthread_create(&bp[1].cons_tid, NULL, tlem_main, (void*)&bp[1]);
 
@@ -2655,6 +2685,8 @@ main(int argc, char **argv)
     ED("exiting on abort");
     sleep(1);
 
+    latency_reduction_stop();
+
     return (0);
 }
 

From b0726c1e08c84e600bbe67315a90e7018d071d71 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 12:22:56 +0200
Subject: [PATCH 1749/2207] tlem: avoid too many useless TXSYNCs

---
 apps/tlem/tlem.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 3ea045c9c..4cc6ecdc3 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1743,12 +1743,15 @@ cons(void *_pa)
             ND(4, "                 >>>> TXSYNC, pkt not ready yet h %ld t %ld now %ld tx %ld",
                     h, t, q->cons_now, p->pt_tx);
             q->rx_wait++;
-            /* this also sends any pending arp messages from this or
-             * previous loop iterations
-             */
-            ioctl(pa->pb->fd, NIOCTXSYNC, 0);
-            pending = 0;
-            usleep(5);
+            if (pending > 0) {
+                /* this also sends any pending arp messages from this or
+                 * previous loop iterations
+                 */
+                ioctl(pa->pb->fd, NIOCTXSYNC, 0);
+                pending = 0;
+            } else {
+                usleep(5);
+            }
             set_tns_now(&q->cons_now, q->t0);
             continue;
         }

From f838ec2679e7dc0a2e9ad54608707c87e6ea22c6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Sep 2018 12:25:03 +0200
Subject: [PATCH 1750/2207] tlem: prefer sampling of stats over sliding window

---
 apps/tlem/tlem.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 4cc6ecdc3..ad95d8c48 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2680,10 +2680,10 @@ main(int argc, char **argv)
                 (double)(q0->c_loss.d[0])/(1<<24),
                 q0->c_loss.d[1] == 0 ? 0 :
                 (double)(q0->c_loss.d[2])/q0->c_loss.d[1]);
-        bp[0].q.rx_qmax = (bp[0].q.rx_qmax * 7)/8; // ewma
-        bp[0].q.prod_max_gap = (bp[0].q.prod_max_gap * 7)/8; // ewma
-        bp[1].q.rx_qmax = (bp[1].q.rx_qmax * 7)/8; // ewma
-        bp[1].q.prod_max_gap = (bp[1].q.prod_max_gap * 7)/8; // ewma
+        bp[0].q.rx_qmax = 0;
+        bp[0].q.prod_max_gap = 0;
+        bp[1].q.rx_qmax = 0;
+        bp[1].q.prod_max_gap = 0;
     }
     ED("exiting on abort");
     sleep(1);

From 04aefbec573af4ebbebaf6524e2920b413fd8a08 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Oct 2018 10:11:03 +0200
Subject: [PATCH 1751/2207] tlem: double -H forces failure if hugepages are not
 sufficient

---
 apps/tlem/tlem.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index ad95d8c48..fb9a1d674 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1855,7 +1855,7 @@ tlem_main(void *_a)
     q->buf = mmap(0, need, PROT_WRITE | PROT_READ, mmap_flags, -1, 0);
     if (q->buf == MAP_FAILED) {
         ED("alloc %s bytes for queue failed, exiting", b1);
-        if (mmap_flags & MAP_HUGETLB) {
+        if (mmap_flags & MAP_HUGETLB && a->hugepages < 2) {
             ED("trying again without hugepages");
             mmap_flags &= ~MAP_HUGETLB;
             goto retry;
@@ -2273,7 +2273,7 @@ main(int argc, char **argv)
                 bp[0].route_mode = 1;
                 break;
             case 'H':
-                hugepages = 1;
+                hugepages++;
                 break;
             case 's':
                 if (sfname != NULL) {
@@ -2620,7 +2620,7 @@ main(int argc, char **argv)
     if (hugepages) {
 #ifdef MAP_HUGETLB
         ED("using hugepages");
-        bp[0].hugepages = bp[1].hugepages = 1;
+        bp[0].hugepages = bp[1].hugepages = hugepages;
 #else /* !MAP_HUGETLB */
         ED("WARNING: hugepages not supported");
         hugepages = 0;

From 02d26808cd3f72ba111d1514c1a6ac8ee6e24032 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 12 Oct 2018 10:14:53 +0200
Subject: [PATCH 1752/2207] tlem: mlockall() when running as server

---
 apps/tlem/tlem.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index fb9a1d674..433c988c6 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2576,6 +2576,10 @@ main(int argc, char **argv)
     }
 
     if (server) {
+	/* lock everything in core */
+	if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
+	    ED("failed to lock memory: %s", strerror(errno));
+	}
         /* set the maximum values */
         for (i = 0; i < EC_NOPTS; i++) {
             if (set_max(invdopt['M']->arg[i], &bp[i].q))

From be352675d610b1ad15461ab8f196167497340550 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 19 Oct 2018 12:26:29 +0200
Subject: [PATCH 1753/2207] tlem: take maximum bandwidth from -M when not
 specified

---
 apps/tlem/tlem.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 433c988c6..2f4be4ea3 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2099,6 +2099,14 @@ set_max(const char *arg, struct _qs *q)
             ED("invalid max-bps: %s", av[1]);
             return 1;
         }
+	/* if we did not get any bw limitation from -B, use this one */
+	if (q->c_bw.run == null_run_fn) {
+	    if (cmd_apply(bw_cfg, av[1], q, &q->c_bw)) {
+		ED("warning: failed to set default bandwidth limitation to %s", av[1]);
+	    } else {
+		ED("set maximum bandwidth to %s", av[1]);
+	    }
+	}
     }
     if (ac > 2) {
         /* third argument: max hold time */

From ae9af4cf8523a614b844774111357eaf28a2f3f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Oct 2018 08:23:48 -0400
Subject: [PATCH 1754/2207] tlem: optional infinite size queue len

---
 apps/tlem/tlem.c | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 2f4be4ea3..786db6f5c 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -300,7 +300,8 @@ struct _eci {
         struct _ec      ec_loss;
         struct _ec      ec_reorder;
 	uint64_t	ec_delay_offset;
-	long		ec_allow_drop;
+	int		ec_allow_drop;
+	uint32_t	ec_qsize;
 #define EC_DATASZ       (1U << 16)
         char            ec_data[EC_DATASZ];
 };
@@ -1172,7 +1173,7 @@ enq(struct _qs *q)
             q->cur_len, (int)q->prod_tail, p->next,
             p->pt_qout, p->pt_tx);
     q->prod_tail = p->next;
-    if (q->ec->max_bps)
+    if (q->qsize)
         q->prod_queued += p->pktlen;
     /* XXX update timestamps ? */
     return 0;
@@ -2566,6 +2567,10 @@ main(int argc, char **argv)
             a->ec_delay_offset = parse_time(invdopt['O']->arg[i]);
             q->delay_offset = a->ec_delay_offset;
         }
+	if (invdopt['Q']->arg[i] != NULL) {
+            a->ec_qsize = parse_qsize(invdopt['Q']->arg[0]);
+            q->qsize = a->ec_qsize;
+	}
         bp[i].q.txstats = &ecf->stats[j++];
         bp[i].q.rxstats = &ecf->stats[j++];
     }
@@ -2602,17 +2607,14 @@ main(int argc, char **argv)
         exit(0);
     }
 
-    bp[0].q.qsize = parse_qsize(invdopt['Q']->arg[0]);
-    bp[1].q.qsize = parse_qsize(invdopt['Q']->arg[1]);
-
-    if (bp[0].q.qsize == 0) {
-        ED("qsize= 0 is not valid, set to 50k");
-        bp[0].q.qsize = 50000;
-    }
-    if (bp[1].q.qsize == 0) {
-        ED("qsize= 0 is not valid, set to 50k");
-        bp[1].q.qsize = 50000;
-    }
+    //if (bp[0].q.qsize == 0) {
+    //    ED("qsize= 0 is not valid, set to 50k");
+    //    bp[0].q.qsize = 50000;
+    //}
+    //if (bp[1].q.qsize == 0) {
+    //    ED("qsize= 0 is not valid, set to 50k");
+    //    bp[1].q.qsize = 50000;
+    //}
 
 #ifdef WITH_MAX_LAG
     for (i = 0; i < EC_NOPTS; i++) {
@@ -3455,4 +3457,5 @@ ec_activate(struct _qs *q)
     q->c_reorder.ec = &a->ec_reorder;
     q->allow_drop = a->ec_allow_drop;
     q->delay_offset = a->ec_delay_offset;
+    q->qsize = a->ec_qsize;
 }

From e59e389dc5b5e81824a1618553b6662245d9bd70 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 31 Oct 2018 09:01:02 -0400
Subject: [PATCH 1755/2207] tlem: precompute the tt for all possibile packet
 sizes

---
 apps/tlem/tlem.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 786db6f5c..6e2e00de1 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -3167,6 +3167,7 @@ static int
 const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
     uint64_t bw, *d;
+    int i;
 
     if (strncmp(av[0], "const", 5) != 0 && ac > 1)
         return 2; /* unrecognised */
@@ -3176,13 +3177,15 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     if (bw == U_PARSE_ERR) {
         return (ac == 2) ? 1 /* error */ : 2 /* unrecognised */;
     }
-    dst->arg = ec_alloc(q, dst->ec, sizeof(uint64_t));
+    dst->arg = ec_alloc(q, dst->ec, MAX_PKT * sizeof(uint32_t));
     if (dst->arg == NULL)
         return 1;
     if (update_max_bw(q, bw))
         return 1;
     d = dst->arg;
-    d[0] = bw;
+    for (i = 0; i < MAX_PKT; i++) {
+        d[i] = bw ? 8ULL * TIME_UNITS * i / bw : 0;
+    }
     return 0;	/* success */
 }
 
@@ -3191,8 +3194,8 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_bw_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t *d = arg->arg, bps = d[0];
-    q->cur_tt = bps ? 8ULL* TIME_UNITS * q->cur_len / bps : 0 ;
+    uint64_t *d = arg->arg;
+    q->cur_tt = d[q->cur_len];
     return 0;
 }
 
@@ -3201,6 +3204,7 @@ static int
 ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
     uint64_t bw, *d;
+    int i;
 
     if (strcmp(av[0], "ether") != 0)
         return 2; /* unrecognised */
@@ -3211,11 +3215,13 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
         return 1; /* error */
     if (update_max_bw(q, bw))
         return 1;
-    dst->arg = ec_alloc(q, dst->ec, sizeof(uint64_t));
+    dst->arg = ec_alloc(q, dst->ec, MAX_PKT * sizeof(uint32_t));
     if (dst->arg == NULL)
         return 1;
     d = dst->arg;
-    d[0] = bw;
+    for (i = 0; i < MAX_PKT; i++) {
+        d[i] = bw ? 8ULL * TIME_UNITS * (i + 24) / bw : 0;
+    }
     return 0;	/* success */
 }
 
@@ -3224,8 +3230,8 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 ether_bw_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t *d = arg->arg, bps = d[0];
-    q->cur_tt = bps ? 8ULL * TIME_UNITS * (q->cur_len + 24) / bps : 0 ;
+    uint64_t *d = arg->arg;
+    q->cur_tt = d[q->cur_len];
     return 0;
 }
 

From fe40063e34e7a3fe7d5f9b973b080739a03f1bbd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 2 Nov 2018 16:13:52 +0100
Subject: [PATCH 1756/2207] tlem: use a finite queue when bw limitation is in
 effect

---
 apps/tlem/tlem.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 6e2e00de1..34aa6e388 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2516,8 +2516,6 @@ main(int argc, char **argv)
     }
 
     /* use same parameters for both directions if needed */
-    if (invdopt['Q']->arg[0] == NULL)
-        invdopt['Q']->arg[0] = "0";
     for (scandopt = dopt; scandopt->opt; scandopt++) {
         if (!(scandopt->flags & DOPT_CLONE))
             continue;
@@ -2570,6 +2568,17 @@ main(int argc, char **argv)
 	if (invdopt['Q']->arg[i] != NULL) {
             a->ec_qsize = parse_qsize(invdopt['Q']->arg[0]);
             q->qsize = a->ec_qsize;
+	} else if (invdopt['B']->arg[i] != NULL) {
+	    /* we need e small finite queue for bandwidth emulation,
+	     * otherwise delay is unbounded
+	     */
+	    ED("setting qsize to 50k");
+	    a->ec_qsize = 50000;
+	    q->qsize = 50000;
+	} else {
+	    ED("using unlimited qsize");
+	    a->ec_qsize = 0;
+	    q->qsize = 0; /* infinite */
 	}
         bp[i].q.txstats = &ecf->stats[j++];
         bp[i].q.rxstats = &ecf->stats[j++];
@@ -2607,15 +2616,6 @@ main(int argc, char **argv)
         exit(0);
     }
 
-    //if (bp[0].q.qsize == 0) {
-    //    ED("qsize= 0 is not valid, set to 50k");
-    //    bp[0].q.qsize = 50000;
-    //}
-    //if (bp[1].q.qsize == 0) {
-    //    ED("qsize= 0 is not valid, set to 50k");
-    //    bp[1].q.qsize = 50000;
-    //}
-
 #ifdef WITH_MAX_LAG
     for (i = 0; i < EC_NOPTS; i++) {
         if (bp[i].max_lag == 0) {

From ff271a362bccbd210bdb13941a1278507315e5ec Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Nov 2018 15:51:32 +0100
Subject: [PATCH 1757/2207] tlem: fix type of arrays in pre-computed bw

---
 apps/tlem/tlem.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 34aa6e388..e48acedd1 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -3166,7 +3166,8 @@ update_max_bw(struct _qs *q, uint64_t bw)
 static int
 const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-    uint64_t bw, *d;
+    uint64_t bw;
+    uint32_t *d;
     int i;
 
     if (strncmp(av[0], "const", 5) != 0 && ac > 1)
@@ -3194,7 +3195,7 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 const_bw_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t *d = arg->arg;
+    uint32_t *d = arg->arg;
     q->cur_tt = d[q->cur_len];
     return 0;
 }
@@ -3203,7 +3204,8 @@ const_bw_run(struct _qs *q, struct _cfg *arg)
 static int
 ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 {
-    uint64_t bw, *d;
+    uint64_t bw;
+    uint32_t *d;
     int i;
 
     if (strcmp(av[0], "ether") != 0)
@@ -3230,7 +3232,7 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
 static int
 ether_bw_run(struct _qs *q, struct _cfg *arg)
 {
-    uint64_t *d = arg->arg;
+    uint32_t *d = arg->arg;
     q->cur_tt = d[q->cur_len];
     return 0;
 }

From f9026e279180516c4e24274afc347330801d95de Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Nov 2018 23:21:11 +0100
Subject: [PATCH 1758/2207] tlem: add bw emulation via token bucket

---
 apps/tlem/tlem.c | 93 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 87 insertions(+), 6 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index e48acedd1..1ce02c639 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -286,6 +286,7 @@ struct _cfg {
     /* placeholders for common values */
     void *arg;		/* allocated memory */
     struct _ec *ec;     /* external configuration */
+    uint64_t def_qsize; /* default qsize (for bw configs) */
 };
 
 
@@ -1439,8 +1440,9 @@ null_run_fn(struct _qs *q, struct _cfg *cfg)
 static int
 drop_after(struct _qs *q)
 {
-    (void)q; // XXX
-    return 0;
+    int drop = q->cur_drop;
+    q->cur_drop = 0;
+    return drop;
 }
 
 /* poducer: send the proper command depending on the contents of the received
@@ -1502,6 +1504,7 @@ prod_procpkt(struct _qs *q)
     tt = q->cur_tt;
     q->qt_qout += tt;
     if (drop_after(q)) {
+	q->qt_qout -= tt;
         q->txstats->drop_packets++;
         q->txstats->drop_bytes += q->cur_len;
         return;
@@ -2572,9 +2575,9 @@ main(int argc, char **argv)
 	    /* we need e small finite queue for bandwidth emulation,
 	     * otherwise delay is unbounded
 	     */
-	    ED("setting qsize to 50k");
-	    a->ec_qsize = 50000;
-	    q->qsize = 50000;
+	    ED("setting qsize to %lluB", (unsigned long long)q->c_bw.def_qsize);
+	    a->ec_qsize = q->c_bw.def_qsize;
+	    q->qsize = q->c_bw.def_qsize;
 	} else {
 	    ED("using unlimited qsize");
 	    a->ec_qsize = 0;
@@ -3133,7 +3136,7 @@ interpacket_delay_run(struct _qs *q, struct _cfg *arg)
     return 0;
 }
 
-#define TLEM_CFG_END	NULL, NULL
+#define TLEM_CFG_END	NULL, NULL, 0
 
 static struct _cfg delay_cfg[] = {
 	{ const_delay_parse, const_delay_run,
@@ -3187,6 +3190,7 @@ const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     for (i = 0; i < MAX_PKT; i++) {
         d[i] = bw ? 8ULL * TIME_UNITS * i / bw : 0;
     }
+    dst->def_qsize = 50000;
     return 0;	/* success */
 }
 
@@ -3197,6 +3201,7 @@ const_bw_run(struct _qs *q, struct _cfg *arg)
 {
     uint32_t *d = arg->arg;
     q->cur_tt = d[q->cur_len];
+    q->cur_drop = 0;
     return 0;
 }
 
@@ -3224,6 +3229,7 @@ ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     for (i = 0; i < MAX_PKT; i++) {
         d[i] = bw ? 8ULL * TIME_UNITS * (i + 24) / bw : 0;
     }
+    dst->def_qsize = 50000;
     return 0;	/* success */
 }
 
@@ -3234,6 +3240,79 @@ ether_bw_run(struct _qs *q, struct _cfg *arg)
 {
     uint32_t *d = arg->arg;
     q->cur_tt = d[q->cur_len];
+    q->cur_drop = 0;
+    return 0;
+}
+
+/* token bucket. We don't limit the transmission time of
+ * each packet, but non-conforming packets are dropped
+ */
+#define WSHIFT 20
+struct avgbw_arg {
+    uint64_t token;
+    uint64_t bucket;
+    uint64_t depth;
+    uint64_t last_token;
+};
+static int
+avg_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
+{
+    double bw, token;
+    struct avgbw_arg *d;
+
+    if (strcmp(av[0], "avg") != 0)
+        return 2; /* unrecognised */
+    if (ac != 2)
+        return 1; /* error */
+    bw = parse_bw(av[ac - 1]);
+    if (bw == U_PARSE_ERR)
+        return 1; /* error */
+    if (update_max_bw(q, bw))
+        return 1;
+    token = (bw / 8) * (1UL << WSHIFT) / 1e9;
+    dst->arg = ec_alloc(q, dst->ec, sizeof(*d));
+    if (dst->arg == NULL)
+        return 1;
+    d = dst->arg;
+    d->token = token;
+    d->bucket = 0;
+    d->depth = 4 * token;
+    if (d->depth < 2*MAX_PKT)
+	d->depth = 2*MAX_PKT;
+    d->last_token = 0;
+    dst->def_qsize = 0; /* skip the queue emulation */
+    D("token %lluB/%.2fms depth %llu",
+	    (unsigned long long)d->token, (1UL << WSHIFT)/1e6,
+	    (unsigned long long)d->depth);
+    return 0;	/* success */
+
+}
+
+static int
+avg_bw_run(struct _qs *q, struct _cfg *arg)
+{
+    struct avgbw_arg *d = arg->arg;
+    uint64_t now = (q->prod_now >> WSHIFT);
+    uint64_t sz = q->cur_len + 24;
+    uint64_t tokens;
+
+    /* insert all the necessary tokens */
+    tokens = (now - d->last_token) * d->token;
+    d->last_token = now;
+    d->bucket += tokens;
+    if (d->bucket > d->depth)
+	d->bucket = d->depth;
+    ND(1, "%llu: now %llu last %llu tokens %llu bucket %llu",
+		(unsigned long long)q->prod_now,
+		(unsigned long long)now,
+		(unsigned long long)d->last_token,
+		(unsigned long long)tokens,
+		(unsigned long long)d->bucket);
+    q->cur_tt = 0;
+    q->cur_drop = sz > d->bucket;
+    if (!q->cur_drop)
+	d->bucket -= sz;
+    //printf("%llu %llu\n", (unsigned long long)q->prod_now, (unsigned long long)d->bucket);
     return 0;
 }
 
@@ -3242,6 +3321,7 @@ static struct _cfg bw_cfg[] = {
 		"constant,bps", TLEM_CFG_END },
 	{ ether_bw_parse, ether_bw_run,
 		"ether,bps", TLEM_CFG_END },
+	{ avg_bw_parse, avg_bw_run, "avg,bps", TLEM_CFG_END },
 	{ NULL, NULL, NULL, TLEM_CFG_END }
 };
 
@@ -3352,6 +3432,7 @@ const_ber_run(struct _qs *q, struct _cfg *arg)
     return 0;
 }
 
+
 static struct _cfg loss_cfg[] = {
 	{ const_plr_parse, const_plr_run,
 		"plr,prob # 0 <= prob <= 1", TLEM_CFG_END },

From 8540cd750b839723cb3089677d3babe4ac7ceb82 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 7 Feb 2019 12:07:13 +0100
Subject: [PATCH 1759/2207] tlem: double the size of the configuration space

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 1ce02c639..d9b79792e 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -303,7 +303,7 @@ struct _eci {
 	uint64_t	ec_delay_offset;
 	int		ec_allow_drop;
 	uint32_t	ec_qsize;
-#define EC_DATASZ       (1U << 16)
+#define EC_DATASZ       (1U << 17)
         char            ec_data[EC_DATASZ];
 };
 

From 7941d3c9101919613d2ebb8c26bf82d31c55bafa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 26 Sep 2019 17:56:30 +0200
Subject: [PATCH 1760/2207] tlem: fix out-of-bound access in arpq

---
 apps/tlem/tlem.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index d9b79792e..ec5e0d9c0 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -886,11 +886,13 @@ arpq_get_cmd(struct arp_cmd_q *a)
 static inline void
 arpq_release(struct arp_cmd_q *a)
 {
-    if (likely(a->q[a->toclean].valid != 2))
+    int c = a->toclean & (ARP_CMD_QSIZE - 1);
+    if (likely(a->q[c].valid != 2))
         return;
-    while (a->q[a->toclean].valid == 2) {
-        a->q[a->toclean].valid = 0;
+    while (a->q[c].valid == 2) {
+        a->q[c].valid = 0;
         a->toclean++;
+	c = a->toclean & (ARP_CMD_QSIZE - 1);
     }
 }
 

From 6abf4ff9bac77f3229d6da183747ddf1f9f12b47 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 29 Sep 2019 17:43:36 +0200
Subject: [PATCH 1761/2207] tlem: fix order of ntohs

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index ec5e0d9c0..42527c33f 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1644,7 +1644,7 @@ cons_update_dst(struct pipe_args *pa, void *pkt)
     //uint8_t *d = (uint8_t *)&dst;
 
     ND("dst %u.%u.%u.%u", d[0], d[1], d[2], d[3]);
-    if (unlikely(!(eh->ether_type == ntohs(ETHERTYPE_IP))))
+    if (unlikely(!(ntohs(eh->ether_type) == ETHERTYPE_IP)))
         return -1; /* drop */
     if (unlikely(dst == ipv4->ip_bcast || dst == 0xffffffff))
         return -1; /* drop */

From 94c0be58d817b34b53e63169744bf59eca5c95d4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 29 Sep 2019 17:43:50 +0200
Subject: [PATCH 1762/2207] tlem: ignore 802.3 packets

---
 apps/tlem/tlem.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 42527c33f..500f0a93d 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1644,6 +1644,8 @@ cons_update_dst(struct pipe_args *pa, void *pkt)
     //uint8_t *d = (uint8_t *)&dst;
 
     ND("dst %u.%u.%u.%u", d[0], d[1], d[2], d[3]);
+    if (unlikely((ntohs(eh->ether_type) < 0x600)))
+	return -2; /* ignore 802.3 packets */
     if (unlikely(!(ntohs(eh->ether_type) == ETHERTYPE_IP)))
         return -1; /* drop */
     if (unlikely(dst == ipv4->ip_bcast || dst == 0xffffffff))
@@ -1776,7 +1778,10 @@ cons(void *_pa)
                 /* drop this packet. Any pending arp message
                  * will be sent in the next iteration
                  */
-                q->rxstats->drop_packets++;
+		if (injected == -1) {
+		    q->rxstats->drop_packets++;
+		    q->rxstats->drop_bytes += p->pktlen;
+		}
                 goto next;
             }
             pending += injected;

From 796c00976a43f11ebb7cddfd094c2ebb9c82b439 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 7 Oct 2019 18:10:31 +0200
Subject: [PATCH 1763/2207] tlem: fix source MAC addresses in route mode

---
 apps/tlem/tlem.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 500f0a93d..4198a8bff 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -931,7 +931,17 @@ struct ipv4_info {
 	in_addr_t	ip_subnet;
 	in_addr_t	ip_bcast;
 	in_addr_t	ip_gw;
-	uint8_t		ether_addr[6];
+	union {
+		struct {
+		    uint8_t  pad1[2];
+		    uint8_t  ether_addr[6];
+		};
+		struct {
+		    uint16_t pad2;
+		    uint16_t eth1;
+		    uint32_t eth2;
+		};
+	};
 	/* pre-formatted arp messages */
 	union {
 		uint8_t pkt[60];
@@ -1626,13 +1636,14 @@ cons_handle_arp(struct pipe_args *pa, struct arp_cmd *c)
     return rv;
 }
 
-/* change the ethernet target address according to the local ARP table.
+/* change the ethernet target address according to the local ARP table
+ * and set the source address to the local MAC.
  * may send an ARP request.
  * returns the number of packets injected, or < 0 if the packet
  * needs to be dropped
  */
 static inline int
-cons_update_dst(struct pipe_args *pa, void *pkt)
+cons_update_macs(struct pipe_args *pa, void *pkt)
 {
     struct ether_header *eh = pkt;
     struct ip *iph = (struct ip *)(eh + 1);
@@ -1679,6 +1690,9 @@ cons_update_dst(struct pipe_args *pa, void *pkt)
     /* copy negated dst into eh (either brodcast or unicast) */
     *(uint32_t *)eh = ~e->eth1;
     *(uint16_t *)((char *)eh + 4) = ~e->eth2;
+    /* copy local MAC address into source */
+    *(uint16_t *)((char *)eh + 6) = ipv4->eth1;
+    *(uint32_t *)((char *)eh + 8) = ipv4->eth2;
     return injected;
 }
 
@@ -1773,7 +1787,7 @@ cons(void *_pa)
         ND(5, "drain len %ld now %ld tx %ld h %ld t %ld next %ld",
                 p->pktlen, q->cons_now, p->pt_tx, h, t, p->next);
         if (pa->route_mode && !retrying) {
-            int injected = cons_update_dst(pa, p + 1);
+            int injected = cons_update_macs(pa, p + 1);
             if (unlikely(injected < 0)) {
                 /* drop this packet. Any pending arp message
                  * will be sent in the next iteration

From 436c96904e26c76e435ea3b2b591211f8221d9b4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Oct 2019 12:04:10 +0200
Subject: [PATCH 1764/2207] tlem: fix error-check in const_reorder_parse

---
 apps/tlem/tlem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 4198a8bff..eb30d59e7 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -3490,7 +3490,7 @@ const_reorder_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[])
     uint64_t delay, *d;
     int err;
 
-    if (strcmp(av[0], "const") != 0 && ac > 2)
+    if (strcmp(av[0], "const") != 0 && ac != 2)
         return 2; /* not recognized */
     if (ac > 3)
         return 1; /* error */

From ab676aaea04869445a8b6c4f5abd03f168091f9e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Oct 2019 12:07:12 +0200
Subject: [PATCH 1765/2207] tlem: also show reorder values on startup

---
 apps/tlem/tlem.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index eb30d59e7..dc97e643e 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1920,10 +1920,11 @@ tlem_main(void *_a)
         q->hold_buflen = need - (sizeof(struct h_pkt) + MAX_PKT);
     }
 
-    ED("----\n\t%s -> %s :  bps %lld delay %s loss %s queue %lld bytes"
+    ED("----\n\t%s -> %s :  bps %lld delay %s loss %s reorder %s queue %lld bytes"
             "\n\tbuffer   %s bytes\n\thold-buf %s bytes",
             q->prod_ifname, q->cons_ifname,
             (long long)q->ec->max_bps, q->c_delay.optarg, q->c_loss.optarg,
+	    q->c_reorder.optarg,
             (long long)q->qsize, b1,
             b2);
 

From e04dfc71e239e1ad5248c4dddfce811bae6183ef Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 19 Jun 2019 15:00:00 +0200
Subject: [PATCH 1766/2207] tlem: remove unused code

---
 apps/tlem/tlem.c | 35 ++++-------------------------------
 1 file changed, 4 insertions(+), 31 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index dc97e643e..6df90d563 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -1240,37 +1240,10 @@ wait_for_packets(struct _qs *q)
         if (n0)
             break;
         prev = 0; /* we slept */
-        if (1) {
-            usleep(5);
-            ioctl(q->src_port->fd, NIOCRXSYNC, 0);
-            ec_checkactive(q);
-            set_tns_now(&q->prod_now, q->t0);
-        } else {
-            struct pollfd pfd;
-            struct netmap_ring *rx;
-            int ret;
-
-            pfd.fd = q->src_port->fd;
-            pfd.revents = 0;
-            pfd.events = POLLIN;
-            ND(1, "prepare for poll on %s", q->prod_ifname);
-            ret = poll(&pfd, 1, 10000);
-            if (ret <= 0 || verbose > 1) {
-                D("poll %s ev %x %x rx %d@%d",
-                        ret <= 0 ? "timeout" : "ok",
-                        pfd.events,
-                        pfd.revents,
-                        rx_queued(q->src_port),
-                        NETMAP_RXRING(q->src_port->nifp, q->src_port->first_rx_ring)->cur
-                 );
-            }
-            if (pfd.revents & POLLERR) {
-                rx = NETMAP_RXRING(q->src_port->nifp, q->src_port->first_rx_ring);
-                D("error on fd0, rx [%d,%d,%d)",
-                        rx->head, rx->cur, rx->tail);
-                sleep(1);
-            }
-        }
+        usleep(5);
+        ioctl(q->src_port->fd, NIOCRXSYNC, 0);
+        ec_checkactive(q);
+        set_tns_now(&q->prod_now, q->t0);
     }
     set_tns_now(&q->prod_now, q->t0);
     if (ts_cmp(q->qt_qout, q->prod_now) < 0) {

From 8a80d9873986800573033b42cf2fa2e4a23dc93e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 20 Jun 2019 14:58:45 +0200
Subject: [PATCH 1767/2207] tlem: refactor impairment structures

---
 apps/tlem/tlem.c | 144 +++++++++++++++++++++++------------------------
 1 file changed, 72 insertions(+), 72 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 6df90d563..be18bfe14 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -289,6 +289,14 @@ struct _cfg {
     uint64_t def_qsize; /* default qsize (for bw configs) */
 };
 
+/* impairments */
+enum {
+	I_DELAY = 0,
+	I_BW,
+	I_LOSS,
+	I_REORDER,
+	I_NUM
+};
 
 /* configuration instance. There may be one or more of these
  * for direction. One of them is the active one, currently
@@ -296,10 +304,7 @@ struct _cfg {
  * then make it active when ready.
  */
 struct _eci {
-        struct _ec      ec_delay;
-        struct _ec      ec_bw;
-        struct _ec      ec_loss;
-        struct _ec      ec_reorder;
+        struct _ec      ec_imp[I_NUM];
 	uint64_t	ec_delay_offset;
 	int		ec_allow_drop;
 	uint32_t	ec_qsize;
@@ -430,10 +435,7 @@ struct _qs { /* shared queue */
 	uint64_t	qsize;	/* queue size in bytes */
 
 	/* handlers for various options */
-	struct _cfg	c_delay;
-	struct _cfg	c_bw;
-	struct _cfg	c_loss;
-	struct _cfg	c_reorder;
+	struct _cfg	c_imp[I_NUM];
 
 	/* producer's fields */
 	uint64_t	prod_tail_1 ALIGN_CACHE; /* head of queue */
@@ -671,17 +673,13 @@ ec_init(struct _qs *q, struct _ecs *ec, int server)
 
     q->ec = ec;
     for (i = 0; i < EC_NINST; i++)
-        q->ec_nta[i] = 0;
+	q->ec_nta[i] = 0;
     q->ec_active = server ? 0 : ec_next(q->ec->active);
     ci = &q->ec->instances[q->ec_active];
-    ci->ec_delay.ec_valid = 0;
-    q->c_delay.ec = &ci->ec_delay;
-    ci->ec_bw.ec_valid = 0;
-    q->c_bw.ec = &ci->ec_bw;
-    ci->ec_loss.ec_valid = 0;
-    q->c_loss.ec = &ci->ec_loss;
-    ci->ec_reorder.ec_valid = 0;
-    q->c_reorder.ec = &ci->ec_reorder;
+    for (i = 0; i < I_NUM; i++) {
+	ci->ec_imp[i].ec_valid = 0;
+	q->c_imp[i].ec = &ci->ec_imp[i];
+    }
     return 0;
 }
 
@@ -1468,7 +1466,7 @@ prod_procpkt(struct _qs *q)
 {
     uint64_t t_tx, tt;	/* output and transmission time */
 
-    q->c_loss.run(q, &q->c_loss);
+    q->c_imp[I_LOSS].run(q, &q->c_imp[I_LOSS]);
     if (q->cur_drop) {
         q->txstats->drop_packets++;
         q->txstats->drop_bytes += q->cur_len;
@@ -1485,7 +1483,7 @@ prod_procpkt(struct _qs *q)
         }
     }
     // XXX possibly implement c_tt for transmission time emulation
-    q->c_bw.run(q, &q->c_bw);
+    q->c_imp[I_BW].run(q, &q->c_imp[I_BW]);
     tt = q->cur_tt;
     q->qt_qout += tt;
     if (drop_after(q)) {
@@ -1495,7 +1493,7 @@ prod_procpkt(struct _qs *q)
         return;
     }
     if (!q->reuse_delay) {
-        q->c_delay.run(q, &q->c_delay); /* compute delay */
+        q->c_imp[I_DELAY].run(q, &q->c_imp[I_DELAY]); /* compute delay */
         if (q->delay_offset > q->cur_delay) {
             q->cur_delay = 0;
         } else {
@@ -1553,7 +1551,7 @@ prod(void *_pa)
                 prod_push_arp(pa, q->cur_pkt);
                 continue;
             }
-            q->c_reorder.run(q, &q->c_reorder);
+            q->c_imp[I_REORDER].run(q, &q->c_imp[I_REORDER]);
             if (q->cur_hold_delay) {
                 q->cur_hold_delay += q->prod_now;
                 q->txstats->reorder_packets++;
@@ -1896,8 +1894,8 @@ tlem_main(void *_a)
     ED("----\n\t%s -> %s :  bps %lld delay %s loss %s reorder %s queue %lld bytes"
             "\n\tbuffer   %s bytes\n\thold-buf %s bytes",
             q->prod_ifname, q->cons_ifname,
-            (long long)q->ec->max_bps, q->c_delay.optarg, q->c_loss.optarg,
-	    q->c_reorder.optarg,
+            (long long)q->ec->max_bps, q->c_imp[I_DELAY].optarg, q->c_imp[I_LOSS].optarg,
+	    q->c_imp[I_REORDER].optarg,
             (long long)q->qsize, b1,
             b2);
 
@@ -2099,8 +2097,8 @@ set_max(const char *arg, struct _qs *q)
             return 1;
         }
 	/* if we did not get any bw limitation from -B, use this one */
-	if (q->c_bw.run == null_run_fn) {
-	    if (cmd_apply(bw_cfg, av[1], q, &q->c_bw)) {
+	if (q->c_imp[I_BW].run == null_run_fn) {
+	    if (cmd_apply(bw_cfg, av[1], q, &q->c_imp[I_BW])) {
 		ED("warning: failed to set default bandwidth limitation to %s", av[1]);
 	    } else {
 		ED("set maximum bandwidth to %s", av[1]);
@@ -2135,6 +2133,19 @@ struct dir_opt {
 #define MAXOPTS 1024
 #define DOPT(a, f)  { .opt = a, .flags = f, .arg = { NULL, NULL } }
 
+/* mapping between options and configurations */
+struct cfg_opt {
+    int opt;
+    struct _cfg *c;
+};
+
+struct cfg_opt all_cfgs[] = {
+    [I_DELAY]	= { 'D', delay_cfg },
+    [I_BW]    	= { 'B', bw_cfg },
+    [I_LOSS]  	= { 'L', loss_cfg },
+    [I_REORDER]	= { 'R', reorder_cfg },
+};
+
 int
 main(int argc, char **argv)
 {
@@ -2188,15 +2199,13 @@ main(int argc, char **argv)
     for (i = 0; i < EC_NOPTS; i++) {
         struct _qs *q = &bp[i].q;
         uint64_t seed = time(0);
+	int j;
+
         memcpy(q->prod_seed, &seed, sizeof(q->prod_seed));
-        q->c_delay.optarg = "0";
-        q->c_delay.run = null_run_fn;
-        q->c_loss.optarg = "0";
-        q->c_loss.run = null_run_fn;
-        q->c_bw.optarg = "0";
-        q->c_bw.run = null_run_fn;
-        q->c_reorder.optarg = "0";
-        q->c_reorder.run = null_run_fn;
+	for (j = 0; j < I_NUM; j++) {
+	    q->c_imp[j].optarg = "0";
+	    q->c_imp[j].run = null_run_fn;
+	}
     }
 
     ncpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -2527,6 +2536,7 @@ main(int argc, char **argv)
     for (i = 0; i < EC_NOPTS; i++) { /* once per queue */
         struct _qs *q = &bp[i].q;
         struct _eci *a;
+	int k;
 
         if (ec_init(q, &ecf->sets[i], server))
             exit(1);
@@ -2535,10 +2545,9 @@ main(int argc, char **argv)
             continue;
         }
         a = &q->ec->instances[q->ec_active];
-        err += cmd_apply(delay_cfg, invdopt['D']->arg[i], q, &q->c_delay);
-        err += cmd_apply(bw_cfg, invdopt['B']->arg[i], q, &q->c_bw);
-        err += cmd_apply(loss_cfg, invdopt['L']->arg[i], q, &q->c_loss);
-        err += cmd_apply(reorder_cfg, invdopt['R']->arg[i], q, &q->c_reorder);
+	for (k = 0; k < I_NUM; k++) {
+	    err += cmd_apply(all_cfgs[k].c, invdopt[all_cfgs[k].opt]->arg[i], q, &q->c_imp[k]);
+	}
 #ifdef WITH_MAX_LAG
         if (invdopt['d']->arg[i] != NULL) {
             unsigned long max_lag = parse_time(invdopt[(int)'d']->arg[i]);
@@ -2570,9 +2579,9 @@ main(int argc, char **argv)
 	    /* we need e small finite queue for bandwidth emulation,
 	     * otherwise delay is unbounded
 	     */
-	    ED("setting qsize to %lluB", (unsigned long long)q->c_bw.def_qsize);
-	    a->ec_qsize = q->c_bw.def_qsize;
-	    q->qsize = q->c_bw.def_qsize;
+	    ED("setting qsize to %lluB", (unsigned long long)q->c_imp[I_BW].def_qsize);
+	    a->ec_qsize = q->c_imp[I_BW].def_qsize;
+	    q->qsize = q->c_imp[I_BW].def_qsize;
 	} else {
 	    ED("using unlimited qsize");
 	    a->ec_qsize = 0;
@@ -3504,41 +3513,32 @@ static struct _cfg reorder_cfg[] = {
 void
 ec_activate(struct _qs *q)
 {
-    int i = q->ec_active;
+    int i = q->ec_active, j;
     struct _eci *a = &q->ec->instances[i];
 
-    if (a->ec_bw.ec_valid) {
-        q->c_bw = bw_cfg[a->ec_bw.ec_index];
-        q->c_bw.arg = &a->ec_data[a->ec_bw.ec_dataoff];
-    } else {
-        q->cur_tt = 0;
-        q->c_bw.run = null_run_fn;
-    }
-    q->c_bw.ec = &a->ec_bw;
-    if (a->ec_delay.ec_valid) {
-        q->c_delay = delay_cfg[a->ec_delay.ec_index];
-        q->c_delay.arg = &a->ec_data[a->ec_delay.ec_dataoff];
-    } else {
-        q->cur_delay = 0;
-        q->c_delay.run = null_run_fn;
-    }
-    q->c_delay.ec = &a->ec_delay;
-    if (a->ec_loss.ec_valid) {
-        q->c_loss = loss_cfg[a->ec_loss.ec_index];
-        q->c_loss.arg = &a->ec_data[a->ec_loss.ec_dataoff];
-    } else {
-        q->cur_drop = 0;
-        q->c_loss.run = null_run_fn;
-    }
-    q->c_loss.ec = &a->ec_loss;
-    if (a->ec_reorder.ec_valid) {
-        q->c_reorder = reorder_cfg[a->ec_reorder.ec_index];
-        q->c_reorder.arg = &a->ec_data[a->ec_reorder.ec_dataoff];
-    } else {
-        q->cur_hold_delay = 0;
-        q->c_reorder.run = null_run_fn;
+    for (j = 0; j < I_NUM; j++) {
+	if (a->ec_imp[j].ec_valid) {
+	    q->c_imp[j] = all_cfgs[j].c[a->ec_imp[j].ec_index];
+	    q->c_imp[j].arg = &a->ec_data[a->ec_imp[j].ec_dataoff];
+	} else {
+	    switch (j) {
+	    case I_DELAY:
+	        q->cur_delay = 0;
+	        break;
+	    case I_BW:
+		q->cur_tt = 0;
+	        break;
+	    case I_LOSS:
+		q->cur_drop = 0;
+	        break;
+	    case I_REORDER:
+		q->cur_hold_delay = 0;
+	        break;
+	    }
+	    q->c_imp[j].run = null_run_fn;
+	}
+	q->c_imp[j].ec = &a->ec_imp[j];
     }
-    q->c_reorder.ec = &a->ec_reorder;
     q->allow_drop = a->ec_allow_drop;
     q->delay_offset = a->ec_delay_offset;
     q->qsize = a->ec_qsize;

From ae2c7c5973b20121edaeb41baeaae013b711110e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Oct 2019 15:40:25 +0200
Subject: [PATCH 1768/2207] tlem: simplify prod to handle just one rx ring

---
 apps/tlem/tlem.c | 63 +++++++++---------------------------------------
 1 file changed, 11 insertions(+), 52 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index be18bfe14..7d8ae36fb 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -450,8 +450,7 @@ struct _qs { /* shared queue */
 	/* parameters for reading from the netmap port */
 	struct nmport_d *src_port;		/* netmap descriptor */
 	const char *	prod_ifname;	/* interface name */
-	struct netmap_ring *rxring;	/* current ring being handled */
-	uint32_t	si;		/* ring index */
+	struct netmap_ring *rxring;	/* source netmap ring */
 	int		burst;
 	uint32_t	rx_qmax;	/* stats on max queued */
 
@@ -1191,20 +1190,6 @@ enq(struct _qs *q)
 }
 
 
-static int
-rx_queued(struct nmport_d *d)
-{
-    u_int tot = 0, i;
-    for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
-        struct netmap_ring *rxr = NETMAP_RXRING(d->nifp, i);
-
-        ND(5, "ring %d h %d cur %d tail %d", i,
-                rxr->head, rxr->cur, rxr->tail);
-        tot += nm_ring_space(rxr);
-    }
-    return tot;
-}
-
 static inline int
 hold_update_release(struct _qs *q)
 {
@@ -1231,7 +1216,7 @@ wait_for_packets(struct _qs *q)
     while (!do_abort) {
         if (hold_update_release(q))
             break;
-        n0 = rx_queued(q->src_port);
+        n0 = nm_ring_space(q->rxring);
         if (n0 > (int)q->rx_qmax) {
             q->rx_qmax = n0;
         }
@@ -1282,43 +1267,16 @@ static void
 scan_ring(struct _qs *q, int next /* bool */)
 {
     struct netmap_slot *rs;
-    struct netmap_ring *rxr = q->rxring; /* invalid if next == 0 */
-    struct nmport_d *pa = q->src_port;
+    struct netmap_ring *rxr = q->rxring;
     int nfrags;
 
-    /* fast path for the first two */
-    if (likely(next != 0)) { /* current ring */
-        ND(10, "scan next");
+    if (likely(next != 0)) {
         /* advance */
         rxr->head = rxr->cur = nm_ring_next(rxr, rxr->cur);
-        if (!nm_ring_empty(rxr)) /* good one */
-            goto got_one;
-        q->si++;	/* otherwise update and fallthrough */
-    } else { /* scan from beginning */
-        q->si = pa->first_rx_ring;
-        ND(10, "scanning first ring %d", q->si);
-    }
-    while (q->si <= pa->last_rx_ring) {
-        q->rxring = rxr = NETMAP_RXRING(pa->nifp, q->si);
-        if (!nm_ring_empty(rxr))
-            break;
-        q->si++;
-        continue;
-    }
-    if (q->si > pa->last_rx_ring) { /* no data, cur == tail */
-        ND(5, "no more pkts on %s", q->prod_ifname);
-        return;
+        if (nm_ring_empty(rxr)) /* no more packets */
+            return;
     }
-got_one:
     rs = &rxr->slot[rxr->cur];
-    if (unlikely(rs->buf_idx < 2)) {
-        D("wrong index rx[%d] = %d", rxr->cur, rs->buf_idx);
-        sleep(2);
-    }
-    if (unlikely(rs->len > MAX_PKT)) { // XXX
-        D("wrong len rx[%d] len %d", rxr->cur, rs->len);
-        rs->len = 0;
-    }
     /* netmap makes sure that we do not receive incomplete packets */
     nfrags = 0;
     q->cur_len = 0;
@@ -1333,10 +1291,6 @@ scan_ring(struct _qs *q, int next /* bool */)
         rxr->cur = nm_ring_next(rxr, rxr->cur);
         rs = &rxr->slot[rxr->cur];
     } while (nfrags < MAX_FRAGS);
-    if (unlikely(nfrags >= MAX_FRAGS)) {
-        RD(5, "WARNING: too many fragments: truncating packet");
-        // XXX do something here
-    }
     q->cur_pkt = q->cur_frags[0].buf;
     q->cur_nfrags = nfrags;
     rxr->head = rxr->cur;
@@ -2661,6 +2615,11 @@ main(int argc, char **argv)
             D("cannot open %s", a->q.prod_ifname);
 	    exit(1);
         }
+	if (a->pa->first_rx_ring != a->pa->last_rx_ring) {
+	    D("%s has more than one rx ring", a->q.prod_ifname);
+	    exit(1);
+	}
+	a->q.rxring = NETMAP_RXRING(a->pa->nifp, a->pa->first_rx_ring);
         a->pb = nmport_open(a->q.cons_ifname);
         if (a->pb == NULL) {
             D("cannot open %s", a->q.cons_ifname);

From 70f2a2af410528947268425162093f4992bc57d4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Oct 2019 16:10:12 +0200
Subject: [PATCH 1769/2207] tlem: refactor route-mode init code

---
 apps/tlem/tlem.c | 320 ++++++++++++++++++++++++-----------------------
 1 file changed, 164 insertions(+), 156 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 7d8ae36fb..528a314ac 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -971,6 +971,168 @@ ipv4_dump(const struct ipv4_info *i)
 
 struct ipv4_info ipv4[2];
 
+static void usage();
+void
+route_mode_init(const char *ifname[], const char *gateways[])
+{
+    int fd, i;
+    struct ifreq ifr;
+#ifdef __FreeBSD__
+    struct ifaddrs *ifap, *p;
+
+    if (getifaddrs(&ifap) < 0) {
+	ED("failed to get interface list: %s", strerror(errno));
+	usage();
+    }
+#endif /* __FreeBSD__ */
+
+    fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+    if (fd < 0) {
+	ED("failed to open SOCK_DGRAM socket: %s", strerror(errno));
+	usage();
+    }
+
+    for (i = 0; i < 2; i++) {
+	struct ipv4_info *ip = &ipv4[i];
+	char *dst = ip->name;
+	const char *scan;
+	struct ether_header *eh;
+	struct ether_arp *ah;
+	void *hwaddr = NULL;
+
+	/* try to extract the port name */
+	if (!strncmp("vale", ifname[i], 4)) {
+	    ED("route mode not supported for VALE port %s", ifname[i]);
+	    usage();
+	}
+	if (strncmp("netmap:", ifname[i], 7)) {
+	    ED("missing netmap: prefix in %s", ifname[i]);
+	    usage();
+	}
+	scan = ifname[i] + 7;
+	if (strlen(scan) >= IFNAMSIZ) {
+	    ED("name too long: %s", scan);
+	    usage();
+	}
+	while (*scan && isalnum(*scan))
+	    *dst++ = *scan++;
+	*dst = '\0';
+	ED("trying to get configuration for %s", ip->name);
+
+	/* MAC address */
+#ifdef linux
+	memset(&ifr, 0, sizeof(ifr));
+	strcpy(ifr.ifr_name, ip->name);
+	if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) {
+	    hwaddr = ifr.ifr_addr.sa_data;
+	}
+#elif defined (__FreeBSD__)
+	errno = ENOENT;
+	for (p = ifap; p; p = p->ifa_next) {
+
+	    if (!strcmp(p->ifa_name, ip->name) &&
+		    p->ifa_addr != NULL &&
+		    p->ifa_addr->sa_family == AF_LINK)
+	    {
+		struct sockaddr_dl *sdp =
+		    (struct sockaddr_dl *)p->ifa_addr;
+		hwaddr = sdp->sdl_data + sdp->sdl_nlen;
+		break;
+	    }
+	}
+#endif /* __FreeBSD__ */
+	if (hwaddr == NULL) {
+	    ED("failed to get MAC address for %s: %s",
+		    ip->name, strerror(errno));
+	    usage();
+	}
+	memcpy(ip->ether_addr, hwaddr, 6);
+
+#define get_ip_info(_c, _f, _m) 						\
+	memset(&ifr, 0, sizeof(ifr));						\
+	strcpy(ifr.ifr_name, ip->name);						\
+	ifr.ifr_addr.sa_family = AF_INET;					\
+	if (ioctl(fd, _c, &ifr) < 0) {						\
+	    ED("failed to get IPv4 " _m " for %s: %s",				\
+		    ip->name, strerror(errno));					\
+	    usage();								\
+	}									\
+	memcpy(&ip->_f, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, 4);	\
+
+
+	/* IP address */
+	get_ip_info(SIOCGIFADDR, ip_addr, "address");
+	/* netmask */
+	get_ip_info(SIOCGIFNETMASK, ip_mask, "netmask");
+	/* broadcast */
+	get_ip_info(SIOCGIFBRDADDR, ip_bcast, "broadcast");
+#undef get_ip_info
+
+	/* do we have an IP address? */
+	if (ip->ip_addr == 0) {
+	    ED("no IPv4 address found for %s", ip->name);
+	    usage();
+	}
+
+	/* cache the subnet */
+	ip->ip_subnet = ip->ip_addr & ip->ip_mask;
+
+	/* default gateway, if any */
+	if (gateways[i]) {
+	    const char *gw = gateways[i];
+	    struct ipv4_info *ip = &ipv4[i];
+	    struct in_addr a;
+	    if (!inet_aton(gw, &a)) {
+		ED("not a valid IP address: %s", gw);
+		usage();
+	    }
+	    if ((a.s_addr & ip->ip_mask) != ip->ip_subnet) {
+		ED("gateway %s unreachable", gw);
+		usage();
+	    }
+	    ip->ip_gw = a.s_addr;
+	}
+
+	ipv4_dump(ip);
+
+	/* precompute the arp reply for this interface */
+	eh = &ip->arp_reply.arp.eh;
+	ah = &ip->arp_reply.arp.ah;
+	memset(&ip->arp_reply, 0, sizeof(ip->arp_reply));
+	memcpy(eh->ether_shost, ip->ether_addr, 6);
+	eh->ether_type = htons(ETHERTYPE_ARP);
+	ah->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+	ah->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+	ah->ea_hdr.ar_hln = 6;
+	ah->ea_hdr.ar_pln = 4;
+	ah->ea_hdr.ar_op = htons(ARPOP_REPLY);
+	memcpy(ah->arp_sha, ip->ether_addr, 6);
+	memcpy(ah->arp_spa, &ip->ip_addr, 4);
+
+	/* precompute the arp request for this interface */
+	eh = &ip->arp_request.arp.eh;
+	ah = &ip->arp_request.arp.ah;
+	memcpy(&ip->arp_request, &ip->arp_reply,
+		sizeof(ip->arp_reply));
+	memset(eh->ether_dhost, 0xff, 6);
+	ah->ea_hdr.ar_op = htons(ARPOP_REQUEST);
+
+	/* allocate the arp table */
+	ip->arp_table = arp_table_new(ip->ip_mask);
+	if (ip->arp_table == NULL) {
+	    ED("failed to allocate the arp table for %s: %s", ip->name,
+		    strerror(errno));
+	    usage();
+	}
+    }
+
+    close(fd);
+#ifdef __FreeBSD__
+    freeifaddrs(ifap);
+#endif /* __FreeBSD__ */
+}
+
 struct pipe_args {
 	int		zerocopy;
 	int		wait_link;
@@ -2302,162 +2464,8 @@ main(int argc, char **argv)
         }
 
         if (bp[0].route_mode) {
-            int fd;
-            struct ifreq ifr;
-#ifdef __FreeBSD__
-            struct ifaddrs *ifap, *p;
-
-            if (getifaddrs(&ifap) < 0) {
-                ED("failed to get interface list: %s", strerror(errno));
-                usage();
-            }
-#endif /* __FreeBSD__ */
-
-            fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-
-            if (fd < 0) {
-                ED("failed to open SOCK_DGRAM socket: %s", strerror(errno));
-                usage();
-            }
-
-            for (i = 0; i < 2; i++) {
-                struct ipv4_info *ip = &ipv4[i];
-                char *dst = ip->name;
-                const char *scan;
-                struct ether_header *eh;
-                struct ether_arp *ah;
-                void *hwaddr = NULL;
-
-                /* try to extract the port name */
-                if (!strncmp("vale", ifname[i], 4)) {
-                    ED("route mode not supported for VALE port %s", ifname[i]);
-                    usage();
-                }
-                if (strncmp("netmap:", ifname[i], 7)) {
-                    ED("missing netmap: prefix in %s", ifname[i]);
-                    usage();
-                }
-                scan = ifname[i] + 7;
-                if (strlen(scan) >= IFNAMSIZ) {
-                    ED("name too long: %s", scan);
-                    usage();
-                }
-                while (*scan && isalnum(*scan))
-                    *dst++ = *scan++;
-                *dst = '\0';
-                ED("trying to get configuration for %s", ip->name);
-
-                /* MAC address */
-#ifdef linux
-                memset(&ifr, 0, sizeof(ifr));
-                strcpy(ifr.ifr_name, ip->name);
-                if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) {
-                    hwaddr = ifr.ifr_addr.sa_data;
-                }
-#elif defined (__FreeBSD__)
-                errno = ENOENT;
-                for (p = ifap; p; p = p->ifa_next) {
-
-                    if (!strcmp(p->ifa_name, ip->name) &&
-                            p->ifa_addr != NULL &&
-                            p->ifa_addr->sa_family == AF_LINK)
-                    {
-                        struct sockaddr_dl *sdp =
-                            (struct sockaddr_dl *)p->ifa_addr;
-                        hwaddr = sdp->sdl_data + sdp->sdl_nlen;
-                        break;
-                    }
-                }
-#endif /* __FreeBSD__ */
-                if (hwaddr == NULL) {
-                    ED("failed to get MAC address for %s: %s",
-                            ip->name, strerror(errno));
-                    usage();
-                }
-                memcpy(ip->ether_addr, hwaddr, 6);
-
-#define get_ip_info(_c, _f, _m) 								\
-                memset(&ifr, 0, sizeof(ifr));						\
-                strcpy(ifr.ifr_name, ip->name);						\
-                ifr.ifr_addr.sa_family = AF_INET;					\
-                if (ioctl(fd, _c, &ifr) < 0) {						\
-                    ED("failed to get IPv4 " _m " for %s: %s",			\
-                            ip->name, strerror(errno));			\
-                    usage();							\
-                }									\
-                memcpy(&ip->_f, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, 4);	\
-
-
-                /* IP address */
-                get_ip_info(SIOCGIFADDR, ip_addr, "address");
-                /* netmask */
-                get_ip_info(SIOCGIFNETMASK, ip_mask, "netmask");
-                /* broadcast */
-                get_ip_info(SIOCGIFBRDADDR, ip_bcast, "broadcast");
-#undef get_ip_info
-
-                /* do we have an IP address? */
-                if (ip->ip_addr == 0) {
-                    ED("no IPv4 address found for %s", ip->name);
-                    usage();
-                }
-
-                /* cache the subnet */
-                ip->ip_subnet = ip->ip_addr & ip->ip_mask;
-
-                /* default gateway, if any */
-                if (invdopt['G']->arg[i]) {
-                    const char *gw = invdopt['G']->arg[i];
-                    struct ipv4_info *ip = &ipv4[i];
-                    struct in_addr a;
-                    if (!inet_aton(gw, &a)) {
-                        ED("not a valid IP address: %s", gw);
-                        usage();
-                    }
-                    if ((a.s_addr & ip->ip_mask) != ip->ip_subnet) {
-                        ED("gateway %s unreachable", gw);
-                        usage();
-                    }
-                    ip->ip_gw = a.s_addr;
-                }
-
-                ipv4_dump(ip);
-
-                /* precompute the arp reply for this interface */
-                eh = &ip->arp_reply.arp.eh;
-                ah = &ip->arp_reply.arp.ah;
-                memset(&ip->arp_reply, 0, sizeof(ip->arp_reply));
-                memcpy(eh->ether_shost, ip->ether_addr, 6);
-                eh->ether_type = htons(ETHERTYPE_ARP);
-                ah->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
-                ah->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
-                ah->ea_hdr.ar_hln = 6;
-                ah->ea_hdr.ar_pln = 4;
-                ah->ea_hdr.ar_op = htons(ARPOP_REPLY);
-                memcpy(ah->arp_sha, ip->ether_addr, 6);
-                memcpy(ah->arp_spa, &ip->ip_addr, 4);
-
-                /* precompute the arp request for this interface */
-                eh = &ip->arp_request.arp.eh;
-                ah = &ip->arp_request.arp.ah;
-                memcpy(&ip->arp_request, &ip->arp_reply,
-                        sizeof(ip->arp_reply));
-                memset(eh->ether_dhost, 0xff, 6);
-                ah->ea_hdr.ar_op = htons(ARPOP_REQUEST);
-
-                /* allocate the arp table */
-                ip->arp_table = arp_table_new(ip->ip_mask);
-                if (ip->arp_table == NULL) {
-                    ED("failed to allocate the arp table for %s: %s", ip->name,
-                            strerror(errno));
-                    usage();
-                }
-            }
-
-            close(fd);
-#ifdef __FreeBSD__
-            freeifaddrs(ifap);
-#endif /* __FreeBSD__ */
+	    const char *gateways[] = { invdopt['G']->arg[0], invdopt['G']->arg[1] };
+	    route_mode_init(ifname, gateways);
         }
 
         bp[1] = bp[0]; /* copy parameters, but swap interfaces */

From d50134a8823d2fccc230a233f436588e50216f4c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 13 Feb 2020 18:13:44 +0100
Subject: [PATCH 1770/2207] tlem: update the man page

---
 apps/tlem/tlem.8 | 47 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 5 deletions(-)

diff --git a/apps/tlem/tlem.8 b/apps/tlem/tlem.8
index 14ce43461..54176c1e4 100644
--- a/apps/tlem/tlem.8
+++ b/apps/tlem/tlem.8
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 16, 2016
+.Dd February 13, 2020
 .Dt TLEM 1
 .Os
 .Sh NAME
@@ -39,13 +39,17 @@
 .Op Fl D Ar delay
 .Op Fl L Ar loss
 .Op Fl R Ar reordering
-.Op Fl Q Ar queue size
+.Op Fl Q Ar queue-size
 .Op Fl C Ar cpu-placement
 .Op Fl G Ar gateway
-.Op Fl b Ar batch size
+.Op Fl b Ar batch-size
 .Op Fl w Ar wait-link
+.Op Fl s Ar session-name
+.Op Fl a
 .Op Fl v
+.Op Fl q
 .Op Fl r
+.Op Fl M Ar max-bw Ns Cm , Ns Ar max-delay Ns Cm , Ns Ar max-hold
 .El
 .Sh DESCRIPTION
 .Nm
@@ -145,8 +149,31 @@ Indicates the optional default gateways to be used in route-mode.
 indicates the number of seconds to wait before transmitting.
 It defaults to 2, and may be useful when talking to physical
 ports to let link negotiation complete before starting transmission.
+.It Fl s Ar session-file
+Enables client/server mode. The first instance of
+.Nm
+that successfully creates and/or locks the
+.Ar session-file
+becomes the server. Other
+.Nm
+instances that use the same
+.Ar session-file
+do not start new emulations, but rather send their emulation parameters
+to the server. This feature can be used to dynamically change the
+emulation parameters of a running emulation. Please note that the
+internal buffers are not re-allocated, and therefore the dynamic emulated
+delay and bandwidth can never exceed the values used initially be the
+server. Alternatively, the
+.Fl M
+option can be used when starting the server to set the maximum bandwidth, delay
+and hold-time that can be accepted in client requests.
+.It Fl a
+Only useful in client/server mode. Ask the server to shutdown
+and wait until it terminates.
 .It Fl v
-Enable verbose mode
+Increase verbosity.
+.It Fl q
+Decrease verbosity.
 .It Fl b Ar batch-size
 Maximum batch size to use during transmissions.
 .Nm
@@ -155,6 +182,13 @@ larger batches, up to the value specified with this option,
 when running at high rates.
 .It Fl r
 Enable route-mode.
+.It Fl M Ar max-bw Ns Cm , Ns Ar max-delay Ns Cm , Ns Ar max-hold
+
+Set the maximum bandwidth, delay and packet-reordering
+hold-time. The paramethers are only meaningful for the
+server process when operating in client/server mode (see the
+.Fl s
+option).
 .El
 .Sh OPERATION
 .Nm
@@ -208,7 +242,10 @@ http://info.iet.unipi.it/~luigi/research.html
 has been written by
 .An Luigi Rizzo
 at the Universita` di Pisa, Italy.
+Route mode and client/server operation has been added by Giuseppe Lettieri
+at the Univerista` di Pisa, Italy.
 .Pp
 This work has received funding from the European
 Union's Horizon 2020 research and innovation programme
-2014-2018 under grant agreement No. 644866.
+2014-2018 under grant agreement No. 644866, and from
+East Cost Datacom Inc., Rockledge, FL, USA.

From 3460a4296beadf73818a88f8b5d83b286dd5f5ed Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 13 Feb 2020 18:18:59 +0100
Subject: [PATCH 1771/2207] tlem: fix spelling in the man page

---
 apps/tlem/tlem.8 | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/apps/tlem/tlem.8 b/apps/tlem/tlem.8
index 54176c1e4..f5b600a3f 100644
--- a/apps/tlem/tlem.8
+++ b/apps/tlem/tlem.8
@@ -96,7 +96,7 @@ specified once (in which case they affect both directions),
 or twice (once per direction).
 .Bl -tag -width Ds
 .It Fl i Ar port
-Name of the netmap port. It must be supplied exactly twice to indentify
+Name of the netmap port. It must be supplied exactly twice to identify
 the two ports that must be interconnected.
 Any netmap port type (physical interface, VALE switch, pipe, monitor port...)
 can be used.
@@ -136,7 +136,7 @@ the loss and delay arguments.
 .It Fl Q Ar size
 Queue size,
 .Ar size
-is a number optionally folllowed by k, K, m, M, g, G to specify
+is a number optionally followed by k, K, m, M, g, G to specify
 the queue size in bytes, Kilobytes, Megabytes, Gigabytes.
 The queue is used to buffer incoming packets before bandwidth
 limitations are applied.
@@ -158,11 +158,11 @@ becomes the server. Other
 .Nm
 instances that use the same
 .Ar session-file
-do not start new emulations, but rather send their emulation parameters
+do not start new emulations, but rather send their parameters
 to the server. This feature can be used to dynamically change the
 emulation parameters of a running emulation. Please note that the
 internal buffers are not re-allocated, and therefore the dynamic emulated
-delay and bandwidth can never exceed the values used initially be the
+delay and bandwidth can never exceed the values used initially by the
 server. Alternatively, the
 .Fl M
 option can be used when starting the server to set the maximum bandwidth, delay
@@ -185,7 +185,7 @@ Enable route-mode.
 .It Fl M Ar max-bw Ns Cm , Ns Ar max-delay Ns Cm , Ns Ar max-hold
 
 Set the maximum bandwidth, delay and packet-reordering
-hold-time. The paramethers are only meaningful for the
+hold-time. The parameters are only meaningful for the
 server process when operating in client/server mode (see the
 .Fl s
 option).

From a0480ca880a02f8eb99163d2f1ac23072185f88c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 14 Feb 2020 12:47:20 +0100
Subject: [PATCH 1772/2207] tlem: print a warning instead of failing on
 multi-ring NICs

---
 apps/tlem/tlem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 528a314ac..7fd655e77 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2624,8 +2624,8 @@ main(int argc, char **argv)
 	    exit(1);
         }
 	if (a->pa->first_rx_ring != a->pa->last_rx_ring) {
-	    D("%s has more than one rx ring", a->q.prod_ifname);
-	    exit(1);
+	    D("WARNING: %s has more than one rx ring; only ring %d will be used",
+			    a->q.prod_ifname, a->pa->first_rx_ring);
 	}
 	a->q.rxring = NETMAP_RXRING(a->pa->nifp, a->pa->first_rx_ring);
         a->pb = nmport_open(a->q.cons_ifname);

From 34ea6ff3d630d2700135596b5030d7a854d8fa3c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 5 Mar 2020 11:01:24 +0100
Subject: [PATCH 1773/2207] linux/i40e: patch for Intel 2.11.21 version

---
 LINUX/final-patches/intel--i40e--2.11.21 | 156 +++++++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.11.21

diff --git a/LINUX/final-patches/intel--i40e--2.11.21 b/LINUX/final-patches/intel--i40e--2.11.21
new file mode 100644
index 000000000..e9823dcad
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.11.21
@@ -0,0 +1,156 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 81f5ab9..85bfb8c 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index bd4b467..58e7855 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -146,6 +146,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3539,6 +3544,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3620,6 +3629,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13959,6 +13973,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14331,6 +14350,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 96bc531..106f9b7 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2559,6 +2568,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 4468c707b76311c9f32d9d5c365208b3d47013ac Mon Sep 17 00:00:00 2001
From: Jose Luis Duran 
Date: Tue, 31 Mar 2020 06:19:34 -0300
Subject: [PATCH 1774/2207] Fix a typo in man vale-ctl(4)

---
 apps/vale-ctl/vale-ctl.4 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/vale-ctl/vale-ctl.4 b/apps/vale-ctl/vale-ctl.4
index 67e07e59f..09ba27121 100644
--- a/apps/vale-ctl/vale-ctl.4
+++ b/apps/vale-ctl/vale-ctl.4
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 24, 2018
+.Dd March 31, 2020
 .Dt VALE-CTL 4
 .Os
 .Sh NAME
@@ -95,7 +95,7 @@ Create a new persistent VALE port with name
 .Ar interface .
 The name must be different from any other network interface
 already present in the system.
-.It Fl d Ar interface
+.It Fl r Ar interface
 Destroy the persistent VALE port with name
 .Ar inteface .
 .It Fl l Ar valeSSS:PPP

From 5a0b906f00a4ad84b4758523d0d7da22aaef4307 Mon Sep 17 00:00:00 2001
From: Chris Packham 
Date: Wed, 15 Apr 2020 14:58:57 +1200
Subject: [PATCH 1775/2207] linux/configure: check for struct timeval

As of Linux v5.6 struct timeval does not exist (in the kernel). Detect
this and define our own when needed.

Fixes #689

Signed-off-by: Chris Packham 
---
 LINUX/bsd_glue.h |  7 +++++++
 LINUX/configure  | 12 ++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 8dc75b3cb..97e026fbe 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -440,6 +440,13 @@ struct nm_linux_selrecord_t;
 
 #define	tsleep(a, b, c, t)	msleep(10)
 
+#ifndef NETMAP_LINUX_HAVE_STRUCT_TIMEVAL
+struct timeval {
+	long	tv_sec;		/* seconds */
+	long	tv_usec;	/* microseconds */
+};
+#endif /* !NETMAP_LINUX_HAVE_STRUCT_TIMEVAL */
+
 #define microtime		do_gettimeofday		/* debugging */
 #ifndef NETMAP_LINUX_HAVE_DO_GETTIMEOFDAY
 #define do_gettimeofday(tv_)					\
diff --git a/LINUX/configure b/LINUX/configure
index cd63cb908..64300edf8 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1740,6 +1740,18 @@ EOF
 	}
 EOF
 
+  # is struct timeval defined?
+  add_test 'have STRUCT_TIMEVAL' << EOF
+	#include 
+
+	void
+	dummy(struct timeval *tv) {
+		tv->tv_sec = 0;
+		tv->tv_usec = 0;
+		return;
+	}
+EOF
+
   add_test 'have DO_GETTIMEOFDAY' <
 

From bf2a924e5e9e71521075dc731ace58a5a67f41b5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 28 Mar 2020 14:28:37 +0100
Subject: [PATCH 1776/2207] libnetmap: fix parsing of extmem options

---
 libnetmap/nmport.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 21dc7cbff..736a62c43 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -142,6 +142,7 @@ static struct nmreq_opt_parser *nmport_opt_parsers;
 
 #define NPOPT_PARSER(o)		nmport_opt_##o##_parser
 #define NPOPT_DESC(o)		nmport_opt_##o##_desc
+#define NPOPT_NRKEYS(o)		(NPOPT_DESC(o).nr_keys)
 #define NPOPT_DECL(o, f)						\
 static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *);			\
 static struct nmreq_opt_parser NPOPT_DESC(o) = {			\
@@ -252,7 +253,7 @@ NPOPT_PARSER(extmem)(struct nmreq_parse_ctx *p)
 
 	pi = &d->extmem->nro_info;
 
-	for  (i = 1; i < 7; i++) {
+	for  (i = 0; i < NPOPT_NRKEYS(extmem); i++) {
 		const char *k = p->keys[i];
 		uint32_t v;
 

From 236bc0c622cd6e479b9d1ea4f5f73683cf92a7cb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 28 Mar 2020 16:06:50 +0100
Subject: [PATCH 1777/2207] libnetmap: fix missing netmap_extmem() function

---
 libnetmap/nmport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 736a62c43..2ace0a6c2 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -51,7 +51,7 @@ nmport_delete(struct nmport_d *d)
 }
 
 int
-nmport_extmem_from_mem(struct nmport_d *d, void *base, size_t size)
+nmport_extmem(struct nmport_d *d, void *base, size_t size)
 {
 	struct nmctx *ctx = d->ctx;
 
@@ -106,7 +106,7 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 	}
 	d->extmem_autounmap = 1;
 
-	if (nmport_extmem_from_mem(d, p, mapsize) < 0)
+	if (nmport_extmem(d, p, mapsize) < 0)
 		goto fail;
 
 	close(fd);

From a54363b4d8fc722a2177c353402daf1aa0bc8bb7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 28 Mar 2020 16:09:07 +0100
Subject: [PATCH 1778/2207] libnetmap: fix comment for nmport_extmem_from_file

---
 libnetmap/libnetmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index bbca3bd27..74617febe 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -372,7 +372,7 @@ struct nmport_d *nmport_clone(struct nmport_d *);
  */
 int nmport_extmem(struct nmport_d *d, void *base, size_t size);
 
-/* nmport_extmem - use the extmem obtained by mapping a file
+/* nmport_extmem_from_file - use the extmem obtained by mapping a file
  * @d		the port we want to use the extmem for
  * @fname	path of the file we want to map
  *

From f3bfa06222d669a882e9575604184caecd7843dd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 28 Mar 2020 16:19:32 +0100
Subject: [PATCH 1779/2207] libnetmap: add function to get extmem pools info

---
 libnetmap/libnetmap.h | 11 +++++++++++
 libnetmap/nmport.c    |  8 ++++++++
 2 files changed, 19 insertions(+)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 74617febe..cf0ecd51e 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -386,6 +386,17 @@ int nmport_extmem(struct nmport_d *d, void *base, size_t size);
  */
 int nmport_extmem_from_file(struct nmport_d *d, const char *fname);
 
+/* nmport_extmem_getinfo - opbtai a pointer to the extmem configuration
+ * @d		the port we want to obtain the pointer from
+ *
+ * Returns a pointer to the nmreq_pools_info structure containing the
+ * configuration of the extmem attached to port @d, or NULL if no extmem
+ * is attached. This can be used to set the desired configuration before
+ * registering the port, or to read the actual configuration after
+ * registration.
+ */
+struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
+
 /* nmport_undo_extmem - remove the extmem option, if any
  * @d		the port we want to remove the extmem from
  *
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 2ace0a6c2..30ad1b6c8 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -120,6 +120,14 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 	return -1;
 }
 
+struct nmreq_pools_info*
+nmport_extmem_getinfo(struct nmport_d *d)
+{
+	if (d->extmem == NULL)
+		return NULL;
+	return &d->extmem->nro_info;
+}
+
 void
 nmport_undo_extmem(struct nmport_d *d)
 {

From 406186097b4eb6a0bd645dd72222b63929a61086 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 10 Apr 2020 12:28:38 +0200
Subject: [PATCH 1780/2207] mem: uniform callback parameters

---
 sys/dev/netmap/netmap_mem2.c | 139 ++++++++++++++++++-----------------
 1 file changed, 71 insertions(+), 68 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 88e715d3a..7c8d2b65d 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -151,11 +151,14 @@ struct netmap_mem_ops {
 	ssize_t  (*nmd_if_offset)(struct netmap_mem_d *, const void *vaddr);
 	void (*nmd_delete)(struct netmap_mem_d *);
 
-	struct netmap_if * (*nmd_if_new)(struct netmap_adapter *,
-					 struct netmap_priv_d *);
-	void (*nmd_if_delete)(struct netmap_adapter *, struct netmap_if *);
-	int  (*nmd_rings_create)(struct netmap_adapter *);
-	void (*nmd_rings_delete)(struct netmap_adapter *);
+	struct netmap_if * (*nmd_if_new)(struct netmap_mem_d *,
+			struct netmap_adapter *, struct netmap_priv_d *);
+	void (*nmd_if_delete)(struct netmap_mem_d *,
+			struct netmap_adapter *, struct netmap_if *);
+	int  (*nmd_rings_create)(struct netmap_mem_d *,
+			struct netmap_adapter *);
+	void (*nmd_rings_delete)(struct netmap_mem_d *,
+			struct netmap_adapter *);
 };
 
 struct netmap_mem_d {
@@ -267,7 +270,7 @@ netmap_mem_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	struct netmap_mem_d *nmd = na->nm_mem;
 
 	NMA_LOCK(nmd);
-	nifp = nmd->ops->nmd_if_new(na, priv);
+	nifp = nmd->ops->nmd_if_new(nmd, na, priv);
 	NMA_UNLOCK(nmd);
 
 	return nifp;
@@ -279,7 +282,7 @@ netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nif)
 	struct netmap_mem_d *nmd = na->nm_mem;
 
 	NMA_LOCK(nmd);
-	nmd->ops->nmd_if_delete(na, nif);
+	nmd->ops->nmd_if_delete(nmd, na, nif);
 	NMA_UNLOCK(nmd);
 }
 
@@ -290,7 +293,7 @@ netmap_mem_rings_create(struct netmap_adapter *na)
 	struct netmap_mem_d *nmd = na->nm_mem;
 
 	NMA_LOCK(nmd);
-	rv = nmd->ops->nmd_rings_create(na);
+	rv = nmd->ops->nmd_rings_create(nmd, na);
 	NMA_UNLOCK(nmd);
 
 	return rv;
@@ -302,7 +305,7 @@ netmap_mem_rings_delete(struct netmap_adapter *na)
 	struct netmap_mem_d *nmd = na->nm_mem;
 
 	NMA_LOCK(nmd);
-	nmd->ops->nmd_rings_delete(na);
+	nmd->ops->nmd_rings_delete(nmd, na);
 	NMA_UNLOCK(nmd);
 }
 
@@ -1854,36 +1857,6 @@ netmap_mem_fini(void)
 	netmap_mem_put(&nm_mem);
 }
 
-static void
-netmap_free_rings(struct netmap_adapter *na)
-{
-	enum txrx t;
-
-	for_rx_tx(t) {
-		u_int i;
-		for (i = 0; i < netmap_all_rings(na, t); i++) {
-			struct netmap_kring *kring = NMR(na, t)[i];
-			struct netmap_ring *ring = kring->ring;
-
-			if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) {
-				if (netmap_debug & NM_DEBUG_MEM)
-					nm_prinf("NOT deleting ring %s (ring %p, users %d neekring %d)",
-						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
-				continue;
-			}
-			if (netmap_debug & NM_DEBUG_MEM)
-				nm_prinf("deleting ring %s", kring->name);
-			if (!(kring->nr_kflags & NKR_FAKERING)) {
-				nm_prdis("freeing bufs for %s", kring->name);
-				netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots);
-			} else {
-				nm_prdis("NOT freeing bufs for %s", kring->name);
-			}
-			netmap_ring_free(na->nm_mem, ring);
-			kring->ring = NULL;
-		}
-	}
-}
 
 /* call with NMA_LOCK held *
  *
@@ -1893,7 +1866,7 @@ netmap_free_rings(struct netmap_adapter *na)
  * in netmap_krings_create().
  */
 static int
-netmap_mem2_rings_create(struct netmap_adapter *na)
+netmap_mem2_rings_create(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	enum txrx t;
 
@@ -1917,7 +1890,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 			ndesc = kring->nkr_num_slots;
 			len = sizeof(struct netmap_ring) +
 				  ndesc * sizeof(struct netmap_slot);
-			ring = netmap_ring_malloc(na->nm_mem, len);
+			ring = netmap_ring_malloc(nmd, len);
 			if (ring == NULL) {
 				nm_prerr("Cannot allocate %s_ring", nm_txrx2str(t));
 				goto cleanup;
@@ -1926,16 +1899,16 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 			kring->ring = ring;
 			*(uint32_t *)(uintptr_t)&ring->num_slots = ndesc;
 			*(int64_t *)(uintptr_t)&ring->buf_ofs =
-			    (na->nm_mem->pools[NETMAP_IF_POOL].memtotal +
-				na->nm_mem->pools[NETMAP_RING_POOL].memtotal) -
-				netmap_ring_offset(na->nm_mem, ring);
+			    (nmd->pools[NETMAP_IF_POOL].memtotal +
+				nmd->pools[NETMAP_RING_POOL].memtotal) -
+				netmap_ring_offset(nmd, ring);
 
 			/* copy values from kring */
 			ring->head = kring->rhead;
 			ring->cur = kring->rcur;
 			ring->tail = kring->rtail;
 			*(uint32_t *)(uintptr_t)&ring->nr_buf_size =
-				netmap_mem_bufsize(na->nm_mem);
+				netmap_mem_bufsize(nmd);
 			nm_prdis("%s h %d c %d t %d", kring->name,
 				ring->head, ring->cur, ring->tail);
 			nm_prdis("initializing slots for %s_ring", nm_txrx2str(t));
@@ -1943,7 +1916,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 				/* this is a real ring */
 				if (netmap_debug & NM_DEBUG_MEM)
 					nm_prinf("allocating buffers for %s", kring->name);
-				if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) {
+				if (netmap_new_bufs(nmd, ring->slot, ndesc)) {
 					nm_prerr("Cannot allocate buffers for %s_ring", nm_txrx2str(t));
 					goto cleanup;
 				}
@@ -1951,7 +1924,7 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 				/* this is a fake ring, set all indices to 0 */
 				if (netmap_debug & NM_DEBUG_MEM)
 					nm_prinf("NOT allocating buffers for %s", kring->name);
-				netmap_mem_set_ring(na->nm_mem, ring->slot, ndesc, 0);
+				netmap_mem_set_ring(nmd, ring->slot, ndesc, 0);
 			}
 		        /* ring info */
 		        *(uint16_t *)(uintptr_t)&ring->ringid = kring->ring_id;
@@ -1972,12 +1945,35 @@ netmap_mem2_rings_create(struct netmap_adapter *na)
 }
 
 static void
-netmap_mem2_rings_delete(struct netmap_adapter *na)
+netmap_mem2_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
-	/* last instance, release bufs and rings */
-	netmap_free_rings(na);
-}
+	enum txrx t;
 
+	for_rx_tx(t) {
+		u_int i;
+		for (i = 0; i < netmap_all_rings(na, t); i++) {
+			struct netmap_kring *kring = NMR(na, t)[i];
+			struct netmap_ring *ring = kring->ring;
+
+			if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) {
+				if (netmap_debug & NM_DEBUG_MEM)
+					nm_prinf("NOT deleting ring %s (ring %p, users %d neekring %d)",
+						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
+				continue;
+			}
+			if (netmap_debug & NM_DEBUG_MEM)
+				nm_prinf("deleting ring %s", kring->name);
+			if (!(kring->nr_kflags & NKR_FAKERING)) {
+				nm_prdis("freeing bufs for %s", kring->name);
+				netmap_free_bufs(nmd, ring->slot, kring->nkr_num_slots);
+			} else {
+				nm_prdis("NOT freeing bufs for %s", kring->name);
+			}
+			netmap_ring_free(nmd, ring);
+			kring->ring = NULL;
+		}
+	}
+}
 
 /* call with NMA_LOCK held */
 /*
@@ -1988,7 +1984,8 @@ netmap_mem2_rings_delete(struct netmap_adapter *na)
  * the interface is in netmap mode.
  */
 static struct netmap_if *
-netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
+netmap_mem2_if_new(struct netmap_mem_d *nmd,
+		struct netmap_adapter *na, struct netmap_priv_d *priv)
 {
 	struct netmap_if *nifp;
 	ssize_t base; /* handy for relative offsets between rings and nifp */
@@ -2007,9 +2004,9 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	 */
 
 	len = sizeof(struct netmap_if) + (ntot * sizeof(ssize_t));
-	nifp = netmap_if_malloc(na->nm_mem, len);
+	nifp = netmap_if_malloc(nmd, len);
 	if (nifp == NULL) {
-		NMA_UNLOCK(na->nm_mem);
+		NMA_UNLOCK(nmd);
 		return NULL;
 	}
 
@@ -2027,7 +2024,7 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 	 * between the ring and nifp, so the information is usable in
 	 * userspace to reach the ring from the nifp.
 	 */
-	base = netmap_if_offset(na->nm_mem, nifp);
+	base = netmap_if_offset(nmd, nifp);
 	for (i = 0; i < n[NR_TX]; i++) {
 		/* XXX instead of ofs == 0 maybe use the offset of an error
 		 * ring, like we do for buffers? */
@@ -2035,7 +2032,7 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 
 		if (na->tx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_TX]
 				&& i < priv->np_qlast[NR_TX]) {
-			ofs = netmap_ring_offset(na->nm_mem,
+			ofs = netmap_ring_offset(nmd,
 						 na->tx_rings[i]->ring) - base;
 		}
 		*(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = ofs;
@@ -2047,7 +2044,7 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 
 		if (na->rx_rings[i]->ring != NULL && i >= priv->np_qfirst[NR_RX]
 				&& i < priv->np_qlast[NR_RX]) {
-			ofs = netmap_ring_offset(na->nm_mem,
+			ofs = netmap_ring_offset(nmd,
 						 na->rx_rings[i]->ring) - base;
 		}
 		*(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = ofs;
@@ -2057,14 +2054,15 @@ netmap_mem2_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
 }
 
 static void
-netmap_mem2_if_delete(struct netmap_adapter *na, struct netmap_if *nifp)
+netmap_mem2_if_delete(struct netmap_mem_d *nmd,
+		struct netmap_adapter *na, struct netmap_if *nifp)
 {
 	if (nifp == NULL)
 		/* nothing to do */
 		return;
 	if (nifp->ni_bufs_head)
 		netmap_extra_free(na, nifp->ni_bufs_head);
-	netmap_if_free(na->nm_mem, nifp);
+	netmap_if_free(nmd, nifp);
 }
 
 static void
@@ -2633,13 +2631,14 @@ netmap_mem_pt_guest_delete(struct netmap_mem_d *nmd)
 }
 
 static struct netmap_if *
-netmap_mem_pt_guest_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv)
+netmap_mem_pt_guest_if_new(struct netmap_mem_d *nmd,
+		struct netmap_adapter *na, struct netmap_priv_d *priv)
 {
-	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)na->nm_mem;
+	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 	struct mem_pt_if *ptif;
 	struct netmap_if *nifp = NULL;
 
-	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
+	ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp);
 	if (ptif == NULL) {
 		nm_prerr("interface %s is not in passthrough", na->name);
 		goto out;
@@ -2652,25 +2651,27 @@ netmap_mem_pt_guest_if_new(struct netmap_adapter *na, struct netmap_priv_d *priv
 }
 
 static void
-netmap_mem_pt_guest_if_delete(struct netmap_adapter *na, struct netmap_if *nifp)
+netmap_mem_pt_guest_if_delete(struct netmap_mem_d * nmd,
+		struct netmap_adapter *na, struct netmap_if *nifp)
 {
 	struct mem_pt_if *ptif;
 
-	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
+	ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp);
 	if (ptif == NULL) {
 		nm_prerr("interface %s is not in passthrough", na->name);
 	}
 }
 
 static int
-netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
+netmap_mem_pt_guest_rings_create(struct netmap_mem_d *nmd,
+		struct netmap_adapter *na)
 {
-	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)na->nm_mem;
+	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 	struct mem_pt_if *ptif;
 	struct netmap_if *nifp;
 	int i, error = -1;
 
-	ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp);
+	ptif = netmap_mem_pt_guest_ifp_lookup(nmd, na->ifp);
 	if (ptif == NULL) {
 		nm_prerr("interface %s is not in passthrough", na->name);
 		goto out;
@@ -2701,7 +2702,7 @@ netmap_mem_pt_guest_rings_create(struct netmap_adapter *na)
 }
 
 static void
-netmap_mem_pt_guest_rings_delete(struct netmap_adapter *na)
+netmap_mem_pt_guest_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 #if 0
 	enum txrx t;
@@ -2715,6 +2716,8 @@ netmap_mem_pt_guest_rings_delete(struct netmap_adapter *na)
 		}
 	}
 #endif
+	(void)nmd;
+	(void)na;
 }
 
 static struct netmap_mem_ops netmap_mem_pt_guest_ops = {

From 4cca7280fe22dc1a368ae1c2a69af79fdbf687ca Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 May 2020 16:23:45 +0200
Subject: [PATCH 1781/2207] libnetmap: generic cleanup functions

---
 libnetmap/libnetmap.h |  3 +++
 libnetmap/nmport.c    | 31 +++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index cf0ecd51e..588b41ddc 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -186,6 +186,9 @@ struct nmport_d {
 	uint16_t last_rx_ring;
 	uint16_t cur_tx_ring;		/* used by nmport_inject */
 	uint16_t cur_rx_ring;
+
+	/* LIFO list of cleanup functions (used internally) */
+	struct nmport_cleanup_d *clist;
 };
 
 /* nmport_open - opens a port from a portspec
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 30ad1b6c8..65061bc58 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -14,6 +14,36 @@
 #define LIBNETMAP_NOTHREADSAFE
 #include "libnetmap.h"
 
+struct nmport_cleanup_d {
+	struct nmport_cleanup_d *next;
+	void (*cleanup)(struct nmport_cleanup_d *, struct nmport_d *);
+};
+
+static void
+nmport_push_cleanup(struct nmport_d *d, struct nmport_cleanup_d *c)
+{
+	c->next = d->clist;
+	d->clist = c;
+}
+
+static void
+nmport_pop_cleanup(struct nmport_d *d)
+{
+	struct nmport_cleanup_d *top;
+
+	top = d->clist;
+	d->clist = d->clist->next;
+	(*top->cleanup)(top, d);
+	nmctx_free(d->ctx, top);
+}
+
+void nmport_do_cleanup(struct nmport_d *d)
+{
+	while (d->clist != NULL) {
+		nmport_pop_cleanup(d);
+	}
+}
+
 static struct nmport_d *
 nmport_new_with_ctx(struct nmctx *ctx)
 {
@@ -387,6 +417,7 @@ void
 nmport_undo_parse(struct nmport_d *d)
 {
 	nmport_undo_extmem(d);
+	nmport_do_cleanup(d);
 	memset(&d->reg, 0, sizeof(d->reg));
 	memset(&d->hdr, 0, sizeof(d->hdr));
 }

From bc0cb47c7f81a058c87535275334e6813098ea5e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 May 2020 16:24:39 +0200
Subject: [PATCH 1782/2207] libnetmap: use generic cleanup for extmem-from-file

---
 libnetmap/libnetmap.h |  1 -
 libnetmap/nmport.c    | 46 ++++++++++++++++++++++++++++++++-----------
 2 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 588b41ddc..3a3339379 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -175,7 +175,6 @@ struct nmport_d {
 	int mmap_done;		/* nmport_mmap() has been called */
 	/* pointer to the extmem option contained in the hdr options, if any */
 	struct nmreq_opt_extmem *extmem;
-	int extmem_autounmap;	/* 1 if nmport_undo_extmem should also munmap */
 
 	/* the fields below are compatible with nm_open() */
 	int fd;				/* "/dev/netmap", -1 if not open */
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 65061bc58..ec1ff9ecb 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -111,6 +111,21 @@ nmport_extmem(struct nmport_d *d, void *base, size_t size)
 	return 0;
 }
 
+struct nmport_extmem_from_file_cleanup_d {
+	struct nmport_cleanup_d up;
+	void *p;
+	size_t size;
+};
+
+void nmport_extmem_from_file_cleanup(struct nmport_cleanup_d *c,
+		struct nmport_d *d)
+{
+	struct nmport_extmem_from_file_cleanup_d *cc =
+		(struct nmport_extmem_from_file_cleanup_d *)c;
+
+	munmap(cc->p, cc->size);
+}
+
 int
 nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 {
@@ -118,6 +133,14 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 	int fd = -1;
 	off_t mapsize;
 	void *p;
+	struct nmport_extmem_from_file_cleanup_d *clnup = NULL;
+
+	clnup = nmctx_malloc(ctx, sizeof(*clnup));
+	if (clnup == NULL) {
+		nmctx_ferror(ctx, "cannot allocate cleanup descriptor");
+		errno = ENOMEM;
+		goto fail;
+	}
 
 	fd = open(fname, O_RDWR);
 	if (fd < 0) {
@@ -134,19 +157,27 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 		nmctx_ferror(ctx, "cannot mmap '%s': %s", fname, strerror(errno));
 		goto fail;
 	}
-	d->extmem_autounmap = 1;
+	close(fd);
+
+	clnup->p = p;
+	clnup->size = mapsize;
+	clnup->up.cleanup = nmport_extmem_from_file_cleanup;
+	nmport_push_cleanup(d, &clnup->up);
 
 	if (nmport_extmem(d, p, mapsize) < 0)
 		goto fail;
 
-	close(fd);
-
 	return 0;
 
 fail:
 	if (fd >= 0)
 		close(fd);
-	nmport_undo_extmem(d);
+	if (clnup != NULL) {
+		if (clnup->p != MAP_FAILED)
+			nmport_pop_cleanup(d);
+		else
+			nmctx_free(ctx, clnup);
+	}
 	return -1;
 }
 
@@ -161,18 +192,12 @@ nmport_extmem_getinfo(struct nmport_d *d)
 void
 nmport_undo_extmem(struct nmport_d *d)
 {
-	void *p;
-
 	if (d->extmem == NULL)
 		return;
 
-	p = (void *)d->extmem->nro_usrptr;
-	if (p != MAP_FAILED && d->extmem_autounmap)
-		munmap(p, d->extmem->nro_info.nr_memsize);
 	nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
 	nmctx_free(d->ctx, d->extmem);
 	d->extmem = NULL;
-	d->extmem_autounmap = 0;
 }
 
 /* head of the list of options */
@@ -704,7 +729,6 @@ nmport_clone(struct nmport_d *d)
 	c->register_done = 0;
 	c->mem = NULL;
 	c->extmem = NULL;
-	c->extmem_autounmap = 0;
 	c->mmap_done = 0;
 	c->first_tx_ring = 0;
 	c->last_tx_ring = 0;

From ce34dfb7b478ca55a2af9adb58633911b725ab8c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 May 2020 18:23:13 +0200
Subject: [PATCH 1783/2207] libnetmap: function to get option name from reqtype

---
 libnetmap/libnetmap.h |  1 +
 libnetmap/nmreq.c     | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 3a3339379..4abc65c18 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -561,6 +561,7 @@ void nmreq_push_option(struct nmreq_header *, struct nmreq_option *);
 void nmreq_remove_option(struct nmreq_header *, struct nmreq_option *);
 struct nmreq_option *nmreq_find_option(struct nmreq_header *, uint32_t);
 void nmreq_free_options(struct nmreq_header *);
+const char* nmreq_option_name(uint32_t);
 
 /* nmctx manipulation */
 
diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index 71f420df5..26a395cea 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -608,6 +608,23 @@ nmreq_free_options(struct nmreq_header *h)
 	}
 }
 
+const char*
+nmreq_option_name(uint32_t nro_reqtype)
+{
+	switch (nro_reqtype) {
+	case NETMAP_REQ_OPT_EXTMEM:
+		return "extmem";
+	case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
+		return "sync-kloop-eventfds";
+	case NETMAP_REQ_OPT_CSB:
+		return "csb";
+	case NETMAP_REQ_OPT_SYNC_KLOOP_MODE:
+		return "sync-kloop-mode";
+	default:
+		return "unknown";
+	}
+}
+
 #if 0
 #include 
 static void

From 9c566c8d843f47bab17d1c76b728327f5b50e9c3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 May 2020 18:33:47 +0200
Subject: [PATCH 1784/2207] libnetmap: generalize options error printout

---
 libnetmap/libnetmap.h |  4 ++++
 libnetmap/nmport.c    | 18 ++++++++++++++----
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 4abc65c18..41477d6f7 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -562,6 +562,10 @@ void nmreq_remove_option(struct nmreq_header *, struct nmreq_option *);
 struct nmreq_option *nmreq_find_option(struct nmreq_header *, uint32_t);
 void nmreq_free_options(struct nmreq_header *);
 const char* nmreq_option_name(uint32_t);
+#define nmreq_foreach_option(h_, o_) \
+	for ((o_) = (struct nmreq_option *)((h_)->nr_options);\
+	     (o_) != NULL;\
+	     (o_) = (struct nmreq_option *)((o_)->nro_next))
 
 /* nmctx manipulation */
 
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index ec1ff9ecb..4ee51232c 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -495,11 +495,21 @@ nmport_register(struct nmport_d *d)
 	}
 
 	if (ioctl(d->fd, NIOCCTRL, &d->hdr) < 0) {
-		nmctx_ferror(ctx, "%s: %s", d->hdr.nr_name, strerror(errno));
-		if (d->extmem != NULL && d->extmem->nro_opt.nro_status) {
-			nmctx_ferror(ctx, "failed to allocate extmem: %s",
-					strerror(d->extmem->nro_opt.nro_status));
+		struct nmreq_option *o;
+		int option_errors = 0;
+
+		nmreq_foreach_option(&d->hdr, o) {
+			if (o->nro_status) {
+				nmctx_ferror(ctx, "%s: option %s: %s",
+						d->hdr.nr_name,
+						nmreq_option_name(o->nro_reqtype),
+						strerror(o->nro_status));
+				option_errors++;
+			}
+
 		}
+		if (!option_errors)
+			nmctx_ferror(ctx, "%s: %s", d->hdr.nr_name, strerror(errno));
 		goto err;
 	}
 

From e881ebfdf928773cf85b82c367a6d59f35f5f222 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 May 2020 18:43:10 +0200
Subject: [PATCH 1785/2207] libnetmap: use generic cleanup for extmem

---
 libnetmap/libnetmap.h | 16 ++--------------
 libnetmap/nmport.c    | 39 +++++++++++++++++++++++++++------------
 2 files changed, 29 insertions(+), 26 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 41477d6f7..b6da2dbcf 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -365,9 +365,6 @@ struct nmport_d *nmport_clone(struct nmport_d *);
  * between nmport_parse() and nmport_register() (or between nmport_prepare()
  * and nmport_open_desc()).
  *
- * If @d was already using extmem the function fails. The previous extmem
- * can be removed with nmport_extmem_undo(), if necessary.
- *
  * It returns 0 on success. On failure it returns -1, sets errno to an error
  * value and sends an error message to the error() method of the context used
  * when @d was created. Moreover, *@d is left unchanged.
@@ -378,9 +375,8 @@ int nmport_extmem(struct nmport_d *d, void *base, size_t size);
  * @d		the port we want to use the extmem for
  * @fname	path of the file we want to map
  *
- * This works like nmport_extmem, but the extmem memory is obtained
- * by mmap()ping @fname. netmap_undo_extmem() and nmport_close()
- * will also automatically munmap() the file.
+ * This works like nmport_extmem, but the extmem memory is obtained by
+ * mmap()ping @fname. nmport_close() will also automatically munmap() the file.
  *
  * It returns 0 on success. On failure it returns -1, sets errno to an error
  * value and sends an error message to the error() method of the context used
@@ -399,14 +395,6 @@ int nmport_extmem_from_file(struct nmport_d *d, const char *fname);
  */
 struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
 
-/* nmport_undo_extmem - remove the extmem option, if any
- * @d		the port we want to remove the extmem from
- *
- * Removes the extmem option, if any was used in @d. It also munmap the
- * extmem region if that was obtained via nmport_extmem_from_file().
- */
-void nmport_undo_extmem(struct nmport_d *);
-
 /* enable/disable options
  *
  * These functions can be used to disable options that the application cannot
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 4ee51232c..49acf7236 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -80,10 +80,25 @@ nmport_delete(struct nmport_d *d)
 	nmctx_free(d->ctx, d);
 }
 
+void
+nmport_extmem_cleanup(struct nmport_cleanup_d *c, struct nmport_d *d)
+{
+	(void)c;
+
+	if (d->extmem == NULL)
+		return;
+
+	nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
+	nmctx_free(d->ctx, d->extmem);
+	d->extmem = NULL;
+}
+
+
 int
 nmport_extmem(struct nmport_d *d, void *base, size_t size)
 {
 	struct nmctx *ctx = d->ctx;
+	struct nmport_cleanup_d *clnup = NULL;
 
 	if (d->register_done) {
 		nmctx_ferror(ctx, "%s: cannot set extmem of an already registered port", d->hdr.nr_name);
@@ -97,9 +112,17 @@ nmport_extmem(struct nmport_d *d, void *base, size_t size)
 		return -1;
 	}
 
+	clnup = (struct nmport_cleanup_d *)nmctx_malloc(ctx, sizeof(*clnup));
+	if (clnup == NULL) {
+		nmctx_ferror(ctx, "failed to allocate cleanup descriptor");
+		errno = ENOMEM;
+		return -1;
+	}
+
 	d->extmem = nmctx_malloc(ctx, sizeof(*d->extmem));
 	if (d->extmem == NULL) {
 		nmctx_ferror(ctx, "%s: cannot allocate extmem option", d->hdr.nr_name);
+		nmctx_free(ctx, clnup);
 		errno = ENOMEM;
 		return -1;
 	}
@@ -108,6 +131,10 @@ nmport_extmem(struct nmport_d *d, void *base, size_t size)
 	d->extmem->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
 	d->extmem->nro_info.nr_memsize = size;
 	nmreq_push_option(&d->hdr, &d->extmem->nro_opt);
+
+	clnup->cleanup = nmport_extmem_cleanup;
+	nmport_push_cleanup(d, clnup);
+
 	return 0;
 }
 
@@ -189,17 +216,6 @@ nmport_extmem_getinfo(struct nmport_d *d)
 	return &d->extmem->nro_info;
 }
 
-void
-nmport_undo_extmem(struct nmport_d *d)
-{
-	if (d->extmem == NULL)
-		return;
-
-	nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
-	nmctx_free(d->ctx, d->extmem);
-	d->extmem = NULL;
-}
-
 /* head of the list of options */
 static struct nmreq_opt_parser *nmport_opt_parsers;
 
@@ -441,7 +457,6 @@ nmport_parse(struct nmport_d *d, const char *ifname)
 void
 nmport_undo_parse(struct nmport_d *d)
 {
-	nmport_undo_extmem(d);
 	nmport_do_cleanup(d);
 	memset(&d->reg, 0, sizeof(d->reg));
 	memset(&d->hdr, 0, sizeof(d->hdr));

From 83ef5aa6449731e703119906c0093f7a2a86a4b2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 12 Mar 2019 11:55:30 +0100
Subject: [PATCH 1786/2207] pass the hdr down during REGIF

---
 sys/dev/netmap/netmap.c         | 21 +++++++++++----------
 sys/dev/netmap/netmap_bdg.c     |  3 +--
 sys/dev/netmap/netmap_kern.h    |  5 ++---
 sys/dev/netmap/netmap_monitor.c |  3 +--
 4 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 982f76d45..a74e60df7 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1829,13 +1829,15 @@ netmap_ring_reinit(struct netmap_kring *kring)
  *
  */
 int
-netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
-			uint16_t nr_ringid, uint64_t nr_flags)
+netmap_interp_ringid(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 {
 	struct netmap_adapter *na = priv->np_na;
+	struct nmreq_register *reg = (struct nmreq_register *)hdr->nr_body;
 	int excluded_direction[] = { NR_TX_RINGS_ONLY, NR_RX_RINGS_ONLY };
 	enum txrx t;
 	u_int j;
+	u_int nr_flags = reg->nr_flags, nr_mode = reg->nr_mode,
+	      nr_ringid = reg->nr_ringid;
 
 	for_rx_tx(t) {
 		if (nr_flags & excluded_direction[t]) {
@@ -1929,19 +1931,19 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
  * for all rings is the same as a single ring.
  */
 static int
-netmap_set_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
-		uint16_t nr_ringid, uint64_t nr_flags)
+netmap_set_ringid(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 {
 	struct netmap_adapter *na = priv->np_na;
+	struct nmreq_register *reg = (struct nmreq_register *)hdr->nr_body;
 	int error;
 	enum txrx t;
 
-	error = netmap_interp_ringid(priv, nr_mode, nr_ringid, nr_flags);
+	error = netmap_interp_ringid(priv, hdr);
 	if (error) {
 		return error;
 	}
 
-	priv->np_txpoll = (nr_flags & NR_NO_TX_POLL) ? 0 : 1;
+	priv->np_txpoll = (reg->nr_flags & NR_NO_TX_POLL) ? 0 : 1;
 
 	/* optimization: count the users registered for more than
 	 * one ring, which are the ones sleeping on the global queue.
@@ -2286,7 +2288,7 @@ netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
  */
 int
 netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
-	uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags)
+	struct nmreq_header *hdr)
 {
 	struct netmap_if *nifp = NULL;
 	int error;
@@ -2311,7 +2313,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	}
 
 	/* compute the range of tx and rx rings to monitor */
-	error = netmap_set_ringid(priv, nr_mode, nr_ringid, nr_flags);
+	error = netmap_set_ringid(priv, hdr);
 	if (error)
 		goto err_put_lut;
 
@@ -2552,8 +2554,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 					break;
 				}
 
-				error = netmap_do_regif(priv, na, req->nr_mode,
-							req->nr_ringid, req->nr_flags);
+				error = netmap_do_regif(priv, na, hdr);
 				if (error) {    /* reg. failed, release priv and ref */
 					break;
 				}
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index ad8d98afe..b69bdb4f0 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1477,8 +1477,7 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 		if (npriv == NULL)
 			return ENOMEM;
 		npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */
-		error = netmap_do_regif(npriv, na, req->reg.nr_mode,
-					req->reg.nr_ringid, req->reg.nr_flags);
+		error = netmap_do_regif(npriv, na, hdr);
 		if (error) {
 			netmap_priv_delete(npriv);
 			return error;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 13ed80580..41b9e741b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1432,8 +1432,7 @@ int netmap_attach_common(struct netmap_adapter *);
 /* fill priv->np_[tr]xq{first,last} using the ringid and flags information
  * coming from a struct nmreq_register
  */
-int netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
-			uint16_t nr_ringid, uint64_t nr_flags);
+int netmap_interp_ringid(struct netmap_priv_d *priv, struct nmreq_header *hdr);
 /* update the ring parameters (number and size of tx and rx rings).
  * It calls the nm_config callback, if available.
  */
@@ -1468,7 +1467,7 @@ void netmap_enable_all_rings(struct ifnet *);
 
 int netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu);
 int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
-		uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags);
+		struct nmreq_header *);
 void netmap_do_unregif(struct netmap_priv_d *priv);
 
 u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index f0c1505d7..42096dd1f 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -950,8 +950,7 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	mna->priv.np_na = pna;
 
 	/* grab all the rings we need in the parent */
-	error = netmap_interp_ringid(&mna->priv, req->nr_mode, req->nr_ringid,
-					req->nr_flags);
+	error = netmap_interp_ringid(&mna->priv, hdr);
 	if (error) {
 		nm_prerr("ringid error");
 		goto free_out;

From b2e51658db874d61bc68ef326cf0c843fdf30a5f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Mar 2019 11:22:33 +0100
Subject: [PATCH 1787/2207] add convenience macro to loop over registered rings

---
 sys/dev/netmap/netmap.c | 58 +++++++++++++++++++++--------------------
 1 file changed, 30 insertions(+), 28 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a74e60df7..44f7c47c0 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1973,6 +1973,19 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
 	priv->np_kloop_state = 0;
 }
 
+#define within_sel(p_, t_, i_)					  	  \
+	((i_) < (p_)->np_qlast[(t_)])
+#define nonempty_sel(p_, t_)						  \
+	(within_sel((p_), (t_), (p_)->np_qfirst[(t_)]))
+#define foreach_selected_ring(p_, t_, i_, kring_)			  \
+	for ((t_) = nonempty_sel((p_), NR_RX) ? NR_RX : NR_TX,		  \
+	     (i_) = (p_)->np_qfirst[(t_)];				  \
+	     (t_ == NR_RX ||						  \
+	      (t == NR_TX && within_sel((p_), (t_), (i_)))) &&     	  \
+	      ((kring_) = NMR((p_)->np_na, (t_))[(i_)]); 		  \
+	     (i_) = within_sel((p_), (t_), (i_) + 1) ? (i_) + 1 :         \
+		(++(t_) < NR_TXRX ? (p_)->np_qfirst[(t_)] : (i_)))
+
 
 /* Set the nr_pending_mode for the requested rings.
  * If requested, also try to get exclusive access to the rings, provided
@@ -1999,29 +2012,23 @@ netmap_krings_get(struct netmap_priv_d *priv)
 	 * are neither alread exclusively owned, nor we
 	 * want exclusive ownership when they are already in use
 	 */
-	for_rx_tx(t) {
-		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = NMR(na, t)[i];
-			if ((kring->nr_kflags & NKR_EXCLUSIVE) ||
-			    (kring->users && excl))
-			{
-				nm_prdis("ring %s busy", kring->name);
-				return EBUSY;
-			}
+	foreach_selected_ring(priv, t, i, kring) {
+		if ((kring->nr_kflags & NKR_EXCLUSIVE) ||
+		    (kring->users && excl))
+		{
+			nm_prdis("ring %s busy", kring->name);
+			return EBUSY;
 		}
 	}
 
 	/* second round: increment usage count (possibly marking them
 	 * as exclusive) and set the nr_pending_mode
 	 */
-	for_rx_tx(t) {
-		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = NMR(na, t)[i];
-			kring->users++;
-			if (excl)
-				kring->nr_kflags |= NKR_EXCLUSIVE;
-	                kring->nr_pending_mode = NKR_NETMAP_ON;
-		}
+	foreach_selected_ring(priv, t, i, kring) {
+		kring->users++;
+		if (excl)
+			kring->nr_kflags |= NKR_EXCLUSIVE;
+		kring->nr_pending_mode = NKR_NETMAP_ON;
 	}
 
 	return 0;
@@ -2034,7 +2041,6 @@ netmap_krings_get(struct netmap_priv_d *priv)
 static void
 netmap_krings_put(struct netmap_priv_d *priv)
 {
-	struct netmap_adapter *na = priv->np_na;
 	u_int i;
 	struct netmap_kring *kring;
 	int excl = (priv->np_flags & NR_EXCLUSIVE);
@@ -2047,15 +2053,12 @@ netmap_krings_put(struct netmap_priv_d *priv)
 			priv->np_qfirst[NR_RX],
 			priv->np_qlast[MR_RX]);
 
-	for_rx_tx(t) {
-		for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
-			kring = NMR(na, t)[i];
-			if (excl)
-				kring->nr_kflags &= ~NKR_EXCLUSIVE;
-			kring->users--;
-			if (kring->users == 0)
-				kring->nr_pending_mode = NKR_NETMAP_OFF;
-		}
+	foreach_selected_ring(priv, t, i, kring) {
+		if (excl)
+			kring->nr_kflags &= ~NKR_EXCLUSIVE;
+		kring->users--;
+		if (kring->users == 0)
+			kring->nr_pending_mode = NKR_NETMAP_OFF;
 	}
 }
 
@@ -2215,7 +2218,6 @@ netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
 	return 0;
 }
 
-
 /*
  * possibly move the interface to netmap-mode.
  * If success it returns a pointer to netmap_if, otherwise NULL.

From a2b1b4ea221a63626ff4b1bfa07c6c356da28434 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 12 Mar 2019 18:14:31 +0100
Subject: [PATCH 1788/2207] add per-slot offset support

This patch introduces a new register option: NETMAP_REQ_OPT_OFFSET.
With this option a configurable part of the ptr field in the netmap_slot
can be used to specify an offset into the buffer.
The offset field can be read and updated using the bitmask found
in ring->offset_mask after a successful register.

For RX rings, the user writes the offset o in an empty slot before
passing it to netmap; then, netmap will write the incoming packet at an
offset o' >= o in the buffer. o' may be larger than o because of, e.g.,
alignment constrains.  If o' > o netmap will also update the
corresponding field in the slot. Note that large offsets may cause
the port to split the packet over several slots, setting the NS_MOREFRAG
flag accordingly.

For TX rings, the user may prepare the packet to send at an offset o
into the buffer and write o in the offset field. Netmap will send the
packets starting o bytes in the buffer. Note that the address of the
packet must comply with any alignment constraints that the port may
have, or the result will be undefined. The user may read the alignment
constraint in the new ring->buf_align field.  It is also possibile that
empty slots already come with a non-zero offset o specified in the
offset field. In this case, the user will have to write the packet at an
offset o' >= o.

During open, the user must also declare the maximum offset that she
is going to use. Any offset larger than this will be truncated.
---
 LINUX/if_e1000_netmap.h      | 107 ++++++++++++++++---
 libnetmap/libnetmap.h        |  26 +++++
 libnetmap/nmport.c           |  40 +++++++
 sys/dev/netmap/netmap.c      | 198 +++++++++++++++++++++++++++++++++++
 sys/dev/netmap/netmap_kern.h |  77 +++++++++++++-
 sys/net/netmap.h             |  31 +++++-
 sys/net/netmap_user.h        |  10 ++
 7 files changed, 471 insertions(+), 18 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index fc5afcaba..24ff1bff5 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -121,13 +121,14 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			uint64_t paddr;
-			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			/* device-specific */
 			struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
 			int hw_flags = E1000_TXD_CMD_IFCS;
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
 				hw_flags |= adapter->txd_cmd;
@@ -135,13 +136,11 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 				 * We may set it only if NS_REPORT is set or
 				 * at least once every half ring. */
 			}
-			if (slot->flags & NS_BUF_CHANGED) {
-				curr->buffer_addr = htole64(paddr);
-			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
+			curr->buffer_addr = htole64(paddr + offset);
 			curr->upper.data = 0;
 			curr->lower.data = htole32(len | hw_flags);
 			nm_i = nm_next(nm_i, lim);
@@ -175,7 +174,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
 			struct netmap_slot *slot = &ring->slot[tosync];
 			uint64_t paddr;
-			(void)PNMB(na, slot, &paddr);
+			(void)PNMB_O(kring, slot, &paddr);
 
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_TX);
@@ -236,7 +235,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			dma_rmb(); /* read descriptor after status DD */
 
 			slot = ring->slot + nm_i;
-			PNMB(na, slot, &paddr);
+			PNMB_O(kring, slot, &paddr);
 			slot->len = le16toh(curr->length);
 			slot->flags = NS_MOREFRAG;
 			if (staterr & E1000_RXD_STAT_EOP) {
@@ -270,7 +269,8 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
 				goto ring_reset;
 			if (slot->flags & NS_BUF_CHANGED) {
-				curr->buffer_addr = htole64(paddr);
+				uint64_t offset = nm_get_offset(kring, slot);
+				curr->buffer_addr = htole64(paddr + offset);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
 			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
@@ -297,6 +297,72 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 	return netmap_ring_reinit(kring);
 }
 
+struct e1000_netmap_szdesc {
+	uint32_t bufsize;
+	uint32_t rctl;
+};
+
+#define E1000_NETMAP_RCTL_MASK	0x7A030000
+static struct e1000_netmap_szdesc e1000_netmap_bufsize[] = {
+	{ 16384,	0x02010000},
+	{ 8192,		0x02020000},
+	{ 4096,		0x02030000},
+	{ 2048,		0x00000000},
+	{ 1024,		0x00010000},
+	{ 512,		0x00020000},
+	{ 256,		0x00030000},
+	{ 0,		0},
+};
+
+static uint32_t
+e1000_netmap_get_rctl(uint32_t bufsize)
+{
+	struct e1000_netmap_szdesc *sz;
+
+	for (sz = e1000_netmap_bufsize; sz->bufsize; sz++)
+		if (bufsize == sz->bufsize)
+			return sz->rctl;
+
+	return ((bufsize >> 10) & 0xF) << 27;
+}
+
+static int
+e1000_netmap_bufcfg(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	uint64_t target, bufsz, maxframe;
+	struct e1000_netmap_szdesc *sz;
+
+	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+	maxframe = na->ifp->mtu + ETH_HLEN + ETH_FCS_LEN;
+	if (maxframe < target) {
+		/* we can ignore the offset */
+		target = NETMAP_BUF_SIZE(na);
+	}
+
+	bufsz = 0;
+	for (sz = e1000_netmap_bufsize; sz->bufsize; sz++)
+		if (sz->bufsize <= target) {
+			bufsz = sz->bufsize;
+			break;
+		}
+	if (bufsz) {
+		target >>= 10;
+		if (target < 1 || target > 15)
+			return EINVAL;
+
+		bufsz = target << 10;
+	}
+	kring->hwbuf_len = bufsz;
+	kring->buf_align = 0; /* no alignment */
+	nm_prinf("%s: hwbuf_len %llu", kring->name, kring->hwbuf_len);
+	return 0;
+}
 
 /*
  * Make the tx and rx rings point to the netmap buffers.
@@ -306,16 +372,19 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 	struct e1000_hw *hw = &adapter->hw;
 	struct ifnet *ifp = adapter->netdev;
 	struct netmap_adapter* na = NA(ifp);
+	struct netmap_kring *kring;
 	struct netmap_slot* slot;
 	struct e1000_tx_ring* txr = &adapter->tx_ring[0];
 	unsigned int i, r, si;
 	uint64_t paddr;
+	uint32_t rctl;
 
 	if (!nm_native_on(na))
 		return 0;
 
 	for (r = 0; r < na->num_rx_rings; r++) {
 		struct e1000_rx_ring *rxr;
+		kring = na->rx_rings[r];
 		slot = netmap_reset(na, NR_RX, r, 0);
 		if (!slot) {
 			nm_prinf("Skipping RX ring %d, netmap mode not requested", r);
@@ -324,8 +393,8 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		rxr = &adapter->rx_ring[r];
 
 		for (i = 0; i < rxr->count; i++) {
-			si = netmap_idx_n2k(na->rx_rings[r], i);
-			PNMB(na, slot + si, &paddr);
+			si = netmap_idx_n2k(kring, i);
+			PNMB_O(kring, slot + si, &paddr);
 			E1000_RX_DESC(*rxr, i)->buffer_addr = htole64(paddr);
 		}
 
@@ -334,6 +403,13 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[0]);
 		if (i < 0) // XXX something wrong here, can it really happen ?
 			i += rxr->count;
+
+		/* program the RCTL */
+		rctl = er32(RCTL);
+		rctl = (rctl & ~E1000_NETMAP_RCTL_MASK) |
+			e1000_netmap_get_rctl(kring->hwbuf_len);
+		ew32(RCTL, rctl);
+
 		wmb(); /* Force memory writes to complete */
 		writel(i, hw->hw_addr + rxr->rdt);
 	}
@@ -347,8 +423,9 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		}
 
 		for (i = 0; i < na->num_tx_desc; i++) {
-			si = netmap_idx_n2k(na->tx_rings[r], i);
-			PNMB(na, slot + si, &paddr);
+			kring = na->tx_rings[r];
+			si = netmap_idx_n2k(kring, i);
+			PNMB_O(kring, slot + si, &paddr);
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
 		}
 	}
@@ -359,14 +436,13 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 static int
 e1000_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
-	struct SOFTC_T *adapter = netdev_priv(na->ifp);
 	int ret = netmap_rings_config_get(na, info);
 
 	if (ret) {
 		return ret;
 	}
 
-	info->rx_buf_maxsize = adapter->rx_buffer_len;
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
 
 	return 0;
 }
@@ -380,7 +456,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
-	na.na_flags = NAF_MOREFRAG;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
 	na.num_tx_desc = adapter->tx_ring[0].count;
 	na.num_rx_desc = adapter->rx_ring[0].count;
 	na.num_tx_rings = na.num_rx_rings = 1;
@@ -390,6 +466,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 	na.nm_rxsync = e1000_netmap_rxsync;
 	na.nm_intr = e1000_netmap_intr;
 	na.nm_config = e1000_netmap_config;
+	na.nm_bufcfg = e1000_netmap_bufcfg;
 
 	netmap_attach(&na);
 }
diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index b6da2dbcf..be22a2cd9 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -149,6 +149,23 @@ struct nmem_d;
  *			file must be assigned. The other keys default to zero,
  *			causing netmap to take the corresponding values from
  *			the priv_{if,ring,buf}_{num,size} sysctls.
+ *
+ *  offset (multi-key)
+ *			reserve (part of) the ptr fields as an offset field
+ *			and write an initial offset into them.
+ *
+ *			The keys are:
+ *
+ *		        bits		number of bits of ptr to use
+ *		       *initial		initial offset value
+ *
+ *		        initial must be assigned. If bits is omitted, it
+ *		        defaults to the entire ptr field. The max offset is set
+ *		        at the same value as the initial offset. Note that the
+ *		        actual values may be increased by the kernel.
+ *
+ *		        This option is disabled by default (see
+ *			nmport_enable_option() below)
  */
 
 
@@ -395,6 +412,15 @@ int nmport_extmem_from_file(struct nmport_d *d, const char *fname);
  */
 struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
 
+
+/* nmport_offset - use offsets for this port
+ * @initial	the initial offset for all the slots
+ * @maxoff	the maximum offset
+ * @bits	the number of bits of slot->ptr to use for the offsets
+ */
+int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff,
+		uint64_t bits);
+
 /* enable/disable options
  *
  * These functions can be used to disable options that the application cannot
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 49acf7236..2f10413fb 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -216,6 +216,27 @@ nmport_extmem_getinfo(struct nmport_d *d)
 	return &d->extmem->nro_info;
 }
 
+int
+nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff, uint64_t bits)
+{
+	struct nmctx *ctx = d->ctx;
+	struct nmreq_opt_offsets *opt;
+
+	opt = nmctx_malloc(ctx, sizeof(*opt));
+	if (opt == NULL) {
+		nmctx_ferror(ctx, "%s: cannot allocate offset option", d->hdr.nr_name);
+		errno = ENOMEM;
+		return -1;
+	}
+	memset(opt, 0, sizeof(*opt));
+	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
+	opt->nro_offset_bits = bits;
+	opt->nro_initial_offset = initial;
+	opt->nro_max_offset = maxoff;
+	nmreq_push_option(&d->hdr, &opt->nro_opt);
+	return 0;
+}
+
 /* head of the list of options */
 static struct nmreq_opt_parser *nmport_opt_parsers;
 
@@ -295,6 +316,9 @@ NPOPT_DECL(conf, 0)
 	NPKEY_DECL(conf, host_rx_rings, 0)
 	NPKEY_DECL(conf, tx_slots, 0)
 	NPKEY_DECL(conf, rx_slots, 0)
+NPOPT_DECL(offset, NMREQ_OPTF_DISABLED)
+	NPKEY_DECL(offset, initial, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
+	NPKEY_DECL(offset, bits, 0)
 
 
 static int
@@ -400,6 +424,22 @@ NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p)
 	return 0;
 }
 
+static int
+NPOPT_PARSER(offset)(struct nmreq_parse_ctx *p)
+{
+	struct nmport_d *d;
+	uint64_t initial, bits;
+
+	d = p->token;
+
+	initial = atoi(nmport_key(p, offset, initial));
+	bits = 0;
+	if (nmport_key(p, offset, bits) != NULL)
+		bits = atoi(nmport_key(p, offset, bits));
+
+	return nmport_offset(d, initial, initial, bits);
+}
+
 
 void
 nmport_disable_option(const char *opt)
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 44f7c47c0..558939899 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -798,6 +798,18 @@ netmap_update_config(struct netmap_adapter *na)
 static int netmap_txsync_to_host(struct netmap_kring *kring, int flags);
 static int netmap_rxsync_from_host(struct netmap_kring *kring, int flags);
 
+static int
+netmap_default_bufcfg(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+
+	(void)flags;
+
+	kring->hwbuf_len = NETMAP_BUF_SIZE(na) - kring->offset_max;
+	kring->buf_align = 0; /* no alignment */
+	return 0;
+}
+
 /* create the krings array and initialize the fields common to all adapters.
  * The array layout is this:
  *
@@ -878,12 +890,16 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 			kring->nr_pending_mode = NKR_NETMAP_OFF;
 			if (i < nma_get_nrings(na, t)) {
 				kring->nm_sync = (t == NR_TX ? na->nm_txsync : na->nm_rxsync);
+				kring->nm_bufcfg = na->nm_bufcfg;
+				if (kring->nm_bufcfg == NULL)
+					kring->nm_bufcfg = netmap_default_bufcfg;
 			} else {
 				if (!(na->na_flags & NAF_HOST_RINGS))
 					kring->nr_kflags |= NKR_FAKERING;
 				kring->nm_sync = (t == NR_TX ?
 						netmap_txsync_to_host:
 						netmap_rxsync_from_host);
+				kring->nm_bufcfg = netmap_default_bufcfg;
 			}
 			kring->nm_notify = na->nm_notify;
 			kring->rhead = kring->rcur = kring->nr_hwcur = 0;
@@ -2218,6 +2234,176 @@ netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
 	return 0;
 }
 
+/* Handle the offset option, if present in the hdr.
+ * Returns 0 on success, or an error.
+ */
+static int
+netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
+{
+	struct nmreq_opt_offsets *opt;
+	struct netmap_adapter *na = priv->np_na;
+	struct netmap_kring *kring;
+	uint64_t mask = 0, bits = 0, maxbits = sizeof(uint64_t) * 8,
+		 max_offset = 0, initial_offset = 0;
+	u_int i;
+	enum txrx t;
+	int error = 0;
+
+	opt = (struct nmreq_opt_offsets *)
+		nmreq_getoption(hdr, NETMAP_REQ_OPT_OFFSETS);
+	if (opt == NULL)
+		return 0;
+
+	if (!(na->na_flags & NAF_OFFSETS)) {
+		if (netmap_verbose)
+			nm_prerr("%s does not support offsets",
+				na->name);
+		error = EOPNOTSUPP;
+		goto out;
+	}
+
+	/* check sanity of the opt values */
+	max_offset = opt->nro_max_offset;
+	initial_offset = opt->nro_initial_offset;
+	bits = opt->nro_offset_bits;
+
+	if (bits > maxbits) {
+		if (netmap_verbose)
+			nm_prerr("bits: %llu too large (max %llu)",
+				bits, maxbits);
+		error = EINVAL;
+		goto out;
+	}
+	/* we take bits == 0 as a request to use the entire field */
+	if (bits == 0 || bits == maxbits) {
+		/* shifting a type by sizeof(type) is undefined */
+		bits = maxbits;
+		mask = 0xffffffffffffffff;
+	} else {
+		mask = (1ULL << bits) - 1;
+	}
+	if (max_offset > NETMAP_BUF_SIZE(na)) {
+		if (netmap_verbose)
+			nm_prerr("max offset %llu > buf size %u",
+				max_offset, NETMAP_BUF_SIZE(na));
+		error = EINVAL;
+		goto out;
+	}
+	if ((max_offset & mask) != max_offset) {
+		if (netmap_verbose)
+			nm_prerr("max offset %llu to large for %llu bits",
+				max_offset, bits);
+		error = EINVAL;
+		goto out;
+	}
+	if (initial_offset > max_offset) {
+		if (netmap_verbose)
+			nm_prerr("initial offset %llu > max offset %llu",
+				initial_offset, max_offset);
+		error = EINVAL;
+		goto out;
+	}
+
+	/* initialize the kring and ring fields. */
+	foreach_selected_ring(priv, t, i, kring) {
+		struct netmap_kring *kring = NMR(na, t)[i];
+		struct netmap_ring *ring = kring->ring;
+		u_int j;
+
+		/* it the ring is already in use we check that the
+		 * new request is compatible with the existing one
+		 */
+		if (kring->offset_mask) {
+			if ((kring->offset_mask & mask) != mask ||
+			     kring->offset_max < max_offset) {
+				if (netmap_verbose)
+					nm_prinf("%s: cannot decrease"
+						 "offset mask and/or max"
+						 "(current: mask=%llx,max=%llu",
+							kring->name,
+							kring->offset_mask,
+							kring->offset_max);
+				error = EBUSY;
+				goto out;
+			}
+			mask = kring->offset_mask;
+			max_offset = kring->offset_max;
+		} else {
+			kring->offset_mask = mask;
+			*(uint64_t *)&ring->offset_mask = mask;
+			kring->offset_max = max_offset;
+		}
+
+		/* if there is an initial offset, put it into
+		 * all the slots
+		 *
+		 * Note: we cannot change the offsets if the
+		 * ring is already in use.
+		 */
+		if (!initial_offset || kring->users > 1)
+			continue;
+
+		for (j = 0; j < kring->nkr_num_slots; j++) {
+			struct netmap_slot *slot = ring->slot + j;
+
+			nm_write_offset(kring, slot, initial_offset);
+		}
+	}
+
+out:
+	opt->nro_opt.nro_status = error;
+	if (!error) {
+		opt->nro_max_offset = max_offset;
+	}
+	return error;
+
+}
+
+static int
+netmap_compute_buf_len(struct netmap_priv_d *priv)
+{
+	enum txrx t;
+	u_int i;
+	struct netmap_kring *kring;
+	int error = 0;
+	unsigned mtu = 0;
+	struct netmap_adapter *na = priv->np_na;
+
+	if (na->ifp != NULL)
+		mtu = nm_os_ifnet_mtu(na->ifp);
+
+	foreach_selected_ring(priv, t, i, kring) {
+
+		if (kring->users > 1)
+			continue;
+
+		error = kring->nm_bufcfg(kring, 0);
+		if (error)
+			goto out;
+
+		*(uint64_t *)&kring->ring->buf_align = kring->buf_align;
+
+		if (mtu && t == NR_RX && kring->hwbuf_len < mtu) {
+			if (!(na->na_flags & NAF_MOREFRAG)) {
+				nm_prerr("error: large MTU (%d) needed "
+					 "but %s does not support "
+					 "NS_MOREFRAG", mtu,
+					 na->name);
+				error = EINVAL;
+				goto out;
+			} else {
+				nm_prinf("info: netmap application on "
+					 "%s needs to support "
+					 "NS_MOREFRAG "
+					 "(MTU=%u,buf_size=%llu)",
+					 kring->name, mtu, kring->hwbuf_len);
+			}
+		}
+	}
+out:
+	return error;
+}
+
 /*
  * possibly move the interface to netmap-mode.
  * If success it returns a pointer to netmap_if, otherwise NULL.
@@ -2366,6 +2552,16 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	if (error)
 		goto err_rel_excl;
 
+	/* initialize offsets if requested */
+	error = netmap_offsets_init(priv, hdr);
+	if (error)
+		goto err_rel_excl;
+
+	/* compute and validate the buf lenghts */
+	error = netmap_compute_buf_len(priv);
+	if (error)
+		goto err_rel_excl;
+
 	/* in all cases, create a new netmap if */
 	nifp = netmap_mem_if_new(na, priv);
 	if (nifp == NULL) {
@@ -3010,6 +3206,8 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 	case NETMAP_REQ_OPT_SYNC_KLOOP_MODE:
 		rv = sizeof(struct nmreq_opt_sync_kloop_mode);
 		break;
+	case NETMAP_REQ_OPT_OFFSETS:
+		rv = sizeof(struct nmreq_opt_offsets);
 	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 41b9e741b..6da330276 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -536,6 +536,30 @@ struct netmap_kring {
 	uint32_t pipe_tail;		/* hwtail updated by the other end */
 #endif /* WITH_PIPES */
 
+	/* mask for the offset-related part of the ptr field in the slots */
+	uint64_t offset_mask;
+	/* maximum user-specified offset, as stipulated at bind time.
+	 * Larger offset requests will be silently capped to offset_max.
+	 */
+	uint64_t offset_max;
+
+	/* size of hardware buffer. This may be less than the size of
+	 * the netmap buffers because of non-zero offsets, or because
+	 * the netmap buffer size exceeds the capability of the hardware.
+	 */
+	uint64_t hwbuf_len;
+
+	/* required aligment (in bytes) for the buffers used by this ring.
+	 * Netmap buffers are aligned to cachelines, which should suffice
+	 * for most NICs. If the user is passing offsets, though, we need
+	 * to check that the resulting buf address complies with any
+	 * alignment restriction.
+	 */
+	uint64_t buf_align;
+
+	/* harware specific logic for the selection of the hwbuf_len */
+	int (*nm_bufcfg)(struct netmap_kring *kring, int flags);
+
 	int (*save_notify)(struct netmap_kring *kring, int flags);
 
 #ifdef WITH_MONITOR
@@ -596,7 +620,6 @@ nm_prev(uint32_t i, uint32_t lim)
 	return unlikely (i == 0) ? lim : i - 1;
 }
 
-
 /*
  *
  * Here is the layout for the Rx and Tx rings.
@@ -720,6 +743,7 @@ struct netmap_adapter {
 #define NAF_FORCE_NATIVE 128	/* the adapter is always NATIVE */
 /* free */
 #define NAF_MOREFRAG	512	/* the adapter supports NS_MOREFRAG */
+#define NAF_OFFSETS	1024	/* the adapter supports the slot offsets */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
 				  * cannot be registered from userspace
@@ -783,6 +807,22 @@ struct netmap_adapter {
 	 * nm_config() returns configuration information from the OS
 	 *	Called with NMG_LOCK held.
 	 *
+	 * nm_bufcfg()
+	 *      the purpose of this callback is to fill the kring->hwbuf_len
+	 *      (l) and kring->buf_align fields. The l value is most important
+	 *      for RX rings, where we want to disallow writes outside of the
+	 *      netmap buffer. The l value must be computed taking into account
+	 *      the stipulated max_offset (o), possibily increased if there are
+	 *      alignemnt constrains, the maxframe (m), if known, and the
+	 *      current NETMAP_BUF_SIZE (b) of the memory region used by the
+	 *      adapter. We want the largest supported l such that o + l <= b.
+	 *      If m is known to be <= b - o, the callback may also choose the
+	 *      largest l <= b, ignoring the offset.  The buf_align field is
+	 *      most important for TX rings when there are offsets.  The user
+	 *      will see this value in the ring->buf_align field.  Misaligned
+	 *      offsets will cause the corresponding packets to be silently
+	 *      dropped.
+	 *
 	 * nm_krings_create() create and init the tx_rings and
 	 * 	rx_rings arrays of kring structures. In particular,
 	 * 	set the nm_sync callbacks for each ring.
@@ -812,6 +852,7 @@ struct netmap_adapter {
 	int (*nm_txsync)(struct netmap_kring *kring, int flags);
 	int (*nm_rxsync)(struct netmap_kring *kring, int flags);
 	int (*nm_notify)(struct netmap_kring *kring, int flags);
+	int (*nm_bufcfg)(struct netmap_kring *kring, int flags);
 #define NAF_FORCE_READ      1
 #define NAF_FORCE_RECLAIM   2
 #define NAF_CAN_FORWARD_DOWN 4
@@ -1414,6 +1455,12 @@ uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *);
 	} while (0)
 #endif
 
+#define NM_CHECK_ADDR_LEN_OFF(na_, l_, o_) do {				\
+	if ((l_) + (o_) < (l_) || 					\
+	    (l_) + (o_) > NETMAP_BUF_SIZE(na_)) {			\
+		(l_) = NETMAP_BUF_SIZE(na_) - (o_);			\
+	} } while (0)
+
 
 /*---------------------------------------------------------------*/
 /*
@@ -1904,6 +1951,34 @@ PNMB(struct netmap_adapter *na, struct netmap_slot *slot, uint64_t *pp)
 	return ret;
 }
 
+static inline void
+nm_write_offset(struct netmap_kring *kring,
+		struct netmap_slot *slot, uint64_t offset)
+{
+	slot->ptr = (slot->ptr & ~kring->offset_mask) |
+		(offset & kring->offset_mask);
+}
+
+static inline uint64_t
+nm_get_offset(struct netmap_kring *kring, struct netmap_slot *slot)
+{
+	uint64_t offset = (slot->ptr & kring->offset_mask);
+	if (unlikely(offset > kring->offset_max))
+		offset = kring->offset_max;
+	return offset;
+}
+
+
+static inline void *
+PNMB_O(struct netmap_kring *kring, struct netmap_slot *slot, uint64_t *pp)
+{
+	void *addr = PNMB(kring->na, slot, pp);
+	uint64_t offset = nm_get_offset(kring, slot);
+	addr = (char *)addr + offset;
+	*pp += offset;
+	return addr;
+}
+
 
 /*
  * Structure associated to each netmap file descriptor.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 6e302cff8..804cc328f 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -297,11 +297,24 @@ struct netmap_ring {
 
 	struct timeval	ts;		/* (k) time of last *sync() */
 
+	/* offset_mask is used to isolate the part of the ptr field
+	 * in the slots used to contain an offset in the buffer.
+	 * It is zero if the ring has not be opened using the
+	 * NETMAP_REQ_OPT_OFFSETS option.
+	 */
+	const uint64_t	offset_mask;
+	/* the alignment requirement, in bytes, for the start
+	 * of the packets inside the buffers.
+	 * User programs should take this alignment into
+	 * account when specifing buffer-offsets in TX slots.
+	 */
+	const uint64_t	buf_align;
+
 	/* opaque room for a mutex or similar object */
 #if !defined(_WIN32) || defined(__CYGWIN__)
-	uint8_t	__attribute__((__aligned__(NM_CACHE_ALIGN))) sem[128];
+	uint8_t	__attribute__((__aligned__(NM_CACHE_ALIGN))) sem[112];
 #else
-	uint8_t	__declspec(align(NM_CACHE_ALIGN)) sem[128];
+	uint8_t	__declspec(align(NM_CACHE_ALIGN)) sem[112];
 #endif
 
 	/* the slots follow. This struct has variable size */
@@ -563,6 +576,12 @@ enum {
 	 */
 	NETMAP_REQ_OPT_SYNC_KLOOP_MODE,
 
+	/* On NETMAP_REQ_REGISTER, ask for (part of) the ptr field in the
+	 * slots of the registered rings to be used as an offset field
+	 * for the start of the packets inside the netmap buffer.
+	 */
+	NETMAP_REQ_OPT_OFFSETS,
+
 	/* This is a marker to count the number of available options.
 	 * New options must be added above it. */
 	NETMAP_REQ_OPT_MAX,
@@ -935,4 +954,12 @@ struct nmreq_opt_csb {
 	uint64_t		csb_ktoa;
 };
 
+struct nmreq_opt_offsets {
+	struct nmreq_option	nro_opt;
+	uint64_t		nro_max_offset;
+	uint64_t		nro_initial_offset;
+	uint32_t		nro_offset_bits;
+	uint32_t		nro_tx_align;
+};
+
 #endif /* _NET_NETMAP_H_ */
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index bf50afcbc..eb9415501 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -123,6 +123,16 @@
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
 		(ring)->nr_buf_size )
 
+#define NETMAP_ROFFSET(ring, slot)			\
+	((slot)->ptr & (ring)->offset_mask)
+
+#define NETMAP_WOFFSET(ring, slot, offset)		\
+	do { (slot)->ptr = ((slot)->ptr & ~(ring)->offset_mask) | \
+		((offset) & (ring)->offset_mask) } while (0)
+
+#define NETMAP_BUF_OFFSET(ring, slot)			\
+	(NETMAP_BUF(ring, (slot)->buf_idx) + NETMAP_ROFFSET(ring, slot))
+
 
 static inline uint32_t
 nm_ring_next(struct netmap_ring *r, uint32_t i)

From 15a355a914cecefe4f674bac5deece737c48a820 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 16:50:35 +0100
Subject: [PATCH 1789/2207] pipe: avoid large buffer on stack

---
 sys/dev/netmap/netmap_pipe.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index c15a08319..4787d293a 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -660,7 +660,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	const char *pipe_id = NULL;
 	int role = 0;
 	int error, retries = 0;
-	char *cbra;
+	char *cbra, pipe_char;
 
 	/* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */
 	cbra = strrchr(hdr->nr_name, '{');
@@ -675,6 +675,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			return 0;
 		}
 	}
+	pipe_char = *cbra;
 	pipe_id = cbra + 1;
 	if (*pipe_id == '\0' || cbra == hdr->nr_name) {
 		/* Bracket is the last character, so pipe name is missing;
@@ -690,15 +691,13 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 
 	/* first, try to find the parent adapter */
 	for (;;) {
-		char nr_name_orig[NETMAP_REQ_IFNAMSIZ];
 		int create_error;
 
 		/* Temporarily remove the pipe suffix. */
-		strlcpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
 		*cbra = '\0';
 		error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
 		/* Restore the pipe suffix. */
-		strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
+		*cbra = pipe_char;
 		if (!error)
 			break;
 		if (error != ENXIO || retries++) {
@@ -711,7 +710,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 		NMG_UNLOCK();
 		create_error = netmap_vi_create(hdr, 1 /* autodelete */);
 		NMG_LOCK();
-		strlcpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
+		*cbra = pipe_char;
 		if (create_error && create_error != EEXIST) {
 			if (create_error != EOPNOTSUPP) {
 				nm_prerr("failed to create a persistent vale port: %d",

From 640c708ebc1b01f8f0ab0f9cbff3797eaf7e6af4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 17:09:05 +0100
Subject: [PATCH 1790/2207] pipe: simplify ring initialization

The previous code was prepared to handle fake rings in either
the registering pipe-end or in the other end, but the latter
case was actually the only possible one.
This patch sanctions this, since this arrangement is needed
for proper initial-offset propagation.
---
 sys/dev/netmap/netmap_pipe.c | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 4787d293a..b183bd426 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -414,7 +414,6 @@ netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona)
 		for (i = 0; i < nma_get_nrings(na, t); i++) {
 			struct netmap_kring *kring = NMR(na, t)[i];
 			if (nm_kring_pending_on(kring)) {
-				struct netmap_kring *sring, *dring;
 
 				kring->nr_mode = NKR_NETMAP_ON;
 				if ((kring->nr_kflags & NKR_FAKERING) &&
@@ -427,26 +426,17 @@ netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona)
 				}
 
 				/* copy the buffers from the non-fake ring */
-				if (kring->nr_kflags & NKR_FAKERING) {
-					sring = kring->pipe;
-					dring = kring;
-				} else {
-					sring = kring;
-					dring = kring->pipe;
-				}
-				memcpy(dring->ring->slot,
-				       sring->ring->slot,
+				memcpy(kring->pipe->ring->slot,
+				       kring->ring->slot,
 				       sizeof(struct netmap_slot) *
-						sring->nkr_num_slots);
+						kring->nkr_num_slots);
 				/* mark both rings as fake and needed,
 				 * so that buffers will not be
 				 * deleted by the standard machinery
 				 * (we will delete them by ourselves in
 				 * netmap_pipe_krings_delete)
 				 */
-				sring->nr_kflags |=
-					(NKR_FAKERING | NKR_NEEDRING);
-				dring->nr_kflags |=
+				kring->nr_kflags |=
 					(NKR_FAKERING | NKR_NEEDRING);
 				kring->nr_mode = NKR_NETMAP_ON;
 			}

From ede8cb33964ec84c632301e56ac784e9fe4a5899 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2019 17:32:55 +0100
Subject: [PATCH 1791/2207] pipe: add support for offsets

---
 sys/dev/netmap/netmap_pipe.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index b183bd426..37149d818 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -211,8 +211,12 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
 			m--, k = nm_next(k, lim), nk = (complete ? k : nk)) {
 		struct netmap_slot *rs = &rxring->slot[k];
 		struct netmap_slot *ts = &txring->slot[k];
+		uint64_t off = nm_get_offset(rxkring, rs);
 
 		*rs = *ts;
+		if (nm_get_offset(rxkring, rs) < off) {
+			nm_write_offset(rxkring, rs, off);
+		}
 		if (ts->flags & NS_BUF_CHANGED) {
 			ts->flags &= ~NS_BUF_CHANGED;
 		}
@@ -263,9 +267,9 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
 		struct netmap_slot *rs = &rxring->slot[k];
 		struct netmap_slot *ts = &txring->slot[k];
 
+		/* copy the slot. This also propagates any offset */
+		*ts = *rs;
 		if (rs->flags & NS_BUF_CHANGED) {
-			/* copy the slot and report the buffer change */
-			*ts = *rs;
 			rs->flags &= ~NS_BUF_CHANGED;
 		}
 	}
@@ -425,11 +429,18 @@ netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona)
 					continue;
 				}
 
-				/* copy the buffers from the non-fake ring */
+				/* copy the buffers from the non-fake ring
+				 * (this also propagates any initial offset)
+				 */
 				memcpy(kring->pipe->ring->slot,
 				       kring->ring->slot,
 				       sizeof(struct netmap_slot) *
 						kring->nkr_num_slots);
+				/* copy the offset-related fields */
+				*(uint64_t *)&kring->pipe->ring->offset_mask =
+					kring->ring->offset_mask;
+				*(uint64_t *)&kring->pipe->ring->buf_align =
+					kring->ring->buf_align;
 				/* mark both rings as fake and needed,
 				 * so that buffers will not be
 				 * deleted by the standard machinery
@@ -760,7 +771,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	mna->up.nm_krings_create = netmap_pipe_krings_create;
 	mna->up.nm_krings_delete = netmap_pipe_krings_delete;
 	mna->up.nm_mem = netmap_mem_get(pna->nm_mem);
-	mna->up.na_flags |= NAF_MEM_OWNER;
+	mna->up.na_flags |= NAF_MEM_OWNER | NAF_OFFSETS;
 	mna->up.na_lut = pna->na_lut;
 
 	mna->up.num_tx_rings = req->nr_tx_rings;

From 54b26740c377630da2321a4cab38f6e2025e5ac0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Apr 2019 19:00:49 +0200
Subject: [PATCH 1792/2207] vale: add support for offsets

---
 sys/dev/netmap/netmap_kern.h |  9 +++++++
 sys/dev/netmap/netmap_mem2.c |  2 +-
 sys/dev/netmap/netmap_vale.c | 50 ++++++++++++++++++++++++------------
 3 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6da330276..987b36735 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1922,6 +1922,9 @@ struct plut_entry {
 
 struct netmap_obj_pool;
 
+/* alignment for netmap buffers */
+#define NM_BUF_ALIGN	64
+
 /*
  * NMB return the virtual address of a buffer (buffer 0 on bad index)
  * PNMB also fills the physical address
@@ -1968,6 +1971,12 @@ nm_get_offset(struct netmap_kring *kring, struct netmap_slot *slot)
 	return offset;
 }
 
+static inline void *
+NMB_O(struct netmap_kring *kring, struct netmap_slot *slot)
+{
+	void *addr = NMB(kring->na, slot);
+	return (char *)addr + nm_get_offset(kring, slot);
+}
 
 static inline void *
 PNMB_O(struct netmap_kring *kring, struct netmap_slot *slot, uint64_t *pp)
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 7c8d2b65d..fe49781dc 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1330,7 +1330,7 @@ netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int obj
 	p->r_objsize = objsize;
 
 #define MAX_CLUSTSIZE	(1<<22)		// 4 MB
-#define LINE_ROUND	NM_CACHE_ALIGN	// 64
+#define LINE_ROUND	NM_BUF_ALIGN	// 64
 	if (objsize >= MAX_CLUSTSIZE) {
 		/* we could do it but there is no point */
 		nm_prerr("unsupported allocation for %d bytes", objsize);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 3f96ef832..24d908cd5 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -99,7 +99,7 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z gle
  * In the tx loop, we aggregate traffic in batches to make all operations
  * faster. The batch size is bridge_batch.
  */
-#define NM_BDG_MAXRINGS		16	/* XXX unclear how many. */
+#define NM_BDG_MAXRINGS		16	/* XXX unclear how many (must be a pow of 2). */
 #define NM_BDG_MAXSLOTS		4096	/* XXX same as above */
 #define NM_BRIDGE_RINGSIZE	1024	/* in the device */
 #define NM_BDG_BATCH		1024	/* entries in the forwarding buffer */
@@ -154,8 +154,9 @@ struct netmap_bdg_ops vale_bdg_ops = {
  * with other odd sizes. We assume there is enough room
  * in the source and destination buffers.
  *
- * XXX only for multiples of 64 bytes, non overlapped.
+ * XXX only for multiples of NM_BUF_ALIGN bytes, non overlapped.
  */
+
 static inline void
 pkt_copy(void *_src, void *_dst, int l)
 {
@@ -165,7 +166,8 @@ pkt_copy(void *_src, void *_dst, int l)
 		memcpy(dst, src, l);
 		return;
 	}
-	for (; likely(l > 0); l-=64) {
+	for (; likely(l > 0); l -= NM_BUF_ALIGN) {
+		/* XXX NM_BUF_ALIGN/sizeof(uint64_t) statements */
 		*dst++ = *src++;
 		*dst++ = *src++;
 		*dst++ = *src++;
@@ -651,8 +653,9 @@ nm_vale_preflush(struct netmap_kring *kring, u_int end)
 		/* this slot goes into a list so initialize the link field */
 		ft[ft_i].ft_next = NM_FT_NULL;
 		buf = ft[ft_i].ft_buf = (slot->flags & NS_INDIRECT) ?
-			(void *)(uintptr_t)slot->ptr : NMB(&na->up, slot);
-		if (unlikely(buf == NULL)) {
+			(void *)(uintptr_t)slot->ptr : NMB_O(kring, slot);
+		if (unlikely(buf == NULL ||
+		     slot->len > NETMAP_BUF_SIZE(&na->up) - nm_get_offset(kring, slot))) {
 			nm_prlim(5, "NULL %s buffer pointer from %s slot %d len %d",
 				(slot->flags & NS_INDIRECT) ? "INDIRECT" : "DIRECT",
 				kring->name, j, ft[ft_i].ft_len);
@@ -939,9 +942,6 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 	/*
 	 * Broadcast traffic goes to ring 0 on all destinations.
 	 * So we need to add these rings to the list of ports to scan.
-	 * XXX at the moment we scan all NM_BDG_MAXPORTS ports, which is
-	 * expensive. We should keep a compact list of active destinations
-	 * so we could shorten this loop.
 	 */
 	brddst = dst_ents + NM_BDG_BROADCAST * NM_BDG_MAXRINGS;
 	if (brddst->bq_head != NM_FT_NULL) {
@@ -998,7 +998,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		next = d->bq_head;
 		/* we need to reserve this many slots. If fewer are
 		 * available, some packets will be dropped.
-		 * Packets may have multiple fragments, so we may not use
+		 * Packets may have multiple fragments, so
 		 * there is a chance that we may not use all of the slots
 		 * we have claimed, so we will need to handle the leftover
 		 * ones when we regain the lock.
@@ -1108,21 +1108,36 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 				do {
 					char *dst, *src = ft_p->ft_buf;
 					size_t copy_len = ft_p->ft_len, dst_len = copy_len;
+					uintptr_t src_cb;
+					uint64_t dstoff, dstoff_cb;
+					int src_co, dst_co;
+					const uintptr_t mask = NM_BUF_ALIGN - 1;
 
 					slot = &ring->slot[j];
 					dst = NMB(&dst_na->up, slot);
+					dstoff = nm_get_offset(kring, slot);
+					dstoff_cb = dstoff & ~mask;
+					src_cb = ((uintptr_t)src) & ~mask;
+					src_co = ((uintptr_t)src) & mask;
+					dst_co = ((uintptr_t)(dst + dstoff)) & mask;
+					if (dst_co < src_co) {
+						dstoff_cb += NM_BUF_ALIGN;
+					}
+					dstoff = dstoff_cb + src_co;
+					copy_len += src_co;
 
 					nm_prdis("send [%d] %d(%d) bytes at %s:%d",
 							i, (int)copy_len, (int)dst_len,
 							NM_IFPNAME(dst_ifp), j);
-					/* round to a multiple of 64 */
-					copy_len = (copy_len + 63) & ~63;
 
-					if (unlikely(copy_len > NETMAP_BUF_SIZE(&dst_na->up) ||
-						     copy_len > NETMAP_BUF_SIZE(&na->up))) {
-						nm_prlim(5, "invalid len %d, down to 64", (int)copy_len);
-						copy_len = dst_len = 64; // XXX
+					if (unlikely(dstoff > NETMAP_BUF_SIZE(&dst_na->up) ||
+				                     dst_len > NETMAP_BUF_SIZE(&dst_na->up) - dstoff)) {
+						nm_prlim(5, "dropping packet/fragment of len %zu, dest offset %llu",
+								dst_len, (unsigned long long)dstoff);
+						copy_len = dst_len = 0;
+						dstoff = nm_get_offset(kring, slot);
 					}
+
 					if (ft_p->ft_flags & NS_INDIRECT) {
 						if (copyin(src, dst, copy_len)) {
 							// invalid user pointer, pretend len is 0
@@ -1130,10 +1145,11 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 						}
 					} else {
 						//memcpy(dst, src, copy_len);
-						pkt_copy(src, dst, (int)copy_len);
+						pkt_copy((char *)src_cb, dst + dstoff_cb, (int)copy_len);
 					}
 					slot->len = dst_len;
 					slot->flags = (cnt << 8)| NS_MOREFRAG;
+					nm_write_offset(kring, slot, dstoff);
 					j = nm_next(j, lim);
 					needed--;
 					ft_p++;
@@ -1312,7 +1328,7 @@ netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
 	if (netmap_verbose)
 		nm_prinf("max frame size %u", vpna->mfs);
 
-	na->na_flags |= NAF_BDG_MAYSLEEP;
+	na->na_flags |= (NAF_BDG_MAYSLEEP | NAF_OFFSETS);
 	/* persistent VALE ports look like hw devices
 	 * with a native netmap adapter
 	 */

From 35675c9ed6bef1c07c4aba7640b97907c5acd16b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 27 May 2019 18:53:12 +0200
Subject: [PATCH 1793/2207] linux/e1000: fix bufcfg logic

---
 LINUX/if_e1000_netmap.h | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 24ff1bff5..c62c1ad28 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -351,12 +351,14 @@ e1000_netmap_bufcfg(struct netmap_kring *kring, int flags)
 			bufsz = sz->bufsize;
 			break;
 		}
-	if (bufsz) {
-		target >>= 10;
-		if (target < 1 || target > 15)
-			return EINVAL;
-
-		bufsz = target << 10;
+	if (!bufsz)
+		return EINVAL;
+	/* check if we can find a better size using 1K increments */
+	target >>= 10;
+	if (target >= 1 && target <= 15) {
+		target <<= 10;
+		if (target > bufsz)
+			bufsz = target;
 	}
 	kring->hwbuf_len = bufsz;
 	kring->buf_align = 0; /* no alignment */

From 23ebacb33ba7fbe0034c04ab12c9547af3e357b5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 10 Jun 2019 14:28:18 +0200
Subject: [PATCH 1794/2207] linux/ixgbe: add support for offsets

---
 LINUX/ixgbe_netmap_linux.h | 70 +++++++++++++++++++++++++++++---------
 1 file changed, 54 insertions(+), 16 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 9649113ec..42541c2a9 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -122,12 +122,13 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	struct ixgbe_hw *hw = &adapter->hw;
 	u32 srrctl;
 	u8 reg_idx = rx_ring->reg_idx;
+	struct netmap_kring *kring = na->rx_rings[reg_idx];
 
 	if (hw->mac.type == ixgbe_mac_82598EB) {
 		u16 mask = adapter->ring_feature[RING_F_RSS].mask;
 		reg_idx &= mask;
 	}
-	srrctl = ((NETMAP_BUF_SIZE(na) + 1023) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT);
+	srrctl =  kring->hwbuf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
 	/*
 	 * XXX
 	 * With Advanced RX descriptor, the address needs to be rewritten,
@@ -136,7 +137,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 	 * (ixgbe datasheet - Section 7.1.9)
 	 */
 	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
-	nm_prdis("bufsz: %d srrctl: %x", NETMAP_BUF_SIZE(na), srrctl);
+	nm_prdis("bufsz: %d srrctl: %x", kring->hwbuf_len, srrctl);
 	IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
 }
 
@@ -329,7 +330,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			uint64_t paddr;
-			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			/* device-specific */
 			union ixgbe_adv_tx_desc *curr = NM_IXGBE_TX_DESC(txr, nic_i);
@@ -337,7 +338,8 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 				IXGBE_ADVTXD_DCMD_IFCS;
 			u_int totlen = len;
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
 			report = slot->flags & NS_REPORT ||
 				nic_i == 0 ||
@@ -350,7 +352,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 				 */
 				union ixgbe_adv_tx_desc *first = curr;
 
-				first->read.buffer_addr = htole64(paddr);
+				first->read.buffer_addr = htole64(paddr + offset);
 				first->read.cmd_type_len = htole32(len | hw_flags);
 				netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 						&paddr, len, NR_TX);
@@ -373,13 +375,14 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 					}
 					slot = &ring->slot[nm_i];
 					len = slot->len;
-					addr = PNMB(na, slot, &paddr);
-					NM_CHECK_ADDR_LEN(na, addr, len);
+					PNMB(na, slot, &paddr);
+					offset = nm_get_offset(kring, slot);
+					NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 					curr = NM_IXGBE_TX_DESC(txr, nic_i);
 					totlen += len;
 					if (!(slot->flags & NS_MOREFRAG))
 						break;
-					curr->read.buffer_addr = htole64(paddr);
+					curr->read.buffer_addr = htole64(paddr + offset);
 					curr->read.olinfo_status = 0;
 					curr->read.cmd_type_len = htole32(len | hw_flags);
 
@@ -400,7 +403,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
 			/* Fill the slot in the NIC ring. */
-			curr->read.buffer_addr = htole64(paddr);
+			curr->read.buffer_addr = htole64(paddr + offset);
 			curr->read.olinfo_status = htole32(totlen << IXGBE_ADVTXD_PAYLEN_SHIFT);
 			curr->read.cmd_type_len = htole32(len | hw_flags);
 			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
@@ -482,7 +485,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags)
 	for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
 		struct netmap_slot *slot = &ring->slot[tosync];
 		uint64_t paddr;
-		(void)PNMB(na, slot, &paddr);
+		(void)PNMB_O(kring, slot, &paddr);
 
 		netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 				&paddr, slot->len, NR_TX);
@@ -570,7 +573,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			slot->len = size;
 			complete = staterr & IXGBE_RXD_STAT_EOP;
 			slot->flags = complete ? 0 : NS_MOREFRAG;
-			PNMB(na, slot, &paddr);
+			PNMB_O(kring, slot, &paddr);
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, size, NR_RX);
 
@@ -610,6 +613,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(rxr, nic_i);
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
@@ -622,7 +626,7 @@ ixgbe_netmap_rxsync(struct netmap_kring *kring, int flags)
 					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
 			curr->wb.upper.length = 0;
 			curr->wb.upper.status_error = 0;
-			curr->read.pkt_addr = htole64(paddr);
+			curr->read.pkt_addr = htole64(paddr + offset);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -718,12 +722,15 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	struct netmap_slot *slot;
 	int lim, i;
 	struct NM_IXGBE_RING *ring = NM_IXGBE_RX_RING(adapter, ring_nr);
+	struct netmap_kring *kring;
 
 	slot = netmap_reset(na, NR_RX, ring_nr, 0);
 	/* same as in ixgbe_setup_transmit_ring() */
 	if (!slot)
 		return 0;	// not in native netmap mode
-	// XXX can we move it later ?
+
+	kring = na->rx_rings[ring_nr];
+
 	ixgbe_netmap_configure_srrctl(adapter, ring);
 
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
@@ -734,10 +741,10 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 		 * considering the offset between the netmap and NIC rings
 		 * (see comment in ixgbe_setup_transmit_ring() ).
 		 */
-		int si = netmap_idx_n2k(na->rx_rings[ring_nr], i);
+		int si = netmap_idx_n2k(kring, i);
 		union ixgbe_adv_rx_desc *curr = NM_IXGBE_RX_DESC(ring, i);
 		uint64_t paddr;
-		PNMB(na, slot + si, &paddr);
+		PNMB_O(kring, slot + si, &paddr);
 		/* Update descriptor */
 		curr->read.pkt_addr = htole64(paddr);
 		curr->wb.upper.length = 0;
@@ -855,6 +862,36 @@ ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 	return 0;
 }
 
+static int
+ixgbe_netmap_bufcfg(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	uint64_t target, maxframe;
+
+	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
+
+	kring->buf_align = 0;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+
+	maxframe = ifp->mtu + ETH_HLEN + ETH_FCS_LEN;
+	if (maxframe < target) {
+		target = NETMAP_BUF_SIZE(na);
+	}
+
+	target >>= 10;
+	if (target < 1 || target > 16)
+		return EINVAL;
+
+	kring->hwbuf_len = target << 10;
+
+	return 0;
+}
+
 
 static void ixgbe_netmap_detach(struct NM_IXGBE_ADAPTER *adapter);
 /*
@@ -873,7 +910,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
-	na.na_flags = NAF_MOREFRAG;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
 	na.num_tx_desc = NM_IXGBE_TX_RING(adapter, 0)->count;
 	na.num_rx_desc = NM_IXGBE_RX_RING(adapter, 0)->count;
 	na.num_tx_rings = adapter->num_tx_queues;
@@ -886,6 +923,7 @@ ixgbe_netmap_attach(struct NM_IXGBE_ADAPTER *adapter)
 	na.nm_krings_delete = ixgbe_netmap_krings_delete;
 	na.nm_intr = ixgbe_netmap_intr;
 	na.nm_config = ixgbe_netmap_config;
+	na.nm_bufcfg = ixgbe_netmap_bufcfg;
 
 	if (netmap_attach_ext(&na, sizeof(struct netmap_ixgbe_adapter), 1)) {
 		pr_err("netmap: failed to attach netmap adapter");

From dc078cff0f18fc022573bc91dcebca78601f59e5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 10 Jun 2019 15:57:36 +0200
Subject: [PATCH 1795/2207] linux/i40e: add support for offsets

---
 LINUX/i40e_netmap_linux.h | 55 ++++++++++++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 10 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 1ce377557..745e83271 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -137,6 +137,7 @@ i40e_netmap_preconfigure_rx_ring(struct i40e_ring *ring,
 		struct i40e_hmc_obj_rxq *rx_ctx)
 {
 	struct netmap_adapter *na;
+	struct netmap_kring *kring;
 
 	if (!ring->netdev) {
 		// XXX it this possible?
@@ -148,8 +149,8 @@ i40e_netmap_preconfigure_rx_ring(struct i40e_ring *ring,
 	if (netmap_reset(na, NR_RX, ring->queue_index, 0) == NULL)
 		return;	// not in native netmap mode
 
-	rx_ctx->dbuff = DIV_ROUND_UP(NETMAP_BUF_SIZE(na),
-			BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
+	kring = na->rx_rings[ring->queue_index];
+	rx_ctx->dbuff = kring->hwbuf_len >> I40E_RXQ_CTX_DBUFF_SHIFT;
 }
 
 static int
@@ -179,7 +180,7 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 		int si = netmap_idx_n2k(kring, i);
 		uint64_t paddr;
 		union i40e_rx_desc *rx = I40E_RX_DESC(ring, i);
-		PNMB(na, slot + si, &paddr);
+		PNMB_O(kring, slot + si, &paddr);
 
 		rx->read.pkt_addr = htole64(paddr);
 		rx->read.hdr_addr = 0;
@@ -226,6 +227,37 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 	return 0;
 }
 
+static int
+i40e_netmap_bufcfg(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	uint64_t target, maxframe, incr;
+
+	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
+
+	kring->buf_align = 0;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+
+	maxframe = ifp->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+	if (maxframe < target) {
+		target = NETMAP_BUF_SIZE(na);
+	}
+
+	incr = 1UL << I40E_RXQ_CTX_DBUFF_SHIFT;
+	target &= ~(incr - 1);
+	if (target < 1024UL || target > 16384UL - incr)
+		return EINVAL;
+
+	kring->hwbuf_len = target;
+
+	return 0;
+}
+
 static int
 i40e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
@@ -256,7 +288,7 @@ i40e_netmap_attach(struct i40e_vsi *vsi)
 
 	na.ifp = vsi->netdev;
 	na.pdev = &vsi->back->pdev->dev;
-	na.na_flags = NAF_MOREFRAG;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
 	na.num_tx_desc = NM_I40E_TX_RING(vsi, 0)->count;
 	na.num_rx_desc = NM_I40E_RX_RING(vsi, 0)->count;
 	na.num_tx_rings = na.num_rx_rings = vsi->num_queue_pairs;
@@ -265,6 +297,7 @@ i40e_netmap_attach(struct i40e_vsi *vsi)
 	na.nm_rxsync = i40e_netmap_rxsync;
 	na.nm_register = i40e_netmap_reg;
 	na.nm_config = i40e_netmap_config;
+	na.nm_bufcfg = i40e_netmap_bufcfg;
 	netmap_attach(&na);
 }
 
@@ -370,7 +403,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			uint64_t paddr;
-			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			/* device-specific */
 			struct i40e_tx_desc *curr = I40E_TX_DESC(txr, nic_i);
@@ -380,7 +413,8 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 			__builtin_prefetch(&ring->slot[nm_i + 1]);
 			__builtin_prefetch(I40E_TX_DESC(txr, nic_i));
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
 				hw_flags |= ((u64)(I40E_TX_DESC_CMD_EOP) <<
@@ -402,7 +436,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 			/* Fill the slot in the NIC ring.
 			 * (we should investigate if using legacy descriptors
 			 * is faster). */
-			curr->buffer_addr = htole64(paddr);
+			curr->buffer_addr = htole64(paddr + offset);
 			curr->cmd_type_offset_bsz = htole64(
 			    ((u64)len << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
 			    hw_flags |
@@ -438,7 +472,7 @@ i40e_netmap_txsync(struct netmap_kring *kring, int flags)
 		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
 			struct netmap_slot *slot = &ring->slot[tosync];
 			uint64_t paddr;
-			(void)PNMB(na, slot, &paddr);
+			(void)PNMB_O(kring, slot, &paddr);
 
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_TX);
@@ -550,7 +584,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 				complete = 1;
 			}
 			slot->flags = slot_flags;
-			PNMB(na, slot, &paddr);
+			PNMB_O(kring, slot, &paddr);
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_RX);
 
@@ -582,6 +616,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			union i40e_rx_desc *curr = I40E_RX_DESC(rxr, nic_i);
 
@@ -593,7 +628,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 				//netmap_reload_map(na, rxr->ptag, rxbuf->pmap, addr);
 				slot->flags &= ~NS_BUF_CHANGED;
 			}
-			curr->read.pkt_addr = htole64(paddr);
+			curr->read.pkt_addr = htole64(paddr + offset);
 			curr->read.hdr_addr = 0; // XXX needed
 			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 					&paddr, NETMAP_BUF_SIZE(na), NR_RX);

From 3d3f61d3983095e4cf2f80647a7130128e008ad4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 11 Jun 2019 17:27:28 +0200
Subject: [PATCH 1796/2207] linux/igb: add support for offsets

---
 LINUX/if_igb_netmap.h | 91 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 75 insertions(+), 16 deletions(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 4db19f1f8..396e81e85 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -47,28 +47,46 @@ char netmap_igb_driver_name[] = "igb" NETMAP_LINUX_DRIVER_SUFFIX;
  */
 #ifdef NETMAP_LINUX_HAVE_IGB_RD32
 #define READ_TDH(_adapter, _txr)	igb_rd32(&(_adapter)->hw, E1000_TDH((_txr)->reg_idx))
+#define READ_RCTL(_adapter, _rxr)	igb_rd32(&(_adapter)->hw, E1000_RXDCTL((_rxr)->reg_idx))
 #elif defined(E1000_READ_REG)
 #define READ_TDH(_adapter, _txr)	E1000_READ_REG(&(_adapter)->hw, E1000_TDH((_txr)->reg_idx))
+#define READ_RCTL(_adapter, _rxr)	E1000_READ_REG(&(_adapter)->hw, E1000_RXDCTL((_rxr)->reg_idx))
 #elif defined rd32
 static inline u32 READ_TDH(struct igb_adapter *adapter, struct igb_ring *txr)
 {
 	struct e1000_hw *hw = &adapter->hw;
 	return rd32(E1000_TDH(txr->reg_idx));
 }
+static inline u32 READ_RCTL(struct igb_adapter *adapter, struct igb_ring *rxr)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	return rd32(E1000_RXDCTL(rxr->reg_idx));
+}
 #else
 #define	READ_TDH(_adapter, _txr)	readl((_txr)->head)
+#define	READ_RCTL(_adapter, _rxr)	readl(E1000_RXDCRL((_rxr)->reg_idx))
 #endif
 #ifdef E1000_WRITE_REG
+#define NM_WRITE_RCTL(_adapter, _rxr, _rxdctl)	\
+	E1000_WRITE_REG(&(_adapter)->hw, E1000_RXDCTL((_rxr)->reg_idx), (rxdctl))
 #define NM_WRITE_SRRCTL(_adapter, _rxr, _srrctl)	\
 	E1000_WRITE_REG(&(_adapter)->hw, E1000_SRRCTL((_rxr)->reg_idx), (srrctl))
 #elif defined(wr32)
-static inline void NM_WRITE_SRRCTL(struct igb_adapter *adapter, struct igb_ring *txr,
+static inline void NM_WRITE_RCTL(struct igb_adapter *adapter, struct igb_ring *rxr,
+	u32 rxdctl)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	wr32(E1000_RXDCTL(rxr->reg_idx), rxdctl);
+}
+static inline void NM_WRITE_SRRCTL(struct igb_adapter *adapter, struct igb_ring *rxr,
 	u32 srrctl)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	wr32(E1000_TDH(txr->reg_idx), srrctl);
+	wr32(E1000_TDH(rxr->reg_idx), srrctl);
 }
 #else
+#define NM_WRITE_RCTL(_adapter, _rxr, _rxdctl)	\
+	writel(E1000_RCTL((_rxr)->reg_idx, (_rxdctl))
 #define NM_WRITE_SRRCTL(_adapter, _rxr, _srrctl)	\
 	writel(E1000_SRRCTL((_rxr)->reg_idx, (_srrctl))
 #endif
@@ -154,6 +172,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 			u_int len = slot->len;
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			/* device-specific */
 			union e1000_adv_tx_desc *curr =
@@ -162,7 +181,8 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 				E1000_ADVTXD_DCMD_IFCS;
 			u_int totlen = len;
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
 			report = slot->flags & NS_REPORT ||
 				nic_i == 0 ||
@@ -175,7 +195,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 				 */
 				union e1000_adv_tx_desc *first = curr;
 
-				first->read.buffer_addr = htole64(paddr);
+				first->read.buffer_addr = htole64(paddr + offset);
 				first->read.cmd_type_len = htole32(len | hw_flags);
 				netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 						&paddr, len, NR_TX);
@@ -199,12 +219,14 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 					slot = &ring->slot[nm_i];
 					len = slot->len;
 					addr = PNMB(na, slot, &paddr);
-					NM_CHECK_ADDR_LEN(na, addr, len);
+					PNMB(na, slot, &paddr);
+					offset = nm_get_offset(kring, slot);
+					NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 					curr = E1000_TX_DESC_ADV(*txr, nic_i);
 					totlen += len;
 					if (!(slot->flags & NS_MOREFRAG))
 						break;
-					curr->read.buffer_addr = htole64(paddr);
+					curr->read.buffer_addr = htole64(paddr + offset);
 					curr->read.olinfo_status = 0;
 					curr->read.cmd_type_len = htole32(len | hw_flags);
 
@@ -224,7 +246,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
 
 			/* Fill the slot in the NIC ring. */
-			curr->read.buffer_addr = htole64(paddr);
+			curr->read.buffer_addr = htole64(paddr + offset);
 			// XXX check olinfo and cmd_type_len
 			curr->read.olinfo_status = htole32(totlen<< E1000_ADVTXD_PAYLEN_SHIFT);
 			curr->read.cmd_type_len = htole32(len | hw_flags);
@@ -259,7 +281,7 @@ igb_netmap_txsync(struct netmap_kring *kring, int flags)
 		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
 			struct netmap_slot *slot = &ring->slot[tosync];
 			uint64_t paddr;
-			(void)PNMB(na, slot, &paddr);
+			(void)PNMB_O(kring, slot, &paddr);
 
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_TX);
@@ -319,7 +341,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			dma_rmb(); /* read descriptor after status DD */
-			PNMB(na, slot, &paddr);
+			PNMB_O(kring, slot, &paddr);
 			slot->len = le16toh(curr->wb.upper.length);
 			complete = (staterr & E1000_RXD_STAT_EOP);
 			slot->flags = complete ? 0 : NS_MOREFRAG;
@@ -348,6 +370,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 			union e1000_adv_rx_desc *curr = E1000_RX_DESC_ADV(*rxr, nic_i);
 
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
@@ -358,7 +381,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			}
 			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
-			curr->read.pkt_addr = htole64(paddr);
+			curr->read.pkt_addr = htole64(paddr + offset);
 			curr->read.hdr_addr = 0;
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
@@ -388,6 +411,7 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 	struct netmap_adapter* na = NA(ifp);
 	struct netmap_slot* slot;
 	struct igb_ring *txr = adapter->tx_ring[ring_nr];
+	struct netmap_kring *kring;
 	int i, si;
 	void *addr;
 	uint64_t paddr;
@@ -395,10 +419,11 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 	slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
 		return 0;  // not in netmap native mode
+	kring = na->tx_rings[ring_nr];
 	for (i = 0; i < na->num_tx_desc; i++) {
 		union e1000_adv_tx_desc *tx_desc;
-		si = netmap_idx_n2k(na->tx_rings[ring_nr], i);
-		addr = PNMB(na, slot + si, &paddr);
+		si = netmap_idx_n2k(kring, i);
+		addr = PNMB_O(kring, slot + si, &paddr);
 		tx_desc = E1000_TX_DESC_ADV(*txr, i);
 		tx_desc->read.buffer_addr = htole64(paddr);
 		/* actually we don't care to init the rings here */
@@ -406,15 +431,46 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 	return 1;	// success
 }
 
+static int
+igb_netmap_bufcfg(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	uint64_t target, maxframe;
+
+	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+	maxframe = na->ifp->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
+	if (maxframe < target) {
+		/* we can ignore the offset */
+		target = NETMAP_BUF_SIZE(na);
+	}
+
+	target >>= 10;
+	if (target >= 1 && target <= 16) {
+		target <<= 10;
+	} else {
+		return EINVAL;
+	}
+	kring->hwbuf_len = target;
+	kring->buf_align = 0; /* no alignment */
+	nm_prinf("%s: hwbuf_len %llu", kring->name, kring->hwbuf_len);
+	return 0;
+}
+
 static void
 igb_netmap_configure_srrctl(struct igb_ring *rxr)
 {
 	struct ifnet *ifp = rxr->netdev;
 	struct netmap_adapter* na = NA(ifp);
 	struct igb_adapter *adapter = netdev_priv(ifp);
+	struct netmap_kring *kring = na->rx_rings[rxr->reg_idx];
 	u32 srrctl;
 
-	srrctl = ALIGN(NETMAP_BUF_SIZE(na), 1024) >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+	srrctl = kring->hwbuf_len >> E1000_SRRCTL_BSIZEPKT_SHIFT;
 	srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
 	srrctl |= E1000_SRRCTL_DROP_EN;
 	NM_WRITE_SRRCTL(adapter, rxr, srrctl);
@@ -428,6 +484,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	struct netmap_adapter* na = NA(ifp);
 	int reg_idx = rxr->reg_idx;
 	struct netmap_slot* slot;
+	struct netmap_kring *kring;
 	u_int i;
 
 	/*
@@ -446,12 +503,13 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 
 	igb_netmap_configure_srrctl(rxr);
 
+	kring = na->rx_rings[reg_idx];
 	for (i = 0; i < rxr->count; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;
-		int si = netmap_idx_n2k(na->rx_rings[reg_idx], i);
+		int si = netmap_idx_n2k(kring, i);
 
-		PNMB(na, slot + si, &paddr);
+		PNMB_O(kring, slot + si, &paddr);
 		rx_desc = E1000_RX_DESC_ADV(*rxr, i);
 		rx_desc->read.hdr_addr = 0;
 		rx_desc->read.pkt_addr = htole64(paddr);
@@ -489,7 +547,7 @@ igb_netmap_attach(struct SOFTC_T *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
-	na.na_flags = NAF_MOREFRAG;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
 	na.num_tx_desc = adapter->tx_ring_count;
 	na.num_rx_desc = adapter->rx_ring_count;
 	na.num_tx_rings = adapter->num_tx_queues;
@@ -499,6 +557,7 @@ igb_netmap_attach(struct SOFTC_T *adapter)
 	na.nm_txsync = igb_netmap_txsync;
 	na.nm_rxsync = igb_netmap_rxsync;
 	na.nm_config = igb_netmap_config;
+	na.nm_bufcfg = igb_netmap_bufcfg;
 	netmap_attach(&na);
 }
 

From 14903e71d623a8135ff5d9daee01a2f75df4db2d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 9 Dec 2019 15:17:21 +0100
Subject: [PATCH 1797/2207] linux/e1000e: add support for offsets

---
 LINUX/if_e1000e_netmap.h | 80 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 7c69018dc..16d7b8ee2 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -112,6 +112,74 @@ e1000_netmap_reg(struct netmap_adapter *na, int onoff)
 	return (0);
 }
 
+struct e1000e_netmap_szdesc {
+	uint32_t bufsize;
+	uint32_t rctl;
+};
+
+#define E1000_NETMAP_RCTL_MASK	0x7A030000
+static struct e1000e_netmap_szdesc e1000e_netmap_bufsize[] = {
+	{ 16384,	0x02010000},
+	{ 8192,		0x02020000},
+	{ 4096,		0x02030000},
+	{ 2048,		0x00000000},
+	{ 1024,		0x00010000},
+	{ 512,		0x00020000},
+	{ 256,		0x00030000},
+	{ 0,		0},
+};
+
+static uint32_t
+e1000e_netmap_get_rctl(uint32_t bufsize)
+{
+	struct e1000e_netmap_szdesc *sz;
+
+	for (sz = e1000e_netmap_bufsize; sz->bufsize; sz++)
+		if (bufsize == sz->bufsize)
+			return sz->rctl;
+
+	return ((bufsize >> 10) & 0xF) << 27;
+}
+
+static int
+e1000e_netmap_bufcfg(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	uint64_t target, bufsz, maxframe;
+	struct e1000e_netmap_szdesc *sz;
+
+	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+	maxframe = na->ifp->mtu + ETH_HLEN + ETH_FCS_LEN;
+	if (maxframe < target) {
+		/* we can ignore the offset */
+		target = NETMAP_BUF_SIZE(na);
+	}
+
+	bufsz = 0;
+	for (sz = e1000e_netmap_bufsize; sz->bufsize; sz++)
+		if (sz->bufsize <= target) {
+			bufsz = sz->bufsize;
+			break;
+		}
+	if (!bufsz)
+		return EINVAL;
+	/* check if we can find a better size using 1K increments */
+	target >>= 10;
+	if (target >= 1 && target <= 15) {
+		target <<= 10;
+		if (target > bufsz)
+			bufsz = target;
+	}
+	kring->hwbuf_len = bufsz;
+	kring->buf_align = 0; /* no alignment */
+	nm_prinf("%s: hwbuf_len %llu", kring->name, kring->hwbuf_len);
+	return 0;
+}
 
 /*
  * Reconcile kernel and user view of the transmit ring.
@@ -336,13 +404,16 @@ static void e1000e_no_rx_alloc(struct SOFTC_T *a, int n)
  */
 static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 {
+	struct e1000_hw *hw = &adapter->hw;
 	struct ifnet *ifp = adapter->netdev;
 	struct netmap_adapter* na = NA(ifp);
+	struct netmap_kring *kring;
 	struct netmap_slot* slot;
 	struct e1000_ring *rxr = adapter->rx_ring;
 	struct e1000_ring *txr = adapter->tx_ring;
 	int i, si;
 	uint64_t paddr;
+	uint32_t rctl;
 
 	if (!nm_native_on(na))
 		return 0;
@@ -362,6 +433,14 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		rxr->next_to_use = 0;
 		/* preserve buffers already made available to clients */
 		i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[0]);
+
+		/* program the RCTL */
+		kring = na->rx_rings[0];
+		rctl = er32(RCTL);
+		rctl = (rctl & ~E1000_NETMAP_RCTL_MASK) |
+			e1000e_netmap_get_rctl(kring->hwbuf_len);
+		ew32(RCTL, rctl);
+
 		wmb();	/* Force memory writes to complete */
 		NM_WR_RX_TAIL(i);
 	}
@@ -412,6 +491,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 	na.nm_txsync = e1000_netmap_txsync;
 	na.nm_rxsync = e1000_netmap_rxsync;
 	na.nm_config = e1000e_netmap_config;
+	na.nm_bufcfg = e1000e_netmap_bufcfg;
 	netmap_attach(&na);
 }
 

From 08050e15c11b0ce908c5201514c359e46acb16af Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 2 May 2020 17:35:13 +0200
Subject: [PATCH 1798/2207] offsets: refactor bufcfg logic

---
 LINUX/i40e_netmap_linux.h    | 12 ++----------
 LINUX/if_e1000_netmap.h      | 12 ++----------
 LINUX/if_e1000e_netmap.h     | 11 ++---------
 LINUX/if_igb_netmap.h        | 12 +-----------
 LINUX/ixgbe_netmap_linux.h   | 10 +---------
 sys/dev/netmap/netmap.c      | 22 +++++++++++++++-------
 sys/dev/netmap/netmap_kern.h |  4 ++--
 7 files changed, 25 insertions(+), 58 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 745e83271..6e565f76b 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -228,13 +228,10 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 }
 
 static int
-i40e_netmap_bufcfg(struct netmap_kring *kring, int flags)
+i40e_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
 	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
-	uint64_t target, maxframe, incr;
-
-	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
+	uint64_t incr;
 
 	kring->buf_align = 0;
 
@@ -243,11 +240,6 @@ i40e_netmap_bufcfg(struct netmap_kring *kring, int flags)
 		return 0;
 	}
 
-	maxframe = ifp->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
-	if (maxframe < target) {
-		target = NETMAP_BUF_SIZE(na);
-	}
-
 	incr = 1UL << I40E_RXQ_CTX_DBUFF_SHIFT;
 	target &= ~(incr - 1);
 	if (target < 1024UL || target > 16384UL - incr)
diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index c62c1ad28..20025dba5 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -327,23 +327,15 @@ e1000_netmap_get_rctl(uint32_t bufsize)
 }
 
 static int
-e1000_netmap_bufcfg(struct netmap_kring *kring, int flags)
+e1000_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct netmap_adapter *na = kring->na;
-	uint64_t target, bufsz, maxframe;
+	uint64_t bufsz;
 	struct e1000_netmap_szdesc *sz;
 
-	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
-
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
-	maxframe = na->ifp->mtu + ETH_HLEN + ETH_FCS_LEN;
-	if (maxframe < target) {
-		/* we can ignore the offset */
-		target = NETMAP_BUF_SIZE(na);
-	}
 
 	bufsz = 0;
 	for (sz = e1000_netmap_bufsize; sz->bufsize; sz++)
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 16d7b8ee2..a7213683e 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -142,23 +142,16 @@ e1000e_netmap_get_rctl(uint32_t bufsize)
 }
 
 static int
-e1000e_netmap_bufcfg(struct netmap_kring *kring, int flags)
+e1000e_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
 	struct netmap_adapter *na = kring->na;
-	uint64_t target, bufsz, maxframe;
+	uint64_t bufsz;
 	struct e1000e_netmap_szdesc *sz;
 
-	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
-
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
-	maxframe = na->ifp->mtu + ETH_HLEN + ETH_FCS_LEN;
-	if (maxframe < target) {
-		/* we can ignore the offset */
-		target = NETMAP_BUF_SIZE(na);
-	}
 
 	bufsz = 0;
 	for (sz = e1000e_netmap_bufsize; sz->bufsize; sz++)
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 396e81e85..2d87acd58 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -432,22 +432,12 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 }
 
 static int
-igb_netmap_bufcfg(struct netmap_kring *kring, int flags)
+igb_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct netmap_adapter *na = kring->na;
-	uint64_t target, maxframe;
-
-	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
-
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
-	maxframe = na->ifp->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
-	if (maxframe < target) {
-		/* we can ignore the offset */
-		target = NETMAP_BUF_SIZE(na);
-	}
 
 	target >>= 10;
 	if (target >= 1 && target <= 16) {
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 42541c2a9..d7bf60d15 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -863,13 +863,10 @@ ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 }
 
 static int
-ixgbe_netmap_bufcfg(struct netmap_kring *kring, int flags)
+ixgbe_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
 	struct netmap_adapter *na = kring->na;
 	struct ifnet *ifp = na->ifp;
-	uint64_t target, maxframe;
-
-	target = NETMAP_BUF_SIZE(na) - kring->offset_max;
 
 	kring->buf_align = 0;
 
@@ -878,11 +875,6 @@ ixgbe_netmap_bufcfg(struct netmap_kring *kring, int flags)
 		return 0;
 	}
 
-	maxframe = ifp->mtu + ETH_HLEN + ETH_FCS_LEN;
-	if (maxframe < target) {
-		target = NETMAP_BUF_SIZE(na);
-	}
-
 	target >>= 10;
 	if (target < 1 || target > 16)
 		return EINVAL;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 558939899..4b5fe1c29 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -799,13 +799,9 @@ static int netmap_txsync_to_host(struct netmap_kring *kring, int flags);
 static int netmap_rxsync_from_host(struct netmap_kring *kring, int flags);
 
 static int
-netmap_default_bufcfg(struct netmap_kring *kring, int flags)
+netmap_default_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct netmap_adapter *na = kring->na;
-
-	(void)flags;
-
-	kring->hwbuf_len = NETMAP_BUF_SIZE(na) - kring->offset_max;
+	kring->hwbuf_len = target;
 	kring->buf_align = 0; /* no alignment */
 	return 0;
 }
@@ -2368,6 +2364,7 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 	int error = 0;
 	unsigned mtu = 0;
 	struct netmap_adapter *na = priv->np_na;
+	uint64_t target, maxframe;
 
 	if (na->ifp != NULL)
 		mtu = nm_os_ifnet_mtu(na->ifp);
@@ -2377,7 +2374,18 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 		if (kring->users > 1)
 			continue;
 
-		error = kring->nm_bufcfg(kring, 0);
+		target = NETMAP_BUF_SIZE(kring->na) -
+			kring->offset_max;
+
+		if (mtu) {
+			maxframe = mtu + ETH_HLEN +
+				ETH_FCS_LEN + 4; /* VLAN_HLEN */
+			if (maxframe < target) {
+				target = NETMAP_BUF_SIZE(kring->na);
+			}
+		}
+
+		error = kring->nm_bufcfg(kring, target);
 		if (error)
 			goto out;
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 987b36735..c20bf2c86 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -558,7 +558,7 @@ struct netmap_kring {
 	uint64_t buf_align;
 
 	/* harware specific logic for the selection of the hwbuf_len */
-	int (*nm_bufcfg)(struct netmap_kring *kring, int flags);
+	int (*nm_bufcfg)(struct netmap_kring *kring, uint64_t target);
 
 	int (*save_notify)(struct netmap_kring *kring, int flags);
 
@@ -852,7 +852,7 @@ struct netmap_adapter {
 	int (*nm_txsync)(struct netmap_kring *kring, int flags);
 	int (*nm_rxsync)(struct netmap_kring *kring, int flags);
 	int (*nm_notify)(struct netmap_kring *kring, int flags);
-	int (*nm_bufcfg)(struct netmap_kring *kring, int flags);
+	int (*nm_bufcfg)(struct netmap_kring *kring, uint64_t target);
 #define NAF_FORCE_READ      1
 #define NAF_FORCE_RECLAIM   2
 #define NAF_CAN_FORWARD_DOWN 4

From 047611f5722624b0d1cb859f2e1e3e109d8ea982 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 2 May 2020 18:38:24 +0200
Subject: [PATCH 1799/2207] offsets: add min_gap parameter

---
 libnetmap/libnetmap.h        |  3 ++-
 libnetmap/nmport.c           |  6 ++++--
 sys/dev/netmap/netmap.c      | 11 +++++++++--
 sys/dev/netmap/netmap_kern.h |  6 ++++++
 sys/net/netmap.h             |  1 +
 5 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index be22a2cd9..a3bca2a5b 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -417,9 +417,10 @@ struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
  * @initial	the initial offset for all the slots
  * @maxoff	the maximum offset
  * @bits	the number of bits of slot->ptr to use for the offsets
+ * @mingap	the minimum gap betwen offsets (in shared buffers)
  */
 int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff,
-		uint64_t bits);
+		uint64_t bits, uint64_t mingap);
 
 /* enable/disable options
  *
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 2f10413fb..c1c206c92 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -217,7 +217,8 @@ nmport_extmem_getinfo(struct nmport_d *d)
 }
 
 int
-nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff, uint64_t bits)
+nmport_offset(struct nmport_d *d, uint64_t initial,
+		uint64_t maxoff, uint64_t bits, uint64_t mingap)
 {
 	struct nmctx *ctx = d->ctx;
 	struct nmreq_opt_offsets *opt;
@@ -233,6 +234,7 @@ nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff, uint64_t bi
 	opt->nro_offset_bits = bits;
 	opt->nro_initial_offset = initial;
 	opt->nro_max_offset = maxoff;
+	opt->nro_min_gap = mingap;
 	nmreq_push_option(&d->hdr, &opt->nro_opt);
 	return 0;
 }
@@ -437,7 +439,7 @@ NPOPT_PARSER(offset)(struct nmreq_parse_ctx *p)
 	if (nmport_key(p, offset, bits) != NULL)
 		bits = atoi(nmport_key(p, offset, bits));
 
-	return nmport_offset(d, initial, initial, bits);
+	return nmport_offset(d, initial, initial, bits, 0);
 }
 
 
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4b5fe1c29..5998b6a50 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2240,7 +2240,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	struct netmap_adapter *na = priv->np_na;
 	struct netmap_kring *kring;
 	uint64_t mask = 0, bits = 0, maxbits = sizeof(uint64_t) * 8,
-		 max_offset = 0, initial_offset = 0;
+		 max_offset = 0, initial_offset = 0, min_gap = 0;
 	u_int i;
 	enum txrx t;
 	int error = 0;
@@ -2260,6 +2260,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 	/* check sanity of the opt values */
 	max_offset = opt->nro_max_offset;
+	min_gap = opt->nro_min_gap;
 	initial_offset = opt->nro_initial_offset;
 	bits = opt->nro_offset_bits;
 
@@ -2328,6 +2329,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			kring->offset_mask = mask;
 			*(uint64_t *)&ring->offset_mask = mask;
 			kring->offset_max = max_offset;
+			kring->offset_gap = min_gap;
 		}
 
 		/* if there is an initial offset, put it into
@@ -2376,12 +2378,17 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 
 		target = NETMAP_BUF_SIZE(kring->na) -
 			kring->offset_max;
+		if (!kring->offset_gap)
+			kring->offset_gap =
+				NETMAP_BUF_SIZE(kring->na);
+		if (kring->offset_gap < target)
+			target = kring->offset_gap;
 
 		if (mtu) {
 			maxframe = mtu + ETH_HLEN +
 				ETH_FCS_LEN + 4; /* VLAN_HLEN */
 			if (maxframe < target) {
-				target = NETMAP_BUF_SIZE(kring->na);
+				target = kring->offset_gap;
 			}
 		}
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c20bf2c86..3985fd5bd 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -542,6 +542,12 @@ struct netmap_kring {
 	 * Larger offset requests will be silently capped to offset_max.
 	 */
 	uint64_t offset_max;
+	/* minimum gap between two consecutive offsets into the same
+	 * buffer, as stipulated at bind time. This is used to choose
+	 * the hwbuf_len, but is not otherwise checked for compliance
+	 * at runtime.
+	 */
+	uint64_t offset_gap;
 
 	/* size of hardware buffer. This may be less than the size of
 	 * the netmap buffers because of non-zero offsets, or because
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 804cc328f..541d0e16d 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -960,6 +960,7 @@ struct nmreq_opt_offsets {
 	uint64_t		nro_initial_offset;
 	uint32_t		nro_offset_bits;
 	uint32_t		nro_tx_align;
+	uint64_t		nro_min_gap;
 };
 
 #endif /* _NET_NETMAP_H_ */

From 2906bf3b19ebf64d392c3166c6b1f6100369e9e3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 May 2020 16:05:10 +0200
Subject: [PATCH 1800/2207] offsets: user doc

---
 libnetmap/libnetmap.h | 32 ++++++++++++++++++++++++++++++++
 sys/net/netmap.h      | 16 ++++++++++++++++
 sys/net/netmap_user.h |  5 +++++
 3 files changed, 53 insertions(+)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index a3bca2a5b..c3361a8d6 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -418,6 +418,38 @@ struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
  * @maxoff	the maximum offset
  * @bits	the number of bits of slot->ptr to use for the offsets
  * @mingap	the minimum gap betwen offsets (in shared buffers)
+ *
+ * With this option the lower @bits bits of the ptr field in the netmap_slot
+ * can be used to specify an offset into the buffer.  All offsets will be set
+ * to the @initial value by netmap.
+ *
+ * The offset field can be read and updated using the bitmask found in
+ * ring->offset_mask after a successful register.  netmap_user.h contains
+ * some helper macros (NETMAP_ROFFSET, NETMAP_WOFFSET and NETMAP_BUF_OFFSET).
+ *
+ * For RX rings, the user writes the offset o in an empty slot before passing
+ * it to netmap; then, netmap will write the incoming packet at an offset o' >=
+ * o in the buffer. o' may be larger than o because of, e.g., alignment
+ * constrains.  If o' > o netmap will also update the offset field in the slot.
+ * Note that large offsets may cause the port to split the packet over several
+ * slots, setting the NS_MOREFRAG flag accordingly.
+ *
+ * For TX rings, the user may prepare the packet to send at an offset o into
+ * the buffer and write o in the offset field. Netmap will send the packets
+ * starting o bytes in the buffer. Note that the address of the packet must
+ * comply with any alignment constraints that the port may have, or the result
+ * will be undefined. The user may read the alignment constraint in the new
+ * ring->buf_align field.  It is also possibile that empty slots already come
+ * with a non-zero offset o specified in the offset field. In this case, the
+ * user will have to write the packet at an offset o' >= o.
+ *
+ * The user must also declare the @maxoff offset that she is going to use. Any
+ * offset larger than this will be truncated.
+ *
+ * The user may also declare a @mingap (ignored if zero) if she plans to use
+ * offsets to share the same buffer among several slots. Netmap will guarantee
+ * that it will never write more than @mingap bytes for each slot, irrespective
+ * of the buffer lenght.
  */
 int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff,
 		uint64_t bits, uint64_t mingap);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 541d0e16d..6e213ef4a 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -954,12 +954,28 @@ struct nmreq_opt_csb {
 	uint64_t		csb_ktoa;
 };
 
+/* option NETMAP_REQ_OPT_OFFSETS */
 struct nmreq_opt_offsets {
 	struct nmreq_option	nro_opt;
+	/* the user must declare the maximum offset value that she is
+	 * going to put into the offset slot-fields. Any larger value
+	 * found at runtime will be cropped. On output the (possibly
+	 * higher) effective max value is returned.
+	 */
 	uint64_t		nro_max_offset;
+	/* optional initial offset value, to be set in all slots. */
 	uint64_t		nro_initial_offset;
+	/* number of bits in the lower part of the 'ptr' field to be
+	 * used as the offset field. On output the (possibily larger)
+	 * effective number of bits is returned.
+	 * 0 means: use the whole ptr field.
+	 */
 	uint32_t		nro_offset_bits;
+	/* required alignment for the beginning of the packets
+	 * (base of the buffer plus offset) in the TX slots.
+	 */
 	uint32_t		nro_tx_align;
+	/* Reserved: set to zero. */
 	uint64_t		nro_min_gap;
 };
 
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index eb9415501..035b11e74 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -123,13 +123,18 @@
 	( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
 		(ring)->nr_buf_size )
 
+/* read the offset field in a ring's slot */
 #define NETMAP_ROFFSET(ring, slot)			\
 	((slot)->ptr & (ring)->offset_mask)
 
+/* update the offset field in a ring's slot */
 #define NETMAP_WOFFSET(ring, slot, offset)		\
 	do { (slot)->ptr = ((slot)->ptr & ~(ring)->offset_mask) | \
 		((offset) & (ring)->offset_mask) } while (0)
 
+/* obtain the start of the buffer pointed to by  a ring's slot, taking the
+ * offset field into accout
+ */
 #define NETMAP_BUF_OFFSET(ring, slot)			\
 	(NETMAP_BUF(ring, (slot)->buf_idx) + NETMAP_ROFFSET(ring, slot))
 

From 9e02e95ea10a8c61c36faa409f4bd79227a84947 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 8 May 2020 19:04:22 +0200
Subject: [PATCH 1801/2207] libnetmap: cleanup for offset option

---
 libnetmap/nmport.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index c1c206c92..a4fd6bb92 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -216,16 +216,41 @@ nmport_extmem_getinfo(struct nmport_d *d)
 	return &d->extmem->nro_info;
 }
 
+struct nmport_offset_cleanup_d {
+	struct nmport_cleanup_d up;
+	struct nmreq_opt_offsets *opt;
+};
+
+static void
+nmport_offset_cleanup(struct nmport_cleanup_d *c,
+		struct nmport_d *d)
+{
+	struct nmport_offset_cleanup_d *cc =
+		(struct nmport_offset_cleanup_d *)c;
+
+	nmreq_remove_option(&d->hdr, cc->opt);
+	nmctx_free(d->ctx, cc->opt);
+}
+
 int
 nmport_offset(struct nmport_d *d, uint64_t initial,
 		uint64_t maxoff, uint64_t bits, uint64_t mingap)
 {
 	struct nmctx *ctx = d->ctx;
 	struct nmreq_opt_offsets *opt;
+	struct nmport_offset_cleanup_d *clnup = NULL;
+
+	clnup = nmctx_malloc(ctx, sizeof(*clnup));
+	if (clnup == NULL) {
+		nmctx_ferror(ctx, "cannot allocate cleanup descriptor");
+		errno = ENOMEM;
+		return -1;
+	}
 
 	opt = nmctx_malloc(ctx, sizeof(*opt));
 	if (opt == NULL) {
 		nmctx_ferror(ctx, "%s: cannot allocate offset option", d->hdr.nr_name);
+		nmctx_free(ctx, clnup);
 		errno = ENOMEM;
 		return -1;
 	}
@@ -236,6 +261,11 @@ nmport_offset(struct nmport_d *d, uint64_t initial,
 	opt->nro_max_offset = maxoff;
 	opt->nro_min_gap = mingap;
 	nmreq_push_option(&d->hdr, &opt->nro_opt);
+
+	clnup->up.cleanup = nmport_offset_cleanup;
+	clnup->opt = opt;
+	nmport_push_cleanup(d, clnup);
+
 	return 0;
 }
 

From ac4640886b1b062c7deb187f80cea76fff81e23b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 11:49:32 +0200
Subject: [PATCH 1802/2207] libnetmap: fix warnings

---
 libnetmap/nmport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index a4fd6bb92..3b7bbea14 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -228,7 +228,7 @@ nmport_offset_cleanup(struct nmport_cleanup_d *c,
 	struct nmport_offset_cleanup_d *cc =
 		(struct nmport_offset_cleanup_d *)c;
 
-	nmreq_remove_option(&d->hdr, cc->opt);
+	nmreq_remove_option(&d->hdr, &cc->opt->nro_opt);
 	nmctx_free(d->ctx, cc->opt);
 }
 
@@ -264,7 +264,7 @@ nmport_offset(struct nmport_d *d, uint64_t initial,
 
 	clnup->up.cleanup = nmport_offset_cleanup;
 	clnup->opt = opt;
-	nmport_push_cleanup(d, clnup);
+	nmport_push_cleanup(d, &clnup->up);
 
 	return 0;
 }

From a05d422ade612dab7b607527b4809b889d05e7f7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 15:24:17 +0200
Subject: [PATCH 1803/2207] brwap: fix ring usage counters

---
 sys/dev/netmap/netmap_bdg.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index b69bdb4f0..77f99b972 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1250,12 +1250,6 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		hwna->na_lut.objtotal = 0;
 		hwna->na_lut.objsize = 0;
 
-		/* pass ownership of the netmap rings to the hwna */
-		for_rx_tx(t) {
-			for (i = 0; i < netmap_all_rings(na, t); i++) {
-				NMR(na, t)[i]->ring = NULL;
-			}
-		}
 		/* reset the number of host rings to default */
 		for_rx_tx(t) {
 			nma_set_host_nrings(hwna, t, 1);
@@ -1310,10 +1304,13 @@ netmap_bwrap_krings_create_common(struct netmap_adapter *na)
 		return error;
 	}
 
-	/* increment the usage counter for all the hwna krings */
+	/* increment the usage counter for all the hwna and na krings */
 	for_rx_tx(t) {
 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users++;
+			/* this to prevent deleation of the rings through
+			 * our krings, instead of through the hwna ones */
+			NMR(na, t)[i]->users++;
 		}
 	}
 
@@ -1355,6 +1352,7 @@ netmap_bwrap_krings_create_common(struct netmap_adapter *na)
 	for_rx_tx(t) {
 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users--;
+			NMR(na, t)[i]->users--;
 		}
 	}
 	hwna->nm_krings_delete(hwna);
@@ -1377,6 +1375,7 @@ netmap_bwrap_krings_delete_common(struct netmap_adapter *na)
 	for_rx_tx(t) {
 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users--;
+			NMR(na, t)[i]->users--;
 		}
 	}
 

From 58344d8d6bc12a22c0c9fa7f63f496ecb69a22d4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 17:01:41 +0200
Subject: [PATCH 1804/2207] libnetmap: recognize offset option in
 nmreq_option_name

---
 libnetmap/nmreq.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index 26a395cea..f9a767cd5 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -620,6 +620,8 @@ nmreq_option_name(uint32_t nro_reqtype)
 		return "csb";
 	case NETMAP_REQ_OPT_SYNC_KLOOP_MODE:
 		return "sync-kloop-mode";
+	case NETMAP_REQ_OPT_OFFSETS:
+		return "offsets";
 	default:
 		return "unknown";
 	}

From ef1bc0524829c16ad893ce682d3e06e8f3290281 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 18:23:11 +0200
Subject: [PATCH 1805/2207] null: advertise offset support

---
 sys/dev/netmap/netmap_null.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index e880304e7..c91afdb55 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -151,6 +151,7 @@ netmap_get_null_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	nna->up.num_rx_rings = req->nr_rx_rings;
 	nna->up.num_tx_desc = req->nr_tx_slots;
 	nna->up.num_rx_desc = req->nr_rx_slots;
+	nna->up.na_flags = NAF_OFFSETS;
 	error = netmap_attach_common(&nna->up);
 	if (error)
 		goto free_nna;

From fb6763c717572679d3f19bed4f34dee9f08d06f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 18:02:50 +0200
Subject: [PATCH 1806/2207] mem: slightly generalize finalize and deref

---
 sys/dev/netmap/netmap_mem2.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index fe49781dc..e9e1bd8c1 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -146,8 +146,8 @@ struct netmap_mem_ops {
 
 	vm_paddr_t (*nmd_ofstophys)(struct netmap_mem_d *, vm_ooffset_t);
 	int (*nmd_config)(struct netmap_mem_d *);
-	int (*nmd_finalize)(struct netmap_mem_d *);
-	void (*nmd_deref)(struct netmap_mem_d *);
+	int (*nmd_finalize)(struct netmap_mem_d *, struct netmap_adapter *);
+	void (*nmd_deref)(struct netmap_mem_d *, struct netmap_adapter *);
 	ssize_t  (*nmd_if_offset)(struct netmap_mem_d *, const void *vaddr);
 	void (*nmd_delete)(struct netmap_mem_d *);
 
@@ -370,7 +370,7 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 
 	nmd->active++;
 
-	nmd->lasterr = nmd->ops->nmd_finalize(nmd);
+	nmd->lasterr = nmd->ops->nmd_finalize(nmd, na);
 
 	if (!nmd->lasterr && na->pdev) {
 		nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
@@ -487,7 +487,7 @@ netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 		 */
 		netmap_mem_init_bitmaps(nmd);
 	}
-	nmd->ops->nmd_deref(nmd);
+	nmd->ops->nmd_deref(nmd, na);
 
 	nmd->active--;
 	if (last_user) {
@@ -1805,7 +1805,7 @@ netmap_mem2_config(struct netmap_mem_d *nmd)
 }
 
 static int
-netmap_mem2_finalize(struct netmap_mem_d *nmd)
+netmap_mem2_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	if (nmd->flags & NETMAP_MEM_FINALIZED)
 		goto out;
@@ -2066,7 +2066,7 @@ netmap_mem2_if_delete(struct netmap_mem_d *nmd,
 }
 
 static void
-netmap_mem2_deref(struct netmap_mem_d *nmd)
+netmap_mem2_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 
 	if (netmap_debug & NM_DEBUG_MEM)
@@ -2518,7 +2518,7 @@ netmap_mem_pt_guest_config(struct netmap_mem_d *nmd)
 }
 
 static int
-netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
+netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 	uint64_t mem_size;
@@ -2591,7 +2591,7 @@ netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd)
 }
 
 static void
-netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd)
+netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 

From 6195b6dea4ccc933b0caaa3cf9a3cd196ee17592 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 18:10:29 +0200
Subject: [PATCH 1807/2207] mem: add flag to skip buffer (un)mapping

---
 sys/dev/netmap/netmap_mem2.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index e9e1bd8c1..5fc623514 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -168,6 +168,7 @@ struct netmap_mem_d {
 	u_int flags;
 #define NETMAP_MEM_FINALIZED	0x1	/* preallocation done */
 #define NETMAP_MEM_HIDDEN	0x8	/* beeing prepared */
+#define NETMAP_MEM_NOMAP	0x10	/* do not map/unmap pdevs */
 	int lasterr;		/* last error for curr config */
 	int active;		/* active users */
 	int refcount;
@@ -372,7 +373,7 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 
 	nmd->lasterr = nmd->ops->nmd_finalize(nmd, na);
 
-	if (!nmd->lasterr && na->pdev) {
+	if (!nmd->lasterr && !(nmd->flags & NETMAP_MEM_NOMAP)) {
 		nmd->lasterr = netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na);
 	}
 
@@ -476,7 +477,7 @@ netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	int last_user = 0;
 	NMA_LOCK(nmd);
-	if (na->active_fds <= 0)
+	if (na->active_fds <= 0 && !(nmd->flags & NETMAP_MEM_NOMAP))
 		netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na);
 	if (nmd->active == 1) {
 		last_user = 1;
@@ -1547,7 +1548,7 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	nm_prerr("unsupported on Windows");
 #else /* linux */
 	nm_prdis("unmapping and freeing plut for %s", na->name);
-	if (lut->plut == NULL)
+	if (lut->plut == NULL || na->pdev == NULL)
 		return 0;
 	for (i = 0; i < lim; i += p->_clustentries) {
 		if (lut->plut[i].paddr)

From 83271a9de9781019103e0ef9a88ce9a842a0180e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 9 May 2020 18:19:45 +0200
Subject: [PATCH 1808/2207] mem: add functions for (un)needed rings tests

---
 sys/dev/netmap/netmap_mem2.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 5fc623514..733f89c7f 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1858,6 +1858,22 @@ netmap_mem_fini(void)
 	netmap_mem_put(&nm_mem);
 }
 
+static int
+netmap_mem_ring_needed(struct netmap_kring *kring)
+{
+	return kring->ring == NULL &&
+		(kring->users > 0 ||
+		 (kring->nr_kflags & NKR_NEEDRING));
+}
+
+static int
+netmap_mem_ring_todelete(struct netmap_kring *kring)
+{
+	return kring->ring != NULL &&
+		kring->users == 0 &&
+		!(kring->nr_kflags & NKR_NEEDRING);
+}
+
 
 /* call with NMA_LOCK held *
  *
@@ -1879,7 +1895,7 @@ netmap_mem2_rings_create(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 			struct netmap_ring *ring = kring->ring;
 			u_int len, ndesc;
 
-			if (ring || (!kring->users && !(kring->nr_kflags & NKR_NEEDRING))) {
+			if (!netmap_mem_ring_needed(kring)) {
 				/* uneeded, or already created by somebody else */
 				if (netmap_debug & NM_DEBUG_MEM)
 					nm_prinf("NOT creating ring %s (ring %p, users %d neekring %d)",
@@ -1956,7 +1972,7 @@ netmap_mem2_rings_delete(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 			struct netmap_kring *kring = NMR(na, t)[i];
 			struct netmap_ring *ring = kring->ring;
 
-			if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) {
+			if (!netmap_mem_ring_todelete(kring)) {
 				if (netmap_debug & NM_DEBUG_MEM)
 					nm_prinf("NOT deleting ring %s (ring %p, users %d neekring %d)",
 						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);

From 431c09e4dd5dbe29414131033a7208e86b88614b Mon Sep 17 00:00:00 2001
From: Josh Blum 
Date: Fri, 22 May 2020 08:49:09 -0500
Subject: [PATCH 1809/2207] fix NETMAP_WOFFSET missing semicolon

---
 sys/net/netmap_user.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 035b11e74..098dc52aa 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -130,7 +130,7 @@
 /* update the offset field in a ring's slot */
 #define NETMAP_WOFFSET(ring, slot, offset)		\
 	do { (slot)->ptr = ((slot)->ptr & ~(ring)->offset_mask) | \
-		((offset) & (ring)->offset_mask) } while (0)
+		((offset) & (ring)->offset_mask); } while (0)
 
 /* obtain the start of the buffer pointed to by  a ring's slot, taking the
  * offset field into accout

From c59790b6a4d8d7a7c32cf12ac85a0d3cc8173010 Mon Sep 17 00:00:00 2001
From: Josh Blum 
Date: Fri, 22 May 2020 09:16:40 -0500
Subject: [PATCH 1810/2207] libnetmap: fix doc typos

---
 libnetmap/libnetmap.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index c3361a8d6..ec1458fbe 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -252,11 +252,11 @@ int nmport_inject(struct nmport_d *d, const void *buf, size_t size);
  * The relation among the functions is as follows:
  *
  *				   |nmport_new
- * 		|nport_prepare	 = |
+ * 		|nmport_prepare	 = |
  *		|		   |nmport_parse
  * nmport_open =|
  *		|		   |nmport_register
- *		|nport_open_desc = |
+ *		|nmport_open_desc =|
  *				   |nmport_mmap
  *
  */
@@ -449,7 +449,7 @@ struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
  * The user may also declare a @mingap (ignored if zero) if she plans to use
  * offsets to share the same buffer among several slots. Netmap will guarantee
  * that it will never write more than @mingap bytes for each slot, irrespective
- * of the buffer lenght.
+ * of the buffer length.
  */
 int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff,
 		uint64_t bits, uint64_t mingap);

From 21c866b4192b1befcdc665fad4785dd2d4469457 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 16:31:40 +0200
Subject: [PATCH 1811/2207] linux/e1000e: patch for Intel 3.8.4 version

---
 LINUX/final-patches/intel--e1000e--3.8.4 | 91 ++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.8.4

diff --git a/LINUX/final-patches/intel--e1000e--3.8.4 b/LINUX/final-patches/intel--e1000e--3.8.4
new file mode 100644
index 000000000..d135f82f7
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.8.4
@@ -0,0 +1,91 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index 9af58b1..8cd5edb 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -36,7 +36,7 @@ e1000e-y += kcompat.o
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := e1000e
++DRIVER := e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index bfd9dc8..b7e91da 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -483,6 +483,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1013,6 +1017,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1330,6 +1345,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4263,6 +4283,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8735,6 +8759,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8831,6 +8859,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 4fb6e9990aa3e7d843af3958f21ba69a67528414 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 16:32:18 +0200
Subject: [PATCH 1812/2207] linux/i40e: patch for Intel 2.11.25 version

---
 LINUX/final-patches/intel--i40e--2.11.25 | 156 +++++++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.11.25

diff --git a/LINUX/final-patches/intel--i40e--2.11.25 b/LINUX/final-patches/intel--i40e--2.11.25
new file mode 100644
index 000000000..766dbefa7
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.11.25
@@ -0,0 +1,156 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 81f5ab9..85bfb8c 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index b67de06..59f1044 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -146,6 +146,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3539,6 +3544,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3620,6 +3629,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -13959,6 +13973,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14331,6 +14350,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 96bc531..106f9b7 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2559,6 +2568,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From ac83dae2779a996165c37ad4b85fd0f0a9b3dbe9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 16:32:26 +0200
Subject: [PATCH 1813/2207] linux/i40e: patch for Intel 2.11.29 version

---
 LINUX/final-patches/intel--i40e--2.11.29 | 157 +++++++++++++++++++++++
 1 file changed, 157 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.11.29

diff --git a/LINUX/final-patches/intel--i40e--2.11.29 b/LINUX/final-patches/intel--i40e--2.11.29
new file mode 100644
index 000000000..ea0fe64be
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.11.29
@@ -0,0 +1,157 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 81f5ab9..85bfb8c 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 7ad12f4..a6ef9c4 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -147,6 +147,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3555,6 +3560,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3636,6 +3645,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -14000,6 +14014,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14372,6 +14392,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 96bc531..106f9b7 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -784,6 +788,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2559,6 +2568,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
++
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
+ 		struct i40e_rx_buffer *rx_buffer;
+ 		union i40e_rx_desc *rx_desc;

From 4c7b1eb85479438f3817f85852a032609f80aea1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 16:35:08 +0200
Subject: [PATCH 1814/2207] linux/igb: patch for Intel 5.3.5.61 version

---
 LINUX/final-patches/intel--igb--5.3.5.61 | 138 +++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.5.61

diff --git a/LINUX/final-patches/intel--igb--5.3.5.61 b/LINUX/final-patches/intel--igb--5.3.5.61
new file mode 100644
index 000000000..b36da908e
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.5.61
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 811a634..2559d39 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 12826ba..9288205 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3203,6 +3207,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3408,6 +3416,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3820,6 +3832,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7505,6 +7520,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8521,6 +8541,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8840,6 +8865,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From c8b1301a19a86667856fee8ec8a598d44d1df293 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 16:35:09 +0200
Subject: [PATCH 1815/2207] linux/ixgbe: patch for Intel 5.7.1 version

---
 LINUX/final-patches/intel--ixgbe--5.7.1 | 173 ++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.7.1

diff --git a/LINUX/final-patches/intel--ixgbe--5.7.1 b/LINUX/final-patches/intel--ixgbe--5.7.1
new file mode 100644
index 000000000..19a4b74d9
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.7.1
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 01e67d7..91f53e1 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index f6eb944..c44e8bc 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -711,6 +711,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -730,6 +747,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2200,6 +2228,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3661,6 +3699,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4337,6 +4379,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12916,6 +12964,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12971,6 +13023,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From a2daa3d9e7a42431569c263010e1871b9e56dadf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 16:35:09 +0200
Subject: [PATCH 1816/2207] linux/ixgbevf: patch for Intel 4.7.1 version

---
 LINUX/final-patches/intel--ixgbevf--4.7.1 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.7.1

diff --git a/LINUX/final-patches/intel--ixgbevf--4.7.1 b/LINUX/final-patches/intel--ixgbevf--4.7.1
new file mode 100644
index 000000000..834fc1edc
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.7.1
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index dc49435..103a5d1 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index e74af0d..72f1225 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -343,6 +343,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -363,6 +380,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2066,6 +2104,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2300,6 +2342,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5599,8 +5645,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5641,6 +5689,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 503b058..7642a11 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 979849be071c7e0705f071ae2a1d49aaa1740db2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 19:44:59 +0200
Subject: [PATCH 1817/2207] linux/i40e: remove unused variable

---
 LINUX/i40e_netmap_linux.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 6e565f76b..abcef9116 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -230,7 +230,6 @@ i40e_netmap_reg(struct netmap_adapter *na, int onoff)
 static int
 i40e_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct netmap_adapter *na = kring->na;
 	uint64_t incr;
 
 	kring->buf_align = 0;

From 507906da28476f068e1964e3ed92e1d80875db30 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 20:09:50 +0200
Subject: [PATCH 1818/2207] linux/i40e: fix warning in 2.11.* patches

---
 LINUX/final-patches/intel--i40e--2.11.21 | 15 +++++++--------
 LINUX/final-patches/intel--i40e--2.11.25 | 15 +++++++--------
 LINUX/final-patches/intel--i40e--2.11.29 | 15 +++++++--------
 3 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/LINUX/final-patches/intel--i40e--2.11.21 b/LINUX/final-patches/intel--i40e--2.11.21
index e9823dcad..a27bd9e1a 100644
--- a/LINUX/final-patches/intel--i40e--2.11.21
+++ b/LINUX/final-patches/intel--i40e--2.11.21
@@ -112,7 +112,7 @@ index bd4b467..58e7855 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 96bc531..106f9b7 100644
+index 96bc531..1615a4d 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -138,9 +138,9 @@ index 96bc531..106f9b7 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2559,6 +2568,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -150,7 +150,6 @@ index 96bc531..106f9b7 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.11.25 b/LINUX/final-patches/intel--i40e--2.11.25
index 766dbefa7..308d09699 100644
--- a/LINUX/final-patches/intel--i40e--2.11.25
+++ b/LINUX/final-patches/intel--i40e--2.11.25
@@ -112,7 +112,7 @@ index b67de06..59f1044 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 96bc531..106f9b7 100644
+index 96bc531..1615a4d 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -138,9 +138,9 @@ index 96bc531..106f9b7 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2559,6 +2568,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -150,7 +150,6 @@ index 96bc531..106f9b7 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.11.29 b/LINUX/final-patches/intel--i40e--2.11.29
index ea0fe64be..30ae49a8e 100644
--- a/LINUX/final-patches/intel--i40e--2.11.29
+++ b/LINUX/final-patches/intel--i40e--2.11.29
@@ -113,7 +113,7 @@ index 7ad12f4..a6ef9c4 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 96bc531..106f9b7 100644
+index 96bc531..1615a4d 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -139,9 +139,9 @@ index 96bc531..106f9b7 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2559,6 +2568,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	int dummy, nm_irq;
@@ -151,7 +151,6 @@ index 96bc531..106f9b7 100644
 +	}
 +#endif /* DEV_NETMAP */
 +
-+
- 	while (likely(total_rx_packets < (unsigned int)budget)) {
- 		struct i40e_rx_buffer *rx_buffer;
- 		union i40e_rx_desc *rx_desc;
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From 1a86593d7c4dfc6a893440ada724004cf29db241 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 20:20:19 +0200
Subject: [PATCH 1819/2207] linux/i40e: restore rx-ring preconfig in 2.11.*
 patches

---
 LINUX/final-patches/intel--i40e--2.11.21 | 19 +++++++++++++++----
 LINUX/final-patches/intel--i40e--2.11.25 | 19 +++++++++++++++----
 LINUX/final-patches/intel--i40e--2.11.29 | 19 +++++++++++++++----
 3 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/LINUX/final-patches/intel--i40e--2.11.21 b/LINUX/final-patches/intel--i40e--2.11.21
index a27bd9e1a..3219a3bdd 100644
--- a/LINUX/final-patches/intel--i40e--2.11.21
+++ b/LINUX/final-patches/intel--i40e--2.11.21
@@ -48,7 +48,7 @@ index 81f5ab9..85bfb8c 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index bd4b467..58e7855 100644
+index bd4b467..3e461eb 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -146,6 +146,11 @@ bool i40e_is_l4mode_enabled(void)
@@ -74,7 +74,18 @@ index bd4b467..58e7855 100644
  	return 0;
  }
  
-@@ -3620,6 +3629,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3592,6 +3601,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3620,6 +3633,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index bd4b467..58e7855 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -13959,6 +13973,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -13959,6 +13977,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index bd4b467..58e7855 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -14331,6 +14350,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -14331,6 +14354,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.11.25 b/LINUX/final-patches/intel--i40e--2.11.25
index 308d09699..d5fa6d98c 100644
--- a/LINUX/final-patches/intel--i40e--2.11.25
+++ b/LINUX/final-patches/intel--i40e--2.11.25
@@ -48,7 +48,7 @@ index 81f5ab9..85bfb8c 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index b67de06..59f1044 100644
+index b67de06..ce19f27 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -146,6 +146,11 @@ bool i40e_is_l4mode_enabled(void)
@@ -74,7 +74,18 @@ index b67de06..59f1044 100644
  	return 0;
  }
  
-@@ -3620,6 +3629,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3592,6 +3601,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3620,6 +3633,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index b67de06..59f1044 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -13959,6 +13973,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -13959,6 +13977,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -98,7 +109,7 @@ index b67de06..59f1044 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -14331,6 +14350,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -14331,6 +14354,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}
diff --git a/LINUX/final-patches/intel--i40e--2.11.29 b/LINUX/final-patches/intel--i40e--2.11.29
index 30ae49a8e..2b5dddbdb 100644
--- a/LINUX/final-patches/intel--i40e--2.11.29
+++ b/LINUX/final-patches/intel--i40e--2.11.29
@@ -48,7 +48,7 @@ index 81f5ab9..85bfb8c 100644
  clean:
  	@+$(call kernelbuild,clean)
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 7ad12f4..a6ef9c4 100644
+index 7ad12f4..2768a89 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
 @@ -147,6 +147,11 @@ bool i40e_is_l4mode_enabled(void)
@@ -74,7 +74,18 @@ index 7ad12f4..a6ef9c4 100644
  	return 0;
  }
  
-@@ -3636,6 +3645,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -3608,6 +3617,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3636,6 +3649,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -86,7 +97,7 @@ index 7ad12f4..a6ef9c4 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -14000,6 +14014,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -14000,6 +14018,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  	}
  
  	set_bit(__I40E_VSI_RELEASING, vsi->state);
@@ -99,7 +110,7 @@ index 7ad12f4..a6ef9c4 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -14372,6 +14392,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -14372,6 +14396,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  	    (vsi->type == I40E_VSI_VMDQ2)) {
  		ret = i40e_vsi_config_rss(vsi);
  	}

From 2259dc2a66eb7110c609cd61c421b3955fd80f24 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 May 2020 20:38:44 +0200
Subject: [PATCH 1820/2207] linux/ixgbe: remove unused variables

---
 LINUX/ixgbe_netmap_linux.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index d7bf60d15..935e2ed17 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -865,9 +865,6 @@ ixgbe_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 static int
 ixgbe_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
-
 	kring->buf_align = 0;
 
 	if (kring->tx == NR_TX) {

From e2b6bd267bab38d44c1cbca757ea645f1bb5a0b9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 May 2020 15:29:15 +0200
Subject: [PATCH 1821/2207] linux/ixgbe: fix warnings in 5.[67].* patches

---
 LINUX/final-patches/intel--ixgbe--5.6.1 | 16 ++++++++--------
 LINUX/final-patches/intel--ixgbe--5.6.3 | 16 ++++++++--------
 LINUX/final-patches/intel--ixgbe--5.6.5 | 16 ++++++++--------
 LINUX/final-patches/intel--ixgbe--5.7.1 | 16 ++++++++--------
 4 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/LINUX/final-patches/intel--ixgbe--5.6.1 b/LINUX/final-patches/intel--ixgbe--5.6.1
index 75fc830ed..c5a46c51a 100644
--- a/LINUX/final-patches/intel--ixgbe--5.6.1
+++ b/LINUX/final-patches/intel--ixgbe--5.6.1
@@ -62,7 +62,7 @@ index e613859..8ca5eaa 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index c2bcd19..72bcd0f 100644
+index c2bcd19..ce130fd 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -706,6 +706,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -107,9 +107,9 @@ index c2bcd19..72bcd0f 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2195,6 +2223,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2189,6 +2217,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -121,9 +121,9 @@ index c2bcd19..72bcd0f 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct ixgbe_rx_buffer *rx_buffer;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -3656,6 +3694,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  	memset(ring->tx_buffer_info, 0,
  	       sizeof(struct ixgbe_tx_buffer) * ring->count);
@@ -165,7 +165,7 @@ index c2bcd19..72bcd0f 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.6.3 b/LINUX/final-patches/intel--ixgbe--5.6.3
index 53de6fedb..10c7afaf2 100644
--- a/LINUX/final-patches/intel--ixgbe--5.6.3
+++ b/LINUX/final-patches/intel--ixgbe--5.6.3
@@ -62,7 +62,7 @@ index e613859..8ca5eaa 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index af1af52..2744f7b 100644
+index af1af52..0be976d 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -706,6 +706,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -107,9 +107,9 @@ index af1af52..2744f7b 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2195,6 +2223,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2189,6 +2217,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -121,9 +121,9 @@ index af1af52..2744f7b 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct ixgbe_rx_buffer *rx_buffer;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -3656,6 +3694,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  	memset(ring->tx_buffer_info, 0,
  	       sizeof(struct ixgbe_tx_buffer) * ring->count);
@@ -165,7 +165,7 @@ index af1af52..2744f7b 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.6.5 b/LINUX/final-patches/intel--ixgbe--5.6.5
index 82c2d74dd..69b3443d5 100644
--- a/LINUX/final-patches/intel--ixgbe--5.6.5
+++ b/LINUX/final-patches/intel--ixgbe--5.6.5
@@ -62,7 +62,7 @@ index e613859..8ca5eaa 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index a6971c3..6cee6ed 100644
+index a6971c3..87a4138 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -706,6 +706,23 @@ struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -107,9 +107,9 @@ index a6971c3..6cee6ed 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2195,6 +2223,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2189,6 +2217,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -121,9 +121,9 @@ index a6971c3..6cee6ed 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct ixgbe_rx_buffer *rx_buffer;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -3656,6 +3694,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  	memset(ring->tx_buffer_info, 0,
  	       sizeof(struct ixgbe_tx_buffer) * ring->count);
@@ -165,7 +165,7 @@ index a6971c3..6cee6ed 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS
diff --git a/LINUX/final-patches/intel--ixgbe--5.7.1 b/LINUX/final-patches/intel--ixgbe--5.7.1
index 19a4b74d9..4a523e6bf 100644
--- a/LINUX/final-patches/intel--ixgbe--5.7.1
+++ b/LINUX/final-patches/intel--ixgbe--5.7.1
@@ -62,7 +62,7 @@ index 01e67d7..91f53e1 100644
  clean:
  	@+$(call devkernelbuild,clean)
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index f6eb944..c44e8bc 100644
+index f6eb944..82325f1 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -711,6 +711,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
@@ -107,9 +107,9 @@ index f6eb944..c44e8bc 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2200,6 +2228,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	xdp.rxq = &rx_ring->xdp_rxq;
- #endif
+@@ -2194,6 +2222,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
 +	/*
@@ -121,9 +121,9 @@ index f6eb944..c44e8bc 100644
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
 +
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct ixgbe_rx_buffer *rx_buffer;
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
 @@ -3661,6 +3699,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  	memset(ring->tx_buffer_info, 0,
  	       sizeof(struct ixgbe_tx_buffer) * ring->count);
@@ -165,7 +165,7 @@ index f6eb944..c44e8bc 100644
  	netdev = adapter->netdev;
 +
 +#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
++	ixgbe_netmap_detach(adapter);
 +#endif /* DEV_NETMAP */
 +
  #ifdef HAVE_IXGBE_DEBUG_FS

From bc8e67761c21167650704cd7f774a5197f019b80 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 May 2020 17:04:04 +0200
Subject: [PATCH 1822/2207] linux/igb: fix error in Intel makefile

---
 LINUX/default-config.mak.in_ | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 17a7766e5..3798a9ce3 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -62,7 +62,6 @@ define intel_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sourceforge.net/projects/e1000/files/$(1)%20stable/$(2)/$(1)-$(2).tar.gz -P @SRCDIR@/ext-drivers/
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
-$(1)@prepare	:=
 $(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 $(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 $(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
@@ -75,10 +74,11 @@ define default
 $(1)@v := $(if $($(1)@v),$($(1)@v),$(2))
 endef
 
-# some additional, driver-specific CFLAGS (used in the @build variable above)
+# some additional, driver-specific CFLAGS (used in the @build variable above) and fixes
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/igb-fix.sh,)
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))
@@ -90,6 +90,7 @@ $(eval $(call default,i40e,2.4.6))
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 
+
 define mellanox_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz || wget http://content.mellanox.com/ofed/MLNX_EN-$(2)/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz -P @SRCDIR@/ext-drivers
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz && tar xf mlnx-en-$(2)-ubuntu18.04-x86_64/src/MLNX_EN_SRC-$(2).tgz && tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)

From 5f68c51b36d8758c988bea62b5e7865f7acac5f1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 May 2020 17:12:01 +0200
Subject: [PATCH 1823/2207] linux/e1000e: fix error in Intel makefile

---
 LINUX/default-config.mak.in_ |  3 ++-
 LINUX/intel-fix.sh           | 16 ++++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)
 create mode 100755 LINUX/intel-fix.sh

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 3798a9ce3..892b38839 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -78,7 +78,8 @@ endef
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
-igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/igb-fix.sh,)
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/intel-fix.sh igb,)
+e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))
diff --git a/LINUX/intel-fix.sh b/LINUX/intel-fix.sh
new file mode 100755
index 000000000..276eb4d74
--- /dev/null
+++ b/LINUX/intel-fix.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+cd $1
+patch -p1 <
Date: Sat, 23 May 2020 17:13:02 +0200
Subject: [PATCH 1824/2207] linux/e1000e: remove unused variable

---
 LINUX/if_e1000e_netmap.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index a7213683e..455f28a14 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -144,7 +144,6 @@ e1000e_netmap_get_rctl(uint32_t bufsize)
 static int
 e1000e_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct netmap_adapter *na = kring->na;
 	uint64_t bufsz;
 	struct e1000e_netmap_szdesc *sz;
 

From 535174635d5e0d7bd79342a1f5b26c35e6f5987e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 May 2020 17:20:02 +0200
Subject: [PATCH 1825/2207] linux/ixgbevf: fix error in Intel makefile

---
 LINUX/default-config.mak.in_ | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 892b38839..9f5490014 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -80,6 +80,7 @@ igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))

From e5b0b8a8cc81a76fc2f34418e50a742bed382883 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 May 2020 17:32:52 +0200
Subject: [PATCH 1826/2207] linux/e1000e: obey netmap-suffix in recent patches

---
 LINUX/final-patches/intel--e1000e--3.6.0      | 32 +++++++++++++++++--
 LINUX/final-patches/intel--e1000e--3.8.4      | 32 +++++++++++++++++--
 .../final-patches/intel--e1000e--netmap-3.6.0 |  0
 3 files changed, 60 insertions(+), 4 deletions(-)
 create mode 100644 LINUX/final-patches/intel--e1000e--netmap-3.6.0

diff --git a/LINUX/final-patches/intel--e1000e--3.6.0 b/LINUX/final-patches/intel--e1000e--3.6.0
index 7467099b4..f89d82778 100644
--- a/LINUX/final-patches/intel--e1000e--3.6.0
+++ b/LINUX/final-patches/intel--e1000e--3.6.0
@@ -1,8 +1,36 @@
 diff --git a/e1000e/Makefile b/e1000e/Makefile
-index f300712..d8ca5dd 100644
+index f300712..01c2de9 100644
 --- a/e1000e/Makefile
 +++ b/e1000e/Makefile
-@@ -36,7 +36,7 @@ e1000e-y += kcompat.o
+@@ -9,9 +9,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the @SUMMARY@
+ #
+ 
+-obj-$(CONFIG_E1000E) += e1000e.o
++obj-$(CONFIG_E1000E) += e1000e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define e1000e-y
++define e1000e$(NETMAP_DRIVER_SUFFIX)-y
+ 	netdev.o
+ 	ethtool.o
+ 	ich8lan.o
+@@ -23,20 +23,20 @@ define e1000e-y
+ 	82571.o
+ 	param.o
+ endef
+-e1000e-y := $(strip ${e1000e-y})
++e1000e$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${e1000e$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+ #ifdef BUILD_PTP_SUPPORT
+-e1000e-$(CONFIG_PTP_1588_CLOCK:m=y) += ptp.o
++e1000e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ptp.o
+ #endif
+ 
+ #ifndef REMOVE_COMPAT
+ 
+-e1000e-y += kcompat.o
++e1000e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile
  
diff --git a/LINUX/final-patches/intel--e1000e--3.8.4 b/LINUX/final-patches/intel--e1000e--3.8.4
index d135f82f7..e2595db82 100644
--- a/LINUX/final-patches/intel--e1000e--3.8.4
+++ b/LINUX/final-patches/intel--e1000e--3.8.4
@@ -1,8 +1,36 @@
 diff --git a/e1000e/Makefile b/e1000e/Makefile
-index 9af58b1..8cd5edb 100644
+index 9af58b1..00ca1e8 100644
 --- a/e1000e/Makefile
 +++ b/e1000e/Makefile
-@@ -36,7 +36,7 @@ e1000e-y += kcompat.o
+@@ -9,9 +9,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the @SUMMARY@
+ #
+ 
+-obj-$(CONFIG_E1000E) += e1000e.o
++obj-$(CONFIG_E1000E) += e1000e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define e1000e-y
++define e1000e$(NETMAP_DRIVER_SUFFIX)-y
+ 	netdev.o
+ 	ethtool.o
+ 	ich8lan.o
+@@ -23,20 +23,20 @@ define e1000e-y
+ 	82571.o
+ 	param.o
+ endef
+-e1000e-y := $(strip ${e1000e-y})
++e1000e$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${e1000e$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+ #ifdef BUILD_PTP_SUPPORT
+-e1000e-$(CONFIG_PTP_1588_CLOCK:m=y) += ptp.o
++e1000e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ptp.o
+ #endif
+ 
+ #ifndef REMOVE_COMPAT
+ 
+-e1000e-y += kcompat.o
++e1000e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile
  
diff --git a/LINUX/final-patches/intel--e1000e--netmap-3.6.0 b/LINUX/final-patches/intel--e1000e--netmap-3.6.0
new file mode 100644
index 000000000..e69de29bb

From d3784d3f63b4734d44ca357322a4f848e72afdbd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Jun 2020 19:21:06 +0000
Subject: [PATCH 1827/2207] FreeBSD: fix compilation

---
 sys/dev/netmap/netmap.c         | 24 ++++++++++++++----------
 sys/dev/netmap/netmap_freebsd.c |  2 +-
 sys/dev/netmap/netmap_kern.h    | 11 +++++++++++
 sys/dev/netmap/netmap_pipe.c    |  4 ++--
 4 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5998b6a50..c1fd7db26 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2267,7 +2267,8 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	if (bits > maxbits) {
 		if (netmap_verbose)
 			nm_prerr("bits: %llu too large (max %llu)",
-				bits, maxbits);
+				(unsigned long long)bits,
+				(unsigned long long)maxbits);
 		error = EINVAL;
 		goto out;
 	}
@@ -2282,21 +2283,23 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 	if (max_offset > NETMAP_BUF_SIZE(na)) {
 		if (netmap_verbose)
 			nm_prerr("max offset %llu > buf size %u",
-				max_offset, NETMAP_BUF_SIZE(na));
+				(unsigned long long)max_offset, NETMAP_BUF_SIZE(na));
 		error = EINVAL;
 		goto out;
 	}
 	if ((max_offset & mask) != max_offset) {
 		if (netmap_verbose)
 			nm_prerr("max offset %llu to large for %llu bits",
-				max_offset, bits);
+				(unsigned long long)max_offset,
+				(unsigned long long)bits);
 		error = EINVAL;
 		goto out;
 	}
 	if (initial_offset > max_offset) {
 		if (netmap_verbose)
 			nm_prerr("initial offset %llu > max offset %llu",
-				initial_offset, max_offset);
+				(unsigned long long)initial_offset,
+				(unsigned long long)max_offset);
 		error = EINVAL;
 		goto out;
 	}
@@ -2318,8 +2321,8 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 						 "offset mask and/or max"
 						 "(current: mask=%llx,max=%llu",
 							kring->name,
-							kring->offset_mask,
-							kring->offset_max);
+							(unsigned long long)kring->offset_mask,
+							(unsigned long long)kring->offset_max);
 				error = EBUSY;
 				goto out;
 			}
@@ -2327,7 +2330,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			max_offset = kring->offset_max;
 		} else {
 			kring->offset_mask = mask;
-			*(uint64_t *)&ring->offset_mask = mask;
+			*(uint64_t *)(uintptr_t)&ring->offset_mask = mask;
 			kring->offset_max = max_offset;
 			kring->offset_gap = min_gap;
 		}
@@ -2386,7 +2389,7 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 
 		if (mtu) {
 			maxframe = mtu + ETH_HLEN +
-				ETH_FCS_LEN + 4; /* VLAN_HLEN */
+				ETH_FCS_LEN + VLAN_HLEN;
 			if (maxframe < target) {
 				target = kring->offset_gap;
 			}
@@ -2396,7 +2399,7 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 		if (error)
 			goto out;
 
-		*(uint64_t *)&kring->ring->buf_align = kring->buf_align;
+		*(uint64_t *)(uintptr_t)&kring->ring->buf_align = kring->buf_align;
 
 		if (mtu && t == NR_RX && kring->hwbuf_len < mtu) {
 			if (!(na->na_flags & NAF_MOREFRAG)) {
@@ -2411,7 +2414,8 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 					 "%s needs to support "
 					 "NS_MOREFRAG "
 					 "(MTU=%u,buf_size=%llu)",
-					 kring->name, mtu, kring->hwbuf_len);
+					 kring->name, mtu,
+					 (unsigned long long)kring->hwbuf_len);
 			}
 		}
 	}
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 2580144ab..42551df09 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1056,7 +1056,7 @@ netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
 		*mres = page;
 		vm_page_insert(page, object, pidx);
 	}
-	vm_page_valid(page);
+	page->valid = VM_PAGE_BITS_ALL;
 	return (VM_PAGER_OK);
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 3985fd5bd..e0fc2d02b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2493,4 +2493,15 @@ void netmap_uninit_bridges(void);
 #define CSB_WRITE(csb, field, v) (suword32(&csb->field, v))
 #endif /* ! linux */
 
+/* some macros that may not be defined */
+#ifndef ETH_HLEN
+#define ETH_HLEN 6
+#endif
+#ifndef ETH_FCS_LEN
+#define ETH_FCS_LEN 4
+#endif
+#ifndef VLAN_HLEN
+#define VLAN_HLEN 4
+#endif
+
 #endif /* _NET_NETMAP_KERN_H_ */
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 37149d818..a39df1524 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -437,9 +437,9 @@ netmap_pipe_reg_both(struct netmap_adapter *na, struct netmap_adapter *ona)
 				       sizeof(struct netmap_slot) *
 						kring->nkr_num_slots);
 				/* copy the offset-related fields */
-				*(uint64_t *)&kring->pipe->ring->offset_mask =
+				*(uint64_t *)(uintptr_t)&kring->pipe->ring->offset_mask =
 					kring->ring->offset_mask;
-				*(uint64_t *)&kring->pipe->ring->buf_align =
+				*(uint64_t *)(uintptr_t)&kring->pipe->ring->buf_align =
 					kring->ring->buf_align;
 				/* mark both rings as fake and needed,
 				 * so that buffers will not be

From 893e374041626a058bf739679aa6ae38d8227e84 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Wed, 3 Jun 2020 19:34:56 +0200
Subject: [PATCH 1828/2207] align code from FreeBSD-CURRENT

---
 sys/dev/netmap/if_ptnet.c        | 320 ++-----------------------------
 sys/dev/netmap/if_vtnet_netmap.h |  68 ++-----
 sys/dev/netmap/netmap.c          |  12 +-
 sys/dev/netmap/netmap_freebsd.c  |   5 +-
 sys/dev/netmap/netmap_generic.c  |   9 +
 sys/dev/netmap/netmap_kern.h     |   2 +-
 sys/dev/netmap/netmap_vale.c     |   2 +-
 7 files changed, 57 insertions(+), 361 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 468ebabe9..99d21c38f 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -87,6 +87,8 @@
 #include 
 #include 
 
+#ifdef WITH_PTNETMAP
+
 #ifndef INET
 #error "INET not defined, cannot support offloadings"
 #endif
@@ -693,11 +695,12 @@ ptnet_irqs_init(struct ptnet_softc *sc)
 	cpu_cur = CPU_FIRST();
 	for (i = 0; i < nvecs; i++) {
 		struct ptnet_queue *pq = sc->queues + i;
-		static void (*handler)(void *context, int pending);
 
-		handler = (i < sc->num_tx_rings) ? ptnet_tx_task : ptnet_rx_task;
+		if (i < sc->num_tx_rings)
+			TASK_INIT(&pq->task, 0, ptnet_tx_task, pq);
+		else
+			NET_TASK_INIT(&pq->task, 0, ptnet_rx_task, pq);
 
-		TASK_INIT(&pq->task, 0, handler, pq);
 		pq->taskq = taskqueue_create_fast("ptnet_queue", M_NOWAIT,
 					taskqueue_thread_enqueue, &pq->taskq);
 		taskqueue_start_threads(&pq->taskq, 1, PI_NET, "%s-pq-%d",
@@ -1335,150 +1338,6 @@ ptnet_rx_intr(void *opaque)
 	ptnet_rx_eof(pq, PTNET_RX_BUDGET, true);
 }
 
-/* The following offloadings-related functions are taken from the vtnet
- * driver, but the same functionality is required for the ptnet driver.
- * As a temporary solution, I copied this code from vtnet and I started
- * to generalize it (taking away driver-specific statistic accounting),
- * making as little modifications as possible.
- * In the future we need to share these functions between vtnet and ptnet.
- */
-static int
-ptnet_tx_offload_ctx(struct mbuf *m, int *etype, int *proto, int *start)
-{
-	struct ether_vlan_header *evh;
-	int offset;
-
-	evh = mtod(m, struct ether_vlan_header *);
-	if (evh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
-		/* BMV: We should handle nested VLAN tags too. */
-		*etype = ntohs(evh->evl_proto);
-		offset = sizeof(struct ether_vlan_header);
-	} else {
-		*etype = ntohs(evh->evl_encap_proto);
-		offset = sizeof(struct ether_header);
-	}
-
-	switch (*etype) {
-#if defined(INET)
-	case ETHERTYPE_IP: {
-		struct ip *ip, iphdr;
-		if (__predict_false(m->m_len < offset + sizeof(struct ip))) {
-			m_copydata(m, offset, sizeof(struct ip),
-			    (caddr_t) &iphdr);
-			ip = &iphdr;
-		} else
-			ip = (struct ip *)(m->m_data + offset);
-		*proto = ip->ip_p;
-		*start = offset + (ip->ip_hl << 2);
-		break;
-	}
-#endif
-#if defined(INET6)
-	case ETHERTYPE_IPV6:
-		*proto = -1;
-		*start = ip6_lasthdr(m, offset, IPPROTO_IPV6, proto);
-		/* Assert the network stack sent us a valid packet. */
-		KASSERT(*start > offset,
-		    ("%s: mbuf %p start %d offset %d proto %d", __func__, m,
-		    *start, offset, *proto));
-		break;
-#endif
-	default:
-		/* Here we should increment the tx_csum_bad_ethtype counter. */
-		return (EINVAL);
-	}
-
-	return (0);
-}
-
-static int
-ptnet_tx_offload_tso(if_t ifp, struct mbuf *m, int eth_type,
-		     int offset, bool allow_ecn, struct virtio_net_hdr *hdr)
-{
-	static struct timeval lastecn;
-	static int curecn;
-	struct tcphdr *tcp, tcphdr;
-
-	if (__predict_false(m->m_len < offset + sizeof(struct tcphdr))) {
-		m_copydata(m, offset, sizeof(struct tcphdr), (caddr_t) &tcphdr);
-		tcp = &tcphdr;
-	} else
-		tcp = (struct tcphdr *)(m->m_data + offset);
-
-	hdr->hdr_len = offset + (tcp->th_off << 2);
-	hdr->gso_size = m->m_pkthdr.tso_segsz;
-	hdr->gso_type = eth_type == ETHERTYPE_IP ? VIRTIO_NET_HDR_GSO_TCPV4 :
-	    VIRTIO_NET_HDR_GSO_TCPV6;
-
-	if (tcp->th_flags & TH_CWR) {
-		/*
-		 * Drop if VIRTIO_NET_F_HOST_ECN was not negotiated. In FreeBSD,
-		 * ECN support is not on a per-interface basis, but globally via
-		 * the net.inet.tcp.ecn.enable sysctl knob. The default is off.
-		 */
-		if (!allow_ecn) {
-			if (ppsratecheck(&lastecn, &curecn, 1))
-				if_printf(ifp,
-				    "TSO with ECN not negotiated with host\n");
-			return (ENOTSUP);
-		}
-		hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
-	}
-
-	/* Here we should increment tx_tso counter. */
-
-	return (0);
-}
-
-static struct mbuf *
-ptnet_tx_offload(if_t ifp, struct mbuf *m, bool allow_ecn,
-		 struct virtio_net_hdr *hdr)
-{
-	int flags, etype, csum_start, proto, error;
-
-	flags = m->m_pkthdr.csum_flags;
-
-	error = ptnet_tx_offload_ctx(m, &etype, &proto, &csum_start);
-	if (error)
-		goto drop;
-
-	if ((etype == ETHERTYPE_IP && flags & PTNET_CSUM_OFFLOAD) ||
-	    (etype == ETHERTYPE_IPV6 && flags & PTNET_CSUM_OFFLOAD_IPV6)) {
-		/*
-		 * We could compare the IP protocol vs the CSUM_ flag too,
-		 * but that really should not be necessary.
-		 */
-		hdr->flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM;
-		hdr->csum_start = csum_start;
-		hdr->csum_offset = m->m_pkthdr.csum_data;
-		/* Here we should increment the tx_csum counter. */
-	}
-
-	if (flags & CSUM_TSO) {
-		if (__predict_false(proto != IPPROTO_TCP)) {
-			/* Likely failed to correctly parse the mbuf.
-			 * Here we should increment the tx_tso_not_tcp
-			 * counter. */
-			goto drop;
-		}
-
-		KASSERT(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM,
-		    ("%s: mbuf %p TSO without checksum offload %#x",
-		    __func__, m, flags));
-
-		error = ptnet_tx_offload_tso(ifp, m, etype, csum_start,
-					     allow_ecn, hdr);
-		if (error)
-			goto drop;
-	}
-
-	return (m);
-
-drop:
-	m_freem(m);
-	return (NULL);
-}
-
 static void
 ptnet_vlan_tag_remove(struct mbuf *m)
 {
@@ -1494,157 +1353,6 @@ ptnet_vlan_tag_remove(struct mbuf *m)
 	m_adj(m, ETHER_VLAN_ENCAP_LEN);
 }
 
-/*
- * Use the checksum offset in the VirtIO header to set the
- * correct CSUM_* flags.
- */
-static int
-ptnet_rx_csum_by_offset(struct mbuf *m, uint16_t eth_type, int ip_start,
-			struct virtio_net_hdr *hdr)
-{
-#if defined(INET) || defined(INET6)
-	int offset = hdr->csum_start + hdr->csum_offset;
-#endif
-
-	/* Only do a basic sanity check on the offset. */
-	switch (eth_type) {
-#if defined(INET)
-	case ETHERTYPE_IP:
-		if (__predict_false(offset < ip_start + sizeof(struct ip)))
-			return (1);
-		break;
-#endif
-#if defined(INET6)
-	case ETHERTYPE_IPV6:
-		if (__predict_false(offset < ip_start + sizeof(struct ip6_hdr)))
-			return (1);
-		break;
-#endif
-	default:
-		/* Here we should increment the rx_csum_bad_ethtype counter. */
-		return (1);
-	}
-
-	/*
-	 * Use the offset to determine the appropriate CSUM_* flags. This is
-	 * a bit dirty, but we can get by with it since the checksum offsets
-	 * happen to be different. We assume the host host does not do IPv4
-	 * header checksum offloading.
-	 */
-	switch (hdr->csum_offset) {
-	case offsetof(struct udphdr, uh_sum):
-	case offsetof(struct tcphdr, th_sum):
-		m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-		m->m_pkthdr.csum_data = 0xFFFF;
-		break;
-	default:
-		/* Here we should increment the rx_csum_bad_offset counter. */
-		return (1);
-	}
-
-	return (0);
-}
-
-static int
-ptnet_rx_csum_by_parse(struct mbuf *m, uint16_t eth_type, int ip_start,
-		       struct virtio_net_hdr *hdr)
-{
-	int offset, proto;
-
-	switch (eth_type) {
-#if defined(INET)
-	case ETHERTYPE_IP: {
-		struct ip *ip;
-		if (__predict_false(m->m_len < ip_start + sizeof(struct ip)))
-			return (1);
-		ip = (struct ip *)(m->m_data + ip_start);
-		proto = ip->ip_p;
-		offset = ip_start + (ip->ip_hl << 2);
-		break;
-	}
-#endif
-#if defined(INET6)
-	case ETHERTYPE_IPV6:
-		if (__predict_false(m->m_len < ip_start +
-		    sizeof(struct ip6_hdr)))
-			return (1);
-		offset = ip6_lasthdr(m, ip_start, IPPROTO_IPV6, &proto);
-		if (__predict_false(offset < 0))
-			return (1);
-		break;
-#endif
-	default:
-		/* Here we should increment the rx_csum_bad_ethtype counter. */
-		return (1);
-	}
-
-	switch (proto) {
-	case IPPROTO_TCP:
-		if (__predict_false(m->m_len < offset + sizeof(struct tcphdr)))
-			return (1);
-		m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-		m->m_pkthdr.csum_data = 0xFFFF;
-		break;
-	case IPPROTO_UDP:
-		if (__predict_false(m->m_len < offset + sizeof(struct udphdr)))
-			return (1);
-		m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
-		m->m_pkthdr.csum_data = 0xFFFF;
-		break;
-	default:
-		/*
-		 * For the remaining protocols, FreeBSD does not support
-		 * checksum offloading, so the checksum will be recomputed.
-		 */
-#if 0
-		if_printf(ifp, "cksum offload of unsupported "
-		    "protocol eth_type=%#x proto=%d csum_start=%d "
-		    "csum_offset=%d\n", __func__, eth_type, proto,
-		    hdr->csum_start, hdr->csum_offset);
-#endif
-		break;
-	}
-
-	return (0);
-}
-
-/*
- * Set the appropriate CSUM_* flags. Unfortunately, the information
- * provided is not directly useful to us. The VirtIO header gives the
- * offset of the checksum, which is all Linux needs, but this is not
- * how FreeBSD does things. We are forced to peek inside the packet
- * a bit.
- *
- * It would be nice if VirtIO gave us the L4 protocol or if FreeBSD
- * could accept the offsets and let the stack figure it out.
- */
-static int
-ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr)
-{
-	struct ether_header *eh;
-	struct ether_vlan_header *evh;
-	uint16_t eth_type;
-	int offset, error;
-
-	eh = mtod(m, struct ether_header *);
-	eth_type = ntohs(eh->ether_type);
-	if (eth_type == ETHERTYPE_VLAN) {
-		/* BMV: We should handle nested VLAN tags too. */
-		evh = mtod(m, struct ether_vlan_header *);
-		eth_type = ntohs(evh->evl_proto);
-		offset = sizeof(struct ether_vlan_header);
-	} else
-		offset = sizeof(struct ether_header);
-
-	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)
-		error = ptnet_rx_csum_by_offset(m, eth_type, offset, hdr);
-	else
-		error = ptnet_rx_csum_by_parse(m, eth_type, offset, hdr);
-
-	return (error);
-}
-/* End of offloading-related functions to be shared with vtnet. */
-
 static void
 ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring,
 		  unsigned int head, unsigned int sync_flags)
@@ -1776,7 +1484,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 			 * two 8-bytes-wide writes. */
 			memset(nmbuf, 0, PTNET_HDR_SIZE);
 			if (mhead->m_pkthdr.csum_flags & PTNET_ALL_OFFLOAD) {
-				mhead = ptnet_tx_offload(ifp, mhead, false,
+				mhead = virtio_net_tx_offload(ifp, mhead, false,
 							 vh);
 				if (unlikely(!mhead)) {
 					/* Packet dropped because errors
@@ -2154,14 +1862,11 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 			}
 		}
 
-		if (have_vnet_hdr && (vh->flags & (VIRTIO_NET_HDR_F_NEEDS_CSUM
-					| VIRTIO_NET_HDR_F_DATA_VALID))) {
-			if (unlikely(ptnet_rx_csum(mhead, vh))) {
-				m_freem(mhead);
-				nm_prlim(1, "Csum offload error: dropping");
-				pq->stats.iqdrops ++;
-				deliver = 0;
-			}
+		if (unlikely(have_vnet_hdr && virtio_net_rx_csum(mhead, vh))) {
+			m_freem(mhead);
+			nm_prlim(1, "Csum offload error: dropping");
+			pq->stats.iqdrops ++;
+			deliver = 0;
 		}
 
 skip:
@@ -2291,3 +1996,4 @@ ptnet_poll(if_t ifp, enum poll_cmd cmd, int budget)
 	return count;
 }
 #endif /* DEVICE_POLLING */
+#endif /* WITH_PTNETMAP */
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 6e0bc60b9..51b7977b9 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -52,37 +52,6 @@ vtnet_netmap_queue_on(struct vtnet_softc *sc, enum txrx t, int idx)
 		na->tx_rings[idx]->nr_mode == NKR_NETMAP_ON);
 }
 
-static void
-vtnet_free_used(struct virtqueue *vq, int netmap_bufs, enum txrx t, int idx)
-{
-	void *cookie;
-	int deq = 0;
-
-	while ((cookie = virtqueue_dequeue(vq, NULL)) != NULL) {
-		if (netmap_bufs) {
-			/* These are netmap buffers: there is nothing to do. */
-		} else {
-			/* These are mbufs that we need to free. */
-			struct mbuf *m;
-
-			if (t == NR_TX) {
-				struct vtnet_tx_header *txhdr = cookie;
-				m = txhdr->vth_mbuf;
-				m_freem(m);
-				uma_zfree(vtnet_tx_header_zone, txhdr);
-			} else {
-				m = cookie;
-				m_freem(m);
-			}
-		}
-		deq++;
-	}
-
-	if (deq)
-		nm_prinf("%d sgs dequeued from %s-%d (netmap=%d)",
-			 deq, nm_txrx2str(t), idx, netmap_bufs);
-}
-
 /* Register and unregister. */
 static int
 vtnet_netmap_reg(struct netmap_adapter *na, int state)
@@ -113,18 +82,13 @@ vtnet_netmap_reg(struct netmap_adapter *na, int state)
 	for (i = 0; i < sc->vtnet_act_vq_pairs; i++) {
 		struct vtnet_txq *txq = &sc->vtnet_txqs[i];
 		struct vtnet_rxq *rxq = &sc->vtnet_rxqs[i];
-		struct netmap_kring *kring;
 
 		VTNET_TXQ_LOCK(txq);
-		kring = NMR(na, NR_TX)[i];
-		vtnet_free_used(txq->vtntx_vq,
-				kring->nr_mode == NKR_NETMAP_ON, NR_TX, i);
+		vtnet_txq_free_mbufs(txq);
 		VTNET_TXQ_UNLOCK(txq);
 
 		VTNET_RXQ_LOCK(rxq);
-		kring = NMR(na, NR_RX)[i];
-		vtnet_free_used(rxq->vtnrx_vq,
-				kring->nr_mode == NKR_NETMAP_ON, NR_RX, i);
+		vtnet_rxq_free_mbufs(rxq);
 		VTNET_RXQ_UNLOCK(rxq);
 	}
 	vtnet_init_locked(sc);
@@ -165,7 +129,6 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 	/*
 	 * First part: process new packets to send.
 	 */
-	rmb();
 
 	nm_i = kring->nr_hwcur;
 	if (nm_i != head) {	/* we have new packets to send */
@@ -232,14 +195,20 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 	return 0;
 }
 
+/*
+ * Publish (up to) num netmap receive buffers to the host,
+ * starting from the first one that the user made available
+ * (kring->nr_hwcur).
+ */
 static int
-vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int nm_i, u_int head)
+vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 {
 	struct netmap_adapter *na = kring->na;
 	struct ifnet *ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int const lim = kring->nkr_num_slots - 1;
+	u_int nm_i = kring->nr_hwcur;
 
 	/* device-specific */
 	struct vtnet_softc *sc = ifp->if_softc;
@@ -250,7 +219,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int nm_i, u_int head)
 	struct sglist_seg ss[2];
 	struct sglist sg = { ss, 0, 0, 2 };
 
-	for (; nm_i != head; nm_i = nm_next(nm_i, lim)) {
+	for (; num > 0; nm_i = nm_next(nm_i, lim), num--) {
 		struct netmap_slot *slot = &ring->slot[nm_i];
 		uint64_t paddr;
 		void *addr = PNMB(na, slot, &paddr);
@@ -302,10 +271,11 @@ vtnet_netmap_rxq_populate(struct vtnet_rxq *rxq)
 			kring->nr_pending_mode == NKR_NETMAP_ON))
 		return -1;
 
-	/* Expose all the RX netmap buffers. Note that the number of
-	 * netmap slots in the RX ring matches the maximum number of
-	 * 2-elements sglist that the RX virtqueue can accommodate. */
-	error = vtnet_netmap_kring_refill(kring, 0, na->num_rx_desc);
+	/* Expose all the RX netmap buffers we can. In case of no indirect
+	 * buffers, the number of netmap slots in the RX ring matches the
+	 * maximum number of 2-elements sglist that the RX virtqueue can
+	 * accommodate (minus 1 to avoid netmap ring wraparound). */
+	error = vtnet_netmap_kring_refill(kring, na->num_rx_desc - 1);
 	virtqueue_notify(rxq->vtnrx_vq);
 
 	return error < 0 ? ENXIO : 0;
@@ -331,7 +301,6 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 	struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr];
 	struct virtqueue *vq = rxq->vtnrx_vq;
 
-	rmb();
 	/*
 	 * First part: import newly received packets.
 	 * Only accept our own buffers (matching the token). We should only get
@@ -381,7 +350,12 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	nm_i = kring->nr_hwcur; /* netmap ring index */
 	if (nm_i != head) {
-		int nm_j = vtnet_netmap_kring_refill(kring, nm_i, head);
+		int howmany = head - nm_i;
+		int nm_j;
+
+		if (howmany < 0)
+			howmany += kring->nkr_num_slots;
+		nm_j = vtnet_netmap_kring_refill(kring, howmany);
 		if (nm_j < 0)
 			return nm_j;
 		kring->nr_hwcur = nm_j;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 5998b6a50..14ce4592e 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -437,11 +437,13 @@ ports attached to the switch)
 #include 	/* struct socket */
 #include 
 #include 
+#include 
 #include 
 #include  /* sockaddrs */
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -538,7 +540,8 @@ int ptnet_vnet_hdr = 1;
 SYSBEGIN(main_init);
 
 SYSCTL_DECL(_dev_netmap);
-SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args");
+SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+    "Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
 		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 #ifdef CONFIG_NETMAP_DEBUG
@@ -1160,7 +1163,11 @@ netmap_send_up(struct ifnet *dst, struct mbq *q)
 {
 	struct mbuf *m;
 	struct mbuf *head = NULL, *prev = NULL;
+#ifdef __FreeBSD__
+	struct epoch_tracker et;
 
+	NET_EPOCH_ENTER(et);
+#endif /* __FreeBSD__ */
 	/* Send packets up, outside the lock; head/prev machinery
 	 * is only useful for Windows. */
 	while ((m = mbq_dequeue(q)) != NULL) {
@@ -1172,6 +1179,9 @@ netmap_send_up(struct ifnet *dst, struct mbq *q)
 	}
 	if (head)
 		nm_os_send_up(dst, NULL, head);
+#ifdef __FreeBSD__
+	NET_EPOCH_EXIT(et);
+#endif /* __FreeBSD__ */
 	mbq_fini(q);
 }
 
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 2580144ab..e37815dc8 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1022,12 +1022,10 @@ netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
 	vm_paddr_t paddr;
 	vm_page_t page;
 	vm_memattr_t memattr;
-	vm_pindex_t pidx;
 
 	nm_prdis("object %p offset %jd prot %d mres %p",
 			object, (intmax_t)offset, prot, mres);
 	memattr = object->memattr;
-	pidx = OFF_TO_IDX(offset);
 	paddr = netmap_mem_ofstophys(na->nm_mem, offset);
 	if (paddr == 0)
 		return VM_PAGER_FAIL;
@@ -1052,9 +1050,8 @@ netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
 		VM_OBJECT_WUNLOCK(object);
 		page = vm_page_getfake(paddr, memattr);
 		VM_OBJECT_WLOCK(object);
-		vm_page_free(*mres);
+		vm_page_replace(page, object, (*mres)->pindex, *mres);
 		*mres = page;
-		vm_page_insert(page, object, pidx);
 	}
 	vm_page_valid(page);
 	return (VM_PAGER_OK);
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 330f1d2c2..37de01963 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -669,6 +669,11 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (nm_i != head) {	/* we have new packets to send */
 		struct nm_os_gen_arg a;
 		u_int event = -1;
+#ifdef __FreeBSD__
+		struct epoch_tracker et;
+
+		NET_EPOCH_ENTER(et);
+#endif
 
 		if (gna->txqdisc && nm_kr_txempty(kring)) {
 			/* In txqdisc mode, we ask for a delayed notification,
@@ -776,6 +781,10 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 		/* Update hwcur to the next slot to transmit. Here nm_i
 		 * is not necessarily head, we could break early. */
 		kring->nr_hwcur = nm_i;
+
+#ifdef __FreeBSD__
+		NET_EPOCH_EXIT(et);
+#endif
 	}
 
 	/*
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 3985fd5bd..8edb0d8ec 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -76,7 +76,6 @@
 #define WITH_PIPES
 #define WITH_MONITOR
 #define WITH_GENERIC
-#define WITH_PTNETMAP	/* ptnetmap guest support */
 #define WITH_EXTMEM
 #define WITH_NMNULL
 #endif
@@ -626,6 +625,7 @@ nm_prev(uint32_t i, uint32_t lim)
 	return unlikely (i == 0) ? lim : i - 1;
 }
 
+
 /*
  *
  * Here is the layout for the Rx and Tx rings.
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 24d908cd5..2ae81c96f 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1034,7 +1034,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 		}
 
 		nm_prdis(5, "pass 2 dst %d is %x %s",
-			i, d_i, is_vp ? "virtual" : "nic/host");
+			i, d_i, nm_is_bwrap(&dst_na->up) ? "nic/host" : "virtual");
 		dst_nr = d_i & (NM_BDG_MAXRINGS-1);
 		nrings = dst_na->up.num_rx_rings;
 		if (dst_nr >= nrings)

From 95713656bdf471d0351360adcc15ea77b8560526 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 5 Jun 2020 17:03:33 +0200
Subject: [PATCH 1829/2207] restore binary compatibility for netmap_rings

---
 sys/net/netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 6e213ef4a..1607d8ecc 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -312,9 +312,9 @@ struct netmap_ring {
 
 	/* opaque room for a mutex or similar object */
 #if !defined(_WIN32) || defined(__CYGWIN__)
-	uint8_t	__attribute__((__aligned__(NM_CACHE_ALIGN))) sem[112];
+	uint8_t	__attribute__((__aligned__(NM_CACHE_ALIGN))) sem[128];
 #else
-	uint8_t	__declspec(align(NM_CACHE_ALIGN)) sem[112];
+	uint8_t	__declspec(align(NM_CACHE_ALIGN)) sem[128];
 #endif
 
 	/* the slots follow. This struct has variable size */

From 0ae82ae90c537a7768a372a79638d412747c0985 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 5 Jun 2020 17:03:56 +0200
Subject: [PATCH 1830/2207] fix indentation warning

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 86bf947ec..4b2f04e32 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -541,7 +541,7 @@ SYSBEGIN(main_init);
 
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
-    "Netmap args");
+		"Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
 		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 #ifdef CONFIG_NETMAP_DEBUG

From bc09dd64edbf2880947daaee5fa6e7d23a850809 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 5 Jun 2020 17:19:25 +0200
Subject: [PATCH 1831/2207] add binary compatibility regression test

---
 utils/ctrl-api-test.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index a75e21cca..0ad4abc54 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -57,6 +57,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "libnetmap.h"
 
 #ifdef __FreeBSD__
@@ -1954,6 +1955,37 @@ nmreq_parsing(struct TestContext *ctx)
 	return ret;
 }
 
+static int
+binarycomp(struct TestContext *ctx)
+{
+#define ckroff(f, o) do {\
+	if (offsetof(struct netmap_ring, f) != (o)) {\
+		printf("offset of netmap_ring.%s is %zd, but it should be %d",\
+				#f, offsetof(struct netmap_ring, f), (o));\
+		return -1;\
+	}\
+} while (0)
+
+	(void)ctx;
+
+	ckroff(buf_ofs, 0);
+	ckroff(num_slots, 8);
+	ckroff(nr_buf_size, 12);
+	ckroff(ringid, 16);
+	ckroff(dir, 18);
+	ckroff(head, 20);
+	ckroff(cur, 24);
+	ckroff(tail, 28);
+	ckroff(flags, 32);
+	ckroff(ts, 40);
+	ckroff(offset_mask, 56);
+	ckroff(buf_align, 64);
+	ckroff(sem, 128);
+	ckroff(slot, 256);
+
+	return 0;
+}
+
 static void
 usage(const char *prog)
 {
@@ -2023,6 +2055,7 @@ static struct mytest tests[] = {
 	decltest(legacy_regif_extra_bufs_pipe),
 	decltest(legacy_regif_extra_bufs_pipe_vale),
 	decltest(nmreq_parsing),
+	decltest(binarycomp),
 };
 
 static void

From 204e0efc7677f81668a10bd8967837f42123161e Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Fri, 22 May 2020 02:39:25 +0000
Subject: [PATCH 1832/2207] mlx5 5.0 patch

---
 LINUX/configure                         |   2 +-
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/mellanox--mlx5--5.0 | 380 ++++++++++++++++++++++++
 3 files changed, 382 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--5.0

diff --git a/LINUX/configure b/LINUX/configure
index 64300edf8..935c7e161 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -504,7 +504,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS := -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
+EXTRA_CFLAGS := -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 17a7766e5..c1a2356f5 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -102,7 +102,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,4.5-1.0.1.0))
+$(eval $(call default,mlx5,5.0-1.0.0.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 
diff --git a/LINUX/final-patches/mellanox--mlx5--5.0 b/LINUX/final-patches/mellanox--mlx5--5.0
new file mode 100644
index 000000000..c251c95c3
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--5.0
@@ -0,0 +1,380 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 88f7ea5..ed5507a 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -6,12 +6,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o lib/dm.o \
+@@ -20,11 +20,11 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		fw_exp.o sriov_sysfs.o mst_dump.o en_diag.o params.o crdump.o \
+ 		icmd.o capi.o diag/diag_cnt.o eswitch_devlink_compat.o devlink.o
+ 
+-mlx5_core-$(CONFIG_ENABLE_MLX5_FS_DEBUGFS) += fs_debugfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_ENABLE_MLX5_FS_DEBUGFS) += fs_debugfs.o
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o \
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+ 		en/reporter_tx.o en/reporter_rx.o en/params.o en_debugfs.o en_sniffer.o
+@@ -32,16 +32,16 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
+ 					miniflow.o miniflow_aging.o en_bond.o lib/geneve.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_ACCEL_FS) += en_accel/fs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ACCEL_FS) += en_accel/fs.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o \
+ 					steering/dr_ste.o steering/dr_send.o \
+@@ -51,38 +51,39 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o ecpf.o rdma.o
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o ecpf.o rdma.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
+-mlx5_core-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
+ 				 fpga/trans.o fpga/xfer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_IPSEC) += en_accel/ipsec_steering.o en_accel/ipsec_offload.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_IPSEC) += en_accel/ipsec_steering.o en_accel/ipsec_offload.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
++mlx5_core-$(NETMAP_DRIVER_SUFFIX)$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ 				   en_accel/ktls.o en_accel/ktls_tx.o
++
+ #
+ # Mdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o meddev/mdev_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o meddev/mdev_driver.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index a34b25a..8ac923a 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -13,6 +13,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->channel->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 06a1fb0..1c17838 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -69,6 +69,16 @@
+ #include "lib/mlx5.h"
+ #include "en_accel/ipsec_steering.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ struct mlx5e_rq_param {
+ 	u32			rqc[MLX5_ST_SZ_DW(rqc)];
+ 	struct mlx5_wq_param	wq;
+@@ -102,6 +112,9 @@ struct mlx5e_channel_param {
+ 
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -777,6 +790,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ 		rq->dim_obj.dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_free:
+@@ -1000,6 +1017,12 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 	struct mlx5e_channel *c = rq->channel;
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(c->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1047,6 +1070,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->channel->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1164,6 +1191,9 @@ err_free_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->channel->netdev)) || NA(rq->channel->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	mlx5e_trigger_irq(&rq->channel->icosq);
+ }
+@@ -1427,6 +1457,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1620,6 +1655,9 @@ static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe_info *wi;
+@@ -1642,6 +1680,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3485,6 +3529,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -3529,6 +3578,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++	netmap_disable_all_rings(netdev);
++#endif
++
+ 	if (MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER)) {
+ 		mlx5e_sniffer_stop(priv);
+ 		MLX5E_SET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER, 0);
+@@ -6556,6 +6609,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ 	const struct mlx5e_profile *profile = priv->profile;
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	if (profile->cleanup)
+ 		profile->cleanup(priv);
+ 	free_netdev(netdev);
+@@ -6675,6 +6732,11 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
+ 	mlx5e_dcbnl_init_app(priv);
+ #endif
+ #endif
++
++#ifdef DEV_NETMAP
++	mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return priv;
+ 
+ err_unregister_netdev:
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index 535367a..e68cac8 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -51,6 +51,14 @@
+ #include "en/xdp.h"
+ #include "en/health.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -169,7 +177,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -1754,6 +1762,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 591ee79..da75df5 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -41,8 +41,16 @@
+ #include "en_accel/ktls.h"
+ #include "lib/clock.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+-				       u32 cqcc, void *data)
++                                       u32 cqcc, void *data)
+ {
+ 	u32 ci = mlx5_cqwq_ctr2ix(wq, cqcc);
+ 
+@@ -706,6 +714,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->channel->netdev, sq->channel->ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -845,14 +858,16 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 			continue;
+ 		}
+ 
+-		for (i = 0; i < wi->num_dma; i++) {
+-			struct mlx5e_sq_dma *dma =
+-				mlx5e_dma_get(sq, dma_fifo_cc++);
++		if (!nm_netmap_on(NA(sq->txq->dev))) {
++			/* do not free skbs in netmap mode */
++			for (i = 0; i < wi->num_dma; i++) {
++				struct mlx5e_sq_dma *dma =
++					mlx5e_dma_get(sq, sq->dma_fifo_cc++);
+ 
+-			mlx5e_tx_dma_unmap(sq->pdev, dma);
++				mlx5e_tx_dma_unmap(sq->pdev, dma);
++			}
++			dev_kfree_skb_any(skb);
+ 		}
+-
+-		dev_kfree_skb_any(skb);
+ 		sqcc += wi->num_wqebbs;
+ 	}
+ 

From 07bf0f37ccbf7fceff97c623ccc39577c99604d9 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Mon, 29 Jun 2020 10:58:18 +0100
Subject: [PATCH 1833/2207] linux: kthread_(un)use_mm w/o set_fs in 5.8 or
 later

---
 LINUX/configure      | 11 +++++++++++
 LINUX/netmap_linux.c | 12 ++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 64300edf8..15f9ce9d5 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1139,6 +1139,17 @@ EOF
 	}
 EOF
 
+  # (un)use_mm is unavailable in kernel 5.8 and later
+  add_test 'have KTHREAD_USE_MM' <
+	#include 
+
+	void dummy(struct mm_struct *mm)
+	{
+		kthread_use_mm(mm);
+	}
+EOF
+
   # number of parameters in ndo_select_queue
   # (we expect at most one of these to succeed)
   params="NULL, NULL"
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index b54940cb0..8a4ea5b17 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1655,11 +1655,17 @@ static int
 nm_kctx_worker(void *data)
 {
 	struct nm_kctx *nmk = data;
+#ifndef NETMAP_LINUX_HAVE_KTHREAD_USE_MM
 	mm_segment_t oldfs = get_fs();
+#endif /* NETMAP_LINUX_HAVE_KTHREAD_USE_MM */
 
 	if (nmk->mm) {
+#ifndef NETMAP_LINUX_HAVE_KTHREAD_USE_MM
 		set_fs(USER_DS);
 		use_mm(nmk->mm);
+#else
+		kthread_use_mm(nmk->mm);
+#endif /* NETMAP_LINUX_HAVE_KTHREAD_USE_MM */
 	}
 
 	while (!kthread_should_stop()) {
@@ -1669,10 +1675,16 @@ nm_kctx_worker(void *data)
 	}
 
 	if (nmk->mm) {
+#ifndef NETMAP_LINUX_HAVE_KTHREAD_USE_MM
 		unuse_mm(nmk->mm);
+#else
+		kthread_unuse_mm(nmk->mm);
+#endif /* NETMAP_LINUX_HAVE_KTHREAD_USE_MM */
 	}
 
+#ifndef NETMAP_LINUX_HAVE_KTHREAD_USE_MM
 	set_fs(oldfs);
+#endif /* NETMAP_LINUX_HAVE_KTHREAD_USE_MM */
 	return 0;
 }
 

From f222f8bb6d707dec8a9411ec839d6f4ba93b668e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 Jul 2020 09:53:57 +0200
Subject: [PATCH 1834/2207] ctrl-api-test: check string lengths

---
 utils/ctrl-api-test.c | 46 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 0ad4abc54..f78238c3a 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -73,6 +73,8 @@ eventfd(int x __unused, int y __unused)
 #include 
 #endif
 
+#define NM_IFNAMSZ 64
+
 static int
 exec_command(int argc, const char *const argv[])
 {
@@ -145,9 +147,9 @@ exec_command(int argc, const char *const argv[])
 #define THRET_FAILURE	((void *)0)
 
 struct TestContext {
-	char ifname[64];
-	char ifname_ext[128];
-	char bdgname[64];
+	char ifname[NM_IFNAMSZ];
+	char ifname_ext[NM_IFNAMSZ];
+	char bdgname[NM_IFNAMSZ];
 	uint32_t nr_tx_slots;   /* slots in tx rings */
 	uint32_t nr_rx_slots;   /* slots in rx rings */
 	uint16_t nr_tx_rings;   /* number of tx rings */
@@ -178,12 +180,13 @@ static struct TestContext ctx_;
 
 typedef int (*testfunc_t)(struct TestContext *ctx);
 
+/* strlen(ifname) must be < NM_IFNAMSZ */
 static void
 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
 {
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->nr_version = NETMAP_API;
-	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
+	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
 }
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
@@ -528,16 +531,30 @@ port_register_hwall_rx(struct TestContext *ctx)
 	return port_register(ctx);
 }
 
+
+static int
+vale_mkname(char *vpname, struct TestContext *ctx)
+{
+	if (snprintf(vpname, NM_IFNAMSZ, "%s:%s", ctx->bdgname, ctx->ifname_ext) >= NM_IFNAMSZ) {
+		fprintf(stderr, "%s:%s too long (max %d chars)\n", ctx->bdgname, ctx->ifname_ext,
+				NM_IFNAMSZ - 1);
+		return -1;
+	}
+	return 0;
+}
+
+
 /* NETMAP_REQ_VALE_ATTACH */
 static int
 vale_attach(struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
 	struct nmreq_header hdr;
-	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
 
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
@@ -569,10 +586,11 @@ vale_detach(struct TestContext *ctx)
 {
 	struct nmreq_header hdr;
 	struct nmreq_vale_detach req;
-	char vpname[256];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
@@ -847,10 +865,12 @@ vale_polling_enable(struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
 	struct nmreq_header hdr;
-	char vpname[256];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
+
 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
 	nmreq_hdr_init(&hdr, vpname);
@@ -879,10 +899,12 @@ vale_polling_disable(struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
 	struct nmreq_header hdr;
-	char vpname[256];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
+
 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
 	nmreq_hdr_init(&hdr, vpname);

From a0386df4ea7bd5f91c9c3819a776533ae3ff831c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 20 Jul 2020 09:59:38 +0200
Subject: [PATCH 1835/2207] ctrl-api-test: add assertion to silence gcc-9

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index f78238c3a..fac920547 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -180,12 +180,12 @@ static struct TestContext ctx_;
 
 typedef int (*testfunc_t)(struct TestContext *ctx);
 
-/* strlen(ifname) must be < NM_IFNAMSZ */
 static void
 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
 {
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->nr_version = NETMAP_API;
+	assert(strlen(ifname) < NM_IFNAMSZ);
 	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
 }
 

From 67cb9f9f7a39628a1d7d3ec06e438f9e88cfcba7 Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Fri, 31 Jul 2020 09:03:34 -0400
Subject: [PATCH 1836/2207] fix parsing of legacy nmr->nr_ringid

Code was checking for NETMAP_{SW,HW}_RING in req->nr_ringid which
had already been masked by NETMAP_RING_MASK. Therefore, the comparisons
always failed and set NR_REG_ALL_NIC. Check against the original nmr
structure.
---
 sys/dev/netmap/netmap_legacy.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 55b10a547..512e1e084 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -76,9 +76,9 @@ nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
 		/* Convert the older nmr->nr_ringid (original
 		 * netmap control API) to nmr->nr_flags. */
 		u_int regmode = NR_REG_DEFAULT;
-		if (req->nr_ringid & NETMAP_SW_RING) {
+		if (nmr->nr_ringid & NETMAP_SW_RING) {
 			regmode = NR_REG_SW;
-		} else if (req->nr_ringid & NETMAP_HW_RING) {
+		} else if (nmr->nr_ringid & NETMAP_HW_RING) {
 			regmode = NR_REG_ONE_NIC;
 		} else {
 			regmode = NR_REG_ALL_NIC;

From 7bb5e904f6c0bc2e928cb735e5c702a92d947f1d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 4 Aug 2020 15:56:14 +0200
Subject: [PATCH 1837/2207] linux: patches for vanilla 5.8

---
 ...400--99999 => vanilla--i40e--41400--50800} |   0
 .../final-patches/vanilla--i40e--50800--99999 | 115 +++++++++++++++
 ...00--99999 => vanilla--ixgbe--41400--50800} |   0
 .../vanilla--ixgbe--50800--99999              | 134 ++++++++++++++++++
 ...--99999 => vanilla--ixgbevf--41100--50800} |   0
 .../vanilla--ixgbevf--50800--99999            | 127 +++++++++++++++++
 6 files changed, 376 insertions(+)
 rename LINUX/final-patches/{vanilla--i40e--41400--99999 => vanilla--i40e--41400--50800} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--50800--99999
 rename LINUX/final-patches/{vanilla--ixgbe--41400--99999 => vanilla--ixgbe--41400--50800} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--50800--99999
 rename LINUX/final-patches/{vanilla--ixgbevf--41100--99999 => vanilla--ixgbevf--41100--50800} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--50800--99999

diff --git a/LINUX/final-patches/vanilla--i40e--41400--99999 b/LINUX/final-patches/vanilla--i40e--41400--50800
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--41400--99999
rename to LINUX/final-patches/vanilla--i40e--41400--50800
diff --git a/LINUX/final-patches/vanilla--i40e--50800--99999 b/LINUX/final-patches/vanilla--i40e--50800--99999
new file mode 100644
index 000000000..2b662afd8
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--50800--99999
@@ -0,0 +1,115 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 56ecd6c3f236..0f52cbe03dcd 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -104,6 +104,10 @@ MODULE_LICENSE("GPL v2");
+ MODULE_VERSION(DRV_VERSION);
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+@@ -3241,6 +3245,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3330,6 +3338,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3358,6 +3370,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->xsk_umem) {
+ 		xsk_buff_set_rxq_info(ring->xsk_umem, &ring->xdp_rxq);
+ 		ok = i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring));
+@@ -13363,6 +13380,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13730,6 +13752,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index f9555c847f73..9ac901483469 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_txrx_common.h"
+ #include "i40e_xsk.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -782,6 +786,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2320,6 +2329,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/vanilla--ixgbe--41400--99999 b/LINUX/final-patches/vanilla--ixgbe--41400--50800
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbe--41400--99999
rename to LINUX/final-patches/vanilla--ixgbe--41400--50800
diff --git a/LINUX/final-patches/vanilla--ixgbe--50800--99999 b/LINUX/final-patches/vanilla--ixgbe--50800--99999
new file mode 100644
index 000000000..81fca27b7
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--50800--99999
@@ -0,0 +1,134 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 97a423ecf808..8b84a5992faa 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -460,6 +460,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1122,6 +1138,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2299,13 +2326,23 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
+-	xdp.rxq = &rx_ring->xdp_rxq;
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
+ 
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = ixgbe_rx_frame_truesize(rx_ring, 0);
+ #endif
+ 
++	xdp.rxq = &rx_ring->xdp_rxq;
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		union ixgbe_adv_rx_desc *rx_desc;
+ 		struct ixgbe_rx_buffer *rx_buffer;
+@@ -3537,6 +3574,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -3551,7 +3592,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+ 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
+@@ -4144,6 +4185,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ 	else
+@@ -5644,6 +5689,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -11177,6 +11225,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 
+ 	ixgbe_mii_bus_init(hw);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11223,6 +11275,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
+ 	set_bit(__IXGBE_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--41100--99999 b/LINUX/final-patches/vanilla--ixgbevf--41100--50800
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbevf--41100--99999
rename to LINUX/final-patches/vanilla--ixgbevf--41100--50800
diff --git a/LINUX/final-patches/vanilla--ixgbevf--50800--99999 b/LINUX/final-patches/vanilla--ixgbevf--50800--99999
new file mode 100644
index 000000000..57e847f7a
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--50800--99999
@@ -0,0 +1,127 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index a39e2cb384dd..e75f700647c7 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -257,6 +257,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev, unsigned int txqueue)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -276,6 +294,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1135,13 +1165,24 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
+-	xdp.rxq = &rx_ring->xdp_rxq;
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
+ 
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
++#endif /* DEV_NETMAP */
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = ixgbevf_rx_frame_truesize(rx_ring, 0);
+ #endif
+ 
++	xdp.rxq = &rx_ring->xdp_rxq;
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		struct ixgbevf_rx_buffer *rx_buffer;
+ 		union ixgbe_adv_rx_desc *rx_desc;
+@@ -1746,6 +1787,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1754,7 +1799,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(reg_idx));
+ 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ /**
+@@ -1980,6 +2025,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4737,6 +4786,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4777,6 +4830,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 

From a1fb6f69d9e8ac462204f78d6f42727d98f80b9a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Aug 2020 09:22:51 +0200
Subject: [PATCH 1838/2207] nmport: add missing default key for share option

---
 libnetmap/nmport.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 3b7bbea14..7ea1edf6c 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -330,6 +330,7 @@ nmport_opt_##o##_key_##k##_ctor(void)					\
 #define nmport_defkey(p, o)	((p)->keys[NPOPT_DESC(o).default_key])
 
 NPOPT_DECL(share, 0)
+	NPKEY_DECL(share, port, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
 NPOPT_DECL(extmem, 0)
 	NPKEY_DECL(extmem, file, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
 	NPKEY_DECL(extmem, if_num, 0)

From c81fffeee942c742aee0634447566f6d43fae56e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Aug 2020 09:38:58 +0200
Subject: [PATCH 1839/2207] linux/ixgbe: revert spurious modifications in
 vanilla patch

---
 .../vanilla--ixgbe--50800--99999              | 25 +++----------------
 1 file changed, 4 insertions(+), 21 deletions(-)

diff --git a/LINUX/final-patches/vanilla--ixgbe--50800--99999 b/LINUX/final-patches/vanilla--ixgbe--50800--99999
index 81fca27b7..cae395415 100644
--- a/LINUX/final-patches/vanilla--ixgbe--50800--99999
+++ b/LINUX/final-patches/vanilla--ixgbe--50800--99999
@@ -1,5 +1,5 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 97a423ecf808..8b84a5992faa 100644
+index 97a423ecf808..a40ffcf4a6ee 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
 @@ -460,6 +460,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
@@ -43,11 +43,10 @@ index 97a423ecf808..8b84a5992faa 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2299,13 +2326,23 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+@@ -2299,6 +2326,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
  	unsigned int xdp_xmit = 0;
  	struct xdp_buff xdp;
  
--	xdp.rxq = &rx_ring->xdp_rxq;
 +#ifdef DEV_NETMAP
 +	/*
 +	 * 	 Same as the txeof routine: only wakeup clients on intr.
@@ -57,17 +56,10 @@ index 97a423ecf808..8b84a5992faa 100644
 +	if (nm_irq != NM_IRQ_PASS)
 +		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
 +#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
  
  	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
- #if (PAGE_SIZE < 8192)
- 	xdp.frame_sz = ixgbe_rx_frame_truesize(rx_ring, 0);
- #endif
- 
-+	xdp.rxq = &rx_ring->xdp_rxq;
-+
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct ixgbe_rx_buffer *rx_buffer;
 @@ -3537,6 +3574,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  	memset(ring->tx_buffer_info, 0,
  	       sizeof(struct ixgbe_tx_buffer) * ring->count);
@@ -79,15 +71,6 @@ index 97a423ecf808..8b84a5992faa 100644
  	/* enable queue */
  	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
-@@ -3551,7 +3592,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
- 	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
- 	if (!wait_loop)
--		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
-+		e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
- }
- 
- static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
 @@ -4144,6 +4185,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  

From 78202984e4a6c7f4232dbb096720a8f74bdce4f3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 7 Aug 2020 09:50:05 +0200
Subject: [PATCH 1840/2207] bwrap: correctly handle offsets and hwbuf_len

---
 sys/dev/netmap/netmap_bdg.c | 39 +++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 77f99b972..d896df44f 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1286,6 +1286,40 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 	return 0;
 }
 
+/* nm_bufcfg callback for bwrap */
+static int
+netmap_bwrap_bufcfg(struct netmap_kring *kring, uint64_t target)
+{
+	struct netmap_adapter *na = kring->na;
+	struct netmap_bwrap_adapter *bna =
+		(struct netmap_bwrap_adapter *)na;
+	struct netmap_adapter *hwna = bna->hwna;
+	struct netmap_kring *hwkring;
+	enum txrx r;
+	int error;
+
+	/* we need the hw kring that corresponds to the bwrap one:
+	 * remember that rx and tx are swapped
+	 */
+	r = nm_txrx_swap(kring->tx);
+	hwkring = NMR(hwna, r)[kring->ring_id];
+
+	/* copy down the offset information, forward the request
+	 * and copy up the results
+	 */
+	hwkring->offset_mask = kring->offset_mask;
+	hwkring->offset_max  = kring->offset_max;
+	hwkring->offset_gap  = kring->offset_gap;
+
+	error = hwkring->nm_bufcfg(hwkring, target);
+	if (error)
+		return error;
+
+	kring->hwbuf_len = hwkring->hwbuf_len;
+	kring->buf_align = hwkring->buf_align;
+
+	return 0;
+}
 
 /* nm_krings_create callback for bwrap */
 int
@@ -1304,13 +1338,13 @@ netmap_bwrap_krings_create_common(struct netmap_adapter *na)
 		return error;
 	}
 
-	/* increment the usage counter for all the hwna and na krings */
+	/* increment the usage counter for all the hwna krings */
 	for_rx_tx(t) {
 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users++;
 			/* this to prevent deleation of the rings through
 			 * our krings, instead of through the hwna ones */
-			NMR(na, t)[i]->users++;
+			NMR(na, t)[i]->nr_kflags |= NKR_NEEDRING;
 		}
 	}
 
@@ -1526,6 +1560,7 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 	}
 	na->nm_dtor = netmap_bwrap_dtor;
 	na->nm_config = netmap_bwrap_config;
+	na->nm_bufcfg = netmap_bwrap_bufcfg;
 	na->nm_bdg_ctl = netmap_bwrap_bdg_ctl;
 	na->pdev = hwna->pdev;
 	na->nm_mem = netmap_mem_get(hwna->nm_mem);

From cd656a14b1410039c6cde6a2bce3714922785c51 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Mon, 24 Aug 2020 17:11:32 +0200
Subject: [PATCH 1841/2207] libnetmap: fix code spelling

---
 libnetmap/libnetmap.h | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index ec1458fbe..ed9edbfad 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -56,7 +56,7 @@ struct nmem_d;
  *  netmap 		(no id allowed)
  *  			the standard subsystem
  *
- *  vale 		(followed by a possibily empty id)
+ *  vale 		(followed by a possibly empty id)
  *  			the vpname is connected to a VALE switch identified by
  *  			the id (an empty id selects the default switch)
  *
@@ -126,7 +126,7 @@ struct nmem_d;
  *  			slots		number of slots in each tx and rx
  *  					ring
  *  			tx-slots	number of slots in each tx ring
- *  			rx-slots	numner of slots in each rx ring
+ *  			rx-slots	number of slots in each rx ring
  *
  *  			(more specific keys override the less specific ones)
  *			All keys default to zero if not assigned, and the
@@ -210,7 +210,7 @@ struct nmport_d {
 /* nmport_open - opens a port from a portspec
  * @portspec	the port opening specification
  *
- * If successfull, the function returns a new nmport_d describing a netmap
+ * If successful, the function returns a new nmport_d describing a netmap
  * port, opened according to the port specification, ready to be used for rx
  * and/or tx.
  *
@@ -298,7 +298,7 @@ int nmport_register(struct nmport_d *);
 /* nmport_mmap - maps the port resources into the process memory
  * @d		the nmport to be mapped
  *
- * The port must have been previosly been registered using nmport_register.
+ * The port must have been previously been registered using nmport_register.
  *
  * Note that if extmem is used (either via an option or by calling an
  * nmport_extmem_* function before nmport_register()), no new mmap() is issued.
@@ -464,7 +464,7 @@ int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff,
  * If the option is unknown, nmport_disable_option is a NOP, while
  * nmport_enable_option returns -1 and sets errno to EOPNOTSUPP.
  *
- * These functions are not threadsafe and are ment to be used at the beginning
+ * These functions are not threadsafe and are meant to be used at the beginning
  * of the program.
  */
 void nmport_disable_option(const char *opt);
@@ -503,7 +503,7 @@ void nmreq_header_init(struct nmreq_header *hdr, uint16_t reqtype, void *body);
 int nmreq_header_decode(const char **ppspec, struct nmreq_header *hdr,
 		struct nmctx *ctx);
 
-/* nmreq_regiter_decode - inizialize an nmreq_register
+/* nmreq_regiter_decode - initialize an nmreq_register
  * @pmode:	(in/out) pointer to a pointer to an opening mode
  * @reg:	pointer to the nmreq_register to be initialized
  * @ctx:	pointer to the nmctx to use (for errors)
@@ -533,7 +533,7 @@ int nmreq_register_decode(const char **pmode, struct nmreq_register *reg,
  *
  * This function parses each option in @opt. Each option is matched (based on
  * the "option" prefix) to a corresponding parser in @parsers. The function
- * checks that the syntax is appropriate for the parser and it assignes all the
+ * checks that the syntax is appropriate for the parser and it assigns all the
  * keys mentioned in the option. It then passes control to the parser, to
  * interpret the keys values.
  *
@@ -594,7 +594,7 @@ struct nmreq_parse_ctx {
  * @portname	pointer to a pointer to the portname
  * @ctx		pointer to the nmctx to use (for errors)
  *
- * *@portname must point to a substem:vpname porname, possibily followed by
+ * *@portname must point to a substem:vpname porname, possibly followed by
  * something else.
  *
  * If successful, returns the mem_id of *@portname and moves @portname past the
@@ -622,10 +622,10 @@ const char* nmreq_option_name(uint32_t);
  *   ports that are using the same region (as identified by the mem_id) will
  *   point to the same nmem_d instance.
  *
- * - allow the user to specifiy how to lock accesses to the above list, if
+ * - allow the user to specify how to lock accesses to the above list, if
  *   needed (lock() callback)
  *
- * - allow the user to specifiy how error messages should be delivered (error()
+ * - allow the user to specify how error messages should be delivered (error()
  *   callback)
  *
  * - select the verbosity of the library (verbose field); if verbose==0, no
@@ -664,7 +664,7 @@ struct nmctx *nmctx_set_default(struct nmctx *ctx);
 
 /* struct nmem_d - describes a memory region currently used */
 struct nmem_d {
-	uint16_t mem_id;	/* the region netmap identifer */
+	uint16_t mem_id;	/* the region netmap identifier */
 	int refcount;		/* how many nmport_d's point here */
 	void *mem;		/* memory region base address */
 	size_t size;		/* memory region size */
@@ -697,7 +697,7 @@ static  __attribute__((used)) void libnetmap_init(void)
 
 /* nmctx_set_threadsafe - install a threadsafe default context
  *
- * called by the contructor in nmctx-pthread.o to initialize a lock and install
+ * called by the constructor in nmctx-pthread.o to initialize a lock and install
  * the lock() callback in the default context.
  */
 void nmctx_set_threadsafe(void);

From 42785fd5d8db2f8c1e0ae7e832e9ba2481014881 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Mon, 24 Aug 2020 17:18:08 +0200
Subject: [PATCH 1842/2207] import netmap_kring_on() from FreeBSD

---
 sys/dev/netmap/netmap_kern.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 624aa3514..7291df2be 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1401,6 +1401,24 @@ nm_native_on(struct netmap_adapter *na)
 	return nm_netmap_on(na) && (na->na_flags & NAF_NATIVE);
 }
 
+static inline struct netmap_kring *
+netmap_kring_on(struct netmap_adapter *na, u_int q, enum txrx t)
+{
+        struct netmap_kring *kring = NULL;
+
+        if (!nm_native_on(na))
+                return NULL;
+
+        if (t == NR_RX && q < na->num_rx_rings)
+                kring = na->rx_rings[q];
+        else if (t == NR_TX && q < na->num_tx_rings)
+                kring = na->tx_rings[q];
+        else
+                return NULL;
+
+        return (kring->nr_mode == NKR_NETMAP_ON) ? kring : NULL;
+}
+
 static inline int
 nm_iszombie(struct netmap_adapter *na)
 {

From bb351c2ff37d904ac5bf3983c8f3a8d22db40265 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 24 Aug 2020 19:54:27 +0200
Subject: [PATCH 1843/2207] bwrap: forward get_lut request to embedded host
 adapter

---
 sys/dev/netmap/netmap_bdg.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index d896df44f..4f01e23de 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1269,6 +1269,11 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 	struct netmap_adapter *hwna = bna->hwna;
 	int error;
 
+	/* cache the lut in the embedded host adapter */
+	error = netmap_mem_get_lut(hwna->nm_mem, &bna->host.up.na_lut);
+	if (error)
+		return error;
+
 	/* Forward the request to the hwna. It may happen that nobody
 	 * registered hwna yet, so netmap_mem_get_lut() may have not
 	 * been called yet. */

From dbf4b73e36be647c5abc52f8e31ebeb8ac9cb6dd Mon Sep 17 00:00:00 2001
From: jhk 
Date: Thu, 27 Aug 2020 21:25:08 +0200
Subject: [PATCH 1844/2207] libnetmap: nmreq_remove_option: use the correct
 pointer type

---
 libnetmap/nmreq.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index f9a767cd5..8c44dfdfc 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -585,13 +585,13 @@ nmreq_find_option(struct nmreq_header *h, uint32_t t)
 void
 nmreq_remove_option(struct nmreq_header *h, struct nmreq_option *o)
 {
-	uintptr_t *scan;
+	struct nmreq_option **nmo;
 
-	for (scan = &h->nr_options; *scan;
-			scan = &((struct nmreq_option *)*scan)->nro_next) {
-		if (*scan == (uintptr_t)o) {
-			*scan = o->nro_next;
-			o->nro_next = 0;
+	for (nmo = (struct nmreq_option **)&h->nr_options; *nmo != NULL;
+	    nmo = (struct nmreq_option **)&(*nmo)->nro_next) {
+		if (*nmo == o) {
+			*((uint64_t *)(*nmo)) = o->nro_next;
+			o->nro_next = (uint64_t)(uintptr_t)NULL;
 			break;
 		}
 	}

From f386adc50871e2e4efce6b335aff3722f8659230 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 28 Aug 2020 15:08:36 +0200
Subject: [PATCH 1845/2207] linux/ixgbe: patch for Intel 5.8.1 version

---
 LINUX/default-config.mak.in_            |   3 +-
 LINUX/final-patches/intel--ixgbe--5.8.1 | 173 ++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.8.1

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 9f5490014..b6d161e40 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -80,7 +80,8 @@ igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
-ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1),@SRCDIR@/intel-fix.sh ixgbevf,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
+ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1),@SRCDIR@/intel-fix.sh ixgbe,)
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))
diff --git a/LINUX/final-patches/intel--ixgbe--5.8.1 b/LINUX/final-patches/intel--ixgbe--5.8.1
new file mode 100644
index 000000000..a563b9161
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.8.1
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 01e67d7..91f53e1 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 1e3ac19..5ea92e0 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -711,6 +711,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -730,6 +747,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2194,6 +2222,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3661,6 +3699,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4337,6 +4379,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12940,6 +12988,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -12995,6 +13047,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From c3daf06b327a240a9da73c2a100c2c2cf7ca2a0e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 28 Aug 2020 15:08:58 +0200
Subject: [PATCH 1846/2207] linux/ixgbevf: patch for Intel 4.8.1 version

---
 LINUX/final-patches/intel--ixgbevf--4.8.1 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.8.1

diff --git a/LINUX/final-patches/intel--ixgbevf--4.8.1 b/LINUX/final-patches/intel--ixgbevf--4.8.1
new file mode 100644
index 000000000..30e56aaec
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.8.1
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index dc49435..103a5d1 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 1336492..8f43efc 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -343,6 +343,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -363,6 +380,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2066,6 +2104,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2300,6 +2342,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5599,8 +5645,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5641,6 +5689,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index e658a62..ede68df 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 3d49b490a3998522823e938ccbd23343e174227e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 28 Aug 2020 15:07:41 +0200
Subject: [PATCH 1847/2207] linux/i40e: patch for Intel 2.12.6 version

---
 LINUX/default-config.mak.in_            |   1 +
 LINUX/final-patches/intel--i40e--2.12.6 | 167 ++++++++++++++++++++++++
 2 files changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.12.6

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index b6d161e40..959810f31 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -82,6 +82,7 @@ igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1),@SRCDIR@/intel-fix.sh ixgbe,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6),@SRCDIR@/intel-fix.sh i40e,)
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))
diff --git a/LINUX/final-patches/intel--i40e--2.12.6 b/LINUX/final-patches/intel--i40e--2.12.6
new file mode 100644
index 000000000..8d9b999f3
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.12.6
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 81f5ab9..85bfb8c 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 6750c3c..f6e3fd1 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -148,6 +148,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3619,6 +3624,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3672,6 +3681,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3700,6 +3713,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -14167,6 +14185,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14539,6 +14563,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index e3eb496..39c987d 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -974,6 +978,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2745,6 +2754,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From 9de0edd4e46b4f22c96dbc4a165d15c00cc1c0ac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 28 Aug 2020 15:08:05 +0200
Subject: [PATCH 1848/2207] linux/igb: patch for Intel 5.3.6 version

---
 LINUX/default-config.mak.in_          |   2 +-
 LINUX/final-patches/intel--igb--5.3.6 | 138 ++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--igb--5.3.6

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 959810f31..0922d83fa 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -78,7 +78,7 @@ endef
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
-igb@prepare := $(if $(filter $(igb@v),5.3.5.61),@SRCDIR@/intel-fix.sh igb,)
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1),@SRCDIR@/intel-fix.sh ixgbe,)
diff --git a/LINUX/final-patches/intel--igb--5.3.6 b/LINUX/final-patches/intel--igb--5.3.6
new file mode 100644
index 000000000..b840f93f0
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.3.6
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 811a634..2559d39 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 54ec261..9252c05 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3203,6 +3207,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3408,6 +3416,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3820,6 +3832,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7505,6 +7520,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8521,6 +8541,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8840,6 +8865,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From b93b272b984204ec8b3d341714196cfb91a7c9d3 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 1 Sep 2020 07:58:25 +0200
Subject: [PATCH 1849/2207] libnetmap: add missing copyright headers

---
 libnetmap/nmctx-pthreads.c | 29 +++++++++++++++++++++++++++++
 libnetmap/nmctx.c          | 29 +++++++++++++++++++++++++++++
 libnetmap/nmport.c         | 29 +++++++++++++++++++++++++++++
 libnetmap/nmreq.c          | 29 +++++++++++++++++++++++++++++
 4 files changed, 116 insertions(+)

diff --git a/libnetmap/nmctx-pthreads.c b/libnetmap/nmctx-pthreads.c
index 7253abf9c..2943b7ccc 100644
--- a/libnetmap/nmctx-pthreads.c
+++ b/libnetmap/nmctx-pthreads.c
@@ -1,3 +1,32 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include 
 #include 
 #include 
diff --git a/libnetmap/nmctx.c b/libnetmap/nmctx.c
index e9f9238fa..5bb52df52 100644
--- a/libnetmap/nmctx.c
+++ b/libnetmap/nmctx.c
@@ -1,3 +1,32 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include 
 #include 
 #include 
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 7ea1edf6c..adf205ae5 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -1,3 +1,32 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include 
 #include 
 #include 
diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index 8c44dfdfc..f3207fac0 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -1,3 +1,32 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Universita` di Pisa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include 
 #include 
 #include 

From 4edac94585685d9496c918b729623c0deab36c4b Mon Sep 17 00:00:00 2001
From: Carl Smith 
Date: Wed, 2 Sep 2020 16:43:33 +1200
Subject: [PATCH 1850/2207] linux: Use GFP_USER for contiguous memory
 allocation

GFP_ATOMIC prevents memory reclaim. In the scenario where the device
has been running for a while the number of free pages can be low,
but the file cache can be large. Without allowing memory reclaim
we would get "page allocation failures".
---
 LINUX/bsd_glue.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 97e026fbe..bfbce9ba9 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -416,7 +416,7 @@ static inline int ilog2(uint64_t n)
 #define contigmalloc(sz, ty, flags, a, b, pgsz, c) ({		\
 	unsigned int order_ =					\
 		ilog2(roundup_pow_of_two(sz)/PAGE_SIZE);	\
-	struct page *p_ = alloc_pages(GFP_ATOMIC | __GFP_ZERO,  \
+	struct page *p_ = alloc_pages(GFP_USER | __GFP_ZERO,  \
 		order_);					\
 	if (p_ != NULL) 					\
 		split_page(p_, order_);				\

From 183c2fd926c3484bd1c890bc50fdebb7a350ada2 Mon Sep 17 00:00:00 2001
From: Arne Welzel 
Date: Tue, 8 Sep 2020 16:07:59 +0200
Subject: [PATCH 1851/2207] linux/nm_os_vi_persist: Create new interface in
 net_ns of current task

Attempting to run a pipe-only lb invocation in a non-root network
namespace fails

    $ sudo unshare -n
    $ lb -i in}0 -p out:4
    171.051996 main [671] interface is in}0
    171.054191 nm_open [965] NIOCREGIF failed: No such device or address netmap:in}0
    171.054199 main [802] cannot open netmap:in}0

The `in` interface is, however, created in the root namespace.

Set the network namespace of the new device to the one of the current task
before registering it to solve this.
---
 LINUX/netmap_linux.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 8a4ea5b17..3e9d6e40f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2358,8 +2358,10 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 		error = ENOMEM;
 		goto err_put;
 	}
-	dev_net_set(ifp, &init_net);
+#ifdef CONFIG_NET_NS
+	dev_net_set(ifp, current->nsproxy->net_ns);
 	ifp->features |= NETIF_F_NETNS_LOCAL; /* just for safety */
+#endif
 	ifp->dev.driver = &linux_dummy_drv;
 	error = register_netdev(ifp);
 	if (error < 0) {

From 80ba4f149a48d24041e951e28ab3406296badb4f Mon Sep 17 00:00:00 2001
From: Arne Welzel 
Date: Fri, 11 Sep 2020 01:34:09 +0200
Subject: [PATCH 1852/2207] netmap.h/freebsd: Include  instead of
  when compiling with C++

Compiling the following C++ program on FreeBSD (11.4 / 12.1) currently fails.
This affects the netmap plugin for Zeek [1].

    $ cat test_netmap.cc
    #include 

    extern "C" {
    #define NETMAP_WITH_LIBS
    #include 
    }

    int main(int argc, char *argv[])
    {
            std::cout << "netmap" << std::endl;
    }

    $ clang++  ./test_netmap.cc
    In file included from ./test_netmap.cc:5:
    In file included from /usr/include/net/netmap_user.h:100:
    In file included from /usr/include/net/netmap.h:814:
    /usr/include/stdatomic.h:187:17: error: unknown type name '_Bool'
    typedef _Atomic(_Bool)                  atomic_bool;
                    ^
    /usr/include/stdatomic.h:187:26: error: C++ requires a type specifier for all declarations
    typedef _Atomic(_Bool)                  atomic_bool;

Similar issues [2,3] (though GCC) suggest to use  instead
of  for C++.

[1] https://github.com/zeek/bro-netmap/issues/11
[2] https://bugs.python.org/issue23644
[3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932#c4
---
 sys/net/netmap.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 1607d8ecc..b9500da3a 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -832,7 +832,16 @@ static inline void nm_ldld_barrier(void)
 #define nm_ldld_barrier	atomic_thread_fence_acq
 #define nm_stld_barrier	atomic_thread_fence_seq_cst
 #else  /* !_KERNEL */
+
+#ifdef __cplusplus
+#include 
+using std::memory_order_release;
+using std::memory_order_acquire;
+
+#else /* __cplusplus */
 #include 
+#endif /* __cplusplus */
+
 static inline void nm_stst_barrier(void)
 {
 	atomic_thread_fence(memory_order_release);

From 5b19e786d56dcca24c3378a06d2a5e51c0a031c6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Sep 2020 13:45:38 +0200
Subject: [PATCH 1853/2207] libnetmap: enable -O2

---
 libnetmap/GNUmakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libnetmap/GNUmakefile b/libnetmap/GNUmakefile
index 1b9e4f075..3828abed1 100644
--- a/libnetmap/GNUmakefile
+++ b/libnetmap/GNUmakefile
@@ -1,7 +1,7 @@
 SRCDIR ?= ../
 PREFIX ?= usr/local
 CFLAGS=-O2 -pipe -Wall -Werror
-CFLAGS=-g
+CFLAGS +=-g
 CFLAGS += -I $(SRCDIR)/sys
 VPATH = $(SRCDIR)/libnetmap
 SRCS=$(notdir $(wildcard $(SRCDIR)/libnetmap/*.c))

From 0bc24ddd04b0070a8ef8a23dc4dfacb45d3f2a9a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 13 Sep 2020 13:50:32 +0200
Subject: [PATCH 1854/2207] lb: add NS_MOREFRAG support

---
 apps/lb/lb.c | 106 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 90 insertions(+), 16 deletions(-)

diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 26a64e67f..eeffdbcdd 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -88,7 +88,7 @@ struct compact_ipv6_hdr {
 #define DEF_BATCH	2048
 #define DEF_WAIT_LINK	2
 #define DEF_STATS_INT	600
-#define BUF_REVOKE	100
+#define BUF_REVOKE	150
 #define STAT_MSG_MAXSIZE 1024
 
 struct {
@@ -481,6 +481,28 @@ void init_groups(void)
 	g->last = 1;
 }
 
+
+/* To support packets that span multiple slots (NS_MOREFRAG) we
+ * need to make sure of the following:
+ *
+ * - all fragments of the same packet must go to the same output pipe
+ * - when dropping, all fragments of the same packet must be dropped
+ *
+ * For the former point we remember and reuse the last hash computed
+ * in each input ring, and only update it when NS_MOREFRAG was not
+ * set in the last received slot (this marks the start of a new packet).
+ *
+ * For the latter point, we only update the output ring head pointer
+ * when an entire packet has been forwarded. We keep a shadow_head
+ * pointer to know where to put the next partial fragment and,
+ * when the need to drop arises, we roll it back to head.
+ */
+struct morefrag {
+	uint16_t last_flag;	/* for intput rings */
+	uint32_t last_hash;	/* for input rings */
+	uint32_t shadow_head;	/* for output rings */
+};
+
 /* push the packet described by slot rs to the group g.
  * This may cause other buffers to be pushed down the
  * chain headed by g.
@@ -493,21 +515,28 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs)
 	struct port_des *port = &g->ports[output_port];
 	struct netmap_ring *ring = port->ring;
 	struct overflow_queue *q = port->oq;
+	struct morefrag *mf = (struct morefrag *)ring->sem;
+	uint16_t curmf = rs->flags & NS_MOREFRAG;
 
 	/* Move the packet to the output pipe, unless there is
 	 * either no space left on the ring, or there is some
 	 * packet still in the overflow queue (since those must
 	 * take precedence over the new one)
 	*/
-	if (ring->head != ring->tail && (q == NULL || oq_empty(q))) {
-		struct netmap_slot *ts = &ring->slot[ring->head];
+	if (mf->shadow_head != ring->tail && (q == NULL || oq_empty(q))) {
+		struct netmap_slot *ts = &ring->slot[mf->shadow_head];
 		struct netmap_slot old_slot = *ts;
 
 		ts->buf_idx = rs->buf_idx;
 		ts->len = rs->len;
-		ts->flags |= NS_BUF_CHANGED;
+		ts->flags = rs->flags | NS_BUF_CHANGED;
 		ts->ptr = rs->ptr;
-		ring->head = nm_ring_next(ring, ring->head);
+		mf->shadow_head = nm_ring_next(ring, mf->shadow_head);
+		if (!curmf) {
+			ring->head = mf->shadow_head;
+		}
+		ND("curmf %2x ts->flags %2x shadow_head %3u head %3u tail %3u",
+				curmf, ts->flags, mf->shadow_head, ring->head, ring->tail);
 		port->ctr.bytes += rs->len;
 		port->ctr.pkts++;
 		forwarded++;
@@ -516,9 +545,20 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs)
 
 	/* use the overflow queue, if available */
 	if (q == NULL || oq_full(q)) {
+		uint32_t scan;
 		/* no space left on the ring and no overflow queue
 		 * available: we are forced to drop the packet
 		 */
+
+		/* drop previous fragments, if any */
+		for (scan = ring->head; scan != mf->shadow_head;
+				scan = nm_ring_next(ring, scan)) {
+			struct netmap_slot *ts = &ring->slot[scan];
+			dropped++;
+			port->ctr.drop_bytes += ts->len;
+		}
+		mf->shadow_head = ring->head;
+
 		dropped++;
 		port->ctr.drop++;
 		port->ctr.drop_bytes += rs->len;
@@ -550,9 +590,12 @@ uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs)
 
 		/* move the oldest BUF_REVOKE buffers from the
 		 * lp queue to the free queue
+		 *
+		 * We cannot revoke a partially received packet.
+		 * To make thinks simple we make sure to leave
+		 * at least NETMAP_MAX_FRAGS slots in the queue.
 		 */
-		// XXX optimize this cycle
-		for (j = 0; lp->oq->n && j < BUF_REVOKE; j++) {
+		for (j = 0; lp->oq->n > NETMAP_MAX_FRAGS && j < BUF_REVOKE; j++) {
 			struct netmap_slot tmp = oq_deq(lp->oq);
 
 			dropped++;
@@ -779,10 +822,16 @@ int main(int argc, char **argv)
 					k + 1, g->pipename, g->first_id + k, g->pipename, g->first_id + k);
 				return (1);
 			} else {
+				struct morefrag *mf;
+
 				D("successfully opened pipe #%d %s (tx slots: %d)",
 				  k + 1, p->interface, p->nmd->reg.nr_tx_slots);
 				p->ring = NETMAP_TXRING(p->nmd->nifp, 0);
 				p->last_tail = nm_ring_next(p->ring, p->ring->tail);
+				mf = (struct morefrag *)p->ring->sem;
+				mf->last_flag = 0;	/* unused */
+				mf->last_hash = 0;	/* unused */
+				mf->shadow_head = p->ring->head;
 			}
 			D("zerocopy %s",
 			  (rxport->nmd->mem == p->nmd->mem) ? "enabled" : "disabled");
@@ -835,6 +884,16 @@ int main(int argc, char **argv)
 	if (glob_arg.stdout_interval > 0 && glob_arg.stdout_interval < poll_timeout)
 		poll_timeout = glob_arg.stdout_interval;
 
+	/* initialize the morefrag structures for the input rings */
+	for (i = rxport->nmd->first_rx_ring; i <= rxport->nmd->last_rx_ring; i++) {
+		struct netmap_ring *rxring = NETMAP_RXRING(rxport->nmd->nifp, i);
+		struct morefrag *mf = (struct morefrag *)rxring->sem;
+
+		mf->last_flag = 0;
+		mf->last_hash = 0;
+		mf->shadow_head = 0; /* unused */
+	}
+
 	while (!do_abort) {
 		u_int polli = 0;
 		iter++;
@@ -863,7 +922,7 @@ int main(int argc, char **argv)
 		pollfd[polli].revents = 0;
 		++polli;
 
-		//RD(5, "polling %d file descriptors", polli+1);
+		ND(5, "polling %d file descriptors", polli);
 		rv = poll(pollfd, polli, poll_timeout);
 		if (rv <= 0) {
 			if (rv < 0 && errno != EAGAIN && errno != EINTR)
@@ -895,7 +954,7 @@ int main(int argc, char **argv)
 					struct netmap_slot *rs = &ring->slot[last];
 					// XXX less aggressive?
 					rs->buf_idx = forward_packet(g + 1, rs);
-					rs->flags |= NS_BUF_CHANGED;
+					rs->flags = NS_BUF_CHANGED;
 					rs->ptr = 0;
 				}
 				p->last_tail = last;
@@ -911,27 +970,34 @@ int main(int argc, char **argv)
 			for (i = 0; i < npipes; i++) {
 				struct port_des *p = &ports[i];
 				struct overflow_queue *q = p->oq;
-				uint32_t j, lim;
+				uint32_t j;
+				int64_t lim;
 				struct netmap_ring *ring;
 				struct netmap_slot *slot;
+				struct morefrag *mf;
 
 				if (oq_empty(q))
 					continue;
 				ring = p->ring;
-				lim = nm_ring_space(ring);
+				mf = (struct morefrag *)ring->sem;
+				lim = ring->tail - mf->shadow_head;
 				if (!lim)
 					continue;
+				if (lim < 0)
+					lim += ring->num_slots;
 				if (q->n < lim)
 					lim = q->n;
 				for (j = 0; j < lim; j++) {
 					struct netmap_slot s = oq_deq(q), tmp;
 					tmp.ptr = 0;
-					slot = &ring->slot[ring->head];
+					slot = &ring->slot[mf->shadow_head];
 					tmp.buf_idx = slot->buf_idx;
 					oq_enq(freeq, &tmp);
 					*slot = s;
 					slot->flags |= NS_BUF_CHANGED;
-					ring->head = nm_ring_next(ring, ring->head);
+					mf->shadow_head = nm_ring_next(ring, mf->shadow_head);
+					if (!(slot->flags & NS_MOREFRAG))
+						ring->head = mf->shadow_head;
 				}
 			}
 		}
@@ -940,6 +1006,7 @@ int main(int argc, char **argv)
 		int batch = 0;
 		for (i = rxport->nmd->first_rx_ring; i <= rxport->nmd->last_rx_ring; i++) {
 			struct netmap_ring *rxring = NETMAP_RXRING(rxport->nmd->nifp, i);
+			struct morefrag *mf = (struct morefrag *)rxring->sem;
 
 			//D("prepare to scan rings");
 			int next_head = rxring->head;
@@ -952,7 +1019,15 @@ int main(int argc, char **argv)
 				received_bytes += rs->len;
 
 				// CHOOSE THE CORRECT OUTPUT PIPE
-				rs->ptr = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B');
+				// If the previous slot had NS_MOREFRAG set, this is another
+				// fragment of the last packet and it should go to the same
+				// output pipe as before.
+				if (!mf->last_flag) {
+					// 'B' is just a hashing seed
+					mf->last_hash = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B');
+				}
+				mf->last_flag = rs->flags & NS_MOREFRAG;
+				rs->ptr = mf->last_hash;
 				if (rs->ptr == 0) {
 					non_ip++; // XXX ??
 				}
@@ -961,9 +1036,8 @@ int main(int argc, char **argv)
 				next_slot = &rxring->slot[next_head];
 				next_buf = NETMAP_BUF(rxring, next_slot->buf_idx);
 				__builtin_prefetch(next_buf);
-				// 'B' is just a hashing seed
 				rs->buf_idx = forward_packet(g, rs);
-				rs->flags |= NS_BUF_CHANGED;
+				rs->flags = NS_BUF_CHANGED;
 				rxring->head = rxring->cur = next_head;
 
 				batch++;

From da8f9e09ac4b4500a601435b79a584944ce3fe06 Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Wed, 16 Sep 2020 16:38:24 -0400
Subject: [PATCH 1855/2207] pkt-gen: minor corrections to documentation

---
 apps/pkt-gen/pkt-gen.8 | 12 ++++++------
 apps/pkt-gen/pkt-gen.c | 16 ++++++++--------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
index 74226cf5d..2d5365884 100644
--- a/apps/pkt-gen/pkt-gen.8
+++ b/apps/pkt-gen/pkt-gen.8
@@ -95,7 +95,7 @@ for server-side ping-pong operation.
 .It Fl n Ar count
 Number of iterations of the
 .Nm
-function, with 0 meaning infinite).
+function (with 0 meaning infinite).
 In case of
 .Ar tx
 or
@@ -147,10 +147,10 @@ is larger than one, each thread handles a single TX ring (in
 .Ar tx
 mode), a single RX ring (in
 .Ar rx
-mode), or a TX/RX ring couple.
+mode), or a TX/RX ring pair.
 The number of
 .Ar threads
-must be less or equal than the number of TX (or RX) ring available
+must be less than or equal to the number of TX (or RX) rings available
 in the device specified by
 .Ar interface .
 .It Fl T Ar report_ms
@@ -158,7 +158,7 @@ Number of milliseconds between reports.
 .It Fl w Ar wait_for_link_time
 Number of seconds to wait before starting the
 .Nm
-function, useuful to make sure that the network link is up.
+function, useful to make sure that the network link is up.
 A network device driver may take some time to enter netmap mode, or
 to create a new transmit/receive ring pair when
 .Xr netmap 4
@@ -168,7 +168,7 @@ Packet transmission rate.
 Not setting the packet transmission rate tells
 .Nm
 to transmit packets as quickly as possible.
-On servers from 2010 on-wards
+On servers from 2010 onward
 .Xr netmap 4
 is able to completely use all of the bandwidth of a 10 or 40Gbps link,
 so this option should be used unless your intention is to saturate the link.
@@ -230,7 +230,7 @@ This adds 4 bytes of CRC and 20 bytes of framing to each packet.
 .It Fl C Ar tx_slots[,rx_slots[,tx_rings[,rx_rings]]]
 Configuration in terms of number of rings and slots to be used when
 opening the netmap port.
-Such configuration has effect on software ports
+Such configuration has an effect on software ports
 created on the fly, such as VALE ports and netmap pipes.
 The configuration may consist of 1 to 4 numbers separated by commas:
 .Ar tx_slots , rx_slots , tx_rings , rx_rings .
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index ef876f4fd..d78ebb3a2 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -281,7 +281,7 @@ struct glob_arg {
 #define OPT_TS		16	/* add a timestamp */
 #define OPT_INDIRECT	32	/* use indirect buffers, tx only */
 #define OPT_DUMP	64	/* dump rx/tx traffic */
-#define OPT_RUBBISH	256	/* send wathever the buffers contain */
+#define OPT_RUBBISH	256	/* send whatever the buffers contain */
 #define OPT_RANDOM_SRC  512
 #define OPT_RANDOM_DST  1024
 #define OPT_PPS_STATS   2048
@@ -2374,7 +2374,7 @@ usage(int errcode)
 "             for client-side ping-pong operation, and pong for server-side ping-pong operation.\n"
 "\n"
 "     -n count\n"
-"             Number of iterations of the pkt-gen function, with 0 meaning infinite).  In case of tx or rx,\n"
+"             Number of iterations of the pkt-gen function (with 0 meaning infinite).  In case of tx or rx,\n"
 "             count is the number of packets to receive or transmit.  In case of ping or pong, count is the\n"
 "             number of ping-pong transactions.\n"
 "\n"
@@ -2411,20 +2411,20 @@ usage(int errcode)
 "     -p threads\n"
 "             Number of threads to use.  By default, only a single thread is used to handle all the netmap\n"
 "             rings.  If threads is larger than one, each thread handles a single TX ring (in tx mode), a\n"
-"             single RX ring (in rx mode), or a TX/RX ring couple.  The number of threads must be less or\n"
-"             equal than the number of TX (or RX) ring available in the device specified by interface.\n"
+"             single RX ring (in rx mode), or a TX/RX ring pair.  The number of threads must be less than or\n"
+"             equal to the number of TX (or RX) rings available in the device specified by interface.\n"
 "\n"
 "     -T report_ms\n"
 "             Number of milliseconds between reports.\n"
 "\n"
 "     -w wait_for_link_time\n"
-"             Number of seconds to wait before starting the pkt-gen function, useuful to make sure that the\n"
+"             Number of seconds to wait before starting the pkt-gen function, useful to make sure that the\n"
 "             network link is up.  A network device driver may take some time to enter netmap mode, or to\n"
 "             create a new transmit/receive ring pair when netmap(4) requests one.\n"
 "\n"
 "     -R rate\n"
 "             Packet transmission rate.  Not setting the packet transmission rate tells pkt-gen to transmit\n"
-"             packets as quickly as possible.  On servers from 2010 on-wards netmap(4) is able to com-\n"
+"             packets as quickly as possible.  On servers from 2010 onward netmap(4) is able to com-\n"
 "             pletely use all of the bandwidth of a 10 or 40Gbps link, so this option should be used unless\n"
 "             your intention is to saturate the link.\n"
 "\n"
@@ -2470,7 +2470,7 @@ usage(int errcode)
 "\n"
 "     -C tx_slots[,rx_slots[,tx_rings[,rx_rings]]]\n"
 "             Configuration in terms of number of rings and slots to be used when opening the netmap port.\n"
-"             Such configuration has effect on software ports created on the fly, such as VALE ports and\n"
+"             Such configuration has an effect on software ports created on the fly, such as VALE ports and\n"
 "             netmap pipes.  The configuration may consist of 1 to 4 numbers separated by commas: tx_slots,\n"
 "             rx_slots, tx_rings, rx_rings.  Missing numbers or zeroes stand for default values.  As an\n"
 "             additional convenience, if exactly one number is specified, then this is assigned to both\n"
@@ -2486,7 +2486,7 @@ usage(int errcode)
 "				OPT_INDIRECT	32 (use indirect buffers)\n"
 "				OPT_DUMP	64 (dump rx/tx traffic)\n"
 "				OPT_RUBBISH	256\n"
-"					(send wathever the buffers contain)\n"
+"					(send whatever the buffers contain)\n"
 "				OPT_RANDOM_SRC  512\n"
 "				OPT_RANDOM_DST  1024\n"
 "				OPT_PPS_STATS   2048\n"

From 197bf9946995dd16a4cef29180dfab3f3c8728d7 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 22 Sep 2020 22:16:55 +0200
Subject: [PATCH 1856/2207] use uintptr_t as intermediate cast between uint64_t
 and void*

---
 libnetmap/libnetmap.h | 4 ++--
 libnetmap/nmport.c    | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index ed9edbfad..984ca3795 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -610,9 +610,9 @@ struct nmreq_option *nmreq_find_option(struct nmreq_header *, uint32_t);
 void nmreq_free_options(struct nmreq_header *);
 const char* nmreq_option_name(uint32_t);
 #define nmreq_foreach_option(h_, o_) \
-	for ((o_) = (struct nmreq_option *)((h_)->nr_options);\
+	for ((o_) = (struct nmreq_option *)((uintptr_t)((h_)->nr_options));\
 	     (o_) != NULL;\
-	     (o_) = (struct nmreq_option *)((o_)->nro_next))
+	     (o_) = (struct nmreq_option *)((uintptr_t)((o_)->nro_next)))
 
 /* nmctx manipulation */
 
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index adf205ae5..3e0c2a632 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -685,7 +685,7 @@ nmport_mmap(struct nmport_d *d)
 		}
 		memset(m, 0, sizeof(*m));
 		if (d->extmem != NULL) {
-			m->mem = (void *)d->extmem->nro_usrptr;
+			m->mem = (void *)((uintptr_t)d->extmem->nro_usrptr);
 			m->size = d->extmem->nro_info.nr_memsize;
 			m->is_extmem = 1;
 		} else {

From 66891400135f406e71c18649b1887a046b6f6ea5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Kaniewski?= 
Date: Sun, 27 Sep 2020 21:03:54 +0200
Subject: [PATCH 1857/2207] Fix constness warnings generated when "-Wcast-qual"
 compiler option is used.

---
 sys/net/netmap_user.h | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 098dc52aa..fda076497 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -307,13 +307,10 @@ struct nm_desc {
  * when the descriptor is open correctly, d->self == d
  * Eventually we should also use some magic number.
  */
-#define P2NMD(p)		((struct nm_desc *)(p))
+#define P2NMD(p)		((const struct nm_desc *)(p))
 #define IS_NETMAP_DESC(d)	((d) && P2NMD(d)->self == P2NMD(d))
 #define NETMAP_FD(d)		(P2NMD(d)->fd)
 
-
-
-
 /*
  * The callback, invoked on each received packet. Same as libpcap
  */
@@ -638,7 +635,7 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 	const char *vpname = NULL;
 	u_int namelen;
 	uint32_t nr_ringid = 0, nr_flags;
-	char errmsg[MAXERRMSG] = "";
+	char errmsg[MAXERRMSG] = "", *tmp;
 	long num;
 	uint16_t nr_arg2 = 0;
 	enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK, P_MEMID } p_state;
@@ -735,12 +732,13 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 			port++;
 			break;
 		case P_GETNUM:
-			num = strtol(port, (char **)&port, 10);
+			num = strtol(port, &tmp, 10);
 			if (num < 0 || num >= NETMAP_RING_MASK) {
 				snprintf(errmsg, MAXERRMSG, "'%ld' out of range [0, %d)",
 						num, NETMAP_RING_MASK);
 				goto fail;
 			}
+			port = tmp;
 			nr_ringid = num & NETMAP_RING_MASK;
 			p_state = P_RNGSFXOK;
 			break;
@@ -782,11 +780,12 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 				snprintf(errmsg, MAXERRMSG, "double setting of memid");
 				goto fail;
 			}
-			num = strtol(port, (char **)&port, 10);
+			num = strtol(port, &tmp, 10);
 			if (num <= 0) {
 				snprintf(errmsg, MAXERRMSG, "invalid memid %ld, must be >0", num);
 				goto fail;
 			}
+			port = tmp;
 			nr_arg2 = num;
 			p_state = P_RNGSFXOK;
 			break;
@@ -1068,7 +1067,7 @@ nm_inject(struct nm_desc *d, const void *buf, size_t size)
 			ring->slot[i].flags = NS_MOREFRAG;
 			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
 			i = nm_ring_next(ring, i);
-			buf = (char *)buf + ring->nr_buf_size;
+			buf = (const char *)buf + ring->nr_buf_size;
 		}
 		idx = ring->slot[i].buf_idx;
 		ring->slot[i].len = rem;

From e12dda60bc11f6696b54fcd05c44f5eb2948f9bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Kaniewski?= 
Date: Sun, 27 Sep 2020 21:08:12 +0200
Subject: [PATCH 1858/2207] Fix the example code.

---
 share/man/man4/netmap.4 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index cbdd55435..327705f7e 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -1038,7 +1038,7 @@ void receiver(void)
     for (;;) {
 	poll(&fds, 1, -1);
         while ( (buf = nm_nextpkt(d, &h)) )
-	    consume_pkt(buf, h->len);
+	    consume_pkt(buf, h.len);
     }
     nm_close(d);
 }

From 985278a328a7519bd3801be320346f4b40da02dc Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 3 Oct 2020 15:12:30 +0200
Subject: [PATCH 1859/2207] apps: fix multiple compilation warnings

---
 apps/bridge/bridge.c     |  4 ++--
 apps/include/ctrs.h      |  6 ++---
 apps/lb/lb.c             | 39 +++++++++++++++---------------
 apps/lb/pkt_hash.c       | 52 ++++++++++++++++++++--------------------
 apps/nmreplay/nmreplay.c | 33 ++++++++++++-------------
 apps/pkt-gen/pkt-gen.c   | 22 ++++++++---------
 6 files changed, 79 insertions(+), 77 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index e826f2498..4c7290866 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -17,7 +17,7 @@
 #include 
 #include 
 
-int verbose = 0;
+static int verbose = 0;
 
 static int do_abort = 0;
 static int zerocopy = 1; /* enable zerocopy if possible */
@@ -34,7 +34,7 @@ sigint_h(int sig)
 /*
  * how many packets on this set of queues ?
  */
-int
+static int
 pkt_queued(struct nmport_d *d, int tx)
 {
 	u_int i, tot = 0;
diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h
index b8bb8c986..7e0265b48 100644
--- a/apps/include/ctrs.h
+++ b/apps/include/ctrs.h
@@ -20,12 +20,12 @@ struct my_ctrs {
  * Caller has to make sure that the buffer is large enough.
  */
 static const char *
-norm2(char *buf, double val, char *fmt, int normalize)
+norm2(char *buf, double val, const char *fmt, int normalize)
 {
-	char *units[] = { "", "K", "M", "G", "T" };
+	const char *units[] = { "", "K", "M", "G", "T" };
 	u_int i;
 	if (normalize)
-		for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++)
+		for (i = 0; val >=1000 && i < sizeof(units)/sizeof(const char *) - 1; i++)
 			val /= 1000;
 	else
 		i=0;
diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index eeffdbcdd..251d53fb0 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -91,7 +91,7 @@ struct compact_ipv6_hdr {
 #define BUF_REVOKE	150
 #define STAT_MSG_MAXSIZE 1024
 
-struct {
+static struct {
 	char ifname[MAX_IFNAMELEN + 1];
 	char base_name[MAX_IFNAMELEN + 1];
 	int netmap_fd;
@@ -117,7 +117,7 @@ struct overflow_queue {
 	uint32_t size;
 };
 
-struct overflow_queue *freeq;
+static struct overflow_queue *freeq;
 
 static inline int
 oq_full(struct overflow_queue *q)
@@ -162,12 +162,12 @@ oq_deq(struct overflow_queue *q)
 
 static volatile int do_abort = 0;
 
-uint64_t dropped = 0;
-uint64_t forwarded = 0;
-uint64_t received_bytes = 0;
-uint64_t received_pkts = 0;
-uint64_t non_ip = 0;
-uint32_t freeq_n = 0;
+static uint64_t dropped = 0;
+static uint64_t forwarded = 0;
+static uint64_t received_bytes = 0;
+static uint64_t received_pkts = 0;
+static uint64_t non_ip = 0;
+static uint32_t freeq_n = 0;
 
 struct port_des {
 	char interface[MAX_PORTNAMELEN];
@@ -180,7 +180,7 @@ struct port_des {
 	struct group_des *group;
 };
 
-struct port_des *ports;
+static struct port_des *ports;
 
 /* each group of pipes receives all the packets */
 struct group_des {
@@ -192,7 +192,7 @@ struct group_des {
 	int custom_port;
 };
 
-struct group_des *groups;
+static struct group_des *groups;
 
 /* statistcs */
 struct counters {
@@ -207,7 +207,7 @@ struct counters {
 #define COUNTERS_FULL	1
 };
 
-struct counters counters_buf;
+static struct counters counters_buf;
 
 static void *
 print_stats(void *arg)
@@ -389,7 +389,7 @@ static void sigint_h(int sig)
 	signal(SIGINT, SIG_DFL);
 }
 
-void usage()
+static void usage()
 {
 	printf("usage: lb [options]\n");
 	printf("where options are:\n");
@@ -406,9 +406,9 @@ void usage()
 }
 
 static int
-parse_pipes(char *spec)
+parse_pipes(const char *spec)
 {
-	char *end = index(spec, ':');
+	const char *end = index(spec, ':');
 	static int max_groups = 0;
 	struct group_des *g;
 
@@ -460,7 +460,8 @@ parse_pipes(char *spec)
 }
 
 /* complete the initialization of the groups data structure */
-void init_groups(void)
+static void
+init_groups(void)
 {
 	int i, j, t = 0;
 	struct group_des *g = NULL;
@@ -508,7 +509,8 @@ struct morefrag {
  * chain headed by g.
  * Return a free buffer.
  */
-uint32_t forward_packet(struct group_des *g, struct netmap_slot *rs)
+static uint32_t
+forward_packet(struct group_des *g, struct netmap_slot *rs)
 {
 	uint32_t hash = rs->ptr;
 	uint32_t output_port = hash % g->nports;
@@ -939,7 +941,6 @@ int main(int argc, char **argv)
 		 */
 		for (i = glob_arg.num_groups - 1U; i > 0; i--) {
 			struct group_des *g = &groups[i - 1];
-			int j;
 
 			for (j = 0; j < g->nports; j++) {
 				struct port_des *p = &g->ports[j];
@@ -970,7 +971,7 @@ int main(int argc, char **argv)
 			for (i = 0; i < npipes; i++) {
 				struct port_des *p = &ports[i];
 				struct overflow_queue *q = p->oq;
-				uint32_t j;
+				uint32_t k;
 				int64_t lim;
 				struct netmap_ring *ring;
 				struct netmap_slot *slot;
@@ -987,7 +988,7 @@ int main(int argc, char **argv)
 					lim += ring->num_slots;
 				if (q->n < lim)
 					lim = q->n;
-				for (j = 0; j < lim; j++) {
+				for (k = 0; k < lim; k++) {
 					struct netmap_slot s = oq_deq(q), tmp;
 					tmp.ptr = 0;
 					slot = &ring->slot[mf->shadow_head];
diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index ba7be296c..3071935e1 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -146,7 +146,7 @@ static uint32_t decode_gre_hash(const uint8_t *, uint8_t, uint8_t);
  ** Parser + hash function for the IPv4 packet
  **/
 static uint32_t
-decode_ip_n_hash(struct ip *iph, uint8_t hash_split, uint8_t seed)
+decode_ip_n_hash(const struct ip *iph, uint8_t hash_split, uint8_t seed)
 {
 	uint32_t rc = 0;
 
@@ -156,19 +156,19 @@ decode_ip_n_hash(struct ip *iph, uint8_t hash_split, uint8_t seed)
 			ntohs(0xFFFD) + seed,
 			ntohs(0xFFFE) + seed);
 	} else {
-		struct tcphdr *tcph = NULL;
-		struct udphdr *udph = NULL;
+		const struct tcphdr *tcph = NULL;
+		const struct udphdr *udph = NULL;
 
 		switch (iph->ip_p) {
 		case IPPROTO_TCP:
-			tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ip_hl<<2));
+			tcph = (const struct tcphdr *)((const uint8_t *)iph + (iph->ip_hl<<2));
 			rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
 					 ntohl(iph->ip_dst.s_addr),
 					 ntohs(tcph->th_sport) + seed,
 					 ntohs(tcph->th_dport) + seed);
 			break;
 		case IPPROTO_UDP:
-			udph = (struct udphdr *)((uint8_t *)iph + (iph->ip_hl<<2));
+			udph = (const struct udphdr *)((const uint8_t *)iph + (iph->ip_hl<<2));
 			rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
 					 ntohl(iph->ip_dst.s_addr),
 					 ntohs(udph->uh_sport) + seed,
@@ -176,11 +176,11 @@ decode_ip_n_hash(struct ip *iph, uint8_t hash_split, uint8_t seed)
 			break;
 		case IPPROTO_IPIP:
 			/* tunneling */
-			rc = decode_ip_n_hash((struct ip *)((uint8_t *)iph + (iph->ip_hl<<2)),
+			rc = decode_ip_n_hash((const struct ip *)((const uint8_t *)iph + (iph->ip_hl<<2)),
 					      hash_split, seed);
 			break;
 		case IPPROTO_GRE:
-			rc = decode_gre_hash((uint8_t *)iph + (iph->ip_hl<<2),
+			rc = decode_gre_hash((const uint8_t *)iph + (iph->ip_hl<<2),
 					hash_split, seed);
 			break;
 		case IPPROTO_ICMP:
@@ -206,7 +206,7 @@ decode_ip_n_hash(struct ip *iph, uint8_t hash_split, uint8_t seed)
  ** Parser + hash function for the IPv6 packet
  **/
 static uint32_t
-decode_ipv6_n_hash(struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
+decode_ipv6_n_hash(const struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
 {
 	uint32_t saddr, daddr;
 	uint32_t rc = 0;
@@ -227,19 +227,19 @@ decode_ipv6_n_hash(struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
 				 ntohs(0xFFFD) + seed,
 				 ntohs(0xFFFE) + seed);
 	} else {
-		struct tcphdr *tcph = NULL;
-		struct udphdr *udph = NULL;
+		const struct tcphdr *tcph = NULL;
+		const struct udphdr *udph = NULL;
 
 		switch(ntohs(ipv6h->ip6_ctlun.ip6_un1.ip6_un1_nxt)) {
 		case IPPROTO_TCP:
-			tcph = (struct tcphdr *)(ipv6h + 1);
+			tcph = (const struct tcphdr *)(ipv6h + 1);
 			rc = sym_hash_fn(ntohl(saddr),
 					 ntohl(daddr),
 					 ntohs(tcph->th_sport) + seed,
 					 ntohs(tcph->th_dport) + seed);
 			break;
 		case IPPROTO_UDP:
-			udph = (struct udphdr *)(ipv6h + 1);
+			udph = (const struct udphdr *)(ipv6h + 1);
 			rc = sym_hash_fn(ntohl(saddr),
 					 ntohl(daddr),
 					 ntohs(udph->uh_sport) + seed,
@@ -247,16 +247,16 @@ decode_ipv6_n_hash(struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
 			break;
 		case IPPROTO_IPIP:
 			/* tunneling */
-			rc = decode_ip_n_hash((struct ip *)(ipv6h + 1),
+			rc = decode_ip_n_hash((const struct ip *)(ipv6h + 1),
 					      hash_split, seed);
 			break;
 		case IPPROTO_IPV6:
 			/* tunneling */
-			rc = decode_ipv6_n_hash((struct ip6_hdr *)(ipv6h + 1),
+			rc = decode_ipv6_n_hash((const struct ip6_hdr *)(ipv6h + 1),
 						hash_split, seed);
 			break;
 		case IPPROTO_GRE:
-			rc = decode_gre_hash((uint8_t *)(ipv6h + 1), hash_split, seed);
+			rc = decode_gre_hash((const uint8_t *)(ipv6h + 1), hash_split, seed);
 			break;
 		case IPPROTO_ICMP:
 		case IPPROTO_ESP:
@@ -281,7 +281,7 @@ decode_ipv6_n_hash(struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
  *   * (See decode_vlan_n_hash & pkt_hdr_hash functions).
  *    */
 static uint32_t
-decode_others_n_hash(struct ether_header *ethh, uint8_t seed)
+decode_others_n_hash(const struct ether_header *ethh, uint8_t seed)
 {
 	uint32_t saddr, daddr, rc;
 
@@ -306,18 +306,18 @@ decode_others_n_hash(struct ether_header *ethh, uint8_t seed)
  ** Parser + hash function for VLAN packet
  **/
 static inline uint32_t
-decode_vlan_n_hash(struct ether_header *ethh, uint8_t hash_split, uint8_t seed)
+decode_vlan_n_hash(const struct ether_header *ethh, uint8_t hash_split, uint8_t seed)
 {
 	uint32_t rc = 0;
-	struct vlanhdr *vhdr = (struct vlanhdr *)(ethh + 1);
+	const struct vlanhdr *vhdr = (const struct vlanhdr *)(ethh + 1);
 
 	switch (ntohs(vhdr->proto)) {
 	case ETHERTYPE_IP:
-		rc = decode_ip_n_hash((struct ip *)(vhdr + 1),
+		rc = decode_ip_n_hash((const struct ip *)(vhdr + 1),
 				      hash_split, seed);
 		break;
 	case ETHERTYPE_IPV6:
-		rc = decode_ipv6_n_hash((struct ip6_hdr *)(vhdr + 1),
+		rc = decode_ipv6_n_hash((const struct ip6_hdr *)(vhdr + 1),
 					hash_split, seed);
 		break;
 	case ETHERTYPE_ARP:
@@ -337,15 +337,15 @@ uint32_t
 pkt_hdr_hash(const unsigned char *buffer, uint8_t hash_split, uint8_t seed)
 {
 	uint32_t rc = 0;
-	struct ether_header *ethh = (struct ether_header *)buffer;
+	const struct ether_header *ethh = (const struct ether_header *)buffer;
 
 	switch (ntohs(ethh->ether_type)) {
 	case ETHERTYPE_IP:
-		rc = decode_ip_n_hash((struct ip *)(ethh + 1),
+		rc = decode_ip_n_hash((const struct ip *)(ethh + 1),
 				      hash_split, seed);
 		break;
 	case ETHERTYPE_IPV6:
-		rc = decode_ipv6_n_hash((struct ip6_hdr *)(ethh + 1),
+		rc = decode_ipv6_n_hash((const struct ip6_hdr *)(ethh + 1),
 					hash_split, seed);
 		break;
 	case ETHERTYPE_VLAN:
@@ -373,15 +373,15 @@ decode_gre_hash(const uint8_t *grehdr, uint8_t hash_split, uint8_t seed)
 			   !!(*grehdr & 2) + /* Routing */
 			   !!(*grehdr & 4) + /* Key */
 			   !!(*grehdr & 8)); /* Sequence Number */
-	uint16_t proto = ntohs(*(uint16_t *)(void *)(grehdr + 2));
+	uint16_t proto = ntohs(*(const uint16_t *)(const void *)(grehdr + 2));
 
 	switch (proto) {
 	case ETHERTYPE_IP:
-		rc = decode_ip_n_hash((struct ip *)(grehdr + len),
+		rc = decode_ip_n_hash((const struct ip *)(grehdr + len),
 				      hash_split, seed);
 		break;
 	case ETHERTYPE_IPV6:
-		rc = decode_ipv6_n_hash((struct ip6_hdr *)(grehdr + len),
+		rc = decode_ipv6_n_hash((const struct ip6_hdr *)(grehdr + len),
 					hash_split, seed);
 		break;
 	case 0x6558: /* Transparent Ethernet Bridging */
diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index c72a659d6..0fe0a1a76 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -433,7 +433,7 @@ readpcap(const char *fn)
 
 enum my_pcap_mode { PM_NONE, PM_FAST, PM_FIXED, PM_REAL };
 
-int verbose = 0;
+static int verbose = 0;
 
 static int do_abort = 0;
 
@@ -990,7 +990,8 @@ usage(void)
 static char **
 split_arg(const char *src, int *_ac)
 {
-    char *my = NULL, **av = NULL, *seps = " \t\r\n,";
+    char *my = NULL, **av = NULL;
+    const char *seps = " \t\r\n,";
     int l, i, ac; /* number of entries */
 
     if (!src)
@@ -1129,15 +1130,15 @@ main(int argc, char **argv)
 
 	/* set default values */
 	for (i = 0; i < N_OPTS; i++) {
-	    struct _qs *q = &bp[i].q;
-
-	    q->burst = 128;
-	    q->c_delay.optarg = "0";
-	    q->c_delay.run = null_run_fn;
-	    q->c_loss.optarg = "0";
-	    q->c_loss.run = null_run_fn;
-	    q->c_bw.optarg = "0";
-	    q->c_bw.run = null_run_fn;
+	    struct _qs *qs = &bp[i].q;
+
+	    qs->burst = 128;
+	    qs->c_delay.optarg = "0";
+	    qs->c_delay.run = null_run_fn;
+	    qs->c_loss.optarg = "0";
+	    qs->c_loss.run = null_run_fn;
+	    qs->c_bw.optarg = "0";
+	    qs->c_bw.run = null_run_fn;
 	}
 
 	// Options:
@@ -1252,10 +1253,10 @@ main(int argc, char **argv)
 
 	/* apply commands */
 	for (i = 0; i < N_OPTS; i++) { /* once per queue */
-		struct _qs *q = &bp[i].q;
-		err += cmd_apply(delay_cfg, d[i], q, &q->c_delay);
-		err += cmd_apply(bw_cfg, b[i], q, &q->c_bw);
-		err += cmd_apply(loss_cfg, l[i], q, &q->c_loss);
+		struct _qs *qs = &bp[i].q;
+		err += cmd_apply(delay_cfg, d[i], qs, &qs->c_delay);
+		err += cmd_apply(bw_cfg, b[i], qs, &qs->c_bw);
+		err += cmd_apply(loss_cfg, l[i], qs, &qs->c_loss);
 	}
 
 	pthread_create(&bp[0].cons_tid, NULL, nmreplay_main, (void*)&bp[0]);
@@ -1289,7 +1290,7 @@ main(int argc, char **argv)
  * the final entry has s = NULL.
  */
 struct _sm {	/* string and multiplier */
-	char *s;
+	const char *s;
 	double m;
 };
 
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index d78ebb3a2..897b558a4 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -184,14 +184,14 @@ static inline void CPU_SET(uint32_t i, cpuset_t *p)
 	do {struct timespec t0 = {0,0}; *(b) = t0; } while (0)
 #endif  /* __APPLE__ */
 
-const char *default_payload="netmap pkt-gen DIRECT payload\n"
+static const char *default_payload = "netmap pkt-gen DIRECT payload\n"
 	"http://info.iet.unipi.it/~luigi/netmap/ ";
 
-const char *indirect_payload="netmap pkt-gen indirect payload\n"
+static const char *indirect_payload = "netmap pkt-gen indirect payload\n"
 	"http://info.iet.unipi.it/~luigi/netmap/ ";
 
-int verbose = 0;
-int normalize = 1;
+static int verbose = 0;
+static int normalize = 1;
 
 #define VIRT_HDR_1	10	/* length of a base vnet-hdr */
 #define VIRT_HDR_2	12	/* length of the extenede vnet-hdr */
@@ -223,7 +223,7 @@ struct pkt {
     ((af) == AF_INET ? (p)->ipv4.f: (p)->ipv6.f)
 
 struct ip_range {
-	char *name;
+	const char *name;
 	union {
 		struct {
 			uint32_t start, end; /* same as struct in_addr */
@@ -237,7 +237,7 @@ struct ip_range {
 };
 
 struct mac_range {
-	char *name;
+	const char *name;
 	struct ether_addr start, end;
 };
 
@@ -302,7 +302,7 @@ struct glob_arg {
 	int td_type;
 	void *mmap_addr;
 	char ifname[MAX_IFNAMELEN];
-	char *nmr_config;
+	const char *nmr_config;
 	int dummy_send;
 	int virt_header;	/* send also the virt_header */
 	char *packet_file;	/* -P option */
@@ -633,7 +633,7 @@ system_ncpus(void)
  * If there is no 4th number, then the 3rd is assigned to both #tx-rings
  * and #rx-rings.
  */
-int
+static int
 parse_nmr_config(const char* conf, struct nmreq_register *nmr)
 {
 	char *w, *tok;
@@ -1255,7 +1255,7 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame,
 /*
  * Index of the highest bit set
  */
-uint32_t
+static uint32_t
 msb64(uint64_t x)
 {
 	uint64_t m = 1ULL << 63;
@@ -2722,7 +2722,7 @@ main_thread(struct glob_arg *g)
 
 struct td_desc {
 	int ty;
-	char *key;
+	const char *key;
 	void *f;
 	int default_burst;
 };
@@ -2742,7 +2742,7 @@ tap_alloc(char *dev)
 {
 	struct ifreq ifr;
 	int fd, err;
-	char *clonedev = TAP_CLONEDEV;
+	const char *clonedev = TAP_CLONEDEV;
 
 	(void)err;
 	(void)dev;

From dc57832048d1fc984fb7d48178be0ad0dd06e731 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 3 Oct 2020 15:20:28 +0200
Subject: [PATCH 1860/2207] pkt-gen: fix warning in checksum()

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 897b558a4..271de2903 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -738,7 +738,7 @@ checksum(const void *data, uint16_t len, uint32_t sum)
 
 	/* Checksum all the pairs of bytes first... */
 	for (i = 0; i < (len & ~1U); i += 2) {
-		sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i)));
+		sum += (uint16_t)ntohs(*((const uint16_t *)(addr + i)));
 		if (sum > 0xFFFF)
 			sum -= 0xFFFF;
 	}

From ea55d09c198231bcdd7edecaa2d35122bbafd57e Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Thu, 22 Oct 2020 09:58:39 -0400
Subject: [PATCH 1861/2207] freebsd: fix mutex double unlock

If memory allocation in netmap_mem2_if_new() fails, it unlocks the
nm_mem mutex before returning. However, the calling function
netmap_mem_if_new() also unlocks the mutex.
---
 sys/dev/netmap/netmap_mem2.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 733f89c7f..8e77299d5 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2023,7 +2023,6 @@ netmap_mem2_if_new(struct netmap_mem_d *nmd,
 	len = sizeof(struct netmap_if) + (ntot * sizeof(ssize_t));
 	nifp = netmap_if_malloc(nmd, len);
 	if (nifp == NULL) {
-		NMA_UNLOCK(nmd);
 		return NULL;
 	}
 

From bd93524e4ac2e620778239395118dd57a0016324 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=9A=D0=BE=D1=80=D0=B5=D0=BD=D0=B1=D0=B5=D1=80=D0=B3=20?=
 =?UTF-8?q?=E2=98=A2=EF=B8=8F=20=20=D0=9C=D0=B0=D1=80=D0=BA?=
 
Date: Tue, 3 Nov 2020 01:21:30 +0500
Subject: [PATCH 1862/2207] Fix BUG_ON() in Linux on vxlan/gretap/hyper-v
 interfaces

Wrong headroom calculations lead to pskb_expand_head() in the drivers.
It fails since skb is shared. Correct calculations prevent
expanding skb.
---
 LINUX/netmap_linux.c            | 6 +++---
 sys/dev/netmap/netmap_generic.c | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 3e9d6e40f..057f27b3b 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -959,7 +959,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	netdev_tx_t ret;
 	uint16_t ethertype;
 
-	/* We know that the driver needs to prepend ifp->needed_headroom bytes
+	/* We know that the driver needs to prepend LL_RESERVED_SPACE(ifp) bytes
 	 * to each packet to be transmitted. We then reset the mbuf pointers
 	 * to the correct initial state:
 	 *    ___________________________________________
@@ -969,10 +969,10 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	 *               tail
 	 *
 	 * which correspond to an empty buffer with exactly
-	 * ifp->needed_headroom bytes between head and data.
+	 * LL_RESERVED_SPACE(ifp) bytes between head and data.
 	 */
 	m->len = 0;
-	m->data = m->head + ifp->needed_headroom;
+	m->data = m->head + LL_RESERVED_SPACE(ifp);
 	skb_reset_tail_pointer(m);
 	skb_reset_mac_header(m);
 
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 37de01963..e35d4a44e 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -106,7 +106,7 @@ __FBSDID("$FreeBSD: head/sys/dev/netmap/netmap_generic.c 274353 2014-11-10 20:19
 static inline struct mbuf *
 nm_os_get_mbuf(struct ifnet *ifp, int len)
 {
-	return alloc_skb(ifp->needed_headroom + len +
+	return alloc_skb(LL_RESERVED_SPACE(ifp) + len +
 			 ifp->needed_tailroom, GFP_ATOMIC);
 }
 

From 44050f879f4616989830b24372192a899d9c3ecc Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 22 Nov 2020 10:42:15 +0100
Subject: [PATCH 1863/2207] apps: rearrange includes (merge from FreeBSD)

---
 apps/bridge/bridge.c     |  2 +-
 apps/lb/lb.c             | 21 +++++++++---------
 apps/nmreplay/nmreplay.c | 45 +++++++++++++++----------------------
 apps/pkt-gen/pkt-gen.c   | 48 +++++++++++++++++++---------------------
 4 files changed, 52 insertions(+), 64 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 4c7290866..a10142e69 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -6,7 +6,7 @@
  * A netmap client to bridge two network interfaces
  * (or one interface and the host stack).
  *
- * $FreeBSD: head/tools/tools/netmap/bridge.c 228975 2011-12-30 00:04:11Z uqs $
+ * $FreeBSD$
  */
 
 #include 
diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 251d53fb0..37fe97cc6 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -23,22 +23,21 @@
  * SUCH DAMAGE.
  */
 /* $FreeBSD$ */
-#include 
-#include 
 #include 
-#include 
+#include 
 #include 
-#include 
-#include 
-#include 
-
 #include 
-#include 
-#include 
-
 #include 		/* htonl */
-
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include "pkt_hash.h"
 #include "ctrs.h"
diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index 0fe0a1a76..e0a9e2146 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -106,13 +106,26 @@
 #define DDD(_fmt, ...)	ED("--DDD-- " _fmt, ##__VA_ARGS__)
 
 #define _GNU_SOURCE	// for CPU_SET() etc
-#include 
-#include 
-#include 
-#include 
 #include 
+#include 
+#include 
+#include  /* log, exp etc. */
+#include 
+#ifdef __FreeBSD__
+#include  /* pthread w/ affinity */
+#include  /* cpu_set */
+#endif /* __FreeBSD__ */
 #include 
-
+#include 
+#include 
+#include  /* memcpy */
+#include 
+#include 
+#include 
+#include 
+#include  // setpriority
+#include 
+#include 
 
 /*
  *
@@ -244,15 +257,6 @@ static struct nm_pcap_file *readpcap(const char *fn);
 static void destroy_pcap(struct nm_pcap_file *file);
 
 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include  /* memcpy */
-
-#include 
-
 #define NS_SCALE 1000000000UL	/* nanoseconds in 1s */
 
 static void destroy_pcap(struct nm_pcap_file *pf)
@@ -437,18 +441,6 @@ static int verbose = 0;
 
 static int do_abort = 0;
 
-#include 
-#include 
-#include 
-#include 
-
-#include  // setpriority
-
-#ifdef __FreeBSD__
-#include  /* pthread w/ affinity */
-#include  /* cpu_set */
-#endif /* __FreeBSD__ */
-
 #ifdef linux
 #define cpuset_t        cpu_set_t
 #endif
@@ -1374,7 +1366,6 @@ parse_bw(const char *arg)
  * 24 useful random bits.
  */
 
-#include  /* log, exp etc. */
 static inline uint64_t
 my_random24(void)	/* 24 useful bits */
 {
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 271de2903..e6237b8ba 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -38,41 +38,39 @@
  */
 
 #define _GNU_SOURCE	/* for CPU_SET() */
-#include 
-#include 
-
-
-#include 
-#include 
-#include 
-#include 	// isprint()
-#include 
-#include 	// sysconf()
-#include 
-#include 
-#include 
 #include 	/* ntohs */
-#if !defined(_WIN32) && !defined(linux)
-#include 	/* sysctl */
-#endif
+#include 
+#include 	// isprint()
+#include 
+#include 
 #include 	/* getifaddrs */
+#include 
+#include 
 #include 
 #include 
 #include 
-#include 
 #include 
+#include 
+#ifndef NO_PCAP
+#include 
+#endif
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#if !defined(_WIN32) && !defined(linux)
+#include 	/* sysctl */
+#endif
+#include 
+#include 	// sysconf()
 #ifdef linux
 #define IPV6_VERSION	0x60
 #define IPV6_DEFHLIM	64
 #endif
-#include 
-#include 
-
-#include 
-
-#ifndef NO_PCAP
-#include 
-#endif
 
 #include "ctrs.h"
 

From db3040be2c281ac527b4a02730a7d243776824a8 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 22 Nov 2020 14:34:48 +0100
Subject: [PATCH 1864/2207] bridge: update from FreeBSD

---
 apps/bridge/bridge.c | 116 +++++++++++++++++++++++++++----------------
 1 file changed, 74 insertions(+), 42 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index a10142e69..af8c28471 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -3,19 +3,19 @@
  *
  * BSD license
  *
- * A netmap client to bridge two network interfaces
- * (or one interface and the host stack).
+ * A netmap application to bridge two network interfaces,
+ * or one interface and the host stack.
  *
  * $FreeBSD$
  */
 
+#include 
+#include 
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
-#include 
 
 static int verbose = 0;
 
@@ -32,30 +32,39 @@ sigint_h(int sig)
 
 
 /*
- * how many packets on this set of queues ?
+ * How many slots do we (user application) have on this
+ * set of queues ?
  */
 static int
-pkt_queued(struct nmport_d *d, int tx)
+rx_slots_avail(struct nmport_d *d)
 {
 	u_int i, tot = 0;
 
-	if (tx) {
-		for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) {
-			tot += nm_ring_space(NETMAP_TXRING(d->nifp, i));
-		}
-	} else {
-		for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
-			tot += nm_ring_space(NETMAP_RXRING(d->nifp, i));
-		}
+	for (i = d->first_rx_ring; i <= d->last_rx_ring; i++) {
+		tot += nm_ring_space(NETMAP_RXRING(d->nifp, i));
 	}
+
+	return tot;
+}
+
+static int
+tx_slots_avail(struct nmport_d *d)
+{
+	u_int i, tot = 0;
+
+	for (i = d->first_tx_ring; i <= d->last_tx_ring; i++) {
+		tot += nm_ring_space(NETMAP_TXRING(d->nifp, i));
+	}
+
 	return tot;
 }
 
 /*
- * move up to 'limit' pkts from rxring to txring swapping buffers.
+ * Move up to 'limit' pkts from rxring to txring, swapping buffers
+ * if zerocopy is possible. Otherwise fall back on packet copying.
  */
 static int
-process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
+rings_move(struct netmap_ring *rxring, struct netmap_ring *txring,
 	      u_int limit, const char *msg)
 {
 	u_int j, k, m = 0;
@@ -63,7 +72,7 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 	/* print a warning if any of the ring flags is set (e.g. NM_REINIT) */
 	if (rxring->flags || txring->flags)
 		D("%s rxflags %x txflags %x",
-			msg, rxring->flags, txring->flags);
+		    msg, rxring->flags, txring->flags);
 	j = rxring->head; /* RX */
 	k = txring->head; /* TX */
 	m = nm_ring_space(rxring);
@@ -79,16 +88,18 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 
 		/* swap packets */
 		if (ts->buf_idx < 2 || rs->buf_idx < 2) {
-			RD(5, "wrong index rx[%d] = %d  -> tx[%d] = %d",
-				j, rs->buf_idx, k, ts->buf_idx);
+			RD(2, "wrong index rxr[%d] = %d  -> txr[%d] = %d",
+			    j, rs->buf_idx, k, ts->buf_idx);
 			sleep(2);
 		}
 		/* copy the packet length. */
 		if (rs->len > rxring->nr_buf_size) {
-			RD(5, "wrong len %d rx[%d] -> tx[%d]", rs->len, j, k);
+			RD(2,  "%s: invalid len %u, rxr[%d] -> txr[%d]",
+			    msg, rs->len, j, k);
 			rs->len = 0;
 		} else if (verbose > 1) {
-			D("%s send len %d rx[%d] -> tx[%d]", msg, rs->len, j, k);
+			D("%s: fwd len %u, rx[%d] -> tx[%d]",
+			    msg, rs->len, j, k);
 		}
 		ts->len = rs->len;
 		if (zerocopy) {
@@ -111,24 +122,23 @@ process_rings(struct netmap_ring *rxring, struct netmap_ring *txring,
 	rxring->head = rxring->cur = j;
 	txring->head = txring->cur = k;
 	if (verbose && m > 0)
-		D("%s sent %d packets to %p", msg, m, txring);
+		D("%s fwd %d packets: rxring %u --> txring %u",
+		    msg, m, rxring->ringid, txring->ringid);
 
 	return (m);
 }
 
-/* move packts from src to destination */
+/* Move packets from source port to destination port. */
 static int
-move(struct nmport_d *src, struct nmport_d *dst, u_int limit)
+ports_move(struct nmport_d *src, struct nmport_d *dst, u_int limit,
+	const char *msg)
 {
 	struct netmap_ring *txring, *rxring;
 	u_int m = 0, si = src->first_rx_ring, di = dst->first_tx_ring;
-	const char *msg = (src->reg.nr_flags == NR_REG_SW) ?
-		"host->net" : "net->host";
 
 	while (si <= src->last_rx_ring && di <= dst->last_tx_ring) {
 		rxring = NETMAP_RXRING(src->nifp, si);
 		txring = NETMAP_TXRING(dst->nifp, di);
-		ND("txring %p rxring %p", txring, rxring);
 		if (nm_ring_empty(rxring)) {
 			si++;
 			continue;
@@ -137,7 +147,7 @@ move(struct nmport_d *src, struct nmport_d *dst, u_int limit)
 			di++;
 			continue;
 		}
-		m += process_rings(rxring, txring, limit, msg);
+		m += rings_move(rxring, txring, limit, msg);
 	}
 
 	return (m);
@@ -149,7 +159,7 @@ usage(void)
 {
 	fprintf(stderr,
 		"netmap bridge program: forward packets between two "
-			"network interfaces\n"
+			"netmap ports\n"
 		"    usage(1): bridge [-v] [-i ifa] [-i ifb] [-b burst] "
 			"[-w wait_time] [-L]\n"
 		"    usage(2): bridge [-v] [-w wait_time] [-L] "
@@ -161,6 +171,11 @@ usage(void)
 		"    is not specified, otherwise loopback traffic on ifa.\n"
 		"\n"
 		"    example: bridge -w 10 -i netmap:eth3 -i netmap:eth1\n"
+		"\n"
+		"    If ifa and ifb are two interfaces, they must be in\n"
+		"    promiscuous mode. Otherwise, if bridging with the \n"
+		"    host stack, the interface must have the offloads \n"
+		"    disabled.\n"
 		);
 	exit(1);
 }
@@ -175,13 +190,15 @@ usage(void)
 int
 main(int argc, char **argv)
 {
+	char msg_a2b[128], msg_b2a[128];
 	struct pollfd pollfd[2];
-	int ch;
 	u_int burst = 1024, wait_link = 4;
 	struct nmport_d *pa = NULL, *pb = NULL;
 	char *ifa = NULL, *ifb = NULL;
 	char ifabuf[64] = { 0 };
+	int pa_sw_rings, pb_sw_rings;
 	int loopback = 0;
+	int ch;
 
 	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
 
@@ -281,14 +298,27 @@ main(int argc, char **argv)
 		pa->hdr.nr_name, pa->first_rx_ring, pa->reg.nr_rx_rings,
 		pb->hdr.nr_name, pb->first_rx_ring, pb->reg.nr_rx_rings);
 
+	pa_sw_rings = (pa->reg.nr_mode == NR_REG_SW ||
+	    pa->reg.nr_mode == NR_REG_ONE_SW);
+	pb_sw_rings = (pb->reg.nr_mode == NR_REG_SW ||
+	    pb->reg.nr_mode == NR_REG_ONE_SW);
+
+	snprintf(msg_a2b, sizeof(msg_a2b), "%s:%s --> %s:%s",
+			pa->hdr.nr_name, pa_sw_rings ? "host" : "nic",
+			pb->hdr.nr_name, pb_sw_rings ? "host" : "nic");
+
+	snprintf(msg_b2a, sizeof(msg_b2a), "%s:%s --> %s:%s",
+			pb->hdr.nr_name, pb_sw_rings ? "host" : "nic",
+			pa->hdr.nr_name, pa_sw_rings ? "host" : "nic");
+
 	/* main loop */
 	signal(SIGINT, sigint_h);
 	while (!do_abort) {
 		int n0, n1, ret;
 		pollfd[0].events = pollfd[1].events = 0;
 		pollfd[0].revents = pollfd[1].revents = 0;
-		n0 = pkt_queued(pa, 0);
-		n1 = pkt_queued(pb, 0);
+		n0 = rx_slots_avail(pa);
+		n1 = rx_slots_avail(pb);
 #if defined(_WIN32) || defined(BUSYWAIT)
 		if (n0) {
 			ioctl(pollfd[1].fd, NIOCTXSYNC, NULL);
@@ -322,35 +352,37 @@ main(int argc, char **argv)
 				ret <= 0 ? "timeout" : "ok",
 				pollfd[0].events,
 				pollfd[0].revents,
-				pkt_queued(pa, 0),
+				rx_slots_avail(pa),
 				NETMAP_RXRING(pa->nifp, pa->cur_rx_ring)->head,
-				pkt_queued(pa, 1),
+				tx_slots_avail(pa),
 				pollfd[1].events,
 				pollfd[1].revents,
-				pkt_queued(pb, 0),
+				rx_slots_avail(pb),
 				NETMAP_RXRING(pb->nifp, pb->cur_rx_ring)->head,
-				pkt_queued(pb, 1)
+				tx_slots_avail(pb)
 			);
 		if (ret < 0)
 			continue;
 		if (pollfd[0].revents & POLLERR) {
 			struct netmap_ring *rx = NETMAP_RXRING(pa->nifp, pa->cur_rx_ring);
 			D("error on fd0, rx [%d,%d,%d)",
-				rx->head, rx->cur, rx->tail);
+			    rx->head, rx->cur, rx->tail);
 		}
 		if (pollfd[1].revents & POLLERR) {
 			struct netmap_ring *rx = NETMAP_RXRING(pb->nifp, pb->cur_rx_ring);
 			D("error on fd1, rx [%d,%d,%d)",
-				rx->head, rx->cur, rx->tail);
+			    rx->head, rx->cur, rx->tail);
 		}
 		if (pollfd[0].revents & POLLOUT)
-			move(pb, pa, burst);
+			ports_move(pb, pa, burst, msg_b2a);
 
 		if (pollfd[1].revents & POLLOUT)
-			move(pa, pb, burst);
+			ports_move(pa, pb, burst, msg_a2b);
 
-		/* We don't need ioctl(NIOCTXSYNC) on the two file descriptors here,
-		 * kernel will txsync on next poll(). */
+		/*
+		 * We don't need ioctl(NIOCTXSYNC) on the two file descriptors.
+		 * here. The kernel will txsync on next poll().
+		 */
 	}
 	nmport_close(pb);
 	nmport_close(pa);

From a7a80b1ad4e5aeb47a8793336c76033ac7f2b71f Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 22 Nov 2020 19:27:53 +0100
Subject: [PATCH 1865/2207] bridge: use a larger message buffer to avoid string
 truncation

---
 apps/bridge/bridge.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index af8c28471..a9adffad2 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -190,7 +190,7 @@ usage(void)
 int
 main(int argc, char **argv)
 {
-	char msg_a2b[128], msg_b2a[128];
+	char msg_a2b[256], msg_b2a[256];
 	struct pollfd pollfd[2];
 	u_int burst = 1024, wait_link = 4;
 	struct nmport_d *pa = NULL, *pb = NULL;

From 1081af667cba3e160b7850286dadf54d2c57e97a Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Sat, 12 Sep 2020 22:20:34 +0000
Subject: [PATCH 1866/2207] Add mlx5 version 5.1 patch

---
 LINUX/configure                         |   2 +-
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/mellanox--mlx5--5.1 | 390 ++++++++++++++++++++++++
 LINUX/mlx5-prepare.sh                   |   2 +-
 4 files changed, 393 insertions(+), 3 deletions(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--5.1

diff --git a/LINUX/configure b/LINUX/configure
index 770df2605..3846a028b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -504,7 +504,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS := -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
+EXTRA_CFLAGS := -Wframe-larger-than=2000 -Wno-maybe-uninitialized -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 40074ba93..81997b4b0 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -107,7 +107,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,5.0-1.0.0.0))
+$(eval $(call default,mlx5,5.1-1.0.4.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 
diff --git a/LINUX/final-patches/mellanox--mlx5--5.1 b/LINUX/final-patches/mellanox--mlx5--5.1
new file mode 100644
index 000000000..e72afd966
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--5.1
@@ -0,0 +1,390 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index f781b2b..1f772c2 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -8,12 +8,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
+@@ -22,12 +22,12 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		sriov_sysfs.o mst_dump.o en_diag.o params.o crdump.o \
+ 		diag/diag_cnt.o eswitch_devlink_compat.o
+ 
+-mlx5_core-y += compat.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y += compat.o
+ 
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o\
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+ 		en/reporter_tx.o en/reporter_rx.o en/params.o en_debugfs.o \
+@@ -36,60 +36,60 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += en_rep.o lib/geneve.o lib/port_tun.o lag_mp.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += en_rep.o lib/geneve.o lib/port_tun.o lag_mp.o \
+ 					en/mod_hdr.o en/rep/bond.o
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					en/mapping.o esw/chains.o en/tc_tun.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
+ 					diag/en_tc_tracepoint.o
+-mlx5_core-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ 				      ecpf.o rdma.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
+ 				      esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
+ 				      esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o
+ 
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
+-mlx5_core-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
+ 			 fpga/tls.o fpga/trans.o fpga/xfer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o en_accel/ipsec_fs.o esw/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ 				   en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
+ 				   en_accel/ktls_tx.o en_accel/ktls_rx.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o \
+ 					steering/dr_ste.o \
+@@ -101,4 +101,4 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # Mdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o meddev/mdev_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o meddev/mdev_driver.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index 62a38bc..d45ba17 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -13,6 +13,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->channel->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index d40b62e..54672e7 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -78,8 +78,21 @@
+ #include "fpga/ipsec.h"
+ #include "compat.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -840,6 +853,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ 		rq->dim_obj.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_free:
+@@ -1061,6 +1078,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 	struct mlx5e_channel *c = rq->channel;
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(c->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1125,6 +1148,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->channel->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1245,6 +1272,9 @@ err_free_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->channel->netdev)) || NA(rq->channel->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	mlx5e_trigger_irq(&rq->channel->icosq);
+ }
+@@ -1526,6 +1556,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1723,6 +1758,9 @@ static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1744,6 +1782,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3699,6 +3743,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -3732,6 +3781,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++       netmap_disable_all_rings(netdev);
++#endif
++
+ 	netif_carrier_off(priv->netdev);
+ 	mlx5e_destroy_debugfs(priv);
+ #if defined(CONFIG_MLX5_EN_SPECIAL_SQ) && (defined(HAVE_NDO_SET_TX_MAXRATE) || defined(HAVE_NDO_SET_TX_MAXRATE_EXTENDED))
+@@ -7048,6 +7101,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ {
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++       netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_netdev_cleanup(netdev, priv);
+ 	free_netdev(netdev);
+ }
+@@ -7159,6 +7216,10 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
+ #endif
+ #endif
+ 
++#ifdef DEV_NETMAP
++       mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	if (MLX5_ESWITCH_MANAGER(mdev))
+ 		mlx5e_rep_register_vport_reps(mdev, priv);
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index b5f7ba9..e03a9d3 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -63,6 +63,14 @@ static inline void mlx5e_set_skb_driver_xmit_more(struct sk_buff *skb,
+ 		skb->cb[47] = MLX5_XMIT_MORE_SKB_CB;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -181,7 +189,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -1930,6 +1938,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 4739f3b..f101fd4 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -40,8 +40,16 @@
+ #include "en_accel/en_accel.h"
+ #include "lib/clock.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+-				       u32 cqcc, void *data)
++                                       u32 cqcc, void *data)
+ {
+ 	u32 ci = mlx5_cqwq_ctr2ix(wq, cqcc);
+ 
+@@ -695,6 +703,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->channel->netdev, sq->channel->ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -833,14 +846,18 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 			continue;
+ 		}
+ 
+-		for (i = 0; i < wi->num_dma; i++) {
+-			struct mlx5e_sq_dma *dma =
+-				mlx5e_dma_get(sq, dma_fifo_cc++);
+ 
+-			mlx5e_tx_dma_unmap(sq->pdev, dma);
+-		}
++                if (!nm_netmap_on(NA(sq->txq->dev))) {
++                       /* do not free skbs in netmap mode */
++                       for (i = 0; i < wi->num_dma; i++) {
++                               struct mlx5e_sq_dma *dma =
++                                       mlx5e_dma_get(sq, dma_fifo_cc++);
++
++                               mlx5e_tx_dma_unmap(sq->pdev, dma);
++                       }
++                       dev_kfree_skb_any(skb);
++                }
+ 
+-		dev_kfree_skb_any(skb);
+ 		npkts++;
+ 		nbytes += wi->num_bytes;
+ 		sqcc += wi->num_wqebbs;
diff --git a/LINUX/mlx5-prepare.sh b/LINUX/mlx5-prepare.sh
index d567c3f02..96365d8ae 100755
--- a/LINUX/mlx5-prepare.sh
+++ b/LINUX/mlx5-prepare.sh
@@ -7,4 +7,4 @@ if [ -e mlx5/config.mk ]; then
 fi
 
 cd mlx5
-scripts/mlnx_en_patch.sh --without-mlx4 -s $KSRC -j$(grep -c processor /proc/cpuinfo)
+scripts/mlnx_en_patch.sh -s $KSRC -j$(grep -c processor /proc/cpuinfo)

From e32e82fd0cedc9766f552212f3f6eade2c69daf1 Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Fri, 4 Dec 2020 14:46:10 +0000
Subject: [PATCH 1867/2207] Move disabled warnings to DISABLED_WARNINGS

---
 LINUX/configure | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 3846a028b..9f4d54192 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -504,7 +504,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS := -Wframe-larger-than=2000 -Wno-maybe-uninitialized -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
+EXTRA_CFLAGS := -Wframe-larger-than=2000 -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 I_DRIVERS := $(idrv print)
@@ -982,7 +982,7 @@ EOF
 
   add_test true broken_buildsystem < /dev/null
 
-DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation missing-attributes"
+DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation missing-attributes maybe-uninitialized unused-variable unused-label"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"

From 8e444e0994b78f44b1427dafcdb2567f676f454b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Dec 2020 16:52:02 +0100
Subject: [PATCH 1868/2207] linux/e1000e: patch for Intel 3.8.7 version

---
 LINUX/final-patches/intel--e1000e--3.8.7 | 119 +++++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 LINUX/final-patches/intel--e1000e--3.8.7

diff --git a/LINUX/final-patches/intel--e1000e--3.8.7 b/LINUX/final-patches/intel--e1000e--3.8.7
new file mode 100644
index 000000000..3e5929ed7
--- /dev/null
+++ b/LINUX/final-patches/intel--e1000e--3.8.7
@@ -0,0 +1,119 @@
+diff --git a/e1000e/Makefile b/e1000e/Makefile
+index 9af58b1..00ca1e8 100644
+--- a/e1000e/Makefile
++++ b/e1000e/Makefile
+@@ -9,9 +9,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the @SUMMARY@
+ #
+ 
+-obj-$(CONFIG_E1000E) += e1000e.o
++obj-$(CONFIG_E1000E) += e1000e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define e1000e-y
++define e1000e$(NETMAP_DRIVER_SUFFIX)-y
+ 	netdev.o
+ 	ethtool.o
+ 	ich8lan.o
+@@ -23,20 +23,20 @@ define e1000e-y
+ 	82571.o
+ 	param.o
+ endef
+-e1000e-y := $(strip ${e1000e-y})
++e1000e$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${e1000e$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+ #ifdef BUILD_PTP_SUPPORT
+-e1000e-$(CONFIG_PTP_1588_CLOCK:m=y) += ptp.o
++e1000e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ptp.o
+ #endif
+ 
+ #ifndef REMOVE_COMPAT
+ 
+-e1000e-y += kcompat.o
++e1000e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := e1000e
++DRIVER := e1000e$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+diff --git a/e1000e/netdev.c b/e1000e/netdev.c
+index a8eb9b7..de06d62 100644
+--- a/e1000e/netdev.c
++++ b/e1000e/netdev.c
+@@ -483,6 +483,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+ 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ #ifdef HAVE_HW_TIME_STAMP
+ /**
+  * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
+@@ -1013,6 +1017,17 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring)
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++#ifdef CONFIG_E1000E_NAPI
++#define NETMAP_DUMMY work_done
++#else
++	int dummy;
++#define NETMAP_DUMMY &dummy
++#endif
++	if (netmap_rx_irq(netdev, 0, NETMAP_DUMMY))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1330,6 +1345,11 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4263,6 +4283,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ #endif
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000e_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
+ }
+ 
+@@ -8755,6 +8779,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_register;
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
+@@ -8851,6 +8879,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	iounmap(adapter->hw.hw_addr);
+ 	if ((adapter->hw.flash_address) &&
+ 	    (adapter->hw.mac.type < e1000_pch_spt))

From 0aca4cde0c6bb43d41ece07047d73b18ea7e25b6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Dec 2020 16:52:33 +0100
Subject: [PATCH 1869/2207] linux/i40e: patch for Intel 2.13.10 version

---
 LINUX/final-patches/intel--i40e--2.13.10 | 167 +++++++++++++++++++++++
 1 file changed, 167 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.13.10

diff --git a/LINUX/final-patches/intel--i40e--2.13.10 b/LINUX/final-patches/intel--i40e--2.13.10
new file mode 100644
index 000000000..599cb8b79
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.13.10
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 81f5ab9..85bfb8c 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 62aeafe..5572ab1 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -148,6 +148,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3693,6 +3698,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3746,6 +3755,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3774,6 +3787,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -14676,6 +14694,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15048,6 +15072,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index f5d5bdf..7f7efd7 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -935,6 +939,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2709,6 +2718,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ #endif

From 456d5e91d357a4094f662cfe2e72075e9e9a62eb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Dec 2020 16:53:07 +0100
Subject: [PATCH 1870/2207] linux/igb: patch for Intel 5.4.6 version

---
 LINUX/final-patches/intel--igb--5.4.6 | 138 ++++++++++++++++++++++++++
 1 file changed, 138 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.4.6

diff --git a/LINUX/final-patches/intel--igb--5.4.6 b/LINUX/final-patches/intel--igb--5.4.6
new file mode 100644
index 000000000..ec1420cdb
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.4.6
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 811a634..2559d39 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 1517b38..c87d686 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3209,6 +3213,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3414,6 +3422,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3826,6 +3838,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7511,6 +7526,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8527,6 +8547,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8846,6 +8871,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From d39417bbea05bd7613776001540c1c560123406c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Dec 2020 16:53:32 +0100
Subject: [PATCH 1871/2207] linux/ixgbe: patch for Intel 5.9.4 version

---
 LINUX/final-patches/intel--ixgbe--5.9.4 | 173 ++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.9.4

diff --git a/LINUX/final-patches/intel--ixgbe--5.9.4 b/LINUX/final-patches/intel--ixgbe--5.9.4
new file mode 100644
index 000000000..e5d6c51d5
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.9.4
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 01e67d7..91f53e1 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 1123fe5..9578b42 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -711,6 +711,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -730,6 +747,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2203,6 +2231,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3670,6 +3708,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4346,6 +4388,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12957,6 +13005,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13012,6 +13064,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 9082364b7f3590a6a5d48d209eaff2545a3785a5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Dec 2020 16:53:51 +0100
Subject: [PATCH 1872/2207] linux/ixgbevf: patch for Intel 4.9.3 version

---
 LINUX/final-patches/intel--ixgbevf--4.9.3 | 168 ++++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.9.3

diff --git a/LINUX/final-patches/intel--ixgbevf--4.9.3 b/LINUX/final-patches/intel--ixgbevf--4.9.3
new file mode 100644
index 000000000..5975f38b7
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.9.3
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index dc49435..103a5d1 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index ac1e9a2..039fb8f 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -343,6 +343,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -363,6 +380,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1361,6 +1389,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2066,6 +2104,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2300,6 +2342,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5609,8 +5655,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5651,6 +5699,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 00cdebd..e4a5497 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 31bded587901b35288fe1c9fb90283cdc4a736f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 11 Dec 2020 18:49:34 +0100
Subject: [PATCH 1873/2207] linux: patches for 5.9 drivers

---
 ...20--99999 => vanilla--e1000--20620--41500} |   0
 .../vanilla--e1000--41400--99999              |  91 ++++++++++++++
 .../vanilla--ixgbe--50800--50a00              | 117 ++++++++++++++++++
 3 files changed, 208 insertions(+)
 rename LINUX/final-patches/{vanilla--e1000--20620--99999 => vanilla--e1000--20620--41500} (100%)
 create mode 100644 LINUX/final-patches/vanilla--e1000--41400--99999
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--50800--50a00

diff --git a/LINUX/final-patches/vanilla--e1000--20620--99999 b/LINUX/final-patches/vanilla--e1000--20620--41500
similarity index 100%
rename from LINUX/final-patches/vanilla--e1000--20620--99999
rename to LINUX/final-patches/vanilla--e1000--20620--41500
diff --git a/LINUX/final-patches/vanilla--e1000--41400--99999 b/LINUX/final-patches/vanilla--e1000--41400--99999
new file mode 100644
index 000000000..d85b20fc7
--- /dev/null
+++ b/LINUX/final-patches/vanilla--e1000--41400--99999
@@ -0,0 +1,91 @@
+diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
+index 43b6d3cec3b3..43afd047fc95 100644
+--- a/e1000/e1000_main.c
++++ b/e1000/e1000_main.c
+@@ -179,6 +179,10 @@ static const struct pci_error_handlers e1000_err_handler = {
+ 	.resume = e1000_io_resume,
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver e1000_driver = {
+ 	.name     = e1000_driver_name,
+ 	.id_table = e1000_pci_tbl,
+@@ -374,6 +378,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+ 	e1000_configure_tx(adapter);
+ 	e1000_setup_rctl(adapter);
+ 	e1000_configure_rx(adapter);
++#ifdef DEV_NETMAP
++	if (e1000_netmap_init_buffers(adapter))
++		return;
++#endif /* DEV_NETMAP */
+ 	/* call E1000_DESC_UNUSED which always leaves
+ 	 * at least 1 descriptor unused to make sure
+ 	 * next_to_use != next_to_clean
+@@ -1203,6 +1211,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 
+ 	e1000_vlan_filter_on_off(adapter, false);
+ 
++#ifdef DEV_NETMAP
++	e1000_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* print bus type/speed/width info */
+ 	e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
+ 	       ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
+@@ -1270,6 +1282,10 @@ static void e1000_remove(struct pci_dev *pdev)
+ 
+ 	kfree(adapter->tx_ring);
+ 	kfree(adapter->rx_ring);
++	
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
+ 
+ 	if (hw->mac_type == e1000_ce4100)
+ 		iounmap(hw->ce4100_gbe_mdio_base_virt);
+@@ -3834,6 +3850,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
+ 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
++		return 1; /* cleaned ok */
++#endif /* DEV_NETMAP */
+ 	i = tx_ring->next_to_clean;
+ 	eop = tx_ring->buffer_info[i].next_to_watch;
+ 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+@@ -4134,6 +4154,15 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
++	if (nm_irq != NM_IRQ_PASS) {
++		if (nm_irq == NM_IRQ_RESCHED) {
++			*work_done = work_to_do;
++		}
++		return 1;
++	}
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC(*rx_ring, i);
+ 	buffer_info = &rx_ring->buffer_info[i];
+@@ -4356,6 +4385,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ 	bool cleaned = false;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
++	if (nm_irq != NM_IRQ_PASS) {
++		if (nm_irq == NM_IRQ_RESCHED) {
++			*work_done = work_to_do;
++		}
++		return 1;
++	}
++#endif /* DEV_NETMAP */
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = E1000_RX_DESC(*rx_ring, i);
+ 	buffer_info = &rx_ring->buffer_info[i];
diff --git a/LINUX/final-patches/vanilla--ixgbe--50800--50a00 b/LINUX/final-patches/vanilla--ixgbe--50800--50a00
new file mode 100644
index 000000000..cae395415
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--50800--50a00
@@ -0,0 +1,117 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 97a423ecf808..a40ffcf4a6ee 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -460,6 +460,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1122,6 +1138,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2299,6 +2326,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+@@ -3537,6 +3574,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4144,6 +4185,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ 	else
+@@ -5644,6 +5689,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -11177,6 +11225,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 
+ 	ixgbe_mii_bus_init(hw);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -11223,6 +11275,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
+ 	set_bit(__IXGBE_REMOVING, &adapter->state);

From 3cf567e1b167470dc37a4da74b3f493aeb807e01 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 14 Dec 2020 14:15:36 +0100
Subject: [PATCH 1874/2207] linux: patches for 5.10 drivers

---
 ...20--41500 => vanilla--e1000--20620--99999} |   0
 .../vanilla--e1000--41400--99999              |  91 --------------
 ...800--99999 => vanilla--i40e--50800--50a00} |   0
 .../final-patches/vanilla--i40e--50a00--99999 | 115 ++++++++++++++++++
 ...00--99999 => vanilla--ixgbe--50a00--99999} |  26 ++--
 5 files changed, 128 insertions(+), 104 deletions(-)
 rename LINUX/final-patches/{vanilla--e1000--20620--41500 => vanilla--e1000--20620--99999} (100%)
 delete mode 100644 LINUX/final-patches/vanilla--e1000--41400--99999
 rename LINUX/final-patches/{vanilla--i40e--50800--99999 => vanilla--i40e--50800--50a00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--50a00--99999
 rename LINUX/final-patches/{vanilla--ixgbe--50800--99999 => vanilla--ixgbe--50a00--99999} (83%)

diff --git a/LINUX/final-patches/vanilla--e1000--20620--41500 b/LINUX/final-patches/vanilla--e1000--20620--99999
similarity index 100%
rename from LINUX/final-patches/vanilla--e1000--20620--41500
rename to LINUX/final-patches/vanilla--e1000--20620--99999
diff --git a/LINUX/final-patches/vanilla--e1000--41400--99999 b/LINUX/final-patches/vanilla--e1000--41400--99999
deleted file mode 100644
index d85b20fc7..000000000
--- a/LINUX/final-patches/vanilla--e1000--41400--99999
+++ /dev/null
@@ -1,91 +0,0 @@
-diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index 43b6d3cec3b3..43afd047fc95 100644
---- a/e1000/e1000_main.c
-+++ b/e1000/e1000_main.c
-@@ -179,6 +179,10 @@ static const struct pci_error_handlers e1000_err_handler = {
- 	.resume = e1000_io_resume,
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- static struct pci_driver e1000_driver = {
- 	.name     = e1000_driver_name,
- 	.id_table = e1000_pci_tbl,
-@@ -374,6 +378,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
- 	e1000_configure_tx(adapter);
- 	e1000_setup_rctl(adapter);
- 	e1000_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	if (e1000_netmap_init_buffers(adapter))
-+		return;
-+#endif /* DEV_NETMAP */
- 	/* call E1000_DESC_UNUSED which always leaves
- 	 * at least 1 descriptor unused to make sure
- 	 * next_to_use != next_to_clean
-@@ -1203,6 +1211,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 
- 	e1000_vlan_filter_on_off(adapter, false);
- 
-+#ifdef DEV_NETMAP
-+	e1000_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	/* print bus type/speed/width info */
- 	e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
- 	       ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
-@@ -1270,6 +1282,10 @@ static void e1000_remove(struct pci_dev *pdev)
- 
- 	kfree(adapter->tx_ring);
- 	kfree(adapter->rx_ring);
-+	
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
- 
- 	if (hw->mac_type == e1000_ce4100)
- 		iounmap(hw->ce4100_gbe_mdio_base_virt);
-@@ -3834,6 +3850,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
- 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
- 	unsigned int bytes_compl = 0, pkts_compl = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
-+		return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -4134,6 +4154,15 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		if (nm_irq == NM_IRQ_RESCHED) {
-+			*work_done = work_to_do;
-+		}
-+		return 1;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];
-@@ -4356,6 +4385,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		if (nm_irq == NM_IRQ_RESCHED) {
-+			*work_done = work_to_do;
-+		}
-+		return 1;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];
diff --git a/LINUX/final-patches/vanilla--i40e--50800--99999 b/LINUX/final-patches/vanilla--i40e--50800--50a00
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--50800--99999
rename to LINUX/final-patches/vanilla--i40e--50800--50a00
diff --git a/LINUX/final-patches/vanilla--i40e--50a00--99999 b/LINUX/final-patches/vanilla--i40e--50a00--99999
new file mode 100644
index 000000000..ad26c4b7a
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--50a00--99999
@@ -0,0 +1,115 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 1337686bd099..71244892b7a8 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -95,6 +95,10 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+ MODULE_LICENSE("GPL v2");
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+@@ -3254,6 +3258,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3344,6 +3352,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3372,6 +3384,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->xsk_pool) {
+ 		xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+ 		ok = i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring));
+@@ -13281,6 +13298,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -13646,6 +13668,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 3f5825fa67c9..53d7ae1922c8 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_txrx_common.h"
+ #include "i40e_xsk.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -782,6 +786,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2340,6 +2349,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/vanilla--ixgbe--50800--99999 b/LINUX/final-patches/vanilla--ixgbe--50a00--99999
similarity index 83%
rename from LINUX/final-patches/vanilla--ixgbe--50800--99999
rename to LINUX/final-patches/vanilla--ixgbe--50a00--99999
index cae395415..60def20af 100644
--- a/LINUX/final-patches/vanilla--ixgbe--50800--99999
+++ b/LINUX/final-patches/vanilla--ixgbe--50a00--99999
@@ -1,8 +1,8 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 97a423ecf808..a40ffcf4a6ee 100644
+index f3f449f53920..27545e40ab26 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
-@@ -460,6 +460,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+@@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
  	{ .name = NULL }
  };
  
@@ -25,7 +25,7 @@ index 97a423ecf808..a40ffcf4a6ee 100644
  
  /*
   * ixgbe_regdump - register printout routine
-@@ -1122,6 +1138,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+@@ -1120,6 +1136,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
  	if (test_bit(__IXGBE_DOWN, &adapter->state))
  		return true;
  
@@ -43,7 +43,7 @@ index 97a423ecf808..a40ffcf4a6ee 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2299,6 +2326,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+@@ -2301,6 +2328,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
  	unsigned int xdp_xmit = 0;
  	struct xdp_buff xdp;
  
@@ -60,7 +60,7 @@ index 97a423ecf808..a40ffcf4a6ee 100644
  	xdp.rxq = &rx_ring->xdp_rxq;
  
  	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
-@@ -3537,6 +3574,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+@@ -3540,6 +3577,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  	memset(ring->tx_buffer_info, 0,
  	       sizeof(struct ixgbe_tx_buffer) * ring->count);
  
@@ -71,7 +71,7 @@ index 97a423ecf808..a40ffcf4a6ee 100644
  	/* enable queue */
  	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
-@@ -4144,6 +4185,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -4147,6 +4188,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -79,10 +79,10 @@ index 97a423ecf808..a40ffcf4a6ee 100644
 +	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
 +		return;
 +#endif /* DEV_NETMAP */
- 	if (ring->xsk_umem)
+ 	if (ring->xsk_pool)
  		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
  	else
-@@ -5644,6 +5689,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -5673,6 +5718,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
@@ -92,9 +92,9 @@ index 97a423ecf808..a40ffcf4a6ee 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -11177,6 +11225,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 
- 	ixgbe_mii_bus_init(hw);
+@@ -11055,6 +11103,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_netdev;
  
 +#ifdef DEV_NETMAP
 +	ixgbe_netmap_attach(adapter);
@@ -102,8 +102,8 @@ index 97a423ecf808..a40ffcf4a6ee 100644
 +
  	return 0;
  
- err_register:
-@@ -11223,6 +11275,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ err_netdev:
+@@ -11103,6 +11155,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev  = adapter->netdev;

From 03d108226421d1ae4fc5f29ce4fb2499e83210a3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 17 Dec 2020 08:56:37 +0100
Subject: [PATCH 1875/2207] Revert "pkt-gen: allow -Z and -z to be used
 together"

This reverts commit 334e94600b3f43e08ed828c24ffe06016c26f584.

See comment on:

https://github.com/luigirizzo/netmap/commit/334e94600b3f43e08ed828c24ffe06016c26f584
---
 apps/pkt-gen/pkt-gen.c | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index e6237b8ba..958c4a52a 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -839,19 +839,19 @@ update_ip(struct pkt *pkt, struct targ *t)
 		}
 		naddr = g->src_ip.ipv4.start;
 		ip.ip_src.s_addr = htonl(naddr);
-	} while (0);
-	/* update checksums if needed */
-	if (oaddr != naddr) {
-		ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
-		ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
-		ip_sum = cksum_add(ip_sum, naddr >> 16);
-		ip_sum = cksum_add(ip_sum, naddr & 0xffff);
-	}
-	if (oport != nport) {
-		udp_sum = cksum_add(udp_sum, ~oport);
-		udp_sum = cksum_add(udp_sum, nport);
-	}
-	do {
+
+		/* update checksums if needed */
+		if (oaddr != naddr) {
+			ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
+			ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
+			ip_sum = cksum_add(ip_sum, naddr >> 16);
+			ip_sum = cksum_add(ip_sum, naddr & 0xffff);
+		}
+		if (oport != nport) {
+			udp_sum = cksum_add(udp_sum, ~oport);
+			udp_sum = cksum_add(udp_sum, nport);
+		}
+
 		naddr = oaddr = ntohl(ip.ip_dst.s_addr);
 		nport = oport = ntohs(udp.uh_dport);
 		if (g->options & OPT_RANDOM_DST) {
@@ -939,14 +939,14 @@ update_ip6(struct pkt *pkt, struct targ *t)
 		}
 		naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]);
 		ip6.ip6_src.s6_addr16[group] = htons(naddr);
-	} while (0);
-	/* update checksums if needed */
-	if (oaddr != naddr)
-		udp_sum = cksum_add(~oaddr, naddr);
-	if (oport != nport)
-		udp_sum = cksum_add(udp_sum,
-		    cksum_add(~oport, nport));
-	do {
+
+		/* update checksums if needed */
+		if (oaddr != naddr)
+			udp_sum = cksum_add(~oaddr, naddr);
+		if (oport != nport)
+			udp_sum = cksum_add(udp_sum,
+			    cksum_add(~oport, nport));
+
 		group = g->dst_ip.ipv6.egroup;
 		naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
 		nport = oport = ntohs(udp.uh_dport);

From a9846914dfa40d3bf1d2346639724bb1b7da74e3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 17 Dec 2020 09:47:28 +0100
Subject: [PATCH 1876/2207] pkt-gen: allow -Z -z without breaking ip/port range
 generation

---
 apps/pkt-gen/pkt-gen.c | 105 ++++++++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 49 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 958c4a52a..f961fd825 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -802,6 +802,25 @@ dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur)
 #define uh_sum check
 #endif /* linux */
 
+static uint16_t
+new_ip_sum(uint16_t ip_sum, uint32_t oaddr, uint32_t naddr)
+{
+	ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
+	ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
+	ip_sum = cksum_add(ip_sum, naddr >> 16);
+	ip_sum = cksum_add(ip_sum, naddr & 0xffff);
+	return ip_sum;
+}
+
+static uint16_t
+new_udp_sum(uint16_t udp_sum, uint16_t oport, uint16_t nport)
+{
+	udp_sum = cksum_add(udp_sum, ~oport);
+	udp_sum = cksum_add(udp_sum, nport);
+	return udp_sum;
+}
+
+
 static void
 update_ip(struct pkt *pkt, struct targ *t)
 {
@@ -810,7 +829,7 @@ update_ip(struct pkt *pkt, struct targ *t)
 	struct udphdr udp;
 	uint32_t oaddr, naddr;
 	uint16_t oport, nport;
-	uint16_t ip_sum, udp_sum;
+	uint16_t ip_sum = 0, udp_sum = 0;
 
 	memcpy(&ip, &pkt->ipv4.ip, sizeof(ip));
 	memcpy(&udp, &pkt->ipv4.udp, sizeof(udp));
@@ -823,33 +842,26 @@ update_ip(struct pkt *pkt, struct targ *t)
 			udp.uh_sport = nrand48(t->seed);
 			naddr = ntohl(ip.ip_src.s_addr);
 			nport = ntohs(udp.uh_sport);
-			break;
-		}
-		if (oport < g->src_ip.port1) {
-			nport = oport + 1;
+			ip_sum = new_ip_sum(ip_sum, oaddr, naddr);
+			udp_sum = new_udp_sum(udp_sum, oport, nport);
+		} else {
+			if (oport < g->src_ip.port1) {
+				nport = oport + 1;
+				udp.uh_sport = htons(nport);
+				udp_sum = new_udp_sum(udp_sum, oport, nport);
+				break;
+			}
+			nport = g->src_ip.port0;
 			udp.uh_sport = htons(nport);
-			break;
-		}
-		nport = g->src_ip.port0;
-		udp.uh_sport = htons(nport);
-		if (oaddr < g->src_ip.ipv4.end) {
-			naddr = oaddr + 1;
+			if (oaddr < g->src_ip.ipv4.end) {
+				naddr = oaddr + 1;
+				ip.ip_src.s_addr = htonl(naddr);
+				ip_sum = new_ip_sum(ip_sum, oaddr, naddr);
+				break;
+			}
+			naddr = g->src_ip.ipv4.start;
 			ip.ip_src.s_addr = htonl(naddr);
-			break;
-		}
-		naddr = g->src_ip.ipv4.start;
-		ip.ip_src.s_addr = htonl(naddr);
-
-		/* update checksums if needed */
-		if (oaddr != naddr) {
-			ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
-			ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
-			ip_sum = cksum_add(ip_sum, naddr >> 16);
-			ip_sum = cksum_add(ip_sum, naddr & 0xffff);
-		}
-		if (oport != nport) {
-			udp_sum = cksum_add(udp_sum, ~oport);
-			udp_sum = cksum_add(udp_sum, nport);
+			ip_sum = new_ip_sum(ip_sum, oaddr, naddr);
 		}
 
 		naddr = oaddr = ntohl(ip.ip_dst.s_addr);
@@ -859,34 +871,29 @@ update_ip(struct pkt *pkt, struct targ *t)
 			udp.uh_dport = nrand48(t->seed);
 			naddr = ntohl(ip.ip_dst.s_addr);
 			nport = ntohs(udp.uh_dport);
-			break;
-		}
-		if (oport < g->dst_ip.port1) {
-			nport = oport + 1;
+			ip_sum = new_ip_sum(ip_sum, oaddr, naddr);
+			udp_sum = new_udp_sum(udp_sum, oport, nport);
+		} else {
+			if (oport < g->dst_ip.port1) {
+				nport = oport + 1;
+				udp.uh_dport = htons(nport);
+				udp_sum = new_udp_sum(udp_sum, oport, nport);
+				break;
+			}
+			nport = g->dst_ip.port0;
 			udp.uh_dport = htons(nport);
-			break;
-		}
-		nport = g->dst_ip.port0;
-		udp.uh_dport = htons(nport);
-		if (oaddr < g->dst_ip.ipv4.end) {
-			naddr = oaddr + 1;
+			if (oaddr < g->dst_ip.ipv4.end) {
+				naddr = oaddr + 1;
+				ip.ip_dst.s_addr = htonl(naddr);
+				ip_sum = new_ip_sum(ip_sum, oaddr, naddr);
+				break;
+			}
+			naddr = g->dst_ip.ipv4.start;
 			ip.ip_dst.s_addr = htonl(naddr);
-			break;
+			ip_sum = new_ip_sum(ip_sum, oaddr, naddr);
 		}
-		naddr = g->dst_ip.ipv4.start;
-		ip.ip_dst.s_addr = htonl(naddr);
 	} while (0);
 	/* update checksums */
-	if (oaddr != naddr) {
-		ip_sum = cksum_add(ip_sum, ~oaddr >> 16);
-		ip_sum = cksum_add(ip_sum, ~oaddr & 0xffff);
-		ip_sum = cksum_add(ip_sum, naddr >> 16);
-		ip_sum = cksum_add(ip_sum, naddr & 0xffff);
-	}
-	if (oport != nport) {
-		udp_sum = cksum_add(udp_sum, ~oport);
-		udp_sum = cksum_add(udp_sum, nport);
-	}
 	if (udp_sum != 0)
 		udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum));
 	if (ip_sum != 0) {

From 9fa9e25ad61b8e8ad4ec8e9470a45b1012a42a19 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 17 Dec 2020 19:25:58 +0100
Subject: [PATCH 1877/2207] linux/virtio: fix uninitialized xdp and napi_tx
 data structures

---
 .../vanilla--virtio_net.c--30300--30500       | 13 ++-
 .../vanilla--virtio_net.c--30500--30800       | 17 ++--
 ...00 => vanilla--virtio_net.c--30800--30a00} | 19 ++---
 .../vanilla--virtio_net.c--30a00--30b00       | 85 +++++++++++++++++++
 .../vanilla--virtio_net.c--30b00--31100       | 19 ++---
 .../vanilla--virtio_net.c--31100--31300       | 19 ++---
 .../vanilla--virtio_net.c--31300--40100       | 19 ++---
 .../vanilla--virtio_net.c--40100--40900       | 19 ++---
 .../vanilla--virtio_net.c--40900--40c00       | 21 +++--
 .../vanilla--virtio_net.c--40c00--40f00       | 21 +++--
 .../vanilla--virtio_net.c--40f00--41000       | 21 +++--
 .../vanilla--virtio_net.c--41000--41100       | 21 +++--
 .../vanilla--virtio_net.c--41100--99999       | 21 +++--
 13 files changed, 192 insertions(+), 123 deletions(-)
 rename LINUX/final-patches/{vanilla--virtio_net.c--30800--30b00 => vanilla--virtio_net.c--30800--30a00} (85%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00

diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
index 7f5e9463b..b233d3428 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 4880aa8b4c28..64e3625b1750 100644
+index 4880aa8b4c28..6521c7e1b366 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -80,6 +80,10 @@ struct virtnet_info {
@@ -42,22 +42,19 @@ index 4880aa8b4c28..64e3625b1750 100644
  again:
  	while (received < budget &&
  	       (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
-@@ -727,7 +745,14 @@ static void virtnet_netpoll(struct net_device *dev)
+@@ -727,7 +745,11 @@ static void virtnet_netpoll(struct net_device *dev)
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
 +#ifdef DEV_NETMAP
 +	int ok = virtio_netmap_init_buffers(vi);
  
-+	if (ok) {
-+		virtnet_napi_enable(vi);
-+		return 0;
-+	}
++	if (!ok)
 +#endif
  	/* Make sure we have some buffers: if oom use wq. */
  	if (!try_fill_recv(vi, GFP_KERNEL))
  		queue_delayed_work(system_nrt_wq, &vi->refill, 0);
-@@ -1107,6 +1132,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1107,6 +1129,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto unregister;
  	}
  
@@ -68,7 +65,7 @@ index 4880aa8b4c28..64e3625b1750 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1169,7 +1198,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1169,7 +1195,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void __devexit virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
index 51dbf469e..bd6128748 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index f18149ae2588..cc935cfce8b2 100644
+index f18149ae2588..19d344ac1326 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -90,6 +90,10 @@ struct virtnet_info {
@@ -42,22 +42,19 @@ index f18149ae2588..cc935cfce8b2 100644
  again:
  	while (received < budget &&
  	       (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
-@@ -742,6 +760,14 @@ static void virtnet_netpoll(struct net_device *dev)
+@@ -742,7 +760,11 @@ static void virtnet_netpoll(struct net_device *dev)
  static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
 +#ifdef DEV_NETMAP
 +	int ok = virtio_netmap_init_buffers(vi);
-+
-+	if (ok) {
-+		virtnet_napi_enable(vi);
-+		return 0;
-+	}
-+#endif
  
++	if (!ok)
++#endif
  	/* Make sure we have some buffers: if oom use wq. */
  	if (!try_fill_recv(vi, GFP_KERNEL))
-@@ -1148,6 +1174,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		queue_delayed_work(system_nrt_wq, &vi->refill, 0);
+@@ -1148,6 +1170,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto unregister;
  	}
  
@@ -68,7 +65,7 @@ index f18149ae2588..cc935cfce8b2 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1210,7 +1240,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1210,7 +1236,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void __devexit virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00 b/LINUX/final-patches/vanilla--virtio_net.c--30800--30a00
similarity index 85%
rename from LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
rename to LINUX/final-patches/vanilla--virtio_net.c--30800--30a00
index b75bfeb91..faf009b22 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30800--30b00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30800--30a00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 35c00c5ea02a..bfbb1787ec55 100644
+index 35c00c5ea02a..93a37247e2c8 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -132,6 +132,10 @@ struct virtnet_info {
@@ -42,23 +42,22 @@ index 35c00c5ea02a..bfbb1787ec55 100644
  again:
  	while (received < budget &&
  	       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
-@@ -635,6 +653,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -635,8 +653,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(&vi->rq[i]);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		/* Make sure we have some buffers: if oom use wq. */
-@@ -1572,6 +1599,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+ 			schedule_delayed_work(&vi->refill, 0);
+@@ -1572,6 +1596,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -69,7 +68,7 @@ index 35c00c5ea02a..bfbb1787ec55 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1617,7 +1648,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1617,7 +1645,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00 b/LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00
new file mode 100644
index 000000000..600fd790d
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00
@@ -0,0 +1,85 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index c9e00387d999..3d4fcc032940 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -131,6 +131,10 @@ struct virtnet_info {
+ 	struct notifier_block nb;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct skb_vnet_hdr {
+ 	union {
+ 		struct virtio_net_hdr hdr;
+@@ -210,6 +214,10 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
+ 	/* We were probably waiting for more output buffers. */
+ 	netif_wake_subqueue(vi->dev, vq2txq(vq));
+ }
+@@ -603,7 +611,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	struct virtnet_info *vi = rq->vq->vdev->priv;
+ 	void *buf;
+ 	unsigned int len, received = 0;
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
+ 
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++	} else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++        }
++#endif
+ again:
+ 	while (received < budget &&
+ 	       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
+@@ -635,8 +653,14 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++#endif
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
+ 		if (i < vi->curr_queue_pairs)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+@@ -1594,6 +1618,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		goto free_recv_bufs;
+ 	}
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+@@ -1639,7 +1667,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	unregister_hotcpu_notifier(&vi->nb);
+ 
+ 	/* Prevent config work handler from accessing the device. */
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
index 29a0d5966..22b4bf14a 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 3d2a90a62649..23654348b613 100644
+index 3d2a90a62649..435ad46baab3 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -131,6 +131,10 @@ struct virtnet_info {
@@ -42,23 +42,22 @@ index 3d2a90a62649..23654348b613 100644
  again:
  	while (received < budget &&
  	       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
-@@ -636,6 +654,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -636,8 +654,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(&vi->rq[i]);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -1592,6 +1619,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+@@ -1592,6 +1616,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -69,7 +68,7 @@ index 3d2a90a62649..23654348b613 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1637,7 +1668,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1637,7 +1665,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
index 09db3f340..c2278934d 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 59caa06f34a6..b64cb151db9f 100644
+index 59caa06f34a6..2480ecd71b1d 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -145,6 +145,10 @@ struct virtnet_info {
@@ -44,23 +44,22 @@ index 59caa06f34a6..b64cb151db9f 100644
  again:
  	received += virtnet_receive(rq, budget - received);
  
-@@ -813,6 +834,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -813,8 +834,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(&vi->rq[i]);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -1826,6 +1856,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+@@ -1826,6 +1853,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -71,7 +70,7 @@ index 59caa06f34a6..b64cb151db9f 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1872,7 +1906,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1872,7 +1903,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
index bc49240cf..e6caac237 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 059fdf1bf5ee..d79cd6a386e0 100644
+index 059fdf1bf5ee..8c97bc74d8a5 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
@@ -44,23 +44,22 @@ index 059fdf1bf5ee..d79cd6a386e0 100644
  	received += virtnet_receive(rq, budget - received);
  
  	/* Out of packets? */
-@@ -808,6 +829,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -808,8 +829,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(&vi->rq[i]);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -1859,6 +1889,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -1859,6 +1886,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -71,7 +70,7 @@ index 059fdf1bf5ee..d79cd6a386e0 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1907,7 +1941,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1907,7 +1938,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900 b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
index 3e453fd44..d4755f270 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40100--40900
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 63c7810e1545..f5fc43c34afa 100644
+index 63c7810e1545..0115f62b92fe 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
@@ -44,23 +44,22 @@ index 63c7810e1545..f5fc43c34afa 100644
  	received = virtnet_receive(rq, budget);
  
  	/* Out of packets? */
-@@ -808,6 +829,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -808,8 +829,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(&vi->rq[i]);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -1881,6 +1911,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -1881,6 +1908,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -71,7 +70,7 @@ index 63c7810e1545..f5fc43c34afa 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1929,7 +1963,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1929,7 +1960,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00 b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
index e852dffa3..06d2d6579 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40900--40c00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index cbf1c613c67a..be4daabbc51b 100644
+index cbf1c613c67a..4b9be7350412 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -155,6 +155,10 @@ struct virtnet_info {
@@ -44,23 +44,22 @@ index cbf1c613c67a..be4daabbc51b 100644
  	received = virtnet_receive(rq, budget);
  
  	/* Out of packets? */
-@@ -787,6 +808,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -787,8 +808,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(&vi->rq[i]);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -1928,6 +1958,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -1928,6 +1955,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_unregister_netdev;
  	}
  
@@ -71,7 +70,7 @@ index cbf1c613c67a..be4daabbc51b 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1975,7 +2009,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1975,7 +2006,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
@@ -86,7 +85,7 @@ index cbf1c613c67a..be4daabbc51b 100644
  	virtnet_cpu_notif_remove(vi);
  
  	/* Make sure no work handler is accessing the device. */
-@@ -2072,6 +2113,9 @@ static unsigned int features_legacy[] = {
+@@ -2072,6 +2110,9 @@ static unsigned int features_legacy[] = {
  	VIRTNET_FEATURES,
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00 b/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
index b254abd9b..38c23f055 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40c00--40f00
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 143d8a95a60d..27de2c282e08 100644
+index 143d8a95a60d..bd58e50c4597 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -170,6 +170,10 @@ struct virtnet_info {
@@ -48,23 +48,22 @@ index 143d8a95a60d..27de2c282e08 100644
  	received = virtnet_receive(rq, budget);
  
  	/* Out of packets? */
-@@ -1114,6 +1137,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -1114,8 +1137,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -2559,6 +2591,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -2559,6 +2588,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  
@@ -75,7 +74,7 @@ index 143d8a95a60d..27de2c282e08 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -2615,7 +2651,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -2615,7 +2648,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
@@ -90,7 +89,7 @@ index 143d8a95a60d..27de2c282e08 100644
  	virtnet_cpu_notif_remove(vi);
  
  	/* Make sure no work handler is accessing the device. */
-@@ -2684,6 +2727,9 @@ static unsigned int features_legacy[] = {
+@@ -2684,6 +2724,9 @@ static unsigned int features_legacy[] = {
  	VIRTNET_FEATURES,
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--40f00--41000 b/LINUX/final-patches/vanilla--virtio_net.c--40f00--41000
index 992fa8cac..36b7a5ba0 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--40f00--41000
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40f00--41000
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 559b215c0169..00aad16f3aa2 100644
+index 559b215c0169..58c22e47b387 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -181,6 +181,10 @@ struct virtnet_info {
@@ -45,23 +45,22 @@ index 559b215c0169..00aad16f3aa2 100644
  	virtnet_poll_cleantx(rq);
  
  	received = virtnet_receive(rq, budget, &xdp_xmit);
-@@ -1223,6 +1245,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -1223,8 +1245,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -2685,6 +2716,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -2685,6 +2713,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  
@@ -72,7 +71,7 @@ index 559b215c0169..00aad16f3aa2 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -2736,7 +2771,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -2736,7 +2768,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
@@ -87,7 +86,7 @@ index 559b215c0169..00aad16f3aa2 100644
  	virtnet_cpu_notif_remove(vi);
  
  	/* Make sure no work handler is accessing the device. */
-@@ -2803,6 +2845,9 @@ static unsigned int features_legacy[] = {
+@@ -2803,6 +2842,9 @@ static unsigned int features_legacy[] = {
  	VIRTNET_FEATURES,
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--41000--41100 b/LINUX/final-patches/vanilla--virtio_net.c--41000--41100
index 9b71a0a9c..0020198a1 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--41000--41100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--41000--41100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 23374603e4d9..fc0d8be71d4e 100644
+index 23374603e4d9..7fee058adcb6 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -208,6 +208,10 @@ struct virtnet_info {
@@ -45,23 +45,22 @@ index 23374603e4d9..fc0d8be71d4e 100644
  	virtnet_poll_cleantx(rq);
  
  	received = virtnet_receive(rq, budget, &xdp_xmit);
-@@ -1290,6 +1312,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -1290,8 +1312,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i, err;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -2855,6 +2886,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -2855,6 +2883,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  
@@ -72,7 +71,7 @@ index 23374603e4d9..fc0d8be71d4e 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -2905,7 +2940,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -2905,7 +2937,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
@@ -87,7 +86,7 @@ index 23374603e4d9..fc0d8be71d4e 100644
  	virtnet_cpu_notif_remove(vi);
  
  	/* Make sure no work handler is accessing the device. */
-@@ -2972,6 +3014,9 @@ static unsigned int features_legacy[] = {
+@@ -2972,6 +3011,9 @@ static unsigned int features_legacy[] = {
  	VIRTNET_FEATURES,
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--41100--99999 b/LINUX/final-patches/vanilla--virtio_net.c--41100--99999
index f76a4eae6..edc261a9a 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--41100--99999
+++ b/LINUX/final-patches/vanilla--virtio_net.c--41100--99999
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 032e1ac10a30..522036830681 100644
+index 032e1ac10a30..7e92e484d0ab 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -212,6 +212,10 @@ struct virtnet_info {
@@ -44,23 +44,22 @@ index 032e1ac10a30..522036830681 100644
  	virtnet_poll_cleantx(rq);
  
  	received = virtnet_receive(rq, budget, &xdp_xmit);
-@@ -1300,6 +1321,15 @@ static int virtnet_open(struct net_device *dev)
+@@ -1300,8 +1321,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i, err;
 +#ifdef DEV_NETMAP
 +        int ok = virtio_netmap_init_buffers(vi);
-+
-+        if (ok) {
-+            for (i = 0; i < vi->max_queue_pairs; i++)
-+		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
-+            return 0;
-+        }
 +#endif
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
++#ifdef DEV_NETMAP
++		if (!ok)
++#endif
  		if (i < vi->curr_queue_pairs)
-@@ -2871,6 +2901,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 			/* Make sure we have some buffers: if oom use wq. */
+ 			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
+@@ -2871,6 +2898,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  
@@ -71,7 +70,7 @@ index 032e1ac10a30..522036830681 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	netif_carrier_off(dev);
-@@ -2921,7 +2955,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -2921,7 +2952,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
@@ -86,7 +85,7 @@ index 032e1ac10a30..522036830681 100644
  	virtnet_cpu_notif_remove(vi);
  
  	/* Make sure no work handler is accessing the device. */
-@@ -2988,6 +3029,9 @@ static unsigned int features_legacy[] = {
+@@ -2988,6 +3026,9 @@ static unsigned int features_legacy[] = {
  	VIRTNET_FEATURES,
  	VIRTIO_NET_F_GSO,
  	VIRTIO_F_ANY_LAYOUT,

From f621df2112b9c276575dda0bcfde857dc373dbb6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 17 Dec 2020 20:20:16 +0100
Subject: [PATCH 1878/2207] monitor: set a flag in slots containing tx packets

---
 sys/dev/netmap/netmap_monitor.c | 8 ++++++--
 sys/net/netmap.h                | 5 +++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 42096dd1f..1d5b7b962 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -38,6 +38,8 @@
  * the traffic transiting on both the tx and rx corresponding rings in the
  * monitored adapter. During registration, the user can choose if she wants
  * to intercept tx only, rx only, or both tx and rx traffic.
+ * The slots containing traffic intercepted in the tx direction will have
+ * the NS_TXMON flag set.
  *
  * If the monitor is not able to cope with the stream of frames, excess traffic
  * will be dropped.
@@ -590,6 +592,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 	u_int beg, end, i;
 	u_int lim = kring->nkr_num_slots - 1,
 	      mlim; // = mkring->nkr_num_slots - 1;
+	uint16_t txmon = kring->tx == NR_TX ? NS_TXMON : 0;
 
 	if (mkring == NULL) {
 		nm_prlim(5, "NULL monitor on %s", kring->name);
@@ -659,7 +662,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 		ms->len = s->len;
 		s->len = tmp;
 
-		ms->flags = s->flags;
+		ms->flags = (s->flags & ~NS_TXMON) | txmon;
 		s->flags |= NS_BUF_CHANGED;
 
 		beg = nm_next(beg, lim);
@@ -726,6 +729,7 @@ static void
 netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots)
 {
 	u_int j;
+	uint16_t txmon = kring->tx == NR_TX ? NS_TXMON : 0;
 
 	for (j = 0; j < kring->n_monitors; j++) {
 		struct netmap_kring *mkring = kring->monitors[j];
@@ -777,7 +781,7 @@ netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_
 
 			memcpy(dst, src, copy_len);
 			ms->len = copy_len;
-			ms->flags = s->flags;
+			ms->flags = (s->flags & ~NS_TXMON) | txmon;
 			sent++;
 
 			beg = nm_next(beg, lim);
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 1607d8ecc..f4260fb58 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -219,6 +219,11 @@ struct netmap_slot {
 	 * The 'len' field refers to the individual fragment.
 	 */
 
+#define NS_TXMON	0x0040
+	/* (monitor ports only) the packet comes from the TX
+	 * ring of the monitored port
+	 */
+
 #define	NS_PORT_SHIFT	8
 #define	NS_PORT_MASK	(0xff << NS_PORT_SHIFT)
 	/*

From b6f4f4e003d63784a4e81fbe7b36088e7570b096 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 18 Dec 2020 14:18:29 +0100
Subject: [PATCH 1879/2207] linux/scripts: support gcc-10

---
 LINUX/scripts/np | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index b7985cdb9..2b572d2db 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -378,7 +378,7 @@ function build-prep()
 	(
 		cd $dst
 		last=compiler-gcc.h
-		for i in $(seq 9); do
+		for i in $(seq 10); do
 			[ -e include/linux/compiler-gcc$i.h ] ||
 				ln -s $last include/linux/compiler-gcc$i.h
 			last=compiler-gcc$i.h
@@ -391,6 +391,9 @@ KBUILD_CFLAGS += $(call cc-option, -no-pie)\
 KBUILD_CFLAGS += $(call cc-option, -fcf-protection=none)\
 KBUILD_AFLAGS += $(call cc-option, -fno-pie)\
 KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
+		# remove duplicated yylloc definition, since gcc-10 defaults to -fno-common
+		sed -i -e '/^[[:blank:]]*YYLTYPE[[:blank:]][[:blank:]]*yylloc;[[:blank:]]*$/d' \
+			scripts/dtc/dtc-lexer*
 		if [ -f $LINUX_CONFIGS/config-$version ]; then
 			cp $LINUX_CONFIGS/config-$version .config
 			yes '' | make oldconfig

From 7c12af1680b9c3271462688a01e071b3fd61f511 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 18 Dec 2020 16:04:39 +0100
Subject: [PATCH 1880/2207] linux/scripts: compile old kernels with gcc-10

---
 LINUX/scripts/np | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 2b572d2db..95ad2bb0f 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -394,6 +394,9 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		# remove duplicated yylloc definition, since gcc-10 defaults to -fno-common
 		sed -i -e '/^[[:blank:]]*YYLTYPE[[:blank:]][[:blank:]]*yylloc;[[:blank:]]*$/d' \
 			scripts/dtc/dtc-lexer*
+		# make sure per_cpu_load_addr is static
+		sed -i -e 's/^[[:blank:]]*Elf_Addr[[:blank:]][[:blank:]]*per_cpu_load_addr;/static &/' \
+			arch/x86/tools/relocs.c
 		if [ -f $LINUX_CONFIGS/config-$version ]; then
 			cp $LINUX_CONFIGS/config-$version .config
 			yes '' | make oldconfig

From 4ffdbb73f99e6f8f43880c5154d27047322d498c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 18 Dec 2020 16:28:16 +0100
Subject: [PATCH 1881/2207] linux/scripts: also make scripts when preparing
 linux sources

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 95ad2bb0f..b73c99783 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -408,7 +408,7 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		yes '' | make oldconfig
 		# some tools do not compile with -Werror and gcc >= 9
 		sed -i 's/-Werror/-Wno-error/g' $(grep -Rl -- -Werror tools)
-		make modules_prepare
+		make scripts modules_prepare
 		touch .build-prep
 	) >$dst.log 2>&1 || error "build-prep failed for linux $version. Please check $dst.log"
 	echo $dst

From f278b08a780e6c10855702dc67e531f9d219920f Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 2 Jan 2021 11:19:30 +0100
Subject: [PATCH 1882/2207] fix compilation on i386

---
 apps/vale-ctl/vale-ctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index 7e219e2df..bf1bc6229 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -181,7 +181,7 @@ list_all(int fd, struct nmreq_header *hdr)
 {
 	int error;
 	struct nmreq_vale_list *vale_list =
-		(struct nmreq_vale_list *)hdr->nr_body;
+		(struct nmreq_vale_list *)(uintptr_t)hdr->nr_body;
 
 	for (;;) {
 		hdr->nr_name[0] = '\0';

From 7d39de1cd94120b378aade44d921a2a7af1045e1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 4 Jan 2021 23:54:20 +0100
Subject: [PATCH 1883/2207] linux: use pin_user_pages* when available

---
 LINUX/configure      | 10 ++++++++++
 LINUX/netmap_linux.c | 12 +++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 770df2605..66ead4cc3 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1701,6 +1701,16 @@ EOF
 	}
 EOF
 
+  add_test 'have PIN_PAGES' <
+
+	long
+	dummy(unsigned long start, unsigned long nr_pages,
+		unsigned int gup_flags, struct page **pages) {
+		return pin_user_pages_unlocked(start, nr_pages, pages, gup_flags);
+	}
+EOF
+
 # check for page_to_virt
   add_test 'have PAGE_TO_VIRT' <
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 057f27b3b..6ffa7d40e 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -192,7 +192,11 @@ nm_os_extmem_delete(struct nm_os_extmem *e)
 	for (i = 0; i < e->nr_pages; i++) {
 		if (i < e->mapped)
 			kunmap(e->pages[i]);
+#ifdef NETMAP_LINUX_HAVE_PIN_PAGES
+		unpin_user_page(e->pages[i]);
+#else
 		put_page(e->pages[i]);
+#endif
 	}
 	if (e->pages)
 		nm_os_vfree(e->pages);
@@ -258,7 +262,13 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 
 	e->pages = pages;
 
-#ifdef NETMAP_LINUX_HAVE_GUP_4ARGS
+#ifdef NETMAP_LINUX_HAVE_PIN_PAGES
+	res = pin_user_pages_unlocked(
+			p,
+			nr_pages,
+			pages,
+			FOLL_WRITE | FOLL_SPLIT | FOLL_POPULATE);
+#elif NETMAP_LINUX_HAVE_GUP_4ARGS
 	res = get_user_pages_unlocked(
 			p,
 			nr_pages,

From c2127e72f65b44e6dc41b7284d1eb82674d64a5a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 2 Jan 2021 17:43:44 +0100
Subject: [PATCH 1884/2207] linux/e1000e: commit offset support

---
 LINUX/if_e1000e_netmap.h | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 455f28a14..e3955efe8 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -209,13 +209,14 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			u_int len = slot->len;
 			uint64_t paddr;
-			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
 
 			/* device-specific */
 			struct e1000_tx_desc *curr = E1000_TX_DESC(*txr, nic_i);
 			int hw_flags = E1000_TXD_CMD_IFCS;
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
 			if (!(slot->flags & NS_MOREFRAG)) {
 				hw_flags |= adapter->txd_cmd;
@@ -223,15 +224,13 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 				 * We may set it only if NS_REPORT is set or
 				 * at least once every half ring. */
 			}
-			if (slot->flags & NS_BUF_CHANGED) {
-				curr->buffer_addr = htole64(paddr);
-			}
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 
 			/* Fill the slot in the NIC ring. */
+			curr->buffer_addr = htole64(paddr + offset);
 			curr->upper.data = 0;
 			curr->lower.data = htole32(len | hw_flags);
-			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
@@ -266,7 +265,7 @@ e1000_netmap_txsync(struct netmap_kring *kring, int flags)
 		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
 			struct netmap_slot *slot = &ring->slot[tosync];
 			uint64_t paddr;
-			(void)PNMB(na, slot, &paddr);
+			(void)PNMB_O(kring, slot, &paddr);
 
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_TX);
@@ -326,7 +325,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			dma_rmb();  /* read descriptor after status DD */
-			PNMB(na, slot, &paddr);
+			PNMB_O(kring, slot, &paddr);
 			slot->len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
 			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr,
@@ -474,7 +473,7 @@ e1000_netmap_attach(struct SOFTC_T *adapter)
 
 	na.ifp = adapter->netdev;
 	na.pdev = &adapter->pdev->dev;
-	na.na_flags = NAF_MOREFRAG;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
 	na.num_tx_desc = adapter->tx_ring->count;
 	na.num_rx_desc = adapter->rx_ring->count;
 	na.num_tx_rings = na.num_rx_rings = 1;

From cf997a2d3177f938c86335dcceebee925bf48a61 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Jan 2021 14:28:54 +0100
Subject: [PATCH 1885/2207] mem: align totalsize to PAGE_SIZE

---
 sys/dev/netmap/netmap_mem2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8e77299d5..06ed557bf 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1640,6 +1640,7 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
 			goto error;
 		nmd->nm_totalsize += nmd->pools[i].memtotal;
 	}
+	nmd->nm_totalsize = (nmd->nm_totalsize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
 	nmd->lasterr = netmap_mem_init_bitmaps(nmd);
 	if (nmd->lasterr)
 		goto error;

From baefcfd968158635325410c964a181db87fd9004 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Jan 2021 15:35:35 +0100
Subject: [PATCH 1886/2207] extmem: remove obsolete flag

---
 LINUX/netmap_linux.c         | 2 --
 sys/dev/netmap/netmap_mem2.h | 1 -
 2 files changed, 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 6ffa7d40e..a16aa0e4c 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1302,8 +1302,6 @@ linux_netmap_mmap(struct file *f, struct vm_area_struct *vma)
 			(vma->vm_end - vma->vm_start), memsize);
 	if (off + (vma->vm_end - vma->vm_start) > memsize)
 		return -EINVAL;
-	if (memflags & NETMAP_MEM_EXT)
-		return -ENODEV;
 	if (memflags & NETMAP_MEM_IO) {
 		vm_ooffset_t pa;
 
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 8c4bf256f..1707955ed 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -172,7 +172,6 @@ int netmap_mem_pools_info_get(struct nmreq_pools_info *,
 
 #define NETMAP_MEM_PRIVATE	0x2	/* allocator uses private address space */
 #define NETMAP_MEM_IO		0x4	/* the underlying memory is mmapped I/O */
-#define NETMAP_MEM_EXT		0x10	/* external memory (not remappable) */
 
 uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
 

From 4859633feefe6fcfe5daab18db6633684da309e7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 5 Jan 2021 18:30:29 +0100
Subject: [PATCH 1887/2207] extmem: try to use all user-provided memory

---
 sys/dev/netmap/netmap_mem2.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 06ed557bf..d7ec681c3 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1668,10 +1668,16 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
  */
 static void *
 _netmap_mem_private_new(size_t size, struct netmap_obj_params *p,
-		struct netmap_mem_ops *ops, int *perr)
+		struct netmap_mem_ops *ops, uint64_t memtotal, int *perr)
 {
 	struct netmap_mem_d *d = NULL;
 	int i, err = 0;
+	int checksz = 0;
+
+	/* if memtotal is !=0 we check that the request fits the available
+	 * memory. Moreover, any surprlus memory is assigned to buffers.
+	 */
+	checksz = (memtotal > 0);
 
 	d = nm_os_malloc(size);
 	if (d == NULL) {
@@ -1691,9 +1697,30 @@ _netmap_mem_private_new(size_t size, struct netmap_obj_params *p,
 		snprintf(d->pools[i].name, NETMAP_POOL_MAX_NAMSZ,
 				nm_blueprint.pools[i].name,
 				d->name);
+		if (checksz) {
+			uint64_t poolsz = p[i].num * p[i].size;
+			if (memtotal < poolsz) {
+				nm_prerr("%s: request too large", d->pools[i].name);
+				err = ENOMEM;
+				goto error;
+			}
+			memtotal -= poolsz;
+		}
 		d->params[i].num = p[i].num;
 		d->params[i].size = p[i].size;
 	}
+	if (checksz && memtotal > 0) {
+		uint64_t sz = d->params[NETMAP_BUF_POOL].size;
+		uint64_t n = (memtotal + sz - 1) / sz;
+
+		if (n) {
+			if (netmap_verbose) {
+				nm_prinf("%s: adding %llu more buffers",
+						d->pools[NETMAP_BUF_POOL].name, n);
+			}
+			d->params[NETMAP_BUF_POOL].num += n;
+		}
+	}
 
 	NMA_LOCK_INIT(d);
 
@@ -1769,7 +1796,7 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 			p[NETMAP_BUF_POOL].num,
 			p[NETMAP_BUF_POOL].size);
 
-	d = _netmap_mem_private_new(sizeof(*d), p, &netmap_mem_global_ops, perr);
+	d = _netmap_mem_private_new(sizeof(*d), p, &netmap_mem_global_ops, 0, perr);
 
 	return d;
 }
@@ -2280,6 +2307,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 				{ pi->nr_ring_pool_objsize, pi->nr_ring_pool_objtotal },
 				{ pi->nr_buf_pool_objsize, pi->nr_buf_pool_objtotal }},
 			&netmap_mem_ext_ops,
+			pi->nr_memsize,
 			&error);
 	if (nme == NULL)
 		goto out_unmap;

From e0d6b4710a0846e7ddf4fc4c78f38085ff466be2 Mon Sep 17 00:00:00 2001
From: jbouchard 
Date: Tue, 5 Jan 2021 15:52:30 -0500
Subject: [PATCH 1888/2207] append to ldflags instead of assignation

---
 apps/pkt-gen/GNUmakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/GNUmakefile b/apps/pkt-gen/GNUmakefile
index 62d6d5b2b..5a206d821 100644
--- a/apps/pkt-gen/GNUmakefile
+++ b/apps/pkt-gen/GNUmakefile
@@ -14,7 +14,7 @@ CFLAGS += -Werror -Wall -Wunused-function
 CFLAGS += -I $(SRCDIR)/sys -I $(SRCDIR)/apps/include -I $(SRCDIR)/libnetmap
 CFLAGS += -Wextra -Wno-address-of-packed-member
 
-LDFLAGS = -L $(BUILDDIR)/build-libnetmap
+LDFLAGS += -L $(BUILDDIR)/build-libnetmap
 LDLIBS += -lpthread -lm -lnetmap
 ifeq ($(shell uname),Linux)
 	LDLIBS += -lrt	# on linux

From 8f8a4c31dc315a65c9298eca37bf88ee891115f0 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Thu, 7 Jan 2021 08:10:38 +0100
Subject: [PATCH 1889/2207] netmap: bridge: fix NS_MOREFRAG support

Support for NS_MOREFRAG is broken, as NS_MOREFRAG is copied from
the TX slot to the RX slot rather than the other way around.
Also, the NS_MOREFRAG must be copied also in case of packet
copy (no zerocopy).

Reported by:    rajesh1.kumar_amd.com
Differential Revision:  https://reviews.freebsd.org/D27980
---
 apps/bridge/bridge.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index a9adffad2..77d235bf6 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -86,13 +86,12 @@ rings_move(struct netmap_ring *rxring, struct netmap_ring *txring,
 		struct netmap_slot *rs = &rxring->slot[j];
 		struct netmap_slot *ts = &txring->slot[k];
 
-		/* swap packets */
 		if (ts->buf_idx < 2 || rs->buf_idx < 2) {
 			RD(2, "wrong index rxr[%d] = %d  -> txr[%d] = %d",
 			    j, rs->buf_idx, k, ts->buf_idx);
 			sleep(2);
 		}
-		/* copy the packet length. */
+		/* Copy the packet length. */
 		if (rs->len > rxring->nr_buf_size) {
 			RD(2,  "%s: invalid len %u, rxr[%d] -> txr[%d]",
 			    msg, rs->len, j, k);
@@ -109,13 +108,16 @@ rings_move(struct netmap_ring *rxring, struct netmap_ring *txring,
 			/* report the buffer change. */
 			ts->flags |= NS_BUF_CHANGED;
 			rs->flags |= NS_BUF_CHANGED;
-			/* copy the NS_MOREFRAG */
-			rs->flags = (rs->flags & ~NS_MOREFRAG) | (ts->flags & NS_MOREFRAG);
 		} else {
 			char *rxbuf = NETMAP_BUF(rxring, rs->buf_idx);
 			char *txbuf = NETMAP_BUF(txring, ts->buf_idx);
 			nm_pkt_copy(rxbuf, txbuf, ts->len);
 		}
+		/*
+		 * Copy the NS_MOREFRAG from rs to ts, leaving any
+		 * other flags unchanged.
+		 */
+		ts->flags = (ts->flags & ~NS_MOREFRAG) | (rs->flags & NS_MOREFRAG);
 		j = nm_ring_next(rxring, j);
 		k = nm_ring_next(txring, k);
 	}

From d9bb7c350959d3ac1aed9c480613df5bd6de8b1f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 7 Jan 2021 14:15:20 +0100
Subject: [PATCH 1890/2207] linux: fix possible double accounting of vm_pgoff

Only triggerable if mmap()ing with a non-zero offset.
---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a16aa0e4c..e4cff7aa1 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1251,7 +1251,7 @@ linux_netmap_fault(struct vm_fault *vmf)
 	struct netmap_priv_d *priv = vma->vm_private_data;
 	struct netmap_adapter *na = priv->np_na;
 	struct page *page;
-	unsigned long off = (vma->vm_pgoff + vmf->pgoff) << PAGE_SHIFT;
+	unsigned long off = vmf->pgoff << PAGE_SHIFT;
 	unsigned long pa, pfn;
 
 	pa = netmap_mem_ofstophys(na->nm_mem, off);

From 7e280469e619e994077140fde31879fc0f85db59 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Jan 2021 17:17:36 +0100
Subject: [PATCH 1891/2207] linux/e1000e: account for offsets when initializing
 rings

---
 LINUX/if_e1000e_netmap.h | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index e3955efe8..acecd6f33 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -411,22 +411,22 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 
 	slot = netmap_reset(na, NR_RX, 0, 0);
 	if (slot) {
+		kring = na->rx_rings[0];
 		/* initialize the RX ring for netmap mode */
 		adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc;
 		for (i = 0; i < rxr->count; i++) {
 			struct e1000_buffer *bi = &rxr->buffer_info[i];
-			si = netmap_idx_n2k(na->rx_rings[0], i);
-			PNMB(na, slot + si, &paddr);
+			si = netmap_idx_n2k(kring, i);
+			PNMB_O(kring, slot + si, &paddr);
 			if (bi->skb)
 				nm_prerr("Warning: rx skb still set on slot #%d", i);
 			E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr);
 		}
 		rxr->next_to_use = 0;
 		/* preserve buffers already made available to clients */
-		i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[0]);
+		i = rxr->count - 1 - nm_kr_rxspace(kring);
 
 		/* program the RCTL */
-		kring = na->rx_rings[0];
 		rctl = er32(RCTL);
 		rctl = (rctl & ~E1000_NETMAP_RCTL_MASK) |
 			e1000e_netmap_get_rctl(kring->hwbuf_len);
@@ -440,8 +440,9 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 	if (slot) {
 		/* initialize the tx ring for netmap mode */
 		for (i = 0; i < na->num_tx_desc; i++) {
-			si = netmap_idx_n2k(na->tx_rings[0], i);
-			PNMB(na, slot + si, &paddr);
+			kring = na->tx_rings[0];
+			si = netmap_idx_n2k(kring, i);
+			PNMB_O(kring, slot + si, &paddr);
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
 		}
 	}

From 47828bc96e81ca18ce3749278f4d333eb523305e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 11 Jan 2021 17:30:57 +0100
Subject: [PATCH 1892/2207] import netmap_reset() refactoring from FreeBSD

---
 sys/dev/netmap/netmap.c | 90 ++++++++++++++++++++---------------------
 1 file changed, 43 insertions(+), 47 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4b2f04e32..09032f14c 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4286,75 +4286,71 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 
 
 /*
- * netmap_reset() is called by the driver routines when reinitializing
- * a ring. The driver is in charge of locking to protect the kring.
- * If native netmap mode is not set just return NULL.
- * If native netmap mode is set, in particular, we have to set nr_mode to
- * NKR_NETMAP_ON.
+ * Reset function to be called by the driver routines when reinitializing
+ * a hardware ring. The driver is in charge of locking to protect the kring
+ * while this operation is being performed. This is normally achieved by
+ * calling netmap_disable_all_rings() before triggering a reset.
+ * If the kring is not in netmap mode, return NULL to inform the caller
+ * that this is the case.
+ * If the kring is in netmap mode, set hwofs so that the netmap indices
+ * seen by userspace (head/cut/tail) do not change, although the internal
+ * NIC indices have been reset to 0.
+ * In any case, adjust kring->nr_mode.
  */
 struct netmap_slot *
 netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
 	u_int new_cur)
 {
 	struct netmap_kring *kring;
-	int new_hwofs, lim;
+	u_int new_hwtail, new_hwofs;
 
 	if (!nm_native_on(na)) {
 		nm_prdis("interface not in native netmap mode");
 		return NULL;	/* nothing to reinitialize */
 	}
 
-	/* XXX note- in the new scheme, we are not guaranteed to be
-	 * under lock (e.g. when called on a device reset).
-	 * In this case, we should set a flag and do not trust too
-	 * much the values. In practice: TODO
-	 * - set a RESET flag somewhere in the kring
-	 * - do the processing in a conservative way
-	 * - let the *sync() fixup at the end.
-	 */
 	if (tx == NR_TX) {
 		if (n >= na->num_tx_rings)
 			return NULL;
-
 		kring = na->tx_rings[n];
-
-		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
-			kring->nr_mode = NKR_NETMAP_OFF;
-			return NULL;
-		}
-
-		// XXX check whether we should use hwcur or rcur
-		new_hwofs = kring->nr_hwcur - new_cur;
+		/*
+		 * Set hwofs to rhead, so that slots[rhead] is mapped to
+		 * the NIC internal slot 0, and thus the netmap buffer
+		 * at rhead is the next to be transmitted. Transmissions
+		 * that were pending before the reset are considered as
+		 * sent, so that we can have hwcur = rhead. All the slots
+		 * are now owned by the user, so we can also reinit hwtail.
+		 */
+		new_hwofs = kring->rhead;
+		new_hwtail = nm_prev(kring->rhead, kring->nkr_num_slots - 1);
 	} else {
 		if (n >= na->num_rx_rings)
 			return NULL;
 		kring = na->rx_rings[n];
-
-		if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
-			kring->nr_mode = NKR_NETMAP_OFF;
-			return NULL;
-		}
-
-		new_hwofs = kring->nr_hwtail - new_cur;
+		/*
+		 * Set hwofs to hwtail, so that slots[hwtail] is mapped to
+		 * the NIC internal slot 0, and thus the netmap buffer
+		 * at hwtail is the next to be given to the NIC.
+		 * Unread slots (the ones in [rhead,hwtail[) are owned by
+		 * the user, and thus the caller cannot give them
+		 * to the NIC right now.
+		 */
+		new_hwofs = kring->nr_hwtail;
+		new_hwtail = kring->nr_hwtail;
 	}
-	lim = kring->nkr_num_slots - 1;
-	if (new_hwofs > lim)
-		new_hwofs -= lim + 1;
-
-	/* Always set the new offset value and realign the ring. */
-	if (netmap_debug & NM_DEBUG_ON)
-	    nm_prinf("%s %s%d hwofs %d -> %d, hwtail %d -> %d",
-		na->name,
-		tx == NR_TX ? "TX" : "RX", n,
-		kring->nkr_hwofs, new_hwofs,
-		kring->nr_hwtail,
-		tx == NR_TX ? lim : kring->nr_hwtail);
-	kring->nkr_hwofs = new_hwofs;
-	if (tx == NR_TX) {
-		kring->nr_hwtail = kring->nr_hwcur + lim;
-		if (kring->nr_hwtail > lim)
-			kring->nr_hwtail -= lim + 1;
+	if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
+		kring->nr_mode = NKR_NETMAP_OFF;
+		return NULL;
 	}
+	if (netmap_verbose) {
+	    nm_prinf("%s, hc %u->%u, ht %u->%u, ho %u->%u", kring->name,
+	        kring->nr_hwcur, kring->rhead,
+	        kring->nr_hwtail, new_hwtail,
+		kring->nkr_hwofs, new_hwofs);
+	}
+	kring->nr_hwcur = kring->rhead;
+	kring->nr_hwtail = new_hwtail;
+	kring->nkr_hwofs = new_hwofs;
 
 	/*
 	 * Wakeup on the individual and global selwait

From c732d1a987a0af0ea90a48e0941a9dd5185f8c0e Mon Sep 17 00:00:00 2001
From: Konstantin Kogdenko 
Date: Mon, 11 Jan 2021 21:18:20 +0300
Subject: [PATCH 1893/2207] mem: create allocator for each iommu group (on
 demand)

Assign allocator iommu group id (nm_grp) at initialization stage
and do not change it later.
Check group only for hw (hardware) adapters. Virtual adapters can use any
particular allocator. For example, we can choose vale allocator through vale-ctl -m
nm_iommu_group_id() return -1 on error instead of 0, because 0 is valid iommu group.
---
 LINUX/netmap_linux.c         |  4 +-
 WINDOWS/win_glue.h           |  2 +-
 sys/dev/netmap/netmap.c      |  4 +-
 sys/dev/netmap/netmap_kern.h |  2 +-
 sys/dev/netmap/netmap_mem2.c | 93 +++++++++++++++++++++++++++++-------
 sys/dev/netmap/netmap_mem2.h |  1 +
 6 files changed, 84 insertions(+), 22 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 057f27b3b..4ee4e1587 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -326,11 +326,11 @@ int nm_iommu_group_id(struct device *dev)
 	int id;
 
 	if (!dev)
-		return 0;
+		return -1;
 
 	grp = iommu_group_get(dev);
 	if (!grp)
-		return 0;
+		return -1;
 
 	id = iommu_group_id(grp);
 
diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index 39523d194..987c2112b 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -135,7 +135,7 @@ typedef ULONG 			vm_ooffset_t;
  */
 #define destroy_dev(a)
 #define __user
-#define nm_iommu_group_id(dev)	0
+#define nm_iommu_group_id(dev)	-1
 
 
 /*
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4b2f04e32..29c8b4b44 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3941,8 +3941,8 @@ netmap_attach_common(struct netmap_adapter *na)
 	na->active_fds = 0;
 
 	if (na->nm_mem == NULL) {
-		/* use the global allocator */
-		na->nm_mem = netmap_mem_get(&nm_mem);
+		/* use iommu or global allocator */
+		na->nm_mem = netmap_mem_get_iommu(na);
 	}
 #ifdef WITH_VALE
 	if (na->nm_bdg_attach == NULL)
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7291df2be..16d207b3b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1736,7 +1736,7 @@ extern int netmap_generic_txqdisc;
 
 /* Assigns the device IOMMU domain to an allocator.
  * Returns -ENOMEM in case the domain is different */
-#define nm_iommu_group_id(dev) (0)
+#define nm_iommu_group_id(dev) (-1)
 
 /* Callback invoked by the dma machinery after a successful dmamap_load */
 static void netmap_dmamap_cb(__unused void *arg,
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8e77299d5..3aaa166ac 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -312,7 +312,7 @@ netmap_mem_rings_delete(struct netmap_adapter *na)
 
 static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *);
 static int netmap_mem_unmap(struct netmap_obj_pool *, struct netmap_adapter *);
-static int nm_mem_assign_group(struct netmap_mem_d *, struct device *);
+static int nm_mem_check_group(struct netmap_mem_d *, struct device *);
 static void nm_mem_release_id(struct netmap_mem_d *);
 
 nm_memid_t
@@ -323,7 +323,7 @@ netmap_mem_get_id(struct netmap_mem_d *nmd)
 
 #ifdef NM_DEBUG_MEM_PUTGET
 #define NM_DBG_REFC(nmd, func, line)	\
-	nm_prinf("%d mem[%d] -> %d", line, (nmd)->nm_id, (nmd)->refcount);
+	nm_prinf("%d mem[%d:%d] -> %d", line, (nmd)->nm_id, (nmd)->nm_grp, (nmd)->refcount);
 #else
 #define NM_DBG_REFC(nmd, func, line)
 #endif
@@ -360,7 +360,7 @@ int
 netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 {
 	int lasterr = 0;
-	if (nm_mem_assign_group(nmd, na->pdev) < 0) {
+	if (nm_mem_check_group(nmd, na->pdev) < 0) {
 		return ENOMEM;
 	}
 
@@ -492,7 +492,6 @@ netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 
 	nmd->active--;
 	if (last_user) {
-		nmd->nm_grp = -1;
 		nmd->lasterr = 0;
 	}
 
@@ -588,6 +587,7 @@ struct netmap_mem_d nm_mem = {	/* Our memory allocator. */
 	.name = "1"
 };
 
+static struct netmap_mem_d nm_mem_blueprint;
 
 /* blueprint for the private memory allocators */
 /* XXX clang is not happy about using name as a print format */
@@ -653,7 +653,7 @@ DECLARE_SYSCTLS(NETMAP_BUF_POOL, buf);
 
 /* call with nm_mem_list_lock held */
 static int
-nm_mem_assign_id_locked(struct netmap_mem_d *nmd)
+nm_mem_assign_id_locked(struct netmap_mem_d *nmd, int grp_id)
 {
 	nm_memid_t id;
 	struct netmap_mem_d *scan = netmap_last_mem_d;
@@ -667,6 +667,7 @@ nm_mem_assign_id_locked(struct netmap_mem_d *nmd)
 		scan = scan->next;
 		if (id != scan->nm_id) {
 			nmd->nm_id = id;
+			nmd->nm_grp = grp_id;
 			nmd->prev = scan->prev;
 			nmd->next = scan;
 			scan->prev->next = nmd;
@@ -684,12 +685,12 @@ nm_mem_assign_id_locked(struct netmap_mem_d *nmd)
 
 /* call with nm_mem_list_lock *not* held */
 static int
-nm_mem_assign_id(struct netmap_mem_d *nmd)
+nm_mem_assign_id(struct netmap_mem_d *nmd, int grp_id)
 {
 	int ret;
 
 	NM_MTX_LOCK(nm_mem_list_lock);
-	ret = nm_mem_assign_id_locked(nmd);
+	ret = nm_mem_assign_id_locked(nmd, grp_id);
 	NM_MTX_UNLOCK(nm_mem_list_lock);
 
 	return ret;
@@ -729,21 +730,24 @@ netmap_mem_find(nm_memid_t id)
 }
 
 static int
-nm_mem_assign_group(struct netmap_mem_d *nmd, struct device *dev)
+nm_mem_check_group(struct netmap_mem_d *nmd, struct device *dev)
 {
 	int err = 0, id;
+
+	/* Skip not hw adapters.
+	 * Vale port can use particular allocator through vale-ctl -m option
+	 */
+	if (!dev)
+		return 0;
 	id = nm_iommu_group_id(dev);
 	if (netmap_debug & NM_DEBUG_MEM)
 		nm_prinf("iommu_group %d", id);
 
 	NMA_LOCK(nmd);
 
-	if (nmd->nm_grp < 0)
-		nmd->nm_grp = id;
-
 	if (nmd->nm_grp != id) {
 		if (netmap_verbose)
-			nm_prerr("iommu group mismatch: %u vs %u",
+			nm_prerr("iommu group mismatch: %d vs %d",
 					nmd->nm_grp, id);
 		nmd->lasterr = err = ENOMEM;
 	}
@@ -1666,7 +1670,7 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd)
  * allocator for private memory
  */
 static void *
-_netmap_mem_private_new(size_t size, struct netmap_obj_params *p,
+_netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id,
 		struct netmap_mem_ops *ops, int *perr)
 {
 	struct netmap_mem_d *d = NULL;
@@ -1681,7 +1685,7 @@ _netmap_mem_private_new(size_t size, struct netmap_obj_params *p,
 	*d = nm_blueprint;
 	d->ops = ops;
 
-	err = nm_mem_assign_id(d);
+	err = nm_mem_assign_id(d, grp_id);
 	if (err)
 		goto error_free;
 	snprintf(d->name, NM_MEM_NAMESZ, "%d", d->nm_id);
@@ -1768,11 +1772,65 @@ netmap_mem_private_new(u_int txr, u_int txd, u_int rxr, u_int rxd,
 			p[NETMAP_BUF_POOL].num,
 			p[NETMAP_BUF_POOL].size);
 
-	d = _netmap_mem_private_new(sizeof(*d), p, &netmap_mem_global_ops, perr);
+	d = _netmap_mem_private_new(sizeof(*d), p, -1, &netmap_mem_global_ops, perr);
 
 	return d;
 }
 
+/* Reference iommu allocator - find existing or create new,
+ * for not hw addapeters fallback to global allocator.
+ */
+struct netmap_mem_d *
+netmap_mem_get_iommu(struct netmap_adapter *na)
+{
+	int i, err, grp_id;
+	struct netmap_mem_d *nmd;
+
+	if (na == NULL || na->pdev == NULL)
+		return netmap_mem_get(&nm_mem);
+
+	grp_id = nm_iommu_group_id(na->pdev);
+
+	NM_MTX_LOCK(nm_mem_list_lock);
+	nmd = netmap_last_mem_d;
+	do {
+		if (!(nmd->flags & NETMAP_MEM_HIDDEN) && nmd->nm_grp == grp_id) {
+			nmd->refcount++;
+			NM_DBG_REFC(nmd, __FUNCTION__, __LINE__);
+			NM_MTX_UNLOCK(nm_mem_list_lock);
+			return nmd;
+		}
+		nmd = nmd->next;
+	} while (nmd != netmap_last_mem_d);
+
+	nmd = nm_os_malloc(sizeof(*nmd));
+	if (nmd == NULL)
+		goto error;
+
+	*nmd = nm_mem_blueprint;
+
+	err = nm_mem_assign_id_locked(nmd, grp_id);
+	if (err)
+		goto error_free;
+
+	snprintf(nmd->name, sizeof(nmd->name), "%d", nmd->nm_id);
+
+	for (i = 0; i < NETMAP_POOLS_NR; i++) {
+		snprintf(nmd->pools[i].name, NETMAP_POOL_MAX_NAMSZ, "%s-%s",
+			nm_mem_blueprint.pools[i].name, nmd->name);
+	}
+
+	NMA_LOCK_INIT(nmd);
+
+	NM_MTX_UNLOCK(nm_mem_list_lock);
+	return nmd;
+
+error_free:
+	nm_os_free(nmd);
+error:
+	NM_MTX_UNLOCK(nm_mem_list_lock);
+	return NULL;
+}
 
 /* call with lock held */
 static int
@@ -1843,6 +1901,7 @@ NM_MTX_T nm_mem_ext_list_lock;
 int
 netmap_mem_init(void)
 {
+	nm_mem_blueprint = nm_mem;
 	NM_MTX_INIT(nm_mem_list_lock);
 	NMA_LOCK_INIT(&nm_mem);
 	netmap_mem_get(&nm_mem);
@@ -2274,10 +2333,12 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		nm_prinf("not found, creating new");
 
 	nme = _netmap_mem_private_new(sizeof(*nme),
+
 			(struct netmap_obj_params[]){
 				{ pi->nr_if_pool_objsize, pi->nr_if_pool_objtotal },
 				{ pi->nr_ring_pool_objsize, pi->nr_ring_pool_objtotal },
 				{ pi->nr_buf_pool_objsize, pi->nr_buf_pool_objtotal }},
+			-1,
 			&netmap_mem_ext_ops,
 			&error);
 	if (nme == NULL)
@@ -2791,7 +2852,7 @@ netmap_mem_pt_guest_create(nm_memid_t mem_id)
 	ptnmd->pt_ifs = NULL;
 
 	/* Assign new id in the guest (We have the lock) */
-	err = nm_mem_assign_id_locked(&ptnmd->up);
+	err = nm_mem_assign_id_locked(&ptnmd->up, -1);
 	if (err)
 		goto error;
 
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 8c4bf256f..16a3dadd1 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -147,6 +147,7 @@ struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_
 #define netmap_mem_get(d) __netmap_mem_get(d, __FUNCTION__, __LINE__)
 #define netmap_mem_put(d) __netmap_mem_put(d, __FUNCTION__, __LINE__)
 struct netmap_mem_d* __netmap_mem_get(struct netmap_mem_d *, const char *, int);
+struct netmap_mem_d* netmap_mem_get_iommu(struct netmap_adapter *);
 void __netmap_mem_put(struct netmap_mem_d *, const char *, int);
 struct netmap_mem_d* netmap_mem_find(nm_memid_t);
 unsigned netmap_mem_bufsize(struct netmap_mem_d *nmd);

From 70c60a2eb29edfef85bfffae875cf9ac94e04415 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 12 Jan 2021 22:56:00 +0100
Subject: [PATCH 1894/2207] pkt-gen: remove redundant 0x in debug printf

---
 apps/pkt-gen/pkt-gen.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index f961fd825..808f0525b 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -3188,12 +3188,12 @@ main(int arc, char **argv)
 		    req->nr_mem_id);
 		for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
-			D("   TX%d at 0x%p slots %d", i,
+			D("   TX%d at %p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
 		}
 		for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
-			D("   RX%d at 0x%p slots %d", i,
+			D("   RX%d at %p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
 		}
 	}

From 467f4777b7afafcf9252e1112cb9a96af27618cf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 16:44:13 +0100
Subject: [PATCH 1895/2207] add kring field to keep track of slots invalidated
 during NIC reset

Netmap tries to shield applications from NIC resets: during a NIC reset
the hw rings are wiped out and rebuilt from scratch by the NIC driver,
but any active netmap ring is preserved and the new hw rings are
re-initialized using the slots and indices read from the corresponding
netmap ring, if any.

The current implementation, however, unsafely accesses also the part of
the netmap ring in the [head, tail) interval, which belongs to the user.
Proper operation, instead, should only restore the part of the hw ring
that corresponds to the kernel-owned subset of the netmap ring, leaving
the rest for later (i.e., to the *sync callbacks). In preparation for
this, this patch adds a new field to each kring to keep track of the
number of hw rings slots that have yet to be restored from their netmap
ring counterpart.
---
 sys/dev/netmap/netmap_kern.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 16d207b3b..10531cf70 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -459,8 +459,16 @@ struct netmap_kring {
 	 * On a NIC reset, the NIC ring indexes may be reset but the
 	 * indexes in the netmap rings remain the same. nkr_hwofs
 	 * keeps track of the offset between the two.
+	 *
+	 * Moreover, during reset, we can restore only the subset of
+	 * the NIC ring that corresponds to the kernel-owned part of
+	 * the netmap ring. The rest of the slots must be restored
+	 * by the *sync routines when the user releases more slots.
+	 * The nkr_to_refill field keeps track of the number of slots
+	 * that still need to be restored.
 	 */
 	int32_t		nkr_hwofs;
+	int32_t		nkr_to_refill;
 
 	/* last_reclaim is opaque marker to help reduce the frequency
 	 * of operations such as reclaiming tx buffers. A possible use

From 2a357a192df37efb3fcadbbf3453d0f5f1456159 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 17:04:36 +0100
Subject: [PATCH 1896/2207] lock the rings instead of stopping them during NIC
 reset

Before this patch we stopped the netmap rings when a NIC was going down.
A stopped ring notifies an error to the netmap application the next time
that it will issue a *sync operation. The application is expected to
close the port as a result. This was intended as a proper response to an
'ifconfig down' command, which may leave the NIC down for an unbounded
amount of time.

However, the NIC may also go down and then immediatly up in several
occasions, in particular when the rings of a multi-ring NIC are open in
netmap mode one at time: each new open will cause a down/up cycle which
may cause whomever is using the other already-opened rings to see an
error. In these cases we would rather have the already-opened rings to
never cause an error.

This patch removes the stopped state and just locks the rings when the
NIC goes down. This gives us better behaviour in the down/up scenario,
sacrificing the 'ifconfig down' one, at least for now.
---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 280939b4c..6130b6b88 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -636,7 +636,7 @@ void
 netmap_disable_all_rings(struct ifnet *ifp)
 {
 	if (NM_NA_VALID(ifp)) {
-		netmap_set_all_rings(NA(ifp), NM_KR_STOPPED);
+		netmap_set_all_rings(NA(ifp), NM_KR_LOCKED);
 	}
 }
 

From 7dc5b9e6a889ca5689be3bbc74851e824d93166b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 17:20:35 +0100
Subject: [PATCH 1897/2207] linux/e1000: safe restore of NIC rings during reset

---
 LINUX/if_e1000_netmap.h | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 20025dba5..c32576e23 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -268,10 +268,11 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
 				goto ring_reset;
-			if (slot->flags & NS_BUF_CHANGED) {
+			if (slot->flags & NS_BUF_CHANGED || kring->nkr_to_refill) {
 				uint64_t offset = nm_get_offset(kring, slot);
 				curr->buffer_addr = htole64(paddr + offset);
 				slot->flags &= ~NS_BUF_CHANGED;
+				kring->nkr_to_refill--;
 			}
 			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
 					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
@@ -279,6 +280,8 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
 		}
+		if (kring->nkr_to_refill < 0)
+			kring->nkr_to_refill = 0;
 		kring->nr_hwcur = head;
 		rxr->next_to_use = nic_i; // XXX not really used
 		wmb();
@@ -369,7 +372,7 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 	struct netmap_kring *kring;
 	struct netmap_slot* slot;
 	struct e1000_tx_ring* txr = &adapter->tx_ring[0];
-	unsigned int i, r, si;
+	unsigned int i, r, si, n;
 	uint64_t paddr;
 	uint32_t rctl;
 
@@ -386,17 +389,17 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		}
 		rxr = &adapter->rx_ring[r];
 
-		for (i = 0; i < rxr->count; i++) {
+		/* preserve buffers already made available to clients */
+		kring->nkr_to_refill = nm_kr_rxspace(kring);
+		n = rxr->count - kring->nkr_to_refill;
+
+		for (i = 0; i < n; i++) {
 			si = netmap_idx_n2k(kring, i);
 			PNMB_O(kring, slot + si, &paddr);
 			E1000_RX_DESC(*rxr, i)->buffer_addr = htole64(paddr);
 		}
 
 		rxr->next_to_use = 0;
-		/* preserve buffers already made available to clients */
-		i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[0]);
-		if (i < 0) // XXX something wrong here, can it really happen ?
-			i += rxr->count;
 
 		/* program the RCTL */
 		rctl = er32(RCTL);
@@ -416,7 +419,13 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 			continue;
 		}
 
-		for (i = 0; i < na->num_tx_desc; i++) {
+		/* preserve buffers already made available to clients */
+		n = txr->count - nm_kr_txspace(kring);
+		/* there is no need to update nkr_to_refill, since the txsync
+		 * always refills the hw slots anyway
+		 */
+
+		for (i = 0; i < n; i++) {
 			kring = na->tx_rings[r];
 			si = netmap_idx_n2k(kring, i);
 			PNMB_O(kring, slot + si, &paddr);

From 504a91883dab4efa21900cbe2201f6e6555706ae Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 17:47:31 +0100
Subject: [PATCH 1898/2207] linux/ixgbe: safe restore of NIC rings during reset

---
 LINUX/ixgbe_netmap_linux.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 935e2ed17..f100e8dc6 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -720,7 +720,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	 */
 	struct netmap_adapter *na = NA(adapter->netdev);
 	struct netmap_slot *slot;
-	int lim, i;
+	int lim, i, n;
 	struct NM_IXGBE_RING *ring = NM_IXGBE_RX_RING(adapter, ring_nr);
 	struct netmap_kring *kring;
 
@@ -733,9 +733,10 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 
 	ixgbe_netmap_configure_srrctl(adapter, ring);
 
-	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
+	n = nm_kr_rxspace(na->rx_rings[ring_nr]);
+	lim = na->num_rx_desc - 1 - n;
 
-	for (i = 0; i < na->num_rx_desc; i++) {
+	for (i = 0; i < n; i++) {
 		/*
 		 * Fill the map and set the buffer address in the NIC ring,
 		 * considering the offset between the netmap and NIC rings

From e10b1ef0f0750a3e913e21dab0a9e5f6c040348c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 17:50:28 +0100
Subject: [PATCH 1899/2207] linux/i40e: safe restore of NIC rings during reset

---
 LINUX/i40e_netmap_linux.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index abcef9116..c617c00b0 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -159,7 +159,7 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 	struct netmap_adapter *na;
 	struct netmap_slot *slot;
 	struct netmap_kring *kring;
-	int lim, i, ring_nr;
+	int lim, i, ring_nr, n;
 
 	if (!ring->netdev) {
 		// XXX it this possible?
@@ -174,9 +174,10 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 		return 0;	// not in native netmap mode
 
 	kring = na->rx_rings[ring_nr];
-	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
+	n = nm_kr_rxspace(kring);
+	lim = na->num_rx_desc - 1 - n;
 
-	for (i = 0; i < na->num_rx_desc; i++) {
+	for (i = 0; i < n; i++) {
 		int si = netmap_idx_n2k(kring, i);
 		uint64_t paddr;
 		union i40e_rx_desc *rx = I40E_RX_DESC(ring, i);

From a50c526eae8e3ba99fe17400dd7cf251e329806e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 19:04:13 +0100
Subject: [PATCH 1900/2207] linux/igb: fix a warning

---
 ...0400--99999 => vanilla--igb--40400--50a00} |  0
 .../final-patches/vanilla--igb--50a00--99999  | 87 +++++++++++++++++++
 LINUX/if_igb_netmap.h                         |  7 +-
 3 files changed, 91 insertions(+), 3 deletions(-)
 rename LINUX/final-patches/{vanilla--igb--40400--99999 => vanilla--igb--40400--50a00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--igb--50a00--99999

diff --git a/LINUX/final-patches/vanilla--igb--40400--99999 b/LINUX/final-patches/vanilla--igb--40400--50a00
similarity index 100%
rename from LINUX/final-patches/vanilla--igb--40400--99999
rename to LINUX/final-patches/vanilla--igb--40400--50a00
diff --git a/LINUX/final-patches/vanilla--igb--50a00--99999 b/LINUX/final-patches/vanilla--igb--50a00--99999
new file mode 100644
index 000000000..8e6c06e80
--- /dev/null
+++ b/LINUX/final-patches/vanilla--igb--50a00--99999
@@ -0,0 +1,87 @@
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 0d343d050973..ddee5da89ba3 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static int debug = -1;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct igb_reg_info {
+ 	u32 ofs;
+ 	char *name;
+@@ -3489,6 +3493,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef CONFIG_IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == 0) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3798,6 +3806,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
+ 	}
+ #endif
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 
+ 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+ 	 * would have already happened in close and is redundant.
+@@ -4302,6 +4314,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	wr32(E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -8043,6 +8058,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector, int napi_budget)
+ 
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+@@ -8682,6 +8701,16 @@ static int igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+@@ -8861,6 +8890,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	u16 i = rx_ring->next_to_use;
+ 	u16 bufsz;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 2d87acd58..a0adfdb4b 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -475,7 +475,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	int reg_idx = rxr->reg_idx;
 	struct netmap_slot* slot;
 	struct netmap_kring *kring;
-	u_int i;
+	u_int i, n;
 
 	/*
 	 * XXX watch out, the main driver must not use
@@ -494,7 +494,8 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	igb_netmap_configure_srrctl(rxr);
 
 	kring = na->rx_rings[reg_idx];
-	for (i = 0; i < rxr->count; i++) {
+	n = nm_kr_rxspace(na->rx_rings[reg_idx])
+	for (i = 0; i < n; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;
 		int si = netmap_idx_n2k(kring, i);
@@ -505,7 +506,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 		rx_desc->read.pkt_addr = htole64(paddr);
 	}
 	/* preserve buffers already made available to clients */
-	i = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[reg_idx]);
+	i = rxr->count - 1 - n;
 
 	wmb();	/* Force memory writes to complete */
 	nm_prdis("%s rxr%d.tail %d", na->name, reg_idx, i);

From 0dd7b78c8a8e94fbcd48bdb3b9c3862fd3d1f861 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 19:05:24 +0100
Subject: [PATCH 1901/2207] linux/igb: safe restore of NIC rings during reset

---
 LINUX/if_igb_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index a0adfdb4b..e844c4b1f 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -494,7 +494,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	igb_netmap_configure_srrctl(rxr);
 
 	kring = na->rx_rings[reg_idx];
-	n = nm_kr_rxspace(na->rx_rings[reg_idx])
+	n = nm_kr_rxspace(na->rx_rings[reg_idx]);
 	for (i = 0; i < n; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;

From 4a2936df8f9d097776fbeea651a11c8bb3f5480f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Jan 2021 19:08:59 +0100
Subject: [PATCH 1902/2207] linux/e1000e: safe restore of NIC rings during
 reset

---
 LINUX/if_e1000e_netmap.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index acecd6f33..1aa6fb3f3 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -402,7 +402,7 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 	struct netmap_slot* slot;
 	struct e1000_ring *rxr = adapter->rx_ring;
 	struct e1000_ring *txr = adapter->tx_ring;
-	int i, si;
+	int i, si, n;
 	uint64_t paddr;
 	uint32_t rctl;
 
@@ -414,7 +414,8 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		kring = na->rx_rings[0];
 		/* initialize the RX ring for netmap mode */
 		adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc;
-		for (i = 0; i < rxr->count; i++) {
+		n = nm_kr_rxspace(kring);
+		for (i = 0; i < n; i++) {
 			struct e1000_buffer *bi = &rxr->buffer_info[i];
 			si = netmap_idx_n2k(kring, i);
 			PNMB_O(kring, slot + si, &paddr);
@@ -424,7 +425,7 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		}
 		rxr->next_to_use = 0;
 		/* preserve buffers already made available to clients */
-		i = rxr->count - 1 - nm_kr_rxspace(kring);
+		i = rxr->count - 1 - n;
 
 		/* program the RCTL */
 		rctl = er32(RCTL);
@@ -439,8 +440,9 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 	slot = netmap_reset(na, NR_TX, 0, 0);
 	if (slot) {
 		/* initialize the tx ring for netmap mode */
-		for (i = 0; i < na->num_tx_desc; i++) {
-			kring = na->tx_rings[0];
+		kring = na->tx_rings[0];
+		n = nm_kr_rxspace(kring);
+		for (i = 0; i < n; i++) {
 			si = netmap_idx_n2k(kring, i);
 			PNMB_O(kring, slot + si, &paddr);
 			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);

From 7f5d5bcd46d98cb57a8698095c4f8a47723003e4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jan 2021 15:03:49 +0100
Subject: [PATCH 1903/2207] linux/virtio: skip pre-patch build test during
 configure

---
 LINUX/configure | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 66ead4cc3..2cb56527b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -145,6 +145,15 @@ idrv()
 	setop internal_driver "$@"
 }
 
+# external drivers that don't need the pre-patch test
+setop custom_driver new driver
+cdrv()
+{
+	setop custom_driver "$@"
+}
+
+cdrv enable virtio_net.c
+
 update_drivers() {
 	edrv intersect driver
 	idrv copy driver
@@ -507,8 +516,12 @@ else
 EXTRA_CFLAGS := -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
+C_DRIVERS := $(cdrv print)
 I_DRIVERS := $(idrv print)
-all: \$(S_DRIVERS:%=get-%) \$(E_DRIVERS:%=build-%) \$(I_DRIVERS:%=patch-%) tests
+
+TOBUILD := \$(filter-out \$(C_DRIVERS),\$(E_DRIVERS))
+
+all: \$(S_DRIVERS:%=get-%) \$(TOBUILD:%=build-%) \$(I_DRIVERS:%=patch-%) tests
 
 tests:
 	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(EXTRA_CFLAGS)" $kopts
@@ -1057,7 +1070,9 @@ EOF
   }	
 
   for d in $(edrv print); do
-	add_file_exists_check build-$d true "edrv_build_error $d"
+	if !(cdrv enabled $d); then
+            add_file_exists_check build-$d true "edrv_build_error $d"
+	fi
   done
 
   # check that we can patch the internal drivers

From 5f5759a1bd2ec26bfa50031a692849f3a25c456b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jan 2021 15:10:35 +0100
Subject: [PATCH 1904/2207] linux/configure: don't fail on format-truncation
 warnings

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 2cb56527b..b74536ece 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -995,7 +995,7 @@ EOF
 
   add_test true broken_buildsystem < /dev/null
 
-DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation missing-attributes"
+DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned stringop-truncation missing-attributes format-truncation"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"

From 1142cef049ef80584bc7ac24cc34383982ef44ab Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jan 2021 15:16:53 +0100
Subject: [PATCH 1905/2207] linux/build: remove useless dependency

---
 LINUX/netmap.mak.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index eadce9760..9cf2cc1ac 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -63,7 +63,7 @@ distclean-$(1):
 endef
 
 define external_driver
-build-$(1): get-$(1) netmap.ko
+build-$(1): get-$(1)
 	if [ -d $(1) ] && [ -e Module.symvers ]; then cp Module.symvers $(1); fi
 	+$($(1)@build)
 clean-$(1):

From 785ad435407ad00c05ac65dd5dcf840b54255165 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jan 2021 16:21:32 +0100
Subject: [PATCH 1906/2207] linux/virtio_net.c: fix compilation on linux >= 5.3

---
 LINUX/configure                               |  9 +++
 LINUX/final-patches/custom--virtio_net.c--4.9 | 70 +++++++++++--------
 2 files changed, 50 insertions(+), 29 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index b74536ece..71661d071 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1806,6 +1806,15 @@ EOF
 	}
 EOF
 
+  # nf_reset() or nf_reset_ct()?
+  add_test 'have NF_RESET_CT' <
+
+	void dummy(struct sk_buff *skb) {
+		nf_reset_ct(skb);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index d625baa0e..c3195dd2f 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..f9a8c2d 100644
+index cbf1c61..f9fa716 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,12 @@
@@ -368,7 +368,19 @@ index cbf1c61..f9a8c2d 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -951,8 +996,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+@@ -890,7 +935,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 
+ 	/* Don't wait up for transmitted skbs to be freed. */
+ 	skb_orphan(skb);
++#ifdef NETMAP_LINUX_HAVE_NF_RESET_CT
++	nf_reset_ct(skb);
++#else  /* !NETMAP_LINUX_HAVE_NF_RESET_CT */
+ 	nf_reset(skb);
++#endif /* !NETMAP_LINUX_HAVE_NF_RESET_CT */
+ 
+ 	/* If running out of space, stop queue to avoid getting packets that we
+ 	 * are then unable to transmit.
+@@ -951,8 +1000,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
  	BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
  	virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
  
@@ -378,7 +390,7 @@ index cbf1c61..f9a8c2d 100644
  
  	/* Spin for a response, the kick causes an ioport write, trapping
  	 * into the hypervisor, so the request should be handled immediately.
-@@ -1009,8 +1053,13 @@ out:
+@@ -1009,8 +1057,13 @@ out:
  	return ret;
  }
  
@@ -394,7 +406,7 @@ index cbf1c61..f9a8c2d 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1092,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1096,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -407,7 +419,7 @@ index cbf1c61..f9a8c2d 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1258,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1262,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -503,7 +515,7 @@ index cbf1c61..f9a8c2d 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1304,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1308,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -512,7 +524,7 @@ index cbf1c61..f9a8c2d 100644
  	}
  	put_online_cpus();
  
-@@ -1363,51 +1323,63 @@ static void virtnet_get_channels(struct net_device *dev,
+@@ -1363,51 +1327,63 @@ static void virtnet_get_channels(struct net_device *dev,
  	channels->other_count = 0;
  }
  
@@ -593,7 +605,7 @@ index cbf1c61..f9a8c2d 100644
  
  static void virtnet_init_settings(struct net_device *dev)
  {
-@@ -1424,8 +1396,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
+@@ -1424,8 +1400,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
  	.set_channels = virtnet_set_channels,
  	.get_channels = virtnet_get_channels,
  	.get_ts_info = ethtool_op_get_ts_info,
@@ -606,7 +618,7 @@ index cbf1c61..f9a8c2d 100644
  };
  
  #define MIN_MTU 68
-@@ -1446,16 +1420,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1424,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -626,7 +638,7 @@ index cbf1c61..f9a8c2d 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1502,7 +1475,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+@@ -1502,7 +1479,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -636,7 +648,7 @@ index cbf1c61..f9a8c2d 100644
  		netif_napi_del(&vi->rq[i].napi);
  	}
  
-@@ -1565,8 +1540,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1544,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -645,7 +657,7 @@ index cbf1c61..f9a8c2d 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1588,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1592,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -662,7 +674,7 @@ index cbf1c61..f9a8c2d 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1670,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1674,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -673,7 +685,7 @@ index cbf1c61..f9a8c2d 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1678,6 @@ err:
+@@ -1701,33 +1682,6 @@ err:
  	return ret;
  }
  
@@ -707,7 +719,7 @@ index cbf1c61..f9a8c2d 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1718,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1722,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -718,7 +730,7 @@ index cbf1c61..f9a8c2d 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1757,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1761,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -726,7 +738,7 @@ index cbf1c61..f9a8c2d 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1765,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1769,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -735,7 +747,7 @@ index cbf1c61..f9a8c2d 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1775,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1779,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -755,7 +767,7 @@ index cbf1c61..f9a8c2d 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,16 +1816,21 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,16 +1820,21 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -779,7 +791,7 @@ index cbf1c61..f9a8c2d 100644
  	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
  		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
  	else
-@@ -1885,6 +1843,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1847,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -787,7 +799,7 @@ index cbf1c61..f9a8c2d 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1851,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1855,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -795,7 +807,7 @@ index cbf1c61..f9a8c2d 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1865,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1869,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -806,7 +818,7 @@ index cbf1c61..f9a8c2d 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1876,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1880,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -824,7 +836,7 @@ index cbf1c61..f9a8c2d 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1897,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1901,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -835,7 +847,7 @@ index cbf1c61..f9a8c2d 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1926,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1930,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -851,7 +863,7 @@ index cbf1c61..f9a8c2d 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1947,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1951,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -860,7 +872,7 @@ index cbf1c61..f9a8c2d 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1989,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1993,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -871,7 +883,7 @@ index cbf1c61..f9a8c2d 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +1998,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +2002,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -939,7 +951,7 @@ index cbf1c61..f9a8c2d 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2064,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2068,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From 3a1e546632e0aed6b66a2a924a021d5ca4367753 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 23 Jan 2021 16:39:31 +0100
Subject: [PATCH 1907/2207] linux/virtio_net.c: fix warning

---
 LINUX/final-patches/custom--virtio_net.c--4.9 | 119 ++++++++++--------
 1 file changed, 66 insertions(+), 53 deletions(-)

diff --git a/LINUX/final-patches/custom--virtio_net.c--4.9 b/LINUX/final-patches/custom--virtio_net.c--4.9
index c3195dd2f..66a437a29 100644
--- a/LINUX/final-patches/custom--virtio_net.c--4.9
+++ b/LINUX/final-patches/custom--virtio_net.c--4.9
@@ -30,7 +30,7 @@ index 0000000..2c88957
 +
 +endif
 diff --git a/virtio_net.c/virtio_net.c b/virtio_net.c/virtio_net.c
-index cbf1c61..f9fa716 100644
+index cbf1c61..9b92747 100644
 --- a/virtio_net.c/virtio_net.c
 +++ b/virtio_net.c/virtio_net.c
 @@ -26,8 +26,12 @@
@@ -207,7 +207,20 @@ index cbf1c61..f9fa716 100644
  	return NULL;
  }
  
-@@ -579,7 +628,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -521,7 +570,11 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
+ 	hdr = skb_vnet_hdr(skb);
+ 	sg_init_table(rq->sg, 2);
+ 	sg_set_buf(rq->sg, hdr, vi->hdr_len);
+-	skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
++	err = skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
++	if (err < 0) {
++		dev_kfree_skb(skb);
++		return err;
++	}
+ 
+ 	err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp);
+ 	if (err < 0)
+@@ -579,7 +632,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
  	return err;
  }
  
@@ -216,7 +229,7 @@ index cbf1c61..f9fa716 100644
  {
  	const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
  	unsigned int len;
-@@ -591,6 +640,7 @@ static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
+@@ -591,6 +644,7 @@ static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
  
  static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
  {
@@ -224,7 +237,7 @@ index cbf1c61..f9fa716 100644
  	struct page_frag *alloc_frag = &rq->alloc_frag;
  	char *buf;
  	unsigned long ctx;
-@@ -622,6 +672,9 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
+@@ -622,6 +676,9 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
  		put_page(virt_to_head_page(buf));
  
  	return err;
@@ -234,7 +247,7 @@ index cbf1c61..f9fa716 100644
  }
  
  /*
-@@ -637,7 +690,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+@@ -637,7 +694,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
  	int err;
  	bool oom;
  
@@ -242,7 +255,7 @@ index cbf1c61..f9fa716 100644
  	do {
  		if (vi->mergeable_rx_bufs)
  			err = add_recvbuf_mergeable(rq, gfp);
-@@ -729,59 +781,38 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -729,16 +785,32 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  	struct receive_queue *rq =
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received;
@@ -275,13 +288,14 @@ index cbf1c61..f9fa716 100644
 +		if (unlikely(virtqueue_poll(vq, r)) &&
  		    napi_schedule_prep(napi)) {
 -			virtqueue_disable_cb(rq->vq);
--			__napi_schedule(napi);
--		}
--	}
--
--	return received;
--}
--
++			virtqueue_disable_cb(vq);
+ 			__napi_schedule(napi);
+ 		}
+ 	}
+@@ -746,53 +818,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	return received;
+ }
+ 
 -#ifdef CONFIG_NET_RX_BUSY_POLL
 -/* must be called with local_bh_disable()d */
 -static int virtnet_busy_poll(struct napi_struct *napi)
@@ -311,18 +325,17 @@ index cbf1c61..f9fa716 100644
 -			budget -= received;
 -			goto again;
 -		} else {
-+			virtqueue_disable_cb(vq);
- 			__napi_schedule(napi);
- 		}
- 	}
- 
- 	return received;
- }
+-			__napi_schedule(napi);
+-		}
+-	}
+-
+-	return received;
+-}
 -#endif	/* CONFIG_NET_RX_BUSY_POLL */
- 
+-
  static int virtnet_open(struct net_device *dev)
  {
-@@ -789,10 +820,13 @@ static int virtnet_open(struct net_device *dev)
+ 	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -340,7 +353,7 @@ index cbf1c61..f9fa716 100644
  		virtnet_napi_enable(&vi->rq[i]);
  	}
  
-@@ -840,7 +874,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
+@@ -840,7 +878,14 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
  		hdr = skb_vnet_hdr(skb);
  
  	if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
@@ -356,7 +369,7 @@ index cbf1c61..f9fa716 100644
  		BUG();
  
  	if (vi->mergeable_rx_bufs)
-@@ -866,7 +907,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -866,7 +911,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  	struct send_queue *sq = &vi->sq[qnum];
  	int err;
  	struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
@@ -368,7 +381,7 @@ index cbf1c61..f9fa716 100644
  
  	/* Free up any pending old buffers before queueing new ones. */
  	free_old_xmit_skbs(sq);
-@@ -890,7 +935,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -890,7 +939,11 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
  
  	/* Don't wait up for transmitted skbs to be freed. */
  	skb_orphan(skb);
@@ -380,7 +393,7 @@ index cbf1c61..f9fa716 100644
  
  	/* If running out of space, stop queue to avoid getting packets that we
  	 * are then unable to transmit.
-@@ -951,8 +1000,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
+@@ -951,8 +1004,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
  	BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
  	virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
  
@@ -390,7 +403,7 @@ index cbf1c61..f9fa716 100644
  
  	/* Spin for a response, the kick causes an ioport write, trapping
  	 * into the hypervisor, so the request should be handled immediately.
-@@ -1009,8 +1057,13 @@ out:
+@@ -1009,8 +1061,13 @@ out:
  	return ret;
  }
  
@@ -406,7 +419,7 @@ index cbf1c61..f9fa716 100644
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int cpu;
-@@ -1043,9 +1096,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
+@@ -1043,9 +1100,11 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
  	tot->rx_dropped = dev->stats.rx_dropped;
  	tot->rx_length_errors = dev->stats.rx_length_errors;
  	tot->rx_frame_errors = dev->stats.rx_frame_errors;
@@ -419,7 +432,7 @@ index cbf1c61..f9fa716 100644
  
  #ifdef CONFIG_NET_POLL_CONTROLLER
  static void virtnet_netpoll(struct net_device *dev)
-@@ -1207,95 +1262,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+@@ -1207,95 +1266,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
  	return 0;
  }
  
@@ -515,7 +528,7 @@ index cbf1c61..f9fa716 100644
  static void virtnet_get_ringparam(struct net_device *dev,
  				struct ethtool_ringparam *ring)
  {
-@@ -1342,8 +1308,6 @@ static int virtnet_set_channels(struct net_device *dev,
+@@ -1342,8 +1312,6 @@ static int virtnet_set_channels(struct net_device *dev,
  	if (!err) {
  		netif_set_real_num_tx_queues(dev, queue_pairs);
  		netif_set_real_num_rx_queues(dev, queue_pairs);
@@ -524,7 +537,7 @@ index cbf1c61..f9fa716 100644
  	}
  	put_online_cpus();
  
-@@ -1363,51 +1327,63 @@ static void virtnet_get_channels(struct net_device *dev,
+@@ -1363,51 +1331,63 @@ static void virtnet_get_channels(struct net_device *dev,
  	channels->other_count = 0;
  }
  
@@ -605,7 +618,7 @@ index cbf1c61..f9fa716 100644
  
  static void virtnet_init_settings(struct net_device *dev)
  {
-@@ -1424,8 +1400,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
+@@ -1424,8 +1404,10 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
  	.set_channels = virtnet_set_channels,
  	.get_channels = virtnet_get_channels,
  	.get_ts_info = ethtool_op_get_ts_info,
@@ -618,7 +631,7 @@ index cbf1c61..f9fa716 100644
  };
  
  #define MIN_MTU 68
-@@ -1446,16 +1424,15 @@ static const struct net_device_ops virtnet_netdev = {
+@@ -1446,16 +1428,15 @@ static const struct net_device_ops virtnet_netdev = {
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
@@ -638,7 +651,7 @@ index cbf1c61..f9fa716 100644
  };
  
  static void virtnet_config_changed_work(struct work_struct *work)
-@@ -1502,7 +1479,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+@@ -1502,7 +1483,9 @@ static void virtnet_free_queues(struct virtnet_info *vi)
  	int i;
  
  	for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -648,7 +661,7 @@ index cbf1c61..f9fa716 100644
  		netif_napi_del(&vi->rq[i].napi);
  	}
  
-@@ -1565,8 +1544,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
+@@ -1565,8 +1548,6 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
  {
  	struct virtio_device *vdev = vi->vdev;
  
@@ -657,7 +670,7 @@ index cbf1c61..f9fa716 100644
  	vdev->config->del_vqs(vdev);
  
  	virtnet_free_queues(vi);
-@@ -1615,7 +1592,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
+@@ -1615,7 +1596,15 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
  	}
  
  	ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks,
@@ -674,7 +687,7 @@ index cbf1c61..f9fa716 100644
  	if (ret)
  		goto err_find;
  
-@@ -1689,10 +1674,6 @@ static int init_vqs(struct virtnet_info *vi)
+@@ -1689,10 +1678,6 @@ static int init_vqs(struct virtnet_info *vi)
  	if (ret)
  		goto err_free;
  
@@ -685,7 +698,7 @@ index cbf1c61..f9fa716 100644
  	return 0;
  
  err_free:
-@@ -1701,33 +1682,6 @@ err:
+@@ -1701,33 +1686,6 @@ err:
  	return ret;
  }
  
@@ -719,7 +732,7 @@ index cbf1c61..f9fa716 100644
  static bool virtnet_fail_on_feature(struct virtio_device *vdev,
  				    unsigned int fbit,
  				    const char *fname, const char *dname)
-@@ -1768,7 +1722,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1768,7 +1726,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  	struct net_device *dev;
  	struct virtnet_info *vi;
  	u16 max_queue_pairs;
@@ -730,7 +743,7 @@ index cbf1c61..f9fa716 100644
  
  	if (!vdev->config->get) {
  		dev_err(&vdev->dev, "%s failure: config access disabled\n",
-@@ -1804,6 +1761,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1804,6 +1765,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	SET_NETDEV_DEV(dev, &vdev->dev);
  
  	/* Do we support "hardware" checksums? */
@@ -738,7 +751,7 @@ index cbf1c61..f9fa716 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
  		/* This opens up the world of extra features. */
  		dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-@@ -1811,7 +1769,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1811,7 +1773,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
  
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
@@ -747,7 +760,7 @@ index cbf1c61..f9fa716 100644
  				| NETIF_F_TSO_ECN | NETIF_F_TSO6;
  		}
  		/* Individual feature bits: what can host handle? */
-@@ -1821,17 +1779,16 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1821,17 +1783,16 @@ static int virtnet_probe(struct virtio_device *vdev)
  			dev->hw_features |= NETIF_F_TSO6;
  		if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
  			dev->hw_features |= NETIF_F_TSO_ECN;
@@ -767,7 +780,7 @@ index cbf1c61..f9fa716 100644
  
  	dev->vlan_features = dev->features;
  
-@@ -1863,16 +1820,21 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1863,16 +1824,21 @@ static int virtnet_probe(struct virtio_device *vdev)
  	INIT_WORK(&vi->config_work, virtnet_config_changed_work);
  
  	/* If we can receive ANY GSO packets, we must allocate large ones. */
@@ -791,7 +804,7 @@ index cbf1c61..f9fa716 100644
  	    virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
  		vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
  	else
-@@ -1885,6 +1847,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1885,6 +1851,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
  		vi->has_cvq = true;
  
@@ -799,7 +812,7 @@ index cbf1c61..f9fa716 100644
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
-@@ -1892,6 +1855,7 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1892,6 +1859,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  		if (virtnet_change_mtu(dev, mtu))
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
  	}
@@ -807,7 +820,7 @@ index cbf1c61..f9fa716 100644
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
-@@ -1905,10 +1869,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1905,10 +1873,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (err)
  		goto free_stats;
  
@@ -818,7 +831,7 @@ index cbf1c61..f9fa716 100644
  	netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
  	netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
  
-@@ -1920,13 +1880,11 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1920,13 +1884,11 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_vqs;
  	}
  
@@ -836,7 +849,7 @@ index cbf1c61..f9fa716 100644
  
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
-@@ -1943,10 +1901,6 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1943,10 +1905,6 @@ static int virtnet_probe(struct virtio_device *vdev)
  
  	return 0;
  
@@ -847,7 +860,7 @@ index cbf1c61..f9fa716 100644
  free_vqs:
  	cancel_delayed_work_sync(&vi->refill);
  	free_receive_page_frags(vi);
-@@ -1976,11 +1930,13 @@ static void virtnet_remove(struct virtio_device *vdev)
+@@ -1976,11 +1934,13 @@ static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
  
@@ -863,7 +876,7 @@ index cbf1c61..f9fa716 100644
  	unregister_netdev(vi->dev);
  
  	remove_vq_common(vi);
-@@ -1995,8 +1951,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
+@@ -1995,8 +1955,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
  	struct virtnet_info *vi = vdev->priv;
  	int i;
  
@@ -872,7 +885,7 @@ index cbf1c61..f9fa716 100644
  	/* Make sure no work handler is accessing the device */
  	flush_work(&vi->config_work);
  
-@@ -2039,10 +1993,6 @@ static int virtnet_restore(struct virtio_device *vdev)
+@@ -2039,10 +1997,6 @@ static int virtnet_restore(struct virtio_device *vdev)
  	virtnet_set_queues(vi, vi->curr_queue_pairs);
  	rtnl_unlock();
  
@@ -883,7 +896,7 @@ index cbf1c61..f9fa716 100644
  	return 0;
  }
  #endif
-@@ -2052,33 +2002,60 @@ static struct virtio_device_id id_table[] = {
+@@ -2052,33 +2006,60 @@ static struct virtio_device_id id_table[] = {
  	{ 0 },
  };
  
@@ -951,7 +964,7 @@ index cbf1c61..f9fa716 100644
  	.driver.name =	KBUILD_MODNAME,
  	.driver.owner =	THIS_MODULE,
  	.id_table =	id_table,
-@@ -2091,41 +2068,7 @@ static struct virtio_driver virtio_net_driver = {
+@@ -2091,41 +2072,7 @@ static struct virtio_driver virtio_net_driver = {
  #endif
  };
  

From ad56d9d98454fe759503c5747725b68afd421e3e Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 23 Jan 2021 16:47:52 +0100
Subject: [PATCH 1908/2207] fix indentation rule

---
 pre-commit | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pre-commit b/pre-commit
index 15dfabd13..6e9b08561 100755
--- a/pre-commit
+++ b/pre-commit
@@ -42,7 +42,7 @@ fi
 files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c LINUX/forcedeth_netmap.h apps/bridge/bridge.c apps/lb/lb.c apps/vale-ctl/vale-ctl.c apps/dedup/dedup.c apps/include/ctrs.h"
 
 for f in $files; do
-	ERR=$(git grep --line-number "^\(    \)\+" $f | head -n1)
+	ERR=$(git grep --line-number "^\(     \)\+" $f | head -n1)
 	if [ "$ERR" != "" ]; then
 		echo "Wrong indentation in $f"
 		echo "$ERR"

From 2c19a1e1455b4a0096e5081619955e8a6ab93612 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 23 Jan 2021 16:52:40 +0100
Subject: [PATCH 1909/2207] minor style fixes

---
 .clang-format           | 4 ++--
 sys/dev/netmap/netmap.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.clang-format b/.clang-format
index 95a24534b..466dafb9a 100644
--- a/.clang-format
+++ b/.clang-format
@@ -5,8 +5,8 @@ AlwaysBreakAfterDefinitionReturnType: None
 AlwaysBreakAfterReturnType: TopLevelDefinitions
 BreakBeforeBraces: Linux
 ConstructorInitializerIndentWidth: 8
-ContinuationIndentWidth: 8
+ContinuationIndentWidth: 4
 IndentCaseLabels: false
 IndentWidth: 8
 SortIncludes: false
-UseTab: ForIndentation
\ No newline at end of file
+UseTab: ForIndentation
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6130b6b88..51b8941cc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -541,7 +541,7 @@ SYSBEGIN(main_init);
 
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
-		"Netmap args");
+    "Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
 		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 #ifdef CONFIG_NETMAP_DEBUG
@@ -4452,7 +4452,7 @@ nm_set_native_flags(struct netmap_adapter *na)
 	struct ifnet *ifp = na->ifp;
 
 	/* We do the setup for intercepting packets only if we are the
-	 * first user of this adapapter. */
+	 * first user of this adapter. */
 	if (na->active_fds > 0) {
 		return;
 	}

From 657799860d91914a1abe983b645b4bbff3166234 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 25 Jan 2021 08:42:18 +0100
Subject: [PATCH 1910/2207] linux: fix preprocessor directive

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1d4b847ac..121787d59 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -268,7 +268,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			nr_pages,
 			pages,
 			FOLL_WRITE | FOLL_SPLIT | FOLL_POPULATE);
-#elif NETMAP_LINUX_HAVE_GUP_4ARGS
+#elif defined(NETMAP_LINUX_HAVE_GUP_4ARGS)
 	res = get_user_pages_unlocked(
 			p,
 			nr_pages,

From 368c1610a533d10aa868f854a74f5d6b4fc22d79 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 23 Jan 2021 16:47:52 +0100
Subject: [PATCH 1911/2207] fix indentation rule

---
 pre-commit | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pre-commit b/pre-commit
index 15dfabd13..6e9b08561 100755
--- a/pre-commit
+++ b/pre-commit
@@ -42,7 +42,7 @@ fi
 files="sys/dev/netmap/netmap_vale.c sys/dev/netmap/netmap_monitor.c sys/dev/netmap/netmap_pipe.c sys/dev/netmap/netmap.c sys/dev/netmap/netmap_generic.c sys/dev/netmap/netmap_freebsd.c sys/dev/netmap/netmap_legacy.c LINUX/netmap_linux.c LINUX/bsd_glue.h LINUX/i40e_netmap_linux.h LINUX/if_e1000_netmap.h LINUX/if_e1000e_netmap.h LINUX/if_igb_netmap.h LINUX/if_re_netmap_linux.h LINUX/ixgbe_netmap_linux.h LINUX/veth_netmap.h LINUX/virtio_netmap.h LINUX/netmap_ptnet.c LINUX/forcedeth_netmap.h apps/bridge/bridge.c apps/lb/lb.c apps/vale-ctl/vale-ctl.c apps/dedup/dedup.c apps/include/ctrs.h"
 
 for f in $files; do
-	ERR=$(git grep --line-number "^\(    \)\+" $f | head -n1)
+	ERR=$(git grep --line-number "^\(     \)\+" $f | head -n1)
 	if [ "$ERR" != "" ]; then
 		echo "Wrong indentation in $f"
 		echo "$ERR"

From 5ba7cf64517312791d641f0c5b1348cc19ca82ba Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 23 Jan 2021 16:52:40 +0100
Subject: [PATCH 1912/2207] minor style fixes

---
 .clang-format           | 4 ++--
 sys/dev/netmap/netmap.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.clang-format b/.clang-format
index 95a24534b..466dafb9a 100644
--- a/.clang-format
+++ b/.clang-format
@@ -5,8 +5,8 @@ AlwaysBreakAfterDefinitionReturnType: None
 AlwaysBreakAfterReturnType: TopLevelDefinitions
 BreakBeforeBraces: Linux
 ConstructorInitializerIndentWidth: 8
-ContinuationIndentWidth: 8
+ContinuationIndentWidth: 4
 IndentCaseLabels: false
 IndentWidth: 8
 SortIncludes: false
-UseTab: ForIndentation
\ No newline at end of file
+UseTab: ForIndentation
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6130b6b88..51b8941cc 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -541,7 +541,7 @@ SYSBEGIN(main_init);
 
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
-		"Netmap args");
+    "Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
 		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 #ifdef CONFIG_NETMAP_DEBUG
@@ -4452,7 +4452,7 @@ nm_set_native_flags(struct netmap_adapter *na)
 	struct ifnet *ifp = na->ifp;
 
 	/* We do the setup for intercepting packets only if we are the
-	 * first user of this adapapter. */
+	 * first user of this adapter. */
 	if (na->active_fds > 0) {
 		return;
 	}

From 07179f676e00b4373965f83d0a84148abb78d1ac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 25 Jan 2021 08:42:18 +0100
Subject: [PATCH 1913/2207] linux: fix preprocessor directive

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1d4b847ac..121787d59 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -268,7 +268,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			nr_pages,
 			pages,
 			FOLL_WRITE | FOLL_SPLIT | FOLL_POPULATE);
-#elif NETMAP_LINUX_HAVE_GUP_4ARGS
+#elif defined(NETMAP_LINUX_HAVE_GUP_4ARGS)
 	res = get_user_pages_unlocked(
 			p,
 			nr_pages,

From 29560328a2979afb35c8cee4637283f4ab113214 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Tue, 26 Jan 2021 20:57:24 +0000
Subject: [PATCH 1914/2207] bdg: import common parts from vale

---
 LINUX/netmap_linux.c         |   4 +-
 sys/dev/netmap/netmap.c      |  22 +++--
 sys/dev/netmap/netmap_bdg.c  | 151 ++++++++++++++++++++++++++++++++++-
 sys/dev/netmap/netmap_bdg.h  |   2 +
 sys/dev/netmap/netmap_kern.h |   5 +-
 sys/dev/netmap/netmap_vale.c | 139 +-------------------------------
 6 files changed, 167 insertions(+), 156 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 121787d59..fb624a3fb 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2503,8 +2503,8 @@ EXPORT_SYMBOL(netmap_bdg_name);		/* the bridge the vp is attached to */
 EXPORT_SYMBOL(netmap_bdg_update_private_data);
 EXPORT_SYMBOL(netmap_vale_create);
 EXPORT_SYMBOL(netmap_vale_destroy);
-EXPORT_SYMBOL(netmap_vale_attach);
-EXPORT_SYMBOL(netmap_vale_detach);
+EXPORT_SYMBOL(netmap_bdg_attach);
+EXPORT_SYMBOL(netmap_bdg_detach);
 EXPORT_SYMBOL(nm_vi_create);
 EXPORT_SYMBOL(nm_vi_destroy);
 #endif /* WITH_VALE */
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 51b8941cc..d57575c89 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1579,7 +1579,7 @@ netmap_get_na(struct nmreq_header *hdr,
 	if (error || *na != NULL)
 		goto out;
 
-	/* try to see if this is a bridge port */
+	/* try to see if this is a vale port */
 	error = netmap_get_vale_na(hdr, na, nmd, create);
 	if (error)
 		goto out;
@@ -2917,19 +2917,13 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_UNLOCK();
 			break;
 		}
-#ifdef WITH_VALE
 		case NETMAP_REQ_VALE_ATTACH: {
-			error = netmap_vale_attach(hdr, NULL /* userspace request */);
+			error = netmap_bdg_attach(hdr, NULL /* userspace request */);
 			break;
 		}
 
 		case NETMAP_REQ_VALE_DETACH: {
-			error = netmap_vale_detach(hdr, NULL /* userspace request */);
-			break;
-		}
-
-		case NETMAP_REQ_VALE_LIST: {
-			error = netmap_vale_list(hdr);
+			error = netmap_bdg_detach(hdr, NULL /* userspace request */);
 			break;
 		}
 
@@ -3001,6 +2995,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
+#ifdef WITH_VALE
+		case NETMAP_REQ_VALE_LIST: {
+			error = netmap_vale_list(hdr);
+			break;
+		}
+
 		case NETMAP_REQ_VALE_NEWIF: {
 			error = nm_vi_create(hdr);
 			break;
@@ -3010,13 +3010,13 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			error = nm_vi_destroy(hdr->nr_name);
 			break;
 		}
+#endif  /* WITH_VALE */
 
 		case NETMAP_REQ_VALE_POLLING_ENABLE:
 		case NETMAP_REQ_VALE_POLLING_DISABLE: {
 			error = nm_bdg_polling(hdr);
 			break;
 		}
-#endif  /* WITH_VALE */
 		case NETMAP_REQ_POOLS_INFO_GET: {
 			/* Get information from the memory allocator used for
 			 * hdr->nr_name. */
@@ -3944,13 +3944,11 @@ netmap_attach_common(struct netmap_adapter *na)
 		/* use iommu or global allocator */
 		na->nm_mem = netmap_mem_get_iommu(na);
 	}
-#ifdef WITH_VALE
 	if (na->nm_bdg_attach == NULL)
 		/* no special nm_bdg_attach callback. On VALE
 		 * attach, we need to interpose a bwrap
 		 */
 		na->nm_bdg_attach = netmap_default_bdg_attach;
-#endif
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 4f01e23de..f3eed50dc 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -540,6 +540,85 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	return error;
 }
 
+/* Process NETMAP_REQ_VALE_ATTACH.
+ */
+int
+netmap_bdg_attach(struct nmreq_header *hdr, void *auth_token)
+{
+	struct nmreq_vale_attach *req =
+		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
+	struct netmap_vp_adapter * vpna;
+	struct netmap_adapter *na = NULL;
+	struct netmap_mem_d *nmd = NULL;
+	struct nm_bridge *b = NULL;
+	int error;
+
+	NMG_LOCK();
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto unlock_exit;
+	}
+
+	if (req->reg.nr_mem_id) {
+		nmd = netmap_mem_find(req->reg.nr_mem_id);
+		if (nmd == NULL) {
+			error = EINVAL;
+			goto unlock_exit;
+		}
+	}
+
+	/* check for existing one */
+	error = netmap_get_vale_na(hdr, &na, nmd, 0);
+	if (na) {
+		error = EBUSY;
+		goto unref_exit;
+	}
+	error = netmap_get_vale_na(hdr, &na,
+				nmd, 1 /* create if not exists */);
+	if (error) { /* no device */
+		goto unlock_exit;
+	}
+
+	if (na == NULL) { /* VALE prefix missing */
+		error = EINVAL;
+		goto unlock_exit;
+	}
+
+	if (NETMAP_OWNED_BY_ANY(na)) {
+		error = EBUSY;
+		goto unref_exit;
+	}
+
+	if (na->nm_bdg_ctl) {
+		/* nop for VALE ports. The bwrap needs to put the hwna
+		 * in netmap mode (see netmap_bwrap_bdg_ctl)
+		 */
+		error = na->nm_bdg_ctl(hdr, na);
+		if (error)
+			goto unref_exit;
+		nm_prdis("registered %s to netmap-mode", na->name);
+	}
+	vpna = (struct netmap_vp_adapter *)na;
+	req->port_index = vpna->bdg_port;
+
+	if (nmd)
+		netmap_mem_put(nmd);
+
+	NMG_UNLOCK();
+	return 0;
+
+unref_exit:
+	netmap_adapter_put(na);
+unlock_exit:
+	if (nmd)
+		netmap_mem_put(nmd);
+
+	NMG_UNLOCK();
+	return error;
+}
+
 
 int
 nm_is_bwrap(struct netmap_adapter *na)
@@ -547,6 +626,74 @@ nm_is_bwrap(struct netmap_adapter *na)
 	return na->nm_register == netmap_bwrap_reg;
 }
 
+/* Process NETMAP_REQ_VALE_DETACH.
+ */
+int
+netmap_bdg_detach(struct nmreq_header *hdr, void *auth_token)
+{
+	int error;
+
+	NMG_LOCK();
+	error = netmap_bdg_detach_locked(hdr, auth_token);
+	NMG_UNLOCK();
+	return error;
+}
+
+int
+netmap_bdg_detach_locked(struct nmreq_header *hdr, void *auth_token)
+{
+	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
+	struct netmap_vp_adapter *vpna;
+	struct netmap_adapter *na;
+	struct nm_bridge *b = NULL;
+	int error;
+
+	/* permission check for modified bridges */
+	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
+	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
+		error = EACCES;
+		goto error_exit;
+	}
+
+	error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */);
+	if (error) { /* no device, or another bridge or user owns the device */
+		goto error_exit;
+	}
+
+	if (na == NULL) { /* VALE prefix missing */
+		error = EINVAL;
+		goto error_exit;
+	} else if (nm_is_bwrap(na) &&
+		   ((struct netmap_bwrap_adapter *)na)->na_polling_state) {
+		/* Don't detach a NIC with polling */
+		error = EBUSY;
+		goto unref_exit;
+	}
+
+	vpna = (struct netmap_vp_adapter *)na;
+	if (na->na_vp != vpna) {
+		/* trying to detach first attach of VALE persistent port attached
+		 * to 2 bridges
+		 */
+		error = EBUSY;
+		goto unref_exit;
+	}
+	nmreq_det->port_index = vpna->bdg_port;
+
+	if (na->nm_bdg_ctl) {
+		/* remove the port from bridge. The bwrap
+		 * also needs to put the hwna in normal mode
+		 */
+		error = na->nm_bdg_ctl(hdr, na);
+	}
+
+unref_exit:
+	netmap_adapter_put(na);
+error_exit:
+	return error;
+
+}
+
 
 struct nm_bdg_polling_state;
 struct
@@ -1092,7 +1239,7 @@ netmap_bwrap_dtor(struct netmap_adapter *na)
  * hwna rx ring.
  * The bridge wrapper then sends the packets through the bridge.
  */
-static int
+int
 netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
@@ -1217,7 +1364,7 @@ netmap_bwrap_reg(struct netmap_adapter *na, int onoff)
 		/* intercept the hwna nm_nofify callback on the hw rings */
 		for (i = 0; i < hwna->num_rx_rings; i++) {
 			hwna->rx_rings[i]->save_notify = hwna->rx_rings[i]->nm_notify;
-			hwna->rx_rings[i]->nm_notify = netmap_bwrap_intr_notify;
+			hwna->rx_rings[i]->nm_notify = bna->nm_intr_notify;
 		}
 		i = hwna->num_rx_rings; /* for safety */
 		/* save the host ring notify unconditionally */
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index e4683885e..a88eaf11b 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -178,8 +178,10 @@ int netmap_bdg_free(struct nm_bridge *b);
 void netmap_bdg_detach_common(struct nm_bridge *b, int hw, int sw);
 int netmap_vp_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na);
 int netmap_bwrap_reg(struct netmap_adapter *, int onoff);
+int netmap_bdg_detach_locked(struct nmreq_header *hdr, void *auth_token);
 int netmap_vp_reg(struct netmap_adapter *na, int onoff);
 int netmap_vp_rxsync(struct netmap_kring *kring, int flags);
+int netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags);
 int netmap_bwrap_notify(struct netmap_kring *kring, int flags);
 int netmap_bwrap_attach_common(struct netmap_adapter *na,
 		struct netmap_adapter *hwna);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 10531cf70..6fad0afdd 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1152,12 +1152,13 @@ struct netmap_bwrap_adapter {
 	 * here its original value, to be restored at detach
 	 */
 	struct netmap_vp_adapter *saved_na_vp;
+	int (*nm_intr_notify)(struct netmap_kring *kring, int flags);
 };
 int nm_bdg_polling(struct nmreq_header *hdr);
 
+int netmap_bdg_attach(struct nmreq_header *hdr, void *auth_token);
+int netmap_bdg_detach(struct nmreq_header *hdr, void *auth_token);
 #ifdef WITH_VALE
-int netmap_vale_attach(struct nmreq_header *hdr, void *auth_token);
-int netmap_vale_detach(struct nmreq_header *hdr, void *auth_token);
 int netmap_vale_list(struct nmreq_header *hdr);
 int netmap_vi_create(struct nmreq_header *hdr, int);
 int nm_vi_create(struct nmreq_header *);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 2ae81c96f..29f8f4852 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -389,144 +389,6 @@ netmap_vale_list(struct nmreq_header *hdr)
 	return error;
 }
 
-/* Process NETMAP_REQ_VALE_ATTACH.
- */
-int
-netmap_vale_attach(struct nmreq_header *hdr, void *auth_token)
-{
-	struct nmreq_vale_attach *req =
-		(struct nmreq_vale_attach *)(uintptr_t)hdr->nr_body;
-	struct netmap_vp_adapter * vpna;
-	struct netmap_adapter *na = NULL;
-	struct netmap_mem_d *nmd = NULL;
-	struct nm_bridge *b = NULL;
-	int error;
-
-	NMG_LOCK();
-	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
-	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_exit;
-	}
-
-	if (req->reg.nr_mem_id) {
-		nmd = netmap_mem_find(req->reg.nr_mem_id);
-		if (nmd == NULL) {
-			error = EINVAL;
-			goto unlock_exit;
-		}
-	}
-
-	/* check for existing one */
-	error = netmap_get_vale_na(hdr, &na, nmd, 0);
-	if (na) {
-		error = EBUSY;
-		goto unref_exit;
-	}
-	error = netmap_get_vale_na(hdr, &na,
-				nmd, 1 /* create if not exists */);
-	if (error) { /* no device */
-		goto unlock_exit;
-	}
-
-	if (na == NULL) { /* VALE prefix missing */
-		error = EINVAL;
-		goto unlock_exit;
-	}
-
-	if (NETMAP_OWNED_BY_ANY(na)) {
-		error = EBUSY;
-		goto unref_exit;
-	}
-
-	if (na->nm_bdg_ctl) {
-		/* nop for VALE ports. The bwrap needs to put the hwna
-		 * in netmap mode (see netmap_bwrap_bdg_ctl)
-		 */
-		error = na->nm_bdg_ctl(hdr, na);
-		if (error)
-			goto unref_exit;
-		nm_prdis("registered %s to netmap-mode", na->name);
-	}
-	vpna = (struct netmap_vp_adapter *)na;
-	req->port_index = vpna->bdg_port;
-
-	if (nmd)
-		netmap_mem_put(nmd);
-
-	NMG_UNLOCK();
-	return 0;
-
-unref_exit:
-	netmap_adapter_put(na);
-unlock_exit:
-	if (nmd)
-		netmap_mem_put(nmd);
-
-	NMG_UNLOCK();
-	return error;
-}
-
-/* Process NETMAP_REQ_VALE_DETACH.
- */
-int
-netmap_vale_detach(struct nmreq_header *hdr, void *auth_token)
-{
-	struct nmreq_vale_detach *nmreq_det = (void *)(uintptr_t)hdr->nr_body;
-	struct netmap_vp_adapter *vpna;
-	struct netmap_adapter *na;
-	struct nm_bridge *b = NULL;
-	int error;
-
-	NMG_LOCK();
-	/* permission check for modified bridges */
-	b = nm_find_bridge(hdr->nr_name, 0 /* don't create */, NULL);
-	if (b && !nm_bdg_valid_auth_token(b, auth_token)) {
-		error = EACCES;
-		goto unlock_exit;
-	}
-
-	error = netmap_get_vale_na(hdr, &na, NULL, 0 /* don't create */);
-	if (error) { /* no device, or another bridge or user owns the device */
-		goto unlock_exit;
-	}
-
-	if (na == NULL) { /* VALE prefix missing */
-		error = EINVAL;
-		goto unlock_exit;
-	} else if (nm_is_bwrap(na) &&
-		   ((struct netmap_bwrap_adapter *)na)->na_polling_state) {
-		/* Don't detach a NIC with polling */
-		error = EBUSY;
-		goto unref_exit;
-	}
-
-	vpna = (struct netmap_vp_adapter *)na;
-	if (na->na_vp != vpna) {
-		/* trying to detach first attach of VALE persistent port attached
-		 * to 2 bridges
-		 */
-		error = EBUSY;
-		goto unref_exit;
-	}
-	nmreq_det->port_index = vpna->bdg_port;
-
-	if (na->nm_bdg_ctl) {
-		/* remove the port from bridge. The bwrap
-		 * also needs to put the hwna in normal mode
-		 */
-		error = na->nm_bdg_ctl(hdr, na);
-	}
-
-unref_exit:
-	netmap_adapter_put(na);
-unlock_exit:
-	NMG_UNLOCK();
-	return error;
-
-}
-
 
 /* nm_dtor callback for ephemeral VALE ports */
 static void
@@ -1425,6 +1287,7 @@ netmap_vale_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna)
 	na->nm_krings_create = netmap_vale_bwrap_krings_create;
 	na->nm_krings_delete = netmap_vale_bwrap_krings_delete;
 	na->nm_notify = netmap_bwrap_notify;
+	bna->nm_intr_notify = netmap_bwrap_intr_notify;
 	bna->up.retry = 1; /* XXX maybe this should depend on the hwna */
 	/* Set the mfs, needed on the VALE mismatch datapath. */
 	bna->up.mfs = NM_BDG_MFS_DEFAULT;

From 6a5fd616ecdf4523d6fff6f9e05aa219603c42a1 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Tue, 26 Jan 2021 20:57:49 +0000
Subject: [PATCH 1915/2207] bdg: update hostna after config

---
 sys/dev/netmap/netmap_bdg.c  | 14 ++++++++++++++
 sys/dev/netmap/netmap_kern.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index f3eed50dc..7675d9cb1 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1435,6 +1435,16 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 	info->num_rx_descs = hwna->num_tx_desc;
 	info->rx_buf_maxsize = hwna->rx_buf_maxsize;
 
+	if (na->na_flags & NAF_HOST_RINGS && na->na_flags & NAF_HOST_ALL) {
+		enum txrx t;
+		for_rx_tx(t) {
+			int nr = nma_get_nrings(hwna, nm_txrx_swap(t));
+			nma_set_nrings(&bna->host.up, t, nr);
+			nma_set_host_nrings(&bna->up.up, t, nr);
+			nma_set_host_nrings(hwna, t, nma_get_nrings(hwna, t));
+		}
+	}
+
 	return 0;
 }
 
@@ -1732,6 +1742,10 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 		na->na_flags |= NAF_HOST_RINGS;
 		hostna = &bna->host.up;
 
+		/* bwrap_config() called in update_config() might
+		 * increase these default ring parameters.
+		 */
+
 		/* limit the number of host rings to that of hw */
 		nm_bound_var(&hostna->num_tx_rings, 1, 1,
 				nma_get_nrings(hwna, NR_TX), NULL);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6fad0afdd..6f6b03d7b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -758,6 +758,7 @@ struct netmap_adapter {
 /* free */
 #define NAF_MOREFRAG	512	/* the adapter supports NS_MOREFRAG */
 #define NAF_OFFSETS	1024	/* the adapter supports the slot offsets */
+#define NAF_HOST_ALL	2048	/* the adapter wants as many host rings as hw */
 #define NAF_ZOMBIE	(1U<<30) /* the nic driver has been unloaded */
 #define	NAF_BUSY	(1U<<31) /* the adapter is used internally and
 				  * cannot be registered from userspace

From efadbb911f8e0fb1ca93af9d26047fb357634ac4 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Tue, 26 Jan 2021 21:16:29 +0000
Subject: [PATCH 1916/2207] bdg: drop/restore the mem reference of hwna

---
 sys/dev/netmap/netmap.c      | 16 ++++++++++++----
 sys/dev/netmap/netmap_bdg.c  |  2 ++
 sys/dev/netmap/netmap_kern.h |  1 +
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index d57575c89..494e1c604 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -977,6 +977,16 @@ netmap_hw_krings_delete(struct netmap_adapter *na)
 	netmap_krings_delete(na);
 }
 
+void
+netmap_mem_restore(struct netmap_adapter *na)
+{
+	if (na->nm_mem_prev) {
+		netmap_mem_put(na->nm_mem);
+		na->nm_mem = na->nm_mem_prev;
+		na->nm_mem_prev = NULL;
+	}
+}
+
 static void
 netmap_mem_drop(struct netmap_adapter *na)
 {
@@ -984,10 +994,8 @@ netmap_mem_drop(struct netmap_adapter *na)
 	/* if the native allocator had been overrided on regif,
 	 * restore it now and drop the temporary one
 	 */
-	if (last && na->nm_mem_prev) {
-		netmap_mem_put(na->nm_mem);
-		na->nm_mem = na->nm_mem_prev;
-		na->nm_mem_prev = NULL;
+	if (netmap_mem_deref(na->nm_mem, na)) {
+		netmap_mem_restore(na);
 	}
 }
 
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 7675d9cb1..340dae706 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1675,6 +1675,7 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 		error = netmap_do_regif(npriv, na, hdr);
 		if (error) {
 			netmap_priv_delete(npriv);
+			netmap_mem_restore(bna->hwna);
 			return error;
 		}
 		bna->na_kpriv = npriv;
@@ -1685,6 +1686,7 @@ netmap_bwrap_bdg_ctl(struct nmreq_header *hdr, struct netmap_adapter *na)
 		netmap_priv_delete(bna->na_kpriv);
 		bna->na_kpriv = NULL;
 		na->na_flags &= ~NAF_BUSY;
+		netmap_mem_restore(bna->hwna);
 	}
 
 	return error;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6f6b03d7b..e5d7ebad3 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1557,6 +1557,7 @@ int netmap_get_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
 int netmap_get_hw_na(struct ifnet *ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
+void netmap_mem_restore(struct netmap_adapter *na);
 
 #ifdef WITH_VALE
 uint32_t netmap_vale_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,

From e7356e6b2f92a75a85d8fe245d941ae264c327fd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 08:57:33 +0100
Subject: [PATCH 1917/2207] linux/igb: patch for Intel 5.5.2 version

---
 LINUX/default-config.mak.in_          |   2 +-
 LINUX/final-patches/intel--igb--5.5.2 | 138 ++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--igb--5.5.2

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 40074ba93..301764d56 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -78,7 +78,7 @@ endef
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
-igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6),@SRCDIR@/intel-fix.sh igb,)
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1),@SRCDIR@/intel-fix.sh ixgbe,)
diff --git a/LINUX/final-patches/intel--igb--5.5.2 b/LINUX/final-patches/intel--igb--5.5.2
new file mode 100644
index 000000000..1ad59fbc0
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.5.2
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 811a634..2559d39 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 0b53658..25d4630 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3209,6 +3213,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3414,6 +3422,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3826,6 +3838,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7511,6 +7526,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8527,6 +8547,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8846,6 +8871,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From ac03b0a72e0b5a838eccd68e681235c2d55831f9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 09:18:48 +0100
Subject: [PATCH 1918/2207] linux/configure: capture stderr in config.log

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 71661d071..70cddae74 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -564,7 +564,7 @@ EOF
 	(
 		cd $TMPDIR
 		make $MAKE_OPT -k -j $NPROC
-	) >> config.log
+	) >> config.log 2>&1
 	eval "$TESTPOSTPROC"
 	cat >> config.log <
Date: Wed, 27 Jan 2021 09:24:52 +0100
Subject: [PATCH 1919/2207] linux/scripts: don't build null port during driver
 tests

---
 LINUX/scripts/np | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index b73c99783..6164d8b21 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -508,6 +508,7 @@ function check-patch()
 				--disable-vale \
 				--disable-monitor \
 				--disable-ptnetmap \
+				--disable-null \
 				--no-apps \
 				--kernel-opts=CONFIG_STACK_VALIDATION= \
 				$config_opts \

From 3f352c4dafd368e20bf2a9a5604b1b4d403b7972 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 10:29:42 +0100
Subject: [PATCH 1920/2207] linux/i40e: patch for Intel 2.14.13 version

---
 LINUX/default-config.mak.in_             |   2 +-
 LINUX/final-patches/intel--i40e--2.14.13 | 168 +++++++++++++++++++++++
 2 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.14.13

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 301764d56..d61c94d43 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -82,7 +82,7 @@ igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1),@SRCDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6),@SRCDIR@/intel-fix.sh i40e,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13),@SRCDIR@/intel-fix.sh i40e,)
 
 # set all the default versions (can be overrided by --select-version=)
 $(eval $(call default,ixgbe,5.3.8))
diff --git a/LINUX/final-patches/intel--i40e--2.14.13 b/LINUX/final-patches/intel--i40e--2.14.13
new file mode 100644
index 000000000..07208cd44
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.14.13
@@ -0,0 +1,168 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 81f5ab9..85bfb8c 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 9aea7ca..09297e6 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -150,6 +150,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3716,6 +3721,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3769,6 +3778,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3797,6 +3810,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -14865,6 +14883,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15237,6 +15261,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index ea07464..845de14 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -935,6 +939,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2741,7 +2750,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif

From 72dfa0e984b56768c0db01b36a1005b9740816e4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 10:58:12 +0100
Subject: [PATCH 1921/2207] linux/ixgbe: patch for Intel 5.10.2 version

---
 LINUX/default-config.mak.in_             |   2 +-
 LINUX/final-patches/intel--ixgbe--5.10.2 | 173 +++++++++++++++++++++++
 2 files changed, 174 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.10.2

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index d61c94d43..d0c084f67 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -81,7 +81,7 @@ ixgbe@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
-ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1),@SRCDIR@/intel-fix.sh ixgbe,)
+ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2),@SRCDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13),@SRCDIR@/intel-fix.sh i40e,)
 
 # set all the default versions (can be overrided by --select-version=)
diff --git a/LINUX/final-patches/intel--ixgbe--5.10.2 b/LINUX/final-patches/intel--ixgbe--5.10.2
new file mode 100644
index 000000000..7302b57ab
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.10.2
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 01e67d7..91f53e1 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index c4eb984..eeb6ff6 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -711,6 +711,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -730,6 +747,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2208,6 +2236,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3688,6 +3726,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4364,6 +4406,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_umem)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -12983,6 +13031,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13038,6 +13090,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 1497260b26c4c4d8359db313e33a176c6eb5558f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 11:16:34 +0100
Subject: [PATCH 1922/2207] linux/ixgbevf: patch for Intel 4.10.2 version

---
 LINUX/default-config.mak.in_               |   2 +-
 LINUX/final-patches/intel--ixgbevf--4.10.2 | 168 +++++++++++++++++++++
 2 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.10.2

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index d0c084f67..e82156655 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -80,7 +80,7 @@ igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
-ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1),@SRCDIR@/intel-fix.sh ixgbevf,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2),@SRCDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13),@SRCDIR@/intel-fix.sh i40e,)
 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.10.2 b/LINUX/final-patches/intel--ixgbevf--4.10.2
new file mode 100644
index 000000000..47d35bb50
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.10.2
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index dc49435..103a5d1 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 518123d..20e8b7d 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -343,6 +343,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -363,6 +380,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1375,6 +1403,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2093,6 +2131,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2327,6 +2369,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5636,8 +5682,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5678,6 +5726,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 080ed09..2c16b66 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From adf62451d5e6a1a121aade2c842faff0b1a305d1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 15:19:42 +0100
Subject: [PATCH 1923/2207] liux/configure: log stderr also during preliminary
 tests

---
 LINUX/configure | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 70cddae74..040524196 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -487,14 +487,14 @@ EOF
 	(
 		cd $TMPDIR
 		LANG=C make $MAKE_OPT -k -j $NPROC
-	) >> config.log
+	) >> config.log 2>&1
 	if grep -q ": invalid option -- 'O'" config.log; then
 		MAKE_OPT=
 		# let us try again without -O
 		(
 			cd $TMPDIR
 			make -k -j $NPROC
-		) >> config.log
+		) >> config.log 2>&1
 	fi
 	eval "$TESTPOSTPROC"
 	cat >> config.log <
Date: Wed, 27 Jan 2021 15:42:59 +0100
Subject: [PATCH 1924/2207] linux/configure: don't pass EXTRA_CFLAGS to
 external drivers

During the configureation phase, EXTRA_CFLAGS enables -Werror to improve
the sensitivity of the feature tests and selectively disables some of
the warnings to improve the specificity.

The -Werror flag, however, may cause the test build of the unpatched
external drivers to fail, causing them to be unnecessarily disabled.

This patch passes the configuration-phase EXTRA_CFLAGS only to the
feature tests. During this phase the external drivers receive an empty
EXTRA_CFLAGS, thus making the comment in LINUX/default_config.mak.in_
true again.
---
 LINUX/configure | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 040524196..61971e9ca 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -513,7 +513,7 @@ SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 else
-EXTRA_CFLAGS := -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
+WARN_CFLAGS := -Wno-unused-variable -Wno-unused-label -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
 S_DRIVERS := $(drv print)
 E_DRIVERS := $(edrv print)
 C_DRIVERS := $(cdrv print)
@@ -524,7 +524,7 @@ TOBUILD := \$(filter-out \$(C_DRIVERS),\$(E_DRIVERS))
 all: \$(S_DRIVERS:%=get-%) \$(TOBUILD:%=build-%) \$(I_DRIVERS:%=patch-%) tests
 
 tests:
-	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(EXTRA_CFLAGS)" $kopts
+	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts
 
 -include $BUILDDIR/extdrv-versions.mak
 -include $BUILDDIR/default-config.mak

From fe00d906e5c5b7efdea1979ceb420f1a5568fc95 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Jan 2021 16:35:49 +0100
Subject: [PATCH 1925/2207] linux/configure: add MODULE_LICENSE to feature
 tests, to silence modpost

---
 LINUX/configure | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 61971e9ca..5cad0dc87 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -411,6 +411,9 @@ add_named_test() {
 	#include 
 EOF
 		cat	# output the test code read from stdin
+		cat < $TMPDIR/$1.c
 	{
 		cat <
Date: Wed, 27 Jan 2021 23:37:18 +0000
Subject: [PATCH 1926/2207] bug fix on mem_drop()

---
 sys/dev/netmap/netmap.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 494e1c604..1a839bb5b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -990,7 +990,6 @@ netmap_mem_restore(struct netmap_adapter *na)
 static void
 netmap_mem_drop(struct netmap_adapter *na)
 {
-	int last = netmap_mem_deref(na->nm_mem, na);
 	/* if the native allocator had been overrided on regif,
 	 * restore it now and drop the temporary one
 	 */

From c19a8a49751d4a739c0d83965a0d6ae2ca937eb7 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Wed, 27 Jan 2021 23:37:47 +0000
Subject: [PATCH 1927/2207] bdg: decide ring params at the config time

---
 sys/dev/netmap/netmap_bdg.c | 48 +++++++++++++++++--------------------
 1 file changed, 22 insertions(+), 26 deletions(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 340dae706..65f20e7f7 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1435,13 +1435,29 @@ netmap_bwrap_config(struct netmap_adapter *na, struct nm_config_info *info)
 	info->num_rx_descs = hwna->num_tx_desc;
 	info->rx_buf_maxsize = hwna->rx_buf_maxsize;
 
-	if (na->na_flags & NAF_HOST_RINGS && na->na_flags & NAF_HOST_ALL) {
+	if (na->na_flags & NAF_HOST_RINGS) {
+		struct netmap_adapter *hostna = &bna->host.up;
 		enum txrx t;
+
+		/* limit the number of host rings to that of hw */
+		if (na->na_flags & NAF_HOST_ALL) {
+			hostna->num_tx_rings = nma_get_nrings(hwna, NR_RX);
+			hostna->num_rx_rings = nma_get_nrings(hwna, NR_TX);
+		} else {
+			nm_bound_var(&hostna->num_tx_rings, 1, 1,
+				nma_get_nrings(hwna, NR_TX), NULL);
+			nm_bound_var(&hostna->num_rx_rings, 1, 1,
+				nma_get_nrings(hwna, NR_RX), NULL);
+		}
 		for_rx_tx(t) {
-			int nr = nma_get_nrings(hwna, nm_txrx_swap(t));
-			nma_set_nrings(&bna->host.up, t, nr);
-			nma_set_host_nrings(&bna->up.up, t, nr);
-			nma_set_host_nrings(hwna, t, nma_get_nrings(hwna, t));
+			enum txrx r = nm_txrx_swap(t);
+			u_int nr = nma_get_nrings(hostna, t);
+
+			nma_set_host_nrings(na, t, nr);
+			if (nma_get_host_nrings(hwna, t) < nr) {
+				nma_set_host_nrings(hwna, t, nr);
+			}
+			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
 		}
 	}
 
@@ -1744,29 +1760,8 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 		na->na_flags |= NAF_HOST_RINGS;
 		hostna = &bna->host.up;
 
-		/* bwrap_config() called in update_config() might
-		 * increase these default ring parameters.
-		 */
-
-		/* limit the number of host rings to that of hw */
-		nm_bound_var(&hostna->num_tx_rings, 1, 1,
-				nma_get_nrings(hwna, NR_TX), NULL);
-		nm_bound_var(&hostna->num_rx_rings, 1, 1,
-				nma_get_nrings(hwna, NR_RX), NULL);
-
 		snprintf(hostna->name, sizeof(hostna->name), "%s^", na->name);
 		hostna->ifp = hwna->ifp;
-		for_rx_tx(t) {
-			enum txrx r = nm_txrx_swap(t);
-			u_int nr = nma_get_nrings(hostna, t);
-
-			nma_set_nrings(hostna, t, nr);
-			nma_set_host_nrings(na, t, nr);
-			if (nma_get_host_nrings(hwna, t) < nr) {
-				nma_set_host_nrings(hwna, t, nr);
-			}
-			nma_set_ndesc(hostna, t, nma_get_ndesc(hwna, r));
-		}
 		// hostna->nm_txsync = netmap_bwrap_host_txsync;
 		// hostna->nm_rxsync = netmap_bwrap_host_rxsync;
 		hostna->nm_mem = netmap_mem_get(na->nm_mem);
@@ -1776,6 +1771,7 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 			hostna->na_hostvp = &bna->host;
 		hostna->na_flags = NAF_BUSY; /* prevent NIOCREGIF */
 		hostna->rx_buf_maxsize = hwna->rx_buf_maxsize;
+		/* bwrap_config() will determine the number of host rings */
 	}
 	if (hwna->na_flags & NAF_MOREFRAG)
 		na->na_flags |= NAF_MOREFRAG;

From 8c148880665dabcb244a574e471c6bec21ed9298 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 28 Jan 2021 19:03:04 +0000
Subject: [PATCH 1928/2207] reverted #ifdef WITH_VALE position

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 1a839bb5b..4301ba1bf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2924,6 +2924,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			NMG_UNLOCK();
 			break;
 		}
+#ifdef WITH_VALE
 		case NETMAP_REQ_VALE_ATTACH: {
 			error = netmap_bdg_attach(hdr, NULL /* userspace request */);
 			break;
@@ -3002,7 +3003,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			break;
 		}
 
-#ifdef WITH_VALE
 		case NETMAP_REQ_VALE_LIST: {
 			error = netmap_vale_list(hdr);
 			break;

From 553d4589c59d1786ca585cfa1249bc2ea9e2ace5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 29 Jan 2021 12:44:01 +0100
Subject: [PATCH 1929/2207] linux: fix driver init routines

---
 LINUX/forcedeth_netmap.h   | 23 ++++++-----------------
 LINUX/i40e_netmap_linux.h  |  7 +++----
 LINUX/if_e1000_netmap.h    | 29 +++++------------------------
 LINUX/if_e1000e_netmap.h   | 25 +++++++++----------------
 LINUX/if_igb_netmap.h      | 26 ++++++++------------------
 LINUX/if_re_netmap_linux.h |  2 +-
 LINUX/ixgbe_netmap_linux.h |  7 +++----
 7 files changed, 35 insertions(+), 84 deletions(-)

diff --git a/LINUX/forcedeth_netmap.h b/LINUX/forcedeth_netmap.h
index 5a9a1672b..0fd7a2915 100644
--- a/LINUX/forcedeth_netmap.h
+++ b/LINUX/forcedeth_netmap.h
@@ -318,8 +318,6 @@ forcedeth_netmap_rxsync(struct netmap_kring *kring, int flags)
 static int
 forcedeth_netmap_tx_init(struct SOFTC_T *np)
 {
-	struct ring_desc_ex *desc;
-	int i, n;
 	struct netmap_adapter *na = NA(np->dev);
 	struct netmap_slot *slot;
 
@@ -327,20 +325,11 @@ forcedeth_netmap_tx_init(struct SOFTC_T *np)
 	/* slot is NULL if we are not in native netmap mode */
 	if (!slot)
 		return 0;
-	/* in netmap mode, overwrite addresses and maps */
-	//txd = np->rl_ldata.rl_tx_desc;
-	desc = np->tx_ring.ex;
-	n = np->tx_ring_size;
-
-	/* l points in the netmap ring, i points in the NIC ring */
-	for (i = 0; i < n; i++) {
-		int l = netmap_idx_n2k(na->tx_rings[0], i);
-		uint64_t paddr;
-		PNMB(na, slot + l, &paddr);
-		desc[i].flaglen = 0;
-		desc[i].bufhigh = htole32(dma_high(paddr));
-		desc[i].buflow = htole32(dma_low(paddr));
-	}
+
+	/* no need to pre-fill the tx rings, since txsync
+	 * will always overwrite the tx slots
+	 */
+
 	return 1;
 }
 
@@ -361,7 +350,7 @@ forcedeth_netmap_rx_init(struct SOFTC_T *np)
 	 * and also keep one empty.
 	 */
 	lim = np->rx_ring_size - 1 - nm_kr_rxspace(na->rx_rings[0]);
-	for (i = 0; i < np->rx_ring_size; i++) {
+	for (i = 0; i < lim; i++) {
 		void *addr;
 		uint64_t paddr;
 		int l = netmap_idx_n2k(na->rx_rings[0], i);
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index c617c00b0..0f6018888 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -159,7 +159,7 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 	struct netmap_adapter *na;
 	struct netmap_slot *slot;
 	struct netmap_kring *kring;
-	int lim, i, ring_nr, n;
+	int lim, i, ring_nr;
 
 	if (!ring->netdev) {
 		// XXX it this possible?
@@ -174,10 +174,9 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 		return 0;	// not in native netmap mode
 
 	kring = na->rx_rings[ring_nr];
-	n = nm_kr_rxspace(kring);
-	lim = na->num_rx_desc - 1 - n;
+	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
 
-	for (i = 0; i < n; i++) {
+	for (i = 0; i < lim; i++) {
 		int si = netmap_idx_n2k(kring, i);
 		uint64_t paddr;
 		union i40e_rx_desc *rx = I40E_RX_DESC(ring, i);
diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index c32576e23..a8b0864a7 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -371,7 +371,6 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 	struct netmap_adapter* na = NA(ifp);
 	struct netmap_kring *kring;
 	struct netmap_slot* slot;
-	struct e1000_tx_ring* txr = &adapter->tx_ring[0];
 	unsigned int i, r, si, n;
 	uint64_t paddr;
 	uint32_t rctl;
@@ -391,7 +390,7 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 
 		/* preserve buffers already made available to clients */
 		kring->nkr_to_refill = nm_kr_rxspace(kring);
-		n = rxr->count - kring->nkr_to_refill;
+		n = rxr->count - 1 - kring->nkr_to_refill;
 
 		for (i = 0; i < n; i++) {
 			si = netmap_idx_n2k(kring, i);
@@ -408,30 +407,12 @@ static int e1000_netmap_init_buffers(struct SOFTC_T *adapter)
 		ew32(RCTL, rctl);
 
 		wmb(); /* Force memory writes to complete */
-		writel(i, hw->hw_addr + rxr->rdt);
+		writel(n, hw->hw_addr + rxr->rdt);
 	}
 
-	/* now initialize the tx ring(s) */
-	for (r = 0; r < na->num_tx_rings; r++) {
-		slot = netmap_reset(na, NR_TX, r, 0);
-		if (!slot) {
-			nm_prinf("Skipping TX ring %d, netmap mode not requested", r);
-			continue;
-		}
-
-		/* preserve buffers already made available to clients */
-		n = txr->count - nm_kr_txspace(kring);
-		/* there is no need to update nkr_to_refill, since the txsync
-		 * always refills the hw slots anyway
-		 */
-
-		for (i = 0; i < n; i++) {
-			kring = na->tx_rings[r];
-			si = netmap_idx_n2k(kring, i);
-			PNMB_O(kring, slot + si, &paddr);
-			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
-		}
-	}
+	/* no need to initialize the tx rings, since txsync will always
+	 * overwrite the tx slots
+	 */
 
 	return 1;
 }
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index 1aa6fb3f3..cfbba6729 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -401,7 +401,6 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 	struct netmap_kring *kring;
 	struct netmap_slot* slot;
 	struct e1000_ring *rxr = adapter->rx_ring;
-	struct e1000_ring *txr = adapter->tx_ring;
 	int i, si, n;
 	uint64_t paddr;
 	uint32_t rctl;
@@ -414,7 +413,8 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		kring = na->rx_rings[0];
 		/* initialize the RX ring for netmap mode */
 		adapter->alloc_rx_buf = (void*)e1000e_no_rx_alloc;
-		n = nm_kr_rxspace(kring);
+		/* preserve buffers already made available to clients */
+		n = rxr->count - 1 - nm_kr_rxspace(kring);
 		for (i = 0; i < n; i++) {
 			struct e1000_buffer *bi = &rxr->buffer_info[i];
 			si = netmap_idx_n2k(kring, i);
@@ -424,8 +424,6 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 			E1000_RX_DESC_EXT(*rxr, i)->NM_E1R_RX_BUFADDR = htole64(paddr);
 		}
 		rxr->next_to_use = 0;
-		/* preserve buffers already made available to clients */
-		i = rxr->count - 1 - n;
 
 		/* program the RCTL */
 		rctl = er32(RCTL);
@@ -434,20 +432,15 @@ static int e1000e_netmap_init_buffers(struct SOFTC_T *adapter)
 		ew32(RCTL, rctl);
 
 		wmb();	/* Force memory writes to complete */
-		NM_WR_RX_TAIL(i);
+		NM_WR_RX_TAIL(n);
 	}
 
-	slot = netmap_reset(na, NR_TX, 0, 0);
-	if (slot) {
-		/* initialize the tx ring for netmap mode */
-		kring = na->tx_rings[0];
-		n = nm_kr_rxspace(kring);
-		for (i = 0; i < n; i++) {
-			si = netmap_idx_n2k(kring, i);
-			PNMB_O(kring, slot + si, &paddr);
-			E1000_TX_DESC(*txr, i)->buffer_addr = htole64(paddr);
-		}
-	}
+	netmap_reset(na, NR_TX, 0, 0);
+
+	/* no need to fill the tx ring, since txsync will always
+	 * overwrite the tx slots
+	 */
+
 	return 1;
 }
 
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index e844c4b1f..e63982a7e 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -410,24 +410,15 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 	struct ifnet *ifp = adapter->netdev;
 	struct netmap_adapter* na = NA(ifp);
 	struct netmap_slot* slot;
-	struct igb_ring *txr = adapter->tx_ring[ring_nr];
-	struct netmap_kring *kring;
-	int i, si;
-	void *addr;
-	uint64_t paddr;
 
 	slot = netmap_reset(na, NR_TX, ring_nr, 0);
 	if (!slot)
 		return 0;  // not in netmap native mode
-	kring = na->tx_rings[ring_nr];
-	for (i = 0; i < na->num_tx_desc; i++) {
-		union e1000_adv_tx_desc *tx_desc;
-		si = netmap_idx_n2k(kring, i);
-		addr = PNMB_O(kring, slot + si, &paddr);
-		tx_desc = E1000_TX_DESC_ADV(*txr, i);
-		tx_desc->read.buffer_addr = htole64(paddr);
-		/* actually we don't care to init the rings here */
-	}
+
+	/* no need to fill the tx rings, since txsync will
+	 * always overwrite the tx slots
+	 */
+
 	return 1;	// success
 }
 
@@ -494,7 +485,8 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	igb_netmap_configure_srrctl(rxr);
 
 	kring = na->rx_rings[reg_idx];
-	n = nm_kr_rxspace(na->rx_rings[reg_idx]);
+	/* preserve buffers already made available to clients */
+	n = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[reg_idx]);
 	for (i = 0; i < n; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;
@@ -505,12 +497,10 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 		rx_desc->read.hdr_addr = 0;
 		rx_desc->read.pkt_addr = htole64(paddr);
 	}
-	/* preserve buffers already made available to clients */
-	i = rxr->count - 1 - n;
 
 	wmb();	/* Force memory writes to complete */
 	nm_prdis("%s rxr%d.tail %d", na->name, reg_idx, i);
-	writel(i, rxr->tail);
+	writel(n, rxr->tail);
 	return 1;	// success
 }
 
diff --git a/LINUX/if_re_netmap_linux.h b/LINUX/if_re_netmap_linux.h
index ff7cc0c6b..dd8175de6 100644
--- a/LINUX/if_re_netmap_linux.h
+++ b/LINUX/if_re_netmap_linux.h
@@ -311,7 +311,7 @@ re_netmap_rx_init(struct SOFTC_T *sc)
 	 * XXX do we need -1 instead ?
 	 */
 	lim = na->num_rx_desc /* - 1 */ - nm_kr_rxspace(&na->rx_rings[0]);
-	for (i = 0; i < na->num_rx_desc; i++) {
+	for (i = 0; i < lim; i++) {
 		l = netmap_idx_n2k(na->rx_rings[0], i);
 		PNMB(na, slot + l, &paddr);
 		cmdstat = NETMAP_BUF_SIZE(na);
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index f100e8dc6..1ea571a23 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -720,7 +720,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 	 */
 	struct netmap_adapter *na = NA(adapter->netdev);
 	struct netmap_slot *slot;
-	int lim, i, n;
+	int lim, i;
 	struct NM_IXGBE_RING *ring = NM_IXGBE_RX_RING(adapter, ring_nr);
 	struct netmap_kring *kring;
 
@@ -733,10 +733,9 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 
 	ixgbe_netmap_configure_srrctl(adapter, ring);
 
-	n = nm_kr_rxspace(na->rx_rings[ring_nr]);
-	lim = na->num_rx_desc - 1 - n;
+	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 
-	for (i = 0; i < n; i++) {
+	for (i = 0; i < lim; i++) {
 		/*
 		 * Fill the map and set the buffer address in the NIC ring,
 		 * considering the offset between the netmap and NIC rings

From fb76e1df136084c009fc0aff07c2349b7bfd1c37 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 5 Feb 2021 09:36:05 +0100
Subject: [PATCH 1930/2207] linux/mlx5: fix typo in generated makefile

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 3b82c32aa..d61251ca0 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -100,7 +100,7 @@ $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz |
 $(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz && tar xf mlnx-en-$(2)-ubuntu18.04-x86_64/src/MLNX_EN_SRC-$(2).tgz && tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
 $(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@
-$(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$$($1)@cflags) $(EXTRA_CFLAGS)"
+$(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$$($(1)@cflags) $(EXTRA_CFLAGS)"
 $(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)

From fbd337b06c76abedd66d1ca9c035adcdf0ab1dfd Mon Sep 17 00:00:00 2001
From: Carl Smith 
Date: Thu, 11 Feb 2021 08:59:25 +1300
Subject: [PATCH 1931/2207] fix memory leak in NETMAP_REQ_PORT_INFO_GET

---
 sys/dev/netmap/netmap.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4301ba1bf..53e765e5d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2863,6 +2863,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		case NETMAP_REQ_PORT_INFO_GET: {
 			struct nmreq_port_info_get *req =
 				(struct nmreq_port_info_get *)(uintptr_t)hdr->nr_body;
+			int nmd_ref = 0;
 
 			NMG_LOCK();
 			do {
@@ -2904,6 +2905,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						error = EINVAL;
 						break;
 					}
+					nmd_ref = 1;
 				}
 
 				error = netmap_mem_get_info(nmd, &req->nr_memsize, &memflags,
@@ -2921,6 +2923,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 				req->nr_host_rx_rings = na->num_host_rx_rings;
 			} while (0);
 			netmap_unget_na(na, ifp);
+			if (nmd_ref)
+				netmap_mem_put(nmd);
 			NMG_UNLOCK();
 			break;
 		}

From 1dee2083ca098d05bb0dba871220c780f3cb547f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 15 Feb 2021 13:12:58 +0100
Subject: [PATCH 1932/2207] linux: include ethtool.h explicitly

---
 LINUX/bsd_glue.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index bfbce9ba9..fe6553444 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -54,6 +54,7 @@
 #include 	// msleep
 #include 		// skb_copy_to_linear_data_offset
 #include 
+#include 
 
 #include 	// virt_to_phys
 #include 

From 411aae847ac2c33bb531b311a4cffd3927f9e5ac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 15 Feb 2021 15:43:09 +0100
Subject: [PATCH 1933/2207] linux: patches for 5.11 vanilla kernel

---
 ...99 => vanilla--virtio_net.c--41100--50b00} |  0
 .../vanilla--virtio_net.c--50b00--99999       | 98 +++++++++++++++++++
 2 files changed, 98 insertions(+)
 rename LINUX/final-patches/{vanilla--virtio_net.c--41100--99999 => vanilla--virtio_net.c--41100--50b00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--50b00--99999

diff --git a/LINUX/final-patches/vanilla--virtio_net.c--41100--99999 b/LINUX/final-patches/vanilla--virtio_net.c--41100--50b00
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--41100--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--41100--50b00
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--50b00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--50b00--99999
new file mode 100644
index 000000000..9234ec436
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--50b00--99999
@@ -0,0 +1,98 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 508408fbe78f..ebcb50ab46e1 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -236,6 +236,10 @@ struct virtnet_info {
+ 	struct failover *failover;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_mrg_rxbuf hdr;
+ 	/*
+@@ -347,6 +351,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -1451,6 +1460,18 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int received;
+ 	unsigned int xdp_xmit = 0;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -1478,6 +1499,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	for (i = 0; i < vi->max_queue_pairs; i++) {
+ 		if (i < vi->curr_queue_pairs)
+@@ -3134,6 +3164,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 
+ 	virtnet_set_queues(vi, vi->curr_queue_pairs);
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	netif_carrier_off(dev);
+@@ -3187,7 +3221,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -3256,6 +3297,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From f14770c7f84985fccd7a3f28b5ccf167f38ac587 Mon Sep 17 00:00:00 2001
From: Dries De Winter 
Date: Mon, 22 Feb 2021 13:01:52 +0100
Subject: [PATCH 1934/2207] mlx5: call mlx5e_netmap_configure_rx_ring() *after*
 resetting wq

The problem was that mlx5e_modify_rq_state() reset the work queue which messed up synchronization between the mlx5 work queue and netmap ring if it was done after mlx5e_netmap_configure_rx_ring() was already called.
---
 LINUX/final-patches/mellanox--mlx5--5.0 | 28 ++++++++++++-------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/LINUX/final-patches/mellanox--mlx5--5.0 b/LINUX/final-patches/mellanox--mlx5--5.0
index c251c95c3..a4a510e01 100644
--- a/LINUX/final-patches/mellanox--mlx5--5.0
+++ b/LINUX/final-patches/mellanox--mlx5--5.0
@@ -123,7 +123,7 @@ index a34b25a..8ac923a 100644
  
  	netdev_err(sq->channel->netdev,
 diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
-index 06a1fb0..1c17838 100644
+index 06a1fb0..a1ed0d6 100644
 --- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 +++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 @@ -69,6 +69,16 @@
@@ -153,18 +153,7 @@ index 06a1fb0..1c17838 100644
  	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
  		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
  		MLX5_CAP_ETH(mdev, reg_umr_sq);
-@@ -777,6 +790,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
- 		rq->dim_obj.dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_free:
-@@ -1000,6 +1017,12 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+@@ -1000,6 +1013,12 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
  	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
  	struct mlx5e_channel *c = rq->channel;
  
@@ -177,7 +166,7 @@ index 06a1fb0..1c17838 100644
  	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
  
  	do {
-@@ -1047,6 +1070,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+@@ -1047,6 +1066,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
  
  		while (!mlx5_wq_cyc_is_empty(wq)) {
  			wqe_ix = mlx5_wq_cyc_get_tail(wq);
@@ -188,6 +177,17 @@ index 06a1fb0..1c17838 100644
  			rq->dealloc_wqe(rq, wqe_ix);
  			mlx5_wq_cyc_pop(wq);
  		}
+@@ -1152,6 +1175,10 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
+ #endif
+ 		__set_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
 @@ -1164,6 +1191,9 @@ err_free_rq:
  
  void mlx5e_activate_rq(struct mlx5e_rq *rq)

From ca032597214c169ff70ac89a849ed7b5a001ad0f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 25 Feb 2021 20:15:41 +0100
Subject: [PATCH 1935/2207] linux: remove local-ns restriction on vale ports

---
 LINUX/netmap_linux.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index fb624a3fb..b1619a241 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2368,7 +2368,6 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 	}
 #ifdef CONFIG_NET_NS
 	dev_net_set(ifp, current->nsproxy->net_ns);
-	ifp->features |= NETIF_F_NETNS_LOCAL; /* just for safety */
 #endif
 	ifp->dev.driver = &linux_dummy_drv;
 	error = register_netdev(ifp);

From 7fb399cbba3a0d4ab54d1118044e3e94363804e3 Mon Sep 17 00:00:00 2001
From: James Darnley 
Date: Tue, 23 Feb 2021 18:09:21 +0100
Subject: [PATCH 1936/2207] mlx5: copy fix for RX packet loss from f14770c7
 into 5.1

Full commit hash f14770c7f84985fccd7a3f28b5ccf167f38ac587
---
 LINUX/final-patches/mellanox--mlx5--5.1 | 28 ++++++++++++-------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/LINUX/final-patches/mellanox--mlx5--5.1 b/LINUX/final-patches/mellanox--mlx5--5.1
index e72afd966..76fb1927d 100644
--- a/LINUX/final-patches/mellanox--mlx5--5.1
+++ b/LINUX/final-patches/mellanox--mlx5--5.1
@@ -137,7 +137,7 @@ index 62a38bc..d45ba17 100644
  
  	netdev_err(sq->channel->netdev,
 diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
-index d40b62e..54672e7 100644
+index d40b62e..b5767c5 100644
 --- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 +++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 @@ -78,8 +78,21 @@
@@ -162,18 +162,7 @@ index d40b62e..54672e7 100644
  	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
  		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
  		MLX5_CAP_ETH(mdev, reg_umr_sq);
-@@ -840,6 +853,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
- 		rq->dim_obj.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_free:
-@@ -1061,6 +1078,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+@@ -1061,6 +1074,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
  	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
  	struct mlx5e_channel *c = rq->channel;
  
@@ -186,7 +175,7 @@ index d40b62e..54672e7 100644
  	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
  
  	do {
-@@ -1125,6 +1148,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+@@ -1125,6 +1144,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
  
  		while (!mlx5_wq_cyc_is_empty(wq)) {
  			wqe_ix = mlx5_wq_cyc_get_tail(wq);
@@ -197,6 +186,17 @@ index d40b62e..54672e7 100644
  			rq->dealloc_wqe(rq, wqe_ix);
  			mlx5_wq_cyc_pop(wq);
  		}
+@@ -1233,6 +1256,10 @@ int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ 	if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_SKB_XMIT_MORE))
+ 		__set_bit(MLX5E_RQ_STATE_SKB_XMIT_MORE, &c->rq.state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
 @@ -1245,6 +1272,9 @@ err_free_rq:
  
  void mlx5e_activate_rq(struct mlx5e_rq *rq)

From 5c935a628cec38d71e962de77eb7c06dc80fccb3 Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Mon, 15 Feb 2021 23:10:46 +0000
Subject: [PATCH 1937/2207] mlx5: Update to mlx5 v5.2

Includes fix for RX packet loss from commit f14770c7f84985fccd7a3f28b5ccf167f38ac587
---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/mellanox--mlx5--5.2 | 410 ++++++++++++++++++++++++
 2 files changed, 411 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--5.2

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index d61251ca0..10c676f54 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -107,7 +107,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,5.1-1.0.4.0))
+$(eval $(call default,mlx5,5.2-1.0.4.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 mlx5@cflags	= -Wframe-larger-than=2000
diff --git a/LINUX/final-patches/mellanox--mlx5--5.2 b/LINUX/final-patches/mellanox--mlx5--5.2
new file mode 100644
index 000000000..65f023a71
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--5.2
@@ -0,0 +1,410 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 1788bba..d91fe51 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -6,12 +6,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
+@@ -20,12 +20,12 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		mst_dump.o en_diag.o sriov_sysfs.o crdump.o diag/diag_cnt.o \
+ 		eswitch_devlink_compat.o params.o fw_exp.o fw_reset.o
+ 
+-mlx5_core-y += compat.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y += compat.o
+ 
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o \
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+ 		en/reporter_tx.o en/reporter_rx.o en/params.o en/xsk/umem.o \
+@@ -34,62 +34,62 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += lag_mp.o lib/geneve.o lib/port_tun.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += lag_mp.o lib/geneve.o lib/port_tun.o \
+ 					en_rep.o en/rep/bond.o en/mod_hdr.o
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					en/mapping.o lib/fs_chains.o en/tc_tun.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
+ 					en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
+ 					en/tc_sample.o esw/indir_table.o en/tc_tun_common.o
+-mlx5_core-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ 				      ecpf.o rdma.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
+ 				      esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
+ 				      esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o \
+ 				      esw/vporttbl.o
+ 
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
+-mlx5_core-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
+ 	   			 fpga/tls.o fpga/trans.o fpga/xfer.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o en_accel/ipsec_fs.o esw/ipsec.o en/aso.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ 				   en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
+ 				   en_accel/ktls_tx.o en_accel/ktls_rx.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o \
+ 					steering/dr_ste.o steering/dr_send.o \
+@@ -100,4 +100,4 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # Mdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o  meddev/mdev_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o  meddev/mdev_driver.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index a6dceb6..a3cb81d 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -14,6 +14,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index f2d56be..6738e06 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -82,8 +82,21 @@
+ #include "en/ptp.h"
+ #include "compat.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -1038,6 +1051,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ {
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(rq->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1102,6 +1121,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1222,6 +1245,10 @@ int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ 	if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_SKB_XMIT_MORE))
+ 		__set_bit(MLX5E_RQ_STATE_SKB_XMIT_MORE, &c->rq.state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
+@@ -1234,6 +1261,9 @@ err_free_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->netdev)) || NA(rq->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	mlx5e_trigger_irq(rq->icosq);
+ }
+@@ -1509,6 +1539,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1697,6 +1732,9 @@ void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1717,6 +1755,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3805,6 +3849,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -3838,6 +3887,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++       netmap_disable_all_rings(netdev);
++#endif
++
+ 	netif_carrier_off(priv->netdev);
+ 	mlx5e_destroy_debugfs(priv);
+ #if defined(CONFIG_MLX5_EN_SPECIAL_SQ) && (defined(HAVE_NDO_SET_TX_MAXRATE) || defined(HAVE_NDO_SET_TX_MAXRATE_EXTENDED))
+@@ -7010,6 +7063,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ {
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++       netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_netdev_cleanup(netdev, priv);
+ 	free_netdev(netdev);
+ }
+@@ -7123,6 +7180,10 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
+ 
+ 	mlx5e_dcbnl_init_app(priv);
+ 
++#ifdef DEV_NETMAP
++       mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	if (MLX5_ESWITCH_MANAGER(mdev))
+ 		mlx5e_rep_register_vport_reps(mdev, priv);
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index 7e88cbf..ad7257f 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -81,6 +81,14 @@ const struct mlx5e_rx_handlers mlx5e_rx_handlers_nic = {
+ 	.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -209,7 +217,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -1911,6 +1919,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 84a9d6f..e4ad5be 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -42,8 +42,16 @@
+ #include "en_accel/en_accel.h"
+ #include "lib/clock.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+-				       u32 cqcc, void *data)
++                                       u32 cqcc, void *data)
+ {
+ 	u32 ci = mlx5_cqwq_ctr2ix(wq, cqcc);
+ 
+@@ -1026,6 +1034,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->netdev, sq->ch_ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -1148,23 +1161,29 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 
+ 		sqcc += wi->num_wqebbs;
+ 
+-		if (likely(wi->skb)) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			dev_kfree_skb_any(wi->skb);
++                if (!nm_netmap_on(NA(sq->txq->dev))) {
++                       /* do not free skbs in netmap mode */
++			if (likely(wi->skb)) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				dev_kfree_skb_any(wi->skb);
+ 
+-			npkts++;
+-			nbytes += wi->num_bytes;
+-			continue;
+-		}
++				npkts++;
++				nbytes += wi->num_bytes;
++				continue;
++			}
+ 
+-		if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
+-			continue;
++			if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
++				continue;
+ 
+-		if (wi->num_fifo_pkts) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
++			if (wi->num_fifo_pkts) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
+ 
+-			npkts += wi->num_fifo_pkts;
++				npkts += wi->num_fifo_pkts;
++				nbytes += wi->num_bytes;
++			}
++                } else {
++			npkts++;
+ 			nbytes += wi->num_bytes;
+ 		}
+ 	}

From e0c3caae55c9ed2b64558b9528a50c11ae9e2504 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 18 Mar 2021 12:38:35 +0100
Subject: [PATCH 1938/2207] libnetmap: properly initialize cur_{t,r}x_ring

Before this patch, the cur_* fields used by nmport_inject() always
pointed to ring zero, even if only a single ring, different from
zero, had been opened.
---
 libnetmap/nmport.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 3e0c2a632..838ab0ab3 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -714,7 +714,7 @@ nmport_mmap(struct nmport_d *d)
 	num_tx = d->reg.nr_tx_rings + d->nifp->ni_host_tx_rings;
 	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++)
 		;
-	d->first_tx_ring = i;
+	d->cur_tx_ring = d->first_tx_ring = i;
 	for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++)
 		;
 	d->last_tx_ring = i - 1;
@@ -722,7 +722,7 @@ nmport_mmap(struct nmport_d *d)
 	num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings;
 	for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++)
 		;
-	d->first_rx_ring = i;
+	d->cur_rx_ring = d->first_rx_ring = i;
 	for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++)
 		;
 	d->last_rx_ring = i - 1;

From 9e6e00ee226959c0e88f75171cb4794208128a66 Mon Sep 17 00:00:00 2001
From: Firas Ashkar 
Date: Tue, 16 Feb 2021 15:41:36 -0500
Subject: [PATCH 1939/2207] stmmac: add stmmac port

1. add stmmac netmap support (linux version), and

2. fix compiler warning when cross building the driver with:
arm-buildroot-linux-gnueabihf-gcc (Buildroot 2019.02.2-g0b3ebc6ca5-dirty) 8.3.0
---
 LINUX/configure                | 124 ++++-----
 LINUX/default-config.mak.in_   |   3 +
 LINUX/if_stmmac_netmap_linux.h | 467 +++++++++++++++++++++++++++++++++
 apps/pkt-gen/pkt-gen.c         |   2 +-
 libnetmap/nmctx.c              |   1 +
 libnetmap/nmport.c             |   3 +-
 sys/dev/netmap/netmap_mem2.c   |   6 +-
 7 files changed, 539 insertions(+), 67 deletions(-)
 create mode 100644 LINUX/if_stmmac_netmap_linux.h

diff --git a/LINUX/configure b/LINUX/configure
index 1fdb96b76..2facbaa3b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -112,7 +112,7 @@ subsys enable null
 subsys enable ptnetmap
 
 # available drivers
-driver_avail="r8169.c virtio_net.c forcedeth.c veth.c \
+driver_avail="stmmac r8169.c virtio_net.c forcedeth.c veth.c \
 	e1000 e1000e igb ixgbe ixgbevf i40e vmxnet3 mlx5"
 # enabled drivers (bitfield)
 driver=
@@ -883,7 +883,7 @@ EOF
 		message " NOTE  " <
-  
+
   		u16 dummy(struct net_device_ops *ndo)
   		{
   		        return ndo->ndo_select_queue($params);
@@ -1823,66 +1823,66 @@ EOF
   #####################################################
   # checks related to drivers                         #
   #####################################################
-  
+
   # e1000e
   if drv enabled e1000e; then
-  
+
   add_file_exists_check e1000e/e1000.h true "drv_source_error e1000e"
-  
+
   add_test 'have E1000E_HWADDR' <hw.hw_addr + ring->tail;
   	}
 EOF
-  
+
   add_test 'have E1000E_DOWN2' <' $TMPDIR/e1000e/netdev.c \
   	&& have E1000E_EXT_RXDESC" tx_ring[0];
@@ -1964,7 +1964,7 @@ EOF
   # array of rings or array of poiners to rings?
   add_test 'define IXGBEVF_PTR_ARRAY' <tx_ring[0];
@@ -1987,9 +1987,9 @@ EOF
     if edrv enabled virtio_net.c; then
         VNETDIR="virtio_net.c/"
     fi
-  
+
     add_file_exists_check ${VNETDIR}virtio_net.c true "drv_source_error virtio_net.c"
-  
+
     add_test 'define VIRTIO_NET_HDR_FROM_SKB_5ARGS' <
 
@@ -2148,45 +2148,45 @@ EOF
 
     add_test 'define VIRTIO_CB_DELAYED' <
-  
+
   	bool
   	dummy(struct virtqueue *vq) {
   		return virtqueue_enable_cb_delayed(vq);
   	}
 EOF
-  
+
     add_test 'define VIRTIO_GET_VRSIZE' <
-  
+
   	unsigned int
   	dummy(struct virtqueue *vq) {
   		return virtqueue_get_vring_size(vq);
   	}
 EOF
-  
+
     add_test 'define VIRTIO_FREE_PAGES' <
-  
+
   	void
   	dummy(struct virtqueue *vq) {
   		(void)virtqueue_kick(vq);
   	}
 EOF
-  
+
     for s in "" _gfp; do
   	f="virtqueue_add_buf$s"
   	add_test "define VIRTIO_ADD_BUF $f" <
-  
+
   		int
   		dummy(struct virtqueue *vq, struct scatterlist sg[],
   			unsigned int out_num, unsigned int in_num,
@@ -2196,43 +2196,43 @@ EOF
   		}
 EOF
   done
-  
+
     add_test 'define VIRTIO_MULTI_QUEUE' <rq[0].vq;
   	}
 EOF
-  
+
     add_test 'define VIRTIO_RQ_NUM' <rq[0].num;
   	}
 EOF
-  
+
     add_test 'define VIRTIO_SG' <rx_sg;
   	}
 EOF
-  
+
      add_test 'define VIRTIO_NOTIFY' <
-  
+
   	void
   	dummy(struct virtqueue *_vq) {
   		(void)virtqueue_notify(_vq);
   	}
 EOF
-  
+
      add_test 'have GET_LINK_KSETTINGS' <
 
@@ -2244,17 +2244,17 @@ EOF
 EOF
 
   fi # virtio-net
-  
+
   if drv enabled i40e; then
     add_test 'define I40E_PTR_ARRAY' <tx_rings[0];
   	}
 EOF
-   
+
    add_test 'define I40E_PTR_STATE' <
@@ -2286,17 +2286,17 @@ EOF
        }
 EOF
   fi # igb
-  
+
   # END_TESTS
-  
+
   # now we actually create the file
-  
+
   rm -f $configh
   cat > $configh <> config.log <> $configh <
+#include 
+#include 
+
+static int stmmac_open(struct net_device *dev);
+static int stmmac_release(struct net_device *dev);
+
+#ifdef MODULENAME
+#undef MODULENAME
+#define MODULENAME "stmmac" NETMAP_LINUX_DRIVER_SUFFIX
+#endif
+
+/*
+ * Register/unregister, mostly the reinit task
+ */
+static int stmmac_netmap_reg(struct netmap_adapter *na, int onoff)
+{
+	struct ifnet *ifp = na->ifp;
+	int error = 0;
+
+	stmmac_release(ifp);
+
+	/* enable or disable flags and callbacks in na and ifp */
+	if (onoff) {
+		nm_set_native_flags(na);
+
+		if (stmmac_open(ifp) < 0) {
+			error = ENOMEM;
+			goto fail;
+		}
+	} else {
+	fail:
+		nm_clear_native_flags(na);
+		error = stmmac_open(ifp) ? EINVAL : 0;
+	}
+
+	return (error);
+}
+
+/*
+ * Reconcile kernel and user view of the transmit ring.
+ */
+static int stmmac_netmap_txsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int nm_i; /* index into the netmap ring */
+	u_int nic_i; /* index into the NIC ring */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+
+	/* device-specific */
+	struct stmmac_priv *stmac_priv = netdev_priv(ifp);
+
+	rmb();
+
+	/*
+	* First part: process new packets to send.
+	*/
+	if (!netif_carrier_ok(ifp)) {
+		goto out;
+	}
+
+	nm_i = kring->nr_hwcur;
+	/* we have new packets to send */
+	if (nm_i != head) {
+		nic_i = netmap_idx_k2n(kring, nm_i);
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			int len = slot->len;
+			uint64_t paddr;
+			void *addr = PNMB(na, slot, &paddr);
+			uint32_t etdes1 =
+				(slot->len & ETDES1_BUFFER1_SIZE_MASK);
+			uint32_t etdes0 = ETDES0_LAST_SEGMENT | ETDES0_OWN |
+					  ETDES0_FIRST_SEGMENT;
+
+			/* device-specific */
+			struct dma_desc *pdam_desc = NULL;
+			if (stmac_priv->extend_desc)
+				pdam_desc =
+					(struct dma_desc *)(stmac_priv->dma_etx +
+							    nic_i);
+			else
+				pdam_desc = stmac_priv->dma_tx + nic_i;
+
+			NM_CHECK_ADDR_LEN(na, addr, len);
+
+			if (nic_i == lim) /* mark end of ring */
+				etdes0 |= ETDES0_END_RING;
+
+			if (slot->flags & NS_BUF_CHANGED) {
+				/* buffer has changed, reload map */
+				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
+				pdam_desc->des2 = paddr;
+			}
+
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+			pdam_desc->des0 = etdes0;
+			pdam_desc->des1 = etdes1;
+
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+		}
+
+		kring->nr_hwcur = head;
+
+		stmac_priv->cur_tx = nic_i;
+		wmb(); /* synchronize writes to the NIC ring */
+	}
+
+	/*
+	* Second part: reclaim buffers for completed transmissions.
+	*/
+	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
+		for (n = 0, nic_i = stmac_priv->dirty_tx;
+		     nic_i != stmac_priv->cur_tx; n++) {
+			struct dma_desc *pdam_desc = NULL;
+			if (stmac_priv->extend_desc)
+				pdam_desc =
+					(struct dma_desc *)(stmac_priv->dma_etx +
+							    nic_i);
+			else
+				pdam_desc = stmac_priv->dma_tx + nic_i;
+
+			/* check if DMA owned */
+			if (pdam_desc->des0 & ETDES0_OWN)
+				break;
+
+			if (++nic_i == na->num_tx_desc)
+				nic_i = 0;
+		}
+
+		if (n > 0) {
+			stmac_priv->dirty_tx = nic_i;
+			kring->nr_hwtail =
+				nm_prev(netmap_idx_n2k(kring, nic_i), lim);
+		}
+	}
+out:
+	return 0;
+}
+
+/*
+ * Reconcile kernel and user view of the receive ring.
+ * static int stmmac_rx(struct stmmac_priv *priv, int limit)
+ */
+static int stmmac_netmap_rxsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct stmmac_priv *stmac_priv = netdev_priv(ifp);
+	struct netmap_ring *ring = kring->ring;
+	unsigned int nm_i; /* index into the netmap ring */
+	unsigned int entry; /* index into the NIC ring */
+	unsigned int n;
+	unsigned int const lim = kring->nkr_num_slots - 1;
+	unsigned int const head = kring->rhead;
+
+	int force_update =
+		(flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+
+	if (!netif_carrier_ok(ifp))
+		return 0;
+
+	if (head > lim)
+		return netmap_ring_reinit(kring);
+
+	rmb();
+
+	/*
+	* First part: import newly received packets.
+	*/
+	if (netmap_no_pendintr || force_update) {
+		uint32_t stop_i = nm_prev(kring->nr_hwcur, lim);
+		int coe = stmac_priv->hw->rx_csum;
+		uint32_t frame_len = 0x0;
+
+		entry = stmac_priv->cur_rx; /* next pkt to check */
+		nm_i = netmap_idx_n2k(kring, entry);
+
+		while (nm_i != stop_i) {
+			int status;
+			struct dma_desc *pdam_desc;
+
+			if (stmac_priv->extend_desc)
+				pdam_desc =
+					(struct dma_desc *)(stmac_priv->dma_erx +
+							    entry);
+			else
+				pdam_desc = stmac_priv->dma_rx + entry;
+
+			/* read the status of the incoming frame */
+			status = stmac_priv->hw->desc->rx_status(
+				&stmac_priv->dev->stats, &stmac_priv->xstats,
+				pdam_desc);
+
+			/* check if managed by the DMA otherwise go ahead */
+			if (unlikely(status & dma_own))
+				break;
+
+			if ((stmac_priv->extend_desc) &&
+			    (stmac_priv->hw->desc->rx_extended_status))
+				stmac_priv->hw->desc->rx_extended_status(
+					&stmac_priv->dev->stats,
+					&stmac_priv->xstats,
+					stmac_priv->dma_erx + entry);
+
+			frame_len = stmac_priv->hw->desc->get_rx_frame_len(
+				pdam_desc, coe);
+
+			/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+			 * Type frames (LLC/LLC-SNAP)
+			 */
+			if (unlikely(status != llc_snap))
+				frame_len -= ETH_FCS_LEN;
+
+			ring->slot[nm_i].len = frame_len;
+			ring->slot[nm_i].flags = 0;
+
+			nm_i = nm_next(nm_i, lim);
+			entry = nm_next(entry, lim);
+		}
+
+		stmac_priv->cur_rx = entry;
+
+		kring->nr_hwtail = nm_i;
+		kring->nr_kflags &= ~NKR_PENDINTR;
+	}
+
+	/*
+	* Second part: skip past packets that userspace has released.
+	*/
+	nm_i = kring->nr_hwcur;
+	if (nm_i != head) {
+		entry = netmap_idx_k2n(kring, nm_i);
+		for (n = 0; nm_i != head; n++) {
+			uint32_t erdes1 = 0x0;
+
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t paddr;
+			void *addr = PNMB(na, slot, &paddr);
+
+			struct dma_desc *pdam_desc;
+
+			if (stmac_priv->extend_desc)
+				pdam_desc =
+					(struct dma_desc *)(stmac_priv->dma_erx +
+							    entry);
+			else
+				pdam_desc = stmac_priv->dma_rx + entry;
+
+			erdes1 = NETMAP_BUF_SIZE(na);
+
+			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
+				goto ring_reset;
+
+			if (entry == lim) /* mark end of ring */
+				erdes1 |= ERDES1_END_RING;
+
+			if (slot->flags & NS_BUF_CHANGED) {
+				/* buffer has changed, reload map */
+				// netmap_reload_map(pdev, DMA_TO_DEVICE, old_paddr, addr);
+				pdam_desc->des2 = paddr;
+				slot->flags &= ~NS_BUF_CHANGED;
+			}
+
+			pdam_desc->des1 |= erdes1;
+
+			nm_i = nm_next(nm_i, lim);
+			entry = nm_next(entry, lim);
+		}
+
+		kring->nr_hwcur = head;
+		wmb();
+	}
+
+	return 0;
+
+ring_reset:
+	return netmap_ring_reinit(kring);
+}
+
+/*
+ * Make the Tx desc rings point to the netmap buffers.
+ * static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
+ */
+static int stmmac_netmap_tx_init(struct stmmac_priv *stmac_priv)
+{
+	struct netmap_adapter *na = NA(stmac_priv->dev);
+	struct netmap_slot *slot = NULL;
+	int i, l;
+	uint64_t paddr = 0x0;
+
+	slot = netmap_reset(na, NR_TX, 0, 0);
+	if (!slot)
+		return 0;
+
+	/* l points in the netmap ring, i points in the NIC ring */
+	for (i = 0; i < na->num_tx_desc; i++) {
+		uint32_t etdes0 = 0x0;
+		struct dma_desc *pdam_desc = NULL;
+
+		stmac_priv->tx_skbuff[i] = NULL;
+		if (stmac_priv->extend_desc)
+			pdam_desc = &((stmac_priv->dma_etx + i)->basic);
+
+		else
+			pdam_desc = stmac_priv->dma_tx + i;
+
+		if (IS_ERR(pdam_desc))
+			return 0;
+
+		l = netmap_idx_n2k(na->tx_rings[0], i);
+		PNMB(na, slot + l, &paddr);
+
+		/* ETDES2 */
+		pdam_desc->des2 = paddr;
+
+		/* ETDES0 */
+		if (i == na->num_tx_desc - 1)
+			etdes0 |= ETDES0_END_RING;
+
+		pdam_desc->des0 = etdes0;
+	}
+
+	return 1;
+}
+
+/*
+ * Make the Rx desc rings point to the netmap buffers.
+ * static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
+ */
+static int stmmac_netmap_rx_init(struct stmmac_priv *stmac_priv)
+{
+	struct netmap_adapter *na = NA(stmac_priv->dev);
+	struct netmap_slot *slot = NULL;
+	int i, lim, l;
+	uint64_t paddr = 0x0;
+
+	slot = netmap_reset(na, NR_RX, 0, 0);
+	if (!slot)
+		return 0;
+
+	lim = na->num_rx_desc - nm_kr_rxspace(na->rx_rings[0]);
+	for (i = 0; i < na->num_rx_desc; i++) {
+		void *addr;
+		uint32_t erdes1 = 0x0;
+		struct dma_desc *pdam_desc = NULL;
+
+		stmac_priv->rx_skbuff[i] = NULL;
+
+		if (stmac_priv->extend_desc)
+			pdam_desc = &((stmac_priv->dma_erx + i)->basic);
+		else
+			pdam_desc = stmac_priv->dma_rx + i;
+
+		if (IS_ERR(pdam_desc))
+			return 0;
+
+		l = netmap_idx_n2k(na->rx_rings[0], i);
+		addr = PNMB(na, slot + l, &paddr);
+
+		/* NOTE:is not set: ERDES3 and erdes1 |= ((BUF_SIZE_8KiB - 1) << ERDES1_BUFFER2_SIZE_SHIFT) & ERDES1_BUFFER2_SIZE_MASK; */
+
+		/* ERDES2 */
+		pdam_desc->des2 = paddr;
+
+		/* ERDES1 */
+		erdes1 |=
+			((NETMAP_BUF_SIZE(na) - 1) & ERDES1_BUFFER1_SIZE_MASK);
+
+		/* operate in ring mode only, and set last ERDES accordingly*/
+		if (i == na->num_rx_desc - 1) {
+			erdes1 |= ERDES1_END_RING;
+		}
+
+		erdes1 |= ERDES1_DISABLE_IC;
+
+		pdam_desc->des1 |= erdes1;
+
+		/* ERDES0 */
+		if (i < lim)
+			pdam_desc->des0 |= RDES0_OWN;
+	}
+
+	return 1;
+}
+
+static int stmmac_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
+{
+	kring->hwbuf_len = BUF_SIZE_8KiB;
+	kring->buf_align = 0; /* no alignment */
+
+	return 0;
+}
+
+static int stmmac_netmap_config(struct netmap_adapter *na,
+				struct nm_config_info *info)
+{
+	struct stmmac_priv *stmac_priv = netdev_priv(na->ifp);
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret)
+		return ret;
+
+	info->rx_buf_maxsize = stmac_priv->dma_buf_sz;
+
+	return 0;
+}
+
+static void stmmac_netmap_attach(struct stmmac_priv *stmac_priv)
+{
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp = stmac_priv->dev; /* struct net_device *dev; */
+	na.pdev = &stmac_priv->device; /* struct device *device; */
+	na.num_tx_desc = DMA_TX_SIZE;
+	na.num_rx_desc = DMA_RX_SIZE;
+	na.rx_buf_maxsize = BUF_SIZE_8KiB;
+	na.num_tx_rings = na.num_rx_rings = 1;
+	na.nm_txsync = stmmac_netmap_txsync;
+	na.nm_rxsync = stmmac_netmap_rxsync;
+	na.nm_register = stmmac_netmap_reg;
+	na.nm_config = stmmac_netmap_config;
+	na.nm_bufcfg = stmmac_netmap_bufcfg;
+	netmap_attach(&na);
+}
+
+/* end of file */
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 808f0525b..559036faa 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -2511,7 +2511,7 @@ start_threads(struct glob_arg *g) {
 	 * using a single descriptor.
 	 */
 	for (i = 0; i < g->nthreads; i++) {
-		uint64_t seed = time(0) | (time(0) << 32);
+		uint64_t seed = (uint64_t)time(0) | ((uint64_t)time(0) << 32);
 		t = &targs[i];
 
 		bzero(t, sizeof(*t));
diff --git a/libnetmap/nmctx.c b/libnetmap/nmctx.c
index 5bb52df52..489988f33 100644
--- a/libnetmap/nmctx.c
+++ b/libnetmap/nmctx.c
@@ -45,6 +45,7 @@
 static void
 nmctx_default_error(struct nmctx *ctx, const char *errmsg)
 {
+	(void)ctx;
 	fprintf(stderr, "%s\n", errmsg);
 }
 
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 3e0c2a632..c9edca12a 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -176,6 +176,7 @@ struct nmport_extmem_from_file_cleanup_d {
 void nmport_extmem_from_file_cleanup(struct nmport_cleanup_d *c,
 		struct nmport_d *d)
 {
+	(void)d;
 	struct nmport_extmem_from_file_cleanup_d *cc =
 		(struct nmport_extmem_from_file_cleanup_d *)c;
 
@@ -657,7 +658,7 @@ nmport_mmap(struct nmport_d *d)
 	struct nmctx *ctx = d->ctx;
 	struct nmem_d *m = NULL;
 	u_int num_tx, num_rx;
-	int i;
+	unsigned int i;
 
 	if (d->mmap_done) {
 		errno = EINVAL;
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 36597222a..e07b21019 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -330,7 +330,7 @@ netmap_mem_get_id(struct netmap_mem_d *nmd)
 
 /* circular list of all existing allocators */
 static struct netmap_mem_d *netmap_last_mem_d = &nm_mem;
-NM_MTX_T nm_mem_list_lock;
+static NM_MTX_T nm_mem_list_lock;
 
 struct netmap_mem_d *
 __netmap_mem_get(struct netmap_mem_d *nmd, const char *func, int line)
@@ -1534,10 +1534,10 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na)
 	struct netmap_lut *lut;
 	if (na == NULL || na->pdev == NULL)
 		return 0;
-	
+
 	lut = &na->na_lut;
 
-	
+
 
 #if defined(__FreeBSD__)
 	/* On FreeBSD mapping and unmapping is performed by the txsync

From fb21c2bb4dd0a269ab8e6ec3b7ed739bee483579 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Fri, 19 Mar 2021 18:10:05 +0100
Subject: [PATCH 1940/2207] bridge: ensure timely call to NIOCTXSINC in
 busy-wait mode

Avoid transmission stall (if no more traffic comes afterwards).

Fixes #758
---
 apps/bridge/bridge.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 77d235bf6..b5b0663ee 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -323,13 +323,11 @@ main(int argc, char **argv)
 		n1 = rx_slots_avail(pb);
 #if defined(_WIN32) || defined(BUSYWAIT)
 		if (n0) {
-			ioctl(pollfd[1].fd, NIOCTXSYNC, NULL);
 			pollfd[1].revents = POLLOUT;
 		} else {
 			ioctl(pollfd[0].fd, NIOCRXSYNC, NULL);
 		}
 		if (n1) {
-			ioctl(pollfd[0].fd, NIOCTXSYNC, NULL);
 			pollfd[0].revents = POLLOUT;
 		} else {
 			ioctl(pollfd[1].fd, NIOCRXSYNC, NULL);
@@ -375,11 +373,19 @@ main(int argc, char **argv)
 			D("error on fd1, rx [%d,%d,%d)",
 			    rx->head, rx->cur, rx->tail);
 		}
-		if (pollfd[0].revents & POLLOUT)
+		if (pollfd[0].revents & POLLOUT) {
 			ports_move(pb, pa, burst, msg_b2a);
+#if defined(_WIN32) || defined(BUSYWAIT)
+			ioctl(pollfd[0].fd, NIOCTXSYNC, NULL);
+#endif
+		}
 
-		if (pollfd[1].revents & POLLOUT)
+		if (pollfd[1].revents & POLLOUT) {
 			ports_move(pa, pb, burst, msg_a2b);
+#if defined(_WIN32) || defined(BUSYWAIT)
+			ioctl(pollfd[1].fd, NIOCTXSYNC, NULL);
+#endif
+		}
 
 		/*
 		 * We don't need ioctl(NIOCTXSYNC) on the two file descriptors.

From fcf5cdf5d6490f68056e308407d3a793211c529f Mon Sep 17 00:00:00 2001
From: Vincenzo Maffione 
Date: Sat, 20 Mar 2021 17:15:50 +0000
Subject: [PATCH 1941/2207] netmap: freebsd: fix issues in
 nm_os_extmem_create()

Commit imported from FreeBSD
---
 sys/dev/netmap/netmap_freebsd.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 50afb3214..a47cb508d 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -664,6 +664,7 @@ nm_os_vi_detach(struct ifnet *ifp)
 
 #ifdef WITH_EXTMEM
 #include 
+#include 
 #include 
 struct nm_os_extmem {
 	vm_object_t obj;
@@ -726,17 +727,18 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			&obj, &index, &prot, &wired);
 	if (rv != KERN_SUCCESS) {
 		nm_prerr("address %lx not found", p);
+		error = vm_mmap_to_errno(rv);
 		goto out_free;
 	}
+	vm_object_reference(obj);
+
 	/* check that we are given the whole vm_object ? */
 	vm_map_lookup_done(map, entry);
 
-	// XXX can we really use obj after releasing the map lock?
 	e->obj = obj;
-	vm_object_reference(obj);
-	/* wire the memory and add the vm_object to the kernel map,
-	 * to make sure that it is not fred even if the processes that
-	 * are mmap()ing it all exit
+	/* Wire the memory and add the vm_object to the kernel map,
+	 * to make sure that it is not freed even if all the processes
+	 * that are mmap()ing should munmap() it.
 	 */
 	e->kva = vm_map_min(kernel_map);
 	e->size = obj->size << PAGE_SHIFT;
@@ -745,12 +747,14 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			VM_PROT_READ | VM_PROT_WRITE, 0);
 	if (rv != KERN_SUCCESS) {
 		nm_prerr("vm_map_find(%zx) failed", (size_t)e->size);
+		error = vm_mmap_to_errno(rv);
 		goto out_rel;
 	}
 	rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,
 			VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
 	if (rv != KERN_SUCCESS) {
 		nm_prerr("vm_map_wire failed");
+		error = vm_mmap_to_errno(rv);
 		goto out_rem;
 	}
 
@@ -760,9 +764,9 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 
 out_rem:
 	vm_map_remove(kernel_map, e->kva, e->kva + e->size);
-	e->obj = NULL;
 out_rel:
 	vm_object_deallocate(e->obj);
+	e->obj = NULL;
 out_free:
 	nm_os_free(e);
 out:

From 8339c6d5838425f80c4e5e96e93c8f5297a864fa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 21 Mar 2021 16:25:23 +0100
Subject: [PATCH 1942/2207] linux: driver patches for stmmac vanilla driver

---
 .../vanilla--stmmac--40900--40a00             | 132 ++++++++++++++++++
 .../vanilla--stmmac--40a00--40c00             | 131 +++++++++++++++++
 2 files changed, 263 insertions(+)
 create mode 100644 LINUX/final-patches/vanilla--stmmac--40900--40a00
 create mode 100644 LINUX/final-patches/vanilla--stmmac--40a00--40c00

diff --git a/LINUX/final-patches/vanilla--stmmac--40900--40a00 b/LINUX/final-patches/vanilla--stmmac--40900--40a00
new file mode 100644
index 000000000..4be27cd03
--- /dev/null
+++ b/LINUX/final-patches/vanilla--stmmac--40900--40a00
@@ -0,0 +1,132 @@
+diff --git a/stmmac/stmmac_main.c b/stmmac/stmmac_main.c
+index caf069a465f2..a880c2c5c0e0 100644
+--- a/stmmac/stmmac_main.c
++++ b/stmmac/stmmac_main.c
+@@ -121,6 +121,9 @@ static void stmmac_exit_fs(struct net_device *dev);
+ 
+ #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
+ /**
+  * stmmac_verify_args - verify the driver parameters.
+  * Description: it checks the driver parameters and set a default in case of
+@@ -472,7 +475,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ 			/* PTP v1, UDP, any kind of event packet */
+ 			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ 			/* take time stamp for all event messages */
+-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
++			snap_type_sel = 0xFFFFFFFF & PTP_TCR_SNAPTYPSEL_1;
+ 
+ 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+@@ -504,7 +507,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+ 			ptp_v2 = PTP_TCR_TSVER2ENA;
+ 			/* take time stamp for all event messages */
+-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
++			snap_type_sel = 0xFFFFFFFF & PTP_TCR_SNAPTYPSEL_1;
+ 
+ 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+@@ -538,7 +541,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ 			ptp_v2 = PTP_TCR_TSVER2ENA;
+ 			/* take time stamp for all event messages */
+-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
++			snap_type_sel = 0xFFFFFFFF & PTP_TCR_SNAPTYPSEL_1;
+ 
+ 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+@@ -1038,6 +1041,23 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
+ 		/* RX INITIALIZATION */
+ 		pr_debug("\tSKB addresses:\nskb\t\tskb data\tdma data\n");
+ 	}
++
++#ifdef DEV_NETMAP
++	if (stmmac_netmap_rx_init(priv)) {
++		priv->cur_rx = 0;
++		priv->dirty_rx = 1;
++		buf_sz = bfsize;
++
++		if (stmmac_netmap_tx_init(priv)) {
++			priv->dirty_tx = 0;
++			priv->cur_tx = 0;
++			netdev_reset_queue(priv->dev);
++			return 0;
++		}
++	}
++
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < DMA_RX_SIZE; i++) {
+ 		struct dma_desc *p;
+ 		if (priv->extend_desc)
+@@ -1307,6 +1327,11 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 	unsigned int entry = priv->dirty_tx;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(priv->dev, 0))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	spin_lock(&priv->tx_lock);
+ 
+ 	priv->xstats.tx_clean++;
+@@ -1745,7 +1770,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+ 	}
+ 
+ 	if (priv->hw->pcs && priv->hw->mac->pcs_ctrl_ane)
+-		priv->hw->mac->pcs_ctrl_ane(priv->hw, 1, priv->hw->ps, 0);
++		priv->hw->mac->pcs_ctrl_ane((void __iomem *)priv->hw, 1, priv->hw->ps, 0);
+ 
+ 	/*  set TX ring length */
+ 	if (priv->hw->dma->set_tx_ring_len)
+@@ -2481,6 +2506,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
+ 	unsigned int count = 0;
+ 	int coe = priv->hw->rx_csum;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(priv->dev, 0, &count))
++		return count;
++#endif /* DEV_NETMAP */
++
+ 	if (netif_msg_rx_status(priv)) {
+ 		void *rx_head;
+ 
+@@ -3380,6 +3410,10 @@ int stmmac_dvr_probe(struct device *device,
+ 		}
+ 	}
+ 
++#ifdef DEV_NETMAP
++	stmmac_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ error_mdio_register:
+@@ -3424,6 +3458,11 @@ int stmmac_dvr_remove(struct device *dev)
+ 	    priv->hw->pcs != STMMAC_PCS_TBI &&
+ 	    priv->hw->pcs != STMMAC_PCS_RTBI)
+ 		stmmac_mdio_unregister(ndev);
++
++#ifdef DEV_NETMAP
++	netmap_detach(ndev);
++#endif /* DEV_NETMAP */
++
+ 	free_netdev(ndev);
+ 
+ 	return 0;
+@@ -3621,8 +3660,8 @@ static void __exit stmmac_exit(void)
+ #endif
+ }
+ 
+-module_init(stmmac_init)
+-module_exit(stmmac_exit)
++module_init(stmmac_init);
++module_exit(stmmac_exit);
+ 
+ MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");
+ MODULE_AUTHOR("Giuseppe Cavallaro ");
diff --git a/LINUX/final-patches/vanilla--stmmac--40a00--40c00 b/LINUX/final-patches/vanilla--stmmac--40a00--40c00
new file mode 100644
index 000000000..176cb2f86
--- /dev/null
+++ b/LINUX/final-patches/vanilla--stmmac--40a00--40c00
@@ -0,0 +1,131 @@
+diff --git a/stmmac/stmmac_main.c b/stmmac/stmmac_main.c
+index e3f6389e1b01..303d9f03a985 100644
+--- a/stmmac/stmmac_main.c
++++ b/stmmac/stmmac_main.c
+@@ -121,6 +121,9 @@ static void stmmac_exit_fs(struct net_device *dev);
+ 
+ #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
+ /**
+  * stmmac_verify_args - verify the driver parameters.
+  * Description: it checks the driver parameters and set a default in case of
+@@ -474,7 +477,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ 			/* PTP v1, UDP, any kind of event packet */
+ 			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ 			/* take time stamp for all event messages */
+-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
++			snap_type_sel = 0xFFFFFFFF & PTP_TCR_SNAPTYPSEL_1;
+ 
+ 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+@@ -506,7 +509,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+ 			ptp_v2 = PTP_TCR_TSVER2ENA;
+ 			/* take time stamp for all event messages */
+-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
++			snap_type_sel = 0xFFFFFFFF & PTP_TCR_SNAPTYPSEL_1;
+ 
+ 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+@@ -540,7 +543,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+ 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ 			ptp_v2 = PTP_TCR_TSVER2ENA;
+ 			/* take time stamp for all event messages */
+-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
++			snap_type_sel = 0xFFFFFFFF & PTP_TCR_SNAPTYPSEL_1;
+ 
+ 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+@@ -1040,6 +1043,22 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
+ 	netif_dbg(priv, probe, priv->dev,
+ 		  "SKB addresses:\nskb\t\tskb data\tdma data\n");
+ 
++#ifdef DEV_NETMAP
++	if (stmmac_netmap_rx_init(priv)) {
++		priv->cur_rx = 0;
++		priv->dirty_rx = 1;
++		buf_sz = bfsize;
++
++		if (stmmac_netmap_tx_init(priv)) {
++			priv->dirty_tx = 0;
++			priv->cur_tx = 0;
++			netdev_reset_queue(priv->dev);
++			return 0;
++		}
++	}
++
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < DMA_RX_SIZE; i++) {
+ 		struct dma_desc *p;
+ 		if (priv->extend_desc)
+@@ -1308,6 +1327,11 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 	unsigned int entry = priv->dirty_tx;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(priv->dev, 0))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	netif_tx_lock(priv->dev);
+ 
+ 	priv->xstats.tx_clean++;
+@@ -1739,7 +1763,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+ 	}
+ 
+ 	if (priv->hw->pcs && priv->hw->mac->pcs_ctrl_ane)
+-		priv->hw->mac->pcs_ctrl_ane(priv->hw, 1, priv->hw->ps, 0);
++		priv->hw->mac->pcs_ctrl_ane((void __iomem *)priv->hw, 1, priv->hw->ps, 0);
+ 
+ 	/*  set TX ring length */
+ 	if (priv->hw->dma->set_tx_ring_len)
+@@ -2471,6 +2495,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
+ 	unsigned int count = 0;
+ 	int coe = priv->hw->rx_csum;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(priv->dev, 0, &count))
++		return count;
++#endif /* DEV_NETMAP */
++
+ 	if (netif_msg_rx_status(priv)) {
+ 		void *rx_head;
+ 
+@@ -3381,6 +3410,10 @@ int stmmac_dvr_probe(struct device *device,
+ 		goto error_netdev_register;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	stmmac_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return ret;
+ 
+ error_netdev_register:
+@@ -3428,6 +3461,11 @@ int stmmac_dvr_remove(struct device *dev)
+ 	    priv->hw->pcs != STMMAC_PCS_TBI &&
+ 	    priv->hw->pcs != STMMAC_PCS_RTBI)
+ 		stmmac_mdio_unregister(ndev);
++
++#ifdef DEV_NETMAP
++	netmap_detach(ndev);
++#endif /* DEV_NETMAP */
++
+ 	free_netdev(ndev);
+ 
+ 	return 0;
+@@ -3625,8 +3663,8 @@ static void __exit stmmac_exit(void)
+ #endif
+ }
+ 
+-module_init(stmmac_init)
+-module_exit(stmmac_exit)
++module_init(stmmac_init);
++module_exit(stmmac_exit);
+ 
+ MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");
+ MODULE_AUTHOR("Giuseppe Cavallaro ");

From 84dda8fc01e4b4119b815c32879d7425ee5e427d Mon Sep 17 00:00:00 2001
From: jhk 
Date: Mon, 29 Mar 2021 14:37:24 +0200
Subject: [PATCH 1943/2207] LINUX: README.md: bullet point for Linux bridge and
 pkt-gen

---
 LINUX/README.md             | 5 +++++
 sys/dev/netmap/netmap_bdg.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/LINUX/README.md b/LINUX/README.md
index a4ca957b9..0c9e2c14f 100644
--- a/LINUX/README.md
+++ b/LINUX/README.md
@@ -262,6 +262,11 @@ On the receiver, you should see about 14.88 Mpps
   it does not make sense (in terms of performance) for pipes to support
   conversion betweeen netmap buffers and skbuffs.
 
+* pkt-gen traffic does not flow across a Linux bridge.
+  Check that source MAC is not 00:00:00:00:00:00 (pkt-gen default), nor
+  ff:ff:ff:ff:ff:ff. See:
+  https://elixir.bootlin.com/linux/latest/source/net/bridge/br_input.c#L281
+
 
 ## Additional information
 
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 65f20e7f7..085ecfc56 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1520,7 +1520,7 @@ netmap_bwrap_krings_create_common(struct netmap_adapter *na)
 	for_rx_tx(t) {
 		for (i = 0; i < netmap_all_rings(hwna, t); i++) {
 			NMR(hwna, t)[i]->users++;
-			/* this to prevent deleation of the rings through
+			/* this to prevent deletion of the rings through
 			 * our krings, instead of through the hwna ones */
 			NMR(na, t)[i]->nr_kflags |= NKR_NEEDRING;
 		}

From 35097be6513888261eb89a0ef5fb6549a4efd08d Mon Sep 17 00:00:00 2001
From: jhk 
Date: Mon, 29 Mar 2021 18:03:16 +0200
Subject: [PATCH 1944/2207] utils: fd_server: add missing header

---
 utils/fd_server.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index eee3a6cf1..ea882d17a 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -1,6 +1,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 

From cecc4c06d8cc1cb60cf7e0b7d46cfa29cdf361d5 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Mon, 29 Mar 2021 22:02:22 +0200
Subject: [PATCH 1945/2207] offsets: fix minor issues

---
 sys/dev/netmap/netmap.c      | 5 +++--
 sys/dev/netmap/netmap_kern.h | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 53e765e5d..4f5eec3da 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2334,7 +2334,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			if ((kring->offset_mask & mask) != mask ||
 			     kring->offset_max < max_offset) {
 				if (netmap_verbose)
-					nm_prinf("%s: cannot decrease"
+					nm_prinf("%s: cannot increase"
 						 "offset mask and/or max"
 						 "(current: mask=%llx,max=%llu",
 							kring->name,
@@ -2408,7 +2408,7 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 			maxframe = mtu + ETH_HLEN +
 				ETH_FCS_LEN + VLAN_HLEN;
 			if (maxframe < target) {
-				target = kring->offset_gap;
+				target = maxframe;
 			}
 		}
 
@@ -3248,6 +3248,7 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 		break;
 	case NETMAP_REQ_OPT_OFFSETS:
 		rv = sizeof(struct nmreq_opt_offsets);
+		break;
 	}
 	/* subtract the common header */
 	return rv - sizeof(struct nmreq_option);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e5d7ebad3..479197b36 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -828,11 +828,11 @@ struct netmap_adapter {
 	 *      for RX rings, where we want to disallow writes outside of the
 	 *      netmap buffer. The l value must be computed taking into account
 	 *      the stipulated max_offset (o), possibily increased if there are
-	 *      alignemnt constrains, the maxframe (m), if known, and the
+	 *      alignment constraints, the maxframe (m), if known, and the
 	 *      current NETMAP_BUF_SIZE (b) of the memory region used by the
 	 *      adapter. We want the largest supported l such that o + l <= b.
 	 *      If m is known to be <= b - o, the callback may also choose the
-	 *      largest l <= b, ignoring the offset.  The buf_align field is
+	 *      largest l <= m, ignoring the offset.  The buf_align field is
 	 *      most important for TX rings when there are offsets.  The user
 	 *      will see this value in the ring->buf_align field.  Misaligned
 	 *      offsets will cause the corresponding packets to be silently

From 17fbecec550b2a2735f6cda2a4e9cb7fe24d0dae Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 30 Mar 2021 07:52:34 +0200
Subject: [PATCH 1946/2207] align from FreeBSD

---
 sys/dev/netmap/if_re_netmap.h       |   2 +-
 sys/dev/netmap/if_vtnet_netmap.h    | 167 ++++++++++++----------------
 sys/dev/netmap/netmap.c             |   6 +
 sys/dev/netmap/netmap_bdg.c         |   2 +-
 sys/dev/netmap/netmap_generic.c     |   2 +-
 sys/dev/netmap/netmap_kern.h        |  24 ++--
 sys/dev/netmap/netmap_mem2.c        |   5 +-
 sys/dev/netmap/netmap_mem2.h        |   2 +-
 sys/dev/netmap/netmap_monitor.c     |   2 +-
 sys/dev/netmap/netmap_offloadings.c |   2 +-
 sys/dev/netmap/netmap_pipe.c        |   2 +-
 sys/dev/netmap/netmap_vale.c        |   2 +-
 12 files changed, 98 insertions(+), 120 deletions(-)

diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index 2d3352353..0e56a731a 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -26,7 +26,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_re_netmap.h 234225 2012-04-13 15:33:12Z luigi $
+ * $FreeBSD$
  *
  * netmap support for: re
  *
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 51b7977b9..cd652938b 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -24,7 +24,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_vtnet_netmap.h 340436 2018-11-14 15:39:48Z vmaffione $
+ * $FreeBSD$
  */
 
 #include 
@@ -33,77 +33,24 @@
 #include     /* vtophys ? */
 #include 
 
-/*
- * Return 1 if the queue identified by 't' and 'idx' is in netmap mode.
- */
-static int
-vtnet_netmap_queue_on(struct vtnet_softc *sc, enum txrx t, int idx)
-{
-	struct netmap_adapter *na = NA(sc->vtnet_ifp);
-
-	if (!nm_native_on(na))
-		return 0;
-
-	if (t == NR_RX)
-		return !!(idx < na->num_rx_rings &&
-			na->rx_rings[idx]->nr_mode == NKR_NETMAP_ON);
-
-	return !!(idx < na->num_tx_rings &&
-		na->tx_rings[idx]->nr_mode == NKR_NETMAP_ON);
-}
-
 /* Register and unregister. */
 static int
 vtnet_netmap_reg(struct netmap_adapter *na, int state)
 {
 	struct ifnet *ifp = na->ifp;
 	struct vtnet_softc *sc = ifp->if_softc;
-	int success;
-	int i;
-
-	/* Drain the taskqueues to make sure that there are no worker threads
-	 * accessing the virtqueues. */
-	vtnet_drain_taskqueues(sc);
 
+	/*
+	 * Trigger a device reinit, asking vtnet_init_locked() to
+	 * also enter or exit netmap mode.
+	 */
 	VTNET_CORE_LOCK(sc);
-
-	/* We need nm_netmap_on() to return true when called by
-	 * vtnet_init_locked() below. */
-	if (state)
-		nm_set_native_flags(na);
-
-	/* We need to trigger a device reset in order to unexpose guest buffers
-	 * published to the host. */
-	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-	/* Get pending used buffers. The way they are freed depends on whether
-	 * they are netmap buffer or they are mbufs. We can tell apart the two
-	 * cases by looking at kring->nr_mode, before this is possibly updated
-	 * in the loop below. */
-	for (i = 0; i < sc->vtnet_act_vq_pairs; i++) {
-		struct vtnet_txq *txq = &sc->vtnet_txqs[i];
-		struct vtnet_rxq *rxq = &sc->vtnet_rxqs[i];
-
-		VTNET_TXQ_LOCK(txq);
-		vtnet_txq_free_mbufs(txq);
-		VTNET_TXQ_UNLOCK(txq);
-
-		VTNET_RXQ_LOCK(rxq);
-		vtnet_rxq_free_mbufs(rxq);
-		VTNET_RXQ_UNLOCK(rxq);
-	}
-	vtnet_init_locked(sc);
-	success = (ifp->if_drv_flags & IFF_DRV_RUNNING) ? 0 : ENXIO;
-
-	if (state) {
-		netmap_krings_mode_commit(na, state);
-	} else {
-		nm_clear_native_flags(na);
-		netmap_krings_mode_commit(na, state);
-	}
-
+	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+	vtnet_init_locked(sc, state ? VTNET_INIT_NETMAP_ENTER
+	    : VTNET_INIT_NETMAP_EXIT);
 	VTNET_CORE_UNLOCK(sc);
 
-	return success;
+	return (0);
 }
 
 
@@ -196,9 +143,11 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 }
 
 /*
- * Publish (up to) num netmap receive buffers to the host,
- * starting from the first one that the user made available
- * (kring->nr_hwcur).
+ * Publish 'num 'netmap receive buffers to the host, starting
+ * from the next available one (rx->vtnrx_nm_refill).
+ * Return a positive error code on error, and 0 on success.
+ * If we could not publish all of the buffers that's an error,
+ * since the netmap ring and the virtqueue would go out of sync.
  */
 static int
 vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
@@ -208,7 +157,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int const lim = kring->nkr_num_slots - 1;
-	u_int nm_i = kring->nr_hwcur;
+	u_int nm_i;
 
 	/* device-specific */
 	struct vtnet_softc *sc = ifp->if_softc;
@@ -219,7 +168,8 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 	struct sglist_seg ss[2];
 	struct sglist sg = { ss, 0, 0, 2 };
 
-	for (; num > 0; nm_i = nm_next(nm_i, lim), num--) {
+	for (nm_i = rxq->vtnrx_nm_refill; num > 0;
+	    nm_i = nm_next(nm_i, lim), num--) {
 		struct netmap_slot *slot = &ring->slot[nm_i];
 		uint64_t paddr;
 		void *addr = PNMB(na, slot, &paddr);
@@ -227,7 +177,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 
 		if (addr == NETMAP_BUF_BASE(na)) { /* bad buf */
 			if (netmap_ring_reinit(kring))
-				return -1;
+				return EFAULT;
 		}
 
 		slot->flags &= ~NS_BUF_CHANGED;
@@ -240,14 +190,14 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 		err = virtqueue_enqueue(vq, /*cookie=*/rxq, &sg,
 				/*readable=*/0, /*writeable=*/sg.sg_nseg);
 		if (unlikely(err)) {
-			if (err != ENOSPC)
-				nm_prerr("virtqueue_enqueue(%s) failed: %d",
-					kring->name, err);
+			nm_prerr("virtqueue_enqueue(%s) failed: %d",
+				kring->name, err);
 			break;
 		}
 	}
+	rxq->vtnrx_nm_refill = nm_i;
 
-	return nm_i;
+	return num == 0 ? 0 : ENOSPC;
 }
 
 /*
@@ -261,24 +211,30 @@ vtnet_netmap_rxq_populate(struct vtnet_rxq *rxq)
 {
 	struct netmap_adapter *na = NA(rxq->vtnrx_sc->vtnet_ifp);
 	struct netmap_kring *kring;
+	struct netmap_slot *slot;
 	int error;
+	int num;
 
-	if (!nm_native_on(na) || rxq->vtnrx_id >= na->num_rx_rings)
+	slot = netmap_reset(na, NR_RX, rxq->vtnrx_id, 0);
+	if (slot == NULL)
 		return -1;
-
 	kring = na->rx_rings[rxq->vtnrx_id];
-	if (!(nm_kring_pending_on(kring) ||
-			kring->nr_pending_mode == NKR_NETMAP_ON))
-		return -1;
 
-	/* Expose all the RX netmap buffers we can. In case of no indirect
+	/*
+	 * Expose all the RX netmap buffers we can. In case of no indirect
 	 * buffers, the number of netmap slots in the RX ring matches the
 	 * maximum number of 2-elements sglist that the RX virtqueue can
-	 * accommodate (minus 1 to avoid netmap ring wraparound). */
-	error = vtnet_netmap_kring_refill(kring, na->num_rx_desc - 1);
+	 * accommodate. We need to start from kring->nr_hwtail, which is 0
+	 * on the first netmap register and may be different from 0 if a
+	 * virtio re-init (caused by a netma register or i.e., ifconfig)
+	 * happens while the device is in use by netmap.
+	 */
+	rxq->vtnrx_nm_refill = kring->nr_hwtail;
+	num = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
+	error = vtnet_netmap_kring_refill(kring, num);
 	virtqueue_notify(rxq->vtnrx_vq);
 
-	return error < 0 ? ENXIO : 0;
+	return error;
 }
 
 /* Reconcile kernel and user view of the receive ring. */
@@ -304,8 +260,11 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 	/*
 	 * First part: import newly received packets.
 	 * Only accept our own buffers (matching the token). We should only get
-	 * matching buffers. We may need to stop early to avoid hwtail to overrun
-	 * hwcur.
+	 * matching buffers. The hwtail should never overrun hwcur, because
+	 * we publish only N-1 receive buffers (and not N).
+	 * In any case we must not leave this routine with the interrupts
+	 * disabled, pending packets in the VQ and hwtail == (hwcur - 1),
+	 * otherwise the pending packets could stall.
 	 */
 	if (netmap_no_pendintr || force_update) {
 		uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim);
@@ -314,10 +273,17 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 		vtnet_rxq_disable_intr(rxq);
 
 		nm_i = kring->nr_hwtail;
-		while (nm_i != hwtail_lim) {
+		for (;;) {
 			int len;
 			token = virtqueue_dequeue(vq, &len);
 			if (token == NULL) {
+				/*
+				 * Enable the interrupts again and double-check
+				 * for more work. We can go on until we win the
+				 * race condition, since we are not replenishing
+				 * in the meanwhile, and thus we will process at
+				 * most N-1 slots.
+				 */
 				if (interrupts && vtnet_rxq_enable_intr(rxq)) {
 					vtnet_rxq_disable_intr(rxq);
 					continue;
@@ -327,6 +293,11 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (unlikely(token != (void *)rxq)) {
 				nm_prerr("BUG: RX token mismatch");
 			} else {
+				if (nm_i == hwtail_lim) {
+					KASSERT(false, ("hwtail would "
+					    "overrun hwcur"));
+				}
+
 				/* Skip the virtio-net header. */
 				len -= sc->vtnet_hdr_size;
 				if (unlikely(len < 0)) {
@@ -342,28 +313,30 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 		kring->nr_hwtail = nm_i;
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
-	nm_prdis("[B] h %d c %d hwcur %d hwtail %d", ring->head, ring->cur,
-				kring->nr_hwcur, kring->nr_hwtail);
 
 	/*
 	 * Second part: skip past packets that userspace has released.
 	 */
 	nm_i = kring->nr_hwcur; /* netmap ring index */
 	if (nm_i != head) {
-		int howmany = head - nm_i;
-		int nm_j;
-
-		if (howmany < 0)
-			howmany += kring->nkr_num_slots;
-		nm_j = vtnet_netmap_kring_refill(kring, howmany);
-		if (nm_j < 0)
-			return nm_j;
-		kring->nr_hwcur = nm_j;
+		int released;
+		int error;
+
+		released = head - nm_i;
+		if (released < 0)
+			released += kring->nkr_num_slots;
+		error = vtnet_netmap_kring_refill(kring, released);
+		if (error) {
+			nm_prerr("Failed to replenish RX VQ with %u sgs",
+			    released);
+			return error;
+		}
+		kring->nr_hwcur = head;
 		virtqueue_notify(vq);
 	}
 
-	nm_prdis("[C] h %d c %d t %d hwcur %d hwtail %d", ring->head, ring->cur,
-		ring->tail, kring->nr_hwcur, kring->nr_hwtail);
+	nm_prdis("h %d c %d t %d hwcur %d hwtail %d", kring->rhead,
+	    kring->rcur, kring->rtail, kring->nr_hwcur, kring->nr_hwtail);
 
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4f5eec3da..a9ddb5fb5 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -619,6 +619,10 @@ netmap_set_all_rings(struct netmap_adapter *na, int stopped)
 	if (!nm_netmap_on(na))
 		return;
 
+	if (netmap_verbose) {
+		nm_prinf("%s: %sable all rings", na->name,
+		    (stopped ? "dis" : "en"));
+	}
 	for_rx_tx(t) {
 		for (i = 0; i < netmap_real_rings(na, t); i++) {
 			netmap_set_ring(na, i, t, stopped);
@@ -4569,7 +4573,9 @@ netmap_init(void)
 	if (error)
 		goto fail;
 
+#if !defined(__FreeBSD__) || defined(KLD_MODULE)
 	nm_prinf("netmap: loaded module");
+#endif
 	return (0);
 fail:
 	netmap_fini();
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 085ecfc56..8701d9daf 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -58,7 +58,7 @@ ports attached to the switch)
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
-__FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z glebius $");
+__FBSDID("$FreeBSD$");
 
 #include 
 #include 
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index e35d4a44e..f99957673 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -67,7 +67,7 @@
 #ifdef __FreeBSD__
 
 #include  /* prerequisite */
-__FBSDID("$FreeBSD: head/sys/dev/netmap/netmap_generic.c 274353 2014-11-10 20:19:58Z luigi $");
+__FBSDID("$FreeBSD$");
 
 #include 
 #include 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 479197b36..0239a3852 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -28,7 +28,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/netmap_kern.h 238985 2012-08-02 11:59:43Z luigi $
+ * $FreeBSD$
  *
  * The header contains the definitions of constants and function
  * prototypes used only in kernelspace.
@@ -1414,19 +1414,19 @@ nm_native_on(struct netmap_adapter *na)
 static inline struct netmap_kring *
 netmap_kring_on(struct netmap_adapter *na, u_int q, enum txrx t)
 {
-        struct netmap_kring *kring = NULL;
+	struct netmap_kring *kring = NULL;
 
-        if (!nm_native_on(na))
-                return NULL;
+	if (!nm_native_on(na))
+		return NULL;
 
-        if (t == NR_RX && q < na->num_rx_rings)
-                kring = na->rx_rings[q];
-        else if (t == NR_TX && q < na->num_tx_rings)
-                kring = na->tx_rings[q];
-        else
-                return NULL;
+	if (t == NR_RX && q < na->num_rx_rings)
+		kring = na->rx_rings[q];
+	else if (t == NR_TX && q < na->num_tx_rings)
+		kring = na->tx_rings[q];
+	else
+		return NULL;
 
-        return (kring->nr_mode == NKR_NETMAP_ON) ? kring : NULL;
+	return (kring->nr_mode == NKR_NETMAP_ON) ? kring : NULL;
 }
 
 static inline int
@@ -1673,7 +1673,6 @@ int netmap_adapter_put(struct netmap_adapter *na);
 #define NETMAP_BUF_BASE(_na)	((_na)->na_lut.lut[0].vaddr)
 #define NETMAP_BUF_SIZE(_na)	((_na)->na_lut.objsize)
 extern int netmap_no_pendintr;
-extern int netmap_mitigate;
 extern int netmap_verbose;
 #ifdef CONFIG_NETMAP_DEBUG
 extern int netmap_debug;		/* for debugging */
@@ -1695,7 +1694,6 @@ enum {                                  /* debug flags */
 };
 
 extern int netmap_txsync_retry;
-extern int netmap_flags;
 extern int netmap_generic_hwcsum;
 extern int netmap_generic_mit;
 extern int netmap_generic_ringsize;
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index e07b21019..069e0fa75 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -38,7 +38,7 @@
 
 #ifdef __FreeBSD__
 #include  /* prerequisite */
-__FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 241723 2012-10-19 09:41:45Z glebius $");
+__FBSDID("$FreeBSD$");
 
 #include 
 #include 
@@ -1720,7 +1720,8 @@ _netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id,
 		if (n) {
 			if (netmap_verbose) {
 				nm_prinf("%s: adding %llu more buffers",
-						d->pools[NETMAP_BUF_POOL].name, n);
+				    d->pools[NETMAP_BUF_POOL].name,
+				    (unsigned long long)n);
 			}
 			d->params[NETMAP_BUF_POOL].num += n;
 		}
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 3b134f351..c0e039b42 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -29,7 +29,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/netmap_mem2.c 234290 2012-04-14 16:44:18Z luigi $
+ * $FreeBSD$
  *
  * (New) memory allocator for netmap
  */
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 1d5b7b962..9e5d57f7f 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -25,7 +25,7 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/netmap_zmon.c 270063 2014-08-16 15:00:01Z luigi $
+ * $FreeBSD$
  *
  * Monitors
  *
diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index b08a6f8f2..a6ff8b00a 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD: head/sys/dev/netmap/netmap_offloadings.c 261909 2014-02-15 04:53:04Z luigi $ */
+/* $FreeBSD$ */
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index a39df1524..01fd79ded 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD: head/sys/dev/netmap/netmap_pipe.c 261909 2014-02-15 04:53:04Z luigi $ */
+/* $FreeBSD$ */
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 29f8f4852..db3321a4f 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -29,7 +29,7 @@
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
-__FBSDID("$FreeBSD: head/sys/dev/netmap/netmap.c 257176 2013-10-26 17:58:36Z glebius $");
+__FBSDID("$FreeBSD$");
 
 #include 
 #include 

From 6782c072911f671a3e5ce84c0f9afc2e921b8a2c Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 30 Mar 2021 11:53:54 +0200
Subject: [PATCH 1947/2207] bridge: simplify ifdef

---
 apps/bridge/bridge.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index b5b0663ee..0c8f56265 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -17,6 +17,10 @@
 #include 
 #include 
 
+#if defined(_WIN32)
+#define BUSYWAIT
+#endif
+
 static int verbose = 0;
 
 static int do_abort = 0;
@@ -321,7 +325,7 @@ main(int argc, char **argv)
 		pollfd[0].revents = pollfd[1].revents = 0;
 		n0 = rx_slots_avail(pa);
 		n1 = rx_slots_avail(pb);
-#if defined(_WIN32) || defined(BUSYWAIT)
+#ifdef BUSYWAIT
 		if (n0) {
 			pollfd[1].revents = POLLOUT;
 		} else {
@@ -333,7 +337,7 @@ main(int argc, char **argv)
 			ioctl(pollfd[1].fd, NIOCRXSYNC, NULL);
 		}
 		ret = 1;
-#else
+#else  /* !defined(BUSYWAIT) */
 		if (n0)
 			pollfd[1].events |= POLLOUT;
 		else
@@ -345,7 +349,7 @@ main(int argc, char **argv)
 
 		/* poll() also cause kernel to txsync/rxsync the NICs */
 		ret = poll(pollfd, 2, 2500);
-#endif /* defined(_WIN32) || defined(BUSYWAIT) */
+#endif /* !defined(BUSYWAIT) */
 		if (ret <= 0 || verbose)
 		    D("poll %s [0] ev %x %x rx %d@%d tx %d,"
 			     " [1] ev %x %x rx %d@%d tx %d",
@@ -375,14 +379,14 @@ main(int argc, char **argv)
 		}
 		if (pollfd[0].revents & POLLOUT) {
 			ports_move(pb, pa, burst, msg_b2a);
-#if defined(_WIN32) || defined(BUSYWAIT)
+#ifdef BUSYWAIT
 			ioctl(pollfd[0].fd, NIOCTXSYNC, NULL);
 #endif
 		}
 
 		if (pollfd[1].revents & POLLOUT) {
 			ports_move(pa, pb, burst, msg_a2b);
-#if defined(_WIN32) || defined(BUSYWAIT)
+#ifdef BUSYWAIT
 			ioctl(pollfd[1].fd, NIOCTXSYNC, NULL);
 #endif
 		}

From 75477cd4021a02d4ea87ed17cc550bbc330c5c18 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 30 Mar 2021 11:55:07 +0200
Subject: [PATCH 1948/2207] libnetmap: import fixes from FreeBSD

---
 libnetmap/nmreq.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index f3207fac0..d9326052e 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -601,10 +601,9 @@ nmreq_options_decode(const char *opt, struct nmreq_opt_parser parsers[],
 struct nmreq_option *
 nmreq_find_option(struct nmreq_header *h, uint32_t t)
 {
-	struct nmreq_option *o;
+	struct nmreq_option *o = NULL;
 
-	for (o = (struct nmreq_option *)h->nr_options; o != NULL;
-			o = (struct nmreq_option *)o->nro_next) {
+	nmreq_foreach_option(h, o) {
 		if (o->nro_reqtype == t)
 			break;
 	}
@@ -631,8 +630,14 @@ nmreq_free_options(struct nmreq_header *h)
 {
 	struct nmreq_option *o, *next;
 
-	for (o = (struct nmreq_option *)h->nr_options; o != NULL; o = next) {
-		next = (struct nmreq_option *)o->nro_next;
+	/*
+	 * Note: can't use nmreq_foreach_option() here; it frees the
+	 * list as it's walking and nmreq_foreach_option() isn't
+	 * modification-safe.
+	 */
+	for (o = (struct nmreq_option *)(uintptr_t)h->nr_options; o != NULL;
+	    o = next) {
+		next = (struct nmreq_option *)(uintptr_t)o->nro_next;
 		free(o);
 	}
 }

From 4c5ac8eec5d8855dcdb19631b3d4e715283dd5c4 Mon Sep 17 00:00:00 2001
From: Dries De Winter 
Date: Wed, 31 Mar 2021 14:27:05 +0200
Subject: [PATCH 1949/2207] mlx5: always leave one free slot in rx ring

Previously mlx5e_netmap_rxsync() could completely fill up the rx ring but
user space cannot tell the difference between empty and completely full, so
it would be considered as empty and the ring would be stuck forever.

This is now avoided by never making more than (ring size - 1) buffer slots
available for packet reception.
---
 LINUX/mlx5_netmap_linux.h | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index 2170068e9..a22fe6689 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -368,6 +368,7 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
   u_int nm_i = 0; /* index into the netmap ring */
   u_int const lim = kring->nkr_num_slots - 1;
   u_int const head = kring->rhead;
+  u_int const stop_i = nm_prev(head, lim); /* stop reclaiming here */
   uint16_t slot_flags = 0;
 
   /* device-specific */
@@ -394,20 +395,22 @@ int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags) {
 
   /*
    * first part: reclaim buffers that userspace has released:
-   *  (from kring->nr_hwcur to slot before ring->head)
+   *  (from kring->nr_hwcur to second last [*] slot before ring->head)
    * and make the buffers available for reception.
    * As usual nm_i is the index in the netmap ring.
+   * [*] IMPORTANT: we must leave one free slot in the ring
+   * to avoid ring empty/full confusion in userspace.
    */
   nm_i = kring->nr_hwcur;
 
-  if (nm_i != head) {
+  if (nm_i != stop_i) {
     struct mlx5_wq_cyc *wq = &rq->wqe.wq;
     struct mlx5e_rx_wqe_cyc *wqe = mlx5_wq_cyc_get_wqe(wq, mlx5_wq_cyc_get_head(wq));
     struct netmap_slot *slot;
     uint64_t paddr;
     void *addr;
 
-    while (nm_i != head && !mlx5_wq_cyc_is_full(wq)) {
+    while (nm_i != stop_i && !mlx5_wq_cyc_is_full(wq)) {
 
       slot = &ring->slot[nm_i];
       addr = PNMB(na, slot, &paddr); /* find phys address */

From 2356656ed1dd47cbeb873a3b64c88a1ff3b9feca Mon Sep 17 00:00:00 2001
From: jhk 
Date: Fri, 2 Apr 2021 08:45:33 +0200
Subject: [PATCH 1950/2207] run a codespell pass to fix several typos

---
 LINUX/README.md                                |  2 +-
 LINUX/archlinux/PKGBUILD                       |  2 +-
 LINUX/configure                                |  8 ++++----
 LINUX/default-config.mak.in_                   |  2 +-
 LINUX/if_virtio_net_netmap.h                   |  2 +-
 LINUX/if_vmxnet3_netmap_v2.h                   |  2 +-
 LINUX/ixgbe_netmap_linux.h                     |  2 +-
 LINUX/netmap_linux.c                           |  4 ++--
 LINUX/netmap_ptnet.c                           |  2 +-
 LINUX/scripts/np                               | 12 ++++++------
 LINUX/veth_netmap.h                            |  2 +-
 LINUX/virtio_netmap.h                          |  2 +-
 README.md                                      |  2 +-
 README.ptnetmap.md                             |  4 ++--
 WINDOWS/README.txt                             |  8 ++++----
 WINDOWS/includes/net/ethernet.h                |  2 +-
 WINDOWS/nm-ndis/filter.c                       |  6 +++---
 apps/dedup/dedup.c                             |  4 ++--
 apps/lb/lb.c                                   |  2 +-
 apps/pkt-gen/pkt-gen.c                         |  2 +-
 apps/tlem/tlem.c                               | 18 +++++++++---------
 apps/vale-ctl/vale-ctl.4                       |  4 ++--
 extra/python/pktman.py                         |  2 +-
 libnetmap/libnetmap.h                          |  4 ++--
 sys/dev/netmap/if_vtnet_netmap.h               |  2 +-
 sys/dev/netmap/netmap.c                        | 18 +++++++++---------
 sys/dev/netmap/netmap_bdg.c                    |  2 +-
 sys/dev/netmap/netmap_freebsd.c                |  2 +-
 sys/dev/netmap/netmap_generic.c                |  2 +-
 sys/dev/netmap/netmap_kern.h                   | 14 +++++++-------
 sys/dev/netmap/netmap_kloop.c                  | 12 ++++++------
 sys/dev/netmap/netmap_mem2.c                   | 10 +++++-----
 sys/dev/netmap/netmap_mem2.h                   |  4 ++--
 sys/dev/netmap/netmap_monitor.c                |  4 ++--
 sys/dev/netmap/netmap_vale.c                   |  4 ++--
 sys/net/netmap.h                               |  8 ++++----
 sys/net/netmap_user.h                          |  8 ++++----
 utils/ctrl-api-test.c                          |  8 ++++----
 utils/fd_server-legacy.c                       |  2 +-
 utils/fd_server.c                              |  2 +-
 utils/functional-legacy.c                      | 10 +++++-----
 utils/functional.c                             | 10 +++++-----
 .../0001-datapath-netmap-VALE-support.patch    |  6 +++---
 .../0001-datapath-netmap-VALE-support.patch    |  6 +++---
 44 files changed, 117 insertions(+), 117 deletions(-)

diff --git a/LINUX/README.md b/LINUX/README.md
index 0c9e2c14f..6c47b7577 100644
--- a/LINUX/README.md
+++ b/LINUX/README.md
@@ -260,7 +260,7 @@ On the receiver, you should see about 14.88 Mpps
   use the kernel network stack on the other endpoint. This is not a missing
   feature, as the native veth datapath is implemented using netmap pipes, and
   it does not make sense (in terms of performance) for pipes to support
-  conversion betweeen netmap buffers and skbuffs.
+  conversion between netmap buffers and skbuffs.
 
 * pkt-gen traffic does not flow across a Linux bridge.
   Check that source MAC is not 00:00:00:00:00:00 (pkt-gen default), nor
diff --git a/LINUX/archlinux/PKGBUILD b/LINUX/archlinux/PKGBUILD
index 20b3033d5..f3f1d1d7c 100644
--- a/LINUX/archlinux/PKGBUILD
+++ b/LINUX/archlinux/PKGBUILD
@@ -50,7 +50,7 @@ build() {
     echo "SRCPKGDEST=$SRCPKGDEST"
     echo "PKGDEST=$PKGDEST"
     echo "BUILDDIR=$BUILDDIR"
-    # We force some makepkg variables, trying to ovverride yaourt default behaviour,
+    # We force some makepkg variables, trying to override yaourt default behaviour,
     # which is to download sources in $srcdir/../linux instead of the place where
     # makepkg is invoked
     SRCDEST=$NESTEDDIR SRCPKGDEST=$NESTEDDIR PKGDEST=$NESTEDDIR BUILDDIR=$NESTEDDIR \
diff --git a/LINUX/configure b/LINUX/configure
index 2facbaa3b..fd3ef6cf0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -301,7 +301,7 @@ Available options:
   --help                       print this message
   --kernel-dir=                path to configured kernel directory
   --kernel-sources=            path to full kernel sources
-  --kernel-version=	       specifiy the kernel version
+  --kernel-version=	       specify the kernel version
   				(assuming everything is in the default place)
   --kernel-opts=	       additional options to pass to kernel make
                                (you can call this several times)
@@ -577,7 +577,7 @@ EOF
 }
 
 configh=netmap_linux_config.h
-# succes/failure actions are expected to write some macros
+# success/failure actions are expected to write some macros
 # in netma_linux_config.h. The following functions can be
 # used to simplify the task.
 
@@ -1014,7 +1014,7 @@ for w in $DISABLED_WARNINGS; do
 done
 
   message " NOTE  " <nr_hwcur = nm_i; /* note we migth break early */
+		kring->nr_hwcur = nm_i; /* note we might break early */
 	}
 out:
 	if (interrupts && vq->num_free < 32)
diff --git a/LINUX/if_vmxnet3_netmap_v2.h b/LINUX/if_vmxnet3_netmap_v2.h
index d1f1de1c0..0b4352680 100644
--- a/LINUX/if_vmxnet3_netmap_v2.h
+++ b/LINUX/if_vmxnet3_netmap_v2.h
@@ -469,7 +469,7 @@ vmxnet3_netmap_tq_config_tx_buf(struct vmxnet3_tx_queue *tq,
 		PNMB(na, slot + si, &paddr);
 
 		tbi->map_type = VMXNET3_MAP_NONE;
-		/*	the buffer length will get overriden by the actual
+		/*	the buffer length will get overridden by the actual
 		   packet length on transmit */
 		tbi->len      = NETMAP_BUF_SIZE(na);
 		tbi->dma_addr = (dma_addr_t)paddr;
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 1ea571a23..14d37df28 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -239,7 +239,7 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 	} else {
 		nm_clear_native_flags(na);
 	}
-	/* XXX SRIOV migth need another 2sec wait */
+	/* XXX SRIOV might need another 2sec wait */
 	if (netif_running(adapter->netdev))
 		NM_IXGBE_UP(adapter);	/* also enables intr */
 	clear_bit(NM_IXGBE_RESETTING, &adapter->state);
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index b1619a241..98ae19b4d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -378,7 +378,7 @@ nm_os_csum_ipv4(struct nm_iphdr *iph)
 }
 
 /* Compute and insert a TCP/UDP checksum over IPv4: 'iph' points to the IPv4
- * header, 'data' points to the TCP/UDP header, 'datalen' is the lenght of
+ * header, 'data' points to the TCP/UDP header, 'datalen' is the length of
  * TCP/UDP header + payload.
  */
 void
@@ -391,7 +391,7 @@ nm_os_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data,
 }
 
 /* Compute and insert a TCP/UDP checksum over IPv6: 'ip6h' points to the IPv6
- * header, 'data' points to the TCP/UDP header, 'datalen' is the lenght of
+ * header, 'data' points to the TCP/UDP header, 'datalen' is the length of
  * TCP/UDP header + payload.
  */
 void
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 0ffd7ddf3..b752a8ab9 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -776,7 +776,7 @@ ptnet_irqs_init(struct ptnet_info *pi)
 	pi->msix_entries = kzalloc(sizeof(*pi->msix_entries) * pi->num_rings,
 				   GFP_KERNEL);
 	if (!pi->msix_entries) {
-		pr_err("%s: Failed to allocate msix entires\n", __func__);
+		pr_err("%s: Failed to allocate msix entries\n", __func__);
 		return -ENOMEM;
 	}
 
diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 6164d8b21..274f62310 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -93,7 +93,7 @@ function need {
 	[ -n "$v" -a -d "$v${2:+/$2}" ] || error "Variable $1 not set or not valid"
 }
 
-## The following enviroment variables must be set:
+## The following environment variables must be set:
 ##
 ##  GITDIR: the absolute path of the netmap linux
 ## 	git repository, containing all the required netmap-*
@@ -223,8 +223,8 @@ function get-src()
 
 ##
 ##  extend  
-##	checks wether the range of applicability of the 
-##	given  can be extented to include .
+##	checks whether the range of applicability of the
+##	given  can be extended to include .
 ##	It returns 0 on success and 1 on failure.
 function extend()
 {
@@ -280,7 +280,7 @@ function minimize()
 	# the original patches (in tmp-patches) are ordered by version number.
 	# We consider one patch in turn (the 'pivot') and try
 	# to extend its range to cover the range of the next
-	# patch. If this succedes, the merged patch is the new
+	# patch. If this succeeds, the merged patch is the new
 	# pivot, otherwise the current pivot is output and the
 	# next patch becomes the new pivot. The process
 	# is repeated until there are no more patches to consider.
@@ -306,7 +306,7 @@ function minimize()
 		# the patch in its final location
 		out=$(scripts/vers vanilla $drv $ple -c $pre -c -S4)
 		cp $pivot final-patches/$out
-		# the new pivot becames the next patch (if any)
+		# the new pivot becomes the next patch (if any)
 		pivot=$1
 		pre=$nre
 		ple=$nle
@@ -428,7 +428,7 @@ function check-patch()
 	local v1=$(scripts/vers $_patch -s -p -C)
 	# extract the right version
 	local v2=$(scripts/vers $_patch -s -C)
-	# extract the uncoverted right version (might be 99999)
+	# extract the unconverted right version (might be 99999)
 	local end=$(scripts/vers $_patch -s)
 	# extract the driver name
 	local driver=$(scripts/vers $_patch -s -p -p)
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index fdd1126e8..dfdce54e8 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -238,7 +238,7 @@ veth_netmap_attach(struct ifnet *ifp)
 	na.nm_dtor = veth_netmap_dtor;
 	na.num_tx_rings = na.num_rx_rings = 1;
 	netmap_attach_ext(&na, sizeof(struct netmap_veth_adapter),
-			0 /* do not ovveride reg */);
+			0 /* do not override reg */);
 }
 
 /* end of file */
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index bf5e37ff6..0c2eafa4d 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -429,7 +429,7 @@ virtio_netmap_txsync(struct netmap_kring *kring, int flags)
 		virtqueue_kick(vq);
 
 		/* Update hwcur depending on where we stopped. */
-		kring->nr_hwcur = nm_i; /* note we migth break early */
+		kring->nr_hwcur = nm_i; /* note we might break early */
 	}
 out:
 	/* Ask the hypervisor for notifications, possibly only when it has
diff --git a/README.md b/README.md
index 0dad76b1e..1d6c99051 100644
--- a/README.md
+++ b/README.md
@@ -180,7 +180,7 @@ Netmap is able to send packets at very high rates, and for simple
 packet transmission and reception, speed generally not limited by
 the CPU but by other factors (link speed, bus or NIC hw limitations).
 
-For a physical link, the maximum numer of packets per second can
+For a physical link, the maximum number of packets per second can
 be computed with the formula:
 
 	pps = line_rate / (672 + 8 * pkt_size)
diff --git a/README.ptnetmap.md b/README.ptnetmap.md
index 834e5734e..219597759 100644
--- a/README.ptnetmap.md
+++ b/README.ptnetmap.md
@@ -146,7 +146,7 @@ support the virtio-net header.
 Netmap is a framework for high performance network I/O. It exposes an
 hardware-independent API which allows userspace application to directly interact
 with NIC hardware rings, in order to receive and transmit Ethernet frames.
-Rings are always accessed in the context of system calls and NIC interrups
+Rings are always accessed in the context of system calls and NIC interrupts
 are used to notify applications about NIC processing completion.
 The performance boost of netmap w.r.t. traditional socket API primarily comes
 from: (i) batching, since it is possible to send/receive hundreds of packets
@@ -227,5 +227,5 @@ A number of device registers are used for configuration (number of rings and
 slots, device MAC address, supported features, ...) while "kick" registers
 are used for guest-to-host notifications.
 The ptnetmap kthread infrastructure, moreover, has been already extended to
-suppor an arbitrary number of rings, where currently each ring is served
+support an arbitrary number of rings, where currently each ring is served
 by a different kernel thread.
diff --git a/WINDOWS/README.txt b/WINDOWS/README.txt
index 1636f89b4..5b1c1cdf9 100644
--- a/WINDOWS/README.txt
+++ b/WINDOWS/README.txt
@@ -15,7 +15,7 @@ which also build the standard netmap test program, pkt-gen.
 	ports.  Performance is similar to that on FreeBSD and Linux:
 	20Mpps on switch ports, over 100 Mpps on pipes.
 
- 	To load the module, do the following (as adminstrator)
+	To load the module, do the following (as administrator)
 
 	    (cd Output-Win8.1Release/netmap-pkg; ./nm-loader l)
 
@@ -42,7 +42,7 @@ which also build the standard netmap test program, pkt-gen.
 		netmap:ethXX
 
 	as the port name. XX is the Windows "interface index" that
-	can be shown with the followin command (or many other ways):
+	can be shown with the following command (or many other ways):
 
 		netsh int ipv4 show interfaces
 
@@ -82,7 +82,7 @@ a) Build with command line tools and MsBuild.exe
 
 	make clean	# will clean output directories
 
-   The output will be found in the directory ./Output-
+   The output will be found in the directory ./Output-
 
    Please look at the makefile to select different configurations
 
@@ -161,7 +161,7 @@ native netmap mode available on FreeBSD and Linux).
 	pkt-gen-b -i vale0:a{1 -f rx
 
     NETMAP to HOST ring	about 2.3 Mpps if dropped, 1.8Mpps to windump
-       (replace the '5' with the inteface index from
+       (replace the '5' with the interface index from
 		netsh int ipv4 show interfaces
 
 	pkt-gen-b -i netmap:eth5^ -f tx	# on one vm
diff --git a/WINDOWS/includes/net/ethernet.h b/WINDOWS/includes/net/ethernet.h
index 4bb61c550..dc0f635c2 100644
--- a/WINDOWS/includes/net/ethernet.h
+++ b/WINDOWS/includes/net/ethernet.h
@@ -43,7 +43,7 @@
 #define	M_HASFCS	M_PROTO5	/* FCS included at end of frame */
 
 /*
- * Ethernet CRC32 polynomials (big- and little-endian verions).
+ * Ethernet CRC32 polynomials (big- and little-endian versions).
  */
 #define	ETHER_CRC_POLY_LE	0xedb88320
 #define	ETHER_CRC_POLY_BE	0x04c11db6
diff --git a/WINDOWS/nm-ndis/filter.c b/WINDOWS/nm-ndis/filter.c
index a586d4e1f..06ed74ab1 100644
--- a/WINDOWS/nm-ndis/filter.c
+++ b/WINDOWS/nm-ndis/filter.c
@@ -478,7 +478,7 @@ Routine Description:
 
 Arguments:
 
-    FilterModuleContext - pointer to the filter context stucture
+    FilterModuleContext - pointer to the filter context structure
     PauseParameters     - additional information about the pause
 
 Return Value:
@@ -545,7 +545,7 @@ Routine Description:
 
 Arguments:
 
-    FilterModuleContext - pointer to the filter context stucture.
+    FilterModuleContext - pointer to the filter context structure.
     RestartParameters   - additional information about the restart operation.
 
 Return Value:
@@ -1838,7 +1838,7 @@ Routine Description:
     calls the NdisFCancelSendNetBufferLists to propagate the cancel operation.
 
     If your driver does not queue any send NBLs, you may omit this routine.  
-    NDIS will propagate the cancelation on your behalf more efficiently.
+    NDIS will propagate the cancellation on your behalf more efficiently.
 
 Arguments:
 
diff --git a/apps/dedup/dedup.c b/apps/dedup/dedup.c
index 95bdf633a..ffa6f4212 100644
--- a/apps/dedup/dedup.c
+++ b/apps/dedup/dedup.c
@@ -201,7 +201,7 @@ dedup_fresh_packet(struct dedup *d, const struct netmap_slot *s)
 			rfi -= d->fifo_size;
 
 		fs = d->fifo_slot + rfi;
-		ND("checking %lu %lu: lenghts %u %u buf %d", fi, rfi, fs->len, s->len,
+		ND("checking %lu %lu: lengths %u %u buf %d", fi, rfi, fs->len, s->len,
 				fs->buf_idx);
 
 		if (fs->len != s->len)
@@ -302,7 +302,7 @@ dedup_push_in(struct dedup *d, const struct timeval *now)
 		if (out_space == 0)
 			break;
 
-		/* if the FIFO is full, remove and possibily send
+		/* if the FIFO is full, remove and possibly send
 		 * the oldest packet
 		 */
 		if (dedup_fifo_full(d)) {
diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 37fe97cc6..778360d9e 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -498,7 +498,7 @@ init_groups(void)
  * when the need to drop arises, we roll it back to head.
  */
 struct morefrag {
-	uint16_t last_flag;	/* for intput rings */
+	uint16_t last_flag;	/* for input rings */
 	uint32_t last_hash;	/* for input rings */
 	uint32_t shadow_head;	/* for output rings */
 };
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 559036faa..15909300e 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -3149,7 +3149,7 @@ main(int arc, char **argv)
 
 	if (g.virt_header) {
 		/* Set the virtio-net header length, since the user asked
-		 * for it explicitely. */
+		 * for it explicitly. */
 		set_vnet_hdr_len(&g);
 	} else {
 		/* Check whether the netmap port we opened requires us to send
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 7fd655e77..0913fee7a 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -64,7 +64,7 @@ In order to get good and predictable performance, it is important
 that threads are pinned to a single core, and it is preferable that
 prod() and cons() for each direction share the cache as much as possible.
 Putting them on two hyperthreads of the same core seems to give
-good results but that shoud be investigated further.
+good results but that should be investigated further.
 
 It also seems useful to use a scheduler (SCHED_FIFO or SCHED_RR)
 that gives more predictable cycles to the CPU, as well as try
@@ -100,7 +100,7 @@ prod()
 
     q-c_reorder (set with the -R command line option) decides
         whether the packet should be temporary hold to emulate
-	packet reordering. To hold a packet, it shuld set
+	packet reordering. To hold a packet, it should set
 	q->cur_hold_delay to a non-zero value. The packet will
 	reenter the stream once the cur_hold_delay has expired.
 
@@ -546,7 +546,7 @@ ec_next(int i)
 
 /* if fname is NULL tlem will run standalone, i.e., in server mode
  * with no possibility for clients to change the configuration.
- * Otherwise, the first tlem instance that successully locks the
+ * Otherwise, the first tlem instance that successfully locks the
  * first four bytes of the configuration file becomes the server.
  * Clients write-lock the rest of the file, to guarantee mutual
  * exclusive configuration updates among them.
@@ -663,7 +663,7 @@ ec_allowclients()
     return 0;
 }
 
-static void ec_activate(struct _qs *q); // foward
+static void ec_activate(struct _qs *q); // forward
 static int
 ec_init(struct _qs *q, struct _ecs *ec, int server)
 {
@@ -863,7 +863,7 @@ struct arp_cmd_q {
 	uint64_t	tail ALIGN_CACHE; /* private to the producer */
 };
 
-/* consumer: extract a new command.  The command slot is not immediatly
+/* consumer: extract a new command.  The command slot is not immediately
  * released, so that at most ARP_CMD_QSIZE messages are read for each
  * cons() loop.
  */
@@ -1193,7 +1193,7 @@ setaffinity(int i)
     }
     maxprio = sched_get_priority_max(SCHED_RR);
     if (maxprio < 0) {
-        ED("Unable to retrive max RR priority, using 10");
+        ED("Unable to retrieve max RR priority, using 10");
         maxprio = 10;
     }
     bzero(&p, sizeof(p));
@@ -1774,7 +1774,7 @@ cons_update_macs(struct pipe_args *pa, void *pkt)
             injected = 1;
         }
     }
-    /* copy negated dst into eh (either brodcast or unicast) */
+    /* copy negated dst into eh (either broadcast or unicast) */
     *(uint32_t *)eh = ~e->eth1;
     *(uint16_t *)((char *)eh + 4) = ~e->eth2;
     /* copy local MAC address into source */
@@ -2238,7 +2238,7 @@ set_max(const char *arg, struct _qs *q)
     return 0;
 }
 
-/* otions that can be specified for each direction */
+/* options that can be specified for each direction */
 struct dir_opt {
     char opt;
     int  flags;
@@ -2434,7 +2434,7 @@ main(int argc, char **argv)
     argc -= optind;
     argv += optind;
 
-    /* map the session area and auto-detect wether we are server or client */
+    /* map the session area and auto-detect whether we are server or client */
     ecf = ec_map(sfname, &server);
     if (ecf == NULL)
         exit(1);
diff --git a/apps/vale-ctl/vale-ctl.4 b/apps/vale-ctl/vale-ctl.4
index 09ba27121..a2ea6d693 100644
--- a/apps/vale-ctl/vale-ctl.4
+++ b/apps/vale-ctl/vale-ctl.4
@@ -97,7 +97,7 @@ The name must be different from any other network interface
 already present in the system.
 .It Fl r Ar interface
 Destroy the persistent VALE port with name
-.Ar inteface .
+.Ar interface .
 .It Fl l Ar valeSSS:PPP
 Show the internal bridge number and port number of the given switch port.
 .It Fl p Ar valeSSS:PPP
@@ -150,7 +150,7 @@ Using this option you can let them share memory with other ports.
 Pass 1 as
 .Ar memid
 to use the global memory region already shared by all
-harware netmap ports.
+hardware netmap ports.
 .El
 .Sh SEE ALSO
 .Xr netmap 4 ,
diff --git a/extra/python/pktman.py b/extra/python/pktman.py
index 4df06ada8..daa9f2429 100755
--- a/extra/python/pktman.py
+++ b/extra/python/pktman.py
@@ -235,7 +235,7 @@ def receive(idx, ifname, args, parser, queue):
         job = multiprocessing.Process(name = 'worker-' + str(i),
                                         target = handler[args.function],
                                         args = (ring_id, ifname, args, parser, queue))
-        job.deamon = True   # ensure work termination
+        job.daemon = True   # ensure work termination
         jobs.append(job)
 
     # start all the workers
diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 984ca3795..62fa36996 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -417,7 +417,7 @@ struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
  * @initial	the initial offset for all the slots
  * @maxoff	the maximum offset
  * @bits	the number of bits of slot->ptr to use for the offsets
- * @mingap	the minimum gap betwen offsets (in shared buffers)
+ * @mingap	the minimum gap between offsets (in shared buffers)
  *
  * With this option the lower @bits bits of the ptr field in the netmap_slot
  * can be used to specify an offset into the buffer.  All offsets will be set
@@ -439,7 +439,7 @@ struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
  * starting o bytes in the buffer. Note that the address of the packet must
  * comply with any alignment constraints that the port may have, or the result
  * will be undefined. The user may read the alignment constraint in the new
- * ring->buf_align field.  It is also possibile that empty slots already come
+ * ring->buf_align field.  It is also possible that empty slots already come
  * with a non-zero offset o specified in the offset field. In this case, the
  * user will have to write the packet at an offset o' >= o.
  *
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index cd652938b..a05781255 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -114,7 +114,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 		virtqueue_notify(vq);
 
 		/* Update hwcur depending on where we stopped. */
-		kring->nr_hwcur = nm_i; /* note we migth break early */
+		kring->nr_hwcur = nm_i; /* note we might break early */
 	}
 
 	/* Free used slots. We only consider our own used buffers, recognized
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a9ddb5fb5..4835c47d2 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -193,7 +193,7 @@ ports attached to the switch)
  * 	      always attached to a bridge.
  * 	      Persistent VALE ports must must be created separately, and i
  * 	      then attached like normal NICs. The NIOCREGIF we are examining
- * 	      will find them only if they had previosly been created and
+ * 	      will find them only if they had previously been created and
  * 	      attached (see VALE_CTL below).
  *
  * 	- netmap_pipe_adapter 	      [netmap_pipe.c]
@@ -994,7 +994,7 @@ netmap_mem_restore(struct netmap_adapter *na)
 static void
 netmap_mem_drop(struct netmap_adapter *na)
 {
-	/* if the native allocator had been overrided on regif,
+	/* if the native allocator had been overridden on regif,
 	 * restore it now and drop the temporary one
 	 */
 	if (netmap_mem_deref(na->nm_mem, na)) {
@@ -1072,7 +1072,7 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 		}
 	}
 
-	/* possibily decrement counter of tx_si/rx_si users */
+	/* possibly decrement counter of tx_si/rx_si users */
 	netmap_unset_ringid(priv);
 	/* delete the nifp */
 	netmap_mem_if_delete(na, priv->np_nifp);
@@ -1154,7 +1154,7 @@ netmap_dtor(void *data)
  *   they will be forwarded to the hw TX rings, saving the application
  *   from doing the same task in user-space.
  *
- * Transparent fowarding can be enabled per-ring, by setting the NR_FORWARD
+ * Transparent forwarding can be enabled per-ring, by setting the NR_FORWARD
  * flag, or globally with the netmap_fwd sysctl.
  *
  * The transfer NIC --> host is relatively easy, just encapsulate
@@ -1618,7 +1618,7 @@ netmap_get_na(struct nmreq_header *hdr,
 	netmap_adapter_get(ret);
 
 	/*
-	 * if the adapter supports the host rings and it is not alread open,
+	 * if the adapter supports the host rings and it is not already open,
 	 * try to set the number of host rings as requested by the user
 	 */
 	if (((*na)->na_flags & NAF_HOST_RINGS) && (*na)->active_fds == 0) {
@@ -2042,7 +2042,7 @@ netmap_krings_get(struct netmap_priv_d *priv)
 			priv->np_qlast[NR_RX]);
 
 	/* first round: check that all the requested rings
-	 * are neither alread exclusively owned, nor we
+	 * are neither already exclusively owned, nor we
 	 * want exclusive ownership when they are already in use
 	 */
 	foreach_selected_ring(priv, t, i, kring) {
@@ -2597,7 +2597,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	if (error)
 		goto err_rel_excl;
 
-	/* compute and validate the buf lenghts */
+	/* compute and validate the buf lengths */
 	error = netmap_compute_buf_len(priv);
 	if (error)
 		goto err_rel_excl;
@@ -2719,7 +2719,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 		}
 
 		/* Make a kernel-space copy of the user-space nr_body.
-		 * For convenince, the nr_body pointer and the pointers
+		 * For convenience, the nr_body pointer and the pointers
 		 * in the options list will be replaced with their
 		 * kernel-space counterparts. The original pointers are
 		 * saved internally and later restored by nmreq_copyout
@@ -3312,7 +3312,7 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
  * The list of options is copied and the pointers adjusted. The
  * original pointers are saved before the option they belonged.
  *
- * The option table has an entry for every availabe option.  Entries
+ * The option table has an entry for every available option.  Entries
  * for options that have not been passed contain NULL.
  *
  */
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 8701d9daf..729aee7f6 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -951,7 +951,7 @@ nm_bdg_ctl_polling_stop(struct netmap_adapter *na)
 	bps->configured = false;
 	nm_os_free(bps);
 	bna->na_polling_state = NULL;
-	/* reenable interrupts */
+	/* re-enable interrupts */
 	nma_intr_enable(bna->hwna, 1);
 	return 0;
 }
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index a47cb508d..de3fbaaff 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -264,7 +264,7 @@ nm_os_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data,
 #ifdef INET
 	uint16_t pseudolen = datalen + iph->protocol;
 
-	/* Compute and insert the pseudo-header cheksum. */
+	/* Compute and insert the pseudo-header checksum. */
 	*check = in_pseudo(iph->saddr, iph->daddr,
 				 htobe16(pseudolen));
 	/* Compute the checksum on TCP/UDP header + payload
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index f99957673..2068e9fd4 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -446,7 +446,7 @@ generic_mbuf_destructor(struct mbuf *m)
 	/*
 	 * First, clear the event mbuf.
 	 * In principle, the event 'm' should match the one stored
-	 * on ring 'r'. However we check it explicitely to stay
+	 * on ring 'r'. However we check it explicitly to stay
 	 * safe against lower layers (qdisc, driver, etc.) changing
 	 * MBUF_TXQ(m) under our feet. If the match is not found
 	 * on 'r', we try to see if it belongs to some other ring.
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 0239a3852..cc452657d 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -294,7 +294,7 @@ struct nm_bridge;
 struct netmap_priv_d;
 struct nm_bdg_args;
 
-/* os-specific NM_SELINFO_T initialzation/destruction functions */
+/* os-specific NM_SELINFO_T initialization/destruction functions */
 int nm_os_selinfo_init(NM_SELINFO_T *, const char *name);
 void nm_os_selinfo_uninit(NM_SELINFO_T *);
 
@@ -485,7 +485,7 @@ struct netmap_kring {
 	struct netmap_adapter *na;
 
 	/* the adapter that wants to be notified when this kring has
-	 * new slots avaialable. This is usually the same as the above,
+	 * new slots available. This is usually the same as the above,
 	 * but wrappers may let it point to themselves
 	 */
 	struct netmap_adapter *notify_na;
@@ -562,7 +562,7 @@ struct netmap_kring {
 	 */
 	uint64_t hwbuf_len;
 
-	/* required aligment (in bytes) for the buffers used by this ring.
+	/* required alignment (in bytes) for the buffers used by this ring.
 	 * Netmap buffers are aligned to cachelines, which should suffice
 	 * for most NICs. If the user is passing offsets, though, we need
 	 * to check that the resulting buf address complies with any
@@ -570,7 +570,7 @@ struct netmap_kring {
 	 */
 	uint64_t buf_align;
 
-	/* harware specific logic for the selection of the hwbuf_len */
+	/* hardware specific logic for the selection of the hwbuf_len */
 	int (*nm_bufcfg)(struct netmap_kring *kring, uint64_t target);
 
 	int (*save_notify)(struct netmap_kring *kring, int flags);
@@ -709,7 +709,7 @@ struct nm_config_info {
 
 /*
  * default type for the magic field.
- * May be overriden in glue code.
+ * May be overridden in glue code.
  */
 #ifndef NM_OS_MAGIC
 #define NM_OS_MAGIC uint32_t
@@ -827,7 +827,7 @@ struct netmap_adapter {
 	 *      (l) and kring->buf_align fields. The l value is most important
 	 *      for RX rings, where we want to disallow writes outside of the
 	 *      netmap buffer. The l value must be computed taking into account
-	 *      the stipulated max_offset (o), possibily increased if there are
+	 *      the stipulated max_offset (o), possibly increased if there are
 	 *      alignment constraints, the maxframe (m), if known, and the
 	 *      current NETMAP_BUF_SIZE (b) of the memory region used by the
 	 *      adapter. We want the largest supported l such that o + l <= b.
@@ -1680,7 +1680,7 @@ extern int netmap_debug;		/* for debugging */
 #define netmap_debug (0)
 #endif /* !CONFIG_NETMAP_DEBUG */
 enum {                                  /* debug flags */
-	NM_DEBUG_ON = 1,		/* generic debug messsages */
+	NM_DEBUG_ON = 1,		/* generic debug messages */
 	NM_DEBUG_HOST = 0x2,            /* debug host stack */
 	NM_DEBUG_RXSYNC = 0x10,         /* debug on rxsync/txsync */
 	NM_DEBUG_TXSYNC = 0x20,
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 0b89d89bf..8d9edd4be 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -222,7 +222,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
 			if (!a->busy_wait) {
-				/* Reenable notifications. */
+				/* Re-enable notifications. */
 				csb_ktoa_kick_enable(csb_ktoa, 1);
 			}
 			nm_prerr("txsync() failed");
@@ -267,7 +267,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 			 * go to sleep, waiting for a kick from the application when new
 			 * new slots are ready for transmission.
 			 */
-			/* Reenable notifications. */
+			/* Re-enable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Double check, with store-load memory barrier. */
 			nm_stld_barrier();
@@ -356,7 +356,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 
 		if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) {
 			if (!a->busy_wait) {
-				/* Reenable notifications. */
+				/* Re-enable notifications. */
 				csb_ktoa_kick_enable(csb_ktoa, 1);
 			}
 			nm_prerr("rxsync() failed");
@@ -402,7 +402,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 			 * go to sleep, waiting for a kick from the application when new receive
 			 * slots are available.
 			 */
-			/* Reenable notifications. */
+			/* Re-enable notifications. */
 			csb_ktoa_kick_enable(csb_ktoa, 1);
 			/* Double check, with store-load memory barrier. */
 			nm_stld_barrier();
@@ -1000,7 +1000,7 @@ netmap_pt_guest_txsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * space is available.
          */
 	if (nm_kr_wouldblock(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
-		/* Reenable notifications. */
+		/* Re-enable notifications. */
 		atok->appl_need_kick = 1;
                 /* Double check, with store-load memory barrier. */
 		nm_stld_barrier();
@@ -1061,7 +1061,7 @@ netmap_pt_guest_rxsync(struct nm_csb_atok *atok, struct nm_csb_ktoa *ktoa,
 	 * completed.
          */
 	if (nm_kr_wouldblock(kring) && !(kring->nr_kflags & NKR_NOINTR)) {
-		/* Reenable notifications. */
+		/* Re-enable notifications. */
                 atok->appl_need_kick = 1;
                 /* Double check, with store-load memory barrier. */
 		nm_stld_barrier();
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 069e0fa75..5edfc38e1 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -167,7 +167,7 @@ struct netmap_mem_d {
 
 	u_int flags;
 #define NETMAP_MEM_FINALIZED	0x1	/* preallocation done */
-#define NETMAP_MEM_HIDDEN	0x8	/* beeing prepared */
+#define NETMAP_MEM_HIDDEN	0x8	/* being prepared */
 #define NETMAP_MEM_NOMAP	0x10	/* do not map/unmap pdevs */
 	int lasterr;		/* last error for curr config */
 	int active;		/* active users */
@@ -176,7 +176,7 @@ struct netmap_mem_d {
 	struct netmap_obj_pool pools[NETMAP_POOLS_NR];
 
 	nm_memid_t nm_id;	/* allocator identifier */
-	int nm_grp;	/* iommu groupd id */
+	int nm_grp;	/* iommu group id */
 
 	/* list of all existing allocators, sorted by nm_id */
 	struct netmap_mem_d *prev, *next;
@@ -856,7 +856,7 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset)
  *
  *		2a - cycle all the objects in every pool, get the list
  *				of the physical address descriptors
- *		2b - calculate the offset in the array of pages desciptor in the
+ *		2b - calculate the offset in the array of pages descriptor in the
  *				main MDL
  *		2c - copy the descriptors of the object in the main MDL
  *
@@ -1408,7 +1408,7 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p)
 
 	if (p->lut) {
 		/* if the lut is already there we assume that also all the
-		 * clusters have already been allocated, possibily by somebody
+		 * clusters have already been allocated, possibly by somebody
 		 * else (e.g., extmem). In the latter case, the alloc_done flag
 		 * will remain at zero, so that we will not attempt to
 		 * deallocate the clusters by ourselves in
@@ -1984,7 +1984,7 @@ netmap_mem2_rings_create(struct netmap_mem_d *nmd, struct netmap_adapter *na)
 			u_int len, ndesc;
 
 			if (!netmap_mem_ring_needed(kring)) {
-				/* uneeded, or already created by somebody else */
+				/* unneeded, or already created by somebody else */
 				if (netmap_debug & NM_DEBUG_MEM)
 					nm_prinf("NOT creating ring %s (ring %p, users %d neekring %d)",
 						kring->name, ring, kring->users, kring->nr_kflags & NKR_NEEDRING);
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index c0e039b42..61eeb4569 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -57,7 +57,7 @@
  * of the object, and from there locate the offset from the beginning
  * of the region.
  *
- * The invididual allocators manage a pool of memory for objects of
+ * The individual allocators manage a pool of memory for objects of
  * the same size.
  * The pool is split into smaller clusters, whose size is a
  * multiple of the page size. The cluster size is chosen
@@ -70,7 +70,7 @@
  * Allocation scans the bitmap; this is done only on attach, so we are not
  * too worried about performance
  *
- * For each allocator we can define (thorugh sysctl) the size and
+ * For each allocator we can define (through sysctl) the size and
  * number of each object. Memory is allocated at the first use of a
  * netmap file descriptor, and can be freed when all such descriptors
  * have been released (including unmapping the memory).
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 9e5d57f7f..4827c2a75 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -483,7 +483,7 @@ netmap_monitor_stop(struct netmap_adapter *na)
 					netmap_adapter_put(next->priv.np_na); /* nop if null */
 					next->priv.np_na = NULL;
 				}
-				/* orhpan the zmon list */
+				/* orphan the zmon list */
 				if (z->next != NULL)
 					z->next->zmon_list[t].prev = NULL;
 				z->next = NULL;
@@ -601,7 +601,7 @@ netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
 	mring = mkring->ring;
 	mlim = mkring->nkr_num_slots - 1;
 
-	/* get the relased slots (rel_slots) */
+	/* get the released slots (rel_slots) */
 	if (tx == NR_TX) {
 		beg = kring->nr_hwtail + 1;
 		error = kring->mon_sync(kring, flags);
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index db3321a4f..aac4cfe67 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -578,7 +578,7 @@ do {                                                                    \
 static __inline uint32_t
 nm_vale_rthash(const uint8_t *addr)
 {
-	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hask key
+	uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = 0; // hash key
 
 	b += addr[5] << 8;
 	b += addr[4];
@@ -1369,7 +1369,7 @@ nm_vi_destroy(const char *name)
 		goto err;
 	}
 
-	/* also make sure that nobody is using the inferface */
+	/* also make sure that nobody is using the interface */
 	if (NETMAP_OWNED_BY_ANY(&vpna->up) ||
 	    vpna->up.na_refcount > 1 /* any ref besides the one in nm_vi_create()? */) {
 		error = EBUSY;
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 6bd9e0205..6561174e0 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -147,7 +147,7 @@
  *   netmap:foo*, or another registration should be done to open at least a
  *   NIC TX queue in netmap mode.
  *
- * + Netmap is not currently able to deal with intercepted trasmit mbufs which
+ * + Netmap is not currently able to deal with intercepted transmit mbufs which
  *   require offloadings like TSO, UFO, checksumming offloadings, etc. It is
  *   responsibility of the user to disable those offloadings (e.g. using
  *   ifconfig on FreeBSD or ethtool -K on Linux) for an interface that is being
@@ -311,7 +311,7 @@ struct netmap_ring {
 	/* the alignment requirement, in bytes, for the start
 	 * of the packets inside the buffers.
 	 * User programs should take this alignment into
-	 * account when specifing buffer-offsets in TX slots.
+	 * account when specifying buffer-offsets in TX slots.
 	 */
 	const uint64_t	buf_align;
 
@@ -494,7 +494,7 @@ struct netmap_if {
 
 /* Header common to all request options. */
 struct nmreq_option {
-	/* Pointer ot the next option. */
+	/* Pointer to the next option. */
 	uint64_t		nro_next;
 	/* Option type. */
 	uint32_t		nro_reqtype;
@@ -980,7 +980,7 @@ struct nmreq_opt_offsets {
 	/* optional initial offset value, to be set in all slots. */
 	uint64_t		nro_initial_offset;
 	/* number of bits in the lower part of the 'ptr' field to be
-	 * used as the offset field. On output the (possibily larger)
+	 * used as the offset field. On output the (possibly larger)
 	 * effective number of bits is returned.
 	 * 0 means: use the whole ptr field.
 	 */
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index fda076497..27f8592ee 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -55,7 +55,7 @@
  * To compute the next index in a circular ring you can use
  *	i = nm_ring_next(ring, i);
  *
- * To ease porting apps from pcap to netmap we supply a few fuctions
+ * To ease porting apps from pcap to netmap we supply a few functions
  * that can be called to open, close, read and write on netmap in a way
  * similar to libpcap. Note that the read/write function depend on
  * an ioctl()/select()/poll() being issued to refill rings or push
@@ -133,7 +133,7 @@
 		((offset) & (ring)->offset_mask); } while (0)
 
 /* obtain the start of the buffer pointed to by  a ring's slot, taking the
- * offset field into accout
+ * offset field into account
  */
 #define NETMAP_BUF_OFFSET(ring, slot)			\
 	(NETMAP_BUF(ring, (slot)->buf_idx) + NETMAP_ROFFSET(ring, slot))
@@ -322,7 +322,7 @@ typedef void (*nm_cb_t)(u_char *, const struct nm_pkthdr *, const u_char *d);
  * nm_open() opens a file descriptor, binds to a port and maps memory.
  *
  * ifname	(netmap:foo or vale:foo) is the port name
- *		a suffix can indicate the follwing:
+ *		a suffix can indicate the following:
  *		^		bind the host (sw) ring pair
  *		*		bind host and NIC ring pairs
  *		-NN		bind individual NIC ring pair
@@ -701,7 +701,7 @@ nm_parse(const char *ifname, struct nm_desc *d, char *err)
 				nr_flags = NR_REG_PIPE_MASTER;
 				p_state = P_GETNUM;
 				break;
-			case '}': /* pipe (slave endoint) */
+			case '}': /* pipe (slave endpoint) */
 				nr_flags = NR_REG_PIPE_SLAVE;
 				p_state = P_GETNUM;
 				break;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fac920547..41e75ab1f 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -842,7 +842,7 @@ pipe_slave(struct TestContext *ctx)
 }
 
 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
- * registration request used internall by netmap. */
+ * registration request used internally by netmap. */
 static int
 pipe_port_info_get(struct TestContext *ctx)
 {
@@ -1761,7 +1761,7 @@ static struct nmreq_parse_test nmreq_parse_tests[] = {
 	 *       err > 0 => nmreq_header_parse should fail with the given error
 	 *       err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
 	 *       		   fail with error |err|
-	 *       err = 0 => should succeeed
+	 *       err = 0 => should succeed
 	 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
 	 *   	nmreq_register struct in case of success
 	 */
@@ -1898,7 +1898,7 @@ nmreq_reg_parsing(struct TestContext *ctx,
 			}
 			return 0;
 		}
-		printf ("!!! parse failed but it should have succeded\n");
+		printf ("!!! parse failed but it should have succeeded\n");
 		return -1;
 	}
 	if (t->exp_error < 0) {
@@ -1950,7 +1950,7 @@ nmreq_parsing(struct TestContext *ctx)
 
 	nmctx = nmctx_get();
 	if (nmctx == NULL) {
-		printf("Failed to aquire nmctx: %s", strerror(errno));
+		printf("Failed to acquire nmctx: %s", strerror(errno));
 		return -1;
 	}
 	test_nmctx = *nmctx;
diff --git a/utils/fd_server-legacy.c b/utils/fd_server-legacy.c
index b895b99ed..2f2862a11 100644
--- a/utils/fd_server-legacy.c
+++ b/utils/fd_server-legacy.c
@@ -239,7 +239,7 @@ handle_request(int accept_socket, int listen_socket)
 
 	ret = send_fd(accept_socket, fd, &res, sizeof(struct fd_response));
 	if (ret == -1) {
-		printf("error while sending the reponse\n");
+		printf("error while sending the response\n");
 	}
 	return ret;
 }
diff --git a/utils/fd_server.c b/utils/fd_server.c
index ea882d17a..61a0dc9fc 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -262,7 +262,7 @@ handle_request(int accept_socket, int listen_socket)
 
 	ret = send_fd(accept_socket, fd, &res, sizeof(res));
 	if (ret == -1) {
-		msg("error while sending the reponse\n");
+		msg("error while sending the response\n");
 	}
 	return ret;
 }
diff --git a/utils/functional-legacy.c b/utils/functional-legacy.c
index 6c6c6eec2..7b84823de 100644
--- a/utils/functional-legacy.c
+++ b/utils/functional-legacy.c
@@ -661,7 +661,7 @@ rx(struct Global *g, unsigned packets_num)
 				goto again;
 			}
 
-			/* As soon as we find a packet wich doesn't match our
+			/* As soon as we find a packet which doesn't match our
 			 * packet model we exit with status EXIT_FAILURE.
 			 */
 			if (rx_check(g)) {
@@ -794,7 +794,7 @@ usage(FILE *stream)
 	        "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	        "    [-T TIMEOUT_SECS (=1)]\n"
 	        "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
-	        "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
+	        "    [-t LEN[:FILLCHAR[:NUM]] (transmit NUM packets with size "
 	        "LEN bytes)]\n"
 	        "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	        "with size LEN bytes)]\n"
@@ -1040,7 +1040,7 @@ stop_fd_server(struct Global *g)
 	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
 		verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
-		              "fd_server alredy down\n");
+		              "fd_server already down\n");
 		return;
 	}
 	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
@@ -1055,7 +1055,7 @@ stop_fd_server(struct Global *g)
 	/* By calling recv() we synchronize with the fd_server closing the
 	 * socket.
 	 * This way we're sure that during the next call to ./functional
-	 * the fd_server has alredy closed its end and we avoid a possible race
+	 * the fd_server has already closed its end and we avoid a possible race
 	 * condition. Otherwise the call to functional might connect to the
 	 * previous fd_server backlog.
 	 */
@@ -1159,7 +1159,7 @@ swap_in_extra_buffers(struct Global *g)
 
 /* We only re-build the extra buffers list, as requested from netmap. We don't
  * undo the swapping that we did at the start of the program to swap in the
- * extra buffer. This probably leaves the netmap adapter in an incosistent
+ * extra buffer. This probably leaves the netmap adapter in an inconsistent
  * state, that's why we only support this option for interfaces requested
  * directly.
  */
diff --git a/utils/functional.c b/utils/functional.c
index 231a271a6..ed20fd920 100644
--- a/utils/functional.c
+++ b/utils/functional.c
@@ -659,7 +659,7 @@ rx(struct Global *g, unsigned packets_num)
 				goto again;
 			}
 
-			/* As soon as we find a packet wich doesn't match our
+			/* As soon as we find a packet which doesn't match our
 			 * packet model we exit with status EXIT_FAILURE.
 			 */
 			if (rx_check(g)) {
@@ -792,7 +792,7 @@ usage(FILE *stream)
 	        "    [-F MAX_FRAGMENT_SIZE (=inf)]\n"
 	        "    [-T TIMEOUT_SECS (=1)]\n"
 	        "    [-w WAIT_FOR_LINK_SECS (=0)]\n"
-	        "    [-t LEN[:FILLCHAR[:NUM]] (trasmit NUM packets with size "
+	        "    [-t LEN[:FILLCHAR[:NUM]] (transmit NUM packets with size "
 	        "LEN bytes)]\n"
 	        "    [-r LEN[:FILLCHAR[:NUM]] (expect to receive NUM packets "
 	        "with size LEN bytes)]\n"
@@ -1008,7 +1008,7 @@ stop_fd_server(struct Global *g)
 	socket_fd = connect_to_fd_server(g);
 	if (socket_fd == -1) {
 		verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
-		              "fd_server alredy down\n");
+		              "fd_server already down\n");
 		return;
 	}
 	verbose_print(g->verbosity_level, LV_DEBUG_SEND_RECV,
@@ -1023,7 +1023,7 @@ stop_fd_server(struct Global *g)
 	/* By calling recv() we synchronize with the fd_server closing the
 	 * socket.
 	 * This way we're sure that during the next call to ./functional
-	 * the fd_server has alredy closed its end and we avoid a possible race
+	 * the fd_server has already closed its end and we avoid a possible race
 	 * condition. Otherwise the call to functional might connect to the
 	 * previous fd_server backlog.
 	 */
@@ -1127,7 +1127,7 @@ swap_in_extra_buffers(struct Global *g)
 
 /* We only re-build the extra buffers list, as requested from netmap. We don't
  * undo the swapping that we did at the start of the program to swap in the
- * extra buffer. This probably leaves the netmap adapter in an incosistent
+ * extra buffer. This probably leaves the netmap adapter in an inconsistent
  * state, that's why we only support this option for interfaces requested
  * directly.
  */
diff --git a/utils/switch-modules/ovs-2.4.0/0001-datapath-netmap-VALE-support.patch b/utils/switch-modules/ovs-2.4.0/0001-datapath-netmap-VALE-support.patch
index e1fd4f2a7..dcf26b660 100644
--- a/utils/switch-modules/ovs-2.4.0/0001-datapath-netmap-VALE-support.patch
+++ b/utils/switch-modules/ovs-2.4.0/0001-datapath-netmap-VALE-support.patch
@@ -15,7 +15,7 @@ index 000000000..664078ed3
 +This file explains how to install and use the Open vSwitch with VALE.
 +
 +The VALE support for Open vSwitch is **experimental**: it has not
-+been throughly tested.
++been thoroughly tested.
 +It currently supports only netdev (including internal one) and VXLAN
 +vport types.
 +
@@ -60,7 +60,7 @@ index 000000000..664078ed3
 +# modprobe netmap
 +# modprobe openvswitch
 +
-+(2) Run the openvswitch deamon. This step may be performed differently on
++(2) Run the openvswitch daemon. This step may be performed differently on
 +different distributions. Refer to the OVS documentation.
 +
 +(3) Create an OVS bridge:
@@ -77,7 +77,7 @@ index 000000000..664078ed3
 +# ovs-vsctl add-port br0 vi0
 +# ovs-vsctl add-port br0 vi1
 +
-+(6) Add some OpenFlow rules, to forward traffic betweeen vi0 and vi1
++(6) Add some OpenFlow rules, to forward traffic between vi0 and vi1
 +(assuming the port identifiers are 1 and 2):
 +
 +# ovs-ofctl add-flow br0 in_port=1,actions=output:2
diff --git a/utils/switch-modules/ovs-2.6.1/0001-datapath-netmap-VALE-support.patch b/utils/switch-modules/ovs-2.6.1/0001-datapath-netmap-VALE-support.patch
index 1372e0dd5..e37518c56 100644
--- a/utils/switch-modules/ovs-2.6.1/0001-datapath-netmap-VALE-support.patch
+++ b/utils/switch-modules/ovs-2.6.1/0001-datapath-netmap-VALE-support.patch
@@ -15,7 +15,7 @@ index 000000000..7cf02e45e
 +This file explains how to install and use the Open vSwitch with VALE.
 +
 +The VALE support for Open vSwitch is **experimental**: it has not
-+been throughly tested.
++been thoroughly tested.
 +It currently supports only netdev (including internal one) and VXLAN
 +vport types.
 +
@@ -60,7 +60,7 @@ index 000000000..7cf02e45e
 +# modprobe netmap
 +# modprobe openvswitch
 +
-+(2) Run the openvswitch deamon. This step may be performed differently on
++(2) Run the openvswitch daemon. This step may be performed differently on
 +different distributions. Refer to the OVS documentation.
 +
 +(3) Create an OVS bridge:
@@ -77,7 +77,7 @@ index 000000000..7cf02e45e
 +# ovs-vsctl add-port br0 vi0
 +# ovs-vsctl add-port br0 vi1
 +
-+(6) Add some OpenFlow rules, to forward traffic betweeen vi0 and vi1
++(6) Add some OpenFlow rules, to forward traffic between vi0 and vi1
 +(assuming the port identifiers are 1 and 2):
 +
 +# ovs-ofctl add-flow br0 in_port=1,actions=output:2

From c9c823fe7c6340da4a31de7cf6fb81142bc7f777 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Fri, 2 Apr 2021 12:40:35 +0200
Subject: [PATCH 1951/2207] nm_mmap: check if mmap has already been done

---
 sys/net/netmap_user.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 27f8592ee..06b159d9b 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -995,7 +995,8 @@ nm_close(struct nm_desc *d)
 static int
 nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
 {
-	//XXX TODO: check if mmap is already done
+	if (d->done_mmap)
+		return 0;
 
 	if (IS_NETMAP_DESC(parent) && parent->mem &&
 	    parent->req.nr_arg2 == d->req.nr_arg2) {

From 1fbbc5f18c968a4d65aa674df85e5c91245a7ca1 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Fri, 2 Apr 2021 16:28:14 +0200
Subject: [PATCH 1952/2207] libnetmap: fix errno logic in
 nmreq_register_decode()

---
 libnetmap/nmreq.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index d9326052e..8df02aefa 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -255,6 +255,8 @@ nmreq_register_decode(const char **pifname, struct nmreq_register *r, struct nmc
 	uint16_t nr_ringid;
 	uint64_t nr_flags;
 
+	errno = 0;
+
 	/* fill the request */
 
 	p_state = P_START;

From c8c437daf43000f308776ea9722b2d4e2d393665 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Mon, 5 Apr 2021 12:44:02 +0200
Subject: [PATCH 1953/2207] emulated netmap: add support for NAF_OFFSETS

---
 sys/dev/netmap/netmap_generic.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 2068e9fd4..87810f7c7 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -691,15 +691,16 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 
 		while (nm_i != head) {
 			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t offset = nm_get_offset(kring, slot);
+			void *addr = NMB_O(kring, slot);
 			u_int len = slot->len;
-			void *addr = NMB(na, slot);
 			/* device-specific */
 			struct mbuf *m;
 			int tx_ret;
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
-			/* Tale a mbuf from the tx pool (replenishing the pool
+			/* Take a mbuf from the tx pool (replenishing the pool
 			 * entry if necessary) and copy in the user packet. */
 			m = kring->tx_pool[nm_i];
 			if (unlikely(m == NULL)) {
@@ -779,7 +780,7 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 			nm_os_generic_xmit_frame(&a);
 		}
 		/* Update hwcur to the next slot to transmit. Here nm_i
-		 * is not necessarily head, we could break early. */
+		 * is not necessarily head, as we could break early. */
 		kring->nr_hwcur = nm_i;
 
 #ifdef __FreeBSD__
@@ -977,8 +978,7 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags)
 	nm_i = kring->nr_hwtail;
 
 	for (;;) {
-		void *nmaddr;
-		int ofs = 0;
+		int mbuf_ofs = 0;
 		int morefrag;
 
 		m = mbq_dequeue(&tmpq);
@@ -987,8 +987,10 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags)
 		}
 
 		do {
-			nmaddr = NMB(na, &ring->slot[nm_i]);
-			/* We only check the address here on generic rx rings. */
+			struct netmap_slot *slot = ring->slot + nm_i;
+			uint64_t nm_offset = nm_get_offset(kring, slot);
+			void *nmaddr = NMB(na, slot);
+
 			if (nmaddr == NETMAP_BUF_BASE(na)) { /* Bad buffer */
 				m_freem(m);
 				mbq_purge(&tmpq);
@@ -996,10 +998,10 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags)
 				return netmap_ring_reinit(kring);
 			}
 
-			copy = ring->slot[nm_i].len;
-			m_copydata(m, ofs, copy, nmaddr);
-			ofs += copy;
-			morefrag = ring->slot[nm_i].flags & NS_MOREFRAG;
+			copy = slot->len;
+			m_copydata(m, mbuf_ofs, copy, nmaddr + nm_offset);
+			mbuf_ofs += copy;
+			morefrag = slot->flags & NS_MOREFRAG;
 			nm_i = nm_next(nm_i, lim);
 		} while (morefrag);
 
@@ -1111,7 +1113,7 @@ generic_netmap_attach(struct ifnet *ifp)
 	/* when using generic, NAF_NETMAP_ON is set so we force
 	 * NAF_SKIP_INTR to use the regular interrupt handler
 	 */
-	na->na_flags = NAF_SKIP_INTR | NAF_HOST_RINGS;
+	na->na_flags = NAF_SKIP_INTR | NAF_HOST_RINGS | NAF_OFFSETS;
 
 	nm_prdis("[GNA] num_tx_queues(%d), real_num_tx_queues(%d), len(%lu)",
 			ifp->num_tx_queues, ifp->real_num_tx_queues,

From 186898a7a4f530e27c6506af2f58f2edeee52921 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Apr 2021 17:38:56 +0200
Subject: [PATCH 1954/2207] always initialize ni_bufs_head in netmap_if

ni_bufs_head was not properly initialized when no external buffers were
requestedx and contained the ni_bufs_head from the last request. This
was causing spurious buffer frees when alternating between apps that
used external buffers and apps that did not use them.
---
 LINUX/if_e1000_netmap.h      |  9 ++++++++
 LINUX/if_e1000e_netmap.h     |  9 ++++++++
 LINUX/if_igb_netmap.h        | 10 ++++++++
 sys/dev/netmap/netmap.c      | 45 +++++++++++++++++++++++++++---------
 sys/dev/netmap/netmap_kern.h |  1 -
 5 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index a8b0864a7..227d238d4 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -332,14 +332,23 @@ e1000_netmap_get_rctl(uint32_t bufsize)
 static int
 e1000_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
+	struct SOFTC_T *adapter = netdev_priv(kring->na->ifp);
+	struct e1000_hw *hw = &adapter->hw;
 	uint64_t bufsz;
 	struct e1000_netmap_szdesc *sz;
+	uint32_t rctl;
 
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
 
+	rctl = er32(RCTL);
+	if (!(rctl & (E1000_RCTL_LPE|E1000_RCTL_SBP))) {
+		if (hw->max_frame_size < target)
+			target = kring->offset_gap;
+	}
+
 	bufsz = 0;
 	for (sz = e1000_netmap_bufsize; sz->bufsize; sz++)
 		if (sz->bufsize <= target) {
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index cfbba6729..c347a1cdc 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -144,14 +144,23 @@ e1000e_netmap_get_rctl(uint32_t bufsize)
 static int
 e1000e_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
+	struct SOFTC_T *adapter = netdev_priv(kring->na->ifp);
+	struct e1000_hw *hw = &adapter->hw;
 	uint64_t bufsz;
 	struct e1000e_netmap_szdesc *sz;
+	uint32_t rctl;
 
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
 
+	rctl = er32(RCTL);
+	if (!(rctl & (E1000_RCTL_LPE|E1000_RCTL_SBP))) {
+		if (adapter->max_frame_size < target)
+			target = kring->offset_gap;
+	}
+
 	bufsz = 0;
 	for (sz = e1000e_netmap_bufsize; sz->bufsize; sz++)
 		if (sz->bufsize <= target) {
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index e63982a7e..76d3d3a5f 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -425,11 +425,21 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 static int
 igb_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
+	struct SOFTC_T *adapter = netdev_priv(kring->na->ifp);
+	struct igb_ring* rxr = adapter->rx_ring[kring->ring_id];
+	uint32_t rctl;
+
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
 
+	rctl = READ_RCTL(adapter, rxr);
+	if (!(rctl & (E1000_RCTL_LPE|E1000_RCTL_SBP))) {
+		if (adapter->max_frame_size < target)
+			target = kring->offset_gap;
+	}
+
 	target >>= 10;
 	if (target >= 1 && target <= 16) {
 		target <<= 10;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4835c47d2..0073d49cf 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2381,6 +2381,11 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 }
 
+/* set the hardware buffer length in each one of the newly opened rings
+ * (hwbuf_len field in the kring struct). The purpose it to select
+ * the maximum supported input buffer lenght that will not cause writes
+ * outside of the available space, even when offsets are in use.
+ */
 static int
 netmap_compute_buf_len(struct netmap_priv_d *priv)
 {
@@ -2390,32 +2395,48 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 	int error = 0;
 	unsigned mtu = 0;
 	struct netmap_adapter *na = priv->np_na;
-	uint64_t target, maxframe;
+	uint64_t target;
 
 	if (na->ifp != NULL)
 		mtu = nm_os_ifnet_mtu(na->ifp);
 
 	foreach_selected_ring(priv, t, i, kring) {
-
+		/* rings that are already active have their hwbuf_len
+		 * already set and we cannot change it.
+		 */
 		if (kring->users > 1)
 			continue;
 
+		/* For netmap buffers which are not shared among several ring
+		 * slots (the normal case), the available space is the buf size
+		 * minus the max offset declared by the user at open time.  If
+		 * the user plans to have several slots pointing to different
+		 * offsets into the same large buffer, she must also declare a
+		 * "minium gap" between two such consecutive offsets. In this
+		 * case the user-declared 'offset_gap' is taken as the
+		 * available space and offset_max is ignored.
+		 */
+
+		/* start with the normal case (unshared buffers) */
 		target = NETMAP_BUF_SIZE(kring->na) -
 			kring->offset_max;
+		/* if offset_gap is zero, the user does not intend to use
+		 * shared buffers. In this case the minimum gap between
+		 * two consective offsets into the same buffer can be
+		 * assumed to be equal to the buffer size. In this way
+		 * offset_gap always contains the available space ignoring
+		 * offset_max. This may be used by drivers of NICs that
+		 * are guaranteed to never write more than MTU bytes, even
+		 * if the input buffer is larger: if the MTU is less
+		 * than the target they can set hwbuf_len to offset_gap.
+		 * (see nm_mtu_safe_rx() above).
+		 */
 		if (!kring->offset_gap)
 			kring->offset_gap =
 				NETMAP_BUF_SIZE(kring->na);
+
 		if (kring->offset_gap < target)
 			target = kring->offset_gap;
-
-		if (mtu) {
-			maxframe = mtu + ETH_HLEN +
-				ETH_FCS_LEN + VLAN_HLEN;
-			if (maxframe < target) {
-				target = maxframe;
-			}
-		}
-
 		error = kring->nm_bufcfg(kring, target);
 		if (error)
 			goto out;
@@ -2840,6 +2861,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						&nifp->ni_bufs_head, req->nr_extra_bufs);
 					if (netmap_verbose)
 						nm_prinf("got %d extra buffers", req->nr_extra_bufs);
+				} else {
+					nifp->ni_bufs_head = 0;
 				}
 				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index cc452657d..72c598e88 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2021,7 +2021,6 @@ PNMB_O(struct netmap_kring *kring, struct netmap_slot *slot, uint64_t *pp)
 	return addr;
 }
 
-
 /*
  * Structure associated to each netmap file descriptor.
  * It is created on open and left unbound (np_nifp == NULL).

From 758facced9df4b61fd4f12eb0a255a0f5e1b50b4 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Thu, 8 Apr 2021 17:40:40 +0100
Subject: [PATCH 1955/2207] freebsd: compile error

---
 sys/dev/netmap/netmap_generic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 87810f7c7..ec86c4dd7 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -989,7 +989,7 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags)
 		do {
 			struct netmap_slot *slot = ring->slot + nm_i;
 			uint64_t nm_offset = nm_get_offset(kring, slot);
-			void *nmaddr = NMB(na, slot);
+			char *nmaddr = NMB(na, slot);
 
 			if (nmaddr == NETMAP_BUF_BASE(na)) { /* Bad buffer */
 				m_freem(m);

From af52484f2e8c42103ad0c492d09d9775d5f0a67e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 10 Apr 2021 14:01:01 +0200
Subject: [PATCH 1956/2207] make sure rings are disabled during resets

This patch explicitly disables ring synchronization before calling
callbacks that may result in a hardware reset.

Before this patch we relied on capturing the down/up events which,
however, may not be issued by all drivers.
---
 sys/dev/netmap/netmap.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0073d49cf..e9bc42fe9 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1032,7 +1032,9 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 #endif
 
 	if (na->active_fds <= 0 || nm_kring_pending(priv)) {
+		netmap_set_all_rings(na, NR_KR_LOCKED);
 		na->nm_register(na, 0);
+		netmap_set_all_rings(na, 0);
 	}
 
 	/* delete rings and buffers that are no longer needed */
@@ -2633,7 +2635,9 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	if (nm_kring_pending(priv)) {
 		/* Some kring is switching mode, tell the adapter to
 		 * react on this. */
+		netmap_set_all_rings(na, NM_KR_LOCKED);
 		error = na->nm_register(na, 1);
+		netmap_set_all_rings(na, 0);
 		if (error)
 			goto err_del_if;
 	}

From 0ded584c10ed8d03e8f0843a202979f9ec5ca3d7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 10 Apr 2021 14:28:57 +0200
Subject: [PATCH 1957/2207] properly update host-rings mode

Before this patch, the mode (ON/OFF) of all the host rings beyond the
first one for each direction where not being updated during
regif/unregif. This was causing spurious calls to nm_register() which,
for hardware ports, was in turn triggering unnecessary hardware resets.

This affected only applications that were using the "multiple host-rings"
feature.
---
 sys/dev/netmap/netmap.c      | 28 +++++++++++++++++++++++++---
 sys/dev/netmap/netmap_kern.h | 10 ----------
 2 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e9bc42fe9..f3b513a0b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1002,6 +1002,22 @@ netmap_mem_drop(struct netmap_adapter *na)
 	}
 }
 
+static void
+netmap_update_hostrings_mode(struct netmap_adapter *na)
+{
+	enum txrx t;
+	struct netmap_kring *kring;
+	int i;
+
+	for_rx_tx(t) {
+		for (i = nma_get_nrings(na, t);
+		     i < netmap_real_rings(na, t); i++) {
+			kring = NMR(na, t)[i];
+			kring->nr_mode = kring->nr_pending_mode;
+		}
+	}
+}
+
 /*
  * Undo everything that was done in netmap_do_regif(). In particular,
  * call nm_register(ifp,0) to stop netmap mode on the interface and
@@ -1031,8 +1047,10 @@ netmap_do_unregif(struct netmap_priv_d *priv)
 	}
 #endif
 
+	netmap_update_hostrings_mode(na);
+
 	if (na->active_fds <= 0 || nm_kring_pending(priv)) {
-		netmap_set_all_rings(na, NR_KR_LOCKED);
+		netmap_set_all_rings(na, NM_KR_LOCKED);
 		na->nm_register(na, 0);
 		netmap_set_all_rings(na, 0);
 	}
@@ -2632,6 +2650,11 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 		goto err_rel_excl;
 	}
 
+	/* make sure we don't call na->nm_register() when only
+	 * host rings are changing mode
+	 */
+	netmap_update_hostrings_mode(na);
+
 	if (nm_kring_pending(priv)) {
 		/* Some kring is switching mode, tell the adapter to
 		 * react on this. */
@@ -2659,6 +2682,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	netmap_mem_if_delete(na, nifp);
 err_rel_excl:
 	netmap_krings_put(priv);
+	netmap_update_hostrings_mode(na);
 	netmap_mem_rings_delete(na);
 err_del_krings:
 	if (na->active_fds == 0)
@@ -4500,7 +4524,6 @@ nm_set_native_flags(struct netmap_adapter *na)
 
 	na->na_flags |= NAF_NETMAP_ON;
 	nm_os_onenter(ifp);
-	nm_update_hostrings_mode(na);
 }
 
 void
@@ -4514,7 +4537,6 @@ nm_clear_native_flags(struct netmap_adapter *na)
 		return;
 	}
 
-	nm_update_hostrings_mode(na);
 	nm_os_onexit(ifp);
 
 	na->na_flags &= ~NAF_NETMAP_ON;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 72c598e88..8f65c813e 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1435,16 +1435,6 @@ nm_iszombie(struct netmap_adapter *na)
 	return na == NULL || (na->na_flags & NAF_ZOMBIE);
 }
 
-static inline void
-nm_update_hostrings_mode(struct netmap_adapter *na)
-{
-	/* Process nr_mode and nr_pending_mode for host rings. */
-	na->tx_rings[na->num_tx_rings]->nr_mode =
-		na->tx_rings[na->num_tx_rings]->nr_pending_mode;
-	na->rx_rings[na->num_rx_rings]->nr_mode =
-		na->rx_rings[na->num_rx_rings]->nr_pending_mode;
-}
-
 void nm_set_native_flags(struct netmap_adapter *);
 void nm_clear_native_flags(struct netmap_adapter *);
 

From e58a2d6af184adef1f1e03c4ae0e2067c3bdc9a0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 10 Apr 2021 14:57:55 +0200
Subject: [PATCH 1958/2207] Revert "always initialize ni_bufs_head in
 netmap_if"

This reverts commit 186898a7a4f530e27c6506af2f58f2edeee52921.
---
 LINUX/if_e1000_netmap.h      |  9 --------
 LINUX/if_e1000e_netmap.h     |  9 --------
 LINUX/if_igb_netmap.h        | 10 --------
 sys/dev/netmap/netmap.c      | 45 +++++++++---------------------------
 sys/dev/netmap/netmap_kern.h |  1 +
 5 files changed, 12 insertions(+), 62 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 227d238d4..a8b0864a7 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -332,23 +332,14 @@ e1000_netmap_get_rctl(uint32_t bufsize)
 static int
 e1000_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct SOFTC_T *adapter = netdev_priv(kring->na->ifp);
-	struct e1000_hw *hw = &adapter->hw;
 	uint64_t bufsz;
 	struct e1000_netmap_szdesc *sz;
-	uint32_t rctl;
 
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
 
-	rctl = er32(RCTL);
-	if (!(rctl & (E1000_RCTL_LPE|E1000_RCTL_SBP))) {
-		if (hw->max_frame_size < target)
-			target = kring->offset_gap;
-	}
-
 	bufsz = 0;
 	for (sz = e1000_netmap_bufsize; sz->bufsize; sz++)
 		if (sz->bufsize <= target) {
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index c347a1cdc..cfbba6729 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -144,23 +144,14 @@ e1000e_netmap_get_rctl(uint32_t bufsize)
 static int
 e1000e_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct SOFTC_T *adapter = netdev_priv(kring->na->ifp);
-	struct e1000_hw *hw = &adapter->hw;
 	uint64_t bufsz;
 	struct e1000e_netmap_szdesc *sz;
-	uint32_t rctl;
 
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
 
-	rctl = er32(RCTL);
-	if (!(rctl & (E1000_RCTL_LPE|E1000_RCTL_SBP))) {
-		if (adapter->max_frame_size < target)
-			target = kring->offset_gap;
-	}
-
 	bufsz = 0;
 	for (sz = e1000e_netmap_bufsize; sz->bufsize; sz++)
 		if (sz->bufsize <= target) {
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 76d3d3a5f..e63982a7e 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -425,21 +425,11 @@ igb_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
 static int
 igb_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
 {
-	struct SOFTC_T *adapter = netdev_priv(kring->na->ifp);
-	struct igb_ring* rxr = adapter->rx_ring[kring->ring_id];
-	uint32_t rctl;
-
 	if (kring->tx == NR_TX) {
 		kring->hwbuf_len = target;
 		return 0;
 	}
 
-	rctl = READ_RCTL(adapter, rxr);
-	if (!(rctl & (E1000_RCTL_LPE|E1000_RCTL_SBP))) {
-		if (adapter->max_frame_size < target)
-			target = kring->offset_gap;
-	}
-
 	target >>= 10;
 	if (target >= 1 && target <= 16) {
 		target <<= 10;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index f3b513a0b..dee578b7b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2401,11 +2401,6 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 }
 
-/* set the hardware buffer length in each one of the newly opened rings
- * (hwbuf_len field in the kring struct). The purpose it to select
- * the maximum supported input buffer lenght that will not cause writes
- * outside of the available space, even when offsets are in use.
- */
 static int
 netmap_compute_buf_len(struct netmap_priv_d *priv)
 {
@@ -2415,48 +2410,32 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 	int error = 0;
 	unsigned mtu = 0;
 	struct netmap_adapter *na = priv->np_na;
-	uint64_t target;
+	uint64_t target, maxframe;
 
 	if (na->ifp != NULL)
 		mtu = nm_os_ifnet_mtu(na->ifp);
 
 	foreach_selected_ring(priv, t, i, kring) {
-		/* rings that are already active have their hwbuf_len
-		 * already set and we cannot change it.
-		 */
+
 		if (kring->users > 1)
 			continue;
 
-		/* For netmap buffers which are not shared among several ring
-		 * slots (the normal case), the available space is the buf size
-		 * minus the max offset declared by the user at open time.  If
-		 * the user plans to have several slots pointing to different
-		 * offsets into the same large buffer, she must also declare a
-		 * "minium gap" between two such consecutive offsets. In this
-		 * case the user-declared 'offset_gap' is taken as the
-		 * available space and offset_max is ignored.
-		 */
-
-		/* start with the normal case (unshared buffers) */
 		target = NETMAP_BUF_SIZE(kring->na) -
 			kring->offset_max;
-		/* if offset_gap is zero, the user does not intend to use
-		 * shared buffers. In this case the minimum gap between
-		 * two consective offsets into the same buffer can be
-		 * assumed to be equal to the buffer size. In this way
-		 * offset_gap always contains the available space ignoring
-		 * offset_max. This may be used by drivers of NICs that
-		 * are guaranteed to never write more than MTU bytes, even
-		 * if the input buffer is larger: if the MTU is less
-		 * than the target they can set hwbuf_len to offset_gap.
-		 * (see nm_mtu_safe_rx() above).
-		 */
 		if (!kring->offset_gap)
 			kring->offset_gap =
 				NETMAP_BUF_SIZE(kring->na);
-
 		if (kring->offset_gap < target)
 			target = kring->offset_gap;
+
+		if (mtu) {
+			maxframe = mtu + ETH_HLEN +
+				ETH_FCS_LEN + VLAN_HLEN;
+			if (maxframe < target) {
+				target = maxframe;
+			}
+		}
+
 		error = kring->nm_bufcfg(kring, target);
 		if (error)
 			goto out;
@@ -2889,8 +2868,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						&nifp->ni_bufs_head, req->nr_extra_bufs);
 					if (netmap_verbose)
 						nm_prinf("got %d extra buffers", req->nr_extra_bufs);
-				} else {
-					nifp->ni_bufs_head = 0;
 				}
 				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 8f65c813e..5d8957241 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2011,6 +2011,7 @@ PNMB_O(struct netmap_kring *kring, struct netmap_slot *slot, uint64_t *pp)
 	return addr;
 }
 
+
 /*
  * Structure associated to each netmap file descriptor.
  * It is created on open and left unbound (np_nifp == NULL).

From 4cf0616550f527bd2bff2ec00d515d42161cb914 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 7 Apr 2021 17:38:56 +0200
Subject: [PATCH 1959/2207] always initialize ni_bufs_head in netmap_if

ni_bufs_head was not properly initialized when no external buffers were
requestedx and contained the ni_bufs_head from the last request. This
was causing spurious buffer frees when alternating between apps that
used external buffers and apps that did not use them.
---
 sys/dev/netmap/netmap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index dee578b7b..13c412f3b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2868,6 +2868,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 						&nifp->ni_bufs_head, req->nr_extra_bufs);
 					if (netmap_verbose)
 						nm_prinf("got %d extra buffers", req->nr_extra_bufs);
+				} else {
+					nifp->ni_bufs_head = 0;
 				}
 				req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
 

From bf116f8e35b4d914afe14ba8d7ee3e89ee6e2ab3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 10 Apr 2021 17:11:48 +0200
Subject: [PATCH 1960/2207] use safer defaults for hwbuf_len and partially
 revert cecc4c06d8

We must make sure that incoming packets will never overflow the netmap
buffers, even when the user is using the offset feature. In the typical
scenario, the netmap buffer is 2KiB and, with an MTU of 1500, there are
~500 bytes available for user offsets.

Unfortunately, some NICs accept incoming packets even when they are
larger then the MTU. This means that the only way to stop DMA from
overflowing the netmap buffers, when offsets are allowed, is to choose
an hardware buffer lenght which is smaller than the netmap buffer
lenght. For most NICs and for 2KiB netmap buffers, this means 1024
bytes, which is unconveniently small.

The current code, due to a regression introduced in commit cecc4c06d8,
will select the small hardware buf size even when offsets are not
in use. The main purpose of this patch is to fix this bug by returning
to the normal behavior for the no-offsets case.

At the same time, the patch pushes the handling of the offset case
to the lower level driver code, so that it can be made NIC-specific
(in future patches).
---
 sys/dev/netmap/netmap.c | 46 ++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 13c412f3b..69ed05477 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2401,6 +2401,12 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 }
 
+
+/* set the hardware buffer length in each one of the newly opened rings
+ * (hwbuf_len field in the kring struct). The purpose it to select
+ * the maximum supported input buffer lenght that will not cause writes
+ * outside of the available space, even when offsets are in use.
+ */
 static int
 netmap_compute_buf_len(struct netmap_priv_d *priv)
 {
@@ -2410,32 +2416,44 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 	int error = 0;
 	unsigned mtu = 0;
 	struct netmap_adapter *na = priv->np_na;
-	uint64_t target, maxframe;
-
-	if (na->ifp != NULL)
-		mtu = nm_os_ifnet_mtu(na->ifp);
+	uint64_t target;
 
 	foreach_selected_ring(priv, t, i, kring) {
-
+		/* rings that are already active have their hwbuf_len
+		 * already set and we cannot change it.
+		 */
 		if (kring->users > 1)
 			continue;
 
+		/* For netmap buffers which are not shared among several ring
+		 * slots (the normal case), the available space is the buf size
+		 * minus the max offset declared by the user at open time.  If
+		 * the user plans to have several slots pointing to different
+		 * offsets into the same large buffer, she must also declare a
+		 * "minium gap" between two such consecutive offsets. In this
+		 * case the user-declared 'offset_gap' is taken as the
+		 * available space and offset_max is ignored.
+		 */
+
+		/* start with the normal case (unshared buffers) */
 		target = NETMAP_BUF_SIZE(kring->na) -
 			kring->offset_max;
+		/* if offset_gap is zero, the user does not intend to use
+		 * shared buffers. In this case the minimum gap between
+		 * two consective offsets into the same buffer can be
+		 * assumed to be equal to the buffer size. In this way
+		 * offset_gap always contains the available space ignoring
+		 * offset_max. This may be used by drivers of NICs that
+		 * are guaranteed to never write more than MTU bytes, even
+		 * if the input buffer is larger: if the MTU is less
+		 * than the target they can set hwbuf_len to offset_gap.
+		 */
 		if (!kring->offset_gap)
 			kring->offset_gap =
 				NETMAP_BUF_SIZE(kring->na);
+
 		if (kring->offset_gap < target)
 			target = kring->offset_gap;
-
-		if (mtu) {
-			maxframe = mtu + ETH_HLEN +
-				ETH_FCS_LEN + VLAN_HLEN;
-			if (maxframe < target) {
-				target = maxframe;
-			}
-		}
-
 		error = kring->nm_bufcfg(kring, target);
 		if (error)
 			goto out;

From 7a965a5f7bea5e946a6184de76358ec778ff71be Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 11 Apr 2021 23:03:37 +0200
Subject: [PATCH 1961/2207] do not use Linux "struct device *" in common code

---
 sys/dev/netmap/netmap_mem2.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 5edfc38e1..e6c83efe9 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -312,7 +312,7 @@ netmap_mem_rings_delete(struct netmap_adapter *na)
 
 static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *);
 static int netmap_mem_unmap(struct netmap_obj_pool *, struct netmap_adapter *);
-static int nm_mem_check_group(struct netmap_mem_d *, struct device *);
+static int nm_mem_check_group(struct netmap_mem_d *, bus_dma_tag_t);
 static void nm_mem_release_id(struct netmap_mem_d *);
 
 nm_memid_t
@@ -730,7 +730,7 @@ netmap_mem_find(nm_memid_t id)
 }
 
 static int
-nm_mem_check_group(struct netmap_mem_d *nmd, struct device *dev)
+nm_mem_check_group(struct netmap_mem_d *nmd, bus_dma_tag_t dev)
 {
 	int err = 0, id;
 

From 6e1a18b5ab96b5a80deaffe07cb8f48c79bd307a Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Sun, 11 Apr 2021 13:39:22 +0100
Subject: [PATCH 1962/2207] fix g++ compile error

---
 sys/net/netmap_user.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 06b159d9b..5f3b3da55 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -986,7 +986,7 @@ nm_close(struct nm_desc *d)
 		close(d->fd);
 	}
 
-	bzero(d, sizeof(*d));
+	bzero((char *)d, sizeof(*d));
 	free(d);
 	return 0;
 }

From ee2cc162973da102fec8c22df5ccb242e0cf541c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 14 Apr 2021 15:34:08 +0200
Subject: [PATCH 1963/2207] check na validitity under lock on detach

---
 sys/dev/netmap/netmap.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 69ed05477..b3c5a884b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -4208,12 +4208,16 @@ netmap_hw_krings_create(struct netmap_adapter *na)
 void
 netmap_detach(struct ifnet *ifp)
 {
-	struct netmap_adapter *na = NA(ifp);
+	struct netmap_adapter *na;
 
-	if (!na)
+	NMG_LOCK();
+
+	if (!NM_NA_VALID(ifp)) {
+		NMG_UNLOCK();
 		return;
+	}
 
-	NMG_LOCK();
+	na = NA(ifp);
 	netmap_set_all_rings(na, NM_KR_LOCKED);
 	/*
 	 * if the netmap adapter is not native, somebody

From e894bd571e08b8811a5ee6559d7a0bde5e9ebe7c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 21 Apr 2021 10:01:28 +0200
Subject: [PATCH 1964/2207] mem: fix leak on error path

---
 sys/dev/netmap/netmap_mem2.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index e6c83efe9..a6be490e5 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1706,7 +1706,7 @@ _netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id,
 			if (memtotal < poolsz) {
 				nm_prerr("%s: request too large", d->pools[i].name);
 				err = ENOMEM;
-				goto error;
+				goto error_rel_id;
 			}
 			memtotal -= poolsz;
 		}
@@ -1731,14 +1731,15 @@ _netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id,
 
 	err = netmap_mem_config(d);
 	if (err)
-		goto error_rel_id;
+		goto error_destroy_lock;
 
 	d->flags &= ~NETMAP_MEM_FINALIZED;
 
 	return d;
 
-error_rel_id:
+error_destroy_lock:
 	NMA_LOCK_DESTROY(d);
+error_rel_id:
 	nm_mem_release_id(d);
 error_free:
 	nm_os_free(d);

From 4d8a6772f05900f2cf32ecd5928f06739636a0fd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 26 Apr 2021 17:04:12 +0200
Subject: [PATCH 1965/2207] linux: patches for 5.12 vanilla kernel

---
 ...0a00--99999 => vanilla--igb--50a00--50c00} |   0
 .../final-patches/vanilla--igb--50c00--99999  |  87 ++++++++++++
 ...00--99999 => vanilla--ixgbe--50a00--50c00} |   0
 .../vanilla--ixgbe--50c00--99999              | 117 ++++++++++++++++
 ...--99999 => vanilla--ixgbevf--50800--50c00} |   0
 .../vanilla--ixgbevf--50c00--99999            | 126 ++++++++++++++++++
 6 files changed, 330 insertions(+)
 rename LINUX/final-patches/{vanilla--igb--50a00--99999 => vanilla--igb--50a00--50c00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--igb--50c00--99999
 rename LINUX/final-patches/{vanilla--ixgbe--50a00--99999 => vanilla--ixgbe--50a00--50c00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--50c00--99999
 rename LINUX/final-patches/{vanilla--ixgbevf--50800--99999 => vanilla--ixgbevf--50800--50c00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--50c00--99999

diff --git a/LINUX/final-patches/vanilla--igb--50a00--99999 b/LINUX/final-patches/vanilla--igb--50a00--50c00
similarity index 100%
rename from LINUX/final-patches/vanilla--igb--50a00--99999
rename to LINUX/final-patches/vanilla--igb--50a00--50c00
diff --git a/LINUX/final-patches/vanilla--igb--50c00--99999 b/LINUX/final-patches/vanilla--igb--50c00--99999
new file mode 100644
index 000000000..057b27dc6
--- /dev/null
+++ b/LINUX/final-patches/vanilla--igb--50c00--99999
@@ -0,0 +1,87 @@
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index a45cd2b416c8..8a7712bb2a5d 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static int debug = -1;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct igb_reg_info {
+ 	u32 ofs;
+ 	char *name;
+@@ -3489,6 +3493,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef CONFIG_IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == 0) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3798,6 +3806,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
+ 	}
+ #endif
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 
+ 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+ 	 * would have already happened in close and is redundant.
+@@ -4302,6 +4314,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	wr32(E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -8030,6 +8045,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector, int napi_budget)
+ 
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+@@ -8674,6 +8693,16 @@ static int igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
+ 	u32 frame_sz = 0;
+ 	int rx_buf_pgcnt;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = igb_rx_frame_truesize(rx_ring, 0);
+@@ -8852,6 +8881,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	u16 i = rx_ring->next_to_use;
+ 	u16 bufsz;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/vanilla--ixgbe--50a00--99999 b/LINUX/final-patches/vanilla--ixgbe--50a00--50c00
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbe--50a00--99999
rename to LINUX/final-patches/vanilla--ixgbe--50a00--50c00
diff --git a/LINUX/final-patches/vanilla--ixgbe--50c00--99999 b/LINUX/final-patches/vanilla--ixgbe--50c00--99999
new file mode 100644
index 000000000..2781969db
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--50c00--99999
@@ -0,0 +1,117 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index cffb95f8f632..e7273c414ebd 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1120,6 +1136,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2297,6 +2324,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ixgbe_rx_frame_truesize(rx_ring, 0);
+@@ -3534,6 +3571,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4143,6 +4184,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ 	else
+@@ -5669,6 +5714,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -11051,6 +11099,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (err)
+ 		goto err_netdev;
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_netdev:
+@@ -11099,6 +11151,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
+ 	set_bit(__IXGBE_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--50800--99999 b/LINUX/final-patches/vanilla--ixgbevf--50800--50c00
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbevf--50800--99999
rename to LINUX/final-patches/vanilla--ixgbevf--50800--50c00
diff --git a/LINUX/final-patches/vanilla--ixgbevf--50c00--99999 b/LINUX/final-patches/vanilla--ixgbevf--50c00--99999
new file mode 100644
index 000000000..73ed1647d
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--50c00--99999
@@ -0,0 +1,126 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 449d7d5b280d..d5d04e1f6429 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -255,6 +255,24 @@ static void ixgbevf_tx_timeout(struct net_device *netdev, unsigned int __always_
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -274,6 +292,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1123,12 +1153,24 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
++
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ixgbevf_rx_frame_truesize(rx_ring, 0);
+ #endif
+ 	xdp_init_buff(&xdp, frame_sz, &rx_ring->xdp_rxq);
+ 
++	xdp.rxq = &rx_ring->xdp_rxq;
++
+ 	while (likely(total_rx_packets < budget)) {
+ 		struct ixgbevf_rx_buffer *rx_buffer;
+ 		union ixgbe_adv_rx_desc *rx_desc;
+@@ -1733,6 +1775,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -1741,7 +1787,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 		txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(reg_idx));
+ 	}  while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+ 	if (!wait_loop)
+-		hw_dbg(hw, "Could not enable Tx Queue %d\n", reg_idx);
++		pr_err("Could not enable Tx Queue %d\n", reg_idx);
+ }
+ 
+ /**
+@@ -1967,6 +2013,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -4679,6 +4729,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -4719,6 +4773,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 

From acbdedcb7600a46539e51967db8cb0c8de4c9248 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 16 May 2021 17:03:07 +0200
Subject: [PATCH 1966/2207] linux/i40e: check for non-null netdev before
 calling into netmap

When AF_XDP is in use on i40e, the napi callbacks may be called when
ring->netdev is still NULL. This causes crashes in the netmap code,
even if netmap is not used. This patch adds checks for
ring->netdev != NULL before calling into netmap.
---
 LINUX/final-patches/intel--i40e--1.5.25       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--1.6.42       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.0.19       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.0.26       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.0.30       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.1.26       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.10.19.30   | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.10.19.82   | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.11.21      | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.11.25      | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.11.29      | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.12.6       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.13.10      | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.14.13      | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.3.6        | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.4.10       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.4.3        | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.4.6        | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.7.11       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.7.12       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.7.26       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.7.29       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.8.43       | 16 ++++++++------
 LINUX/final-patches/intel--i40e--2.9.21       | 16 ++++++++------
 .../final-patches/vanilla--i40e--30c00--40100 |  6 ++---
 .../final-patches/vanilla--i40e--40100--40300 | 22 ++++++++++++++++---
 .../final-patches/vanilla--i40e--40300--40400 | 22 ++++++++++++++++---
 .../final-patches/vanilla--i40e--40400--40700 | 22 ++++++++++++++++---
 .../final-patches/vanilla--i40e--40700--40e00 | 16 ++++++++------
 .../final-patches/vanilla--i40e--40e00--41000 | 16 ++++++++------
 .../final-patches/vanilla--i40e--41000--41400 | 16 ++++++++------
 .../final-patches/vanilla--i40e--41400--50800 | 16 ++++++++------
 .../final-patches/vanilla--i40e--50800--50a00 | 16 ++++++++------
 .../final-patches/vanilla--i40e--50a00--99999 | 16 ++++++++------
 34 files changed, 330 insertions(+), 222 deletions(-)

diff --git a/LINUX/final-patches/intel--i40e--1.5.25 b/LINUX/final-patches/intel--i40e--1.5.25
index fdb60b9fb..d63333abf 100644
--- a/LINUX/final-patches/intel--i40e--1.5.25
+++ b/LINUX/final-patches/intel--i40e--1.5.25
@@ -123,7 +123,7 @@ index e729c22..b830e4c 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index e0f1f6c..3b131f2 100644
+index e0f1f6c..beb9d6f 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -25,6 +25,10 @@
@@ -142,22 +142,24 @@ index e0f1f6c..3b131f2 100644
  	unsigned int total_bytes = 0;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1892,6 +1901,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1892,6 +1901,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--1.6.42 b/LINUX/final-patches/intel--i40e--1.6.42
index a08dd95a3..20aa9131f 100644
--- a/LINUX/final-patches/intel--i40e--1.6.42
+++ b/LINUX/final-patches/intel--i40e--1.6.42
@@ -123,7 +123,7 @@ index 4dd9457..a2949b4 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index cd37999..1faa8e6 100644
+index cd37999..6a7f635 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -25,6 +25,10 @@
@@ -142,22 +142,24 @@ index cd37999..1faa8e6 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1874,6 +1883,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1874,6 +1883,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.0.19 b/LINUX/final-patches/intel--i40e--2.0.19
index 52547772e..a5a3121ab 100644
--- a/LINUX/final-patches/intel--i40e--2.0.19
+++ b/LINUX/final-patches/intel--i40e--2.0.19
@@ -123,7 +123,7 @@ index 7a2d4d7..0b79e20 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 6c8aa0c..bd90202 100644
+index 6c8aa0c..f6eb037 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -25,6 +25,10 @@
@@ -142,22 +142,24 @@ index 6c8aa0c..bd90202 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1894,6 +1903,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1894,6 +1903,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.0.26 b/LINUX/final-patches/intel--i40e--2.0.26
index e8dad5e7d..02e64ad9f 100644
--- a/LINUX/final-patches/intel--i40e--2.0.26
+++ b/LINUX/final-patches/intel--i40e--2.0.26
@@ -123,7 +123,7 @@ index 15e43a1..d02fc33 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 6c8aa0c..bd90202 100644
+index 6c8aa0c..f6eb037 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -25,6 +25,10 @@
@@ -142,22 +142,24 @@ index 6c8aa0c..bd90202 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1894,6 +1903,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1894,6 +1903,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.0.30 b/LINUX/final-patches/intel--i40e--2.0.30
index 7632ee559..c3ac26053 100644
--- a/LINUX/final-patches/intel--i40e--2.0.30
+++ b/LINUX/final-patches/intel--i40e--2.0.30
@@ -123,7 +123,7 @@ index 142be1c..9a00bf1 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 15b2ecf..8611654 100644
+index 15b2ecf..2d06c40 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -25,6 +25,10 @@
@@ -142,22 +142,24 @@ index 15b2ecf..8611654 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1877,6 +1886,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1877,6 +1886,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.1.26 b/LINUX/final-patches/intel--i40e--2.1.26
index 273454fb0..106dbc354 100644
--- a/LINUX/final-patches/intel--i40e--2.1.26
+++ b/LINUX/final-patches/intel--i40e--2.1.26
@@ -121,7 +121,7 @@ index 4c70594..8a7cace 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index cbd49a9..7c83c01 100644
+index cbd49a9..e9d2a48 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -26,6 +26,10 @@
@@ -140,22 +140,24 @@ index cbd49a9..7c83c01 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2148,6 +2157,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2148,6 +2157,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.10.19.30 b/LINUX/final-patches/intel--i40e--2.10.19.30
index 79cdecf96..e592af958 100644
--- a/LINUX/final-patches/intel--i40e--2.10.19.30
+++ b/LINUX/final-patches/intel--i40e--2.10.19.30
@@ -123,7 +123,7 @@ index 4452767..93b47d2 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index d90951f..eb3c4f5 100644
+index d90951f..13516d4 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index d90951f..eb3c4f5 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2555,6 +2564,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.10.19.82 b/LINUX/final-patches/intel--i40e--2.10.19.82
index 5e87f25b9..94dfbeb4e 100644
--- a/LINUX/final-patches/intel--i40e--2.10.19.82
+++ b/LINUX/final-patches/intel--i40e--2.10.19.82
@@ -123,7 +123,7 @@ index 3588ce8..b5def2e 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index b6b1a78..28a970c 100644
+index b6b1a78..31aefc5 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index b6b1a78..28a970c 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2555,6 +2564,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.11.21 b/LINUX/final-patches/intel--i40e--2.11.21
index 3219a3bdd..89d776d11 100644
--- a/LINUX/final-patches/intel--i40e--2.11.21
+++ b/LINUX/final-patches/intel--i40e--2.11.21
@@ -123,7 +123,7 @@ index bd4b467..3e461eb 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 96bc531..1615a4d 100644
+index 96bc531..12b3953 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index 96bc531..1615a4d 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2555,6 +2564,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.11.25 b/LINUX/final-patches/intel--i40e--2.11.25
index d5fa6d98c..fce69d7df 100644
--- a/LINUX/final-patches/intel--i40e--2.11.25
+++ b/LINUX/final-patches/intel--i40e--2.11.25
@@ -123,7 +123,7 @@ index b67de06..ce19f27 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 96bc531..1615a4d 100644
+index 96bc531..12b3953 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index 96bc531..1615a4d 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2555,6 +2564,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.11.29 b/LINUX/final-patches/intel--i40e--2.11.29
index 2b5dddbdb..65deaef37 100644
--- a/LINUX/final-patches/intel--i40e--2.11.29
+++ b/LINUX/final-patches/intel--i40e--2.11.29
@@ -124,7 +124,7 @@ index 7ad12f4..2768a89 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 96bc531..1615a4d 100644
+index 96bc531..12b3953 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -143,22 +143,24 @@ index 96bc531..1615a4d 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2555,6 +2564,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.12.6 b/LINUX/final-patches/intel--i40e--2.12.6
index 8d9b999f3..f3507c22f 100644
--- a/LINUX/final-patches/intel--i40e--2.12.6
+++ b/LINUX/final-patches/intel--i40e--2.12.6
@@ -124,7 +124,7 @@ index 6750c3c..f6e3fd1 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index e3eb496..39c987d 100644
+index e3eb496..509d0e1 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -143,22 +143,24 @@ index e3eb496..39c987d 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2745,6 +2754,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2745,6 +2754,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.13.10 b/LINUX/final-patches/intel--i40e--2.13.10
index 599cb8b79..ab2876f1d 100644
--- a/LINUX/final-patches/intel--i40e--2.13.10
+++ b/LINUX/final-patches/intel--i40e--2.13.10
@@ -124,7 +124,7 @@ index 62aeafe..5572ab1 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index f5d5bdf..7f7efd7 100644
+index f5d5bdf..b127543 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -143,22 +143,24 @@ index f5d5bdf..7f7efd7 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2709,6 +2718,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2709,6 +2718,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.14.13 b/LINUX/final-patches/intel--i40e--2.14.13
index 07208cd44..1031d4669 100644
--- a/LINUX/final-patches/intel--i40e--2.14.13
+++ b/LINUX/final-patches/intel--i40e--2.14.13
@@ -124,7 +124,7 @@ index 9aea7ca..09297e6 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index ea07464..845de14 100644
+index ea07464..6ea220b 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -143,22 +143,24 @@ index ea07464..845de14 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2741,7 +2750,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2741,7 +2750,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
  #ifdef HAVE_XDP_BUFF_FRAME_SZ
diff --git a/LINUX/final-patches/intel--i40e--2.3.6 b/LINUX/final-patches/intel--i40e--2.3.6
index 57b0a3ef7..8052a5251 100644
--- a/LINUX/final-patches/intel--i40e--2.3.6
+++ b/LINUX/final-patches/intel--i40e--2.3.6
@@ -121,7 +121,7 @@ index 7fea797..6eaed5b 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 6ec8bf6..01938de 100644
+index 6ec8bf6..bfb1740 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -26,6 +26,10 @@
@@ -140,22 +140,24 @@ index 6ec8bf6..01938de 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2254,6 +2263,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2254,6 +2263,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.4.10 b/LINUX/final-patches/intel--i40e--2.4.10
index 8d719ca4b..cf2c7000b 100644
--- a/LINUX/final-patches/intel--i40e--2.4.10
+++ b/LINUX/final-patches/intel--i40e--2.4.10
@@ -121,7 +121,7 @@ index e60e81e..9af8153 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index eea26ba..de76992 100644
+index eea26ba..cf33b88 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -26,6 +26,10 @@
@@ -140,22 +140,24 @@ index eea26ba..de76992 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2386,6 +2395,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2386,6 +2395,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.4.3 b/LINUX/final-patches/intel--i40e--2.4.3
index 100e3a31f..77fbb4f13 100644
--- a/LINUX/final-patches/intel--i40e--2.4.3
+++ b/LINUX/final-patches/intel--i40e--2.4.3
@@ -121,7 +121,7 @@ index 52a661a..487ccc0 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 0c949dd..c68df7d 100644
+index 0c949dd..f204f32 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -26,6 +26,10 @@
@@ -140,22 +140,24 @@ index 0c949dd..c68df7d 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2386,6 +2395,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2386,6 +2395,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.4.6 b/LINUX/final-patches/intel--i40e--2.4.6
index 2d5289bf4..fb8533d23 100644
--- a/LINUX/final-patches/intel--i40e--2.4.6
+++ b/LINUX/final-patches/intel--i40e--2.4.6
@@ -121,7 +121,7 @@ index ae669c3..0fa8375 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index eea26ba..de76992 100644
+index eea26ba..cf33b88 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -26,6 +26,10 @@
@@ -140,22 +140,24 @@ index eea26ba..de76992 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2386,6 +2395,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2386,6 +2395,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.7.11 b/LINUX/final-patches/intel--i40e--2.7.11
index 1cb4da058..da76d0641 100644
--- a/LINUX/final-patches/intel--i40e--2.7.11
+++ b/LINUX/final-patches/intel--i40e--2.7.11
@@ -123,7 +123,7 @@ index 86d76c0..5629a97 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..4d19c85 100644
+index 1859d78..39d426e 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index 1859d78..4d19c85 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2551,6 +2560,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false, xdp_xmit = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.7.12 b/LINUX/final-patches/intel--i40e--2.7.12
index 81e19cf01..d7b4222e5 100644
--- a/LINUX/final-patches/intel--i40e--2.7.12
+++ b/LINUX/final-patches/intel--i40e--2.7.12
@@ -123,7 +123,7 @@ index 6f8e9b4..a62aadd 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..4d19c85 100644
+index 1859d78..39d426e 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index 1859d78..4d19c85 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2551,6 +2560,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false, xdp_xmit = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.7.26 b/LINUX/final-patches/intel--i40e--2.7.26
index c61a0cc0e..0e3d3ab9f 100644
--- a/LINUX/final-patches/intel--i40e--2.7.26
+++ b/LINUX/final-patches/intel--i40e--2.7.26
@@ -123,7 +123,7 @@ index 6d2e21d..9845b9d 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..4d19c85 100644
+index 1859d78..39d426e 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index 1859d78..4d19c85 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2551,6 +2560,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false, xdp_xmit = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.7.29 b/LINUX/final-patches/intel--i40e--2.7.29
index e40bd4d3f..ea949f491 100644
--- a/LINUX/final-patches/intel--i40e--2.7.29
+++ b/LINUX/final-patches/intel--i40e--2.7.29
@@ -123,7 +123,7 @@ index 1914934..c1dcee9 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 1859d78..4d19c85 100644
+index 1859d78..39d426e 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index 1859d78..4d19c85 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2551,6 +2560,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2551,6 +2560,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false, xdp_xmit = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.8.43 b/LINUX/final-patches/intel--i40e--2.8.43
index 0ee33c6e9..560df6f9d 100644
--- a/LINUX/final-patches/intel--i40e--2.8.43
+++ b/LINUX/final-patches/intel--i40e--2.8.43
@@ -123,7 +123,7 @@ index 54940ba..f9e79b7 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index c3ebcd7..ea86118 100644
+index c3ebcd7..ff4bcda 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index c3ebcd7..ea86118 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2554,6 +2563,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2554,6 +2563,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/intel--i40e--2.9.21 b/LINUX/final-patches/intel--i40e--2.9.21
index 720abcdbc..3b7d1e9a3 100644
--- a/LINUX/final-patches/intel--i40e--2.9.21
+++ b/LINUX/final-patches/intel--i40e--2.9.21
@@ -123,7 +123,7 @@ index 47f8b5f..58f65de 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index b1987c8..816b129 100644
+index b1987c8..1daecc8 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -9,6 +9,10 @@
@@ -142,22 +142,24 @@ index b1987c8..816b129 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2555,6 +2564,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2555,6 +2564,16 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
 +
diff --git a/LINUX/final-patches/vanilla--i40e--30c00--40100 b/LINUX/final-patches/vanilla--i40e--30c00--40100
index 98258a9c1..0694fe964 100644
--- a/LINUX/final-patches/vanilla--i40e--30c00--40100
+++ b/LINUX/final-patches/vanilla--i40e--30c00--40100
@@ -73,7 +73,7 @@ index 221aa4795017..db5394879249 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 49d2cfa9b0cc..83f3c560887a 100644
+index 49d2cfa9b0cc..8511b05e7d07 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -27,6 +27,10 @@
@@ -92,7 +92,7 @@ index 49d2cfa9b0cc..83f3c560887a 100644
  	unsigned int total_bytes = 0;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
@@ -104,7 +104,7 @@ index 49d2cfa9b0cc..83f3c560887a 100644
  	u64 qword;
  
 +#ifdef DEV_NETMAP
-+	{
++	if (rx_ring->netdev) {
 +		int dummy, nm_irq;
 +		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
 +		if (nm_irq != NM_IRQ_PASS)
diff --git a/LINUX/final-patches/vanilla--i40e--40100--40300 b/LINUX/final-patches/vanilla--i40e--40100--40300
index c38ad5115..3804d7f56 100644
--- a/LINUX/final-patches/vanilla--i40e--40100--40300
+++ b/LINUX/final-patches/vanilla--i40e--40100--40300
@@ -73,7 +73,7 @@ index 5b5bea159bd5..45bfb58a5c5f 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 9d95042d5a0f..80f8a88a3ae8 100644
+index 9d95042d5a0f..a9223583a90c 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
@@ -92,14 +92,30 @@ index 9d95042d5a0f..80f8a88a3ae8 100644
  	unsigned int total_bytes = 0;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1874,6 +1883,15 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
+@@ -1528,6 +1537,15 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+ 	u8 rx_ptype;
+ 	u64 qword;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS)
++			return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++	}
++#endif /* DEV_NETMAP */
++
+ 	if (budget <= 0)
+ 		return 0;
+ 
+@@ -1874,6 +1892,15 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
  	budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
  
  	i40e_for_each_ring(ring, q_vector->rx) {
diff --git a/LINUX/final-patches/vanilla--i40e--40300--40400 b/LINUX/final-patches/vanilla--i40e--40300--40400
index e2a68e88f..6b0e2be39 100644
--- a/LINUX/final-patches/vanilla--i40e--40300--40400
+++ b/LINUX/final-patches/vanilla--i40e--40300--40400
@@ -74,7 +74,7 @@ index 3dd26cdd0bf2..ebed661a1148 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 738aca68f665..77e14b3828d7 100644
+index 738aca68f665..dc591bc2889b 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
@@ -93,14 +93,30 @@ index 738aca68f665..77e14b3828d7 100644
  	unsigned int total_bytes = 0;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1929,6 +1938,15 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
+@@ -1526,6 +1535,15 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+ 	u8 rx_ptype;
+ 	u64 qword;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS)
++			return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++	}
++#endif /* DEV_NETMAP */
++
+ 	if (budget <= 0)
+ 		return 0;
+ 
+@@ -1929,6 +1947,15 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
  	budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
  
  	i40e_for_each_ring(ring, q_vector->rx) {
diff --git a/LINUX/final-patches/vanilla--i40e--40400--40700 b/LINUX/final-patches/vanilla--i40e--40400--40700
index 03a39ce85..2718d6752 100644
--- a/LINUX/final-patches/vanilla--i40e--40400--40700
+++ b/LINUX/final-patches/vanilla--i40e--40400--40700
@@ -74,7 +74,7 @@ index 4a9873ec28c7..58c0ca3401d3 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 635b3ac17877..baed465e8b35 100644
+index 635b3ac17877..ad7d41e84bd4 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
@@ -93,14 +93,30 @@ index 635b3ac17877..baed465e8b35 100644
  	unsigned int total_bytes = 0;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1912,6 +1921,14 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
+@@ -1477,6 +1486,15 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+ 	u8 rx_ptype;
+ 	u64 qword;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS)
++			return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++	}
++#endif /* DEV_NETMAP */
++
+ 	if (budget <= 0)
+ 		return 0;
+ 
+@@ -1912,6 +1930,14 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
  
  	i40e_for_each_ring(ring, q_vector->rx) {
  		int cleaned;
diff --git a/LINUX/final-patches/vanilla--i40e--40700--40e00 b/LINUX/final-patches/vanilla--i40e--40700--40e00
index 407b97f18..9e3f8736b 100644
--- a/LINUX/final-patches/vanilla--i40e--40700--40e00
+++ b/LINUX/final-patches/vanilla--i40e--40700--40e00
@@ -73,7 +73,7 @@ index 501f15d9f4d6..0073159583d7 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index a8868e1bf832..9186a17975b8 100644
+index a8868e1bf832..274851fe9c52 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -29,6 +29,10 @@
@@ -92,22 +92,24 @@ index a8868e1bf832..9186a17975b8 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1753,6 +1762,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1753,6 +1762,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy;
-+	if (rx_ring->netdev &&
-+	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
-+		return 1;
++	if (rx_ring->netdev) {
++		int dummy;
++		if (rx_ring->netdev &&
++		    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++			return 1;
++	}
 +#endif /* DEV_NETMAP */
 +
  	while (likely(total_rx_packets < budget)) {
diff --git a/LINUX/final-patches/vanilla--i40e--40e00--41000 b/LINUX/final-patches/vanilla--i40e--40e00--41000
index 11324a074..40be9499f 100644
--- a/LINUX/final-patches/vanilla--i40e--40e00--41000
+++ b/LINUX/final-patches/vanilla--i40e--40e00--41000
@@ -73,7 +73,7 @@ index 6498da8806cb..7fbe7d5a62f9 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 120c68f78951..70d59e253a7b 100644
+index 120c68f78951..22ee8ace0ba9 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -31,6 +31,10 @@
@@ -92,22 +92,24 @@ index 120c68f78951..70d59e253a7b 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2069,6 +2078,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2069,6 +2078,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
  	bool failure = false, xdp_xmit = false;
  
 +#ifdef DEV_NETMAP
-+	int dummy;
-+	if (rx_ring->netdev &&
-+	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
-+		return 1;
++	if (rx_ring->netdev) {
++		int dummy;
++		if (rx_ring->netdev &&
++		    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++			return 1;
++	}
 +#endif /* DEV_NETMAP */
 +
  	while (likely(total_rx_packets < (unsigned int)budget)) {
diff --git a/LINUX/final-patches/vanilla--i40e--41000--41400 b/LINUX/final-patches/vanilla--i40e--41000--41400
index 241dd5ce5..581a556e5 100644
--- a/LINUX/final-patches/vanilla--i40e--41000--41400
+++ b/LINUX/final-patches/vanilla--i40e--41000--41400
@@ -73,7 +73,7 @@ index e31adbc75f9c..64564a6a1301 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index e554aa6cf070..ec6957c8950a 100644
+index e554aa6cf070..c4882f93db78 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -32,6 +32,10 @@
@@ -92,22 +92,24 @@ index e554aa6cf070..ec6957c8950a 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2135,6 +2144,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2135,6 +2144,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false, xdp_xmit = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy;
-+	if (rx_ring->netdev &&
-+	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
-+		return 1;
++	if (rx_ring->netdev) {
++		int dummy;
++		if (rx_ring->netdev &&
++		    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++			return 1;
++	}
 +#endif /* DEV_NETMAP */
 +
  	xdp.rxq = &rx_ring->xdp_rxq;
diff --git a/LINUX/final-patches/vanilla--i40e--41400--50800 b/LINUX/final-patches/vanilla--i40e--41400--50800
index 6ab0f7d1d..7146a833e 100644
--- a/LINUX/final-patches/vanilla--i40e--41400--50800
+++ b/LINUX/final-patches/vanilla--i40e--41400--50800
@@ -72,7 +72,7 @@ index 0e5dc74b4ef2..604130f5879d 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index d0a95424ce58..993ff2722007 100644
+index d0a95424ce58..07fb1bcc909c 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -10,6 +10,10 @@
@@ -91,22 +91,24 @@ index d0a95424ce58..993ff2722007 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2334,6 +2343,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2334,6 +2343,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy;
-+	if (rx_ring->netdev &&
-+	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
-+		return 1;
++	if (rx_ring->netdev) {
++		int dummy;
++		if (rx_ring->netdev &&
++		    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++			return 1;
++	}
 +#endif /* DEV_NETMAP */
 +
  	xdp.rxq = &rx_ring->xdp_rxq;
diff --git a/LINUX/final-patches/vanilla--i40e--50800--50a00 b/LINUX/final-patches/vanilla--i40e--50800--50a00
index 2b662afd8..15c620697 100644
--- a/LINUX/final-patches/vanilla--i40e--50800--50a00
+++ b/LINUX/final-patches/vanilla--i40e--50800--50a00
@@ -73,7 +73,7 @@ index 56ecd6c3f236..0f52cbe03dcd 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index f9555c847f73..9ac901483469 100644
+index f9555c847f73..ab0089042e0b 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -10,6 +10,10 @@
@@ -92,22 +92,24 @@ index f9555c847f73..9ac901483469 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2320,6 +2329,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2320,6 +2329,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy;
-+	if (rx_ring->netdev &&
-+	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
-+		return 1;
++	if (rx_ring->netdev) {
++		int dummy;
++		if (rx_ring->netdev &&
++		    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++			return 1;
++	}
 +#endif /* DEV_NETMAP */
 +
  #if (PAGE_SIZE < 8192)
diff --git a/LINUX/final-patches/vanilla--i40e--50a00--99999 b/LINUX/final-patches/vanilla--i40e--50a00--99999
index ad26c4b7a..8ff538012 100644
--- a/LINUX/final-patches/vanilla--i40e--50a00--99999
+++ b/LINUX/final-patches/vanilla--i40e--50a00--99999
@@ -73,7 +73,7 @@ index 1337686bd099..71244892b7a8 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 3f5825fa67c9..53d7ae1922c8 100644
+index 3f5825fa67c9..102e9b18eff0 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -10,6 +10,10 @@
@@ -92,22 +92,24 @@ index 3f5825fa67c9..53d7ae1922c8 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2340,6 +2349,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2340,6 +2349,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	bool failure = false;
  	struct xdp_buff xdp;
  
 +#ifdef DEV_NETMAP
-+	int dummy;
-+	if (rx_ring->netdev &&
-+	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
-+		return 1;
++	if (rx_ring->netdev) {
++		int dummy;
++		if (rx_ring->netdev &&
++		    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++			return 1;
++	}
 +#endif /* DEV_NETMAP */
 +
  #if (PAGE_SIZE < 8192)

From 264caa917546b41b8d9f4460e76d2e4f9815d21e Mon Sep 17 00:00:00 2001
From: Arne Welzel 
Date: Thu, 20 May 2021 10:41:12 +0200
Subject: [PATCH 1967/2207] lb/pkt_hash: Validate ihl field

---
 apps/lb/pkt_hash.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index 3071935e1..eb9704fd2 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -150,7 +150,9 @@ decode_ip_n_hash(const struct ip *iph, uint8_t hash_split, uint8_t seed)
 {
 	uint32_t rc = 0;
 
-	if (hash_split == 2) {
+	if (iph->ip_hl < 5 || iph->ip_hl * 4 > iph->ip_len) {
+		rc = 0;
+	} else if (hash_split == 2) {
 		rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
 			ntohl(iph->ip_dst.s_addr),
 			ntohs(0xFFFD) + seed,

From 62e7b2ebab75ba3d8774cd619c655fb293134004 Mon Sep 17 00:00:00 2001
From: Scott Parlane 
Date: Wed, 26 May 2021 14:15:07 +1200
Subject: [PATCH 1968/2207] i40e: Ignore zero length packets

Buffers that claim to have zero length packets aren't ready yet.
See 0e626ff7ccbfc and d57c0e08c7016 in linux.
---
 LINUX/i40e_netmap_linux.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 0f6018888..55df4cd25 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -569,6 +569,9 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			slot->len = ((qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
 			    >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - crclen;
 
+			if (!slot->len)
+				break;
+
 			if (unlikely((staterr & (1<
Date: Thu, 24 Jun 2021 11:30:36 +0200
Subject: [PATCH 1969/2207] linux/i40e: patch for Intel 2.15.9 version

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/intel--i40e--2.15.9 | 167 ++++++++++++++++++++++++
 2 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.15.9

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 3f277ce97..69b10ec4d 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -82,7 +82,7 @@ igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2),@SRCDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13),@SRCDIR@/intel-fix.sh i40e,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh i40e,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/final-patches/intel--i40e--2.15.9 b/LINUX/final-patches/intel--i40e--2.15.9
new file mode 100644
index 000000000..c76e131c4
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.15.9
@@ -0,0 +1,167 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index e9a83b9..a5d7708 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 37e7bd9..27ff181 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -150,6 +150,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3733,6 +3738,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3786,6 +3795,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3814,6 +3827,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -14870,6 +14888,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15242,6 +15266,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index ce23f6b..4a69af0 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -935,6 +939,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2741,6 +2750,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	bool failure = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);

From 709a1ec06130125841591bdc862911b9082c2331 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 14 Jun 2021 20:27:19 +0200
Subject: [PATCH 1970/2207] linux/ixgbevf: patch for Intel 4.11.1 version

---
 LINUX/default-config.mak.in_               |   2 +-
 LINUX/final-patches/intel--ixgbevf--4.11.1 | 168 +++++++++++++++++++++
 2 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.11.1

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 69b10ec4d..57a7cc4f2 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -80,7 +80,7 @@ igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
-ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2),@SRCDIR@/intel-fix.sh ixgbevf,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2),@SRCDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh i40e,)
 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.11.1 b/LINUX/final-patches/intel--ixgbevf--4.11.1
new file mode 100644
index 000000000..2e3194900
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.11.1
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 6391546..780d1c0 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 530df81..aca755d 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -343,6 +343,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -363,6 +380,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1375,6 +1403,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2093,6 +2131,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2327,6 +2369,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5636,8 +5682,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5678,6 +5726,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 7aaf487..7d3fe65 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 8f144c9274cae4f5660987365690fbb824050a45 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 14 Jun 2021 20:42:48 +0200
Subject: [PATCH 1971/2207] linux/ixgbe: patch for Intel 5.11.3 version

---
 LINUX/default-config.mak.in_             |   2 +-
 LINUX/final-patches/intel--ixgbe--5.11.3 | 173 +++++++++++++++++++++++
 2 files changed, 174 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.11.3

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 57a7cc4f2..514ec80b4 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -81,7 +81,7 @@ ixgbe@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@SRCDIR@/intel-fix.sh ixgbevf,)
-ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2),@SRCDIR@/intel-fix.sh ixgbe,)
+ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@SRCDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh i40e,)
 
 # some additional, driver-specific configuration
diff --git a/LINUX/final-patches/intel--ixgbe--5.11.3 b/LINUX/final-patches/intel--ixgbe--5.11.3
new file mode 100644
index 000000000..ad7f1900e
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.11.3
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index adccdaa..137c98f 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 3205fc0..ce0b0b5 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -715,6 +715,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -734,6 +751,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2212,6 +2240,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3692,6 +3730,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4384,6 +4426,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13011,6 +13059,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13067,6 +13119,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 98b9bbc40647c9b822ec0225bc48aa7ed7614c9e Mon Sep 17 00:00:00 2001
From: Olivier Piras 
Date: Tue, 20 Jul 2021 02:21:05 +0200
Subject: [PATCH 1972/2207] fix compilation on Raspberry Pi

---
 apps/tlem/tlem.c      | 5 +++--
 sys/net/netmap_user.h | 2 +-
 utils/testmmap.c      | 4 ++--
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index 0913fee7a..b9570955c 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -153,6 +153,7 @@ prod()
 #include 
 #include 
 #include 
+#include 
 #include 
 
 
@@ -796,7 +797,7 @@ struct arp_table_entry {
 void
 arp_table_entry_dump(int idx, struct arp_table_entry *e)
 {
-    ED("%d: next %lu addr %02x:%02x:%02x:%02x:%02x:%02x",
+    ED("%d: next %" PRIu64 " addr %02x:%02x:%02x:%02x:%02x:%02x",
             idx, e->next_req,
             (uint8_t)~e->ether_addr[0],
             (uint8_t)~e->ether_addr[1],
@@ -2512,7 +2513,7 @@ main(int argc, char **argv)
 	}
 #ifdef WITH_MAX_LAG
         if (invdopt['d']->arg[i] != NULL) {
-            unsigned long max_lag = parse_time(invdopt[(int)'d']->arg[i]);
+            uint64_t max_lag = parse_time(invdopt[(int)'d']->arg[i]);
             if (max_lag == U_PARSE_ERR) {
                 err++;
             } else {
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 06b159d9b..e17d2dcbe 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1131,7 +1131,7 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
 				slot = &ring->slot[i];
 				d->hdr.len += slot->len;
 				nbuf = (u_char *)NETMAP_BUF(ring, slot->buf_idx);
-				if (oldbuf != NULL && nbuf - oldbuf == ring->nr_buf_size &&
+				if (oldbuf != NULL && (uint32_t)(nbuf - oldbuf) == ring->nr_buf_size &&
 						oldlen == ring->nr_buf_size) {
 					d->hdr.caplen += slot->len;
 					oldbuf = nbuf;
diff --git a/utils/testmmap.c b/utils/testmmap.c
index 8c59ee77a..c045f2881 100644
--- a/utils/testmmap.c
+++ b/utils/testmmap.c
@@ -1421,7 +1421,7 @@ nmr_body_dump_register(void *b)
 		break;
 	}
 	printf("]\n");
-	printf("flags:     %lx [", r->nr_flags);
+	printf("flags:     %" PRIx64 " [", r->nr_flags);
 #define pflag(f)                                                               \
 	if (r->nr_flags & NR_##f) {                                            \
 		printf("%s" #f, flags++ ? ", " : "");                          \
@@ -1515,7 +1515,7 @@ do_register_flags()
 	}
 	if (n)
 		curr_register.nr_flags = flags;
-	output("flags=%lx", curr_register.nr_flags);
+	output("flags=%" PRIx64, curr_register.nr_flags);
 }
 
 struct cmd_def register_commands[] = {

From 962563f91c71c5706e08260d749870508ef9d354 Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Sat, 22 May 2021 21:49:47 +0000
Subject: [PATCH 1973/2207] Update to mlx5 v5.3

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/mellanox--mlx5--5.3 | 411 ++++++++++++++++++++++++
 2 files changed, 412 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--5.3

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 514ec80b4..14bff3674 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -110,7 +110,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,5.2-1.0.4.0))
+$(eval $(call default,mlx5,5.3-1.0.0.1))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 mlx5@cflags	= -Wframe-larger-than=2000
diff --git a/LINUX/final-patches/mellanox--mlx5--5.3 b/LINUX/final-patches/mellanox--mlx5--5.3
new file mode 100644
index 000000000..1c08468c2
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--5.3
@@ -0,0 +1,411 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 971de67..40a2aef 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -6,12 +6,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
+@@ -20,12 +20,12 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		mst_dump.o en_diag.o sriov_sysfs.o crdump.o diag/diag_cnt.o \
+ 		eswitch_devlink_compat.o params.o fw_exp.o fw_reset.o
+ 
+-mlx5_core-y += compat.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y += compat.o
+ 
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o \
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+ 		en/reporter_tx.o en/reporter_rx.o en/params.o en/xsk/umem.o \
+@@ -35,63 +35,63 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += lag_mp.o lib/geneve.o lib/port_tun.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += lag_mp.o lib/geneve.o lib/port_tun.o \
+ 					en_rep.o en/rep/bond.o en/mod_hdr.o \
+ 					en/flow_meter_aso.o
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					en/mapping.o lib/fs_chains.o en/tc_tun.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
+ 					en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
+ 					en/tc_sample.o esw/indir_table.o en/tc_tun_common.o
+-mlx5_core-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ 				      ecpf.o rdma.o esw/vf_meter.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
+ 				      esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
+ 				      esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o \
+ 				      esw/vporttbl.o esw/pet_offloads.o \
+ 
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
+-mlx5_core-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o en_accel/ipsec_fs.o esw/ipsec.o \
+ 				     en/ipsec_aso.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ 				   en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
+ 				   en_accel/ktls_tx.o en_accel/ktls_rx.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o \
+ 					steering/dr_ste.o steering/dr_send.o \
+@@ -102,4 +102,4 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # Mdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o  meddev/mdev_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MDEV) += meddev/sf.o meddev/mdev.o  meddev/mdev_driver.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index a6dceb6..a3cb81d 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -14,6 +14,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 47260b9..0c0e90a 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -84,8 +84,21 @@
+ #include "fpga/ipsec.h"
+ #include "compat.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -824,6 +837,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
+ 		rq->dim_obj.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_free_by_rq_type:
+@@ -1051,6 +1068,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ {
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(rq->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1115,6 +1138,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1261,6 +1288,9 @@ err_dealloc_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->netdev)) || NA(rq->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	mlx5e_trigger_irq(rq->icosq);
+ }
+@@ -1544,6 +1574,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1738,6 +1773,9 @@ void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1758,6 +1796,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3883,6 +3927,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -3916,6 +3965,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++       netmap_disable_all_rings(netdev);
++#endif
++
+ 	netif_carrier_off(priv->netdev);
+ 	mlx5e_destroy_debugfs(priv);
+ #if defined(CONFIG_MLX5_EN_SPECIAL_SQ) && (defined(HAVE_NDO_SET_TX_MAXRATE) || defined(HAVE_NDO_SET_TX_MAXRATE_EXTENDED))
+@@ -7129,6 +7182,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ {
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++       netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_netdev_cleanup(netdev, priv);
+ 	free_netdev(netdev);
+ }
+@@ -7242,6 +7299,10 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
+ 
+ 	mlx5e_dcbnl_init_app(priv);
+ 
++#ifdef DEV_NETMAP
++       mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	if (MLX5_ESWITCH_MANAGER(mdev))
+ 		mlx5e_rep_register_vport_reps(mdev, priv);
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index 78cc065..bf0f358 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -79,6 +79,14 @@ const struct mlx5e_rx_handlers mlx5e_rx_handlers_nic = {
+ 	.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -207,7 +215,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -1992,6 +2000,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 6785213..c521cc8 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -41,8 +41,16 @@
+ #include "ipoib/ipoib.h"
+ #include "en_accel/en_accel.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+-				       u32 cqcc, void *data)
++                                       u32 cqcc, void *data)
+ {
+ 	u32 ci = mlx5_cqwq_ctr2ix(wq, cqcc);
+ 
+@@ -1024,6 +1032,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->netdev, sq->ch_ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -1146,23 +1159,29 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 
+ 		sqcc += wi->num_wqebbs;
+ 
+-		if (likely(wi->skb)) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			dev_kfree_skb_any(wi->skb);
++                if (!nm_netmap_on(NA(sq->txq->dev))) {
++                       /* do not free skbs in netmap mode */
++			if (likely(wi->skb)) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				dev_kfree_skb_any(wi->skb);
+ 
+-			npkts++;
+-			nbytes += wi->num_bytes;
+-			continue;
+-		}
++				npkts++;
++				nbytes += wi->num_bytes;
++				continue;
++			}
+ 
+-		if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
+-			continue;
++			if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
++				continue;
+ 
+-		if (wi->num_fifo_pkts) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
++			if (wi->num_fifo_pkts) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
+ 
+-			npkts += wi->num_fifo_pkts;
++				npkts += wi->num_fifo_pkts;
++				nbytes += wi->num_bytes;
++			}
++                } else {
++			npkts++;
+ 			nbytes += wi->num_bytes;
+ 		}
+ 	}

From 43646bbc9ed79c888bcc557f3a4a8d516b502e58 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 4 Aug 2021 18:43:28 +0200
Subject: [PATCH 1974/2207] monitor: support offsets in copy mode

---
 sys/dev/netmap/netmap_monitor.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 4827c2a75..e05313c1f 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -737,8 +737,7 @@ netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_
 		int free_slots, busy, sent = 0, m;
 		u_int lim = kring->nkr_num_slots - 1;
 		struct netmap_ring *ring = kring->ring, *mring = mkring->ring;
-		u_int max_len = NETMAP_BUF_SIZE(mkring->na);
-
+		u_int max_len;
 		mlim = mkring->nkr_num_slots - 1;
 
 		/* we need to lock the monitor receive ring, since it
@@ -770,9 +769,10 @@ netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_
 			struct netmap_slot *s = &ring->slot[beg];
 			struct netmap_slot *ms = &mring->slot[i];
 			u_int copy_len = s->len;
-			char *src = NMB(kring->na, s),
-			     *dst = NMB(mkring->na, ms);
+			char *src = NMB_O(kring, s),
+			     *dst = NMB_O(mkring, ms);
 
+			max_len = NETMAP_BUF_SIZE(mkring->na) - nm_get_offset(mkring, ms);
 			if (unlikely(copy_len > max_len)) {
 				nm_prlim(5, "%s->%s: truncating %d to %d", kring->name,
 						mkring->name, copy_len, max_len);
@@ -966,7 +966,9 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 			pna->monitor_id++);
 
 	/* the monitor supports the host rings iff the parent does */
-	mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS);
+	mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS) & ~NAF_OFFSETS;
+	if (!zcopy)
+		mna->up.na_flags |= NAF_OFFSETS;
 	/* a do-nothing txsync: monitors cannot be used to inject packets */
 	mna->up.nm_txsync = netmap_monitor_txsync;
 	mna->up.nm_rxsync = netmap_monitor_rxsync;

From f3c239226bc5012f47ca125511a61898028e49dc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 9 Sep 2021 16:56:21 +0200
Subject: [PATCH 1975/2207] linux/i40e: patch for Intel 2.16.11 version

---
 LINUX/final-patches/intel--i40e--2.16.11 | 170 +++++++++++++++++++++++
 1 file changed, 170 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.16.11

diff --git a/LINUX/final-patches/intel--i40e--2.16.11 b/LINUX/final-patches/intel--i40e--2.16.11
new file mode 100644
index 000000000..183956c09
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.16.11
@@ -0,0 +1,170 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index e9a83b9..a5d7708 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 366c67e..389a449 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -150,6 +150,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3953,6 +3958,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4006,6 +4015,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4034,6 +4047,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -15162,6 +15180,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15534,6 +15558,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 096f44f..3d3b7b3 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -9,6 +9,10 @@
+ #include "i40e_trace.h"
+ #include "i40e_prototype.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -935,6 +939,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2743,7 +2752,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif

From cc2dc2f28e2450cd53ec41ad1c24f14e1b10f878 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 9 Sep 2021 16:56:50 +0200
Subject: [PATCH 1976/2207] linux/ixgbe: patch for Intel 5.12.5 version

---
 LINUX/final-patches/intel--ixgbe--5.12.5 | 173 +++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.12.5

diff --git a/LINUX/final-patches/intel--ixgbe--5.12.5 b/LINUX/final-patches/intel--ixgbe--5.12.5
new file mode 100644
index 000000000..c08963d1e
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.12.5
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index adccdaa..137c98f 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index de15aae..94974ca 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -716,6 +716,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -735,6 +752,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2213,6 +2241,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3731,6 +3769,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4422,6 +4464,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13130,6 +13178,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13186,6 +13238,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 7d9019ca52ba279af28902959561d94ce07d0aaa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 9 Sep 2021 16:57:11 +0200
Subject: [PATCH 1977/2207] linux/ixgbevf: patch for Intel 4.12.4 version

---
 LINUX/final-patches/intel--ixgbevf--4.12.4 | 168 +++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.12.4

diff --git a/LINUX/final-patches/intel--ixgbevf--4.12.4 b/LINUX/final-patches/intel--ixgbevf--4.12.4
new file mode 100644
index 000000000..9f81731fc
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.12.4
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 6391546..780d1c0 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index a474676..265926b 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1377,6 +1405,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2095,6 +2133,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2329,6 +2371,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5623,8 +5669,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5665,6 +5713,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 8990cb5..d439cdb 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 247c6bd06d8934c846fe13892aa04b34f7cf2b9d Mon Sep 17 00:00:00 2001
From: Dries De Winter 
Date: Tue, 21 Sep 2021 16:00:48 +0200
Subject: [PATCH 1978/2207] Fix uint32_t overflow in pool size calculation

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index a6be490e5..2b41af761 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1702,7 +1702,7 @@ _netmap_mem_private_new(size_t size, struct netmap_obj_params *p, int grp_id,
 				nm_blueprint.pools[i].name,
 				d->name);
 		if (checksz) {
-			uint64_t poolsz = p[i].num * p[i].size;
+			uint64_t poolsz = (uint64_t)p[i].num * p[i].size;
 			if (memtotal < poolsz) {
 				nm_prerr("%s: request too large", d->pools[i].name);
 				err = ENOMEM;

From d0510468ff5b599ae66a0dea488ea5f41fffa5a0 Mon Sep 17 00:00:00 2001
From: Dries De Winter 
Date: Fri, 24 Sep 2021 17:53:13 +0200
Subject: [PATCH 1979/2207] Fix assymetry in reference counter updates of
 memory allocator

When a single memory region was provided via the EXTMEM option multiple times, for multiple interfaces, then the memory region was never actually released by netmap. After closing all netmap file descriptors, the external memory remained in use by netmap.

The problem was in netmap_mem_drop: the condition to release the memory reference is when the last user of *netmap_adapter* is gone, not when the last user of *netmap_mem_d* is gone.
---
 sys/dev/netmap/netmap.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index b3c5a884b..bea136c76 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -994,10 +994,12 @@ netmap_mem_restore(struct netmap_adapter *na)
 static void
 netmap_mem_drop(struct netmap_adapter *na)
 {
-	/* if the native allocator had been overridden on regif,
-	 * restore it now and drop the temporary one
-	 */
-	if (netmap_mem_deref(na->nm_mem, na)) {
+	netmap_mem_deref(na->nm_mem, na);
+
+	if (na->active_fds <= 0) {
+		/* if the native allocator had been overridden on regif,
+		 * restore it now and drop the temporary one
+		 */
 		netmap_mem_restore(na);
 	}
 }

From 79929dafa8b772834eb6ab3ac6125975db59f377 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 27 Sep 2021 15:50:05 +0200
Subject: [PATCH 1980/2207] mem: print caller function name when debugging
 netmap_mem_put/get

---
 sys/dev/netmap/netmap_mem2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 2b41af761..8575a9409 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -323,7 +323,7 @@ netmap_mem_get_id(struct netmap_mem_d *nmd)
 
 #ifdef NM_DEBUG_MEM_PUTGET
 #define NM_DBG_REFC(nmd, func, line)	\
-	nm_prinf("%d mem[%d:%d] -> %d", line, (nmd)->nm_id, (nmd)->nm_grp, (nmd)->refcount);
+	nm_prinf("%s:%d mem[%d:%d] -> %d", func, line, (nmd)->nm_id, (nmd)->nm_grp, (nmd)->refcount);
 #else
 #define NM_DBG_REFC(nmd, func, line)
 #endif

From b5e704fddbe5a23d102aa03fdfb26ae51a0fcb9d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Nov 2021 15:57:52 +0100
Subject: [PATCH 1981/2207] linux/scripts: workaround for missing
 compiler-gcc11.h

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 274f62310..0b2075277 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -378,7 +378,7 @@ function build-prep()
 	(
 		cd $dst
 		last=compiler-gcc.h
-		for i in $(seq 10); do
+		for i in $(seq 11); do
 			[ -e include/linux/compiler-gcc$i.h ] ||
 				ln -s $last include/linux/compiler-gcc$i.h
 			last=compiler-gcc$i.h

From 5fbe2278423741089c2f8a1277ac220b0eafd863 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Nov 2021 19:50:33 +0100
Subject: [PATCH 1982/2207] linux/scripts: check for unset or null

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 0b2075277..ad04c7086 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -449,7 +449,7 @@ function check-patch()
 
 	while scripts/vers -b $v1 $v2 -L; do
 		# cache lookup
-		local cache=$PWD/cache/$v1/$dtype-$driver${driver_version+:$driver_version}
+		local cache=$PWD/cache/$v1/$dtype-$driver${driver_version:+:$driver_version}
 		mkdir -p $cache
 		local cpatch=$cache/patch
 		local cnmcommit=$cache/nmcommit

From 85e4dc3a3a68aec2a72bb0c2d925bc44bdb541e4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 2 Nov 2021 18:20:48 +0100
Subject: [PATCH 1983/2207] linux: patches for v5.15

---
 ...a00--99999 => vanilla--i40e--50a00--50f00} |   0
 .../final-patches/vanilla--i40e--50f00--99999 | 115 ++++++++++++++++++
 2 files changed, 115 insertions(+)
 rename LINUX/final-patches/{vanilla--i40e--50a00--99999 => vanilla--i40e--50a00--50f00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--50f00--99999

diff --git a/LINUX/final-patches/vanilla--i40e--50a00--99999 b/LINUX/final-patches/vanilla--i40e--50a00--50f00
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--50a00--99999
rename to LINUX/final-patches/vanilla--i40e--50a00--50f00
diff --git a/LINUX/final-patches/vanilla--i40e--50f00--99999 b/LINUX/final-patches/vanilla--i40e--50f00--99999
new file mode 100644
index 000000000..5ec51cbcc
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--50f00--99999
@@ -0,0 +1,115 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index e04b540cedc8..26d4d4edb438 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -98,6 +98,10 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+ MODULE_LICENSE("GPL v2");
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+@@ -3255,6 +3259,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3356,6 +3364,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3386,6 +3398,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->xsk_pool) {
+ 		xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+ 		ok = i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring));
+@@ -13772,6 +13789,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14137,6 +14159,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 10a83e5385c7..1fcf408e2ef3 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_txrx_common.h"
+ #include "i40e_xsk.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -938,6 +942,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2448,6 +2457,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	int xdp_res = 0;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif

From 76612e1a2c0df73ec711ab30871ddaef73d6a44c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 5 Nov 2021 16:28:14 +0100
Subject: [PATCH 1984/2207] linux/ext-drivers: fix dependency on netmap's
 Module.symvers

---
 LINUX/default-config.mak.in_ | 2 +-
 LINUX/netmap.mak.in          | 5 ++---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 14bff3674..d593a9684 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -62,7 +62,7 @@ define intel_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sourceforge.net/projects/e1000/files/$(1)%20stable/$(2)/$(1)-$(2).tar.gz -P @SRCDIR@/ext-drivers/
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
-$(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+$(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
 $(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
 $(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
 $(1)@distclean	:= rm -rf $(1)-$(2)
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 9cf2cc1ac..1b0779180 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -63,9 +63,8 @@ distclean-$(1):
 endef
 
 define external_driver
-build-$(1): get-$(1)
-	if [ -d $(1) ] && [ -e Module.symvers ]; then cp Module.symvers $(1); fi
-	+$($(1)@build)
+build-$(1): get-$(1) Module.symvers
+	+KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers; export KBUILD_EXTRA_SYMBOLS; $($(1)@build)
 clean-$(1):
 	-$($(1)@clean)
 install-$(1): install-netmap

From fc7bfde8df412730c2a0adc6e471e41e857a0f2d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 5 Nov 2021 17:23:43 +0100
Subject: [PATCH 1985/2207] linux/ext-drivers: add explicit dependency on
 netmap.ko

---
 LINUX/netmap.mak.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 1b0779180..be2e5d9a0 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -63,7 +63,7 @@ distclean-$(1):
 endef
 
 define external_driver
-build-$(1): get-$(1) Module.symvers
+build-$(1): get-$(1) netmap.ko
 	+KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers; export KBUILD_EXTRA_SYMBOLS; $($(1)@build)
 clean-$(1):
 	-$($(1)@clean)

From a63ab0c44396a5e112f290ef4f6d98e67c600f8f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 5 Dec 2021 09:53:55 +0100
Subject: [PATCH 1986/2207] linux/ixgbe: patch for Intel 5.13.4 version

---
 LINUX/final-patches/intel--ixgbe--5.13.4 | 173 +++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.13.4

diff --git a/LINUX/final-patches/intel--ixgbe--5.13.4 b/LINUX/final-patches/intel--ixgbe--5.13.4
new file mode 100644
index 000000000..4ec4c688d
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.13.4
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index adccdaa..137c98f 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 57db217..b806707 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -716,6 +716,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -735,6 +752,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2213,6 +2241,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3731,6 +3769,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4422,6 +4464,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13172,6 +13220,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13228,6 +13280,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From 7a7299724a3c594ac541fa7cd2d496df65f90034 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 5 Dec 2021 09:55:06 +0100
Subject: [PATCH 1987/2207] linux/i40e: patch for Intel 2.17.4 version

---
 LINUX/final-patches/intel--i40e--2.17.4 | 170 ++++++++++++++++++++++++
 1 file changed, 170 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.17.4

diff --git a/LINUX/final-patches/intel--i40e--2.17.4 b/LINUX/final-patches/intel--i40e--2.17.4
new file mode 100644
index 000000000..4e3cd60cf
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.17.4
@@ -0,0 +1,170 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index e9a83b9..a5d7708 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_I40E) += i40e.o
++obj-$(CONFIG_I40E) += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,14 +28,14 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -89,9 +89,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 874644b..6440a6d 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -152,6 +152,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3989,6 +3994,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4042,6 +4051,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4070,6 +4083,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -15228,6 +15246,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15600,6 +15624,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index a039064..2c34cf8 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_prototype.h"
+ #include "i40e_txrx_common.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -936,6 +940,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2771,7 +2780,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif

From 11938d3c65e5f4419f0258cb5b6ae27993e1262f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 5 Dec 2021 09:56:17 +0100
Subject: [PATCH 1988/2207] linux/ixgbevf: patch for Intel 4.13.3 version

---
 LINUX/final-patches/intel--ixgbevf--4.13.3 | 168 +++++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.13.3

diff --git a/LINUX/final-patches/intel--ixgbevf--4.13.3 b/LINUX/final-patches/intel--ixgbevf--4.13.3
new file mode 100644
index 000000000..6c6b63ea3
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.13.3
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 6391546..780d1c0 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index e03b00e..2c7165f 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1377,6 +1405,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2095,6 +2133,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2329,6 +2371,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5630,8 +5676,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5672,6 +5720,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 22e5420..7b5b3df 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -4,6 +4,8 @@
+ #ifndef _KCOMPAT_H_
+ #define _KCOMPAT_H_
+ 
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 217a00f82a55ef8590df38a3c4087c0c45beadca Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 5 Dec 2021 10:00:21 +0100
Subject: [PATCH 1989/2207] linux/igb: patches for Intel 5.7.2 and 5.8.5
 versions

---
 LINUX/final-patches/intel--igb--5.7.2 | 138 ++++++++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.8.5 | 138 ++++++++++++++++++++++++++
 2 files changed, 276 insertions(+)
 create mode 100644 LINUX/final-patches/intel--igb--5.7.2
 create mode 100644 LINUX/final-patches/intel--igb--5.8.5

diff --git a/LINUX/final-patches/intel--igb--5.7.2 b/LINUX/final-patches/intel--igb--5.7.2
new file mode 100644
index 000000000..be96e5e7f
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.7.2
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 2ff71a6..6bbeb56 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -25,19 +25,19 @@ define igb-y
+ 	e1000_82575.o
+ 	e1000_i210.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -106,9 +106,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index d9ec4b2..6590a60 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -241,6 +241,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3209,6 +3213,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3414,6 +3422,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3826,6 +3838,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7511,6 +7526,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8527,6 +8547,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8846,6 +8871,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--igb--5.8.5 b/LINUX/final-patches/intel--igb--5.8.5
new file mode 100644
index 000000000..e58675fd5
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.8.5
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 682db41..303f09b 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 75d48c1..00fdc04 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7430,6 +7445,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8446,6 +8466,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8765,6 +8790,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;

From 0ceb4d83e569298c14e9d6d0a717084d06d9a453 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 5 Feb 2022 08:34:29 +0100
Subject: [PATCH 1990/2207] fix indentation

---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bea136c76..901c6c1f8 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -541,7 +541,7 @@ SYSBEGIN(main_init);
 
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
-    "Netmap args");
+		"Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
 		CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
 #ifdef CONFIG_NETMAP_DEBUG

From 7ad68a32dc134fb2d69bd1f785434f0b70863d81 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 5 Feb 2022 08:35:04 +0100
Subject: [PATCH 1991/2207] linux: patches for v5.16

---
 ...c00--40100 => vanilla--i40e--30c00--30d00} |   0
 .../final-patches/vanilla--i40e--30e00--40100 | 117 +++++++++++++++++
 ...f00--99999 => vanilla--i40e--50f00--51000} |   0
 .../final-patches/vanilla--i40e--51000--99999 | 116 +++++++++++++++++
 ...0800--30f00 => vanilla--igb--30800--30d00} |   0
 .../final-patches/vanilla--igb--30e00--30f00  |  89 +++++++++++++
 ...00--30f00 => vanilla--ixgbe--30e00--30f00} |  22 ++--
 .../vanilla--ixgbevf--30d00--30e00            | 118 ------------------
 8 files changed, 333 insertions(+), 129 deletions(-)
 rename LINUX/final-patches/{vanilla--i40e--30c00--40100 => vanilla--i40e--30c00--30d00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--30e00--40100
 rename LINUX/final-patches/{vanilla--i40e--50f00--99999 => vanilla--i40e--50f00--51000} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--51000--99999
 rename LINUX/final-patches/{vanilla--igb--30800--30f00 => vanilla--igb--30800--30d00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--igb--30e00--30f00
 rename LINUX/final-patches/{vanilla--ixgbe--30d00--30f00 => vanilla--ixgbe--30e00--30f00} (83%)
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30d00--30e00

diff --git a/LINUX/final-patches/vanilla--i40e--30c00--40100 b/LINUX/final-patches/vanilla--i40e--30c00--30d00
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--30c00--40100
rename to LINUX/final-patches/vanilla--i40e--30c00--30d00
diff --git a/LINUX/final-patches/vanilla--i40e--30e00--40100 b/LINUX/final-patches/vanilla--i40e--30e00--40100
new file mode 100644
index 000000000..1f5c7f20b
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--30e00--40100
@@ -0,0 +1,117 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index b901371ca361..cef02532b6e1 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -90,6 +90,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(DRV_VERSION);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+  * @hw:   pointer to the HW structure
+@@ -2224,6 +2229,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -2288,6 +2297,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	rx_ctx.l2tsel = 1;
+ 	rx_ctx.showiv = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -2310,6 +2323,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -6764,6 +6782,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -7083,6 +7106,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 		break;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index d4bb482b1a7f..54b9fdfb33a6 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -26,6 +26,10 @@
+ 
+ #include "i40e.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -329,6 +333,11 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
+ 	unsigned int total_packets = 0;
+ 	unsigned int total_bytes = 0;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -975,6 +984,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	u64 qword;
+ 	u16 rx_ptype;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS)
++			return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++	}
++#endif /* DEV_NETMAP */
++
+ 	rx_desc = I40E_RX_DESC(rx_ring, i);
+ 	qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
+ 	rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
diff --git a/LINUX/final-patches/vanilla--i40e--50f00--99999 b/LINUX/final-patches/vanilla--i40e--50f00--51000
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--50f00--99999
rename to LINUX/final-patches/vanilla--i40e--50f00--51000
diff --git a/LINUX/final-patches/vanilla--i40e--51000--99999 b/LINUX/final-patches/vanilla--i40e--51000--99999
new file mode 100644
index 000000000..92f96618c
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--51000--99999
@@ -0,0 +1,116 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 61afc220fc6c..45c3feb5efb0 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -98,6 +98,10 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+ MODULE_LICENSE("GPL v2");
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ static void netdev_hw_addr_refcnt(struct i40e_mac_filter *f,
+ 				  struct net_device *netdev, int delta)
+@@ -3297,6 +3301,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3398,6 +3406,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3428,6 +3440,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->xsk_pool) {
+ 		xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+ 		ok = i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring));
+@@ -13859,6 +13876,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14227,6 +14250,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 10a83e5385c7..1fcf408e2ef3 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_txrx_common.h"
+ #include "i40e_xsk.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -938,6 +942,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2448,6 +2457,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	int xdp_res = 0;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/vanilla--igb--30800--30f00 b/LINUX/final-patches/vanilla--igb--30800--30d00
similarity index 100%
rename from LINUX/final-patches/vanilla--igb--30800--30f00
rename to LINUX/final-patches/vanilla--igb--30800--30d00
diff --git a/LINUX/final-patches/vanilla--igb--30e00--30f00 b/LINUX/final-patches/vanilla--igb--30e00--30f00
new file mode 100644
index 000000000..d96370a10
--- /dev/null
+++ b/LINUX/final-patches/vanilla--igb--30e00--30f00
@@ -0,0 +1,89 @@
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 46d31a49f5ea..199445e39cdc 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -258,6 +258,10 @@ static int debug = -1;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct igb_reg_info {
+ 	u32 ofs;
+ 	char *name;
+@@ -1765,7 +1769,6 @@ void igb_down(struct igb_adapter *adapter)
+ 		napi_disable(&(adapter->q_vector[i]->napi));
+ 	}
+ 
+-
+ 	del_timer_sync(&adapter->watchdog_timer);
+ 	del_timer_sync(&adapter->phy_info_timer);
+ 
+@@ -2492,6 +2495,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef CONFIG_IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == 0) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -2744,6 +2751,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
+ 	}
+ #endif
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 
+ 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+ 	 * would have already happened in close and is redundant.
+@@ -3215,6 +3226,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	wr32(E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -6244,6 +6258,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return 1; /* cleaned ok */
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+@@ -6903,6 +6921,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
+ 	do {
+ 		union e1000_adv_rx_desc *rx_desc;
+ 
+@@ -7020,6 +7042,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30e00--30f00
similarity index 83%
rename from LINUX/final-patches/vanilla--ixgbe--30d00--30f00
rename to LINUX/final-patches/vanilla--ixgbe--30e00--30f00
index febd3bc92..0162133fb 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbe--30e00--30f00
@@ -1,8 +1,8 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 5bcc870f8367..eef466715f03 100644
+index 18076c4178b4..12646872c0f6 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
-@@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+@@ -359,6 +359,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
  	{}
  };
  
@@ -25,7 +25,7 @@ index 5bcc870f8367..eef466715f03 100644
  
  /*
   * ixgbe_regdump - register printout routine
-@@ -959,6 +975,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+@@ -990,6 +1006,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
  	if (test_bit(__IXGBE_DOWN, &adapter->state))
  		return true;
  
@@ -43,7 +43,7 @@ index 5bcc870f8367..eef466715f03 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1995,6 +2022,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+@@ -2026,6 +2053,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
  #endif /* IXGBE_FCOE */
  	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
  
@@ -60,7 +60,7 @@ index 5bcc870f8367..eef466715f03 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3018,6 +3055,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+@@ -3049,6 +3086,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  
  	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
  
@@ -71,7 +71,7 @@ index 5bcc870f8367..eef466715f03 100644
  	/* enable queue */
  	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
-@@ -3394,6 +3435,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3429,6 +3470,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -82,7 +82,7 @@ index 5bcc870f8367..eef466715f03 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4600,16 +4645,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4636,16 +4681,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  	/* enable transmits */
  	netif_tx_start_all_queues(adapter->netdev);
  
@@ -99,7 +99,7 @@ index 5bcc870f8367..eef466715f03 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5412,6 +5447,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5451,6 +5486,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -107,7 +107,7 @@ index 5bcc870f8367..eef466715f03 100644
  	return 0;
  
  err_set_queues:
-@@ -8174,6 +8210,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8228,6 +8264,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -118,7 +118,7 @@ index 5bcc870f8367..eef466715f03 100644
  	return 0;
  
  err_register:
-@@ -8208,6 +8248,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -8262,6 +8302,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
@@ -128,4 +128,4 @@ index 5bcc870f8367..eef466715f03 100644
 +
  	ixgbe_dbg_adapter_exit(adapter);
  
- 	set_bit(__IXGBE_DOWN, &adapter->state);
+ 	set_bit(__IXGBE_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
deleted file mode 100644
index 0dc67d0a7..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
+++ /dev/null
@@ -1,118 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 92ef4cb5a8e8..3c5d85cec0a7 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -193,6 +211,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	tx_buffer_info = &tx_ring->tx_buffer_info[i];
- 	eop_desc = tx_buffer_info->next_to_watch;
-@@ -434,6 +463,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1087,6 +1126,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter)
- }
- 
- /**
-+}
-+
-  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
-  * @adapter: board private structure
-  *
-@@ -1117,6 +1158,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
- 		 */
- 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-+#ifdef DEV_NETMAP
-+		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
-+#endif /* DEV_NETMAP */
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
- 	}
- }
-@@ -1379,6 +1423,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
- 	ixgbevf_configure_rx(adapter);
- 	for (i = 0; i < adapter->num_rx_queues; i++) {
- 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
-+#ifdef DEV_NETMAP
-+		if (ixgbe_netmap_configure_rx_ring(adapter, i))
-+			continue;
-+#endif /* DEV_NETMAP */
- 		ixgbevf_alloc_rx_buffers(adapter, ring,
- 					 ixgbevf_desc_unused(ring));
- 	}
-@@ -3545,6 +3593,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3577,6 +3630,11 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);

From d33ca9da85b3ba440afe8035949f83488c118ce3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 5 Feb 2022 08:35:20 +0100
Subject: [PATCH 1992/2207] add SECURITY.md

---
 SECURITY.md | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 SECURITY.md

diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..acdbdfcde
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,5 @@
+Reporting a Vulnerability
+=========================
+
+Please report suspected vulnerabilities to giuseppe.lettieri@unipi.it. You will receive a response as soon as possibile.
+Patches will target the master branch.

From df7abd260385456cdd1961df25bd472b234c4ce9 Mon Sep 17 00:00:00 2001
From: Michael Rowley 
Date: Sat, 5 Feb 2022 16:33:45 +0000
Subject: [PATCH 1993/2207] Fixed formatting issue.

---
 WINDOWS/netmap_windows.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index 133190836..a68da4493 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -940,7 +940,7 @@ nm_os_ifnet_mtu(struct ifnet *ifp)
 void
 generic_timer_handler(struct hrtimer *t)
 {
-	DbgPrint("unimplemented generic_timer_handler %p\n", t);
+	DbgPrint("unimplemented generic_timer_handler\n", t);
 #if 0
 	struct nm_generic_mit *mit =
 		container_of(t, struct nm_generic_mit, mit_timer);
@@ -968,7 +968,7 @@ generic_timer_handler(struct hrtimer *t)
 void nm_os_mitigation_init(struct nm_generic_mit *mit, int idx,
 struct netmap_adapter *na)
 {
-	DbgPrint("unimplemented generic_timer_handler %p\n");
+	DbgPrint("unimplemented generic_timer_handler\n");
 	//KeInitializeDpc(&mit->mit_timer.deferred_proc, &generic_timer_handler, NULL);
 	//KeInitializeTimer(&mit->mit_timer.timer);
 	//hrtimer_init(&mit->mit_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
@@ -980,7 +980,7 @@ struct netmap_adapter *na)
 
 void nm_os_mitigation_start(struct nm_generic_mit *mit)
 {
-	DbgPrint("unimplemented generic_timer_handler %p\n");
+	DbgPrint("unimplemented generic_timer_handler\n");
 	//LARGE_INTEGER test;
 	//KeSetTimerEx(&mit->mit_timer.timer, test, 1000, &mit->mit_timer.deferred_proc);
 	//mit->mit_timer.active = TRUE;
@@ -990,13 +990,13 @@ void nm_os_mitigation_start(struct nm_generic_mit *mit)
 
 void nm_os_mitigation_restart(struct nm_generic_mit *mit)
 {
-	DbgPrint("unimplemented nm_os_mitigation_start %p\n");
+	DbgPrint("unimplemented nm_os_mitigation_start\n");
 	//hrtimer_forward_now(&mit->mit_timer, ktime_set(0, netmap_generic_mit));
 }
 
 int nm_os_mitigation_active(struct nm_generic_mit *mit)
 {
-	DbgPrint("unimplemented nm_os_mitigation_active %p\n");
+	DbgPrint("unimplemented nm_os_mitigation_active\n");
 	return 0;
 	//return mit->mit_timer.active;
 	//return hrtimer_active(&mit->mit_timer);

From 99e818a6a92e6d89abe38dafe4c4a03aaf5867e2 Mon Sep 17 00:00:00 2001
From: Michio 
Date: Sun, 6 Feb 2022 23:09:27 +0000
Subject: [PATCH 1994/2207] linux: FOLL_SPLIT is removed in 5.15.
 https://patchwork.kernel.org/project/linux-mm/patch/20210430055556.xcmsU3Fo2%25akpm@linux-foundation.org/

---
 LINUX/bsd_glue.h | 3 +++
 LINUX/configure  | 9 +++++++++
 2 files changed, 12 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index fe6553444..1ebb9691f 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -148,6 +148,9 @@ struct net_device_ops {
 			NM_SET_PAGE_COUNT(&(page)[i_], 1);\
 	} while (0)
 #endif /* HAVE_SPLIT_PAGE */
+#ifndef NETMAP_LINUX_HAVE_FOLL_SPLIT
+#define FOLL_SPLIT	FOLL_SPLIT_PMD
+#endif
 
 #if !defined(NETMAP_LINUX_HAVE_NNITD) && !defined(netdev_notifier_info_to_dev)
 #define netdev_notifier_info_to_dev(ptr)	(ptr)
diff --git a/LINUX/configure b/LINUX/configure
index fd3ef6cf0..99665425b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1731,6 +1731,15 @@ EOF
 	}
 EOF
 
+  add_test 'have FOLL_SPLIT' <
+
+	int
+	dummy(void) {
+		return FOLL_SPLIT;
+	}
+EOF
+
 # check for page_to_virt
   add_test 'have PAGE_TO_VIRT' <

From 7490d029579e29be89d1935ad4a84aa202a3b0c4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 7 Feb 2022 12:29:37 +0100
Subject: [PATCH 1995/2207] make sure that na->nm_register() is called at least
 once

Some adapters (e.g., generic) do all their initialization the
first time nm_register(,1) is called. Before this patch, however
nm_register(,1) was not called at all when only host rings where beeing
put in netmap mode. On the other end, nm_register(,0) is always called
when the adapter is released, irrespective of the kind of rings that
were beeing used. This caused the generic adapter (and possibily
others) to try to release resources that had never been allocated,
resulting in warnings and panics.

This patch makes sure that nm_register(0,1) is called at least once
when any ring of the adapter is put in netmap mode, thus restoring
symmetry with the release path.
---
 sys/dev/netmap/netmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 901c6c1f8..2255df706 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2654,7 +2654,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
 	 */
 	netmap_update_hostrings_mode(na);
 
-	if (nm_kring_pending(priv)) {
+	if (na->active_fds == 0 || nm_kring_pending(priv)) {
 		/* Some kring is switching mode, tell the adapter to
 		 * react on this. */
 		netmap_set_all_rings(na, NM_KR_LOCKED);

From 0164d4579f1be1db37dd845555914047f298abaa Mon Sep 17 00:00:00 2001
From: Carsten Cordes 
Date: Thu, 10 Feb 2022 21:42:05 +0100
Subject: [PATCH 1996/2207] Fixes ERROR: modpost errors when running make
 install on Debian Bullseye

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index d593a9684..fb6a097c6 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -63,7 +63,7 @@ $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sour
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
 $(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
-$(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@
+$(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
 $(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
 $(1)@distclean	:= rm -rf $(1)-$(2)
 $(1)@force	:= 1

From ae7ee748963c4b3e4e4db902c912552422dceb47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Olivier=20Cochard-Labb=C3=A9?= 
Date: Tue, 15 Feb 2022 18:42:45 +0100
Subject: [PATCH 1997/2207] Fix variable 'err' usage and compilation

Fix compilation and correct usage of the err variable:

nmreplay.c:1105:13: error: variable 'err' set but not used [-Werror,-Wunused-but-set-variable]
        int ch, i, err=0;
---
 apps/nmreplay/nmreplay.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index e0a9e2146..1ccfb6e31 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -1273,7 +1273,7 @@ main(int argc, char **argv)
 	D("exiting on abort");
 	sleep(1);
 
-	return (0);
+	return (err);
 }
 
 /* conversion factor for numbers.

From 1bf288e0445d0a31261e772d376599549a4091ef Mon Sep 17 00:00:00 2001
From: Saman Dehghan 
Date: Thu, 17 Feb 2022 14:21:50 +0330
Subject: [PATCH 1998/2207] Now netmap supports intel ice nic driver

---
 LINUX/configure                        |  25 +-
 LINUX/default-config.mak.in_           |   4 +-
 LINUX/final-patches/intel--ice--1.7.16 | 209 +++++++++
 LINUX/ice_netmap_linux.h               | 571 +++++++++++++++++++++++++
 4 files changed, 807 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/intel--ice--1.7.16
 create mode 100644 LINUX/ice_netmap_linux.h

diff --git a/LINUX/configure b/LINUX/configure
index 99665425b..48acb9a1d 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -113,7 +113,7 @@ subsys enable ptnetmap
 
 # available drivers
 driver_avail="stmmac r8169.c virtio_net.c forcedeth.c veth.c \
-	e1000 e1000e igb ixgbe ixgbevf i40e vmxnet3 mlx5"
+	e1000 e1000e igb ixgbe ixgbevf ice i40e vmxnet3 mlx5"
 # enabled drivers (bitfield)
 driver=
 drv()
@@ -135,6 +135,7 @@ edrv enable igb
 edrv enable ixgbe
 edrv enable ixgbevf
 edrv enable i40e
+edrv enable ice
 edrv enable mlx5
 edrv enable virtio_net.c
 
@@ -2254,6 +2255,28 @@ EOF
 
   fi # virtio-net
 
+  if drv enabled ice; then
+    add_test 'define ICE_PTR_ARRAY' <tx_rings[0];
+  	}
+EOF
+
+   add_test 'define ICE_PTR_STATE' <
+	#pragma GCC diagnostic error "-Wincompatible-pointer-types"
+
+	int
+	dummy(struct ice_pf *pf) {
+		return test_and_set_bit(1, &pf->state);
+	}
+EOF
+  fi # ice
+
   if drv enabled i40e; then
     add_test 'define I40E_PTR_ARRAY' < ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 9f2320f..a3c304c 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,12 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_virtchnl_pf.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define SAMAN
++#define NETMAP_ICE_MAIN
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -448,6 +454,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -601,6 +611,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++    if (ice_netmap_configure_rx_ring(ring))
++        return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -871,6 +886,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++    ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_lib.c b/ice/ice_lib.c
+index 8899720..03bfcff 100644
+--- a/ice/ice_lib.c
++++ b/ice/ice_lib.c
+@@ -9,6 +9,12 @@
+ #include "ice_devlink.h"
+ #include "ice_vsi_vlan_ops.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_MAIN
++#include 
++#endif
++
++
+ /**
+  * ice_vsi_type_str - maps VSI type enum to string equivalents
+  * @vsi_type: VSI type enum
+@@ -2790,6 +2796,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ 	if (!vsi->agg_node)
+ 		ice_set_agg_vsi(vsi);
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ unroll_clear_rings:
+@@ -3134,6 +3144,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
+ 	 */
+ 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
+ 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
++#ifdef DEV_NETMAP
++        netmap_detach(vsi->netdev);
++#endif
+ 		unregister_netdev(vsi->netdev);
+ 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 037cc5a..884df87 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
+ 	if (!rx_ring->rx_buf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (rx_ring->xsk_pool) {
+ 		ice_xsk_clean_rx_ring(rx_ring);
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
new file mode 100644
index 000000000..ee6a6249b
--- /dev/null
+++ b/LINUX/ice_netmap_linux.h
@@ -0,0 +1,571 @@
+#include 
+#include 
+#include 
+
+int ice_netmap_txsync(struct netmap_kring *kring, int flags);
+int ice_netmap_rxsync(struct netmap_kring *kring, int flags);
+
+extern int ix_crcstrip;
+
+#ifdef NETMAP_LINUX_ICE_PTR_ARRAY
+#define NM_ICE_TX_RING(a, r)		((a)->tx_rings[(r)])
+#define NM_ICE_RX_RING(a, r)		((a)->rx_rings[(r)])
+#else
+#define NM_ICE_TX_RING(a, r)		(&(a)->tx_rings[(r)])
+#define NM_ICE_RX_RING(a, r)		(&(a)->rx_rings[(r)])
+#endif
+#ifdef NETMAP_LINUX_ICE_PTR_STATE
+#define NM_ICE_STATE(pf)		(&(pf)->state)
+#else
+#define NM_ICE_STATE(pf)		((pf)->state)
+#endif
+
+#ifdef NETMAP_ICE_MAIN
+
+#ifdef SAMAN
+#define ice_driver_name netmap_ice_driver_name
+char ice_driver_name[] = "ice" NETMAP_LINUX_DRIVER_SUFFIX;
+/*
+ * device-specific sysctl variables:
+ *
+ * ix_crcstrip: 0: NIC keeps CRC in rx frames (default), 1: NIC strips it.
+ *	During regular operations the CRC is stripped, but on some
+ *	hardware reception of frames not multiple of 64 is slower,
+ *	so using crcstrip=0 helps in benchmarks.
+ *      The driver by default strips CRCs and we do not override it.
+ *
+ */
+SYSCTL_DECL(_dev_netmap);
+int ix_crcstrip = 1;
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
+		CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
+#endif
+
+static void
+ice_netmap_configure_tx_ring(struct ice_ring *ring)
+{
+	struct netmap_adapter *na;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return;
+	}
+
+	na = NA(ring->netdev);
+	netmap_reset(na, NR_TX, ring->q_index, 0);
+}
+
+static void
+ice_netmap_preconfigure_rx_ring(struct ice_ring *ring,
+		struct ice_rlan_ctx *rx_ctx)
+{
+	struct netmap_adapter *na;
+	struct netmap_kring *kring;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return;
+	}
+
+	na = NA(ring->netdev);
+
+	if (netmap_reset(na, NR_RX, ring->q_index, 0) == NULL)
+		return;	// not in native netmap mode
+
+	kring = na->rx_rings[ring->q_index];
+	rx_ctx->dbuf = kring->hwbuf_len >> ICE_RLAN_CTX_DBUF_S;
+}
+
+static int
+ice_netmap_configure_rx_ring(struct ice_ring *ring)
+{
+	struct netmap_adapter *na;
+	struct netmap_slot *slot;
+	struct netmap_kring *kring;
+	int lim, i, ring_nr;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return 0;
+	}
+
+	na = NA(ring->netdev);
+	ring_nr = ring->q_index;
+
+	slot = netmap_reset(na, NR_RX, ring_nr, 0);
+	if (!slot)
+		return 0;	// not in native netmap mode
+
+	kring = na->rx_rings[ring_nr];
+	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
+
+	for (i = 0; i < lim; i++) {
+		int si = netmap_idx_n2k(kring, i);
+		uint64_t paddr;
+		union ice_32b_rx_flex_desc *rx = ICE_RX_DESC(ring, i);
+		PNMB_O(kring, slot + si, &paddr);
+
+		rx->read.pkt_addr = htole64(paddr);
+		rx->read.hdr_addr = 0;
+	}
+	ring->next_to_clean = 0;
+	wmb();
+	writel(lim, ring->tail);
+	return 1;
+}
+
+/*
+ * Register/unregister. We are already under netmap lock.
+ * Only called on the first register or the last unregister.
+ */
+static int
+ice_netmap_reg(struct netmap_adapter *na, int onoff)
+{
+	struct ifnet *ifp = na->ifp;
+	struct ice_netdev_priv *np = netdev_priv(ifp);
+	struct ice_vsi  *vsi = np->vsi;
+	struct ice_pf   *pf = (struct ice_pf *)vsi->back;
+	bool was_running;
+
+	while (test_and_set_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf)))
+			usleep_range(1000, 2000);
+
+	if ( (was_running = netif_running(vsi->netdev)) )
+		ice_down(vsi);
+
+	//set_crcstrip(&adapter->hw, onoff);
+	/* enable or disable flags and callbacks in na and ifp */
+	if (onoff) {
+		nm_set_native_flags(na);
+	} else {
+		nm_clear_native_flags(na);
+	}
+	if (was_running) {
+		ice_up(vsi);
+	}
+	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
+
+	clear_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf));
+
+	return 0;
+}
+
+static int
+ice_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
+{
+	uint64_t incr;
+
+	kring->buf_align = 0;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+
+	incr = 1UL << ICE_RLAN_CTX_DBUF_S;
+	target &= ~(incr - 1);
+	if (target < 1024UL || target > 16384UL - incr)
+		return EINVAL;
+
+	kring->hwbuf_len = target;
+
+	return 0;
+}
+
+static int
+ice_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
+
+	return 0;
+}
+
+/*
+ * The attach routine, called near the end of ice_attach(),
+ * fills the parameters for netmap_attach() and calls it.
+ * It cannot fail, in the worst case (such as no memory)
+ * netmap mode will be disabled and the driver will only
+ * operate in standard mode.
+ */
+static void
+ice_netmap_attach(struct ice_vsi *vsi)
+{
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp = vsi->netdev;
+	na.pdev = &vsi->back->pdev->dev;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
+	na.num_tx_desc = NM_ICE_TX_RING(vsi, 0)->count;
+	na.num_rx_desc = NM_ICE_RX_RING(vsi, 0)->count;
+	na.num_tx_rings = vsi->num_txq;
+    na.num_rx_rings = vsi->num_rxq;
+	na.rx_buf_maxsize = vsi->rx_buf_len;
+	na.nm_txsync = ice_netmap_txsync;
+	na.nm_rxsync = ice_netmap_rxsync;
+	na.nm_register = ice_netmap_reg;
+	na.nm_config = ice_netmap_config;
+	na.nm_bufcfg = ice_netmap_bufcfg;
+	netmap_attach(&na);
+}
+
+#else /* NETMAP_ICE_MAIN */
+
+
+/*
+ * Reconcile kernel and user view of the transmit ring.
+ *
+ * All information is in the kring.
+ * Userspace wants to send packets up to the one before kring->rhead,
+ * kernel knows kring->nr_hwcur is the first unsent packet.
+ *
+ * Here we push packets out (as many as possible), and possibly
+ * reclaim buffers from previously completed transmission.
+ *
+ * The caller (netmap) guarantees that there is only one instance
+ * running at any time. Any interference with other driver
+ * methods should be handled by the individual drivers.
+ */
+
+static inline u_int
+ice_netmap_read_hwtail(void *base, int nslots)
+{
+	struct ice_tx_desc *desc = base;
+	return le32toh(*(volatile __le32 *)&desc[nslots]);
+}
+
+int
+ice_netmap_txsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int nm_i;	/* index into the netmap ring */
+	u_int nic_i;	/* index into the NIC ring */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	/*
+	 * interrupts on every tx packet are expensive so request
+	 * them every half ring, or where NS_REPORT is set
+	 */
+	u_int report_frequency = kring->nkr_num_slots >> 1;
+
+	/* device-specific */
+	struct ice_netdev_priv *np = netdev_priv(ifp);
+	struct ice_vsi *vsi = np->vsi;
+	struct ice_ring *txr;
+
+	if (!netif_carrier_ok(ifp))
+		return 0;
+
+	txr = NM_ICE_TX_RING(vsi, kring->ring_id);
+	if (unlikely(!txr || !txr->desc)) {
+		nm_prlim(1, "ring %s is missing (txr=%p)", kring->name, txr);
+		return ENXIO;
+	}
+
+	/*
+	 * First part: process new packets to send.
+	 * nm_i is the current index in the netmap ring,
+	 * nic_i is the corresponding index in the NIC ring.
+	 * The two numbers differ because upon a *_init() we reset
+	 * the NIC ring but leave the netmap ring unchanged.
+	 * For the transmit ring, we have
+	 *
+	 *		nm_i = kring->nr_hwcur
+	 *		nic_i = IXGBE_TDT (not tracked in the driver)
+	 * and
+	 * 		nm_i == (nic_i + kring->nkr_hwofs) % ring_size
+	 *
+	 * In this driver kring->nkr_hwofs >= 0, but for other
+	 * drivers it might be negative as well.
+	 */
+
+	/*
+	 * If we have packets to send (kring->nr_hwcur != kring->rhead)
+	 * iterate over the netmap ring, fetch length and update
+	 * the corresponding slot in the NIC ring. Some drivers also
+	 * need to update the buffer's physical address in the NIC slot
+	 * even NS_BUF_CHANGED is not set (PNMB computes the addresses).
+	 *
+	 * The netmap_reload_map() calls is especially expensive,
+	 * even when (as in this case) the tag is 0, so do only
+	 * when the buffer has actually changed.
+	 *
+	 * If possible do not set the report/intr bit on all slots,
+	 * but only a few times per ring or when NS_REPORT is set.
+	 *
+	 * Finally, on 10G and faster drivers, it might be useful
+	 * to prefetch the next slot and txr entry.
+	 */
+
+	nm_i = kring->nr_hwcur;
+	if (nm_i != head) {	/* we have new packets to send */
+		nic_i = netmap_idx_k2n(kring, nm_i);
+
+		__builtin_prefetch(&ring->slot[nm_i]);
+		__builtin_prefetch(ICE_TX_DESC(txr, nic_i));
+
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			u_int len = slot->len;
+			uint64_t paddr;
+			uint64_t offset = nm_get_offset(kring, slot);
+
+			/* device-specific */
+			struct ice_tx_desc *curr = ICE_TX_DESC(txr, nic_i);
+			u64 hw_flags = 0;
+
+			/* prefetch for next round */
+			__builtin_prefetch(&ring->slot[nm_i + 1]);
+			__builtin_prefetch(ICE_TX_DESC(txr, nic_i));
+
+			PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
+
+			if (!(slot->flags & NS_MOREFRAG)) {
+				hw_flags |= ((u64)(ICE_TX_DESC_CMD_EOP) <<
+						ICE_TXD_QW1_CMD_S);
+				if (slot->flags & NS_REPORT || nic_i == 0 ||
+						nic_i == report_frequency) {
+					hw_flags |= ((u64)ICE_TX_DESC_CMD_RS <<
+							ICE_TXD_QW1_CMD_S);
+				}
+			}
+			if (slot->flags & NS_BUF_CHANGED) {
+				/* buffer has changed, reload map */
+				//netmap_reload_map(na, txr->dma.tag, txbuf->map, addr);
+			}
+			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
+
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, len, NR_TX);
+			/* Fill the slot in the NIC ring.
+			 * (we should investigate if using legacy descriptors
+			 * is faster). */
+			curr->buf_addr = htole64(paddr + offset);
+			curr->cmd_type_offset_bsz = htole64(
+			    ((u64)len << ICE_TXD_QW1_TX_BUF_SZ_S) |
+			    hw_flags // TODO
+			  ); /* more flags may be needed */
+
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+		}
+		kring->nr_hwcur = head;
+
+		/* synchronize the NIC ring */
+		//bus_dmamap_sync(txr->dma.tag, txr->dma.map,
+		//	BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+		/* (re)start the tx unit up to slot nic_i (excluded) */
+		wmb();
+		writel(nic_i, txr->tail);
+	}
+
+	/*
+	 * Second part: reclaim buffers for completed transmissions.
+	 */
+	nic_i = ice_netmap_read_hwtail(txr->desc, kring->nkr_num_slots);
+	if (nic_i != txr->next_to_clean) {
+		u_int tosync;
+		nm_i = netmap_idx_n2k(kring, nic_i);
+
+		/* some tx completed, increment avail */
+		txr->next_to_clean = nic_i;
+		tosync = nm_next(kring->nr_hwtail, lim);
+		/* sync all buffers that we are returning to userspace */
+		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+			struct netmap_slot *slot = &ring->slot[tosync];
+			uint64_t paddr;
+			(void)PNMB_O(kring, slot, &paddr);
+
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_TX);
+		}
+		kring->nr_hwtail = nm_prev(nm_i, lim);
+	}
+
+	return 0;
+}
+
+
+/*
+ * Reconcile kernel and user view of the receive ring.
+ * Same as for the txsync, this routine must be efficient.
+ * The caller guarantees a single invocations, but races against
+ * the rest of the driver should be handled here.
+ *
+ * On call, kring->rhead is the first packet that userspace wants
+ * to keep, and kring->rcur is the wakeup point.
+ * The kernel has previously reported packets up to kring->rtail.
+ *
+ * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
+ * of whether or not we received an interrupt.
+ */
+int
+ice_netmap_rxsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int nm_i;	/* index into the netmap ring */
+	u_int nic_i;	/* index into the NIC ring */
+	u_int ntail;	/* new tail for the user */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+
+	/* device-specific */
+	struct ice_netdev_priv *np = netdev_priv(ifp);
+	struct ice_vsi *vsi = np->vsi;
+	struct ice_ring *rxr;
+
+	if (!netif_running(ifp))
+		return 0;
+
+	rxr = NM_ICE_RX_RING(vsi, kring->ring_id);
+	if (unlikely(!rxr || !rxr->desc)) {
+		nm_prlim(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
+		return ENXIO;
+	}
+
+	if (head > lim)
+		return netmap_ring_reinit(kring);
+
+	/* XXX check sync modes */
+	//bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
+	//		BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	/*
+	 * First part: import newly received packets.
+	 *
+	 * nm_i is the index of the next free slot in the netmap ring,
+	 * nic_i is the index of the next received packet in the NIC ring,
+	 * and they may differ in case if_init() has been called while
+	 * in netmap mode. For the receive ring we have
+	 *
+	 *	nic_i = rxr->next_check;
+	 *	nm_i = kring->nr_hwtail (previous)
+	 * and
+	 *	nm_i == (nic_i + kring->nkr_hwofs) % ring_size
+	 *
+	 * rxr->next_check is set to 0 on a ring reinit
+	 */
+	if (netmap_no_pendintr || force_update) {
+		int crclen = ix_crcstrip ? 0 : 4;
+		int complete;
+
+		nic_i = rxr->next_to_clean; // or also k2n(kring->nr_hwtail)
+		nm_i = netmap_idx_n2k(kring, nic_i);
+		/* we advance tail only when we see a complete packet */
+		ntail = lim + 1;
+		complete = 0;
+
+		for (n = 0; ; n++) {
+			union ice_32b_rx_flex_desc *curr = ICE_RX_DESC(rxr, nic_i);
+			uint64_t qword = le64toh(*(uint64_t*)&curr->wb.status_error0);
+			uint32_t staterr = (qword & ICE_RXD_QW1_STATUS_M)
+				 >> ICE_RXD_QW1_STATUS_S;
+		        uint16_t slot_flags = 0;
+			struct netmap_slot *slot;
+			uint64_t paddr;
+
+			if (likely(complete)) {
+				ntail = nm_i;
+				complete = 0;
+			}
+
+			if ((staterr & (1<slot + nm_i;
+			slot->len = ((qword & ICE_RXD_QW1_LEN_PBUF_M)
+			    >> ICE_RXD_QW1_LEN_PBUF_S) - crclen;
+
+			if (unlikely((staterr & (1<flags = slot_flags;
+			PNMB_O(kring, slot, &paddr);
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_RX);
+
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+		}
+		if (n) { /* update the state variables */
+			rxr->next_to_clean = nic_i;
+			if (likely(ntail <= lim)) {
+				kring->nr_hwtail = ntail;
+				nm_prdis("%s: nic_i %u nm_i %u ntail %u n %u", ifp->if_xname, nic_i, nm_i, ntail, n);
+			}
+		}
+		kring->nr_kflags &= ~NKR_PENDINTR;
+	}
+
+	/*
+	 * Second part: skip past packets that userspace has released.
+	 * (kring->nr_hwcur to kring->rhead excluded),
+	 * and make the buffers available for reception.
+	 * As usual nm_i is the index in the netmap ring,
+	 * nic_i is the index in the NIC ring, and
+	 * nm_i == (nic_i + kring->nkr_hwofs) % ring_size
+	 */
+	nm_i = kring->nr_hwcur;
+	if (nm_i != head) {
+		nic_i = netmap_idx_k2n(kring, nm_i);
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t paddr;
+			void *addr = PNMB(na, slot, &paddr);
+			uint64_t offset = nm_get_offset(kring, slot);
+
+			union ice_32b_rx_flex_desc *curr = ICE_RX_DESC(rxr, nic_i);
+
+			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
+				goto ring_reset;
+
+			if (slot->flags & NS_BUF_CHANGED) {
+				/* buffer has changed, reload map */
+				//netmap_reload_map(na, rxr->ptag, rxbuf->pmap, addr);
+				slot->flags &= ~NS_BUF_CHANGED;
+			}
+			curr->read.pkt_addr = htole64(paddr + offset);
+			curr->read.hdr_addr = 0; // XXX needed
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+					&paddr, NETMAP_BUF_SIZE(na), NR_RX);
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+		}
+		kring->nr_hwcur = head;
+
+		/*
+		 * IMPORTANT: we must leave one free slot in the ring,
+		 * so move nic_i back by one unit
+		 */
+		nic_i = nm_prev(nic_i, lim);
+		wmb();
+		writel(nic_i, rxr->tail);
+	}
+
+	return 0;
+
+ring_reset:
+	return netmap_ring_reinit(kring);
+}
+
+#endif /* NETMAP_ICE_MAIN */
+
+/* end of file */

From 83bac1e4e89f3a717322dd872c0748fe6dae29c0 Mon Sep 17 00:00:00 2001
From: Saman Dehghan 
Date: Sun, 20 Feb 2022 11:11:24 +0330
Subject: [PATCH 1999/2207] Minor waning error in build time have been fixed.

---
 LINUX/default-config.mak.in_           |   3 +-
 LINUX/final-patches/intel--ice--1.7.16 |  17 +-
 LINUX/ice_netmap_linux.h               | 401 ++++++++++++-------------
 3 files changed, 207 insertions(+), 214 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index b77071e9a..e84c225e9 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -83,7 +83,6 @@ e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@SRCDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
@@ -94,7 +93,7 @@ $(eval $(call default,ixgbevf,4.3.2))
 $(eval $(call default,e1000e,3.4.0.2))
 $(eval $(call default,igb,5.3.5.20))
 $(eval $(call default,i40e,2.4.6))
-$(eval $(call default,ice,2.4.6))
+$(eval $(call default,ice,1.7.16))
 
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
diff --git a/LINUX/final-patches/intel--ice--1.7.16 b/LINUX/final-patches/intel--ice--1.7.16
index c0a3e63e2..95cfa2658 100644
--- a/LINUX/final-patches/intel--ice--1.7.16
+++ b/LINUX/final-patches/intel--ice--1.7.16
@@ -75,23 +75,22 @@ index a98dd4c..8b64fcc 100644
  	$(MAKE) -C lttng
  endif
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index 9f2320f..a3c304c 100644
+index 9f2320f..6e0adf4 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
-@@ -6,6 +6,12 @@
+@@ -6,6 +6,11 @@
  #include "ice_dcb_lib.h"
  #include "ice_virtchnl_pf.h"
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#define SAMAN
-+#define NETMAP_ICE_MAIN
++#define NETMAP_ICE_BASE
 +#include 
 +#endif
 +
  /**
   * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
   * @qs_cfg: gathered variables needed for PF->VSI queues assignment
-@@ -448,6 +454,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+@@ -448,6 +453,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
  	/* Rx queue threshold in units of 64 */
  	rlan_ctx.lrxqthresh = 1;
  
@@ -102,7 +101,7 @@ index 9f2320f..a3c304c 100644
  	/* Enable Flexible Descriptors in the queue context which
  	 * allows this driver to select a specific receive descriptor format
  	 * increasing context priority to pick up profile ID; default is 0x01;
-@@ -601,6 +611,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+@@ -601,6 +610,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
  		return 0;
  	}
  #endif /* HAVE_AF_XDP_ZC_SUPPORT */
@@ -114,7 +113,7 @@ index 9f2320f..a3c304c 100644
  
  	ice_alloc_rx_bufs(ring, num_bufs);
  
-@@ -871,6 +886,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+@@ -871,6 +885,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
  	txq = &qg_buf->txqs[0];
  	if (pf_q == le16_to_cpu(txq->txq_id))
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
@@ -127,7 +126,7 @@ index 9f2320f..a3c304c 100644
  	return 0;
  }
 diff --git a/ice/ice_lib.c b/ice/ice_lib.c
-index 8899720..03bfcff 100644
+index 8899720..99687fe 100644
 --- a/ice/ice_lib.c
 +++ b/ice/ice_lib.c
 @@ -9,6 +9,12 @@
@@ -135,7 +134,7 @@ index 8899720..03bfcff 100644
  #include "ice_vsi_vlan_ops.h"
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#define NETMAP_ICE_MAIN
++#define NETMAP_ICE_LIB
 +#include 
 +#endif
 +
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index ee6a6249b..9b00b69d5 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -2,9 +2,6 @@
 #include 
 #include 
 
-int ice_netmap_txsync(struct netmap_kring *kring, int flags);
-int ice_netmap_rxsync(struct netmap_kring *kring, int flags);
-
 extern int ix_crcstrip;
 
 #ifdef NETMAP_LINUX_ICE_PTR_ARRAY
@@ -20,204 +17,7 @@ extern int ix_crcstrip;
 #define NM_ICE_STATE(pf)		((pf)->state)
 #endif
 
-#ifdef NETMAP_ICE_MAIN
-
-#ifdef SAMAN
-#define ice_driver_name netmap_ice_driver_name
-char ice_driver_name[] = "ice" NETMAP_LINUX_DRIVER_SUFFIX;
-/*
- * device-specific sysctl variables:
- *
- * ix_crcstrip: 0: NIC keeps CRC in rx frames (default), 1: NIC strips it.
- *	During regular operations the CRC is stripped, but on some
- *	hardware reception of frames not multiple of 64 is slower,
- *	so using crcstrip=0 helps in benchmarks.
- *      The driver by default strips CRCs and we do not override it.
- *
- */
-SYSCTL_DECL(_dev_netmap);
-int ix_crcstrip = 1;
-SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
-		CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
-#endif
-
-static void
-ice_netmap_configure_tx_ring(struct ice_ring *ring)
-{
-	struct netmap_adapter *na;
-
-	if (!ring->netdev) {
-		// XXX it this possible?
-		return;
-	}
-
-	na = NA(ring->netdev);
-	netmap_reset(na, NR_TX, ring->q_index, 0);
-}
-
-static void
-ice_netmap_preconfigure_rx_ring(struct ice_ring *ring,
-		struct ice_rlan_ctx *rx_ctx)
-{
-	struct netmap_adapter *na;
-	struct netmap_kring *kring;
-
-	if (!ring->netdev) {
-		// XXX it this possible?
-		return;
-	}
-
-	na = NA(ring->netdev);
-
-	if (netmap_reset(na, NR_RX, ring->q_index, 0) == NULL)
-		return;	// not in native netmap mode
-
-	kring = na->rx_rings[ring->q_index];
-	rx_ctx->dbuf = kring->hwbuf_len >> ICE_RLAN_CTX_DBUF_S;
-}
-
-static int
-ice_netmap_configure_rx_ring(struct ice_ring *ring)
-{
-	struct netmap_adapter *na;
-	struct netmap_slot *slot;
-	struct netmap_kring *kring;
-	int lim, i, ring_nr;
-
-	if (!ring->netdev) {
-		// XXX it this possible?
-		return 0;
-	}
-
-	na = NA(ring->netdev);
-	ring_nr = ring->q_index;
-
-	slot = netmap_reset(na, NR_RX, ring_nr, 0);
-	if (!slot)
-		return 0;	// not in native netmap mode
-
-	kring = na->rx_rings[ring_nr];
-	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
-
-	for (i = 0; i < lim; i++) {
-		int si = netmap_idx_n2k(kring, i);
-		uint64_t paddr;
-		union ice_32b_rx_flex_desc *rx = ICE_RX_DESC(ring, i);
-		PNMB_O(kring, slot + si, &paddr);
-
-		rx->read.pkt_addr = htole64(paddr);
-		rx->read.hdr_addr = 0;
-	}
-	ring->next_to_clean = 0;
-	wmb();
-	writel(lim, ring->tail);
-	return 1;
-}
-
-/*
- * Register/unregister. We are already under netmap lock.
- * Only called on the first register or the last unregister.
- */
-static int
-ice_netmap_reg(struct netmap_adapter *na, int onoff)
-{
-	struct ifnet *ifp = na->ifp;
-	struct ice_netdev_priv *np = netdev_priv(ifp);
-	struct ice_vsi  *vsi = np->vsi;
-	struct ice_pf   *pf = (struct ice_pf *)vsi->back;
-	bool was_running;
-
-	while (test_and_set_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf)))
-			usleep_range(1000, 2000);
-
-	if ( (was_running = netif_running(vsi->netdev)) )
-		ice_down(vsi);
-
-	//set_crcstrip(&adapter->hw, onoff);
-	/* enable or disable flags and callbacks in na and ifp */
-	if (onoff) {
-		nm_set_native_flags(na);
-	} else {
-		nm_clear_native_flags(na);
-	}
-	if (was_running) {
-		ice_up(vsi);
-	}
-	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
-
-	clear_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf));
-
-	return 0;
-}
-
-static int
-ice_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
-{
-	uint64_t incr;
-
-	kring->buf_align = 0;
-
-	if (kring->tx == NR_TX) {
-		kring->hwbuf_len = target;
-		return 0;
-	}
-
-	incr = 1UL << ICE_RLAN_CTX_DBUF_S;
-	target &= ~(incr - 1);
-	if (target < 1024UL || target > 16384UL - incr)
-		return EINVAL;
-
-	kring->hwbuf_len = target;
-
-	return 0;
-}
-
-static int
-ice_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
-{
-	int ret = netmap_rings_config_get(na, info);
-
-	if (ret) {
-		return ret;
-	}
-
-	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
-
-	return 0;
-}
-
-/*
- * The attach routine, called near the end of ice_attach(),
- * fills the parameters for netmap_attach() and calls it.
- * It cannot fail, in the worst case (such as no memory)
- * netmap mode will be disabled and the driver will only
- * operate in standard mode.
- */
-static void
-ice_netmap_attach(struct ice_vsi *vsi)
-{
-	struct netmap_adapter na;
-
-	bzero(&na, sizeof(na));
-
-	na.ifp = vsi->netdev;
-	na.pdev = &vsi->back->pdev->dev;
-	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
-	na.num_tx_desc = NM_ICE_TX_RING(vsi, 0)->count;
-	na.num_rx_desc = NM_ICE_RX_RING(vsi, 0)->count;
-	na.num_tx_rings = vsi->num_txq;
-    na.num_rx_rings = vsi->num_rxq;
-	na.rx_buf_maxsize = vsi->rx_buf_len;
-	na.nm_txsync = ice_netmap_txsync;
-	na.nm_rxsync = ice_netmap_rxsync;
-	na.nm_register = ice_netmap_reg;
-	na.nm_config = ice_netmap_config;
-	na.nm_bufcfg = ice_netmap_bufcfg;
-	netmap_attach(&na);
-}
-
-#else /* NETMAP_ICE_MAIN */
-
+#ifdef NETMAP_ICE_LIB
 
 /*
  * Reconcile kernel and user view of the transmit ring.
@@ -397,7 +197,6 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 	return 0;
 }
 
-
 /*
  * Reconcile kernel and user view of the receive ring.
  * Same as for the txsync, this routine must be efficient.
@@ -566,6 +365,202 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 	return netmap_ring_reinit(kring);
 }
 
-#endif /* NETMAP_ICE_MAIN */
+/*
+ * Register/unregister. We are already under netmap lock.
+ * Only called on the first register or the last unregister.
+ */
+static int
+ice_netmap_reg(struct netmap_adapter *na, int onoff)
+{
+	struct ifnet *ifp = na->ifp;
+	struct ice_netdev_priv *np = netdev_priv(ifp);
+	struct ice_vsi  *vsi = np->vsi;
+	struct ice_pf   *pf = (struct ice_pf *)vsi->back;
+	bool was_running;
+
+	while (test_and_set_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf)))
+			usleep_range(1000, 2000);
+
+	if ( (was_running = netif_running(vsi->netdev)) )
+		ice_down(vsi);
+
+	//set_crcstrip(&adapter->hw, onoff);
+	/* enable or disable flags and callbacks in na and ifp */
+	if (onoff) {
+		nm_set_native_flags(na);
+	} else {
+		nm_clear_native_flags(na);
+	}
+	if (was_running) {
+		ice_up(vsi);
+	}
+	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
+
+	clear_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf));
+
+	return 0;
+}
+
+static int
+ice_netmap_bufcfg(struct netmap_kring *kring, uint64_t target)
+{
+	uint64_t incr;
+
+	kring->buf_align = 0;
+
+	if (kring->tx == NR_TX) {
+		kring->hwbuf_len = target;
+		return 0;
+	}
+
+	incr = 1UL << ICE_RLAN_CTX_DBUF_S;
+	target &= ~(incr - 1);
+	if (target < 1024UL || target > 16384UL - incr)
+		return EINVAL;
+
+	kring->hwbuf_len = target;
+
+	return 0;
+}
+
+static int
+ice_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
+
+	return 0;
+}
+
+/*
+ * The attach routine, called near the end of ice_attach(),
+ * fills the parameters for netmap_attach() and calls it.
+ * It cannot fail, in the worst case (such as no memory)
+ * netmap mode will be disabled and the driver will only
+ * operate in standard mode.
+ */
+static void
+ice_netmap_attach(struct ice_vsi *vsi)
+{
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp = vsi->netdev;
+	na.pdev = &vsi->back->pdev->dev;
+	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
+	na.num_tx_desc = NM_ICE_TX_RING(vsi, 0)->count;
+	na.num_rx_desc = NM_ICE_RX_RING(vsi, 0)->count;
+	na.num_tx_rings = vsi->num_txq;
+    na.num_rx_rings = vsi->num_rxq;
+	na.rx_buf_maxsize = vsi->rx_buf_len;
+	na.nm_txsync = ice_netmap_txsync;
+	na.nm_rxsync = ice_netmap_rxsync;
+	na.nm_register = ice_netmap_reg;
+	na.nm_config = ice_netmap_config;
+	na.nm_bufcfg = ice_netmap_bufcfg;
+	netmap_attach(&na);
+}
+
+#endif // NETMAP_ICE_LIB
+
+#ifdef NETMAP_ICE_BASE
+
+#define ice_driver_name netmap_ice_driver_name
+char ice_driver_name[] = "ice" NETMAP_LINUX_DRIVER_SUFFIX;
+/*
+ * device-specific sysctl variables:
+ *
+ * ix_crcstrip: 0: NIC keeps CRC in rx frames (default), 1: NIC strips it.
+ *	During regular operations the CRC is stripped, but on some
+ *	hardware reception of frames not multiple of 64 is slower,
+ *	so using crcstrip=0 helps in benchmarks.
+ *      The driver by default strips CRCs and we do not override it.
+ *
+ */
+SYSCTL_DECL(_dev_netmap);
+int ix_crcstrip = 1;
+SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
+		CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
+
+static void
+ice_netmap_configure_tx_ring(struct ice_ring *ring)
+{
+	struct netmap_adapter *na;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return;
+	}
+
+	na = NA(ring->netdev);
+	netmap_reset(na, NR_TX, ring->q_index, 0);
+}
+
+static void
+ice_netmap_preconfigure_rx_ring(struct ice_ring *ring,
+		struct ice_rlan_ctx *rx_ctx)
+{
+	struct netmap_adapter *na;
+	struct netmap_kring *kring;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return;
+	}
+
+	na = NA(ring->netdev);
+
+	if (netmap_reset(na, NR_RX, ring->q_index, 0) == NULL)
+		return;	// not in native netmap mode
+
+	kring = na->rx_rings[ring->q_index];
+	rx_ctx->dbuf = kring->hwbuf_len >> ICE_RLAN_CTX_DBUF_S;
+}
+
+static int
+ice_netmap_configure_rx_ring(struct ice_ring *ring)
+{
+	struct netmap_adapter *na;
+	struct netmap_slot *slot;
+	struct netmap_kring *kring;
+	int lim, i, ring_nr;
+
+	if (!ring->netdev) {
+		// XXX it this possible?
+		return 0;
+	}
+
+	na = NA(ring->netdev);
+	ring_nr = ring->q_index;
+
+	slot = netmap_reset(na, NR_RX, ring_nr, 0);
+	if (!slot)
+		return 0;	// not in native netmap mode
+
+	kring = na->rx_rings[ring_nr];
+	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
+
+	for (i = 0; i < lim; i++) {
+		int si = netmap_idx_n2k(kring, i);
+		uint64_t paddr;
+		union ice_32b_rx_flex_desc *rx = ICE_RX_DESC(ring, i);
+		PNMB_O(kring, slot + si, &paddr);
+
+		rx->read.pkt_addr = htole64(paddr);
+		rx->read.hdr_addr = 0;
+	}
+	ring->next_to_clean = 0;
+	wmb();
+	writel(lim, ring->tail);
+	return 1;
+}
+
+#endif /* NETMAP_ICE_BASE */
 
 /* end of file */

From 8c98a88f864943fc8f4222f0cb1570e27cf2b5b8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 21 Feb 2022 09:00:27 +0100
Subject: [PATCH 2000/2207] linux/i40e: patch for Intel 2.17.15 version

---
 LINUX/final-patches/intel--i40e--2.17.15 | 171 +++++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.17.15

diff --git a/LINUX/final-patches/intel--i40e--2.17.15 b/LINUX/final-patches/intel--i40e--2.17.15
new file mode 100644
index 000000000..40405c484
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.17.15
@@ -0,0 +1,171 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 2f77091..d1bcc36 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_adminq.o \
+ 	i40e_common.o \
+@@ -28,9 +28,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ obj-m += auxiliary.o
+@@ -40,7 +40,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -94,9 +94,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index c42883f..39fb831 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -152,6 +152,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -3992,6 +3997,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4045,6 +4054,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4073,6 +4086,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+ 
+ 	return 0;
+@@ -15231,6 +15249,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15603,6 +15627,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index a039064..387e485 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_prototype.h"
+ #include "i40e_txrx_common.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+ 				u32 td_tag)
+ {
+@@ -936,6 +940,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2771,7 +2780,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS) {
++		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif

From 470f0b83b5f73e57f86c3c13010a6165ab4f9f29 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 21 Feb 2022 09:29:05 +0100
Subject: [PATCH 2001/2207] linux/ice: fix bug in Intel Makefile

---
 LINUX/default-config.mak.in_ | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index e84c225e9..797734a8e 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -83,6 +83,7 @@ e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@SRCDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh i40e,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16),@SRCDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH

From c5af2842bf25edb795b391b7b6a5ec759f7a74a2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 21 Feb 2022 09:39:26 +0100
Subject: [PATCH 2002/2207] linux/i40e: more robust build tests for recent
 Intel releases

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 797734a8e..67d20079d 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -82,7 +82,7 @@ igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@SRCDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@SRCDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9),@SRCDIR@/intel-fix.sh i40e,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15),@SRCDIR@/intel-fix.sh i40e,)
 ice@prepare := $(if $(filter $(ice@v),1.7.16),@SRCDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration

From e86bb041dc3ed0e73e354b219ea5bc1ccb795411 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 6 Mar 2022 18:01:24 +0100
Subject: [PATCH 2003/2207] vale: make max number of bridges a load-time
 tunable

---
 LINUX/bsd_glue.h             |  1 +
 LINUX/netmap_linux.c         |  2 +-
 sys/dev/netmap/netmap_bdg.c  |  5 +++--
 sys/dev/netmap/netmap_kern.h |  4 +++-
 sys/dev/netmap/netmap_vale.c | 13 +++++++++----
 5 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 1ebb9691f..e4576a404 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -490,6 +490,7 @@ struct timeval {
  * windows: they are emulated via get/setsockopt
  */
 #define CTLFLAG_RD              1
+#define CTLFLAG_RDTUN           CTLFLAG_RD
 #define CTLFLAG_RW              2
 
 struct sysctl_oid;
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 98ae19b4d..d82ae9fa5 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1572,7 +1572,7 @@ netmap_pernet_init(struct net *net)
 		return error;
 
 	ns->net = net;
-	ns->num_bridges = NM_BRIDGES;
+	ns->num_bridges = vale_max_bridges;
 	ns->bridges = netmap_init_bridges2(ns->num_bridges);
 	if (ns->bridges == NULL) {
 		nm_bns_destroy(net, ns);
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 729aee7f6..e01ec293b 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1828,7 +1828,8 @@ netmap_init_bridges(void)
 #ifdef CONFIG_NET_NS
 	return netmap_bns_register();
 #else
-	nm_bridges = netmap_init_bridges2(NM_BRIDGES);
+        nm_prerr("INIT BRIDGES %u", vale_max_bridges);
+	nm_bridges = netmap_init_bridges2(vale_max_bridges);
 	if (nm_bridges == NULL)
 		return ENOMEM;
 	return 0;
@@ -1841,6 +1842,6 @@ netmap_uninit_bridges(void)
 #ifdef CONFIG_NET_NS
 	netmap_bns_unregister();
 #else
-	netmap_uninit_bridges2(nm_bridges, NM_BRIDGES);
+	netmap_uninit_bridges2(nm_bridges, vale_max_bridges);
 #endif
 }
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 5d8957241..f8d824f08 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1559,6 +1559,8 @@ int netmap_get_vale_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 void *netmap_vale_create(const char *bdg_name, int *return_status);
 int netmap_vale_destroy(const char *bdg_name, void *auth_token);
 
+extern unsigned int vale_max_bridges;
+
 #else /* !WITH_VALE */
 #define netmap_bdg_learning(_1, _2, _3, _4)	0
 #define	netmap_get_vale_na(_1, _2, _3, _4)	0
@@ -1606,7 +1608,7 @@ extern struct nm_bridge *nm_bridges;
 #define netmap_bns_get()
 #define netmap_bns_put(_1)
 #define netmap_bns_getbridges(b, n) \
-	do { *b = nm_bridges; *n = NM_BRIDGES; } while (0)
+	do { *b = nm_bridges; *n = vale_max_bridges; } while (0)
 #endif
 
 /* Various prototypes */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index aac4cfe67..7813984ad 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -84,10 +84,9 @@ __FBSDID("$FreeBSD$");
 
 /*
  * system parameters (most of them in netmap_kern.h)
- * NM_BDG_NAME	prefix for switch port names, default "vale"
+ * NM_BDG_NAME		prefix for switch port names, default "vale"
  * NM_BDG_MAXPORTS	number of ports
- * NM_BRIDGES	max number of switches in the system.
- *	XXX should become a sysctl or tunable
+ * NM_BRIDGES		max number of switches in the system.
  *
  * Switch ports are named valeX:Y where X is the switch name and Y
  * is the port. If Y matches a physical interface name, the port is
@@ -115,10 +114,16 @@ __FBSDID("$FreeBSD$");
  * last packet in the block may overflow the size.
  */
 static int bridge_batch = NM_BDG_BATCH; /* bridge batch size */
+
+/* Max number of vale bridges (loader tunable). */
+unsigned int vale_max_bridges = NM_BRIDGES;
+
 SYSBEGIN(vars_vale);
 SYSCTL_DECL(_dev_netmap);
 SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0,
 		"Max batch size to be used in the bridge");
+SYSCTL_UINT(_dev_netmap, OID_AUTO, max_bridges, CTLFLAG_RDTUN, &vale_max_bridges, 0,
+		"Max number of vale bridges");
 SYSEND;
 
 static int netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *,
@@ -366,7 +371,7 @@ netmap_vale_list(struct nmreq_header *hdr)
 		j = req->nr_port_idx;
 
 		NMG_LOCK();
-		for (error = ENOENT; i < NM_BRIDGES; i++) {
+		for (error = ENOENT; i < vale_max_bridges; i++) {
 			b = bridges + i;
 			for ( ; j < NM_BDG_MAXPORTS; j++) {
 				if (b->bdg_ports[j] == NULL)

From b52a2bcae35e56548acfb0849b248a1e4b0c0c3b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 6 Mar 2022 18:02:00 +0100
Subject: [PATCH 2004/2207] libnetmap: fix error path in
 nmport_extmem_from_file

---
 libnetmap/nmport.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index c9c34059e..80690a7f8 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -198,6 +198,7 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 		errno = ENOMEM;
 		goto fail;
 	}
+	clnup->up.cleanup = NULL;
 
 	fd = open(fname, O_RDWR);
 	if (fd < 0) {
@@ -215,6 +216,7 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 		goto fail;
 	}
 	close(fd);
+	fd = -1;
 
 	clnup->p = p;
 	clnup->size = mapsize;
@@ -230,7 +232,7 @@ nmport_extmem_from_file(struct nmport_d *d, const char *fname)
 	if (fd >= 0)
 		close(fd);
 	if (clnup != NULL) {
-		if (clnup->p != MAP_FAILED)
+		if (clnup->up.cleanup != NULL)
 			nmport_pop_cleanup(d);
 		else
 			nmctx_free(ctx, clnup);

From 4336b262b104570b4f467bc91833b33dc3f17791 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 6 Mar 2022 18:04:28 +0100
Subject: [PATCH 2005/2207] vale: remove leftover print

---
 sys/dev/netmap/netmap_bdg.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index e01ec293b..13275d8f6 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1828,7 +1828,6 @@ netmap_init_bridges(void)
 #ifdef CONFIG_NET_NS
 	return netmap_bns_register();
 #else
-        nm_prerr("INIT BRIDGES %u", vale_max_bridges);
 	nm_bridges = netmap_init_bridges2(vale_max_bridges);
 	if (nm_bridges == NULL)
 		return ENOMEM;

From 0fb5235604ba2682de016b5d48c85c7810276e3c Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 6 Mar 2022 18:17:18 +0100
Subject: [PATCH 2006/2207] import man changes from FreeBSD

---
 share/man/man4/netmap.4 | 43 +++++++++++++++++++++++++++--------------
 share/man/man4/vale.4   | 23 ++++++++--------------
 2 files changed, 37 insertions(+), 29 deletions(-)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 327705f7e..46a2f53b9 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 20, 2018
+.Dd October 3, 2020
 .Dt NETMAP 4
 .Os
 .Sh NAME
@@ -40,7 +40,7 @@
 is a framework for extremely fast and efficient packet I/O
 for userspace and kernel clients, and for Virtual Machines.
 It runs on
-.Fx
+.Fx ,
 Linux and some versions of Windows, and supports a variety of
 .Nm netmap ports ,
 including
@@ -655,7 +655,7 @@ In the example below, "netmap:foo" is any valid netmap port name.
 (default) all hardware ring pairs
 .It NR_REG_SW            "netmap:foo^"
 the ``host rings'', connecting to the host stack.
-.It NR_REG_NIC_SW        "netmap:foo+"
+.It NR_REG_NIC_SW        "netmap:foo*"
 all hardware rings and the host rings
 .It NR_REG_ONE_NIC       "netmap:foo-i"
 only the i-th hardware ring pair, where the number is in
@@ -694,7 +694,7 @@ or
 are called with a write event (POLLOUT/wfdset) or a full ring.
 .Pp
 When registering a virtual interface that is dynamically created to a
-.Xr vale 4
+.Nm VALE
 switch, we can specify the desired number of rings (1 by default,
 and currently up to 16) on it using nr_tx_rings and nr_rx_rings fields.
 .It Dv NIOCTXSYNC
@@ -828,7 +828,7 @@ On
 .Xr cxgbe 4 ,
 .Xr em 4 ,
 .Xr iflib 4
-(providing igb, em and lem),
+.Pq providing Xr igb 4 and Xr em 4 ,
 .Xr ixgbe 4 ,
 .Xr ixl 4 ,
 .Xr re 4 ,
@@ -861,8 +861,10 @@ The sysctl variable
 .Va dev.netmap.admode
 globally controls how netmap mode is implemented.
 .Sh SYSCTL VARIABLES AND MODULE PARAMETERS
-Some aspect of the operation of
+Some aspects of the operation of
 .Nm
+and
+.Nm VALE
 are controlled through sysctl variables on
 .Fx
 .Em ( dev.netmap.* )
@@ -883,15 +885,14 @@ Number of rings used for emulated netmap mode
 Ring size used for emulated netmap mode
 .It Va dev.netmap.generic_mit: 100000
 Controls interrupt moderation for emulated mode
-.It Va dev.netmap.mmap_unreg: 0
 .It Va dev.netmap.fwd: 0
 Forces NS_FORWARD mode
-.It Va dev.netmap.flags: 0
 .It Va dev.netmap.txsync_retry: 2
+Number of txsync loops in the
+.Nm VALE
+flush function
 .It Va dev.netmap.no_pendintr: 1
 Forces recovery of transmit buffers on system calls
-.It Va dev.netmap.mitigate: 1
-Propagates interrupt mitigation to user processes
 .It Va dev.netmap.no_timestamp: 0
 Disables the update of the timestamp in the netmap ring
 .It Va dev.netmap.verbose: 0
@@ -914,6 +915,18 @@ as it impacts the total amount of memory used by netmap.
 .It Va dev.netmap.if_curr_num: 0
 .It Va dev.netmap.if_curr_size: 0
 Actual values in use.
+.It Va dev.netmap.priv_buf_num: 4098
+.It Va dev.netmap.priv_buf_size: 2048
+.It Va dev.netmap.priv_ring_num: 4
+.It Va dev.netmap.priv_ring_size: 20480
+.It Va dev.netmap.priv_if_num: 2
+.It Va dev.netmap.priv_if_size: 1024
+Sizes and number of objects (netmap_if, netmap_ring, buffers)
+for private memory regions.
+A separate memory region is used for each
+.Nm VALE
+port and each pair of
+.Nm netmap pipes .
 .It Va dev.netmap.bridge_batch: 1024
 Batch size used when moving packets across a
 .Nm VALE
@@ -985,7 +998,7 @@ interfaces, as in
 or even connect the NIC to the host stack using netmap
 .Dl bridge -i netmap:ix0
 .Ss USING THE NATIVE API
-The following code implements a traffic generator
+The following code implements a traffic generator:
 .Pp
 .Bd -literal -compact
 #include 
@@ -1020,7 +1033,8 @@ void sender(void)
 }
 .Ed
 .Ss HELPER FUNCTIONS
-A simple receiver can be implemented using the helper functions
+A simple receiver can be implemented using the helper functions:
+.Pp
 .Bd -literal -compact
 #define NETMAP_WITH_LIBS
 #include 
@@ -1049,6 +1063,7 @@ it is possible to do packet forwarding between ports
 swapping buffers.
 The buffer from the transmit ring is used
 to replenish the receive ring:
+.Pp
 .Bd -literal -compact
     uint32_t tmp;
     struct netmap_slot *src, *dst;
@@ -1087,15 +1102,15 @@ changing port names, e.g.,
 .Pp
 The following command attaches an interface and the host stack
 to a switch:
-.Dl vale-ctl -h vale2:em0
+.Dl valectl -h vale2:em0
 Other
 .Nm
 clients attached to the same switch can now communicate
 with the network card or the host.
 .Sh SEE ALSO
 .Xr vale 4 ,
-.Xr vale-ctl 4 ,
 .Xr bridge 8 ,
+.Xr valectl 8 ,
 .Xr lb 8 ,
 .Xr nmreplay 8 ,
 .Xr pkt-gen 8
diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
index dcdd24ccc..d506ff114 100644
--- a/share/man/man4/vale.4
+++ b/share/man/man4/vale.4
@@ -28,7 +28,7 @@
 .\" $FreeBSD$
 .\" $Id: $
 .\"
-.Dd Jan 9, 2019
+.Dd February 6, 2020
 .Dt VALE 4
 .Os
 .Sh NAME
@@ -77,22 +77,15 @@ See
 for details on the API.
 .Ss LIMITS
 .Nm
-currently supports up to 4 switches, 16 ports per switch, with
-1024 buffers per port.
-These hard limits will be
-changed to sysctl variables in future releases.
+currently supports up to 254 ports per switch. The maximum
+number of switches defaults to 8 but can be changed by
+means of the max_bridges sysctl variable.
 .Sh SYSCTL VARIABLES
+See
+.Xr netmap 4
+for a list of sysctl variables that affect
 .Nm
-uses the following sysctl variables to control operation:
-.Bl -tag -width dev.netmap.verbose
-.It dev.netmap.bridge_batch
-The maximum number of packets processed internally
-in each iteration.
-Defaults to 1024, use lower values to trade latency
-with throughput.
-.It dev.netmap.verbose
-Set to non-zero values to enable in-kernel diagnostics.
-.El
+bridges.
 .Sh EXAMPLES
 Create one switch, with a traffic generator connected to one
 port, and a netmap-enabled tcpdump instance on another port:

From 8993516f3b292e91ca506a81210b12e58d66db32 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sun, 6 Mar 2022 18:21:18 +0100
Subject: [PATCH 2007/2207] netmap(4): document max_bridges sysctl

---
 share/man/man4/netmap.4 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 46a2f53b9..9ea100f02 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -933,6 +933,11 @@ Batch size used when moving packets across a
 switch.
 Values above 64 generally guarantee good
 performance.
+.It Va dev.netmap.max_bridges: 8
+Max number of
+.Nm VALE
+switches that can be created. This tunable can be specified
+at loader time.
 .It Va dev.netmap.ptnet_vnet_hdr: 1
 Allow ptnet devices to use virtio-net headers
 .El

From 22363df6af0215b3b2d86e64de11a16561b521dd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Mar 2022 17:21:34 +0100
Subject: [PATCH 2008/2207] extmem: simplify alignment of objects

---
 sys/dev/netmap/netmap_mem2.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8575a9409..de507466d 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2384,11 +2384,12 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 	os = NULL; /* pass ownership */
 
 	clust = nm_os_extmem_nextpage(nme->os);
-	off = 0;
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &nme->up.pools[i];
 		struct netmap_obj_params *o = &nme->up.params[i];
 
+		off = 0;
+
 		p->_objsize = o->size;
 		p->_clustsize = o->size;
 		p->_clustentries = 1;
@@ -2452,6 +2453,14 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		p->objtotal = j;
 		p->numclusters = p->objtotal;
 		p->memtotal = j * (size_t)p->_objsize;
+		if (p->memtotal & (PAGE_SIZE - 1)) {
+			// make sure that the objects of the next pool start page-aligned
+			p->memtotal = (p->memtotal & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
+			if (nr_pages > 0) {
+				clust = nm_os_extmem_nextpage(nme->os);
+				nr_pages--;
+			}
+		}
 		nm_prdis("%d memtotal %zu", j, p->memtotal);
 	}
 

From 86f0b2e34bae9c1ffdc59c46d7f697b2e2cfe3fa Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 8 Mar 2022 17:23:28 +0100
Subject: [PATCH 2009/2207] extmem: simplify alignment of objects

---
 sys/dev/netmap/netmap_mem2.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 8575a9409..de507466d 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2384,11 +2384,12 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 	os = NULL; /* pass ownership */
 
 	clust = nm_os_extmem_nextpage(nme->os);
-	off = 0;
 	for (i = 0; i < NETMAP_POOLS_NR; i++) {
 		struct netmap_obj_pool *p = &nme->up.pools[i];
 		struct netmap_obj_params *o = &nme->up.params[i];
 
+		off = 0;
+
 		p->_objsize = o->size;
 		p->_clustsize = o->size;
 		p->_clustentries = 1;
@@ -2452,6 +2453,14 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 		p->objtotal = j;
 		p->numclusters = p->objtotal;
 		p->memtotal = j * (size_t)p->_objsize;
+		if (p->memtotal & (PAGE_SIZE - 1)) {
+			// make sure that the objects of the next pool start page-aligned
+			p->memtotal = (p->memtotal & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
+			if (nr_pages > 0) {
+				clust = nm_os_extmem_nextpage(nme->os);
+				nr_pages--;
+			}
+		}
 		nm_prdis("%d memtotal %zu", j, p->memtotal);
 	}
 

From 9b4f18ba6b48ec40e3e80c356157718297cb1af6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 15 Mar 2022 08:05:24 +0100
Subject: [PATCH 2010/2207] Fix integer overflow in nmreq_copyin

An unsanitized field in an option could be abused, causing an integer
overflow followed by kernel memory corruption. This might be used
to escape jails/containers.

Reported by: Reno Robert and Lucas Leong (@_wmliang_) of Trend Micro Zero Day Initiative
Security: CVE-2022-23085
---
 sys/dev/netmap/netmap.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 2255df706..9d2147905 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3370,7 +3370,7 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 int
 nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
-	size_t rqsz, optsz, bufsz;
+	size_t rqsz, optsz, bufsz, optbodysz;
 	int error = 0;
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src, **opt_tab;
@@ -3418,8 +3418,18 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		error = copyin(src, &buf, sizeof(*src));
 		if (error)
 			goto out_err;
+		/* Validate nro_size to avoid integer overflow of optsz and bufsz. */
+		if (buf.nro_size > NETMAP_REQ_MAXSIZE) {
+			error = EMSGSIZE;
+			goto out_err;
+		}
 		optsz += sizeof(*src);
-		optsz += nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
+		optbodysz = nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
+		if (optbodysz > NETMAP_REQ_MAXSIZE) {
+			error = EMSGSIZE;
+			goto out_err;
+		}
+		optsz += optbodysz;
 		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
 			error = EMSGSIZE;
 			goto out_err;

From 97e8818491784a9ddc669d2f8ad1050e38704c93 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 15 Mar 2022 08:13:23 +0100
Subject: [PATCH 2011/2207] Fix TOCTOU vulnerability in nmreq_copyin

The total size of the user-provided nmreq was first computed and then
trusted during the copyin. This might lead to kernel memory corruption
and escape from jails/containers.

Reported by: Lucas Leong (@_wmliang_) of Trend Micro Zero Day Initiative
Security: CVE-2022-23084
---
 sys/dev/netmap/netmap.c | 51 ++++++++++++++---------------------------
 1 file changed, 17 insertions(+), 34 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 9d2147905..bc2566db3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3370,11 +3370,10 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 int
 nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 {
-	size_t rqsz, optsz, bufsz, optbodysz;
+	size_t rqsz, optsz, bufsz;
 	int error = 0;
 	char *ker = NULL, *p;
 	struct nmreq_option **next, *src, **opt_tab;
-	struct nmreq_option buf;
 	uint64_t *ptrs;
 
 	if (hdr->nr_reserved) {
@@ -3404,39 +3403,14 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		goto out_err;
 	}
 
-	bufsz = 2 * sizeof(void *) + rqsz +
-		NETMAP_REQ_OPT_MAX * sizeof(opt_tab);
-	/* compute the size of the buf below the option table.
-	 * It must contain a copy of every received option structure.
-	 * For every option we also need to store a copy of the user
-	 * list pointer.
+	/*
+	 * The buffer size must be large enough to store the request body,
+	 * all the possible options and the additional user pointers
+	 * (2+NETMAP_REQ_OPT_MAX). Note that the maximum size of body plus
+	 * options can not exceed NETMAP_REQ_MAXSIZE;
 	 */
-	optsz = 0;
-	for (src = (struct nmreq_option *)(uintptr_t)hdr->nr_options; src;
-	     src = (struct nmreq_option *)(uintptr_t)buf.nro_next)
-	{
-		error = copyin(src, &buf, sizeof(*src));
-		if (error)
-			goto out_err;
-		/* Validate nro_size to avoid integer overflow of optsz and bufsz. */
-		if (buf.nro_size > NETMAP_REQ_MAXSIZE) {
-			error = EMSGSIZE;
-			goto out_err;
-		}
-		optsz += sizeof(*src);
-		optbodysz = nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
-		if (optbodysz > NETMAP_REQ_MAXSIZE) {
-			error = EMSGSIZE;
-			goto out_err;
-		}
-		optsz += optbodysz;
-		if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
-			error = EMSGSIZE;
-			goto out_err;
-		}
-		bufsz += sizeof(void *);
-	}
-	bufsz += optsz;
+	bufsz = (2 + NETMAP_REQ_OPT_MAX) * sizeof(void *) + NETMAP_REQ_MAXSIZE +
+		NETMAP_REQ_OPT_MAX * sizeof(opt_tab);
 
 	ker = nm_os_malloc(bufsz);
 	if (ker == NULL) {
@@ -3474,6 +3448,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		error = copyin(src, opt, sizeof(*src));
 		if (error)
 			goto out_restore;
+		rqsz += sizeof(*src);
 		/* make a copy of the user next pointer */
 		*ptrs = opt->nro_next;
 		/* overwrite the user pointer with the in-kernel one */
@@ -3517,6 +3492,14 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		/* copy the option body */
 		optsz = nmreq_opt_size_by_type(opt->nro_reqtype,
 						opt->nro_size);
+		/* check optsz and nro_size to avoid for possible integer overflows of rqsz */
+		if ((optsz > NETMAP_REQ_MAXSIZE) || (opt->nro_size > NETMAP_REQ_MAXSIZE)
+				|| (rqsz + optsz > NETMAP_REQ_MAXSIZE)
+				|| (optsz > 0 && rqsz + optsz <= rqsz)) {
+			error = EMSGSIZE;
+			goto out_restore;
+		}
+		rqsz += optsz;
 		if (optsz) {
 			/* the option body follows the option header */
 			error = copyin(src + 1, p, optsz);

From 74e2c98afac19f422ecc9559749dbc82581d8b50 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 21 Mar 2022 14:03:26 +0100
Subject: [PATCH 2012/2207] fix compilation with --disable-vale

---
 sys/dev/netmap/netmap_kern.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index f8d824f08..4825accde 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1566,6 +1566,7 @@ extern unsigned int vale_max_bridges;
 #define	netmap_get_vale_na(_1, _2, _3, _4)	0
 #define netmap_bdg_create(_1, _2)	NULL
 #define netmap_bdg_destroy(_1, _2)	0
+#define vale_max_bridges		1
 #endif /* !WITH_VALE */
 
 #ifdef WITH_PIPES

From ead6717619b94a2ad13fbcf290a08f56420a250a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 21 Mar 2022 15:47:20 +0100
Subject: [PATCH 2013/2207] linux: test for new set_ringparam

---
 LINUX/bsd_glue.h     |  8 ++++++--
 LINUX/configure      | 13 +++++++++++++
 LINUX/netmap_linux.c | 13 +++++++++++--
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index e4576a404..98acaf99e 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -304,7 +304,12 @@ struct thread;
 /*
  * We hide behind the ethtool_ops
  */
-int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *);
+int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *
+#ifdef NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS
+		, struct kernel_ethtool_ringparam *
+		, struct netlink_ext_ack
+#endif /* NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS */
+		);
 struct netmap_linux_magic {
 	struct ethtool_ops eto;
 	const struct ethtool_ops *save_eto;
@@ -352,7 +357,6 @@ netdev_tx_t linux_netmap_start_xmit(struct sk_buff *, struct net_device *);
 int linux_netmap_change_mtu(struct net_device *dev, int new_mtu);
 
 /* prevent ring params change while in netmap mode */
-int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *);
 #ifdef NETMAP_LINUX_HAVE_SET_CHANNELS
 int linux_netmap_set_channels(struct net_device *, struct ethtool_channels *);
 #endif
diff --git a/LINUX/configure b/LINUX/configure
index 48acb9a1d..73b9fe9fe 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1830,6 +1830,19 @@ EOF
 	}
 EOF
 
+  # setringparam additional parameters
+  add_test 'have SETRNGPRM_4ARGS' <
+	#include 
+
+	int
+	dummy(struct net_device *net, struct ethtool_ringparam *r,
+		struct kernel_ethtool_ringparam *k,
+		struct netlink_ext_ack *a) {
+		return net->ethtool_ops->set_ringparam(net, r, k, a);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d82ae9fa5..9cb790c96 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1355,7 +1355,12 @@ linux_netmap_change_mtu(struct net_device *dev, int new_mtu)
  */
 int
 linux_netmap_set_ringparam(struct net_device *dev,
-	struct ethtool_ringparam *e)
+	struct ethtool_ringparam *e
+#ifdef NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS
+	, struct kernel_ethtool_ringparam *k
+	, struct netlink_ext_ack *a
+#endif /* NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS */
+	)
 {
 #ifdef NETMAP_LINUX_HAVE_AX25PTR
 	return -EBUSY;
@@ -1365,7 +1370,11 @@ linux_netmap_set_ringparam(struct net_device *dev,
 	if (nm_netmap_on(na))
 		return -EBUSY;
 	if (na->magic.save_eto->set_ringparam)
-		return na->magic.save_eto->set_ringparam(dev, e);
+		return na->magic.save_eto->set_ringparam(dev, e
+#ifdef NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS
+				, k, a
+#endif /* NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS */
+				)
 	return -EOPNOTSUPP;
 #endif /* NETMAP_LINUX_HAVE_AX25PTR */
 }

From 52b55eec87b69267e2846a6ec1ad2565b30ae674 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 21 Mar 2022 18:34:39 +0100
Subject: [PATCH 2014/2207] linux: patches for v5.17

---
 ...c00--30d00 => vanilla--i40e--30c00--40100} |   0
 .../final-patches/vanilla--i40e--30e00--40100 | 117 -----------------
 ...0800--30d00 => vanilla--igb--30800--30f00} |   0
 .../final-patches/vanilla--igb--30e00--30f00  |  89 -------------
 ...00--30f00 => vanilla--ixgbe--30d00--30f00} |  22 ++--
 .../vanilla--ixgbevf--30d00--30e00            | 118 ++++++++++++++++++
 6 files changed, 129 insertions(+), 217 deletions(-)
 rename LINUX/final-patches/{vanilla--i40e--30c00--30d00 => vanilla--i40e--30c00--40100} (100%)
 delete mode 100644 LINUX/final-patches/vanilla--i40e--30e00--40100
 rename LINUX/final-patches/{vanilla--igb--30800--30d00 => vanilla--igb--30800--30f00} (100%)
 delete mode 100644 LINUX/final-patches/vanilla--igb--30e00--30f00
 rename LINUX/final-patches/{vanilla--ixgbe--30e00--30f00 => vanilla--ixgbe--30d00--30f00} (83%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbevf--30d00--30e00

diff --git a/LINUX/final-patches/vanilla--i40e--30c00--30d00 b/LINUX/final-patches/vanilla--i40e--30c00--40100
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--30c00--30d00
rename to LINUX/final-patches/vanilla--i40e--30c00--40100
diff --git a/LINUX/final-patches/vanilla--i40e--30e00--40100 b/LINUX/final-patches/vanilla--i40e--30e00--40100
deleted file mode 100644
index 1f5c7f20b..000000000
--- a/LINUX/final-patches/vanilla--i40e--30e00--40100
+++ /dev/null
@@ -1,117 +0,0 @@
-diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index b901371ca361..cef02532b6e1 100644
---- a/i40e/i40e_main.c
-+++ b/i40e/i40e_main.c
-@@ -90,6 +90,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
- MODULE_LICENSE("GPL");
- MODULE_VERSION(DRV_VERSION);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#define NETMAP_I40E_MAIN
-+#include 
-+#endif
-+
- /**
-  * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
-  * @hw:   pointer to the HW structure
-@@ -2224,6 +2229,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
- 	/* cache tail off for easier writes later */
- 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
- 
-+#ifdef DEV_NETMAP
-+	i40e_netmap_configure_tx_ring(ring);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- }
- 
-@@ -2288,6 +2297,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
- 	rx_ctx.l2tsel = 1;
- 	rx_ctx.showiv = 1;
- 
-+#ifdef DEV_NETMAP
-+	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
-+#endif /* DEV_NETMAP */
-+
- 	/* clear the context in the HMC */
- 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
- 	if (err) {
-@@ -2310,6 +2323,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
- 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
- 	writel(0, ring->tail);
- 
-+#ifdef DEV_NETMAP
-+	if (i40e_netmap_configure_rx_ring(ring))
-+		return 0;
-+#endif /* DEV_NETMAP */
-+
- 	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
- 
- 	return 0;
-@@ -6764,6 +6782,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
- 		return -ENODEV;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	if (vsi->netdev_registered)
-+		netmap_detach(vsi->netdev);
-+#endif
-+
- 	uplink_seid = vsi->uplink_seid;
- 	if (vsi->type != I40E_VSI_SRIOV) {
- 		if (vsi->netdev_registered) {
-@@ -7083,6 +7106,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
- 		break;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	if (vsi->netdev_registered)
-+		i40e_netmap_attach(vsi);
-+#endif
-+
- 	return vsi;
- 
- err_rings:
-diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index d4bb482b1a7f..54b9fdfb33a6 100644
---- a/i40e/i40e_txrx.c
-+++ b/i40e/i40e_txrx.c
-@@ -26,6 +26,10 @@
- 
- #include "i40e.h"
- 
-+#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
-+#include 
-+#endif /* DEV_NETMAP */
-+
- static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
- 				u32 td_tag)
- {
-@@ -329,6 +333,11 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
- 	unsigned int total_packets = 0;
- 	unsigned int total_bytes = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	tx_buf = &tx_ring->tx_bi[i];
- 	tx_desc = I40E_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -975,6 +984,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	u64 qword;
- 	u16 rx_ptype;
- 
-+#ifdef DEV_NETMAP
-+	if (rx_ring->netdev) {
-+		int dummy, nm_irq;
-+		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+		if (nm_irq != NM_IRQ_PASS)
-+			return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+	}
-+#endif /* DEV_NETMAP */
-+
- 	rx_desc = I40E_RX_DESC(rx_ring, i);
- 	qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- 	rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
diff --git a/LINUX/final-patches/vanilla--igb--30800--30d00 b/LINUX/final-patches/vanilla--igb--30800--30f00
similarity index 100%
rename from LINUX/final-patches/vanilla--igb--30800--30d00
rename to LINUX/final-patches/vanilla--igb--30800--30f00
diff --git a/LINUX/final-patches/vanilla--igb--30e00--30f00 b/LINUX/final-patches/vanilla--igb--30e00--30f00
deleted file mode 100644
index d96370a10..000000000
--- a/LINUX/final-patches/vanilla--igb--30e00--30f00
+++ /dev/null
@@ -1,89 +0,0 @@
-diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 46d31a49f5ea..199445e39cdc 100644
---- a/igb/igb_main.c
-+++ b/igb/igb_main.c
-@@ -258,6 +258,10 @@ static int debug = -1;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct igb_reg_info {
- 	u32 ofs;
- 	char *name;
-@@ -1765,7 +1769,6 @@ void igb_down(struct igb_adapter *adapter)
- 		napi_disable(&(adapter->q_vector[i]->napi));
- 	}
- 
--
- 	del_timer_sync(&adapter->watchdog_timer);
- 	del_timer_sync(&adapter->phy_info_timer);
- 
-@@ -2492,6 +2495,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-+#ifdef DEV_NETMAP
-+	igb_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- #ifdef CONFIG_IGB_DCA
- 	if (dca_add_requester(&pdev->dev) == 0) {
- 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -2744,6 +2751,10 @@ static void igb_remove(struct pci_dev *pdev)
- 		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
- 	}
- #endif
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 
- 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
- 	 * would have already happened in close and is redundant.
-@@ -3215,6 +3226,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
- 
- 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
- 	wr32(E1000_TXDCTL(reg_idx), txdctl);
-+#ifdef DEV_NETMAP
-+	igb_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
- 
- /**
-@@ -6244,6 +6258,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
- 
- 	if (test_bit(__IGB_DOWN, &adapter->state))
- 		return true;
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
-+                return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IGB_TX_DESC(tx_ring, i);
-@@ -6903,6 +6921,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
- 	unsigned int total_bytes = 0, total_packets = 0;
- 	u16 cleaned_count = igb_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
-+		return true;
-+#endif /* DEV_NETMAP */
- 	do {
- 		union e1000_adv_rx_desc *rx_desc;
- 
-@@ -7020,6 +7042,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
- 	struct igb_rx_buffer *bi;
- 	u16 i = rx_ring->next_to_use;
- 
-+#ifdef DEV_NETMAP
-+	if (igb_netmap_configure_rx_ring(rx_ring))
-+		return;
-+#endif /* DEV_NETMAP */
-+
- 	/* nothing to do */
- 	if (!cleaned_count)
- 		return;
diff --git a/LINUX/final-patches/vanilla--ixgbe--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
similarity index 83%
rename from LINUX/final-patches/vanilla--ixgbe--30e00--30f00
rename to LINUX/final-patches/vanilla--ixgbe--30d00--30f00
index 0162133fb..febd3bc92 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30e00--30f00
+++ b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
@@ -1,8 +1,8 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 18076c4178b4..12646872c0f6 100644
+index 5bcc870f8367..eef466715f03 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
-@@ -359,6 +359,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+@@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
  	{}
  };
  
@@ -25,7 +25,7 @@ index 18076c4178b4..12646872c0f6 100644
  
  /*
   * ixgbe_regdump - register printout routine
-@@ -990,6 +1006,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+@@ -959,6 +975,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
  	if (test_bit(__IXGBE_DOWN, &adapter->state))
  		return true;
  
@@ -43,7 +43,7 @@ index 18076c4178b4..12646872c0f6 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2026,6 +2053,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+@@ -1995,6 +2022,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
  #endif /* IXGBE_FCOE */
  	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
  
@@ -60,7 +60,7 @@ index 18076c4178b4..12646872c0f6 100644
  	do {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3049,6 +3086,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+@@ -3018,6 +3055,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  
  	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
  
@@ -71,7 +71,7 @@ index 18076c4178b4..12646872c0f6 100644
  	/* enable queue */
  	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
-@@ -3429,6 +3470,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3394,6 +3435,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -82,7 +82,7 @@ index 18076c4178b4..12646872c0f6 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4636,16 +4681,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4600,16 +4645,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  	/* enable transmits */
  	netif_tx_start_all_queues(adapter->netdev);
  
@@ -99,7 +99,7 @@ index 18076c4178b4..12646872c0f6 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5451,6 +5486,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5412,6 +5447,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -107,7 +107,7 @@ index 18076c4178b4..12646872c0f6 100644
  	return 0;
  
  err_set_queues:
-@@ -8228,6 +8264,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8174,6 +8210,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -118,7 +118,7 @@ index 18076c4178b4..12646872c0f6 100644
  	return 0;
  
  err_register:
-@@ -8262,6 +8302,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -8208,6 +8248,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
  	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
  	struct net_device *netdev = adapter->netdev;
  
@@ -128,4 +128,4 @@ index 18076c4178b4..12646872c0f6 100644
 +
  	ixgbe_dbg_adapter_exit(adapter);
  
- 	set_bit(__IXGBE_REMOVING, &adapter->state);
+ 	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
new file mode 100644
index 000000000..0dc67d0a7
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
@@ -0,0 +1,118 @@
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 92ef4cb5a8e8..3c5d85cec0a7 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
+ 
+ static void ixgbevf_tx_timeout(struct net_device *netdev);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
++
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: board private structure
+@@ -193,6 +211,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	i = tx_ring->next_to_clean;
+ 	tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ 	eop_desc = tx_buffer_info->next_to_watch;
+@@ -434,6 +463,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	int cleaned_count = 0;
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	i = rx_ring->next_to_clean;
+ 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
+ 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+@@ -1087,6 +1126,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter)
+ }
+ 
+ /**
++}
++
+  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+  * @adapter: board private structure
+  *
+@@ -1117,6 +1158,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+ 		 */
+ 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
+ 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
++#ifdef DEV_NETMAP
++		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
++#endif /* DEV_NETMAP */
+ 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
+ 	}
+ }
+@@ -1379,6 +1423,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
+ 	ixgbevf_configure_rx(adapter);
+ 	for (i = 0; i < adapter->num_rx_queues; i++) {
+ 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
++#ifdef DEV_NETMAP
++		if (ixgbe_netmap_configure_rx_ring(adapter, i))
++			continue;
++#endif /* DEV_NETMAP */
+ 		ixgbevf_alloc_rx_buffers(adapter, ring,
+ 					 ixgbevf_desc_unused(ring));
+ 	}
+@@ -3545,6 +3593,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
+ 
+ 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	cards_found++;
+ 	return 0;
+ 
+@@ -3577,6 +3630,11 @@ static void ixgbevf_remove(struct pci_dev *pdev)
+ 	struct net_device *netdev = pci_get_drvdata(pdev);
+ 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ 
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_DOWN, &adapter->state);
+ 
+ 	del_timer_sync(&adapter->watchdog_timer);

From 4e2f2d6cf007eb952f176c91cfc9e0213adb45d6 Mon Sep 17 00:00:00 2001
From: Michio 
Date: Sat, 2 Apr 2022 16:31:30 +0100
Subject: [PATCH 2015/2207] linux: fix compile errors

---
 LINUX/bsd_glue.h     | 2 +-
 LINUX/netmap_linux.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 98acaf99e..70388c483 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -307,7 +307,7 @@ struct thread;
 int linux_netmap_set_ringparam(struct net_device *, struct ethtool_ringparam *
 #ifdef NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS
 		, struct kernel_ethtool_ringparam *
-		, struct netlink_ext_ack
+		, struct netlink_ext_ack *
 #endif /* NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS */
 		);
 struct netmap_linux_magic {
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 9cb790c96..0f84608a5 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1374,7 +1374,7 @@ linux_netmap_set_ringparam(struct net_device *dev,
 #ifdef NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS
 				, k, a
 #endif /* NETMAP_LINUX_HAVE_SETRNGPRM_4ARGS */
-				)
+				);
 	return -EOPNOTSUPP;
 #endif /* NETMAP_LINUX_HAVE_AX25PTR */
 }

From d660bd5121b0dc446a505cfac183e32e08bc4754 Mon Sep 17 00:00:00 2001
From: Konstantin Kogdenko 
Date: Mon, 18 Apr 2022 10:42:59 +0300
Subject: [PATCH 2016/2207] linux/veth: fix kernel oops

Check peer_ref before incrementing/decrementig na_refcount.
Oops can be reproduced with pkt-gen:
pkt-gen -f rx -i vetha &
pkt-gen -f rx -i vethb^ &
pkt-gen -f rx -i vethb-0 &
killall pkt-gen
pkt-gen -f rx -i vetha
There is two calls of nm_register for interface vethb.
First one on creating host-ring vethb^ and the second on vethb-0.
If we do not check peer_ref then we would dereferencing peer twice.
---
 LINUX/veth_netmap.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index dfdce54e8..19488e4d6 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -156,11 +156,15 @@ veth_netmap_reg(struct netmap_adapter *na, int onoff)
 		return 0;
 	}
 	if (onoff) {
-		vna->peer->peer_ref = 0;
-		netmap_adapter_put(na);
+		if (vna->peer->peer_ref) {
+			vna->peer->peer_ref = 0;
+			netmap_adapter_put(na);
+		}
 	} else {
-		netmap_adapter_get(na);
-		vna->peer->peer_ref = 1;
+		if (!vna->peer->peer_ref) {
+			netmap_adapter_get(na);
+			vna->peer->peer_ref = 1;
+		}
 	}
 
 	return 0;

From 8be9afd6a94f7e9ba742e768bcb126409a091572 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 25 Apr 2022 15:28:36 +0200
Subject: [PATCH 2017/2207] linux/igb: fix write to SRRCTL

Found by Udo Hessenauer.
---
 LINUX/if_igb_netmap.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index e63982a7e..cfe6356c4 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -82,7 +82,7 @@ static inline void NM_WRITE_SRRCTL(struct igb_adapter *adapter, struct igb_ring
 	u32 srrctl)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	wr32(E1000_TDH(rxr->reg_idx), srrctl);
+	wr32(E1000_SRRCTL(rxr->reg_idx), srrctl);
 }
 #else
 #define NM_WRITE_RCTL(_adapter, _rxr, _rxdctl)	\

From e86c07cbcb8741d2e6cb029dfbc6618052638987 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Apr 2022 14:50:29 +0200
Subject: [PATCH 2018/2207] linux/i40e: fix include directive

Some i40e sources include a local header file using angle brackets.
This was breaking some i40e-specific feature tests, since the tests
don't have the driver's source directory in their include path.
This patch turns the angle brackets into double quotes before running the
tests.
---
 LINUX/intel-fix.sh | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/intel-fix.sh b/LINUX/intel-fix.sh
index 276eb4d74..a4ca62ee1 100755
--- a/LINUX/intel-fix.sh
+++ b/LINUX/intel-fix.sh
@@ -14,3 +14,5 @@ diff --git a/common.mk b/common.mk
      echo "warning: but the signing key cannot be found. The module must" ; \\
      echo "warning: be signed manually using 'scripts/sign-file'." ;
 EOF
+
+sed -i -e 's|^#include |#include "linux/auxiliary_bus.h"|' *_client.h || true

From c9541f64d55b1a61167b2ee24f31fffb747b23b0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Apr 2022 12:02:48 +0200
Subject: [PATCH 2019/2207] linux/i40e: add missing check in the patch for
 2.17.15

---
 LINUX/final-patches/intel--i40e--2.17.15 | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/LINUX/final-patches/intel--i40e--2.17.15 b/LINUX/final-patches/intel--i40e--2.17.15
index 40405c484..a8b2658a4 100644
--- a/LINUX/final-patches/intel--i40e--2.17.15
+++ b/LINUX/final-patches/intel--i40e--2.17.15
@@ -127,7 +127,7 @@ index c42883f..39fb831 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index a039064..387e485 100644
+index a039064..2c34cf8 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -10,6 +10,10 @@
@@ -146,22 +146,24 @@ index a039064..387e485 100644
  	unsigned int budget = vsi->work_limit;
  
 +#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
 +		return true;
 +#endif /* DEV_NETMAP */
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2771,7 +2780,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -2771,7 +2780,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	struct xdp_buff xdp;
  	u16 tpid;
  
 +#ifdef DEV_NETMAP
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
 +	}
 +#endif /* DEV_NETMAP */
  #ifdef HAVE_XDP_BUFF_FRAME_SZ

From 7d9177ed9a121e66bf4eaa0acb5d574e408297da Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Apr 2022 20:02:39 +0200
Subject: [PATCH 2020/2207] libnetmap: fix extra indirection in
 nmreq_remove_option

---
 libnetmap/nmreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index 8df02aefa..0aa9839af 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -620,7 +620,7 @@ nmreq_remove_option(struct nmreq_header *h, struct nmreq_option *o)
 	for (nmo = (struct nmreq_option **)&h->nr_options; *nmo != NULL;
 	    nmo = (struct nmreq_option **)&(*nmo)->nro_next) {
 		if (*nmo == o) {
-			*((uint64_t *)(*nmo)) = o->nro_next;
+			*((uint64_t *)nmo) = o->nro_next;
 			o->nro_next = (uint64_t)(uintptr_t)NULL;
 			break;
 		}

From 523fa09adf8faa8744bd5a7cca56563ffa42fd0c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 4 May 2022 18:26:55 +0200
Subject: [PATCH 2021/2207] linux/scripts: allow for gcc 11

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index ad04c7086..746e8bd6a 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -378,7 +378,7 @@ function build-prep()
 	(
 		cd $dst
 		last=compiler-gcc.h
-		for i in $(seq 11); do
+		for i in $(seq 12); do
 			[ -e include/linux/compiler-gcc$i.h ] ||
 				ln -s $last include/linux/compiler-gcc$i.h
 			last=compiler-gcc$i.h

From 7d36823fa7fd3cc55b93ea0d4e767242a48ef296 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 7 May 2022 10:00:39 +0200
Subject: [PATCH 2022/2207] linux/i40e: apply e86c07cb only when needed

---
 LINUX/configure                       |  2 ++
 LINUX/default-config.mak.in_          | 12 ++++++------
 LINUX/{intel-fix.sh => intel-fix.sh_} |  5 ++++-
 LINUX/netmap.mak.in                   |  2 +-
 4 files changed, 13 insertions(+), 8 deletions(-)
 rename LINUX/{intel-fix.sh => intel-fix.sh_} (76%)

diff --git a/LINUX/configure b/LINUX/configure
index 73b9fe9fe..17423a3ac 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -817,6 +817,8 @@ for dv in $(echo "$versions" | sed 's/,/ /g'); do
 done
 
 replace_vars $SRCDIR/default-config.mak.in_ > default-config.mak
+replace_vars $SRCDIR/intel-fix.sh_ > intel-fix.sh
+chmod +x intel-fix.sh
 
 ###############################################################
 # Makefile creation
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 67d20079d..ba4556d9d 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -78,12 +78,12 @@ endef
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
-igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@SRCDIR@/intel-fix.sh igb,)
-e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@SRCDIR@/intel-fix.sh e1000e,)
-ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@SRCDIR@/intel-fix.sh ixgbevf,)
-ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@SRCDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15),@SRCDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16),@SRCDIR@/intel-fix.sh ice,)
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@BUILDDIR@/intel-fix.sh igb,)
+e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@BUILDDIR@/intel-fix.sh e1000e,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
+ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@BUILDDIR@/intel-fix.sh ixgbe,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15),@BUILDDIR@/intel-fix.sh i40e,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/intel-fix.sh b/LINUX/intel-fix.sh_
similarity index 76%
rename from LINUX/intel-fix.sh
rename to LINUX/intel-fix.sh_
index a4ca62ee1..7c7d6aec8 100755
--- a/LINUX/intel-fix.sh
+++ b/LINUX/intel-fix.sh_
@@ -15,4 +15,7 @@ diff --git a/common.mk b/common.mk
      echo "warning: be signed manually using 'scripts/sign-file'." ;
 EOF
 
-sed -i -e 's|^#include |#include "linux/auxiliary_bus.h"|' *_client.h || true
+if ! [ -e "@KSRC@/include/linux/auxiliary_bus.h" ]
+then
+	sed -i -e 's|^#include |#include "linux/auxiliary_bus.h"|' *_client.h || true
+fi
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index be2e5d9a0..b8e92d39f 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -181,7 +181,7 @@ install-docs:
 distclean: clean $(S_DRIVERS:%=distclean-%)
 	rm -f config.status config.log netmap_linux_config.h \
 		patches drivers.mak Kbuild netmap.mak default-config.mak \
-		extdrv-versions.mak
+		extdrv-versions.mak intel-fix.sh
 	rm -rf netmap-tmpdir
 	rm -f *.orig *.rej
 	if [ -L GNUmakefile ]; then rm GNUmakefile; fi

From 33a807c68da6e75ab48a84accd763c3a378522dd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 6 May 2022 20:36:21 +0200
Subject: [PATCH 2023/2207] linux: patches for latest Intel drivers

---
 LINUX/final-patches/intel--i40e--2.18.9    | 173 +++++++++++++++++
 LINUX/final-patches/intel--ice--1.8.3      | 215 +++++++++++++++++++++
 LINUX/final-patches/intel--ice--1.8.8      | 215 +++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.9.3      | 138 +++++++++++++
 LINUX/final-patches/intel--ixgbe--5.14.6   | 173 +++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.14.5 | 169 ++++++++++++++++
 6 files changed, 1083 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.18.9
 create mode 100644 LINUX/final-patches/intel--ice--1.8.3
 create mode 100644 LINUX/final-patches/intel--ice--1.8.8
 create mode 100644 LINUX/final-patches/intel--igb--5.9.3
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.14.6
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.14.5

diff --git a/LINUX/final-patches/intel--i40e--2.18.9 b/LINUX/final-patches/intel--i40e--2.18.9
new file mode 100644
index 000000000..1b88f16c2
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.18.9
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 62220eb..6e5b009 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ obj-m += auxiliary.o
+@@ -41,7 +41,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -95,9 +95,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index f19b701..d723387 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -161,6 +161,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4142,6 +4147,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4271,6 +4280,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4299,6 +4312,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15595,6 +15613,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -15988,6 +16012,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index cbfc1a1..2d0646e 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -977,6 +981,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2908,7 +2917,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.8.3 b/LINUX/final-patches/intel--ice--1.8.3
new file mode 100644
index 000000000..7a4218177
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.8.3
@@ -0,0 +1,215 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 789a908..cdb3394 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -57,32 +57,33 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
+-ice-$(CONFIG_PCI_IOV) += ice_dcf.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
+-ice-$(CONFIG_PCI_IOV) +=	\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_dcf.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=	\
+ 	ice_sriov.o		\
+ 	ice_vf_mbx.o		\
+ 	ice_vf_vsi_vlan_ops.o	\
+ 	ice_vf_adq.o		\
+ 	ice_virtchnl.o		\
+ 	ice_vf_lib.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ ifeq (${NEED_AUX_BUS},2)
+@@ -92,7 +93,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -119,7 +120,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index adaaa84..cb29c06 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -459,6 +464,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -615,6 +624,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++    if (ice_netmap_configure_rx_ring(ring))
++        return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -885,6 +899,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++    ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_lib.c b/ice/ice_lib.c
+index 034a064..d8d3ef9 100644
+--- a/ice/ice_lib.c
++++ b/ice/ice_lib.c
+@@ -10,6 +10,12 @@
+ #include "ice_vsi_vlan_ops.h"
+ #include "ice_irq.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
++
+ /**
+  * ice_vsi_type_str - maps VSI type enum to string equivalents
+  * @vsi_type: VSI type enum
+@@ -2807,6 +2813,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ 	if (!vsi->agg_node)
+ 		ice_set_agg_vsi(vsi);
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ unroll_clear_rings:
+@@ -3155,6 +3165,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
+ 	 */
+ 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
+ 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
++#ifdef DEV_NETMAP
++        netmap_detach(vsi->netdev);
++#endif
+ 		unregister_netdev(vsi->netdev);
+ 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 68e659d..0bdc49b 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
+ 	if (!rx_ring->rx_buf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (rx_ring->xsk_pool) {
+ 		ice_xsk_clean_rx_ring(rx_ring);
diff --git a/LINUX/final-patches/intel--ice--1.8.8 b/LINUX/final-patches/intel--ice--1.8.8
new file mode 100644
index 000000000..7a4218177
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.8.8
@@ -0,0 +1,215 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 789a908..cdb3394 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -57,32 +57,33 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
+-ice-$(CONFIG_PCI_IOV) += ice_dcf.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
+-ice-$(CONFIG_PCI_IOV) +=	\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_dcf.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=	\
+ 	ice_sriov.o		\
+ 	ice_vf_mbx.o		\
+ 	ice_vf_vsi_vlan_ops.o	\
+ 	ice_vf_adq.o		\
+ 	ice_virtchnl.o		\
+ 	ice_vf_lib.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ ifeq (${NEED_AUX_BUS},2)
+@@ -92,7 +93,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -119,7 +120,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index adaaa84..cb29c06 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -459,6 +464,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -615,6 +624,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++    if (ice_netmap_configure_rx_ring(ring))
++        return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -885,6 +899,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++    ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_lib.c b/ice/ice_lib.c
+index 034a064..d8d3ef9 100644
+--- a/ice/ice_lib.c
++++ b/ice/ice_lib.c
+@@ -10,6 +10,12 @@
+ #include "ice_vsi_vlan_ops.h"
+ #include "ice_irq.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
++
+ /**
+  * ice_vsi_type_str - maps VSI type enum to string equivalents
+  * @vsi_type: VSI type enum
+@@ -2807,6 +2813,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ 	if (!vsi->agg_node)
+ 		ice_set_agg_vsi(vsi);
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ unroll_clear_rings:
+@@ -3155,6 +3165,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
+ 	 */
+ 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
+ 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
++#ifdef DEV_NETMAP
++        netmap_detach(vsi->netdev);
++#endif
+ 		unregister_netdev(vsi->netdev);
+ 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 68e659d..0bdc49b 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
+ 	if (!rx_ring->rx_buf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (rx_ring->xsk_pool) {
+ 		ice_xsk_clean_rx_ring(rx_ring);
diff --git a/LINUX/final-patches/intel--igb--5.9.3 b/LINUX/final-patches/intel--igb--5.9.3
new file mode 100644
index 000000000..90ee9259d
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.9.3
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 682db41..303f09b 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index d551598..9512f22 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7430,6 +7445,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8446,6 +8466,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8765,6 +8790,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.14.6 b/LINUX/final-patches/intel--ixgbe--5.14.6
new file mode 100644
index 000000000..da08a2996
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.14.6
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index adccdaa..137c98f 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 29e2075..7012791 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2228,6 +2256,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4433,6 +4475,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13205,6 +13253,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13261,6 +13313,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.14.5 b/LINUX/final-patches/intel--ixgbevf--4.14.5
new file mode 100644
index 000000000..d2b891c56
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.14.5
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 6391546..780d1c0 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index bdc8871..b57fcb9 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1383,6 +1411,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2101,6 +2139,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2335,6 +2377,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5639,8 +5685,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5681,6 +5729,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 3726b1d..dd43957 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 574abf819c44a05683ea6337ec3bb2bc2b5700e0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 7 May 2022 11:11:30 +0200
Subject: [PATCH 2024/2207] linux/scripts: ignore implicit-fallthrough warnings

---
 LINUX/configure              | 3 ++-
 LINUX/default-config.mak.in_ | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 17423a3ac..6ddde205d 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1003,7 +1003,8 @@ EOF
 
 DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned \
 	stringop-truncation missing-attributes format-truncation \
-	maybe-uninitialized unused-variable unused-label"
+	maybe-uninitialized unused-variable unused-label \
+	implicit-fallthrough"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index ba4556d9d..e40f30a18 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -78,6 +78,7 @@ endef
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := @REC_DISABLED_WARNINGS@
+i40e@cflags := @REC_DISABLED_WARNINGS@
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@BUILDDIR@/intel-fix.sh igb,)
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@BUILDDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@BUILDDIR@/intel-fix.sh ixgbevf,)

From 2de030223d6610a95a9c8ba6f96031e46968b00f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 7 May 2022 12:09:08 +0200
Subject: [PATCH 2025/2207] linux/scripts: perform preliminary tests earlier

---
 LINUX/configure              | 72 ++++++++++++++++++------------------
 LINUX/default-config.mak.in_ |  4 +-
 2 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 6ddde205d..89647c0b9 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -805,6 +805,42 @@ EOF
 fi
 lin_ver=$(awk '/LINUX_VERSION_CODE/ { printf "%03x%02x", $3/256, $3%256}' "$version_hdr")
 
+#################################################
+# preliminary build tests
+#################################################
+
+reset_tests
+
+broken_buildsystem() {
+	error <> $TMPDIR/extra.mk
+	i=$(($i+1))
+done
+
+  message " NOTE  " <> $TMPDIR/extra.mk
-	i=$(($i+1))
-done
-
-  message " NOTE  " <
Date: Wed, 11 May 2022 14:22:21 +0200
Subject: [PATCH 2026/2207] linux/e1000: add missing kring mode setting

Since e1000 doesn't initialize the tx rings when entering netmap mode,
it doesn't cal netmap_reset() on them, thus never marking the tx krings
as "ON". In netmap mode, netmap_transmit() was therefore able to send
network-stack frames on the netmap-owned rings. One symptom was
spurious transmit timeouts reported by kernels with BQL enabled.

This patch adds a call to netmap_krings_mode_commit() when e1000 is put
in netmap mode, thus properly setting the ON mark on tx rings.
---
 LINUX/if_e1000_netmap.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index a8b0864a7..126a8de7e 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -62,6 +62,7 @@ e1000_netmap_reg(struct netmap_adapter *na, int onoff)
 	} else {
 		nm_clear_native_flags(na);
 	}
+	netmap_krings_mode_commit(na, onoff);
 	if (netif_running(adapter->netdev))
 		e1000_up(adapter);
 	else

From d4987784463fc68ac6c9e6ad22f6feb669a6a0d4 Mon Sep 17 00:00:00 2001
From: root 
Date: Tue, 17 May 2022 17:52:41 +0000
Subject: [PATCH 2027/2207] Swap the src and dst IPv4 address in the pong msg

---
 apps/pkt-gen/pkt-gen.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 15909300e..81570e011 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1547,6 +1547,11 @@ pong_body(void *data)
 				dpkt[3] = spkt[0];
 				dpkt[4] = spkt[1];
 				dpkt[5] = spkt[2];
+				/* swap source and destination IPv4 */
+				dpkt[13] = spkt[15];
+				dpkt[14] = spkt[16];
+				dpkt[15] = spkt[13];
+				dpkt[16] = spkt[14];
 				txring->slot[txhead].len = slot->len;
 				txhead = nm_ring_next(txring, txhead);
 				txavail--;

From 2fc5b969ed628a920dcc9ce0c976f76c6ea647d0 Mon Sep 17 00:00:00 2001
From: root 
Date: Wed, 18 May 2022 11:51:21 +0000
Subject: [PATCH 2028/2207] Only flip IP addr for IPv4 packets

---
 apps/pkt-gen/pkt-gen.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 81570e011..79c06dfbc 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1322,6 +1322,10 @@ ping_body(void *data)
 		return NULL;
 	}
 
+	if (targ->g->af == AF_INET6) {
+		D("Warning: ping-pong with IPv6 not supported");
+	}
+
 	bzero(&buckets, sizeof(buckets));
 	clock_gettime(CLOCK_REALTIME_PRECISE, &last_print);
 	now = last_print;
@@ -1504,6 +1508,11 @@ pong_body(void *data)
 	if (n > 0)
 		D("understood ponger %llu but don't know how to do it",
 			(unsigned long long)n);
+
+	if (targ->g->af == AF_INET6) {
+		D("Warning: ping-pong with IPv6 not supported");
+	}
+
 	while (!targ->cancel && (n == 0 || sent < n)) {
 		uint32_t txhead, txavail;
 //#define BUSYWAIT
@@ -1548,11 +1557,14 @@ pong_body(void *data)
 				dpkt[4] = spkt[1];
 				dpkt[5] = spkt[2];
 				/* swap source and destination IPv4 */
-				dpkt[13] = spkt[15];
-				dpkt[14] = spkt[16];
-				dpkt[15] = spkt[13];
-				dpkt[16] = spkt[14];
+				if (ntohs(spkt[6]) & ETHERTYPE_IP) {
+					dpkt[13] = spkt[15];
+					dpkt[14] = spkt[16];
+					dpkt[15] = spkt[13];
+					dpkt[16] = spkt[14];
+				}
 				txring->slot[txhead].len = slot->len;
+				//dump_payload(dst, slot->len, txring, txhead);
 				txhead = nm_ring_next(txring, txhead);
 				txavail--;
 				sent++;

From 58660d0e9fc24bb1dd3918e1d301301b5ae1be3e Mon Sep 17 00:00:00 2001
From: root 
Date: Wed, 18 May 2022 14:38:21 +0000
Subject: [PATCH 2029/2207] fix ethertype check

---
 apps/pkt-gen/pkt-gen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 79c06dfbc..129bbf7f0 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1557,7 +1557,7 @@ pong_body(void *data)
 				dpkt[4] = spkt[1];
 				dpkt[5] = spkt[2];
 				/* swap source and destination IPv4 */
-				if (ntohs(spkt[6]) & ETHERTYPE_IP) {
+				if (spkt[6] == htons(ETHERTYPE_IP)) {
 					dpkt[13] = spkt[15];
 					dpkt[14] = spkt[16];
 					dpkt[15] = spkt[13];

From 0ecb7da2933df1fb0367b14a14d4a3f66fa855c3 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Wed, 25 May 2022 20:28:02 +0200
Subject: [PATCH 2030/2207] README.md: redirect FreeBSD users to the src tree

---
 README.md | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 1d6c99051..795d9951d 100644
--- a/README.md
+++ b/README.md
@@ -17,9 +17,10 @@ To learn about netmap, you can use the following resources:
 
 This repository contains source code (BSD-Copyright) for FreeBSD, Linux and
 Windows.
-Note that recent FreeBSD distributions (>= 10.x) already include both
-Netmap and VALE.
-
+Netmap, VALE and related applications are already included in FreeBSD
+since version 10.x. FreeBSD users should use the code included in the
+FreeBSD src tree rather than the one in this repository, although the two
+codebases are mostly aligned.
 
 ## Why should I use netmap?
 
@@ -89,8 +90,9 @@ by adding a `dev netmap` line, and rebuilding the kernel.
 Alternatively, you can build standalone modules (netmap, ixgbe, em, lem,
 re, igb, ...).
 
-Example applications are available in the `apps/` directory in this
-repository, or in `src/tools/tools/netmap/` in the FreeBSD source tree.
+Linux users can find the netmap example applications in the `apps/`
+directory in this repository. FreeBSD users will find the applications
+in `src/tools/tools/netmap/` within the FreeBSD src tree.
 
 
 ### Linux

From 2e54bde2dda07dd9475499782d0ea2a35e4bdda8 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Thu, 26 May 2022 22:13:24 +0200
Subject: [PATCH 2031/2207] README.md: improve example apps documentation

Closes #807
---
 README.md | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 795d9951d..248b3f8f1 100644
--- a/README.md
+++ b/README.md
@@ -90,8 +90,7 @@ by adding a `dev netmap` line, and rebuilding the kernel.
 Alternatively, you can build standalone modules (netmap, ixgbe, em, lem,
 re, igb, ...).
 
-Linux users can find the netmap example applications in the `apps/`
-directory in this repository. FreeBSD users will find the applications
+FreeBSD users will find the netmap example applications
 in `src/tools/tools/netmap/` within the FreeBSD src tree.
 
 
@@ -108,6 +107,9 @@ from the Intel e1000 project on sourceforce.
 If you need the netmap enabled drivers for e1000, veth, forcedeth,
 virtio-net or r8169 you will also need the full kernel sources.
 
+Linux users can find the netmap example applications in the `apps/`
+directory in this repository.
+
 #### Step 1
 
 Configure netmap. To compile Netmap/VALE and the Intel drivers above:

From b9bc7ae3938b5eaf7a53b5bee869ee27bb837f92 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 31 May 2022 18:52:16 +0200
Subject: [PATCH 2032/2207] linux/scripts: set default driver versions earlier

This is necessary, otherwise some driver build fixes are not
properly selected.
---
 LINUX/default-config.mak.in_ | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 54a370d9c..4de4f89ea 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -74,6 +74,14 @@ define default
 $(1)@v := $(if $($(1)@v),$($(1)@v),$(2))
 endef
 
+# set all the default versions (can be overridden by --select-version=)
+$(eval $(call default,ixgbe,5.3.8))
+$(eval $(call default,ixgbevf,4.3.2))
+$(eval $(call default,e1000e,3.4.0.2))
+$(eval $(call default,igb,5.3.5.20))
+$(eval $(call default,i40e,2.4.6))
+$(eval $(call default,ice,1.7.16))
+
 # some additional, driver-specific CFLAGS (used in the @build variable above) and fixes
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
@@ -89,14 +97,6 @@ ice@prepare := $(if $(filter $(ice@v),1.7.16),@BUILDDIR@/intel-fix.sh ice,)
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
 
-# set all the default versions (can be overridden by --select-version=)
-$(eval $(call default,ixgbe,5.3.8))
-$(eval $(call default,ixgbevf,4.3.2))
-$(eval $(call default,e1000e,3.4.0.2))
-$(eval $(call default,igb,5.3.5.20))
-$(eval $(call default,i40e,2.4.6))
-$(eval $(call default,ice,1.7.16))
-
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 

From a2e003d09b446d9e8ea097b0f720617d43d92bf9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 31 May 2022 18:34:13 +0200
Subject: [PATCH 2033/2207] linux/ice: remove unnecessary build tests

These were copied from i40e, but are not really
needed for ice.
---
 LINUX/configure          | 22 ----------------------
 LINUX/ice_netmap_linux.h | 27 +++++++--------------------
 2 files changed, 7 insertions(+), 42 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 89647c0b9..e8f0f2d14 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2271,28 +2271,6 @@ EOF
 
   fi # virtio-net
 
-  if drv enabled ice; then
-    add_test 'define ICE_PTR_ARRAY' <tx_rings[0];
-  	}
-EOF
-
-   add_test 'define ICE_PTR_STATE' <
-	#pragma GCC diagnostic error "-Wincompatible-pointer-types"
-
-	int
-	dummy(struct ice_pf *pf) {
-		return test_and_set_bit(1, &pf->state);
-	}
-EOF
-  fi # ice
-
   if drv enabled i40e; then
     add_test 'define I40E_PTR_ARRAY' <tx_rings[(r)])
-#define NM_ICE_RX_RING(a, r)		((a)->rx_rings[(r)])
-#else
-#define NM_ICE_TX_RING(a, r)		(&(a)->tx_rings[(r)])
-#define NM_ICE_RX_RING(a, r)		(&(a)->rx_rings[(r)])
-#endif
-#ifdef NETMAP_LINUX_ICE_PTR_STATE
-#define NM_ICE_STATE(pf)		(&(pf)->state)
-#else
-#define NM_ICE_STATE(pf)		((pf)->state)
-#endif
-
 #ifdef NETMAP_ICE_LIB
 
 /*
@@ -66,7 +53,7 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (!netif_carrier_ok(ifp))
 		return 0;
 
-	txr = NM_ICE_TX_RING(vsi, kring->ring_id);
+	txr = vsi->tx_rings[kring->ring_id];
 	if (unlikely(!txr || !txr->desc)) {
 		nm_prlim(1, "ring %s is missing (txr=%p)", kring->name, txr);
 		return ENXIO;
@@ -232,7 +219,7 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 	if (!netif_running(ifp))
 		return 0;
 
-	rxr = NM_ICE_RX_RING(vsi, kring->ring_id);
+	rxr = vsi->rx_rings[kring->ring_id];
 	if (unlikely(!rxr || !rxr->desc)) {
 		nm_prlim(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
 		return ENXIO;
@@ -378,7 +365,7 @@ ice_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct ice_pf   *pf = (struct ice_pf *)vsi->back;
 	bool was_running;
 
-	while (test_and_set_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf)))
+	while (test_and_set_bit(ICE_CFG_BUSY, pf->state))
 			usleep_range(1000, 2000);
 
 	if ( (was_running = netif_running(vsi->netdev)) )
@@ -396,7 +383,7 @@ ice_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
 
-	clear_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf));
+	clear_bit(ICE_CFG_BUSY, pf->state);
 
 	return 0;
 }
@@ -454,10 +441,10 @@ ice_netmap_attach(struct ice_vsi *vsi)
 	na.ifp = vsi->netdev;
 	na.pdev = &vsi->back->pdev->dev;
 	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
-	na.num_tx_desc = NM_ICE_TX_RING(vsi, 0)->count;
-	na.num_rx_desc = NM_ICE_RX_RING(vsi, 0)->count;
+	na.num_tx_desc = vsi->tx_rings[0]->count;
+	na.num_rx_desc = vsi->rx_rings[0]->count;
 	na.num_tx_rings = vsi->num_txq;
-    na.num_rx_rings = vsi->num_rxq;
+	na.num_rx_rings = vsi->num_rxq;
 	na.rx_buf_maxsize = vsi->rx_buf_len;
 	na.nm_txsync = ice_netmap_txsync;
 	na.nm_rxsync = ice_netmap_rxsync;

From 78e5ea516a482e9271f20a15711d1a6459c3fe33 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 11 Jun 2022 16:07:44 +0200
Subject: [PATCH 2034/2207] ctrl-api-test: fix dangling-pointer warning

---
 utils/ctrl-api-test.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 41e75ab1f..c582a32d7 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1974,6 +1974,7 @@ nmreq_parsing(struct TestContext *ctx)
 			ret = -1;
 		}
 	}
+	ctx->nmctx = NULL;
 	return ret;
 }
 

From 1f777076bd242ea42a46b40c0225087084994d01 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Jun 2022 09:56:13 +0200
Subject: [PATCH 2035/2207] linux: patches for latest Intel drivers

---
 LINUX/default-config.mak.in_               |  12 +-
 LINUX/final-patches/intel--i40e--2.19.3    | 173 +++++++++++++++++
 LINUX/final-patches/intel--ice--1.8.9      | 215 +++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.10.2     | 138 +++++++++++++
 LINUX/final-patches/intel--ixgbe--5.15.2   | 173 +++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.15.1 | 169 ++++++++++++++++
 6 files changed, 874 insertions(+), 6 deletions(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.19.3
 create mode 100644 LINUX/final-patches/intel--ice--1.8.9
 create mode 100644 LINUX/final-patches/intel--igb--5.10.2
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.15.2
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.15.1

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 4de4f89ea..0169b6bfe 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -87,12 +87,12 @@ e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
 i40e@cflags :=  $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
-igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@BUILDDIR@/intel-fix.sh igb,)
-e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@BUILDDIR@/intel-fix.sh e1000e,)
-ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
-ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@BUILDDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15),@BUILDDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16),@BUILDDIR@/intel-fix.sh ice,)
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2 5.7.2 5.8.5 5.9.3 5.10.2),@BUILDDIR@/intel-fix.sh igb,)
+e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh e1000e,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
+ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 18.9),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/final-patches/intel--i40e--2.19.3 b/LINUX/final-patches/intel--i40e--2.19.3
new file mode 100644
index 000000000..6f79f49a3
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.19.3
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 572217f..5059ff4 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ obj-m += auxiliary.o
+@@ -41,7 +41,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -95,9 +95,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index b9dc44c..45d84f0 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -163,6 +163,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4146,6 +4151,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4275,6 +4284,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4303,6 +4316,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15612,6 +15630,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16005,6 +16029,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 453e7ac..cb78e15 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -983,6 +987,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2931,7 +2940,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.8.9 b/LINUX/final-patches/intel--ice--1.8.9
new file mode 100644
index 000000000..c26828f02
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.8.9
@@ -0,0 +1,215 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 789a908..cdb3394 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -57,32 +57,33 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
+-ice-$(CONFIG_PCI_IOV) += ice_dcf.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
+-ice-$(CONFIG_PCI_IOV) +=	\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_dcf.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=	\
+ 	ice_sriov.o		\
+ 	ice_vf_mbx.o		\
+ 	ice_vf_vsi_vlan_ops.o	\
+ 	ice_vf_adq.o		\
+ 	ice_virtchnl.o		\
+ 	ice_vf_lib.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ ifeq (${NEED_AUX_BUS},2)
+@@ -92,7 +93,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -119,7 +120,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index adaaa84..cb29c06 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -459,6 +464,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -615,6 +624,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++    if (ice_netmap_configure_rx_ring(ring))
++        return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -885,6 +899,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++    ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_lib.c b/ice/ice_lib.c
+index c13efae..bed8529 100644
+--- a/ice/ice_lib.c
++++ b/ice/ice_lib.c
+@@ -10,6 +10,12 @@
+ #include "ice_vsi_vlan_ops.h"
+ #include "ice_irq.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
++
+ /**
+  * ice_vsi_type_str - maps VSI type enum to string equivalents
+  * @vsi_type: VSI type enum
+@@ -2814,6 +2820,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ 	if (!vsi->agg_node)
+ 		ice_set_agg_vsi(vsi);
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ unroll_clear_rings:
+@@ -3162,6 +3172,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
+ 	 */
+ 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
+ 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
++#ifdef DEV_NETMAP
++        netmap_detach(vsi->netdev);
++#endif
+ 		unregister_netdev(vsi->netdev);
+ 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 68e659d..0bdc49b 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
+ 	if (!rx_ring->rx_buf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (rx_ring->xsk_pool) {
+ 		ice_xsk_clean_rx_ring(rx_ring);
diff --git a/LINUX/final-patches/intel--igb--5.10.2 b/LINUX/final-patches/intel--igb--5.10.2
new file mode 100644
index 000000000..279766615
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.10.2
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 3325ed6..f3195bb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index fdca9fd..206b190 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.15.2 b/LINUX/final-patches/intel--ixgbe--5.15.2
new file mode 100644
index 000000000..c7bf35978
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.15.2
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bd095f..5b38247 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 82ec4c3..95daed1 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2228,6 +2256,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4433,6 +4475,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13204,6 +13252,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13260,6 +13312,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.15.1 b/LINUX/final-patches/intel--ixgbevf--4.15.1
new file mode 100644
index 000000000..79e875ca1
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.15.1
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 1a84106..04f4155 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index f142f2b..ba61d3e 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1383,6 +1411,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2101,6 +2139,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2335,6 +2377,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5639,8 +5685,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5681,6 +5729,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 090771a..250fc59 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 60ac898404967d92aad094b66fa9ec331c68bd7b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Jun 2022 19:19:17 +0200
Subject: [PATCH 2036/2207] Windows: mark as unmantained

---
 README.md          | 4 +++-
 WINDOWS/README.txt | 5 +++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 1d6c99051..05dda1cf7 100644
--- a/README.md
+++ b/README.md
@@ -149,7 +149,9 @@ command above. The new drivers will then be called `e1000e-netmap`,
 ### Windows
 
 Netmap has been ported to Windows in summer 2015 by Alessio Faina as part of
-his Master thesis. Please look [here](WINDOWS/README.txt) for details.
+his Master thesis. You may take a look [here](WINDOWS/README.txt) for details,
+but please be aware that the port has been left behind for years, and is
+currently unmantained.
 
 ## Applications
 
diff --git a/WINDOWS/README.txt b/WINDOWS/README.txt
index 5b1c1cdf9..2e3d5a48f 100644
--- a/WINDOWS/README.txt
+++ b/WINDOWS/README.txt
@@ -1,6 +1,7 @@
 **************************************************************
-DISCLAIMER: This documentation is currently outdated.
-            It is going to be updated soon.
+DISCLAIMER: The Windows port of netmap is currently unmantained.  Not even
+compilation is guaranteed.  Moreover, it is know to contain security-critcal
+bugs.
 **************************************************************
 
 This directory contains the Windows version of netmap, developed by

From ec53bac2601536816e7565bfbf4292c58287c010 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 11 May 2022 14:22:21 +0200
Subject: [PATCH 2037/2207] linux/e1000: add missing kring mode setting

Since e1000 doesn't initialize the tx rings when entering netmap mode,
it doesn't cal netmap_reset() on them, thus never marking the tx krings
as "ON". In netmap mode, netmap_transmit() was therefore able to send
network-stack frames on the netmap-owned rings. One symptom was
spurious transmit timeouts reported by kernels with BQL enabled.

This patch adds a call to netmap_krings_mode_commit() when e1000 is put
in netmap mode, thus properly setting the ON mark on tx rings.
---
 LINUX/if_e1000_netmap.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index a8b0864a7..126a8de7e 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -62,6 +62,7 @@ e1000_netmap_reg(struct netmap_adapter *na, int onoff)
 	} else {
 		nm_clear_native_flags(na);
 	}
+	netmap_krings_mode_commit(na, onoff);
 	if (netif_running(adapter->netdev))
 		e1000_up(adapter);
 	else

From b9b1e370c84d750c88f0ceab53305a673e457c68 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 31 May 2022 18:52:16 +0200
Subject: [PATCH 2038/2207] linux/scripts: set default driver versions earlier

This is necessary, otherwise some driver build fixes are not
properly selected.
---
 LINUX/default-config.mak.in_ | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 54a370d9c..4de4f89ea 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -74,6 +74,14 @@ define default
 $(1)@v := $(if $($(1)@v),$($(1)@v),$(2))
 endef
 
+# set all the default versions (can be overridden by --select-version=)
+$(eval $(call default,ixgbe,5.3.8))
+$(eval $(call default,ixgbevf,4.3.2))
+$(eval $(call default,e1000e,3.4.0.2))
+$(eval $(call default,igb,5.3.5.20))
+$(eval $(call default,i40e,2.4.6))
+$(eval $(call default,ice,1.7.16))
+
 # some additional, driver-specific CFLAGS (used in the @build variable above) and fixes
 e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
@@ -89,14 +97,6 @@ ice@prepare := $(if $(filter $(ice@v),1.7.16),@BUILDDIR@/intel-fix.sh ice,)
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
 
-# set all the default versions (can be overridden by --select-version=)
-$(eval $(call default,ixgbe,5.3.8))
-$(eval $(call default,ixgbevf,4.3.2))
-$(eval $(call default,e1000e,3.4.0.2))
-$(eval $(call default,igb,5.3.5.20))
-$(eval $(call default,i40e,2.4.6))
-$(eval $(call default,ice,1.7.16))
-
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 

From 54768a2bb9313cbe92137d5fe52442773368aa9f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 31 May 2022 18:34:13 +0200
Subject: [PATCH 2039/2207] linux/ice: remove unnecessary build tests

These were copied from i40e, but are not really
needed for ice.
---
 LINUX/configure          | 22 ----------------------
 LINUX/ice_netmap_linux.h | 27 +++++++--------------------
 2 files changed, 7 insertions(+), 42 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 89647c0b9..e8f0f2d14 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2271,28 +2271,6 @@ EOF
 
   fi # virtio-net
 
-  if drv enabled ice; then
-    add_test 'define ICE_PTR_ARRAY' <tx_rings[0];
-  	}
-EOF
-
-   add_test 'define ICE_PTR_STATE' <
-	#pragma GCC diagnostic error "-Wincompatible-pointer-types"
-
-	int
-	dummy(struct ice_pf *pf) {
-		return test_and_set_bit(1, &pf->state);
-	}
-EOF
-  fi # ice
-
   if drv enabled i40e; then
     add_test 'define I40E_PTR_ARRAY' <tx_rings[(r)])
-#define NM_ICE_RX_RING(a, r)		((a)->rx_rings[(r)])
-#else
-#define NM_ICE_TX_RING(a, r)		(&(a)->tx_rings[(r)])
-#define NM_ICE_RX_RING(a, r)		(&(a)->rx_rings[(r)])
-#endif
-#ifdef NETMAP_LINUX_ICE_PTR_STATE
-#define NM_ICE_STATE(pf)		(&(pf)->state)
-#else
-#define NM_ICE_STATE(pf)		((pf)->state)
-#endif
-
 #ifdef NETMAP_ICE_LIB
 
 /*
@@ -66,7 +53,7 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 	if (!netif_carrier_ok(ifp))
 		return 0;
 
-	txr = NM_ICE_TX_RING(vsi, kring->ring_id);
+	txr = vsi->tx_rings[kring->ring_id];
 	if (unlikely(!txr || !txr->desc)) {
 		nm_prlim(1, "ring %s is missing (txr=%p)", kring->name, txr);
 		return ENXIO;
@@ -232,7 +219,7 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 	if (!netif_running(ifp))
 		return 0;
 
-	rxr = NM_ICE_RX_RING(vsi, kring->ring_id);
+	rxr = vsi->rx_rings[kring->ring_id];
 	if (unlikely(!rxr || !rxr->desc)) {
 		nm_prlim(1, "ring %s is missing (rxr=%p)", kring->name, rxr);
 		return ENXIO;
@@ -378,7 +365,7 @@ ice_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct ice_pf   *pf = (struct ice_pf *)vsi->back;
 	bool was_running;
 
-	while (test_and_set_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf)))
+	while (test_and_set_bit(ICE_CFG_BUSY, pf->state))
 			usleep_range(1000, 2000);
 
 	if ( (was_running = netif_running(vsi->netdev)) )
@@ -396,7 +383,7 @@ ice_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
 
-	clear_bit(ICE_CFG_BUSY, NM_ICE_STATE(pf));
+	clear_bit(ICE_CFG_BUSY, pf->state);
 
 	return 0;
 }
@@ -454,10 +441,10 @@ ice_netmap_attach(struct ice_vsi *vsi)
 	na.ifp = vsi->netdev;
 	na.pdev = &vsi->back->pdev->dev;
 	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
-	na.num_tx_desc = NM_ICE_TX_RING(vsi, 0)->count;
-	na.num_rx_desc = NM_ICE_RX_RING(vsi, 0)->count;
+	na.num_tx_desc = vsi->tx_rings[0]->count;
+	na.num_rx_desc = vsi->rx_rings[0]->count;
 	na.num_tx_rings = vsi->num_txq;
-    na.num_rx_rings = vsi->num_rxq;
+	na.num_rx_rings = vsi->num_rxq;
 	na.rx_buf_maxsize = vsi->rx_buf_len;
 	na.nm_txsync = ice_netmap_txsync;
 	na.nm_rxsync = ice_netmap_rxsync;

From 3820b76dc740c0a245fee20e9dd016647cb792c4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Jun 2022 09:56:13 +0200
Subject: [PATCH 2040/2207] linux: patches for latest Intel drivers

---
 LINUX/default-config.mak.in_               |  12 +-
 LINUX/final-patches/intel--i40e--2.19.3    | 173 +++++++++++++++++
 LINUX/final-patches/intel--ice--1.8.9      | 215 +++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.10.2     | 138 +++++++++++++
 LINUX/final-patches/intel--ixgbe--5.15.2   | 173 +++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.15.1 | 169 ++++++++++++++++
 6 files changed, 874 insertions(+), 6 deletions(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.19.3
 create mode 100644 LINUX/final-patches/intel--ice--1.8.9
 create mode 100644 LINUX/final-patches/intel--igb--5.10.2
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.15.2
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.15.1

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 4de4f89ea..0169b6bfe 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -87,12 +87,12 @@ e1000e@cflags := -fno-pie
 igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
 ixgbe@cflags := $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
 i40e@cflags :=  $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
-igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2),@BUILDDIR@/intel-fix.sh igb,)
-e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4),@BUILDDIR@/intel-fix.sh e1000e,)
-ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
-ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3),@BUILDDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15),@BUILDDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16),@BUILDDIR@/intel-fix.sh ice,)
+igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2 5.7.2 5.8.5 5.9.3 5.10.2),@BUILDDIR@/intel-fix.sh igb,)
+e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh e1000e,)
+ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
+ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 18.9),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/final-patches/intel--i40e--2.19.3 b/LINUX/final-patches/intel--i40e--2.19.3
new file mode 100644
index 000000000..6f79f49a3
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.19.3
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 572217f..5059ff4 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ obj-m += auxiliary.o
+@@ -41,7 +41,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -95,9 +95,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index b9dc44c..45d84f0 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -163,6 +163,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4146,6 +4151,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4275,6 +4284,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4303,6 +4316,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15612,6 +15630,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16005,6 +16029,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 453e7ac..cb78e15 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -983,6 +987,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2931,7 +2940,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.8.9 b/LINUX/final-patches/intel--ice--1.8.9
new file mode 100644
index 000000000..c26828f02
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.8.9
@@ -0,0 +1,215 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 789a908..cdb3394 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -57,32 +57,33 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
+-ice-$(CONFIG_PCI_IOV) += ice_dcf.o
+-ice-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
+-ice-$(CONFIG_PCI_IOV) +=	\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_dcf.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) += ice_virtchnl_fdir.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=	\
+ 	ice_sriov.o		\
+ 	ice_vf_mbx.o		\
+ 	ice_vf_vsi_vlan_ops.o	\
+ 	ice_vf_adq.o		\
+ 	ice_virtchnl.o		\
+ 	ice_vf_lib.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ ifeq (${NEED_AUX_BUS},2)
+@@ -92,7 +93,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -119,7 +120,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index adaaa84..cb29c06 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -459,6 +464,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -615,6 +624,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++    if (ice_netmap_configure_rx_ring(ring))
++        return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -885,6 +899,11 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++    ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_lib.c b/ice/ice_lib.c
+index c13efae..bed8529 100644
+--- a/ice/ice_lib.c
++++ b/ice/ice_lib.c
+@@ -10,6 +10,12 @@
+ #include "ice_vsi_vlan_ops.h"
+ #include "ice_irq.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
++
+ /**
+  * ice_vsi_type_str - maps VSI type enum to string equivalents
+  * @vsi_type: VSI type enum
+@@ -2814,6 +2820,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
+ 	if (!vsi->agg_node)
+ 		ice_set_agg_vsi(vsi);
+ 
++#ifdef DEV_NETMAP
++    ice_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ unroll_clear_rings:
+@@ -3162,6 +3172,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
+ 	 */
+ 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
+ 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
++#ifdef DEV_NETMAP
++        netmap_detach(vsi->netdev);
++#endif
+ 		unregister_netdev(vsi->netdev);
+ 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 68e659d..0bdc49b 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
+ 	if (!rx_ring->rx_buf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (rx_ring->xsk_pool) {
+ 		ice_xsk_clean_rx_ring(rx_ring);
diff --git a/LINUX/final-patches/intel--igb--5.10.2 b/LINUX/final-patches/intel--igb--5.10.2
new file mode 100644
index 000000000..279766615
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.10.2
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 3325ed6..f3195bb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index fdca9fd..206b190 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.15.2 b/LINUX/final-patches/intel--ixgbe--5.15.2
new file mode 100644
index 000000000..c7bf35978
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.15.2
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bd095f..5b38247 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 82ec4c3..95daed1 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2228,6 +2256,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4433,6 +4475,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13204,6 +13252,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13260,6 +13312,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.15.1 b/LINUX/final-patches/intel--ixgbevf--4.15.1
new file mode 100644
index 000000000..79e875ca1
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.15.1
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 1a84106..04f4155 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index f142f2b..ba61d3e 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1383,6 +1411,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2101,6 +2139,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2335,6 +2377,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5639,8 +5685,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5681,6 +5729,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 090771a..250fc59 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From b6e9313b2aea64d279222e959b4f326a389baef7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Jun 2022 19:19:17 +0200
Subject: [PATCH 2041/2207] Windows: mark as unmantained

---
 README.md          | 4 +++-
 WINDOWS/README.txt | 5 +++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 248b3f8f1..2342226c0 100644
--- a/README.md
+++ b/README.md
@@ -153,7 +153,9 @@ command above. The new drivers will then be called `e1000e-netmap`,
 ### Windows
 
 Netmap has been ported to Windows in summer 2015 by Alessio Faina as part of
-his Master thesis. Please look [here](WINDOWS/README.txt) for details.
+his Master thesis. You may take a look [here](WINDOWS/README.txt) for details,
+but please be aware that the port has been left behind for years, and is
+currently unmantained.
 
 ## Applications
 
diff --git a/WINDOWS/README.txt b/WINDOWS/README.txt
index 5b1c1cdf9..2e3d5a48f 100644
--- a/WINDOWS/README.txt
+++ b/WINDOWS/README.txt
@@ -1,6 +1,7 @@
 **************************************************************
-DISCLAIMER: This documentation is currently outdated.
-            It is going to be updated soon.
+DISCLAIMER: The Windows port of netmap is currently unmantained.  Not even
+compilation is guaranteed.  Moreover, it is know to contain security-critcal
+bugs.
 **************************************************************
 
 This directory contains the Windows version of netmap, developed by

From e827ea6965d5c47b13eed24cd7dca2798b40fae9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 22 Jun 2022 21:03:00 +0200
Subject: [PATCH 2042/2207] linux/ice: fix hooks and callbacks

---
 LINUX/final-patches/intel--ice--1.7.16 | 79 ++++++++++++-----------
 LINUX/final-patches/intel--ice--1.8.3  | 81 +++++++++++------------
 LINUX/final-patches/intel--ice--1.8.8  | 81 +++++++++++------------
 LINUX/final-patches/intel--ice--1.8.9  | 81 +++++++++++------------
 LINUX/ice_netmap_linux.h               | 89 +++++++++++++++-----------
 5 files changed, 216 insertions(+), 195 deletions(-)

diff --git a/LINUX/final-patches/intel--ice--1.7.16 b/LINUX/final-patches/intel--ice--1.7.16
index 95cfa2658..18cae7233 100644
--- a/LINUX/final-patches/intel--ice--1.7.16
+++ b/LINUX/final-patches/intel--ice--1.7.16
@@ -75,7 +75,7 @@ index a98dd4c..8b64fcc 100644
  	$(MAKE) -C lttng
  endif
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index 9f2320f..6e0adf4 100644
+index 9f2320f..9f9126a 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -95,7 +95,7 @@ index 9f2320f..6e0adf4 100644
  	rlan_ctx.lrxqthresh = 1;
  
 +#ifdef DEV_NETMAP
-+    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
 +#endif /* DEV_NETMAP */
 +
  	/* Enable Flexible Descriptors in the queue context which
@@ -107,8 +107,8 @@ index 9f2320f..6e0adf4 100644
  #endif /* HAVE_AF_XDP_ZC_SUPPORT */
 +    
 +#ifdef DEV_NETMAP
-+    if (ice_netmap_configure_rx_ring(ring))
-+        return 0;
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
 +#endif /* DEV_NETMAP */
  
  	ice_alloc_rx_bufs(ring, num_bufs);
@@ -119,19 +119,19 @@ index 9f2320f..6e0adf4 100644
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+    ice_netmap_configure_tx_ring(ring);
++	ice_netmap_configure_tx_ring(ring);
 +#endif /* DEV_NETMAP */
 +
  
  	return 0;
  }
-diff --git a/ice/ice_lib.c b/ice/ice_lib.c
-index 8899720..99687fe 100644
---- a/ice/ice_lib.c
-+++ b/ice/ice_lib.c
-@@ -9,6 +9,12 @@
- #include "ice_devlink.h"
- #include "ice_vsi_vlan_ops.h"
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 97e754b..4eeb305 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -103,6 +103,12 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#define NETMAP_ICE_LIB
@@ -139,32 +139,32 @@ index 8899720..99687fe 100644
 +#endif
 +
 +
- /**
-  * ice_vsi_type_str - maps VSI type enum to string equivalents
-  * @vsi_type: VSI type enum
-@@ -2790,6 +2796,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
- 	if (!vsi->agg_node)
- 		ice_set_agg_vsi(vsi);
+ static struct workqueue_struct *ice_wq;
  
-+#ifdef DEV_NETMAP
-+    ice_netmap_attach(vsi);
-+#endif
-+
- 	return vsi;
+ static const struct net_device_ops ice_netdev_recovery_ops;
+@@ -6169,6 +6175,9 @@ probe_done:
+ 		dev_warn(dev, "Aux drivers are not supported on this device\n");
+ 	}
  
- unroll_clear_rings:
-@@ -3134,6 +3144,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
- 	 */
- 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
- 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
 +#ifdef DEV_NETMAP
-+        netmap_detach(vsi->netdev);
++	ice_netmap_attach(pf);
 +#endif
- 		unregister_netdev(vsi->netdev);
- 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6279,6 +6288,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
  
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+ 	 * it means that the driver went into recovery mode on load.
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 037cc5a..884df87 100644
+index 037cc5a..899ee4c 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -30,6 +30,10 @@
@@ -189,20 +189,21 @@ index 037cc5a..884df87 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
- 	if (!rx_ring->rx_buf)
- 		return;
+@@ -1481,6 +1489,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
  
 +#ifdef DEV_NETMAP
 +    if (rx_ring->netdev) {
 +        int dummy, nm_irq;
 +        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
 +        if (nm_irq != NM_IRQ_PASS) {
-+            return;
++            return 1;
 +        }
 +    }
 +#endif /* DEV_NETMAP */
 +
- #ifdef HAVE_AF_XDP_ZC_SUPPORT
- 	if (rx_ring->xsk_pool) {
- 		ice_xsk_clean_rx_ring(rx_ring);
++
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
diff --git a/LINUX/final-patches/intel--ice--1.8.3 b/LINUX/final-patches/intel--ice--1.8.3
index 7a4218177..8435ea488 100644
--- a/LINUX/final-patches/intel--ice--1.8.3
+++ b/LINUX/final-patches/intel--ice--1.8.3
@@ -82,7 +82,7 @@ index 789a908..cdb3394 100644
  	$(MAKE) -C lttng
  endif
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index adaaa84..cb29c06 100644
+index adaaa84..b281b6b 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -102,7 +102,7 @@ index adaaa84..cb29c06 100644
  	rlan_ctx.lrxqthresh = 1;
  
 +#ifdef DEV_NETMAP
-+    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
 +#endif /* DEV_NETMAP */
 +
  	/* Enable Flexible Descriptors in the queue context which
@@ -114,8 +114,8 @@ index adaaa84..cb29c06 100644
  #endif /* HAVE_AF_XDP_ZC_SUPPORT */
 +    
 +#ifdef DEV_NETMAP
-+    if (ice_netmap_configure_rx_ring(ring))
-+        return 0;
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
 +#endif /* DEV_NETMAP */
  
  	ice_alloc_rx_bufs(ring, num_bufs);
@@ -126,52 +126,52 @@ index adaaa84..cb29c06 100644
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+    ice_netmap_configure_tx_ring(ring);
++	ice_netmap_configure_tx_ring(ring);
 +#endif /* DEV_NETMAP */
 +
  
  	return 0;
  }
-diff --git a/ice/ice_lib.c b/ice/ice_lib.c
-index 034a064..d8d3ef9 100644
---- a/ice/ice_lib.c
-+++ b/ice/ice_lib.c
-@@ -10,6 +10,12 @@
- #include "ice_vsi_vlan_ops.h"
- #include "ice_irq.h"
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index e00d7f8..9438f93 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#define NETMAP_ICE_LIB
 +#include 
 +#endif
-+
 +
  /**
-  * ice_vsi_type_str - maps VSI type enum to string equivalents
-  * @vsi_type: VSI type enum
-@@ -2807,6 +2813,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
- 	if (!vsi->agg_node)
- 		ice_set_agg_vsi(vsi);
- 
-+#ifdef DEV_NETMAP
-+    ice_netmap_attach(vsi);
-+#endif
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5990,6 +5995,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
 +
- 	return vsi;
- 
- unroll_clear_rings:
-@@ -3155,6 +3165,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
- 	 */
- 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
- 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
 +#ifdef DEV_NETMAP
-+        netmap_detach(vsi->netdev);
++	ice_netmap_attach(pf);
 +#endif
- 		unregister_netdev(vsi->netdev);
- 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6106,6 +6115,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
  
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+ 	 * it means that the driver went into recovery mode on load.
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 68e659d..0bdc49b 100644
+index 68e659d..cb048fe 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -30,6 +30,10 @@
@@ -196,20 +196,21 @@ index 68e659d..0bdc49b 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
- 	if (!rx_ring->rx_buf)
- 		return;
+@@ -1472,6 +1480,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
  
 +#ifdef DEV_NETMAP
 +    if (rx_ring->netdev) {
 +        int dummy, nm_irq;
 +        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
 +        if (nm_irq != NM_IRQ_PASS) {
-+            return;
++            return 1;
 +        }
 +    }
 +#endif /* DEV_NETMAP */
 +
- #ifdef HAVE_AF_XDP_ZC_SUPPORT
- 	if (rx_ring->xsk_pool) {
- 		ice_xsk_clean_rx_ring(rx_ring);
++
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
diff --git a/LINUX/final-patches/intel--ice--1.8.8 b/LINUX/final-patches/intel--ice--1.8.8
index 7a4218177..a23d92e45 100644
--- a/LINUX/final-patches/intel--ice--1.8.8
+++ b/LINUX/final-patches/intel--ice--1.8.8
@@ -82,7 +82,7 @@ index 789a908..cdb3394 100644
  	$(MAKE) -C lttng
  endif
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index adaaa84..cb29c06 100644
+index adaaa84..b281b6b 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -102,7 +102,7 @@ index adaaa84..cb29c06 100644
  	rlan_ctx.lrxqthresh = 1;
  
 +#ifdef DEV_NETMAP
-+    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
 +#endif /* DEV_NETMAP */
 +
  	/* Enable Flexible Descriptors in the queue context which
@@ -114,8 +114,8 @@ index adaaa84..cb29c06 100644
  #endif /* HAVE_AF_XDP_ZC_SUPPORT */
 +    
 +#ifdef DEV_NETMAP
-+    if (ice_netmap_configure_rx_ring(ring))
-+        return 0;
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
 +#endif /* DEV_NETMAP */
  
  	ice_alloc_rx_bufs(ring, num_bufs);
@@ -126,52 +126,52 @@ index adaaa84..cb29c06 100644
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+    ice_netmap_configure_tx_ring(ring);
++	ice_netmap_configure_tx_ring(ring);
 +#endif /* DEV_NETMAP */
 +
  
  	return 0;
  }
-diff --git a/ice/ice_lib.c b/ice/ice_lib.c
-index 034a064..d8d3ef9 100644
---- a/ice/ice_lib.c
-+++ b/ice/ice_lib.c
-@@ -10,6 +10,12 @@
- #include "ice_vsi_vlan_ops.h"
- #include "ice_irq.h"
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index ab5e57c..b957285 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#define NETMAP_ICE_LIB
 +#include 
 +#endif
-+
 +
  /**
-  * ice_vsi_type_str - maps VSI type enum to string equivalents
-  * @vsi_type: VSI type enum
-@@ -2807,6 +2813,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
- 	if (!vsi->agg_node)
- 		ice_set_agg_vsi(vsi);
- 
-+#ifdef DEV_NETMAP
-+    ice_netmap_attach(vsi);
-+#endif
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6005,6 +6010,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
 +
- 	return vsi;
- 
- unroll_clear_rings:
-@@ -3155,6 +3165,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
- 	 */
- 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
- 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
 +#ifdef DEV_NETMAP
-+        netmap_detach(vsi->netdev);
++	ice_netmap_attach(pf);
 +#endif
- 		unregister_netdev(vsi->netdev);
- 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6121,6 +6130,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
  
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+ 	 * it means that the driver went into recovery mode on load.
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 68e659d..0bdc49b 100644
+index 68e659d..cb048fe 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -30,6 +30,10 @@
@@ -196,20 +196,21 @@ index 68e659d..0bdc49b 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
- 	if (!rx_ring->rx_buf)
- 		return;
+@@ -1472,6 +1480,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
  
 +#ifdef DEV_NETMAP
 +    if (rx_ring->netdev) {
 +        int dummy, nm_irq;
 +        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
 +        if (nm_irq != NM_IRQ_PASS) {
-+            return;
++            return 1;
 +        }
 +    }
 +#endif /* DEV_NETMAP */
 +
- #ifdef HAVE_AF_XDP_ZC_SUPPORT
- 	if (rx_ring->xsk_pool) {
- 		ice_xsk_clean_rx_ring(rx_ring);
++
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
diff --git a/LINUX/final-patches/intel--ice--1.8.9 b/LINUX/final-patches/intel--ice--1.8.9
index c26828f02..4ae6ad83e 100644
--- a/LINUX/final-patches/intel--ice--1.8.9
+++ b/LINUX/final-patches/intel--ice--1.8.9
@@ -82,7 +82,7 @@ index 789a908..cdb3394 100644
  	$(MAKE) -C lttng
  endif
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index adaaa84..cb29c06 100644
+index adaaa84..b281b6b 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -102,7 +102,7 @@ index adaaa84..cb29c06 100644
  	rlan_ctx.lrxqthresh = 1;
  
 +#ifdef DEV_NETMAP
-+    ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
 +#endif /* DEV_NETMAP */
 +
  	/* Enable Flexible Descriptors in the queue context which
@@ -114,8 +114,8 @@ index adaaa84..cb29c06 100644
  #endif /* HAVE_AF_XDP_ZC_SUPPORT */
 +    
 +#ifdef DEV_NETMAP
-+    if (ice_netmap_configure_rx_ring(ring))
-+        return 0;
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
 +#endif /* DEV_NETMAP */
  
  	ice_alloc_rx_bufs(ring, num_bufs);
@@ -126,52 +126,52 @@ index adaaa84..cb29c06 100644
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+    ice_netmap_configure_tx_ring(ring);
++	ice_netmap_configure_tx_ring(ring);
 +#endif /* DEV_NETMAP */
 +
  
  	return 0;
  }
-diff --git a/ice/ice_lib.c b/ice/ice_lib.c
-index c13efae..bed8529 100644
---- a/ice/ice_lib.c
-+++ b/ice/ice_lib.c
-@@ -10,6 +10,12 @@
- #include "ice_vsi_vlan_ops.h"
- #include "ice_irq.h"
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index e546eef..4894aa7 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
 +#define NETMAP_ICE_LIB
 +#include 
 +#endif
-+
 +
  /**
-  * ice_vsi_type_str - maps VSI type enum to string equivalents
-  * @vsi_type: VSI type enum
-@@ -2814,6 +2820,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
- 	if (!vsi->agg_node)
- 		ice_set_agg_vsi(vsi);
- 
-+#ifdef DEV_NETMAP
-+    ice_netmap_attach(vsi);
-+#endif
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6005,6 +6010,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
 +
- 	return vsi;
- 
- unroll_clear_rings:
-@@ -3162,6 +3172,9 @@ int ice_vsi_release(struct ice_vsi *vsi)
- 	 */
- 	if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
- 	    (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
 +#ifdef DEV_NETMAP
-+        netmap_detach(vsi->netdev);
++	ice_netmap_attach(pf);
 +#endif
- 		unregister_netdev(vsi->netdev);
- 		clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6121,6 +6130,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
  
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+ 	 * it means that the driver went into recovery mode on load.
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 68e659d..0bdc49b 100644
+index 68e659d..cb048fe 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -30,6 +30,10 @@
@@ -196,20 +196,21 @@ index 68e659d..0bdc49b 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -412,6 +420,16 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring)
- 	if (!rx_ring->rx_buf)
- 		return;
+@@ -1472,6 +1480,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
  
 +#ifdef DEV_NETMAP
 +    if (rx_ring->netdev) {
 +        int dummy, nm_irq;
 +        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
 +        if (nm_irq != NM_IRQ_PASS) {
-+            return;
++            return 1;
 +        }
 +    }
 +#endif /* DEV_NETMAP */
 +
- #ifdef HAVE_AF_XDP_ZC_SUPPORT
- 	if (rx_ring->xsk_pool) {
- 		ice_xsk_clean_rx_ring(rx_ring);
++
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index 1dffe135a..0c30b7b36 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -21,13 +21,6 @@ extern int ix_crcstrip;
  * methods should be handled by the individual drivers.
  */
 
-static inline u_int
-ice_netmap_read_hwtail(void *base, int nslots)
-{
-	struct ice_tx_desc *desc = base;
-	return le32toh(*(volatile __le32 *)&desc[nslots]);
-}
-
 int
 ice_netmap_txsync(struct netmap_kring *kring, int flags)
 {
@@ -43,7 +36,7 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 	 * interrupts on every tx packet are expensive so request
 	 * them every half ring, or where NS_REPORT is set
 	 */
-	u_int report_frequency = kring->nkr_num_slots >> 1;
+	//u_int report_frequency = kring->nkr_num_slots >> 1;
 
 	/* device-specific */
 	struct ice_netdev_priv *np = netdev_priv(ifp);
@@ -121,12 +114,13 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 			if (!(slot->flags & NS_MOREFRAG)) {
 				hw_flags |= ((u64)(ICE_TX_DESC_CMD_EOP) <<
 						ICE_TXD_QW1_CMD_S);
-				if (slot->flags & NS_REPORT || nic_i == 0 ||
-						nic_i == report_frequency) {
-					hw_flags |= ((u64)ICE_TX_DESC_CMD_RS <<
-							ICE_TXD_QW1_CMD_S);
-				}
+				//if (slot->flags & NS_REPORT || nic_i == 0 ||
+				//		nic_i == report_frequency) {
+				//	hw_flags |= ((u64)ICE_TX_DESC_CMD_RS <<
+				//			ICE_TXD_QW1_CMD_S);
+				//}
 			}
+			hw_flags |= ((u64)ICE_TX_DESC_CMD_RS << ICE_TXD_QW1_CMD_S);
 			if (slot->flags & NS_BUF_CHANGED) {
 				/* buffer has changed, reload map */
 				//netmap_reload_map(na, txr->dma.tag, txbuf->map, addr);
@@ -161,23 +155,28 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 	/*
 	 * Second part: reclaim buffers for completed transmissions.
 	 */
-	nic_i = ice_netmap_read_hwtail(txr->desc, kring->nkr_num_slots);
-	if (nic_i != txr->next_to_clean) {
-		u_int tosync;
-		nm_i = netmap_idx_n2k(kring, nic_i);
+	nic_i = txr->next_to_clean;
+	nm_i = netmap_idx_n2k(kring, nic_i);
+	for (n = 0; ; n++) {
+		struct ice_tx_desc *curr = ICE_TX_DESC(txr, nic_i);
+		struct netmap_slot *slot;
+		uint64_t paddr;
 
-		/* some tx completed, increment avail */
+		if (!(curr->cmd_type_offset_bsz &
+					cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE)))
+			break;
+		curr->buf_addr = 0;
+		curr->cmd_type_offset_bsz = 0;
+		slot = &ring->slot[nm_i];
+		(void)PNMB_O(kring, slot, &paddr);
+		netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+				&paddr, slot->len, NR_TX);
+
+		nm_i = nm_next(nm_i, lim);
+		nic_i = nm_next(nic_i, lim);
+	}
+	if (n) {
 		txr->next_to_clean = nic_i;
-		tosync = nm_next(kring->nr_hwtail, lim);
-		/* sync all buffers that we are returning to userspace */
-		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
-			struct netmap_slot *slot = &ring->slot[tosync];
-			uint64_t paddr;
-			(void)PNMB_O(kring, slot, &paddr);
-
-			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
-					&paddr, slot->len, NR_TX);
-		}
 		kring->nr_hwtail = nm_prev(nm_i, lim);
 	}
 
@@ -274,9 +273,9 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if ((staterr & (1<slot + nm_i;
-			slot->len = ((qword & ICE_RXD_QW1_LEN_PBUF_M)
-			    >> ICE_RXD_QW1_LEN_PBUF_S) - crclen;
+			slot->len = (le16_to_cpu(curr->wb.pkt_len) & ICE_RX_FLX_DESC_PKT_LEN_M) - crclen;
 
 			if (unlikely((staterr & (1<back;
 	bool was_running;
 
-	while (test_and_set_bit(ICE_CFG_BUSY, pf->state))
-			usleep_range(1000, 2000);
+	while (ice_is_reset_in_progress(pf->state)) {
+		usleep_range(1000, 2000);
+	}
 
-	if ( (was_running = netif_running(vsi->netdev)) )
+	if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
+		was_running = true;
 		ice_down(vsi);
+	}
 
 	//set_crcstrip(&adapter->hw, onoff);
 	/* enable or disable flags and callbacks in na and ifp */
@@ -383,8 +385,6 @@ ice_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 	//set_crcstrip(&adapter->hw, onoff); // XXX why twice ?
 
-	clear_bit(ICE_CFG_BUSY, pf->state);
-
 	return 0;
 }
 
@@ -432,12 +432,18 @@ ice_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
  * operate in standard mode.
  */
 static void
-ice_netmap_attach(struct ice_vsi *vsi)
+ice_netmap_attach(struct ice_pf *pf)
 {
+	struct ice_vsi *vsi;
 	struct netmap_adapter na;
 
 	bzero(&na, sizeof(na));
 
+	vsi = ice_get_main_vsi(pf);
+	if (!vsi || !vsi->netdev) {
+		nm_prerr("null %s, attach failed", vsi ? "vsi->netdev" : "vsi");
+		return;
+	}
 	na.ifp = vsi->netdev;
 	na.pdev = &vsi->back->pdev->dev;
 	na.na_flags = NAF_MOREFRAG | NAF_OFFSETS;
@@ -454,6 +460,17 @@ ice_netmap_attach(struct ice_vsi *vsi)
 	netmap_attach(&na);
 }
 
+static void
+ice_netmap_detach(struct ice_pf *pf)
+{
+	struct ice_vsi *vsi;
+
+	vsi = ice_get_main_vsi(pf);
+	if (!vsi || !vsi->netdev)
+		return;
+	netmap_detach(vsi->netdev);
+}
+
 #endif // NETMAP_ICE_LIB
 
 #ifdef NETMAP_ICE_BASE

From 1cfbdbc7b8cdc43bcbb983ff86cf3fe489fcc1ac Mon Sep 17 00:00:00 2001
From: cui fliter 
Date: Sat, 9 Jul 2022 22:08:47 +0800
Subject: [PATCH 2043/2207] fix some typos

Signed-off-by: cui fliter 
---
 SECURITY.md                 | 2 +-
 WINDOWS/README.txt          | 2 +-
 extra/python/pktman.py      | 2 +-
 sys/dev/netmap/netmap.c     | 2 +-
 sys/dev/netmap/netmap_bdg.c | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/SECURITY.md b/SECURITY.md
index acdbdfcde..2528b0ade 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,5 +1,5 @@
 Reporting a Vulnerability
 =========================
 
-Please report suspected vulnerabilities to giuseppe.lettieri@unipi.it. You will receive a response as soon as possibile.
+Please report suspected vulnerabilities to giuseppe.lettieri@unipi.it. You will receive a response as soon as possible.
 Patches will target the master branch.
diff --git a/WINDOWS/README.txt b/WINDOWS/README.txt
index 2e3d5a48f..38fbaa247 100644
--- a/WINDOWS/README.txt
+++ b/WINDOWS/README.txt
@@ -215,7 +215,7 @@ provide a similar one for the filter).
 
 To build the kernel modules we use the compiler from Visual Studio.
 
-For convenience, we have construted the "solution" file and the various
+For convenience, we have constructed the "solution" file and the various
 project files with VSC, and then manually cleaned up the .vcxprj files
 to remove the infinite copies of the same set of options generated
 by the GUI. The configurations include instructions to sign the drivers
diff --git a/extra/python/pktman.py b/extra/python/pktman.py
index daa9f2429..a7eeb57c8 100755
--- a/extra/python/pktman.py
+++ b/extra/python/pktman.py
@@ -167,7 +167,7 @@ def receive(idx, ifname, args, parser, queue):
                     choices = ['tx', 'rx'], default = 'rx')
     parser.add_argument('-b', '--batchsize', help = 'number of packets to send with each TXSYNC '
                     'operation', type=int, default = 512, dest = 'batch')
-    parser.add_argument('-l', '--length', help = 'lenght of the ethernet frame sent',
+    parser.add_argument('-l', '--length', help = 'length of the ethernet frame sent',
                     type = int, default = 60)
     parser.add_argument('-D', '--dstmac', help = 'destination MAC of tx packets',
                     default = 'ff:ff:ff:ff:ff:ff')
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index bc2566db3..276ad5f07 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2406,7 +2406,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 /* set the hardware buffer length in each one of the newly opened rings
  * (hwbuf_len field in the kring struct). The purpose it to select
- * the maximum supported input buffer lenght that will not cause writes
+ * the maximum supported input buffer length that will not cause writes
  * outside of the available space, even when offsets are in use.
  */
 static int
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 13275d8f6..a21c76bc8 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1657,7 +1657,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
  * On attach, it needs to provide a fake netmap_priv_d structure and
  * perform a netmap_do_regif() on the bwrap. This will put both the
  * bwrap and the hwna in netmap mode, with the netmap rings shared
- * and cross linked. Moroever, it will start intercepting interrupts
+ * and cross linked. Moreover, it will start intercepting interrupts
  * directed to hwna.
  */
 static int

From 1544d0d2bb10d0e2f783987419a941b8f514e24f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Jul 2022 09:50:48 +0200
Subject: [PATCH 2044/2207] linux/ice: fix typo preventing 1.8.9 to be patched
 properly

Thanks to Przemek Kitszel przemyslaw.kitszel@intel.com for
spotting this.
---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 0169b6bfe..8a9bbd74c 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -92,7 +92,7 @@ e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 18.9),@BUILDDIR@/intel-fix.sh ice,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH

From 59bb8eaba019ac409a382c1e7fb463ca5fd1093c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Jul 2022 09:54:46 +0200
Subject: [PATCH 2045/2207] linux/ice: patch for Intel 1.9.7 version

---
 LINUX/default-config.mak.in_          |   2 +-
 LINUX/final-patches/intel--ice--1.9.7 | 215 ++++++++++++++++++++++++++
 2 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ice--1.9.7

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 8a9bbd74c..786da00b2 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -92,7 +92,7 @@ e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9),@BUILDDIR@/intel-fix.sh ice,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/final-patches/intel--ice--1.9.7 b/LINUX/final-patches/intel--ice--1.9.7
new file mode 100644
index 000000000..2a6bbe0b0
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.9.7
@@ -0,0 +1,215 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index d94e327..76153d3 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -58,12 +58,12 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -75,20 +75,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ ifeq (${NEED_AUX_BUS},2)
+@@ -98,7 +98,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -131,7 +131,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index b43752e..f28e37d 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -461,6 +466,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -617,6 +626,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -889,6 +903,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *tx_ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 832e31e..71bceb6 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6336,6 +6341,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6458,7 +6467,12 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	hw = &pf->hw;
++
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+ 	 * it means that the driver went into recovery mode on load.
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index a094aec..020b7ae 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -1472,6 +1480,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
++
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;

From f495b553ce8164aa27d17759d854c367122c992b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Jul 2022 11:57:09 +0200
Subject: [PATCH 2046/2207] linux/ice: skip manpage installation to fix make
 install error

---
 LINUX/final-patches/intel--ice--1.7.16 | 11 ++++++++++-
 LINUX/final-patches/intel--ice--1.8.3  | 11 ++++++++++-
 LINUX/final-patches/intel--ice--1.8.8  | 11 ++++++++++-
 LINUX/final-patches/intel--ice--1.8.9  | 11 ++++++++++-
 LINUX/final-patches/intel--ice--1.9.7  | 11 ++++++++++-
 5 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/LINUX/final-patches/intel--ice--1.7.16 b/LINUX/final-patches/intel--ice--1.7.16
index 18cae7233..1eadbdaa9 100644
--- a/LINUX/final-patches/intel--ice--1.7.16
+++ b/LINUX/final-patches/intel--ice--1.7.16
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index a98dd4c..8b64fcc 100644
+index a98dd4c..6e6e41f 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -74,6 +74,15 @@ index a98dd4c..8b64fcc 100644
  ifneq ($(wildcard lttng),)
  	$(MAKE) -C lttng
  endif
+@@ -144,7 +144,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
 index 9f2320f..9f9126a 100644
 --- a/ice/ice_base.c
diff --git a/LINUX/final-patches/intel--ice--1.8.3 b/LINUX/final-patches/intel--ice--1.8.3
index 8435ea488..b15d1e9b5 100644
--- a/LINUX/final-patches/intel--ice--1.8.3
+++ b/LINUX/final-patches/intel--ice--1.8.3
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 789a908..cdb3394 100644
+index 789a908..3d66e39 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -81,6 +81,15 @@ index 789a908..cdb3394 100644
  ifneq ($(wildcard lttng),)
  	$(MAKE) -C lttng
  endif
+@@ -151,7 +152,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
 index adaaa84..b281b6b 100644
 --- a/ice/ice_base.c
diff --git a/LINUX/final-patches/intel--ice--1.8.8 b/LINUX/final-patches/intel--ice--1.8.8
index a23d92e45..3f70b2f3a 100644
--- a/LINUX/final-patches/intel--ice--1.8.8
+++ b/LINUX/final-patches/intel--ice--1.8.8
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 789a908..cdb3394 100644
+index 789a908..3d66e39 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -81,6 +81,15 @@ index 789a908..cdb3394 100644
  ifneq ($(wildcard lttng),)
  	$(MAKE) -C lttng
  endif
+@@ -151,7 +152,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
 index adaaa84..b281b6b 100644
 --- a/ice/ice_base.c
diff --git a/LINUX/final-patches/intel--ice--1.8.9 b/LINUX/final-patches/intel--ice--1.8.9
index 4ae6ad83e..0531da6d4 100644
--- a/LINUX/final-patches/intel--ice--1.8.9
+++ b/LINUX/final-patches/intel--ice--1.8.9
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 789a908..cdb3394 100644
+index 789a908..3d66e39 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -81,6 +81,15 @@ index 789a908..cdb3394 100644
  ifneq ($(wildcard lttng),)
  	$(MAKE) -C lttng
  endif
+@@ -151,7 +152,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
 index adaaa84..b281b6b 100644
 --- a/ice/ice_base.c
diff --git a/LINUX/final-patches/intel--ice--1.9.7 b/LINUX/final-patches/intel--ice--1.9.7
index 2a6bbe0b0..aee31d11c 100644
--- a/LINUX/final-patches/intel--ice--1.9.7
+++ b/LINUX/final-patches/intel--ice--1.9.7
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index d94e327..76153d3 100644
+index d94e327..b930d52 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -79,6 +79,15 @@ index d94e327..76153d3 100644
  ifneq ($(wildcard lttng),)
  	$(MAKE) -C lttng
  endif
+@@ -176,7 +176,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
 index b43752e..f28e37d 100644
 --- a/ice/ice_base.c

From 6546c5c732082991ea357643b6a36100e3b16885 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 13 Jul 2022 18:51:07 +0200
Subject: [PATCH 2047/2207] linux: check for extended get_ringparam

---
 LINUX/configure      | 15 ++++++++++++++-
 LINUX/netmap_linux.c | 10 +++++++++-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index e8f0f2d14..a254ba415 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1227,7 +1227,7 @@ EOF
 EOF
 
   # ethtool get_ringparam
-  add_test 'have GET_RINGPARAM' <
 	#include 
 
@@ -1237,6 +1237,19 @@ EOF
 	}
 EOF
 
+  # ethtool extended get_ringparam
+  add_test 'define HAVE_GET_RINGPARAM extended' <
+	#include 
+
+	void
+	dummy(struct net_device *net, struct ethtool_ringparam *rp,
+		struct kernel_ethtool_ringparam *ker,
+		struct netlink_ext_ack *extack) {
+	        net->ethtool_ops->get_ringparam(net, rp, ker, extack);
+	}
+EOF
+
   # ethtool set/get_channels
   add_test 'have SET_CHANNELS' <
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0f84608a5..808cfb05d 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1091,9 +1091,17 @@ nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *r
 	int error = EOPNOTSUPP;
 #ifdef NETMAP_LINUX_HAVE_GET_RINGPARAM
 	struct ethtool_ringparam rp;
+#if NETMAP_LINUX_HAVE_GET_RINGPARAM == extended
+	struct kernel_ethtool_ringparam ker;
+	struct netlink_ext_ack extack;
+#endif
 
 	if (ifp->ethtool_ops && ifp->ethtool_ops->get_ringparam) {
-		ifp->ethtool_ops->get_ringparam(ifp, &rp);
+		ifp->ethtool_ops->get_ringparam(ifp, &rp
+#if NETMAP_LINUX_HAVE_GET_RINGPARAM == extended
+				, &ker, &extack
+#endif
+				);
 		*tx = rp.tx_pending ? rp.tx_pending : rp.tx_max_pending;
 		*rx = rp.rx_pending ? rp.rx_pending : rp.rx_max_pending;
 		if (*rx < 3) {

From af75adb951aae3f95e9c9fcf71ac35e9b21766b7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 14 Jul 2022 11:17:14 +0200
Subject: [PATCH 2048/2207] linux: fix check for get_ringparam

---
 LINUX/configure      | 4 ++--
 LINUX/netmap_linux.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index a254ba415..27845b604 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1227,7 +1227,7 @@ EOF
 EOF
 
   # ethtool get_ringparam
-  add_test 'define GET_RINGPARAM old' <
 	#include 
 
@@ -1238,7 +1238,7 @@ EOF
 EOF
 
   # ethtool extended get_ringparam
-  add_test 'define HAVE_GET_RINGPARAM extended' <
 	#include 
 
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 808cfb05d..d787ebd32 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1091,14 +1091,14 @@ nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *r
 	int error = EOPNOTSUPP;
 #ifdef NETMAP_LINUX_HAVE_GET_RINGPARAM
 	struct ethtool_ringparam rp;
-#if NETMAP_LINUX_HAVE_GET_RINGPARAM == extended
+#if NETMAP_LINUX_HAVE_GET_RINGPARAM == 2
 	struct kernel_ethtool_ringparam ker;
 	struct netlink_ext_ack extack;
 #endif
 
 	if (ifp->ethtool_ops && ifp->ethtool_ops->get_ringparam) {
 		ifp->ethtool_ops->get_ringparam(ifp, &rp
-#if NETMAP_LINUX_HAVE_GET_RINGPARAM == extended
+#if NETMAP_LINUX_HAVE_GET_RINGPARAM == 2
 				, &ker, &extack
 #endif
 				);

From 75294f31aeab8733ed1cf49450985896c1a94787 Mon Sep 17 00:00:00 2001
From: Jan Grashoefer 
Date: Fri, 19 Aug 2022 23:00:16 +0200
Subject: [PATCH 2049/2207] lb/pkt_hash: Fix ip_hl check.

Due to the missing ntohs, the hash can be erroneously set to zero, which
breaks load balancing.
---
 apps/lb/pkt_hash.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index eb9704fd2..b8467be6a 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -150,7 +150,7 @@ decode_ip_n_hash(const struct ip *iph, uint8_t hash_split, uint8_t seed)
 {
 	uint32_t rc = 0;
 
-	if (iph->ip_hl < 5 || iph->ip_hl * 4 > iph->ip_len) {
+	if (iph->ip_hl < 5 || (iph->ip_hl<<2) > ntohs(iph->ip_len)) {
 		rc = 0;
 	} else if (hash_split == 2) {
 		rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),

From 335cb5aee93b9ba7b1353fead20082ecb85befcc Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 6 Sep 2022 22:08:05 +0200
Subject: [PATCH 2050/2207] netmap_update_config: update na->name to cope with
 reconfigurations

---
 sys/dev/netmap/netmap.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 276ad5f07..493dd9955 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -763,6 +763,10 @@ netmap_update_config(struct netmap_adapter *na)
 {
 	struct nm_config_info info;
 
+	if (na->ifp) {
+		strlcpy(na->name, na->ifp->if_xname, sizeof(na->name));
+	}
+
 	bzero(&info, sizeof(info));
 	if (na->nm_config == NULL ||
 	    na->nm_config(na, &info)) {

From d89953a20a90e2df228ff5031ab4a5358f1cb8bc Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 6 Sep 2022 22:57:48 +0200
Subject: [PATCH 2051/2207] netmap_rings_config_get: handle errors on getting
 tx/rx descs

There are situations where nm_os_generic_find_num_desc() may
fail so that netmap_rings_config_get() never calls
nm_os_generic_find_num_queues() to update the number of queues.
This changeset:
 - modifies netmap_rings_config_get() so that a failure of
   nm_os_generic_find_num_desc() does not prevent
   nm_os_generic_find_num_queues() to be called
 - changes netmap_find_num_desc() and its call sites so that
   the function never updates the output arguments on failure,
   and the caller always provides a sane default.

Fixes #872.
---
 LINUX/netmap_linux.c | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index d787ebd32..be2ba85bd 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1083,8 +1083,12 @@ nm_os_generic_set_features(struct netmap_generic_adapter *gna)
 }
 #endif /* WITH_GENERIC */
 
-/* Use ethtool to find the current NIC rings lengths, so that the netmap
-   rings can have the same lengths. */
+/*
+ * Use ethtool to find the current NIC rings lengths, so that the netmap
+ * rings can have the same lengths. If no ethtool command is available,
+ * or something fails, do not update the output arguments.
+ * The caller should initialize the output arguments with sane defaults.
+ */
 int
 nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx)
 {
@@ -1095,6 +1099,7 @@ nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *r
 	struct kernel_ethtool_ringparam ker;
 	struct netlink_ext_ack extack;
 #endif
+	unsigned int ntx, nrx;
 
 	if (ifp->ethtool_ops && ifp->ethtool_ops->get_ringparam) {
 		ifp->ethtool_ops->get_ringparam(ifp, &rp
@@ -1102,15 +1107,13 @@ nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *r
 				, &ker, &extack
 #endif
 				);
-		*tx = rp.tx_pending ? rp.tx_pending : rp.tx_max_pending;
-		*rx = rp.rx_pending ? rp.rx_pending : rp.rx_max_pending;
-		if (*rx < 3) {
-			nm_prerr("Invalid RX ring size %u, using default", *rx);
-			*rx = netmap_generic_ringsize;
+		ntx = rp.tx_pending ? rp.tx_pending : rp.tx_max_pending;
+		nrx = rp.rx_pending ? rp.rx_pending : rp.rx_max_pending;
+		if (nrx >= 3) {
+			*rx = nrx;
 		}
-		if (*tx < 3) {
-			nm_prerr("Invalid TX ring size %u, using default", *tx);
-			*tx = netmap_generic_ringsize;
+		if (ntx >= 3) {
+			*tx = ntx;
 		}
 		error = 0;
 	}
@@ -1156,13 +1159,17 @@ netmap_rings_config_get(struct netmap_adapter *na, struct nm_config_info *info)
 		error = ENXIO;
 		goto out;
 	}
-	error = nm_os_generic_find_num_desc(ifp, &info->num_tx_descs,
-						&info->num_rx_descs);
-	if (error)
-		goto out;
 	nm_os_generic_find_num_queues(ifp, &info->num_tx_rings,
 					&info->num_rx_rings);
 
+	/*
+	 * Start from what we already know and check for config
+	 * updates.
+	 */
+	info->num_tx_descs = na->num_tx_desc;
+	info->num_rx_descs = na->num_rx_desc;
+	nm_os_generic_find_num_desc(ifp, &info->num_tx_descs,
+					&info->num_rx_descs);
 out:
 	rtnl_unlock();
 

From 98d1b1e5a3adbc7606ba9b3ff70225834e46d25b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Sep 2022 10:57:12 +0200
Subject: [PATCH 2052/2207] linux/ice: add patch for Intel 1.9.11 version

---
 LINUX/default-config.mak.in_           |   2 +-
 LINUX/final-patches/intel--ice--1.9.11 | 222 +++++++++++++++++++++++++
 2 files changed, 223 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/intel--ice--1.9.11

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 786da00b2..d28889276 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -92,7 +92,7 @@ e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
 i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7),@BUILDDIR@/intel-fix.sh ice,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7 1.9.11),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/final-patches/intel--ice--1.9.11 b/LINUX/final-patches/intel--ice--1.9.11
new file mode 100644
index 000000000..a7f0d81a4
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.9.11
@@ -0,0 +1,222 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index d94e327..b930d52 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -58,12 +58,12 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -75,20 +75,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ ifeq (${NEED_AUX_BUS},2)
+@@ -98,7 +98,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -131,7 +131,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -176,7 +176,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index b43752e..9fe1540 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -461,6 +466,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -617,6 +626,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -889,6 +903,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *tx_ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 6aaddd0..7af2de9 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6336,6 +6341,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6458,6 +6467,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	hw = &pf->hw;
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index a094aec..020b7ae 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -30,6 +30,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -227,6 +231,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -1472,6 +1480,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
++
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
+ 	xdp.rxq = &rx_ring->xdp_rxq;

From 1537baa99eea562bb419c16aff0af10456977f21 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Sep 2022 17:20:25 +0200
Subject: [PATCH 2053/2207] linux/configure: fix typo that broke getringparam

A missing 'HAVE' in a feature macro name was causing
getringparam to default to EOPNOTSUPP.
---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 27845b604..7c2ee2559 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1227,7 +1227,7 @@ EOF
 EOF
 
   # ethtool get_ringparam
-  add_test 'define GET_RINGPARAM 1' <
 	#include 
 

From e3c97c08bdf7002af59b152d3132e0647f730b66 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 28 Sep 2022 17:56:30 +0200
Subject: [PATCH 2054/2207] linux: bump default versions for Intel drivers

---
 LINUX/default-config.mak.in_ | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index d28889276..8aaa4e33f 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -75,12 +75,12 @@ $(1)@v := $(if $($(1)@v),$($(1)@v),$(2))
 endef
 
 # set all the default versions (can be overridden by --select-version=)
-$(eval $(call default,ixgbe,5.3.8))
-$(eval $(call default,ixgbevf,4.3.2))
-$(eval $(call default,e1000e,3.4.0.2))
-$(eval $(call default,igb,5.3.5.20))
-$(eval $(call default,i40e,2.4.6))
-$(eval $(call default,ice,1.7.16))
+$(eval $(call default,ixgbe,5.15.2))
+$(eval $(call default,ixgbevf,4.15.1))
+$(eval $(call default,e1000e,3.8.7))
+$(eval $(call default,igb,5.10.2))
+$(eval $(call default,i40e,2.19.3))
+$(eval $(call default,ice,1.9.11))
 
 # some additional, driver-specific CFLAGS (used in the @build variable above) and fixes
 e1000e@cflags := -fno-pie

From d29ad38c1bbd225c587490f1bcc24346ef39554c Mon Sep 17 00:00:00 2001
From: Kim SHrier 
Date: Wed, 28 Sep 2022 10:34:43 -0600
Subject: [PATCH 2055/2207] fix ipv6h->ip6_ctlun.ip6_un1.ip6_un1_nxt usage

This member of the IPv6 header is only 1 byte and therefore should
not be byte-swapped using htons.  Using htons on this value means
that none of the cases in the switch statement will match and
the default case will always be chosen.

In addition, the correct ICMP definition for IPv6 should be
IPPROTO_ICMPV6 instead of IPPROTO_ICMP.
---
 apps/lb/pkt_hash.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index b8467be6a..a5b2e7102 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -232,7 +232,7 @@ decode_ipv6_n_hash(const struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed
 		const struct tcphdr *tcph = NULL;
 		const struct udphdr *udph = NULL;
 
-		switch(ntohs(ipv6h->ip6_ctlun.ip6_un1.ip6_un1_nxt)) {
+		switch(ipv6h->ip6_ctlun.ip6_un1.ip6_un1_nxt) {
 		case IPPROTO_TCP:
 			tcph = (const struct tcphdr *)(ipv6h + 1);
 			rc = sym_hash_fn(ntohl(saddr),
@@ -260,7 +260,7 @@ decode_ipv6_n_hash(const struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed
 		case IPPROTO_GRE:
 			rc = decode_gre_hash((const uint8_t *)(ipv6h + 1), hash_split, seed);
 			break;
-		case IPPROTO_ICMP:
+		case IPPROTO_ICMPV6:
 		case IPPROTO_ESP:
 		case IPPROTO_PIM:
 		case IPPROTO_IGMP:

From 509f3dfdb4da848df8db6c821763c745e7465893 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 3 Oct 2022 13:01:59 +0200
Subject: [PATCH 2056/2207] linux/scripts: update vers for 6.0

---
 LINUX/scripts/vers | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/LINUX/scripts/vers b/LINUX/scripts/vers
index 9afeff5df..6f9905b73 100755
--- a/LINUX/scripts/vers
+++ b/LINUX/scripts/vers
@@ -18,7 +18,9 @@ sub checkversion
 
 	if ($may < 2 || $min < 0 || $sub < 0 ||
 	   ($may == 2 && $min != 6 && !($sub >= 32 && !$sub <= 39)) ||
-           ($may == 3 && $min > 19)) {
+	   ($may == 3 && $min > 19) ||
+	   ($may == 4 && $min > 20) ||
+	   ($may == 5 && $min > 19)) {
 		die "Bad version $v";
 	}
 }
@@ -65,6 +67,12 @@ sub next
 		} else {
 			return "5.0";
 		}
+	} elsif ($may == 5) {
+		if ($min < 19) {
+			return "5." . ($min +1);
+		} else {
+			return "6.0";
+		}
 	} else {
 		return "$may." . ($min + 1);
 	}
@@ -82,6 +90,8 @@ sub prev
 			return "3.19";
 		} elsif ($may == 5) {
 			return "4.20";
+		} elsif ($may == 6) {
+			return "5.19";
 		} else {
 			die "Unknown version: $v";
 		}

From 267b1b888d7d65a8b7bb9aefdf7aea89aa620d62 Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Wed, 5 Oct 2022 21:21:52 +0000
Subject: [PATCH 2057/2207] Linux/ice: Fix build

---
 LINUX/final-patches/intel--ice--1.9.11 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/final-patches/intel--ice--1.9.11 b/LINUX/final-patches/intel--ice--1.9.11
index a7f0d81a4..8c0773924 100644
--- a/LINUX/final-patches/intel--ice--1.9.11
+++ b/LINUX/final-patches/intel--ice--1.9.11
@@ -133,7 +133,7 @@ index b43752e..9fe1540 100644
  		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+	ice_netmap_configure_tx_ring(ring);
++	ice_netmap_configure_tx_ring(tx_ring);
 +#endif /* DEV_NETMAP */
  
  	return 0;

From 3fb2f19a44de253d54fed629f459ec50f3316686 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Oct 2022 14:30:36 +0200
Subject: [PATCH 2058/2207] linux/ice: fix uninitialized variable in _reg

Fixes https://github.com/luigirizzo/netmap/issues/879
---
 LINUX/ice_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index 0c30b7b36..ed78d1213 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -362,7 +362,7 @@ ice_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct ice_netdev_priv *np = netdev_priv(ifp);
 	struct ice_vsi  *vsi = np->vsi;
 	struct ice_pf   *pf = (struct ice_pf *)vsi->back;
-	bool was_running;
+	bool was_running = false;
 
 	while (ice_is_reset_in_progress(pf->state)) {
 		usleep_range(1000, 2000);

From f9d73acbb93762a693e339ed515723cbe11c57e3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 18 Oct 2022 14:48:35 +0200
Subject: [PATCH 2059/2207] bwrap: only update hw adapters names

This fixes a regression introduced by commit 335cb5aee9, whereby
the name of the software adapter 'valeXYZ:...' may inadvertently
lose the vale prefix, making it impossibile to detach it from vale.

Fix: 882
---
 sys/dev/netmap/netmap.c      | 2 +-
 sys/dev/netmap/netmap_bdg.h  | 1 -
 sys/dev/netmap/netmap_kern.h | 1 +
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 493dd9955..a08ec720d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -763,7 +763,7 @@ netmap_update_config(struct netmap_adapter *na)
 {
 	struct nm_config_info info;
 
-	if (na->ifp) {
+	if (na->ifp && !nm_is_bwrap(na)) {
 		strlcpy(na->name, na->ifp->if_xname, sizeof(na->name));
 	}
 
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index a88eaf11b..ac8629141 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -192,7 +192,6 @@ void netmap_uninit_bridges2(struct nm_bridge *, u_int);
 int netmap_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
 	void *callback_data, void *auth_token);
 int netmap_bdg_config(struct nm_ifreq *nifr);
-int nm_is_bwrap(struct netmap_adapter *);
 
 #define NM_NEED_BWRAP (-2)
 #endif /* _NET_NETMAP_BDG_H_ */
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 4825accde..d9913369a 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1155,6 +1155,7 @@ struct netmap_bwrap_adapter {
 	struct netmap_vp_adapter *saved_na_vp;
 	int (*nm_intr_notify)(struct netmap_kring *kring, int flags);
 };
+int nm_is_bwrap(struct netmap_adapter *na);
 int nm_bdg_polling(struct nmreq_header *hdr);
 
 int netmap_bdg_attach(struct nmreq_header *hdr, void *auth_token);

From b140c84f98a97810241fe4a7038098ddc29f3f7d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 18 Oct 2022 15:22:18 +0200
Subject: [PATCH 2060/2207] linux: check for put/get_online_cpus()

---
 LINUX/bsd_glue.h |  5 +++++
 LINUX/configure  | 10 ++++++++++
 2 files changed, 15 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 70388c483..8ed518a4d 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -563,4 +563,9 @@ void netmap_bns_unregister(void);
 #define BIT_ULL(nr)	(1ULL << (nr))
 #endif /* !BIT_ULL */
 
+#ifndef NETMAP_LINUX_HAVE_ONLINE_CPUS
+#define get_online_cpus()	cpus_read_lock()
+#define put_online_cpus()	cpus_read_unlock()
+#endif /* NETMAP_LINUX_HAVE_ONLINE_CPUS */
+
 #endif /* NETMAP_BSD_GLUE_H */
diff --git a/LINUX/configure b/LINUX/configure
index 7c2ee2559..8419610d6 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1859,6 +1859,16 @@ EOF
 	}
 EOF
 
+    # put/get_online_cpus or cpu_read_lock/unlock?
+    add_test 'have ONLINE_CPUS' <
+
+	void dummy(void) {
+		get_online_cpus();
+		put_online_cpus();
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################

From 6a01145df7dbf63f7cdc7f06105cc17a1225224a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 22 Oct 2022 18:54:27 +0200
Subject: [PATCH 2061/2207] linux: check for poll_wait_fixed

---
 LINUX/configure               | 14 ++++++++++++++
 sys/dev/netmap/netmap_kloop.c |  6 +++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 8419610d6..e13870fdf 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1869,6 +1869,20 @@ EOF
 	}
 EOF
 
+   # pollwait with 5 args (as seen in uek)
+   add_test 'have POLLWAIT_5ARGS' <
+
+	void dummypoll(struct file *f,
+		wait_queue_head_t *w,
+		struct poll_table_struct *p,
+		unsigned long fixed_event);
+
+	void dummy(poll_table *pt) {
+		init_poll_funcptr(pt, dummypoll);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 8d9edd4be..ce8dbc1bd 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -472,7 +472,11 @@ struct sync_kloop_poll_ctx {
 
 static void
 sync_kloop_poll_table_queue_proc(struct file *file, wait_queue_head_t *wqh,
-				poll_table *pt)
+				poll_table *pt
+#ifdef NETMAP_LINUX_HAVE_POLLWAIT_5ARGS
+				, unsigned long unused
+#endif
+				)
 {
 	struct sync_kloop_poll_ctx *poll_ctx =
 		container_of(pt, struct sync_kloop_poll_ctx, wait_table);

From d67a604e805b67efb563ea8d5eb2d1318acf6ed8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 22 Oct 2022 16:16:49 +0200
Subject: [PATCH 2062/2207] linux/e1000,e1000e,igb: don't return partial frames

---
 LINUX/if_e1000_netmap.h  | 10 +++++++++-
 LINUX/if_e1000e_netmap.h | 11 +++++++++--
 LINUX/if_igb_netmap.h    | 10 +++++++---
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/LINUX/if_e1000_netmap.h b/LINUX/if_e1000_netmap.h
index 126a8de7e..454c76f6c 100644
--- a/LINUX/if_e1000_netmap.h
+++ b/LINUX/if_e1000_netmap.h
@@ -222,6 +222,8 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
+		u_int new_hwtail = (u_int)-1;
+
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -230,6 +232,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			uint32_t staterr = le32toh(curr->status);
 			struct netmap_slot *slot;
 			uint64_t paddr;
+			int complete = 0;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
@@ -242,15 +245,20 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			if (staterr & E1000_RXD_STAT_EOP) {
 				slot->len -= 4; /* exclude the CRC */
 				slot->flags = 0;
+				complete = 1;
 			}
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
 					&paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
+
+			if (complete)
+				new_hwtail = nm_i;
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
-			kring->nr_hwtail = nm_i;
+			if (new_hwtail != (u_int)-1)
+				kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
diff --git a/LINUX/if_e1000e_netmap.h b/LINUX/if_e1000e_netmap.h
index cfbba6729..a9a80301f 100644
--- a/LINUX/if_e1000e_netmap.h
+++ b/LINUX/if_e1000e_netmap.h
@@ -312,6 +312,7 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 */
 	if (netmap_no_pendintr || force_update) {
 		int strip_crc = (adapter->flags2 & FLAG2_CRC_STRIPPING) ? 0 : 4;
+		u_int new_hwtail = (u_int)-1;
 
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
@@ -321,21 +322,27 @@ e1000_netmap_rxsync(struct netmap_kring *kring, int flags)
 			uint32_t staterr = le32toh(curr->NM_E1R_RX_STATUS);
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			uint64_t paddr;
+			int complete;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
 			dma_rmb();  /* read descriptor after status DD */
 			PNMB_O(kring, slot, &paddr);
 			slot->len = le16toh(curr->NM_E1R_RX_LENGTH) - strip_crc;
-			slot->flags = (!(staterr & E1000_RXD_STAT_EOP) ? NS_MOREFRAG : 0);
+			complete = staterr & E1000_RXD_STAT_EOP;
+			slot->flags = complete ? NS_MOREFRAG : 0;
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr,
 					slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
+
+			if (complete)
+				new_hwtail = nm_i;
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
-			kring->nr_hwtail = nm_i;
+			if (new_hwtail != (u_int)-1)
+				kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
 	}
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index cfe6356c4..7d7099e56 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -310,8 +310,6 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
-	int complete; /* did we see a complete packet ? */
-
 	/* device-specific */
 	struct SOFTC_T *adapter = netdev_priv(ifp);
 	struct igb_ring *rxr = adapter->rx_ring[ring_nr];
@@ -328,6 +326,8 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 	 * First part: import newly received packets.
 	 */
 	if (netmap_no_pendintr || force_update) {
+		u_int new_hwtail = (u_int)-1;
+
 		nic_i = rxr->next_to_clean;
 		nm_i = netmap_idx_n2k(kring, nic_i);
 
@@ -337,6 +337,7 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			uint32_t staterr = le32toh(curr->wb.upper.status_error);
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			uint64_t paddr;
+			int complete;
 
 			if ((staterr & E1000_RXD_STAT_DD) == 0)
 				break;
@@ -348,13 +349,16 @@ igb_netmap_rxsync(struct netmap_kring *kring, int flags)
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
 			nm_i = nm_next(nm_i, lim);
 			nic_i = nm_next(nic_i, lim);
+
+			if (complete)
+				new_hwtail = nm_i;
 		}
 		if (n) { /* update the state variables */
 			rxr->next_to_clean = nic_i;
 #ifdef NETMAP_LINUX_HAVE_IGB_NTA
 			rxr->next_to_alloc = nic_i;
 #endif /* NETMAP_LINUX_HAVE_IGB_NTA */
-			if (complete)
+			if (new_hwtail != (u_int)-1)
 				kring->nr_hwtail = nm_i;
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;

From 609ab5b5fafaab41cd0968f75e83055dfc6fec46 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 27 Oct 2022 15:25:15 +0200
Subject: [PATCH 2063/2207] linux/e1000e: fix download url

---
 LINUX/default-config.mak.in_ | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 8aaa4e33f..2f81b370e 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -100,6 +100,7 @@ stmmac@conf := CONFIG_STMMAC_ETH
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 
+e1000e@fetch := test -e @SRCDIR@/ext-drivers/e1000e-$(e1000e@v).tar.gz || wget https://sourceforge.net/projects/e1000/files/e1000e%20historic%20archive/$(e1000e@v)/e1000e-$(e1000e@v).tar.gz -P @SRCDIR@/ext-drivers/
 
 define mellanox_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz || wget http://content.mellanox.com/ofed/MLNX_EN-$(2)/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz -P @SRCDIR@/ext-drivers

From 0ffc28970ec1cf90b38183f271155c032098617f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 27 Oct 2022 15:26:09 +0200
Subject: [PATCH 2064/2207] linux/intel-drivers: don't try to fix non-ext
 drivers

---
 LINUX/intel-fix.sh_ | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/intel-fix.sh_ b/LINUX/intel-fix.sh_
index 7c7d6aec8..2d13e1cf1 100755
--- a/LINUX/intel-fix.sh_
+++ b/LINUX/intel-fix.sh_
@@ -1,5 +1,7 @@
 #!/bin/sh
 
+[ -e common.mk ] || exit 0
+
 cd $1
 patch -p1 <
Date: Thu, 27 Oct 2022 17:56:49 +0200
Subject: [PATCH 2065/2207] linux: update patches for Intel drivers

---
 LINUX/final-patches/intel--i40e--2.20.12   | 173 +++++++++++++++++++++
 LINUX/final-patches/intel--i40e--2.21.12   | 173 +++++++++++++++++++++
 LINUX/final-patches/intel--ice--1.7.15     |   0
 LINUX/final-patches/intel--ice--v1.8.8     |   0
 LINUX/final-patches/intel--igb--5.11.4     | 138 ++++++++++++++++
 LINUX/final-patches/intel--igb--5.12.3     | 138 ++++++++++++++++
 LINUX/final-patches/intel--ixgbe--5.16.5   | 173 +++++++++++++++++++++
 LINUX/final-patches/intel--ixgbe--5.17.1   | 173 +++++++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.16.5 | 169 ++++++++++++++++++++
 9 files changed, 1137 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.20.12
 create mode 100644 LINUX/final-patches/intel--i40e--2.21.12
 create mode 100644 LINUX/final-patches/intel--ice--1.7.15
 create mode 100644 LINUX/final-patches/intel--ice--v1.8.8
 create mode 100644 LINUX/final-patches/intel--igb--5.11.4
 create mode 100644 LINUX/final-patches/intel--igb--5.12.3
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.16.5
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.17.1
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.16.5

diff --git a/LINUX/final-patches/intel--i40e--2.20.12 b/LINUX/final-patches/intel--i40e--2.20.12
new file mode 100644
index 000000000..87d13b430
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.20.12
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 7c87855..51480db 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ obj-m += auxiliary.o
+@@ -41,7 +41,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -95,9 +95,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 88050c6..000b0c8 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -170,6 +170,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4153,6 +4158,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4282,6 +4291,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4310,6 +4323,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15624,6 +15642,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16017,6 +16041,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 47ef1a9..ab2bd0e 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -983,6 +987,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2933,7 +2942,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--i40e--2.21.12 b/LINUX/final-patches/intel--i40e--2.21.12
new file mode 100644
index 000000000..778cd4c36
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.21.12
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 35c640f..e780da7 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 64f3d84..f90c7bf 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -161,6 +161,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4147,6 +4152,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4275,6 +4284,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4303,6 +4316,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15663,6 +15681,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16056,6 +16080,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 72471f0..2300e06 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -981,6 +985,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2947,7 +2956,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.7.15 b/LINUX/final-patches/intel--ice--1.7.15
new file mode 100644
index 000000000..e69de29bb
diff --git a/LINUX/final-patches/intel--ice--v1.8.8 b/LINUX/final-patches/intel--ice--v1.8.8
new file mode 100644
index 000000000..e69de29bb
diff --git a/LINUX/final-patches/intel--igb--5.11.4 b/LINUX/final-patches/intel--igb--5.11.4
new file mode 100644
index 000000000..c0c9eee74
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.11.4
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 3325ed6..f3195bb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index d3d5faa..89cfc64 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--igb--5.12.3 b/LINUX/final-patches/intel--igb--5.12.3
new file mode 100644
index 000000000..fbd2f2827
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.12.3
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 3325ed6..f3195bb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 5f22c8b..4eabf3a 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.16.5 b/LINUX/final-patches/intel--ixgbe--5.16.5
new file mode 100644
index 000000000..39baa92f2
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.16.5
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bd095f..5b38247 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 0450844..66d6a37 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2228,6 +2256,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4433,6 +4475,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13204,6 +13252,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13260,6 +13312,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbe--5.17.1 b/LINUX/final-patches/intel--ixgbe--5.17.1
new file mode 100644
index 000000000..3a1074caa
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.17.1
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 0bd095f..5b38247 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 977a012..8c44e44 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2229,6 +2257,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4434,6 +4476,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13227,6 +13275,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13283,6 +13335,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.16.5 b/LINUX/final-patches/intel--ixgbevf--4.16.5
new file mode 100644
index 000000000..017cef4fe
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.16.5
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 1a84106..04f4155 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 808b53a..dfbb1d2 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1383,6 +1411,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2101,6 +2139,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2335,6 +2377,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5639,8 +5685,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5681,6 +5729,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index d88e5a1..d71d355 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 16559b2c21392a32aad63cccb060e1d14d35f9a9 Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Mon, 28 Nov 2022 10:02:06 -0500
Subject: [PATCH 2066/2207] pkt-gen.c: fix ifname before cmp in source_hwaddr

In source_hwaddr(), the configured ifname is compared against all
interfaces. However, in main(), the string 'netmap:' is prepended to the
interface string if no explicit type is given. Therefore the ifname will
not match any system interface and the source MAC address is always
empty.

Check for the leading 'netmap:' string and skip past it to match against
system interfaces. Note that 'tap:' and 'pcap:' devices strip the type
string from the ifname in main() so no further work is needed.

Tested on FreeBSD 12.3.
---
 apps/pkt-gen/pkt-gen.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 129bbf7f0..dddc5baba 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -684,6 +684,10 @@ source_hwaddr(const char *ifname, char *buf)
 		return (-1);
 	}
 
+	/* remove 'netmap:' prefix before comparing interfaces */
+	if (!strncmp(ifname, "netmap:", 7))
+		ifname = &ifname[7];
+
 	for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
 		struct sockaddr_dl *sdl =
 			(struct sockaddr_dl *)ifap->ifa_addr;

From 435c666784b48145c5f988086894de0c65c0623f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 30 Nov 2022 13:39:10 +0100
Subject: [PATCH 2067/2207] linux/configure: don't unnecessarity download
 e1000e sources

---
 LINUX/default-config.mak.in_ | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 2f81b370e..e00f44af2 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -100,7 +100,9 @@ stmmac@conf := CONFIG_STMMAC_ETH
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
 $(foreach d,$(filter ixgbe ixgbevf e1000e igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
 
+ifneq ($(filter e1000e,$(E_DRIVERS)),)
 e1000e@fetch := test -e @SRCDIR@/ext-drivers/e1000e-$(e1000e@v).tar.gz || wget https://sourceforge.net/projects/e1000/files/e1000e%20historic%20archive/$(e1000e@v)/e1000e-$(e1000e@v).tar.gz -P @SRCDIR@/ext-drivers/
+endif
 
 define mellanox_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz || wget http://content.mellanox.com/ofed/MLNX_EN-$(2)/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz -P @SRCDIR@/ext-drivers

From ada4cb078a7517af7bdd4036ba5b406b3eba4581 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 3 Dec 2022 19:05:09 +0100
Subject: [PATCH 2068/2207] netmap_kern.h: remove double colon

---
 sys/dev/netmap/netmap_kern.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index d9913369a..e5be1c793 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2130,7 +2130,7 @@ struct netmap_monitor_adapter {
  * native netmap support.
  */
 int generic_netmap_attach(struct ifnet *ifp);
-int generic_rx_handler(struct ifnet *ifp, struct mbuf *m);;
+int generic_rx_handler(struct ifnet *ifp, struct mbuf *m);
 
 int nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept);
 int nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept);

From 2abc64bc68119c729c57410233a99b78593655f0 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 3 Dec 2022 19:15:19 +0100
Subject: [PATCH 2069/2207] fix minor typos

---
 sys/dev/netmap/netmap.c     | 4 ++--
 sys/dev/netmap/netmap_bdg.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index a08ec720d..27492f061 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -2410,7 +2410,7 @@ netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 
 /* set the hardware buffer length in each one of the newly opened rings
  * (hwbuf_len field in the kring struct). The purpose it to select
- * the maximum supported input buffer length that will not cause writes
+ * the maximum supported input buffer lenght that will not cause writes
  * outside of the available space, even when offsets are in use.
  */
 static int
@@ -2436,7 +2436,7 @@ netmap_compute_buf_len(struct netmap_priv_d *priv)
 		 * minus the max offset declared by the user at open time.  If
 		 * the user plans to have several slots pointing to different
 		 * offsets into the same large buffer, she must also declare a
-		 * "minium gap" between two such consecutive offsets. In this
+		 * "minimum gap" between two such consecutive offsets. In this
 		 * case the user-declared 'offset_gap' is taken as the
 		 * available space and offset_max is ignored.
 		 */
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index a21c76bc8..13275d8f6 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -1657,7 +1657,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags)
  * On attach, it needs to provide a fake netmap_priv_d structure and
  * perform a netmap_do_regif() on the bwrap. This will put both the
  * bwrap and the hwna in netmap mode, with the netmap rings shared
- * and cross linked. Moreover, it will start intercepting interrupts
+ * and cross linked. Moroever, it will start intercepting interrupts
  * directed to hwna.
  */
 static int

From 41b9e6771ca0c01c8239063e13b27ffd23ffce90 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 6 Dec 2022 19:51:20 +0100
Subject: [PATCH 2070/2207] monitor: fix cb restore when monitored adapter
 unregisters

netmap_monitor_stop() called nm_monitor_none() after the head of
the zero-copy monitors had been reset, thus thinking that there
was nothing left to do.
---
 sys/dev/netmap/netmap_monitor.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index e05313c1f..9f94bed05 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -458,6 +458,9 @@ netmap_monitor_stop(struct netmap_adapter *na)
 			struct netmap_zmon_list *z = &kring->zmon_list[t];
 			u_int j;
 
+			if (nm_monitor_none(kring))
+				continue;
+
 			for (j = 0; j < kring->n_monitors; j++) {
 				struct netmap_kring *mkring =
 					kring->monitors[j];
@@ -470,6 +473,8 @@ netmap_monitor_stop(struct netmap_adapter *na)
 				}
 				kring->monitors[j] = NULL;
 			}
+			kring->n_monitors = 0;
+			nm_monitor_dealloc(kring);
 
 			if (!nm_is_zmon(na)) {
 				/* we are the head of at most one list */
@@ -490,12 +495,7 @@ netmap_monitor_stop(struct netmap_adapter *na)
 				z->prev = NULL;
 			}
 
-			if (!nm_monitor_none(kring)) {
-
-				kring->n_monitors = 0;
-				nm_monitor_dealloc(kring);
-				nm_monitor_restore_callbacks(kring);
-			}
+			nm_monitor_restore_callbacks(kring);
 		}
 	}
 }

From bc41e928189235e3e0da9147f03eb506bf914311 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 11 Dec 2022 16:59:44 +0100
Subject: [PATCH 2071/2207] debug_put_get: don't crash on null pointers

---
 sys/dev/netmap/netmap_kern.h | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index e5be1c793..9dcf8079c 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1639,8 +1639,8 @@ void __netmap_adapter_get(struct netmap_adapter *na);
 #define netmap_adapter_get(na) 				\
 	do {						\
 		struct netmap_adapter *__na = na;	\
-		nm_prinf("getting %p:%s (%d)", __na, (__na)->name, (__na)->na_refcount);	\
 		__netmap_adapter_get(__na);		\
+		nm_prinf("getting %p:%s -> %d", __na, (__na)->name, (__na)->na_refcount);	\
 	} while (0)
 
 int __netmap_adapter_put(struct netmap_adapter *na);
@@ -1648,8 +1648,11 @@ int __netmap_adapter_put(struct netmap_adapter *na);
 #define netmap_adapter_put(na)				\
 	({						\
 		struct netmap_adapter *__na = na;	\
-		nm_prinf("putting %p:%s (%d)", __na, (__na)->name, (__na)->na_refcount);	\
-		__netmap_adapter_put(__na);		\
+		if (__na == NULL)			\
+			nm_prinf("putting NULL");	\
+		else					\
+			nm_prinf("putting %p:%s -> %d", __na, (__na)->name, (__na)->na_refcount - 1);	\
+		__netmap_adapter_put(__na);	\
 	})
 
 #else /* !NM_DEBUG_PUTGET */

From 1c42e1b73080b54460a52033cec6fcb4f1bed14c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Dec 2022 14:00:21 +0100
Subject: [PATCH 2072/2207] monitor: add missing netmap_adapter_put()

---
 sys/dev/netmap/netmap_monitor.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 9f94bed05..8e3e39e6a 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -487,6 +487,8 @@ netmap_monitor_stop(struct netmap_adapter *na)
 					/* let the monitor forget about us */
 					netmap_adapter_put(next->priv.np_na); /* nop if null */
 					next->priv.np_na = NULL;
+					/* drop the additional ref taken in netmap_monitor_add() */
+					netmap_adapter_put(zkring->zmon_list[t].prev->na);
 				}
 				/* orphan the zmon list */
 				if (z->next != NULL)

From 70ff75d569c7df2e9fa0305ffebc3aa3bda65331 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Dec 2022 17:32:50 +0100
Subject: [PATCH 2073/2207] linux/configure: add test for netif_api_add

---
 LINUX/bsd_glue.h     |  6 ++++++
 LINUX/configure      | 13 +++++++++++++
 LINUX/netmap_ptnet.c |  2 +-
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 8ed518a4d..45c3ff7b0 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -568,4 +568,10 @@ void netmap_bns_unregister(void);
 #define put_online_cpus()	cpus_read_unlock()
 #endif /* NETMAP_LINUX_HAVE_ONLINE_CPUS */
 
+#ifdef NETMAP_LINUX_HAVE_NAPI_POLL_WEIGHT
+#define NM_NETIF_NAPI_ADD	netif_napi_add_weight
+#else
+#define NM_NETIF_NAPI_ADD	netif_napi_add
+#endif /* NETMAP_LINUX_HAVE_NAPI_POLL_WEIGHT */
+
 #endif /* NETMAP_BSD_GLUE_H */
diff --git a/LINUX/configure b/LINUX/configure
index e13870fdf..bf80f2415 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1883,6 +1883,19 @@ EOF
 	}
 EOF
 
+  # netif_napi_poll_weight?
+  add_test 'have NAPI_POLL_WEIGHT' <
+
+	void dummy(struct net_device *dev,
+		struct napi_struct *napi,
+		int (*poll)(struct napi_struct *, int),
+		int weight)
+	{
+		netif_napi_add_weight(dev, napi, poll, weight);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index b752a8ab9..95a1d7322 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1390,7 +1390,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	for (i = 0; i < queue_pairs; i++) {
 		struct ptnet_rx_queue *prq = (struct ptnet_rx_queue *)
 					     pi->rxqueues[i];
-		netif_napi_add(netdev, &prq->napi, ptnet_rx_poll, NAPI_POLL_WEIGHT);
+		NM_NETIF_NAPI_ADD(netdev, &prq->napi, ptnet_rx_poll, NAPI_POLL_WEIGHT);
 	}
 
 	strlcpy(netdev->name, pci_name(pdev), sizeof(netdev->name));

From 1e902cd98d5439417fc27be4c31656c892441fb4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 12 Dec 2022 17:33:21 +0100
Subject: [PATCH 2074/2207] linux: check for FOLL_POPULATE

---
 LINUX/netmap_linux.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index be2ba85bd..e36ab2de6 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -236,6 +236,9 @@ nm_os_extmem_nr_pages(struct nm_os_extmem *e)
 struct nm_os_extmem *
 nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 {
+#ifndef FOLL_POPULATE
+#define FOLL_POPULATE 0
+#endif /* FOLL_POPULATE */
 	unsigned long end, start;
 	int nr_pages, res;
 	struct nm_os_extmem *e = NULL;

From c81004f2790ca83e35f034947649b8421a2b6d74 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 24 Dec 2022 15:58:01 +0100
Subject: [PATCH 2075/2207] drop old FreeBSD support code

---
 sys/dev/netmap/if_ptnet.c       |  9 ----
 sys/dev/netmap/netmap_freebsd.c | 24 +---------
 sys/dev/netmap/netmap_generic.c |  4 --
 sys/dev/netmap/netmap_kern.h    | 81 ---------------------------------
 4 files changed, 1 insertion(+), 117 deletions(-)

diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 99d21c38f..5a85027d7 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -93,12 +93,7 @@
 #error "INET not defined, cannot support offloadings"
 #endif
 
-#if __FreeBSD_version >= 1100000
 static uint64_t	ptnet_get_counter(if_t, ift_counter);
-#else
-typedef struct ifnet *if_t;
-#define if_getsoftc(_ifp)   (_ifp)->if_softc
-#endif
 
 //#define PTNETMAP_STATS
 //#define DEBUG
@@ -419,9 +414,7 @@ ptnet_attach(device_t dev)
 	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
 	ifp->if_init = ptnet_init;
 	ifp->if_ioctl = ptnet_ioctl;
-#if __FreeBSD_version >= 1100000
 	ifp->if_get_counter = ptnet_get_counter;
-#endif
 	ifp->if_transmit = ptnet_transmit;
 	ifp->if_qflush = ptnet_qflush;
 
@@ -1015,7 +1008,6 @@ ptnet_media_change(if_t ifp)
 	return 0;
 }
 
-#if __FreeBSD_version >= 1100000
 static uint64_t
 ptnet_get_counter(if_t ifp, ift_counter cnt)
 {
@@ -1053,7 +1045,6 @@ ptnet_get_counter(if_t ifp, ift_counter cnt)
 		return (if_get_counter_default(ifp, cnt));
 	}
 }
-#endif
 
 
 #ifdef PTNETMAP_STATS
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index de3fbaaff..b9348a01b 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -211,11 +211,7 @@ nm_os_ifnet_fini(void)
 unsigned
 nm_os_ifnet_mtu(struct ifnet *ifp)
 {
-#if __FreeBSD_version < 1100030
-	return ifp->if_data.ifi_mtu;
-#else /* __FreeBSD_version >= 1100030 */
 	return ifp->if_mtu;
-#endif
 }
 
 rawsum_t
@@ -423,26 +419,10 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	struct ifnet *ifp = a->ifp;
 	struct mbuf *m = a->m;
 
-#if __FreeBSD_version < 1100000
-	/*
-	 * Old FreeBSD versions. The mbuf has a cluster attached,
-	 * we need to copy from the cluster to the netmap buffer.
-	 */
-	if (MBUF_REFCNT(m) != 1) {
-		nm_prerr("invalid refcnt %d for %p", MBUF_REFCNT(m), m);
-		panic("in generic_xmit_frame");
-	}
-	if (m->m_ext.ext_size < len) {
-		nm_prlim(2, "size %d < len %d", m->m_ext.ext_size, len);
-		len = m->m_ext.ext_size;
-	}
-	bcopy(a->addr, m->m_data, len);
-#else  /* __FreeBSD_version >= 1100000 */
-	/* New FreeBSD versions. Link the external storage to
+	/* Link the external storage to
 	 * the netmap buffer, so that no copy is necessary. */
 	m->m_ext.ext_buf = m->m_data = a->addr;
 	m->m_ext.ext_size = len;
-#endif /* __FreeBSD_version >= 1100000 */
 
 	m->m_flags |= M_PKTHDR;
 	m->m_len = m->m_pkthdr.len = len;
@@ -460,13 +440,11 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 }
 
 
-#if __FreeBSD_version >= 1100005
 struct netmap_adapter *
 netmap_getna(if_t ifp)
 {
 	return (NA((struct ifnet *)ifp));
 }
-#endif /* __FreeBSD_version >= 1100005 */
 
 /*
  * The following two functions are empty until we have a generic
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index ec86c4dd7..7ed2db8f1 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -482,11 +482,7 @@ generic_mbuf_destructor(struct mbuf *m)
 	 * txsync. */
 	netmap_generic_irq(na, r, NULL);
 #ifdef __FreeBSD__
-#if __FreeBSD_version <= 1200050
-	void_mbuf_dtor(m, NULL, NULL);
-#else  /* __FreeBSD_version >= 1200051 */
 	void_mbuf_dtor(m);
-#endif /* __FreeBSD_version >= 1200051 */
 #endif
 }
 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 9dcf8079c..6e6561ef7 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -110,23 +110,12 @@
 #define NM_ATOMIC_TEST_AND_SET(p)       (!atomic_cmpset_acq_int((p), 0, 1))
 #define NM_ATOMIC_CLEAR(p)              atomic_store_rel_int((p), 0)
 
-#if __FreeBSD_version >= 1100030
 #define	WNA(_ifp)	(_ifp)->if_netmap
-#else /* older FreeBSD */
-#define	WNA(_ifp)	(_ifp)->if_pspare[0]
-#endif /* older FreeBSD */
 
-#if __FreeBSD_version >= 1100005
 struct netmap_adapter *netmap_getna(if_t ifp);
-#endif
 
-#if __FreeBSD_version >= 1100027
 #define MBUF_REFCNT(m)		((m)->m_ext.ext_count)
 #define SET_MBUF_REFCNT(m, x)   (m)->m_ext.ext_count = x
-#else
-#define MBUF_REFCNT(m)		((m)->m_ext.ref_cnt ? *((m)->m_ext.ref_cnt) : -1)
-#define SET_MBUF_REFCNT(m, x)   *((m)->m_ext.ref_cnt) = x
-#endif
 
 #define MBUF_QUEUED(m)		1
 
@@ -2393,69 +2382,6 @@ ptnet_sync_tail(struct nm_csb_ktoa *ktoa, struct netmap_kring *kring)
 #ifdef __FreeBSD__
 /*
  * FreeBSD mbuf allocator/deallocator in emulation mode:
- */
-#if __FreeBSD_version < 1100000
-
-/*
- * For older versions of FreeBSD:
- *
- * We allocate EXT_PACKET mbuf+clusters, but need to set M_NOFREE
- * so that the destructor, if invoked, will not free the packet.
- * In principle we should set the destructor only on demand,
- * but since there might be a race we better do it on allocation.
- * As a consequence, we also need to set the destructor or we
- * would leak buffers.
- */
-
-/* mbuf destructor, also need to change the type to EXT_EXTREF,
- * add an M_NOFREE flag, and then clear the flag and
- * chain into uma_zfree(zone_pack, mf)
- * (or reinstall the buffer ?)
- */
-#define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
-	(m)->m_ext.ext_free = (void *)fn;	\
-	(m)->m_ext.ext_type = EXT_EXTREF;	\
-} while (0)
-
-static int
-void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2)
-{
-	/* restore original mbuf */
-	m->m_ext.ext_buf = m->m_data = m->m_ext.ext_arg1;
-	m->m_ext.ext_arg1 = NULL;
-	m->m_ext.ext_type = EXT_PACKET;
-	m->m_ext.ext_free = NULL;
-	if (MBUF_REFCNT(m) == 0)
-		SET_MBUF_REFCNT(m, 1);
-	uma_zfree(zone_pack, m);
-
-	return 0;
-}
-
-static inline struct mbuf *
-nm_os_get_mbuf(struct ifnet *ifp, int len)
-{
-	struct mbuf *m;
-
-	(void)ifp;
-	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
-	if (m) {
-		/* m_getcl() (mb_ctor_mbuf) has an assert that checks that
-		 * M_NOFREE flag is not specified as third argument,
-		 * so we have to set M_NOFREE after m_getcl(). */
-		m->m_flags |= M_NOFREE;
-		m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save
-		m->m_ext.ext_free = (void *)void_mbuf_dtor;
-		m->m_ext.ext_type = EXT_EXTREF;
-		nm_prdis(5, "create m %p refcnt %d", m, MBUF_REFCNT(m));
-	}
-	return m;
-}
-
-#else /* __FreeBSD_version >= 1100000 */
-
-/*
- * Newer versions of FreeBSD, using a straightforward scheme.
  *
  * We allocate mbufs with m_gethdr(), since the mbuf header is needed
  * by the driver. We also attach a customly-provided external storage,
@@ -2468,13 +2394,7 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
  * has a KASSERT(), checking that the mbuf dtor function is not NULL.
  */
 
-#if __FreeBSD_version <= 1200050
-static void void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { }
-#else  /* __FreeBSD_version >= 1200051 */
-/* The arg1 and arg2 pointers argument were removed by r324446, which
- * in included since version 1200051. */
 static void void_mbuf_dtor(struct mbuf *m) { }
-#endif /* __FreeBSD_version >= 1200051 */
 
 #define SET_MBUF_DESTRUCTOR(m, fn)	do {		\
 	(m)->m_ext.ext_free = (fn != NULL) ?		\
@@ -2500,7 +2420,6 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
 	return m;
 }
 
-#endif /* __FreeBSD_version >= 1100000 */
 #endif /* __FreeBSD__ */
 
 struct nmreq_option * nmreq_getoption(struct nmreq_header *, uint16_t);

From 68ae0b8b003421d8968b9178841fdf3bde42f93a Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 31 Dec 2022 15:53:47 +0100
Subject: [PATCH 2076/2207] apps: fix -Wdate-time compilation issues

---
 apps/bridge/bridge.c    | 2 --
 apps/dedup/dedup-main.c | 2 --
 apps/tlem/tlem.c        | 2 --
 3 files changed, 6 deletions(-)

diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 0c8f56265..6bd8809b8 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -206,8 +206,6 @@ main(int argc, char **argv)
 	int loopback = 0;
 	int ch;
 
-	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
-
 	while ((ch = getopt(argc, argv, "hb:ci:vw:L")) != -1) {
 		switch (ch) {
 		default:
diff --git a/apps/dedup/dedup-main.c b/apps/dedup/dedup-main.c
index 1684e5459..5bfeb8e09 100644
--- a/apps/dedup/dedup-main.c
+++ b/apps/dedup/dedup-main.c
@@ -69,8 +69,6 @@ main(int argc, char **argv)
 	time_t last_hash_output = 0;
 #endif
 
-	fprintf(stderr, "%s built %s %s\n\n", argv[0], __DATE__, __TIME__);
-
 	while ((ch = getopt(argc, argv, "hci:vw:W:F:H")) != -1) {
 		switch (ch) {
 		default:
diff --git a/apps/tlem/tlem.c b/apps/tlem/tlem.c
index b9570955c..df9643b52 100644
--- a/apps/tlem/tlem.c
+++ b/apps/tlem/tlem.c
@@ -2309,8 +2309,6 @@ main(int argc, char **argv)
     *strp = '\0';
     ifname = invdopt['i']->arg;
 
-    fprintf(stderr, "%s built %s %s\n", argv[0], __DATE__, __TIME__);
-
     bzero(&bp, sizeof(bp));	/* all data initially go here */
 
     for (i = 0; i < EC_NOPTS; i++) {

From e5df9fe9f2647db3ef93449a4f6b59aa4ade4e4e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 31 Dec 2022 09:44:10 +0100
Subject: [PATCH 2077/2207] linux: fix regression in intel_fix.sh

---
 LINUX/intel-fix.sh_ | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/LINUX/intel-fix.sh_ b/LINUX/intel-fix.sh_
index 2d13e1cf1..df732c56e 100755
--- a/LINUX/intel-fix.sh_
+++ b/LINUX/intel-fix.sh_
@@ -1,8 +1,9 @@
 #!/bin/sh
 
+cd $1
+
 [ -e common.mk ] || exit 0
 
-cd $1
 patch -p1 <
Date: Sat, 31 Dec 2022 09:26:05 +0100
Subject: [PATCH 2078/2207] linux: patches for latest Intel drivers

---
 LINUX/default-config.mak.in_               |   4 +-
 LINUX/final-patches/intel--i40e--2.22.8    | 173 ++++++++++++++++
 LINUX/final-patches/intel--ice--1.10.1.2   | 221 +++++++++++++++++++++
 LINUX/final-patches/intel--ice--1.10.1.2.2 | 221 +++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.13.7     | 138 +++++++++++++
 LINUX/final-patches/intel--ixgbe--5.18.6   | 173 ++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.17.5 | 169 ++++++++++++++++
 7 files changed, 1097 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.22.8
 create mode 100644 LINUX/final-patches/intel--ice--1.10.1.2
 create mode 100644 LINUX/final-patches/intel--ice--1.10.1.2.2
 create mode 100644 LINUX/final-patches/intel--igb--5.13.7
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.18.6
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.17.5

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index e00f44af2..81e118eb3 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -91,8 +91,8 @@ igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2 5.7.2 5.8.5 5.9
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
-ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7 1.9.11),@BUILDDIR@/intel-fix.sh ice,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3 2.22.8),@BUILDDIR@/intel-fix.sh i40e,)
+ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7 1.9.11 1.10.1.2 1.10.1.2.2),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration
 stmmac@conf := CONFIG_STMMAC_ETH
diff --git a/LINUX/final-patches/intel--i40e--2.22.8 b/LINUX/final-patches/intel--i40e--2.22.8
new file mode 100644
index 000000000..295dc1584
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.22.8
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 35c640f..e780da7 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index ed4271e..1d2f26b 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -161,6 +161,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4154,6 +4159,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4282,6 +4291,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4310,6 +4323,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15711,6 +15729,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16104,6 +16128,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index d991b07..4bebbd8 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -981,6 +985,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2948,7 +2957,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.10.1.2 b/LINUX/final-patches/intel--ice--1.10.1.2
new file mode 100644
index 000000000..e3b84270e
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.10.1.2
@@ -0,0 +1,221 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index bdae0d5..5a99acb 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -69,12 +69,12 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -87,20 +87,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ 
+@@ -113,7 +113,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -147,7 +147,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -192,7 +192,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index f3cd8dc..a6c9061 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -461,6 +466,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -617,6 +626,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -889,6 +903,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *tx_ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 9df9e85..493ebc2 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6404,6 +6409,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6528,6 +6537,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	hw = &pf->hw;
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 6aa6b7a..7470c56 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -230,6 +234,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -1626,6 +1634,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--ice--1.10.1.2.2 b/LINUX/final-patches/intel--ice--1.10.1.2.2
new file mode 100644
index 000000000..5c8faaa98
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.10.1.2.2
@@ -0,0 +1,221 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index bdae0d5..5a99acb 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -69,12 +69,12 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -87,20 +87,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ 
+@@ -113,7 +113,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -147,7 +147,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -192,7 +192,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index f3cd8dc..a6c9061 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -461,6 +466,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -617,6 +626,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -889,6 +903,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *tx_ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index bc6e6fa..d2d6e32 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6404,6 +6409,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6528,6 +6537,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	hw = &pf->hw;
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 6aa6b7a..7470c56 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -230,6 +234,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -1626,6 +1634,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.13.7 b/LINUX/final-patches/intel--igb--5.13.7
new file mode 100644
index 000000000..732d346a1
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.13.7
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 3325ed6..f3195bb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 9122b5e..9aa8684 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.18.6 b/LINUX/final-patches/intel--ixgbe--5.18.6
new file mode 100644
index 000000000..f216fc089
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.18.6
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 2a2ffe2..adb10f4 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index effcc4c..c869fbe 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2229,6 +2257,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4434,6 +4476,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13242,6 +13290,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13298,6 +13350,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.17.5 b/LINUX/final-patches/intel--ixgbevf--4.17.5
new file mode 100644
index 000000000..a33db6001
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.17.5
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 27c7cfc..3036354 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 35ef9dc..a7357f6 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1383,6 +1411,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2101,6 +2139,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2335,6 +2377,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5643,8 +5689,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5685,6 +5733,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 8738cb0..27281d6 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 9d3072351f5f61f9e82e32a5bd35d1766b4ba007 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 31 Dec 2022 17:47:20 +0100
Subject: [PATCH 2079/2207] linux/configure: provide a fake Module.symvers for
 tests

---
 LINUX/configure | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/configure b/LINUX/configure
index bf80f2415..ca8f1fbf8 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2378,6 +2378,7 @@ EOF
 Now running compile tests to adapt the code to your
 kernel version. Please wait.
 EOF
+  touch Module.symvers
   run_tests
 
 # check for exported split_page

From 5e9937ec2452cd1c177d1c829d18fa2480dd9bd3 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Jan 2023 10:30:50 +0100
Subject: [PATCH 2080/2207] linux/e1000e: skip manpage install in recent Intel
 versions

This fixes installation errors when using a netmap suffix.
---
 LINUX/final-patches/intel--e1000e--3.6.0 | 20 +++++++++++++++++++-
 LINUX/final-patches/intel--e1000e--3.8.4 | 20 +++++++++++++++++++-
 LINUX/final-patches/intel--e1000e--3.8.7 | 20 +++++++++++++++++++-
 3 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/LINUX/final-patches/intel--e1000e--3.6.0 b/LINUX/final-patches/intel--e1000e--3.6.0
index f89d82778..c9fd21300 100644
--- a/LINUX/final-patches/intel--e1000e--3.6.0
+++ b/LINUX/final-patches/intel--e1000e--3.6.0
@@ -1,5 +1,5 @@
 diff --git a/e1000e/Makefile b/e1000e/Makefile
-index f300712..01c2de9 100644
+index f300712..206f69f 100644
 --- a/e1000e/Makefile
 +++ b/e1000e/Makefile
 @@ -9,9 +9,9 @@ ifneq ($(KERNELRELEASE),)
@@ -39,6 +39,24 @@ index f300712..01c2de9 100644
  
  ifeq (,$(wildcard common.mk))
    $(error Cannot find common.mk build rules)
+@@ -94,7 +94,7 @@ ccc: clean
+ 
+ # Build manfiles
+ manfile:
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	#@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
+ # Clean the module subdirectories
+ clean:
+@@ -104,7 +104,7 @@ clean:
+ # Install the modules and manpage
+ install: default manfile
+ 	@echo "Copying manpages..."
+-	@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	#@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 	@echo "Installing modules..."
+ 	@+$(call devkernelbuild,modules_install)
+ 	@echo "Running depmod..."
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
 index 081ca43..12f992c 100644
 --- a/e1000e/netdev.c
diff --git a/LINUX/final-patches/intel--e1000e--3.8.4 b/LINUX/final-patches/intel--e1000e--3.8.4
index e2595db82..a64f23bae 100644
--- a/LINUX/final-patches/intel--e1000e--3.8.4
+++ b/LINUX/final-patches/intel--e1000e--3.8.4
@@ -1,5 +1,5 @@
 diff --git a/e1000e/Makefile b/e1000e/Makefile
-index 9af58b1..00ca1e8 100644
+index 9af58b1..5a62b40 100644
 --- a/e1000e/Makefile
 +++ b/e1000e/Makefile
 @@ -9,9 +9,9 @@ ifneq ($(KERNELRELEASE),)
@@ -39,6 +39,24 @@ index 9af58b1..00ca1e8 100644
  
  ifeq (,$(wildcard common.mk))
    $(error Cannot find common.mk build rules)
+@@ -94,7 +94,7 @@ ccc: clean
+ 
+ # Build manfiles
+ manfile:
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	#@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
+ # Clean the module subdirectories
+ clean:
+@@ -104,7 +104,7 @@ clean:
+ # Install the modules and manpage
+ install: default manfile
+ 	@echo "Copying manpages..."
+-	@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	#@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 	@echo "Installing modules..."
+ 	@+$(call devkernelbuild,modules_install)
+ 	@echo "Running depmod..."
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
 index bfd9dc8..b7e91da 100644
 --- a/e1000e/netdev.c
diff --git a/LINUX/final-patches/intel--e1000e--3.8.7 b/LINUX/final-patches/intel--e1000e--3.8.7
index 3e5929ed7..536a41ca7 100644
--- a/LINUX/final-patches/intel--e1000e--3.8.7
+++ b/LINUX/final-patches/intel--e1000e--3.8.7
@@ -1,5 +1,5 @@
 diff --git a/e1000e/Makefile b/e1000e/Makefile
-index 9af58b1..00ca1e8 100644
+index 9af58b1..5a62b40 100644
 --- a/e1000e/Makefile
 +++ b/e1000e/Makefile
 @@ -9,9 +9,9 @@ ifneq ($(KERNELRELEASE),)
@@ -39,6 +39,24 @@ index 9af58b1..00ca1e8 100644
  
  ifeq (,$(wildcard common.mk))
    $(error Cannot find common.mk build rules)
+@@ -94,7 +94,7 @@ ccc: clean
+ 
+ # Build manfiles
+ manfile:
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	#@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
+ # Clean the module subdirectories
+ clean:
+@@ -104,7 +104,7 @@ clean:
+ # Install the modules and manpage
+ install: default manfile
+ 	@echo "Copying manpages..."
+-	@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	#@install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 	@echo "Installing modules..."
+ 	@+$(call devkernelbuild,modules_install)
+ 	@echo "Running depmod..."
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
 index a8eb9b7..de06d62 100644
 --- a/e1000e/netdev.c

From 439ea2dfda451ab9920334836b9b97dfab4fc353 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 24 Jan 2023 11:49:48 +0100
Subject: [PATCH 2081/2207] linux/{i40e,ice,igb,ixgbe}: make sure all
 kernel-owned ring slots are initialized

This previously relied on the initialization already performed by
the unpatched driver, which however has changed over time.
---
 LINUX/i40e_netmap_linux.h  | 2 +-
 LINUX/ice_netmap_linux.h   | 2 +-
 LINUX/if_igb_netmap.h      | 2 +-
 LINUX/ixgbe_netmap_linux.h | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 55df4cd25..9acdc106b 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -176,7 +176,7 @@ i40e_netmap_configure_rx_ring(struct i40e_ring *ring)
 	kring = na->rx_rings[ring_nr];
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
 
-	for (i = 0; i < lim; i++) {
+	for (i = 0; i <= lim; i++) {
 		int si = netmap_idx_n2k(kring, i);
 		uint64_t paddr;
 		union i40e_rx_desc *rx = I40E_RX_DESC(ring, i);
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index ed78d1213..e3d64ca1d 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -550,7 +550,7 @@ ice_netmap_configure_rx_ring(struct ice_ring *ring)
 	kring = na->rx_rings[ring_nr];
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
 
-	for (i = 0; i < lim; i++) {
+	for (i = 0; i <= lim; i++) {
 		int si = netmap_idx_n2k(kring, i);
 		uint64_t paddr;
 		union ice_32b_rx_flex_desc *rx = ICE_RX_DESC(ring, i);
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index 7d7099e56..e23ddf631 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -491,7 +491,7 @@ igb_netmap_configure_rx_ring(struct igb_ring *rxr)
 	kring = na->rx_rings[reg_idx];
 	/* preserve buffers already made available to clients */
 	n = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[reg_idx]);
-	for (i = 0; i < n; i++) {
+	for (i = 0; i <= n; i++) {
 		union e1000_adv_rx_desc *rx_desc;
 		uint64_t paddr;
 		int si = netmap_idx_n2k(kring, i);
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 14d37df28..44557e7c1 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -735,7 +735,7 @@ ixgbe_netmap_configure_rx_ring(struct NM_IXGBE_ADAPTER *adapter, int ring_nr)
 
 	lim = na->num_rx_desc - 1 - nm_kr_rxspace(na->rx_rings[ring_nr]);
 
-	for (i = 0; i < lim; i++) {
+	for (i = 0; i <= lim; i++) {
 		/*
 		 * Fill the map and set the buffer address in the NIC ring,
 		 * considering the offset between the netmap and NIC rings

From 952f4616ed2e5d337203ab47d55fc3ac41c03b42 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 24 Jan 2023 12:29:54 +0100
Subject: [PATCH 2082/2207] linux/scripts: avoid '-a' inside test

---
 LINUX/scripts/np | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 746e8bd6a..073e187ac 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -90,7 +90,7 @@ function get-params {
 
 function need {
 	eval "local v=\${$1}"
-	[ -n "$v" -a -d "$v${2:+/$2}" ] || error "Variable $1 not set or not valid"
+	[ -n "$v" ] && [ -d "$v${2:+/$2}" ] || error "Variable $1 not set or not valid"
 }
 
 ## The following environment variables must be set:
@@ -161,7 +161,7 @@ function get-patch()
 	local v2=$(scripts/vers $version -i -c)
 	local patchname=vanilla--$driver--$v1--$v2
 	local out=tmp-patches/$patchname
-	[ -n "$use_cache" -a -s $out ] && { echo $out; return; }
+	[ -n "$use_cache" ] && [ -s $out ] && { echo $out; return; }
 	local drvpath=$(driver-path $driver $version)
 	[ -n "$drvpath" ] || return
 	local drvdir=$(dirname $drvpath)
@@ -285,7 +285,7 @@ function minimize()
 	# next patch becomes the new pivot. The process
 	# is repeated until there are no more patches to consider.
 	local pivot=$1
-	[ -n "$pivot" -a -e "$pivot" ] || return 1
+	[ -n "$pivot" ] && [ -e "$pivot" ] || return 1
 	# extract the left end and right end of the pivot's range
 	local ple=$(scripts/vers $pivot -s -p -C)
 	local pre=$(scripts/vers $pivot -s -C)

From 0331ec1dba20544d3cd3b9628752a4f12d5f1d2d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 24 Jan 2023 12:32:10 +0100
Subject: [PATCH 2083/2207] LINUX/configure: fix ambiguous syntax

---
 LINUX/configure | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index ca8f1fbf8..3a0bd890b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -846,7 +846,7 @@ rm -f extdrv-versions.mak
 for dv in $(echo "$versions" | sed 's/,/ /g'); do
 	d=${dv%:*}
 	v=${dv#*:}
-	if ! $(edrv enabled $d); then
+	if ! edrv enabled $d; then
 		echo "$d is not an external driver" | warning
 	fi
 	echo "$d@v := $v" >> extdrv-versions.mak
@@ -1079,7 +1079,7 @@ EOF
   }
 
   for d in $(edrv print); do
-	if !(cdrv enabled $d); then
+	if ! cdrv enabled $d; then
             add_file_exists_check build-$d true "edrv_build_error $d"
 	fi
   done

From 78c3e219716a1a62a38390d7ae141d673ebbe911 Mon Sep 17 00:00:00 2001
From: "hari.thirusangu" 
Date: Wed, 1 Feb 2023 11:44:13 -0500
Subject: [PATCH 2084/2207] netmap support for igc nic

---
 LINUX/configure                               |   2 +-
 .../final-patches/vanilla--igc--50aa5--50aa6  |  84 ++++
 LINUX/if_igc_netmap.h                         | 452 ++++++++++++++++++
 3 files changed, 537 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/vanilla--igc--50aa5--50aa6
 create mode 100644 LINUX/if_igc_netmap.h

diff --git a/LINUX/configure b/LINUX/configure
index ca8f1fbf8..aa1a09dbe 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -113,7 +113,7 @@ subsys enable ptnetmap
 
 # available drivers
 driver_avail="stmmac r8169.c virtio_net.c forcedeth.c veth.c \
-	e1000 e1000e igb ixgbe ixgbevf ice i40e vmxnet3 mlx5"
+	e1000 e1000e igb igc ixgbe ixgbevf ice i40e vmxnet3 mlx5"
 # enabled drivers (bitfield)
 driver=
 drv()
diff --git a/LINUX/final-patches/vanilla--igc--50aa5--50aa6 b/LINUX/final-patches/vanilla--igc--50aa5--50aa6
new file mode 100644
index 000000000..0db4c99d5
--- /dev/null
+++ b/LINUX/final-patches/vanilla--igc--50aa5--50aa6
@@ -0,0 +1,84 @@
+diff --git a/igc/igc_main.c b/igc/igc_main.c
+index 1a0aae7..4d1966b 100644
+--- a/igc/igc_main.c
++++ b/igc/igc_main.c
+@@ -60,6 +60,10 @@ static const struct pci_device_id igc_pci_tbl[] = {
+ 
+ MODULE_DEVICE_TABLE(pci, igc_pci_tbl);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ enum latency_range {
+ 	lowest_latency = 0,
+ 	low_latency = 1,
+@@ -618,6 +622,9 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
+ 
+ 	txdctl |= IGC_TXDCTL_QUEUE_ENABLE;
+ 	wr32(IGC_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igc_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -1949,6 +1956,11 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
+ 	struct igc_rx_buffer *bi;
+ 	u16 bufsz;
+ 
++#ifdef DEV_NETMAP
++	if (igc_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
+@@ -2014,6 +2026,11 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
+ 	struct sk_buff *skb = rx_ring->skb;
+ 	u16 cleaned_count = igc_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_packets < budget)) {
+ 		union igc_adv_rx_desc *rx_desc;
+ 		struct igc_rx_buffer *rx_buffer;
+@@ -2118,6 +2135,11 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
+ 	if (test_bit(__IGC_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGC_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -5364,6 +5386,10 @@ static int igc_probe(struct pci_dev *pdev,
+ 	/* Check if Media Autosense is enabled */
+ 	adapter->ei = *ei;
+ 
++#ifdef DEV_NETMAP
++	igc_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* print pcie link status and MAC address */
+ 	pcie_print_link_status(pdev);
+ 	netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr);
+@@ -5429,6 +5455,11 @@ static void igc_remove(struct pci_dev *pdev)
+ 	 * would have already happened in close and is redundant.
+ 	 */
+ 	igc_release_hw_control(adapter);
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igc_clear_interrupt_scheme(adapter);
diff --git a/LINUX/if_igc_netmap.h b/LINUX/if_igc_netmap.h
new file mode 100644
index 000000000..f49dfbe42
--- /dev/null
+++ b/LINUX/if_igc_netmap.h
@@ -0,0 +1,452 @@
+/*
+ * netmap support for: igc (linux version)
+ * For details on netmap support please see ixgbe_netmap.h
+ */
+
+#ifndef _IF_IGC_NETMAP_H_
+#define _IF_IGC_NETMAP_H_
+
+#include 
+#include 
+#include 
+
+#define SOFTC_T	igc_adapter
+
+#define igc_driver_name netmap_igc_driver_name
+char netmap_igc_driver_name[] = "igc" NETMAP_LINUX_DRIVER_SUFFIX;
+
+/*
+ * Register/unregister. We are already under netmap lock.
+ * Only called on the first register or the last unregister.
+ */
+static int
+igc_netmap_reg(struct netmap_adapter *na, int onoff)
+{
+	struct ifnet *ifp = na->ifp;
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+
+	/* protect against other reinit */
+	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
+		usleep_range(1000, 2000);
+
+	if (netif_running(adapter->netdev))
+		igc_down(adapter);
+
+	/* enable or disable flags and callbacks in na and ifp */
+	if (onoff) {
+		nm_set_native_flags(na);
+	} else {
+		nm_clear_native_flags(na);
+	}
+
+	if (netif_running(adapter->netdev))
+		igc_up(adapter);
+	else
+		igc_reset(adapter); // XXX is it needed ?
+
+	clear_bit(__IGC_RESETTING, &adapter->state);
+	return (0);
+}
+
+static inline void NM_WRITE_SRRCTL(struct igc_adapter *adapter,
+	struct igc_ring *rxr, u32 srrctl)
+{
+	struct igc_hw *hw = &adapter->hw;
+	wr32(IGC_SRRCTL(rxr->reg_idx), srrctl);
+}
+
+static void
+igc_netmap_configure_srrctl(struct igc_ring *rxr)
+{
+	struct ifnet *ifp = rxr->netdev;
+	struct netmap_adapter* na = NA(ifp);
+	struct igc_adapter *adapter = netdev_priv(ifp);
+	u32 srrctl;
+
+	/* set descriptor configuration not using spilit header */
+	srrctl = ALIGN(NETMAP_BUF_SIZE(na), 1024) >> IGC_SRRCTL_BSIZEPKT_SHIFT;
+	srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF;
+	// XXX: DROP_ENABLE neither defined or enabled in the main driver
+	NM_WRITE_SRRCTL(adapter, rxr, srrctl);
+}
+
+static int
+igc_netmap_configure_rx_ring(struct igc_ring *rxr)
+{
+	struct ifnet *ifp = rxr->netdev;
+	struct netmap_adapter* na = NA(ifp);
+	int reg_idx = rxr->reg_idx;
+	struct netmap_slot* slot;
+	struct netmap_kring *kring;
+	u_int i, n;
+
+	slot = netmap_reset(na, NR_RX, reg_idx, 0);
+	if (!slot)
+		return 0;       // not in native netmap mode
+
+	igc_netmap_configure_srrctl(rxr);
+
+	kring = na->rx_rings[reg_idx];
+
+	/* preserve buffers already made available to clients */
+	n = rxr->count - 1 - nm_kr_rxspace(na->rx_rings[reg_idx]);
+	for (i = 0; i < rxr->count; i++) {
+		union igc_adv_rx_desc *rx_desc;
+		uint64_t paddr;
+		int si = netmap_idx_n2k(kring, i);
+		PNMB(na, slot + si, &paddr);
+		rx_desc = IGC_RX_DESC(rxr, i);
+		rx_desc->read.hdr_addr = 0;
+		rx_desc->read.pkt_addr = htole64(paddr);
+	}
+
+	wmb();  /* Force memory writes to complete */
+	nm_prdis("%s rxr%d.tail %d", na->name, reg_idx, i);
+	writel(n, rxr->tail);
+
+	return 1;      // success
+}
+
+static int
+igc_netmap_configure_tx_ring(struct SOFTC_T *adapter, int ring_nr)
+{
+	struct ifnet *ifp = adapter->netdev;
+	struct netmap_adapter* na = NA(ifp);
+	struct netmap_slot* slot;
+	struct igc_ring *txr = adapter->tx_ring[ring_nr];
+	int i, si;
+	void *addr;
+	uint64_t paddr;
+
+	slot = netmap_reset(na, NR_TX, ring_nr, 0);
+	if (!slot)
+		return 0;  // not in netmap native mode
+
+	for (i = 0; i < na->num_tx_desc; i++) {
+		union igc_adv_tx_desc *tx_desc;
+		si = netmap_idx_n2k(na->tx_rings[ring_nr], i);
+		addr = PNMB(na, slot + si, &paddr);
+		tx_desc = IGC_TX_DESC(txr, i);
+		tx_desc->read.buffer_addr = htole64(paddr);
+		/* actually we don't care to init the rings here */
+	}
+
+	return 1;       // success
+}
+
+/*
+ * Reconcile kernel and user view of the transmit ring.
+ */
+static int
+igc_netmap_txsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int ring_nr = kring->ring_id;
+	u_int nm_i;     /* index into the netmap ring */
+	u_int nic_i;    /* index into the NIC ring */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	/* generate an interrupt approximately every half ring */
+	u_int report_frequency = kring->nkr_num_slots >> 1, report;
+
+	/* device-specific */
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+		struct igc_ring* txr = adapter->tx_ring[ring_nr];
+
+		if (!netif_carrier_ok(ifp) || !netif_device_present(ifp)) {
+			goto out;
+		}
+
+		/*
+		 * First part: process new packets to send.
+		 */
+		nm_i = kring->nr_hwcur;
+		if (nm_i != head) {     /* we have new packets to send */
+			unsigned int total_packets = 0, total_bytes = 0;
+			nic_i = netmap_idx_k2n(kring, nm_i);
+			for (n = 0; nm_i != head; n++) {
+				struct netmap_slot *slot = &ring->slot[nm_i];
+				u_int len = slot->len;
+				uint64_t paddr;
+				__le32 cmd_type = 0;
+				uint32_t olinfo_status=0;
+				void *addr = PNMB(na, slot, &paddr);
+
+				/* device-specific */
+				union igc_adv_tx_desc *curr =
+					IGC_TX_DESC(txr, nic_i);
+				int hw_flags = IGC_ADVTXD_DTYP_DATA | IGC_ADVTXD_DCMD_DEXT |
+						IGC_ADVTXD_DCMD_IFCS;
+				u_int totlen = len;
+
+				NM_CHECK_ADDR_LEN(na, addr, len);
+
+				report = slot->flags & NS_REPORT ||
+					nic_i == 0 ||
+					nic_i == report_frequency;
+				total_packets++;
+				total_bytes += len;
+
+				if (slot->flags & NS_MOREFRAG) {
+					/* There is some duplicated code here, but
+					 * mixing everything up in the outer loop makes
+					 * things less transparent, and it also adds
+					 * unnecessary instructions in the fast path
+					 */
+					union igc_adv_tx_desc *first = curr;
+					first->read.buffer_addr = htole64(paddr);
+					first->read.cmd_type_len = htole32(len | hw_flags);
+					netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+							&paddr, len, NR_TX);
+					/* avoid setting the FCS flag in the
+					 * descriptors after the first, for safety
+					 */
+					hw_flags &= ~IGC_ADVTXD_DCMD_IFCS;
+					for (;;) {
+						nm_i = nm_next(nm_i, lim);
+						nic_i = nm_next(nic_i, lim);
+						/* remember that we have to ask for a
+						 * report each time we move past half a
+						 * ring
+						 */
+						report |= nic_i == 0 ||
+							nic_i == report_frequency;
+						if (nm_i == head) {
+							// XXX should we accept incomplete packets?
+							return EINVAL;
+						}
+						slot = &ring->slot[nm_i];
+						len = slot->len;
+						addr = PNMB(na, slot, &paddr);
+						NM_CHECK_ADDR_LEN(na, addr, len);
+						curr = IGC_TX_DESC(txr, nic_i);
+						totlen += len;
+						total_packets++;
+						total_bytes += len;
+						if (!(slot->flags & NS_MOREFRAG))
+							break;
+						curr->read.buffer_addr = htole64(paddr);
+						curr->read.olinfo_status = 0;
+						curr->read.cmd_type_len = htole32(len | hw_flags);
+						netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+								&paddr, len, NR_TX);
+					}
+					first->read.olinfo_status =
+							htole32(totlen << IGC_ADVTXD_PAYLEN_SHIFT);
+					totlen = 0;
+				}
+				/* curr now always points to the last descriptor of a packet
+				 * (which is also the first for single-slot packets)
+				 *
+				 * EOP and RS must be set only in this descriptor.
+				 */
+				hw_flags |= IGC_ADVTXD_DCMD_EOP | (report ? IGC_ADVTXD_DCMD_RS : 0);
+				slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
+
+				/* Fill the slot in the NIC ring. */
+				curr->read.buffer_addr = htole64(paddr);
+				curr->read.olinfo_status = htole32(olinfo_status | (totlen << IGC_ADVTXD_PAYLEN_SHIFT));
+				curr->read.cmd_type_len = cmd_type | htole32(len | hw_flags);
+				netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev, &paddr, len, NR_TX);
+				nm_i = nm_next(nm_i, lim);
+				nic_i = nm_next(nic_i, lim);
+			}
+		kring->nr_hwcur = head;
+
+		wmb();  /* synchronize writes to the NIC ring */
+
+		/* (re)start the tx unit up to slot nic_i (excluded) */
+		writel(nic_i, txr->tail);
+		wmb();
+		txr->tx_stats.bytes += total_bytes;
+		txr->tx_stats.packets += total_packets;
+	}
+
+	/*
+	 * Second part: reclaim buffers for completed transmissions.
+	 */
+	if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
+		u_int tosync;
+		struct igc_hw *hw = &adapter->hw;
+
+		/* record completed transmissions using TDH */
+		nic_i = rd32(IGC_TDH(txr->reg_idx));
+		if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */
+			nm_prdis("TDH wrap %d", nic_i);
+			nic_i -= kring->nkr_num_slots;
+		}
+		nm_i = netmap_idx_n2k(kring, nic_i);
+		tosync = nm_next(kring->nr_hwtail, lim);
+		/* sync all buffers that we are returning to userspace */
+		for ( ; tosync != nm_i; tosync = nm_next(tosync, lim)) {
+			struct netmap_slot *slot = &ring->slot[tosync];
+			uint64_t paddr;
+			(void)PNMB(na, slot, &paddr);
+
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
+					&paddr, slot->len, NR_TX);
+		}
+		kring->nr_hwtail = nm_prev(nm_i, lim);
+	}
+out:
+	return 0;
+}
+
+/*
+ * Reconcile kernel and user view of the receive ring.
+ */
+static int
+igc_netmap_rxsync(struct netmap_kring *kring, int flags)
+{
+	struct netmap_adapter *na = kring->na;
+	struct ifnet *ifp = na->ifp;
+	struct netmap_ring *ring = kring->ring;
+	u_int ring_nr = kring->ring_id;
+	u_int nm_i;     /* index into the netmap ring */
+	u_int nic_i;    /* index into the NIC ring */
+	u_int n;
+	u_int const lim = kring->nkr_num_slots - 1;
+	u_int const head = kring->rhead;
+	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+
+	/* device-specific */
+	struct SOFTC_T *adapter = netdev_priv(ifp);
+	struct igc_ring *rxr = adapter->rx_ring[ring_nr];
+
+	if (!netif_carrier_ok(ifp) || !netif_device_present(ifp))
+		return 0;
+
+	if (head > lim) {
+		nm_prlim(10, " rxsync lim %d head %d kring %p", lim, head, kring);
+		return netmap_ring_reinit(kring);
+	}
+
+	rmb();
+	/*
+	 * First part: import newly received packets.
+	 */
+	if (netmap_no_pendintr || force_update) {
+		unsigned int total_packets = 0, total_bytes = 0;
+		u_int new_hwtail = (u_int)-1;
+		nic_i = rxr->next_to_clean;
+		nm_i = netmap_idx_n2k(kring, nic_i);
+
+		for (n = 0; ; n++) {
+			union igc_adv_rx_desc *curr =
+				IGC_RX_DESC(rxr, nic_i);
+			uint32_t size = le16_to_cpu(curr->wb.upper.length);
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t paddr;
+			int complete;
+
+			if (!size)
+				break;
+
+			dma_rmb();
+
+			PNMB(na, slot, &paddr);
+			slot->len = size;
+			complete = igc_test_staterr(curr, IGC_RXD_STAT_EOP);
+			slot->flags = complete ? 0 : NS_MOREFRAG;
+			total_packets++;
+			total_bytes += slot->len;
+			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev, &paddr, slot->len, NR_RX);
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+
+			if (complete)
+				new_hwtail = nm_i;
+		}
+
+		if (n) { /* update the state variables */
+			rxr->next_to_clean = nic_i;
+			rxr->next_to_alloc = nic_i;
+			if (new_hwtail != (u_int)-1)
+				kring->nr_hwtail = nm_i;
+		}
+		kring->nr_kflags &= ~NKR_PENDINTR;
+		rxr->rx_stats.bytes += total_bytes;
+		rxr->rx_stats.packets += total_packets;
+	}
+
+	/*
+	 * Second part: skip past packets that userspace has released.
+	 */
+	nm_i = kring->nr_hwcur;
+	if (nm_i != head) {
+		nic_i = netmap_idx_k2n(kring, nm_i);
+		for (n = 0; nm_i != head; n++) {
+			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t paddr;
+			void *addr = PNMB(na, slot, &paddr);
+			union igc_adv_rx_desc *curr = IGC_RX_DESC(rxr, nic_i);
+
+			if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
+				goto ring_reset;
+
+			if (slot->flags & NS_BUF_CHANGED) {
+				slot->flags &= ~NS_BUF_CHANGED;
+			}
+			netmap_sync_map_dev(na, (bus_dma_tag_t) na->pdev,
+				&paddr, NETMAP_BUF_SIZE(na), NR_RX);
+			curr->read.pkt_addr = htole64(paddr);
+			curr->read.hdr_addr = 0;
+			nm_i = nm_next(nm_i, lim);
+			nic_i = nm_next(nic_i, lim);
+		}
+		kring->nr_hwcur = head;
+		wmb();
+		/*
+		 * IMPORTANT: we must leave one free slot in the ring,
+		 * so move nic_i back by one unit
+		 */
+		nic_i = nm_prev(nic_i, lim);
+		writel(nic_i, rxr->tail);
+	}
+
+	return 0;
+
+ring_reset:
+	return netmap_ring_reinit(kring);
+}
+
+static int
+igc_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	int ret = netmap_rings_config_get(na, info);
+
+	if (ret) {
+		return ret;
+	}
+
+	info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
+
+	return 0;
+}
+
+static void
+igc_netmap_attach(struct SOFTC_T *adapter)
+{
+	struct netmap_adapter na;
+
+	bzero(&na, sizeof(na));
+
+	na.ifp = adapter->netdev;
+	na.pdev = &adapter->pdev->dev;
+	na.na_flags = NAF_MOREFRAG;
+	na.num_tx_desc = adapter->tx_ring_count;
+	na.num_rx_desc = adapter->rx_ring_count;
+	na.num_tx_rings = adapter->num_tx_queues;
+	na.num_rx_rings = adapter->num_rx_queues;
+	na.rx_buf_maxsize = 1500; /* will be overwritten by config */
+	na.nm_register = igc_netmap_reg;
+	na.nm_txsync = igc_netmap_txsync;
+	na.nm_rxsync = igc_netmap_rxsync;
+	na.nm_config = igc_netmap_config;
+	netmap_attach(&na);
+}
+
+#endif // _IF_IGC_NETMAP_H_

From d6c9227aa310c95cab6160b2fb24b068fd8d36f5 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 2 Feb 2023 12:19:35 +0100
Subject: [PATCH 2085/2207] linux/igc: extend patch range

---
 .../final-patches/vanilla--igc--41400--50100  | 86 +++++++++++++++++++
 .../final-patches/vanilla--igc--50100--50600  | 83 ++++++++++++++++++
 ...0aa5--50aa6 => vanilla--igc--50600--99999} | 16 ++--
 3 files changed, 177 insertions(+), 8 deletions(-)
 create mode 100644 LINUX/final-patches/vanilla--igc--41400--50100
 create mode 100644 LINUX/final-patches/vanilla--igc--50100--50600
 rename LINUX/final-patches/{vanilla--igc--50aa5--50aa6 => vanilla--igc--50600--99999} (80%)

diff --git a/LINUX/final-patches/vanilla--igc--41400--50100 b/LINUX/final-patches/vanilla--igc--41400--50100
new file mode 100644
index 000000000..ec876c0a6
--- /dev/null
+++ b/LINUX/final-patches/vanilla--igc--41400--50100
@@ -0,0 +1,86 @@
+diff --git a/igc/igc_main.c b/igc/igc_main.c
+index 9d85707e8a81..45868726cc24 100644
+--- a/igc/igc_main.c
++++ b/igc/igc_main.c
+@@ -58,6 +58,12 @@ static void igc_irq_enable(struct igc_adapter *adapter);
+ static void igc_configure_msix(struct igc_adapter *adapter);
+ static bool igc_alloc_mapped_page(struct igc_ring *rx_ring,
+ 				  struct igc_rx_buffer *bi);
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++static void igc_up(struct igc_adapter *adapter);
++static void igc_down(struct igc_adapter *adapter);
++static void igc_reset(struct igc_adapter *adapter);
++#include 
++#endif
+ 
+ enum latency_range {
+ 	lowest_latency = 0,
+@@ -596,6 +602,9 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
+ 
+ 	txdctl |= IGC_TXDCTL_QUEUE_ENABLE;
+ 	wr32(IGC_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igc_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -1333,6 +1342,11 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
+ 	struct igc_rx_buffer *bi;
+ 	u16 bufsz;
+ 
++#ifdef DEV_NETMAP
++	if (igc_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
+@@ -1398,6 +1412,11 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
+ 	struct sk_buff *skb = rx_ring->skb;
+ 	u16 cleaned_count = igc_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_packets < budget)) {
+ 		union igc_adv_rx_desc *rx_desc;
+ 		struct igc_rx_buffer *rx_buffer;
+@@ -1548,6 +1567,11 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
+ 	if (test_bit(__IGC_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGC_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -3687,6 +3711,10 @@ static int igc_probe(struct pci_dev *pdev,
+ 	/* Check if Media Autosense is enabled */
+ 	adapter->ei = *ei;
+ 
++#ifdef DEV_NETMAP
++	igc_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* print pcie link status and MAC address */
+ 	pcie_print_link_status(pdev);
+ 	netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr);
+@@ -3738,6 +3766,11 @@ static void igc_remove(struct pci_dev *pdev)
+ 	 * would have already happened in close and is redundant.
+ 	 */
+ 	igc_release_hw_control(adapter);
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igc_clear_interrupt_scheme(adapter);
diff --git a/LINUX/final-patches/vanilla--igc--50100--50600 b/LINUX/final-patches/vanilla--igc--50100--50600
new file mode 100644
index 000000000..b5a474873
--- /dev/null
+++ b/LINUX/final-patches/vanilla--igc--50100--50600
@@ -0,0 +1,83 @@
+diff --git a/igc/igc_main.c b/igc/igc_main.c
+index 87a11879bf2d..8da49a957b29 100644
+--- a/igc/igc_main.c
++++ b/igc/igc_main.c
+@@ -60,6 +60,9 @@ static void igc_irq_enable(struct igc_adapter *adapter);
+ static void igc_configure_msix(struct igc_adapter *adapter);
+ static bool igc_alloc_mapped_page(struct igc_ring *rx_ring,
+ 				  struct igc_rx_buffer *bi);
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
+ 
+ enum latency_range {
+ 	lowest_latency = 0,
+@@ -598,6 +601,9 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
+ 
+ 	txdctl |= IGC_TXDCTL_QUEUE_ENABLE;
+ 	wr32(IGC_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igc_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -1335,6 +1341,11 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
+ 	struct igc_rx_buffer *bi;
+ 	u16 bufsz;
+ 
++#ifdef DEV_NETMAP
++	if (igc_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
+@@ -1400,6 +1411,11 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
+ 	struct sk_buff *skb = rx_ring->skb;
+ 	u16 cleaned_count = igc_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	while (likely(total_packets < budget)) {
+ 		union igc_adv_rx_desc *rx_desc;
+ 		struct igc_rx_buffer *rx_buffer;
+@@ -1550,6 +1566,11 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
+ 	if (test_bit(__IGC_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++		return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGC_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -3723,6 +3744,10 @@ static int igc_probe(struct pci_dev *pdev,
+ 	/* Check if Media Autosense is enabled */
+ 	adapter->ei = *ei;
+ 
++#ifdef DEV_NETMAP
++	igc_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* print pcie link status and MAC address */
+ 	pcie_print_link_status(pdev);
+ 	netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr);
+@@ -3774,6 +3799,11 @@ static void igc_remove(struct pci_dev *pdev)
+ 	 * would have already happened in close and is redundant.
+ 	 */
+ 	igc_release_hw_control(adapter);
++
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igc_clear_interrupt_scheme(adapter);
diff --git a/LINUX/final-patches/vanilla--igc--50aa5--50aa6 b/LINUX/final-patches/vanilla--igc--50600--99999
similarity index 80%
rename from LINUX/final-patches/vanilla--igc--50aa5--50aa6
rename to LINUX/final-patches/vanilla--igc--50600--99999
index 0db4c99d5..077201a89 100644
--- a/LINUX/final-patches/vanilla--igc--50aa5--50aa6
+++ b/LINUX/final-patches/vanilla--igc--50600--99999
@@ -1,8 +1,8 @@
 diff --git a/igc/igc_main.c b/igc/igc_main.c
-index 1a0aae7..4d1966b 100644
+index d9d5425fe8d9..7d9f5b80f28b 100644
 --- a/igc/igc_main.c
 +++ b/igc/igc_main.c
-@@ -60,6 +60,10 @@ static const struct pci_device_id igc_pci_tbl[] = {
+@@ -52,6 +52,10 @@ static const struct pci_device_id igc_pci_tbl[] = {
  
  MODULE_DEVICE_TABLE(pci, igc_pci_tbl);
  
@@ -13,7 +13,7 @@ index 1a0aae7..4d1966b 100644
  enum latency_range {
  	lowest_latency = 0,
  	low_latency = 1,
-@@ -618,6 +622,9 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
+@@ -612,6 +616,9 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
  
  	txdctl |= IGC_TXDCTL_QUEUE_ENABLE;
  	wr32(IGC_TXDCTL(reg_idx), txdctl);
@@ -23,7 +23,7 @@ index 1a0aae7..4d1966b 100644
  }
  
  /**
-@@ -1949,6 +1956,11 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
+@@ -1801,6 +1808,11 @@ static void igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
  	struct igc_rx_buffer *bi;
  	u16 bufsz;
  
@@ -35,7 +35,7 @@ index 1a0aae7..4d1966b 100644
  	/* nothing to do */
  	if (!cleaned_count)
  		return;
-@@ -2014,6 +2026,11 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
+@@ -1866,6 +1878,11 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
  	struct sk_buff *skb = rx_ring->skb;
  	u16 cleaned_count = igc_desc_unused(rx_ring);
  
@@ -47,7 +47,7 @@ index 1a0aae7..4d1966b 100644
  	while (likely(total_packets < budget)) {
  		union igc_adv_rx_desc *rx_desc;
  		struct igc_rx_buffer *rx_buffer;
-@@ -2118,6 +2135,11 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
+@@ -1970,6 +1987,11 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
  	if (test_bit(__IGC_DOWN, &adapter->state))
  		return true;
  
@@ -59,7 +59,7 @@ index 1a0aae7..4d1966b 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IGC_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -5364,6 +5386,10 @@ static int igc_probe(struct pci_dev *pdev,
+@@ -4788,6 +4810,10 @@ static int igc_probe(struct pci_dev *pdev,
  	/* Check if Media Autosense is enabled */
  	adapter->ei = *ei;
  
@@ -70,7 +70,7 @@ index 1a0aae7..4d1966b 100644
  	/* print pcie link status and MAC address */
  	pcie_print_link_status(pdev);
  	netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr);
-@@ -5429,6 +5455,11 @@ static void igc_remove(struct pci_dev *pdev)
+@@ -4840,6 +4866,11 @@ static void igc_remove(struct pci_dev *pdev)
  	 * would have already happened in close and is redundant.
  	 */
  	igc_release_hw_control(adapter);

From e9138ee8ec18eb793989620cb25dec3d6881ac8a Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Thu, 2 Mar 2023 19:26:56 -0500
Subject: [PATCH 2086/2207] pkt-gen: init all slots of every tx ring

sender_body() uses OPT_COPY to copy the frame into the destination slot
for the first 100,000 packets. Then it removes OPT_COPY to improve
performance. The function always starts with the first tx ring.

If multiple tx rings are in use, it is possible that the initial 100k
packets will only use the first ring. After OPT_COPY is removed, there
may come a time when the first ring is full and sender_body() will move
to the next ring which was never initialized. As a result it will send
all zero packets. (This was discovered when the receiving NIC reported
rx errors.)

Before any transmissions, step through every tx ring and set
NS_BUF_CHANGED on every slot. That will force send_packets() to
initialize the slot when first used. Since it only copies when
necessary, it performs better than always setting OPT_COPY. With this
change, there is no reason for the "drop copy" code.
---
 apps/pkt-gen/pkt-gen.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index dddc5baba..31e78aaf6 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1602,7 +1602,7 @@ sender_body(void *data)
 	uint64_t n = targ->g->npackets / targ->g->nthreads;
 	uint64_t sent = 0;
 	uint64_t event = 0;
-	int options = targ->g->options | OPT_COPY;
+	int options = targ->g->options;
 	struct timespec nexttime = { 0, 0}; // XXX silence compiler
 	int rate_limit = targ->g->tx_rate;
 	struct pkt *pkt = &targ->pkt;
@@ -1676,6 +1676,19 @@ sender_body(void *data)
 			targ->frags++;
 	}
 	D("frags %u frag_size %u", targ->frags, targ->frag_size);
+
+	/* mark all slots of all rings as changed so initial copy will be done */
+	for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
+		uint32_t j;
+		struct netmap_slot *slot;
+
+		txring = NETMAP_TXRING(nifp, i);
+		for (j = 0; j < txring->num_slots; j++) {
+			slot = &txring->slot[j];
+			slot->flags = NS_BUF_CHANGED;
+		}
+	}
+
 	while (!targ->cancel && (n == 0 || sent < n)) {
 		int rv;
 
@@ -1712,10 +1725,6 @@ sender_body(void *data)
 		/*
 		 * scan our queues and send on those with room
 		 */
-		if (options & OPT_COPY && sent > 100000 && !(targ->g->options & OPT_COPY) ) {
-			D("drop copy");
-			options &= ~OPT_COPY;
-		}
 		for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) {
 			int m;
 			uint64_t limit = rate_limit ?  tosend : targ->g->burst;

From f228e0c042e73544ef7059b6c9e00fe4d12b90ce Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 4 Mar 2023 15:39:16 +0100
Subject: [PATCH 2087/2207] pkt-gen: import changes from FreeBSD

---
 apps/pkt-gen/pkt-gen.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index dddc5baba..b06fef055 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1306,7 +1306,7 @@ ping_body(void *data)
 	struct targ *targ = (struct targ *) data;
 	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
 	struct netmap_if *nifp = targ->nmd->nifp;
-	int i, m, rx = 0;
+	int i, m;
 	void *frame;
 	int size;
 	struct timespec ts, now, last_print;
@@ -1399,7 +1399,9 @@ ping_body(void *data)
 		}
 #endif /* BUSYWAIT */
 		/* see what we got back */
-		rx = 0;
+#ifdef BUSYWAIT
+		int rx = 0;
+#endif
 		for (i = targ->nmd->first_rx_ring;
 			i <= targ->nmd->last_rx_ring; i++) {
 			ring = NETMAP_RXRING(nifp, i);
@@ -1434,7 +1436,9 @@ ping_body(void *data)
 				buckets[pos]++;
 				/* now store it in a bucket */
 				ring->head = ring->cur = nm_ring_next(ring, ring->head);
+#ifdef BUSYWAIT
 				rx++;
+#endif
 			}
 		}
 		//D("tx %d rx %d", sent, rx);
@@ -1502,7 +1506,7 @@ pong_body(void *data)
 	struct pollfd pfd = { .fd = targ->fd, .events = POLLIN };
 	struct netmap_if *nifp = targ->nmd->nifp;
 	struct netmap_ring *txring, *rxring;
-	int i, rx = 0;
+	int i;
 	uint64_t sent = 0, n = targ->g->npackets;
 
 	if (targ->g->nthreads > 1) {
@@ -1544,7 +1548,6 @@ pong_body(void *data)
 				src = NETMAP_BUF(rxring, slot->buf_idx);
 				//D("got pkt %p of size %d", src, slot->len);
 				rxring->head = rxring->cur = nm_ring_next(rxring, head);
-				rx++;
 				if (txavail == 0)
 					continue;
 				dst = NETMAP_BUF(txring,
@@ -1579,7 +1582,6 @@ pong_body(void *data)
 #ifdef BUSYWAIT
 		ioctl(pfd.fd, NIOCTXSYNC, NULL);
 #endif
-		//D("tx %d rx %d", sent, rx);
 	}
 
 	targ->completed = 1;
@@ -1837,6 +1839,7 @@ receiver_body(void *data)
 	struct netmap_ring *rxring;
 	int i;
 	struct my_ctrs cur;
+	uint64_t n = targ->g->npackets / targ->g->nthreads;
 
 	memset(&cur, 0, sizeof(cur));
 
@@ -1864,7 +1867,7 @@ receiver_body(void *data)
 	/* main loop, exit after 1s silence */
 	clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic);
     if (targ->g->dev_type == DEV_TAP) {
-	while (!targ->cancel) {
+	while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) {
 		char buf[MAX_BODYSIZE];
 		/* XXX should we poll ? */
 		i = read(targ->g->main_fd, buf, sizeof(buf));
@@ -1876,7 +1879,7 @@ receiver_body(void *data)
 	}
 #ifndef NO_PCAP
     } else if (targ->g->dev_type == DEV_PCAP) {
-	while (!targ->cancel) {
+	while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) {
 		/* XXX should we poll ? */
 		pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap,
 			(u_char *)&targ->ctr);
@@ -1887,7 +1890,7 @@ receiver_body(void *data)
 	int dump = targ->g->options & OPT_DUMP;
 
 	nifp = targ->nmd->nifp;
-	while (!targ->cancel) {
+	while (!targ->cancel && (n == 0 || targ->ctr.pkts < n)) {
 		/* Once we started to receive packets, wait at most 1 seconds
 		   before quitting. */
 #ifdef BUSYWAIT
@@ -2812,7 +2815,7 @@ tap_alloc(char *dev)
 
 	/* try to create the device */
 	if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
-		D("failed to to a TUNSETIFF: %s", strerror(errno));
+		D("failed to do a TUNSETIFF: %s", strerror(errno));
 		close(fd);
 		return err;
 	}
@@ -3204,17 +3207,17 @@ main(int arc, char **argv)
 		struct netmap_if *nifp = g.nmd->nifp;
 		struct nmreq_register *req = &g.nmd->reg;
 
-		D("nifp at offset %"PRIu64", %d tx %d rx region %d",
+		D("nifp at offset %"PRIu64" ntxqs %d nrxqs %d memid %d",
 		    req->nr_offset, req->nr_tx_rings, req->nr_rx_rings,
 		    req->nr_mem_id);
 		for (i = 0; i < req->nr_tx_rings + req->nr_host_tx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_TXRING(nifp, i);
-			D("   TX%d at %p slots %d", i,
+			D("   TX%d at offset %p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
 		}
 		for (i = 0; i < req->nr_rx_rings + req->nr_host_rx_rings; i++) {
 			struct netmap_ring *ring = NETMAP_RXRING(nifp, i);
-			D("   RX%d at %p slots %d", i,
+			D("   RX%d at offset %p slots %d", i,
 			    (void *)((char *)ring - (char *)nifp), ring->num_slots);
 		}
 	}

From d51bbf6cf8efc18455e6ca7de8b2f19ca349562d Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 4 Mar 2023 16:10:04 +0100
Subject: [PATCH 2088/2207] import changes from FreeeBSD:

 - use if_inc_counter() for emulated mode; defined as a NOP on
   Linux for the time being
 - NAF_OFFSETS support for if_vtnet
 - minor changes to if_re
 - use NM_ACCESS_ONCE() in prologues
 - set IFCAP_NETMAP in if_capenable for emulated adapter
 - fix multiple compiler warnings
 - fix multiple typos
---
 LINUX/bsd_glue.h                 |  2 ++
 sys/dev/netmap/if_ptnet.c        |  5 ++---
 sys/dev/netmap/if_re_netmap.h    |  3 +--
 sys/dev/netmap/if_vtnet_netmap.h | 17 ++++++++++-------
 sys/dev/netmap/netmap.c          | 12 +++++++-----
 sys/dev/netmap/netmap_freebsd.c  | 10 ++++++----
 sys/dev/netmap/netmap_generic.c  |  6 ++++--
 sys/dev/netmap/netmap_kern.h     |  2 +-
 sys/dev/netmap/netmap_kloop.c    | 10 +++++++++-
 sys/net/netmap.h                 |  2 +-
 10 files changed, 43 insertions(+), 26 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 45c3ff7b0..eb30d6cef 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -345,6 +345,8 @@ struct netmap_linux_magic {
 #define ifnet           	net_device      /* remap */
 #define	if_xname		name		/* field ifnet-> net_device */
 
+#define	if_inc_counter(ifp, flags, cnt) 	do {} while (0)
+
 /* some other FreeBSD APIs */
 struct net_device* ifunit_ref(const char *name);
 void if_ref(struct net_device *ifp);
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 5a85027d7..be75da2db 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -244,9 +244,8 @@ static driver_t ptnet_driver = {
 };
 
 /* We use (SI_ORDER_MIDDLE+2) here, see DEV_MODULE_ORDERED() invocation. */
-static devclass_t ptnet_devclass;
-DRIVER_MODULE_ORDERED(ptnet, pci, ptnet_driver, ptnet_devclass,
-		      NULL, NULL, SI_ORDER_MIDDLE + 2);
+DRIVER_MODULE_ORDERED(ptnet, pci, ptnet_driver, NULL, NULL,
+		      SI_ORDER_MIDDLE + 2);
 
 static int
 ptnet_probe(device_t dev)
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index 0e56a731a..7c356ab4b 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -176,7 +176,6 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 	struct netmap_ring *ring = kring->ring;
 	u_int nm_i;	/* index into the netmap ring */
 	u_int nic_i;	/* index into the NIC ring */
-	u_int n;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int const head = kring->rhead;
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
@@ -236,7 +235,7 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 	nm_i = kring->nr_hwcur;
 	if (nm_i != head) {
 		nic_i = netmap_idx_k2n(kring, nm_i);
-		for (n = 0; nm_i != head; n++) {
+		while (nm_i != head) {
 			struct netmap_slot *slot = &ring->slot[nm_i];
 			uint64_t paddr;
 			void *addr = PNMB(na, slot, &paddr);
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index a05781255..8bff697b3 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -84,12 +84,13 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 		for (; nm_i != head; nm_i = nm_next(nm_i, lim)) {
 			/* we use an empty header here */
 			struct netmap_slot *slot = &ring->slot[nm_i];
+			uint64_t offset = nm_get_offset(kring, slot);
 			u_int len = slot->len;
 			uint64_t paddr;
-			void *addr = PNMB(na, slot, &paddr);
 			int err;
 
-			NM_CHECK_ADDR_LEN(na, addr, len);
+			(void)PNMB(na, slot, &paddr);
+			NM_CHECK_ADDR_LEN_OFF(na, len, offset);
 
 			slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
 			/* Initialize the scatterlist, expose it to the hypervisor,
@@ -97,7 +98,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 			 */
 			sglist_reset(sg); // cheap
 			err = sglist_append(sg, &txq->vtntx_shrhdr, sc->vtnet_hdr_size);
-			err |= sglist_append_phys(sg, paddr, len);
+			err |= sglist_append_phys(sg, paddr + offset, len);
 			KASSERT(err == 0, ("%s: cannot append to sglist %d",
 						__func__, err));
 			err = virtqueue_enqueue(vq, /*cookie=*/txq, sg,
@@ -171,19 +172,21 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 	for (nm_i = rxq->vtnrx_nm_refill; num > 0;
 	    nm_i = nm_next(nm_i, lim), num--) {
 		struct netmap_slot *slot = &ring->slot[nm_i];
+		uint64_t offset = nm_get_offset(kring, slot);
 		uint64_t paddr;
 		void *addr = PNMB(na, slot, &paddr);
 		int err;
 
 		if (addr == NETMAP_BUF_BASE(na)) { /* bad buf */
-			if (netmap_ring_reinit(kring))
-				return EFAULT;
+			netmap_ring_reinit(kring);
+			return EFAULT;
 		}
 
 		slot->flags &= ~NS_BUF_CHANGED;
 		sglist_reset(&sg);
 		err = sglist_append(&sg, &rxq->vtnrx_shrhdr, sc->vtnet_hdr_size);
-		err |= sglist_append_phys(&sg, paddr, NETMAP_BUF_SIZE(na));
+		err |= sglist_append_phys(&sg, paddr + offset,
+		    NETMAP_BUF_SIZE(na) - offset);
 		KASSERT(err == 0, ("%s: cannot append to sglist %d",
 					__func__, err));
 		/* writable for the host */
@@ -432,7 +435,7 @@ vtnet_netmap_attach(struct vtnet_softc *sc)
 	bzero(&na, sizeof(na));
 
 	na.ifp = sc->vtnet_ifp;
-	na.na_flags = 0;
+	na.na_flags = NAF_OFFSETS;
 	na.num_tx_desc = vtnet_netmap_tx_slots(sc);
 	na.num_rx_desc = vtnet_netmap_rx_slots(sc);
 	na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 27492f061..4c4f61c5b 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1712,8 +1712,8 @@ netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp)
 u_int
 nm_txsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 {
-	u_int head = ring->head; /* read only once */
-	u_int cur = ring->cur; /* read only once */
+	u_int head = NM_ACCESS_ONCE(ring->head);
+	u_int cur = NM_ACCESS_ONCE(ring->cur);
 	u_int n = kring->nkr_num_slots;
 
 	nm_prdis(5, "%s kcur %d ktail %d head %d cur %d tail %d",
@@ -1790,8 +1790,8 @@ nm_rxsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
 	 * - cur could in principle go back, however it does not matter
 	 *   because we are processing a brand new rxsync()
 	 */
-	cur = kring->rcur = ring->cur;	/* read only once */
-	head = kring->rhead = ring->head;	/* read only once */
+	cur = kring->rcur = NM_ACCESS_ONCE(ring->cur);
+	head = kring->rhead = NM_ACCESS_ONCE(ring->head);
 #if 1 /* kernel sanity checks */
 	NM_FAIL_ON(kring->nr_hwcur >= n || kring->nr_hwtail >= n);
 #endif /* kernel sanity checks */
@@ -4337,8 +4337,10 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m)
 	mbq_unlock(q);
 
 done:
-	if (m)
+	if (m) {
+		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
 		m_freem(m);
+	}
 	/* unconditionally wake up listeners */
 	kring->nm_notify(kring, 0);
 	/* this is normally netmap_notify(), but for nics
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index b9348a01b..8c480f2fb 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -351,6 +351,8 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 			ret = EBUSY; /* already set */
 			goto out;
 		}
+
+		ifp->if_capenable |= IFCAP_NETMAP;
 		gna->save_if_input = ifp->if_input;
 		ifp->if_input = freebsd_generic_rx_handler;
 	} else {
@@ -360,6 +362,8 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 			ret = EINVAL;  /* not saved */
 			goto out;
 		}
+
+		ifp->if_capenable &= ~IFCAP_NETMAP;
 		ifp->if_input = gna->save_if_input;
 		gna->save_if_input = NULL;
 	}
@@ -616,7 +620,6 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 		return ENOMEM;
 	}
 	if_initname(ifp, name, IF_DUNIT_NONE);
-	ifp->if_mtu = 65536;
 	ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_init = (void *)nm_vi_dummy;
 	ifp->if_ioctl = nm_vi_dummy;
@@ -799,9 +802,8 @@ static driver_t ptn_memdev_driver = {
 
 /* We use (SI_ORDER_MIDDLE+1) here, see DEV_MODULE_ORDERED() invocation
  * below. */
-static devclass_t ptnetmap_devclass;
-DRIVER_MODULE_ORDERED(ptn_memdev, pci, ptn_memdev_driver, ptnetmap_devclass,
-		      NULL, NULL, SI_ORDER_MIDDLE + 1);
+DRIVER_MODULE_ORDERED(ptn_memdev, pci, ptn_memdev_driver, NULL, NULL,
+		      SI_ORDER_MIDDLE + 1);
 
 /*
  * Map host netmap memory through PCI-BAR in the guest OS,
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 7ed2db8f1..fb23d2d35 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -776,7 +776,7 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 			nm_os_generic_xmit_frame(&a);
 		}
 		/* Update hwcur to the next slot to transmit. Here nm_i
-		 * is not necessarily head, as we could break early. */
+		 * is not necessarily head, we could break early. */
 		kring->nr_hwcur = nm_i;
 
 #ifdef __FreeBSD__
@@ -838,8 +838,10 @@ generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
 		 * support RX scatter-gather. */
 		nm_prlim(2, "Warning: driver pushed up big packet "
 				"(size=%d)", (int)MBUF_LEN(m));
+		if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
 		m_freem(m);
-	} else if (unlikely(mbq_len(&kring->rx_queue) > 1024)) {
+	} else if (unlikely(mbq_len(&kring->rx_queue) > na->num_rx_desc)) {
+		if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
 		m_freem(m);
 	} else {
 		mbq_safe_enqueue(&kring->rx_queue, m);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 6e6561ef7..eb708f5a5 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -2145,7 +2145,7 @@ struct nm_os_gen_arg {
 	void *head, *tail; /* tailq, if the OS-specific routine needs to build one */
 	void *addr;	/* payload of current packet */
 	u_int len;	/* packet length */
-	u_int ring_nr;	/* packet length */
+	u_int ring_nr;	/* transmit ring index */
 	u_int qevent;   /* in txqdisc mode, place an event on this mbuf */
 };
 
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index ce8dbc1bd..67483a35e 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -164,7 +164,9 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 	struct nm_csb_atok *csb_atok = a->csb_atok;
 	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
+#ifdef SYNC_KLOOP_POLL
 	bool more_txspace = false;
+#endif /* SYNC_KLOOP_POLL */
 	uint32_t num_slots;
 	int batch;
 
@@ -239,7 +241,9 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (kring->rtail != kring->nr_hwtail) {
 			/* Some more room available in the parent adapter. */
 			kring->rtail = kring->nr_hwtail;
+#ifdef SYNC_KLOOP_POLL
 			more_txspace = true;
+#endif /* SYNC_KLOOP_POLL */
 		}
 
 		if (unlikely(netmap_debug & NM_DEBUG_TXSYNC)) {
@@ -317,7 +321,9 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 	struct nm_csb_ktoa *csb_ktoa = a->csb_ktoa;
 	struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */
 	int dry_cycles = 0;
+#ifdef SYNC_KLOOP_POLL
 	bool some_recvd = false;
+#endif /* SYNC_KLOOP_POLL */
 	uint32_t num_slots;
 
 	if (unlikely(nm_kr_tryget(kring, 1, NULL))) {
@@ -371,7 +377,9 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		sync_kloop_kernel_write(csb_ktoa, kring->nr_hwcur, hwtail);
 		if (kring->rtail != hwtail) {
 			kring->rtail = hwtail;
+#ifdef SYNC_KLOOP_POLL
 			some_recvd = true;
+#endif /* SYNC_KLOOP_POLL */
 			dry_cycles = 0;
 		} else {
 			dry_cycles++;
@@ -830,7 +838,7 @@ netmap_sync_kloop(struct netmap_priv_d *priv, struct nmreq_header *hdr)
 			 * so that if a notification on ring Y comes after
 			 * we have processed ring Y, but before we call
 			 * schedule(), we don't miss it. This is true because
-			 * the wake up function will change the the task state,
+			 * the wake up function will change the task state,
 			 * and therefore the schedule_timeout() call below
 			 * will observe the change).
 			 */
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 6561174e0..74150f608 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -783,7 +783,7 @@ struct nmreq_pools_info {
  */
 struct nmreq_sync_kloop_start {
 	/* Sleeping is the default synchronization method for the kloop.
-	 * The 'sleep_us' field specifies how many microsconds to sleep for
+	 * The 'sleep_us' field specifies how many microseconds to sleep for
 	 * when there is no work to do, before doing another kloop iteration.
 	 */
 	uint32_t	sleep_us;

From dec90696358bc96878d790ec1aeb4b5e206d52be Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 6 Mar 2023 17:35:14 +0100
Subject: [PATCH 2089/2207] import refactoring of ifnet from FreeBSD

---
 LINUX/bsd_glue.h                 | 14 +++--
 LINUX/i40e_netmap_linux.h        |  2 +-
 LINUX/ice_netmap_linux.h         |  2 +-
 WINDOWS/netmap_windows.c         |  2 +-
 WINDOWS/win_glue.h               |  6 ++-
 sys/dev/netmap/if_ptnet.c        | 86 +++++++++++++++---------------
 sys/dev/netmap/if_re_netmap.h    | 14 ++---
 sys/dev/netmap/if_vtnet_netmap.h | 22 ++++----
 sys/dev/netmap/netmap.c          | 44 ++++++++--------
 sys/dev/netmap/netmap_bdg.c      |  4 +-
 sys/dev/netmap/netmap_bdg.h      |  2 +-
 sys/dev/netmap/netmap_freebsd.c  | 90 ++++++++++++++++----------------
 sys/dev/netmap/netmap_generic.c  | 16 +++---
 sys/dev/netmap/netmap_kern.h     | 81 ++++++++++++++--------------
 sys/dev/netmap/netmap_kloop.c    |  2 +-
 sys/dev/netmap/netmap_legacy.c   |  4 +-
 sys/dev/netmap/netmap_mem2.c     | 14 ++---
 sys/dev/netmap/netmap_mem2.h     |  4 +-
 sys/dev/netmap/netmap_monitor.c  |  2 +-
 sys/dev/netmap/netmap_pipe.c     |  2 +-
 sys/dev/netmap/netmap_vale.c     | 14 ++---
 21 files changed, 215 insertions(+), 212 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index eb30d6cef..002c0edc9 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -298,7 +298,11 @@ struct thread;
  * in linux we have no spares so we overload ax25_ptr, and the detection
  * for netmap-capable is some magic in the area pointed by that.
  */
-#define WNA(_ifp)		(_ifp)->ax25_ptr
+#define if_setnetmapadapter(_ifp, _na)	do { 				\
+	(_ifp)->ax25_ptr = _na;						\
+} while (0)
+#define if_getnetmapadapter(_ifp)	((struct netmap_adapter *)(_ifp)->ax25_ptr)
+
 /* use the default NM_ATTACH_NA/NM_DETACH_NA defined in netmap_kernel.h */
 #else /* !NETMAP_LINUX_HAVE_AX25PTR */
 /*
@@ -315,7 +319,10 @@ struct netmap_linux_magic {
 	const struct ethtool_ops *save_eto;
 };
 #define NM_OS_MAGIC	struct netmap_linux_magic
-#define WNA(ifp)	(ifp->ethtool_ops)
+#define if_setnetmapadapter(_ifp, _na) do {				\
+	(_ifp)->ethtool_ops = _na;					\
+} while (0)
+#define if_getnetmapadapter(_ifp)	((struct netmap_adapter *)(_ifp)->ethtool_ops)
 #define NM_DETACH_NA(ifp)  do {						\
 	(ifp)->ethtool_ops = NA(ifp)->magic.save_eto;			\
 } while (0)
@@ -343,7 +350,8 @@ struct netmap_linux_magic {
 #endif /* NETAP_LINUX_HAVE_AX25PTR */
 
 #define ifnet           	net_device      /* remap */
-#define	if_xname		name		/* field ifnet-> net_device */
+typedef struct net_device* 	if_t;	/* remap */
+#define if_name(ifp)		ifp->name
 
 #define	if_inc_counter(ifp, flags, cnt) 	do {} while (0)
 
diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 9acdc106b..9ccd7d53c 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -589,7 +589,7 @@ i40e_netmap_rxsync(struct netmap_kring *kring, int flags)
 			rxr->next_to_clean = nic_i;
 			if (likely(ntail <= lim)) {
 				kring->nr_hwtail = ntail;
-				nm_prdis("%s: nic_i %u nm_i %u ntail %u n %u", ifp->if_xname, nic_i, nm_i, ntail, n);
+				nm_prdis("%s: nic_i %u nm_i %u ntail %u n %u", if_name(ifp), nic_i, nm_i, ntail, n);
 			}
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index e3d64ca1d..9d1bf3f61 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -294,7 +294,7 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 			rxr->next_to_clean = nic_i;
 			if (likely(ntail <= lim)) {
 				kring->nr_hwtail = ntail;
-				nm_prdis("%s: nic_i %u nm_i %u ntail %u n %u", ifp->if_xname, nic_i, nm_i, ntail, n);
+				nm_prdis("%s: nic_i %u nm_i %u ntail %u n %u", if_name(ifp), nic_i, nm_i, ntail, n);
 			}
 		}
 		kring->nr_kflags &= ~NKR_PENDINTR;
diff --git a/WINDOWS/netmap_windows.c b/WINDOWS/netmap_windows.c
index a68da4493..7570a02fc 100644
--- a/WINDOWS/netmap_windows.c
+++ b/WINDOWS/netmap_windows.c
@@ -626,7 +626,7 @@ ifunit_ref(const char* name)
 
     win32_init_lookaside_buffers(ifp);
 
-    RtlCopyMemory(ifp->if_xname, name, IFNAMSIZ);
+    RtlCopyMemory(if_name(ifp), name, IFNAMSIZ);
     ifp->ifIndex = deviceIfIndex;
 
 	win32_init_lookaside_buffers(ifp);
diff --git a/WINDOWS/win_glue.h b/WINDOWS/win_glue.h
index 987c2112b..44f61c184 100644
--- a/WINDOWS/win_glue.h
+++ b/WINDOWS/win_glue.h
@@ -267,7 +267,7 @@ static int time_uptime_w32()
 struct netmap_adapter;
 
 struct net_device {
-	char	if_xname[IFNAMSIZ];			// external name (name + unit)
+	char	name[IFNAMSIZ];			// external name (name + unit)
 	//        struct ifaltq if_snd;         /* output queue (includes altq) */
 	struct netmap_adapter	*na;
 	void	*pfilter;
@@ -365,7 +365,9 @@ void if_ref(struct net_device *ifp);
 
 PVOID send_up_to_stack(struct ifnet *ifp, struct mbuf *m, PVOID head);
 
-#define WNA(_ifp)		_ifp->na
+#define if_setnetmapadapter(_ifp, _na) do {				\
+	(_ifp)->na = _na;							\
+} while (0)
 #define NM_BNS_GET(b)	do { (void)(b); } while (0)
 #define NM_BNS_PUT(b)   do { (void)(b); } while (0)
 
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index be75da2db..5b3332ee5 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -408,14 +408,14 @@ ptnet_attach(device_t dev)
 	}
 
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
-	ifp->if_baudrate = IF_Gbps(10);
-	ifp->if_softc = sc;
-	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
-	ifp->if_init = ptnet_init;
-	ifp->if_ioctl = ptnet_ioctl;
-	ifp->if_get_counter = ptnet_get_counter;
-	ifp->if_transmit = ptnet_transmit;
-	ifp->if_qflush = ptnet_qflush;
+	if_setbaudrate(ifp, IF_Gbps(10));
+	if_setsoftc(ifp, sc);
+	if_setflags(ifp, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX);
+	if_setinitfn(ifp, ptnet_init);
+	if_setioctlfn(ifp, ptnet_ioctl);
+	if_setget_counter(ifp, ptnet_get_counter);
+	if_settransmitfn(ifp, ptnet_transmit);
+	if_setqflushfn(ifp, ptnet_qflush);
 
 	ifmedia_init(&sc->media, IFM_IMASK, ptnet_media_change,
 		     ptnet_media_status);
@@ -433,25 +433,25 @@ ptnet_attach(device_t dev)
 
 	ether_ifattach(ifp, sc->hwaddr);
 
-	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
-	ifp->if_capabilities |= IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU;
+	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
+	if_setcapabilitiesbit(ifp, IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU, 0);
 
 	if (sc->ptfeatures & PTNETMAP_F_VNET_HDR) {
 		/* Similarly to what the vtnet driver does, we can emulate
 		 * VLAN offloadings by inserting and removing the 802.1Q
 		 * header during transmit and receive. We are then able
 		 * to do checksum offloading of VLAN frames. */
-		ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6
+		if_setcapabilitiesbit(ifp, IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6
 					| IFCAP_VLAN_HWCSUM
 					| IFCAP_TSO | IFCAP_LRO
 					| IFCAP_VLAN_HWTSO
-					| IFCAP_VLAN_HWTAGGING;
+					| IFCAP_VLAN_HWTAGGING, 0);
 	}
 
-	ifp->if_capenable = ifp->if_capabilities;
+	if_setcapenable(ifp, if_getcapabilities(ifp));
 #ifdef DEVICE_POLLING
 	/* Don't enable polling by default. */
-	ifp->if_capabilities |= IFCAP_POLLING;
+	if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0);
 #endif
 	snprintf(sc->lock_name, sizeof(sc->lock_name),
 		 "%s", device_get_nameunit(dev));
@@ -517,7 +517,7 @@ ptnet_detach(device_t dev)
 	ptnet_device_shutdown(sc);
 
 #ifdef DEVICE_POLLING
-	if (sc->ifp->if_capenable & IFCAP_POLLING) {
+	if (if_getcapenable(sc->ifp) & IFCAP_POLLING) {
 		ether_poll_deregister(sc->ifp);
 	}
 #endif
@@ -761,9 +761,9 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 
 	switch (cmd) {
 	case SIOCSIFFLAGS:
-		device_printf(dev, "SIOCSIFFLAGS %x\n", ifp->if_flags);
+		device_printf(dev, "SIOCSIFFLAGS %x\n", if_getflags(ifp));
 		PTNET_CORE_LOCK(sc);
-		if (ifp->if_flags & IFF_UP) {
+		if (if_getflags(ifp) & IFF_UP) {
 			/* Network stack wants the iff to be up. */
 			err = ptnet_init_locked(sc);
 		} else {
@@ -777,8 +777,8 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 
 	case SIOCSIFCAP:
 		device_printf(dev, "SIOCSIFCAP %x %x\n",
-			      ifr->ifr_reqcap, ifp->if_capenable);
-		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+			      ifr->ifr_reqcap, if_getcapenable(ifp));
+		mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
 #ifdef DEVICE_POLLING
 		if (mask & IFCAP_POLLING) {
 			struct ptnet_queue *pq;
@@ -790,7 +790,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 					break;
 				}
 				/* Stop queues and sync with taskqueues. */
-				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+				if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
 				for (i = 0; i < sc->num_rings; i++) {
 					pq = sc-> queues + i;
 					/* Make sure the worker sees the
@@ -804,7 +804,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 								&pq->task);
 					}
 				}
-				ifp->if_drv_flags |= IFF_DRV_RUNNING;
+				if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
 			} else {
 				err = ether_poll_deregister(ifp);
 				for (i = 0; i < sc->num_rings; i++) {
@@ -816,7 +816,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 			}
 		}
 #endif  /* DEVICE_POLLING */
-		ifp->if_capenable = ifr->ifr_reqcap;
+		if_setcapenable(ifp, ifr->ifr_reqcap);
 		break;
 
 	case SIOCSIFMTU:
@@ -826,7 +826,7 @@ ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data)
 			err = EINVAL;
 		} else {
 			PTNET_CORE_LOCK(sc);
-			ifp->if_mtu = ifr->ifr_mtu;
+			if_setmtu(ifp, ifr->ifr_mtu);
 			PTNET_CORE_UNLOCK(sc);
 		}
 		break;
@@ -853,22 +853,22 @@ ptnet_init_locked(struct ptnet_softc *sc)
 	unsigned int nm_buf_size;
 	int ret;
 
-	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
 		return 0; /* nothing to do */
 	}
 
 	device_printf(sc->dev, "%s\n", __func__);
 
 	/* Translate offload capabilities according to if_capenable. */
-	ifp->if_hwassist = 0;
-	if (ifp->if_capenable & IFCAP_TXCSUM)
-		ifp->if_hwassist |= PTNET_CSUM_OFFLOAD;
-	if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
-		ifp->if_hwassist |= PTNET_CSUM_OFFLOAD_IPV6;
-	if (ifp->if_capenable & IFCAP_TSO4)
-		ifp->if_hwassist |= CSUM_IP_TSO;
-	if (ifp->if_capenable & IFCAP_TSO6)
-		ifp->if_hwassist |= CSUM_IP6_TSO;
+	if_sethwassist(ifp, 0);
+	if (if_getcapenable(ifp) & IFCAP_TXCSUM)
+		if_sethwassistbits(ifp, PTNET_CSUM_OFFLOAD, 0);
+	if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
+		if_sethwassistbits(ifp, PTNET_CSUM_OFFLOAD_IPV6, 0);
+	if (if_getcapenable(ifp) & IFCAP_TSO4)
+		if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
+	if (if_getcapenable(ifp) & IFCAP_TSO6)
+		if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
 
 	/*
 	 * Prepare the interface for netmap mode access.
@@ -919,7 +919,7 @@ ptnet_init_locked(struct ptnet_softc *sc)
 	callout_reset(&sc->tick, hz, ptnet_tick, sc);
 #endif
 
-	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
 
 	return 0;
 
@@ -946,14 +946,14 @@ ptnet_stop(struct ptnet_softc *sc)
 
 	device_printf(sc->dev, "%s\n", __func__);
 
-	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
 		return 0; /* nothing to do */
 	}
 
 	/* Clear the driver-ready flag, and synchronize with all the queues,
 	 * so that after this loop we are sure nobody is working anymore with
 	 * the device. This scheme is taken from the vtnet driver. */
-	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
 	callout_stop(&sc->tick);
 	for (i = 0; i < sc->num_rings; i++) {
 		PTNET_Q_LOCK(sc->queues + i);
@@ -1198,7 +1198,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
 				pq = sc->queues + i;
 				pq->ktoa->kern_need_kick = 1;
 				pq->atok->appl_need_kick =
-					(!(ifp->if_capenable & IFCAP_POLLING)
+					(!(if_getcapenable(ifp) & IFCAP_POLLING)
 						&& i >= sc->num_tx_rings);
 			}
 
@@ -1407,7 +1407,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
 		return 0;
 	}
 
-	if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
+	if (unlikely(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) {
 		PTNET_Q_UNLOCK(pq);
 		nm_prlim(1, "Interface is down");
 		return ENETDOWN;
@@ -1609,7 +1609,7 @@ ptnet_transmit(if_t ifp, struct mbuf *m)
 		return err;
 	}
 
-	if (ifp->if_capenable & IFCAP_POLLING) {
+	if (if_getcapenable(ifp) & IFCAP_POLLING) {
 		/* If polling is on, the transmit queues will be
 		 * drained by the poller. */
 		return 0;
@@ -1693,7 +1693,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 
 	PTNET_Q_LOCK(pq);
 
-	if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
+	if (unlikely(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) {
 		goto unlock;
 	}
 
@@ -1837,7 +1837,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 		mhead->m_pkthdr.flowid = pq->kring_id;
 		M_HASHTYPE_SET(mhead, M_HASHTYPE_OPAQUE);
 
-		if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+		if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
 			struct ether_header *eh;
 
 			eh = mtod(mhead, struct ether_header *);
@@ -1874,7 +1874,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 			pq->stats.bytes += mhead->m_pkthdr.len;
 
 			PTNET_Q_UNLOCK(pq);
-			(*ifp->if_input)(ifp, mhead);
+			if_input(ifp, mhead);
 			PTNET_Q_LOCK(pq);
 			/* The ring->head index (and related indices) are
 			 * updated under pq lock by ptnet_ring_update().
@@ -1883,7 +1883,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
 			 * ring from there. */
 			head = ring->head;
 
-			if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
+			if (unlikely(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) {
 				/* The interface has gone down while we didn't
 				 * have the lock. Stop any processing and exit. */
 				goto unlock;
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index 7c356ab4b..d658a3e5c 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -47,8 +47,8 @@
 static int
 re_netmap_reg(struct netmap_adapter *na, int onoff)
 {
-	struct ifnet *ifp = na->ifp;
-	struct rl_softc *adapter = ifp->if_softc;
+	if_t ifp = na->ifp;
+	struct rl_softc *adapter = if_getsoftc(ifp);
 
 	RL_LOCK(adapter);
 	re_stop(adapter); /* also clears IFF_DRV_RUNNING */
@@ -59,7 +59,7 @@ re_netmap_reg(struct netmap_adapter *na, int onoff)
 	}
 	re_init_locked(adapter);	/* also enables intr */
 	RL_UNLOCK(adapter);
-	return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1);
+	return (if_getdrvflags(ifp) & IFF_DRV_RUNNING ? 0 : 1);
 }
 
 
@@ -70,7 +70,7 @@ static int
 re_netmap_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int nm_i;	/* index into the netmap ring */
 	u_int nic_i;	/* index into the NIC ring */
@@ -79,7 +79,7 @@ re_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int const head = kring->rhead;
 
 	/* device-specific */
-	struct rl_softc *sc = ifp->if_softc;
+	struct rl_softc *sc = if_getsoftc(ifp);
 	struct rl_txdesc *txd = sc->rl_ldata.rl_tx_desc;
 
 	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
@@ -172,7 +172,7 @@ static int
 re_netmap_rxsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int nm_i;	/* index into the netmap ring */
 	u_int nic_i;	/* index into the NIC ring */
@@ -181,7 +181,7 @@ re_netmap_rxsync(struct netmap_kring *kring, int flags)
 	int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
 
 	/* device-specific */
-	struct rl_softc *sc = ifp->if_softc;
+	struct rl_softc *sc = if_getsoftc(ifp);
 	struct rl_rxdesc *rxd = sc->rl_ldata.rl_rx_desc;
 
 	if (head > lim)
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index 8bff697b3..fc18976ee 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -37,15 +37,15 @@
 static int
 vtnet_netmap_reg(struct netmap_adapter *na, int state)
 {
-	struct ifnet *ifp = na->ifp;
-	struct vtnet_softc *sc = ifp->if_softc;
+	if_t ifp = na->ifp;
+	struct vtnet_softc *sc = if_getsoftc(ifp);
 
 	/*
 	 * Trigger a device reinit, asking vtnet_init_locked() to
 	 * also enter or exit netmap mode.
 	 */
 	VTNET_CORE_LOCK(sc);
-	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
 	vtnet_init_locked(sc, state ? VTNET_INIT_NETMAP_ENTER
 	    : VTNET_INIT_NETMAP_EXIT);
 	VTNET_CORE_UNLOCK(sc);
@@ -59,7 +59,7 @@ static int
 vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int nm_i;	/* index into the netmap ring */
@@ -67,7 +67,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags)
 	u_int const head = kring->rhead;
 
 	/* device-specific */
-	struct vtnet_softc *sc = ifp->if_softc;
+	struct vtnet_softc *sc = if_getsoftc(ifp);
 	struct vtnet_txq *txq = &sc->vtnet_txqs[ring_nr];
 	struct virtqueue *vq = txq->vtntx_vq;
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
@@ -154,14 +154,14 @@ static int
 vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num)
 {
 	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int const lim = kring->nkr_num_slots - 1;
 	u_int nm_i;
 
 	/* device-specific */
-	struct vtnet_softc *sc = ifp->if_softc;
+	struct vtnet_softc *sc = if_getsoftc(ifp);
 	struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr];
 	struct virtqueue *vq = rxq->vtnrx_vq;
 
@@ -245,7 +245,7 @@ static int
 vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int ring_nr = kring->ring_id;
 	u_int nm_i;	/* index into the netmap ring */
@@ -256,7 +256,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 	int interrupts = !(kring->nr_kflags & NKR_NOINTR);
 
 	/* device-specific */
-	struct vtnet_softc *sc = ifp->if_softc;
+	struct vtnet_softc *sc = if_getsoftc(ifp);
 	struct vtnet_rxq *rxq = &sc->vtnet_rxqs[ring_nr];
 	struct virtqueue *vq = rxq->vtnrx_vq;
 
@@ -349,7 +349,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int flags)
 static void
 vtnet_netmap_intr(struct netmap_adapter *na, int state)
 {
-	struct vtnet_softc *sc = na->ifp->if_softc;
+	struct vtnet_softc *sc = if_getsoftc(na->ifp);
 	int i;
 
 	for (i = 0; i < sc->vtnet_max_vq_pairs; i++) {
@@ -416,7 +416,7 @@ vtnet_netmap_rx_slots(struct vtnet_softc *sc)
 static int
 vtnet_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
-	struct vtnet_softc *sc = na->ifp->if_softc;
+	struct vtnet_softc *sc = if_getsoftc(na->ifp);
 
 	info->num_tx_rings = sc->vtnet_act_vq_pairs;
 	info->num_rx_rings = sc->vtnet_act_vq_pairs;
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 4c4f61c5b..e6c9a41f9 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -637,7 +637,7 @@ netmap_set_all_rings(struct netmap_adapter *na, int stopped)
  * onload).
  */
 void
-netmap_disable_all_rings(struct ifnet *ifp)
+netmap_disable_all_rings(if_t ifp)
 {
 	if (NM_NA_VALID(ifp)) {
 		netmap_set_all_rings(NA(ifp), NM_KR_LOCKED);
@@ -650,7 +650,7 @@ netmap_disable_all_rings(struct ifnet *ifp)
  * napi_enable().
  */
 void
-netmap_enable_all_rings(struct ifnet *ifp)
+netmap_enable_all_rings(if_t ifp)
 {
 	if (NM_NA_VALID(ifp)) {
 		netmap_set_all_rings(NA(ifp), 0 /* enabled */);
@@ -658,7 +658,7 @@ netmap_enable_all_rings(struct ifnet *ifp)
 }
 
 void
-netmap_make_zombie(struct ifnet *ifp)
+netmap_make_zombie(if_t ifp)
 {
 	if (NM_NA_VALID(ifp)) {
 		struct netmap_adapter *na = NA(ifp);
@@ -669,7 +669,7 @@ netmap_make_zombie(struct ifnet *ifp)
 }
 
 void
-netmap_undo_zombie(struct ifnet *ifp)
+netmap_undo_zombie(if_t ifp)
 {
 	if (NM_NA_VALID(ifp)) {
 		struct netmap_adapter *na = NA(ifp);
@@ -764,7 +764,7 @@ netmap_update_config(struct netmap_adapter *na)
 	struct nm_config_info info;
 
 	if (na->ifp && !nm_is_bwrap(na)) {
-		strlcpy(na->name, na->ifp->if_xname, sizeof(na->name));
+		strlcpy(na->name, if_name(na->ifp), sizeof(na->name));
 	}
 
 	bzero(&info, sizeof(info));
@@ -1196,7 +1196,7 @@ netmap_dtor(void *data)
  * After this call the queue is empty.
  */
 static void
-netmap_send_up(struct ifnet *dst, struct mbq *q)
+netmap_send_up(if_t dst, struct mbq *q)
 {
 	struct mbuf *m;
 	struct mbuf *head = NULL, *prev = NULL;
@@ -1467,7 +1467,7 @@ netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
  */
 static void netmap_hw_dtor(struct netmap_adapter *); /* needed by NM_IS_NATIVE() */
 int
-netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adapter **na)
+netmap_get_hw_na(if_t ifp, struct netmap_mem_d *nmd, struct netmap_adapter **na)
 {
 	/* generic support */
 	int i = netmap_admode;	/* Take a snapshot. */
@@ -1557,7 +1557,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_mem_d *nmd, struct netmap_adap
  */
 int
 netmap_get_na(struct nmreq_header *hdr,
-	      struct netmap_adapter **na, struct ifnet **ifp,
+	      struct netmap_adapter **na, if_t *ifp,
 	      struct netmap_mem_d *nmd, int create)
 {
 	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
@@ -1673,7 +1673,7 @@ netmap_get_na(struct nmreq_header *hdr,
 
 /* undo netmap_get_na() */
 void
-netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp)
+netmap_unget_na(struct netmap_adapter *na, if_t ifp)
 {
 	if (ifp)
 		if_rele(ifp);
@@ -2258,12 +2258,12 @@ netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
 			nm_prerr("error: large MTU (%d) needed "
 				 "but %s does not support "
 				 "NS_MOREFRAG", mtu,
-				 na->ifp->if_xname);
+				 if_name(na->ifp));
 			return EINVAL;
 		} else if (nbs < na->rx_buf_maxsize) {
 			nm_prerr("error: using NS_MOREFRAG on "
 				 "%s requires netmap buf size "
-				 ">= %u", na->ifp->if_xname,
+				 ">= %u", if_name(na->ifp),
 				 na->rx_buf_maxsize);
 			return EINVAL;
 		} else {
@@ -2271,7 +2271,7 @@ netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
 				 "%s needs to support "
 				 "NS_MOREFRAG "
 				 "(MTU=%u,netmap_buf_size=%u)",
-				 na->ifp->if_xname, mtu, nbs);
+				 if_name(na->ifp), mtu, nbs);
 		}
 	}
 	return 0;
@@ -2752,7 +2752,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	struct mbq q;	/* packets from RX hw queues to host stack */
 	struct netmap_adapter *na = NULL;
 	struct netmap_mem_d *nmd = NULL;
-	struct ifnet *ifp = NULL;
+	if_t ifp = NULL;
 	int error = 0;
 	u_int i, qfirst, qlast;
 	struct netmap_kring **krings;
@@ -3047,7 +3047,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 			/* Build a nmreq_register out of the nmreq_port_hdr,
 			 * so that we can call netmap_get_bdg_na(). */
 			struct nmreq_register regreq;
-			struct ifnet *ifp;
+			if_t ifp;
 
 			bzero(®req, sizeof(regreq));
 			regreq.nr_mode = NR_REG_ALL_NIC;
@@ -3981,7 +3981,7 @@ netmap_attach_common(struct netmap_adapter *na)
 
 #ifdef __FreeBSD__
 	if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
-		na->if_input = na->ifp->if_input; /* for netmap_send_up */
+		na->if_input = if_getinputfn(na->ifp); /* for netmap_send_up */
 	}
 	na->pdev = na; /* make sure netmap_mem_map() is called */
 #endif /* __FreeBSD__ */
@@ -4071,7 +4071,7 @@ int
 netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 {
 	struct netmap_hw_adapter *hwna = NULL;
-	struct ifnet *ifp = NULL;
+	if_t ifp = NULL;
 
 	if (size < sizeof(struct netmap_hw_adapter)) {
 		if (netmap_debug & NM_DEBUG_ON)
@@ -4107,7 +4107,7 @@ netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
 		goto fail;
 	hwna->up = *arg;
 	hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE;
-	strlcpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name));
+	strlcpy(hwna->up.name, if_name(ifp), sizeof(hwna->up.name));
 	if (override_reg) {
 		hwna->nm_hw_register = hwna->up.nm_register;
 		hwna->up.nm_register = netmap_hw_reg;
@@ -4205,7 +4205,7 @@ netmap_hw_krings_create(struct netmap_adapter *na)
  * Called on module unload by the netmap-enabled drivers
  */
 void
-netmap_detach(struct ifnet *ifp)
+netmap_detach(if_t ifp)
 {
 	struct netmap_adapter *na;
 
@@ -4251,7 +4251,7 @@ netmap_detach(struct ifnet *ifp)
  * we make sure to make the mode change visible here.
  */
 int
-netmap_transmit(struct ifnet *ifp, struct mbuf *m)
+netmap_transmit(if_t ifp, struct mbuf *m)
 {
 	struct netmap_adapter *na = NA(ifp);
 	struct netmap_kring *kring, *tx_kring;
@@ -4491,7 +4491,7 @@ netmap_common_irq(struct netmap_adapter *na, u_int q, u_int *work_done)
  * calls the proper forwarding routine.
  */
 int
-netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done)
+netmap_rx_irq(if_t ifp, u_int q, u_int *work_done)
 {
 	struct netmap_adapter *na = NA(ifp);
 
@@ -4516,7 +4516,7 @@ netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done)
 void
 nm_set_native_flags(struct netmap_adapter *na)
 {
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 
 	/* We do the setup for intercepting packets only if we are the
 	 * first user of this adapter. */
@@ -4531,7 +4531,7 @@ nm_set_native_flags(struct netmap_adapter *na)
 void
 nm_clear_native_flags(struct netmap_adapter *na)
 {
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 
 	/* We undo the setup for intercepting packets only if we are the
 	 * last user of this adapter. */
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index 13275d8f6..ef8cb8104 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -390,7 +390,7 @@ netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 {
 	char *nr_name = hdr->nr_name;
 	const char *ifname;
-	struct ifnet *ifp = NULL;
+	if_t ifp = NULL;
 	int error = 0;
 	struct netmap_vp_adapter *vpna, *hostna = NULL;
 	struct nm_bridge *b;
@@ -1777,7 +1777,7 @@ netmap_bwrap_attach_common(struct netmap_adapter *na,
 		na->na_flags |= NAF_MOREFRAG;
 
 	nm_prdis("%s<->%s txr %d txd %d rxr %d rxd %d",
-		na->name, ifp->if_xname,
+		na->name, if_name(ifp),
 		na->num_tx_rings, na->num_tx_desc,
 		na->num_rx_rings, na->num_rx_desc);
 
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index ac8629141..f5148c740 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -59,7 +59,7 @@ typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
 typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
 typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
 typedef int (*bdg_vp_create_fn_t)(struct nmreq_header *hdr,
-		struct ifnet *ifp, struct netmap_mem_d *nmd,
+		if_t ifp, struct netmap_mem_d *nmd,
 		struct netmap_vp_adapter **ret);
 typedef int (*bdg_bwrap_attach_fn_t)(const char *nr_name, struct netmap_adapter *hwna);
 struct netmap_bdg_ops {
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 8c480f2fb..3b2fdd214 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -171,13 +171,13 @@ nm_os_put_module(void)
 }
 
 static void
-netmap_ifnet_arrival_handler(void *arg __unused, struct ifnet *ifp)
+netmap_ifnet_arrival_handler(void *arg __unused, if_t ifp)
 {
 	netmap_undo_zombie(ifp);
 }
 
 static void
-netmap_ifnet_departure_handler(void *arg __unused, struct ifnet *ifp)
+netmap_ifnet_departure_handler(void *arg __unused, if_t ifp)
 {
 	netmap_make_zombie(ifp);
 }
@@ -209,9 +209,9 @@ nm_os_ifnet_fini(void)
 }
 
 unsigned
-nm_os_ifnet_mtu(struct ifnet *ifp)
+nm_os_ifnet_mtu(if_t ifp)
 {
-	return ifp->if_mtu;
+	return if_getmtu(ifp);
 }
 
 rawsum_t
@@ -294,7 +294,7 @@ nm_os_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data,
 
 /* on FreeBSD we send up one packet at a time */
 void *
-nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev)
+nm_os_send_up(if_t ifp, struct mbuf *m, struct mbuf *prev)
 {
 	NA(ifp)->if_input(ifp, m);
 	return NULL;
@@ -315,7 +315,7 @@ nm_os_mbuf_has_seg_offld(struct mbuf *m)
 }
 
 static void
-freebsd_generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
+freebsd_generic_rx_handler(if_t ifp, struct mbuf *m)
 {
 	int stolen;
 
@@ -341,7 +341,7 @@ int
 nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 {
 	struct netmap_adapter *na = &gna->up.up;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	int ret = 0;
 
 	nm_os_ifnet_lock();
@@ -351,10 +351,9 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 			ret = EBUSY; /* already set */
 			goto out;
 		}
-
-		ifp->if_capenable |= IFCAP_NETMAP;
-		gna->save_if_input = ifp->if_input;
-		ifp->if_input = freebsd_generic_rx_handler;
+		if_setcapenablebit(ifp, IFCAP_NETMAP, 0);
+		gna->save_if_input = if_getinputfn(ifp);
+		if_setinputfn(ifp, freebsd_generic_rx_handler);
 	} else {
 		if (!gna->save_if_input) {
 			nm_prerr("Failed to undo RX intercept on %s",
@@ -362,9 +361,8 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 			ret = EINVAL;  /* not saved */
 			goto out;
 		}
-
-		ifp->if_capenable &= ~IFCAP_NETMAP;
-		ifp->if_input = gna->save_if_input;
+		if_setcapenablebit(ifp, 0, IFCAP_NETMAP);
+		if_setinputfn(ifp, gna->save_if_input);
 		gna->save_if_input = NULL;
 	}
 out:
@@ -384,14 +382,14 @@ int
 nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept)
 {
 	struct netmap_adapter *na = &gna->up.up;
-	struct ifnet *ifp = netmap_generic_getifp(gna);
+	if_t ifp = netmap_generic_getifp(gna);
 
 	nm_os_ifnet_lock();
 	if (intercept) {
-		na->if_transmit = ifp->if_transmit;
-		ifp->if_transmit = netmap_transmit;
+		na->if_transmit = if_gettransmitfn(ifp);
+		if_settransmitfn(ifp, netmap_transmit);
 	} else {
-		ifp->if_transmit = na->if_transmit;
+		if_settransmitfn(ifp, na->if_transmit);
 	}
 	nm_os_ifnet_unlock();
 
@@ -420,7 +418,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 {
 	int ret;
 	u_int len = a->len;
-	struct ifnet *ifp = a->ifp;
+	if_t ifp = a->ifp;
 	struct mbuf *m = a->m;
 
 	/* Link the external storage to
@@ -437,7 +435,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 	m->m_pkthdr.flowid = a->ring_nr;
 	m->m_pkthdr.rcvif = ifp; /* used for tx notification */
-	CURVNET_SET(ifp->if_vnet);
+	CURVNET_SET(if_getvnet(ifp));
 	ret = NA(ifp)->if_transmit(ifp, m);
 	CURVNET_RESTORE();
 	return ret ? -1 : 0;
@@ -447,7 +445,7 @@ nm_os_generic_xmit_frame(struct nm_os_gen_arg *a)
 struct netmap_adapter *
 netmap_getna(if_t ifp)
 {
-	return (NA((struct ifnet *)ifp));
+	return (NA(ifp));
 }
 
 /*
@@ -455,14 +453,14 @@ netmap_getna(if_t ifp)
  * way to extract the info from the ifp
  */
 int
-nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx)
+nm_os_generic_find_num_desc(if_t ifp, unsigned int *tx, unsigned int *rx)
 {
 	return 0;
 }
 
 
 void
-nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq)
+nm_os_generic_find_num_queues(if_t ifp, u_int *txq, u_int *rxq)
 {
 	unsigned num_rings = netmap_generic_rings ? netmap_generic_rings : 1;
 
@@ -513,14 +511,14 @@ nm_os_mitigation_cleanup(struct nm_generic_mit *mit)
 }
 
 static int
-nm_vi_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr)
+nm_vi_dummy(if_t ifp, u_long cmd, caddr_t addr)
 {
 
 	return EINVAL;
 }
 
 static void
-nm_vi_start(struct ifnet *ifp)
+nm_vi_start(if_t ifp)
 {
 	panic("nm_vi_start() must not be called");
 }
@@ -594,9 +592,9 @@ nm_vi_free_index(uint8_t val)
  * increment this refcount on if_attach().
  */
 int
-nm_os_vi_persist(const char *name, struct ifnet **ret)
+nm_os_vi_persist(const char *name, if_t *ret)
 {
-	struct ifnet *ifp;
+	if_t ifp;
 	u_short macaddr_hi;
 	uint32_t macaddr_mid;
 	u_char eaddr[6];
@@ -620,14 +618,14 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 		return ENOMEM;
 	}
 	if_initname(ifp, name, IF_DUNIT_NONE);
-	ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_init = (void *)nm_vi_dummy;
-	ifp->if_ioctl = nm_vi_dummy;
-	ifp->if_start = nm_vi_start;
-	ifp->if_mtu = ETHERMTU;
-	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
-	ifp->if_capabilities |= IFCAP_LINKSTATE;
-	ifp->if_capenable |= IFCAP_LINKSTATE;
+	if_setflags(ifp, IFF_UP | IFF_SIMPLEX | IFF_MULTICAST);
+	if_setinitfn(ifp, (void *)nm_vi_dummy);
+	if_setioctlfn(ifp, nm_vi_dummy);
+	if_setstartfn(ifp, nm_vi_start);
+	if_setmtu(ifp, ETHERMTU);
+	if_setsendqlen(ifp, ifqmaxlen);
+	if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
+	if_setcapenablebit(ifp, IFCAP_LINKSTATE, 0);
 
 	ether_ifattach(ifp, eaddr);
 	*ret = ifp;
@@ -636,9 +634,9 @@ nm_os_vi_persist(const char *name, struct ifnet **ret)
 
 /* unregister from the system and drop the final refcount */
 void
-nm_os_vi_detach(struct ifnet *ifp)
+nm_os_vi_detach(if_t ifp)
 {
-	nm_vi_free_index(((char *)IF_LLADDR(ifp))[5]);
+	nm_vi_free_index(((char *)if_getlladdr(ifp))[5]);
 	ether_ifdetach(ifp);
 	if_free(ifp);
 }
@@ -1502,28 +1500,28 @@ freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
 }
 
 void
-nm_os_onattach(struct ifnet *ifp)
+nm_os_onattach(if_t ifp)
 {
-	ifp->if_capabilities |= IFCAP_NETMAP;
+	if_setcapabilitiesbit(ifp, IFCAP_NETMAP, 0);
 }
 
 void
-nm_os_onenter(struct ifnet *ifp)
+nm_os_onenter(if_t ifp)
 {
 	struct netmap_adapter *na = NA(ifp);
 
-	na->if_transmit = ifp->if_transmit;
-	ifp->if_transmit = netmap_transmit;
-	ifp->if_capenable |= IFCAP_NETMAP;
+	na->if_transmit = if_gettransmitfn(ifp);
+	if_settransmitfn(ifp, netmap_transmit);
+	if_setcapenablebit(ifp, IFCAP_NETMAP, 0);
 }
 
 void
-nm_os_onexit(struct ifnet *ifp)
+nm_os_onexit(if_t ifp)
 {
 	struct netmap_adapter *na = NA(ifp);
 
-	ifp->if_transmit = na->if_transmit;
-	ifp->if_capenable &= ~IFCAP_NETMAP;
+	if_settransmitfn(ifp, na->if_transmit);
+	if_setcapenablebit(ifp, 0, IFCAP_NETMAP);
 }
 
 extern struct cdevsw netmap_cdevsw; /* XXX used in netmap.c, should go elsewhere */
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index fb23d2d35..18a2685f8 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -647,7 +647,7 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
 	struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na;
-	struct ifnet *ifp = na->ifp;
+	if_t ifp = na->ifp;
 	struct netmap_ring *ring = kring->ring;
 	u_int nm_i;	/* index into the netmap ring */ // j
 	u_int const lim = kring->nkr_num_slots - 1;
@@ -812,7 +812,7 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
  * Returns 1 if the packet was stolen, 0 otherwise.
  */
 int
-generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
+generic_rx_handler(if_t ifp, struct mbuf *m)
 {
 	struct netmap_adapter *na = NA(ifp);
 	struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na;
@@ -1021,7 +1021,7 @@ static void
 generic_netmap_dtor(struct netmap_adapter *na)
 {
 	struct netmap_generic_adapter *gna = (struct netmap_generic_adapter*)na;
-	struct ifnet *ifp = netmap_generic_getifp(gna);
+	if_t ifp = netmap_generic_getifp(gna);
 	struct netmap_adapter *prev_na = gna->prev;
 
 	if (prev_na != NULL) {
@@ -1036,10 +1036,6 @@ generic_netmap_dtor(struct netmap_adapter *na)
 		nm_prinf("Native netmap adapter for %s restored", prev_na->name);
 	}
 	NM_RESTORE_NA(ifp, prev_na);
-	/*
-	 * netmap_detach_common(), that it's called after this function,
-	 * overrides WNA(ifp) if na->ifp is not NULL.
-	 */
 	na->ifp = NULL;
 	nm_prinf("Emulated netmap adapter for %s destroyed", na->name);
 }
@@ -1062,7 +1058,7 @@ na_is_generic(struct netmap_adapter *na)
  * actual configuration.
  */
 int
-generic_netmap_attach(struct ifnet *ifp)
+generic_netmap_attach(if_t ifp)
 {
 	struct netmap_adapter *na;
 	struct netmap_generic_adapter *gna;
@@ -1070,7 +1066,7 @@ generic_netmap_attach(struct ifnet *ifp)
 	u_int num_tx_desc, num_rx_desc;
 
 #ifdef __FreeBSD__
-	if (ifp->if_type == IFT_LOOP) {
+	if (if_gettype(ifp) == IFT_LOOP) {
 		nm_prerr("if_loop is not supported by %s", __func__);
 		return EINVAL;
 	}
@@ -1099,7 +1095,7 @@ generic_netmap_attach(struct ifnet *ifp)
 		return ENOMEM;
 	}
 	na = (struct netmap_adapter *)gna;
-	strlcpy(na->name, ifp->if_xname, sizeof(na->name));
+	strlcpy(na->name, if_name(ifp), sizeof(na->name));
 	na->ifp = ifp;
 	na->num_tx_desc = num_tx_desc;
 	na->num_rx_desc = num_rx_desc;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index eb708f5a5..c34733f91 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -110,8 +110,6 @@
 #define NM_ATOMIC_TEST_AND_SET(p)       (!atomic_cmpset_acq_int((p), 0, 1))
 #define NM_ATOMIC_CLEAR(p)              atomic_store_rel_int((p), 0)
 
-#define	WNA(_ifp)	(_ifp)->if_netmap
-
 struct netmap_adapter *netmap_getna(if_t ifp);
 
 #define MBUF_REFCNT(m)		((m)->m_ext.ext_count)
@@ -152,7 +150,7 @@ struct hrtimer {
 	})
 
 /* See explanation in nm_os_generic_xmit_frame. */
-#define	GEN_TX_MBUF_IFP(m)	((struct ifnet *)skb_shinfo(m)->destructor_arg)
+#define	GEN_TX_MBUF_IFP(m)	((if_t)skb_shinfo(m)->destructor_arg)
 
 #define NM_ATOMIC_T	volatile long unsigned int
 
@@ -297,13 +295,13 @@ void nm_os_ifnet_fini(void);
 void nm_os_ifnet_lock(void);
 void nm_os_ifnet_unlock(void);
 
-unsigned nm_os_ifnet_mtu(struct ifnet *ifp);
+unsigned nm_os_ifnet_mtu(if_t ifp);
 
 void nm_os_get_module(void);
 void nm_os_put_module(void);
 
-void netmap_make_zombie(struct ifnet *);
-void netmap_undo_zombie(struct ifnet *);
+void netmap_make_zombie(if_t);
+void netmap_undo_zombie(if_t);
 
 /* os independent alloc/realloc/free */
 void *nm_os_malloc(size_t);
@@ -313,10 +311,10 @@ void nm_os_free(void *);
 void nm_os_vfree(void *);
 
 /* os specific attach/detach enter/exit-netmap-mode routines */
-void nm_os_onattach(struct ifnet *);
-void nm_os_ondetach(struct ifnet *);
-void nm_os_onenter(struct ifnet *);
-void nm_os_onexit(struct ifnet *);
+void nm_os_onattach(if_t);
+void nm_os_ondetach(if_t);
+void nm_os_onenter(if_t);
+void nm_os_onexit(if_t);
 
 /* passes a packet up to the host stack.
  * If the packet is sent (or dropped) immediately it returns NULL,
@@ -324,7 +322,7 @@ void nm_os_onexit(struct ifnet *);
  * In this case, a final call with m=NULL and prev != NULL will send up
  * the entire chain to the host stack.
  */
-void *nm_os_send_up(struct ifnet *, struct mbuf *m, struct mbuf *prev);
+void *nm_os_send_up(if_t, struct mbuf *m, struct mbuf *prev);
 
 int nm_os_mbuf_has_seg_offld(struct mbuf *m);
 int nm_os_mbuf_has_csum_offld(struct mbuf *m);
@@ -785,14 +783,14 @@ struct netmap_adapter {
 	/* copy of if_qflush and if_transmit pointers, to intercept
 	 * packets from the network stack when netmap is active.
 	 */
-	int     (*if_transmit)(struct ifnet *, struct mbuf *);
+	int     (*if_transmit)(if_t, struct mbuf *);
 
 	/* copy of if_input for netmap_send_up() */
-	void     (*if_input)(struct ifnet *, struct mbuf *);
+	void     (*if_input)(if_t, struct mbuf *);
 
 	/* Back reference to the parent ifnet struct. Used for
 	 * hardware ports (emulated netmap included). */
-	struct ifnet *ifp; /* adapter is ifp->if_softc */
+	if_t ifp; /* adapter is if_getsoftc(ifp) */
 
 	/*---- callbacks for this netmap adapter -----*/
 	/*
@@ -1047,11 +1045,11 @@ struct netmap_generic_adapter {	/* emulated device */
 	 *  - save_if_input saves the if_input hook (FreeBSD);
 	 *  - mit implements rx interrupt mitigation;
 	 */
-	void (*save_if_input)(struct ifnet *, struct mbuf *);
+	void (*save_if_input)(if_t, struct mbuf *);
 
 	struct nm_generic_mit *mit;
 #ifdef linux
-        netdev_tx_t (*save_start_xmit)(struct mbuf *, struct ifnet *);
+        netdev_tx_t (*save_start_xmit)(struct mbuf *, if_t);
 #endif
 	/* Is the adapter able to use multiple RX slots to scatter
 	 * each packet pushed up by the driver? */
@@ -1173,7 +1171,7 @@ struct netmap_pipe_adapter {
 	struct netmap_adapter *parent; /* adapter that owns the memory */
 	struct netmap_pipe_adapter *peer; /* the other end of the pipe */
 	int peer_ref;		/* 1 iff we are holding a ref to the peer */
-	struct ifnet *parent_ifp;	/* maybe null */
+	if_t parent_ifp;	/* maybe null */
 
 	u_int parent_slot; /* index in the parent pipe array */
 };
@@ -1346,8 +1344,8 @@ static __inline void nm_kr_start(struct netmap_kring *kr)
  */
 int netmap_attach(struct netmap_adapter *);
 int netmap_attach_ext(struct netmap_adapter *, size_t size, int override_reg);
-void netmap_detach(struct ifnet *);
-int netmap_transmit(struct ifnet *, struct mbuf *);
+void netmap_detach(if_t);
+int netmap_transmit(if_t, struct mbuf *);
 struct netmap_slot *netmap_reset(struct netmap_adapter *na,
 	enum txrx tx, u_int n, u_int new_cur);
 int netmap_ring_reinit(struct netmap_kring *);
@@ -1370,7 +1368,7 @@ enum {
 };
 
 /* default functions to handle rx/tx interrupts */
-int netmap_rx_irq(struct ifnet *, u_int, u_int *);
+int netmap_rx_irq(if_t, u_int, u_int *);
 #define netmap_tx_irq(_n, _q) netmap_rx_irq(_n, _q, NULL)
 int netmap_common_irq(struct netmap_adapter *, u_int, u_int *work_done);
 
@@ -1523,8 +1521,8 @@ void netmap_set_ring(struct netmap_adapter *, u_int ring_id, enum txrx, int stop
 /* set the stopped/enabled status of all rings of the adapter. */
 void netmap_set_all_rings(struct netmap_adapter *, int stopped);
 /* convenience wrappers for netmap_set_all_rings */
-void netmap_disable_all_rings(struct ifnet *);
-void netmap_enable_all_rings(struct ifnet *);
+void netmap_disable_all_rings(if_t);
+void netmap_enable_all_rings(if_t);
 
 int netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu);
 int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
@@ -1533,9 +1531,9 @@ void netmap_do_unregif(struct netmap_priv_d *priv);
 
 u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
 int netmap_get_na(struct nmreq_header *hdr, struct netmap_adapter **na,
-		struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
-void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
-int netmap_get_hw_na(struct ifnet *ifp,
+		if_t *ifp, struct netmap_mem_d *nmd, int create);
+void netmap_unget_na(struct netmap_adapter *na, if_t ifp);
+int netmap_get_hw_na(if_t ifp,
 		struct netmap_mem_d *nmd, struct netmap_adapter **na);
 void netmap_mem_restore(struct netmap_adapter *na);
 
@@ -1690,13 +1688,14 @@ extern int netmap_generic_txqdisc;
 
 /*
  * NA returns a pointer to the struct netmap adapter from the ifp.
- * WNA is os-specific and must be defined in glue code.
+ * The if_getnetmapadapter() and if_setnetmapadapter() helpers are
+ * os-specific and must be defined in glue code.
  */
-#define	NA(_ifp)	((struct netmap_adapter *)WNA(_ifp))
+#define	NA(_ifp)	(if_getnetmapadapter(_ifp))
 
 /*
  * we provide a default implementation of NM_ATTACH_NA/NM_DETACH_NA
- * based on the WNA field.
+ * based on the if_setnetmapadapter() setter function.
  * Glue code may override this by defining its own NM_ATTACH_NA
  */
 #ifndef NM_ATTACH_NA
@@ -1713,14 +1712,14 @@ extern int netmap_generic_txqdisc;
 	((uint32_t)(uintptr_t)NA(ifp) ^ NA(ifp)->magic) == NETMAP_MAGIC )
 
 #define	NM_ATTACH_NA(ifp, na) do {					\
-	WNA(ifp) = na;							\
+	if_setnetmapadapter(ifp, na);					\
 	if (NA(ifp))							\
 		NA(ifp)->magic = 					\
 			((uint32_t)(uintptr_t)NA(ifp)) ^ NETMAP_MAGIC;	\
 } while(0)
-#define NM_RESTORE_NA(ifp, na) 	WNA(ifp) = na;
+#define NM_RESTORE_NA(ifp, na) 	if_setnetmapadapter(ifp, na);
 
-#define NM_DETACH_NA(ifp)	do { WNA(ifp) = NULL; } while (0)
+#define NM_DETACH_NA(ifp)	do { if_setnetmapadapter(ifp, NULL); } while (0)
 #define NM_NA_CLASH(ifp)	(NA(ifp) && !NM_NA_VALID(ifp))
 #endif /* !NM_ATTACH_NA */
 
@@ -2027,7 +2026,7 @@ struct netmap_priv_d {
 	struct netmap_if * volatile np_nifp;	/* netmap if descriptor. */
 
 	struct netmap_adapter	*np_na;
-	struct ifnet	*np_ifp;
+	if_t		np_ifp;
 	uint32_t	np_flags;	/* from the ioctl */
 	u_int		np_qfirst[NR_TXRX],
 			np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */
@@ -2121,8 +2120,8 @@ struct netmap_monitor_adapter {
  * generic netmap emulation for devices that do not have
  * native netmap support.
  */
-int generic_netmap_attach(struct ifnet *ifp);
-int generic_rx_handler(struct ifnet *ifp, struct mbuf *m);
+int generic_netmap_attach(if_t ifp);
+int generic_rx_handler(if_t ifp, struct mbuf *m);
 
 int nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept);
 int nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept);
@@ -2140,7 +2139,7 @@ int na_is_generic(struct netmap_adapter *na);
  * routine to send the queue and free any resources. Failure is ignored.
  */
 struct nm_os_gen_arg {
-	struct ifnet *ifp;
+	if_t ifp;
 	void *m;	/* os-specific mbuf-like object */
 	void *head, *tail; /* tailq, if the OS-specific routine needs to build one */
 	void *addr;	/* payload of current packet */
@@ -2150,11 +2149,11 @@ struct nm_os_gen_arg {
 };
 
 int nm_os_generic_xmit_frame(struct nm_os_gen_arg *);
-int nm_os_generic_find_num_desc(struct ifnet *ifp, u_int *tx, u_int *rx);
-void nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq);
+int nm_os_generic_find_num_desc(if_t ifp, u_int *tx, u_int *rx);
+void nm_os_generic_find_num_queues(if_t ifp, u_int *txq, u_int *rxq);
 void nm_os_generic_set_features(struct netmap_generic_adapter *gna);
 
-static inline struct ifnet*
+static inline if_t
 netmap_generic_getifp(struct netmap_generic_adapter *gna)
 {
         if (gna->prev)
@@ -2291,8 +2290,8 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na,
 			   u_int *j, u_int lim, u_int *howmany);
 
 /* persistent virtual port routines */
-int nm_os_vi_persist(const char *, struct ifnet **);
-void nm_os_vi_detach(struct ifnet *);
+int nm_os_vi_persist(const char *, if_t *);
+void nm_os_vi_detach(if_t);
 void nm_os_vi_init_index(void);
 
 /*
@@ -2402,7 +2401,7 @@ static void void_mbuf_dtor(struct mbuf *m) { }
 } while (0)
 
 static inline struct mbuf *
-nm_os_get_mbuf(struct ifnet *ifp, int len)
+nm_os_get_mbuf(if_t ifp, int len)
 {
 	struct mbuf *m;
 
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index 67483a35e..e8f71d772 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -1162,7 +1162,7 @@ netmap_pt_guest_attach(struct netmap_adapter *arg,
 		       unsigned int nifp_offset, unsigned int memid)
 {
 	struct netmap_pt_guest_adapter *ptna;
-	struct ifnet *ifp = arg ? arg->ifp : NULL;
+	if_t ifp = arg ? arg->ifp : NULL;
 	int error;
 
 	/* get allocator */
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 512e1e084..3f676fccf 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -414,14 +414,14 @@ netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
 	default:	/* allow device-specific ioctls */
 	    {
 		struct nmreq *nmr = (struct nmreq *)data;
-		struct ifnet *ifp = ifunit_ref(nmr->nr_name);
+		if_t ifp = ifunit_ref(nmr->nr_name);
 		if (ifp == NULL) {
 			error = ENXIO;
 		} else {
 			struct socket so;
 
 			bzero(&so, sizeof(so));
-			so.so_vnet = ifp->if_vnet;
+			so.so_vnet = if_getvnet(ifp);
 			// so->so_proto not null.
 			error = ifioctl(&so, cmd, data, td);
 			if_rele(ifp);
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index de507466d..1b290c966 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -2485,7 +2485,7 @@ netmap_mem_ext_create(uint64_t usrptr, struct nmreq_pools_info *pi, int *perror)
 #ifdef WITH_PTNETMAP
 struct mem_pt_if {
 	struct mem_pt_if *next;
-	struct ifnet *ifp;
+	if_t ifp;
 	unsigned int nifp_offset;
 };
 
@@ -2503,7 +2503,7 @@ struct netmap_mem_ptg {
 
 /* Link a passthrough interface to a passthrough netmap allocator. */
 static int
-netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
+netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, if_t ifp,
 			    unsigned int nifp_offset)
 {
 	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
@@ -2526,14 +2526,14 @@ netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp,
 	NMA_UNLOCK(nmd);
 
 	nm_prinf("ifp=%s,nifp_offset=%u",
-		ptif->ifp->if_xname, ptif->nifp_offset);
+		if_name(ptif->ifp), ptif->nifp_offset);
 
 	return 0;
 }
 
 /* Called with NMA_LOCK(nmd) held. */
 static struct mem_pt_if *
-netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d *nmd, struct ifnet *ifp)
+netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d *nmd, if_t ifp)
 {
 	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 	struct mem_pt_if *curr;
@@ -2549,7 +2549,7 @@ netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d *nmd, struct ifnet *ifp)
 
 /* Unlink a passthrough interface from a passthrough netmap allocator. */
 int
-netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, struct ifnet *ifp)
+netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, if_t ifp)
 {
 	struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd;
 	struct mem_pt_if *prev = NULL;
@@ -2566,7 +2566,7 @@ netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, struct ifnet *ifp)
 				ptnmd->pt_ifs = curr->next;
 			}
 			nm_prinf("removed (ifp=%s,nifp_offset=%u)",
-			  curr->ifp->if_xname, curr->nifp_offset);
+			  if_name(curr->ifp), curr->nifp_offset);
 			nm_os_free(curr);
 			ret = 0;
 			break;
@@ -2958,7 +2958,7 @@ netmap_mem_pt_guest_attach(struct ptnetmap_memdev *ptn_dev, nm_memid_t mem_id)
 
 /* Called when ptnet device is attaching */
 struct netmap_mem_d *
-netmap_mem_pt_guest_new(struct ifnet *ifp,
+netmap_mem_pt_guest_new(if_t ifp,
 			unsigned int nifp_offset,
 			unsigned int memid)
 {
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 61eeb4569..036e44d1b 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -160,12 +160,12 @@ struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *,
 #endif /* WITH_EXTMEM */
 
 #ifdef WITH_PTNETMAP
-struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *,
+struct netmap_mem_d* netmap_mem_pt_guest_new(if_t,
 					     unsigned int nifp_offset,
 					     unsigned int memid);
 struct ptnetmap_memdev;
 struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16_t);
-int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
+int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, if_t);
 #endif /* WITH_PTNETMAP */
 
 int netmap_mem_pools_info_get(struct nmreq_pools_info *,
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index 8e3e39e6a..a8bd2d17b 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -907,7 +907,7 @@ netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct nmreq_register preq;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_monitor_adapter *mna;
-	struct ifnet *ifp = NULL;
+	if_t ifp = NULL;
 	int  error;
 	int zcopy = (req->nr_flags & NR_ZCOPY_MON);
 
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 01fd79ded..91cad5201 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -657,7 +657,7 @@ netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
 	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
 	struct netmap_adapter *pna; /* parent adapter */
 	struct netmap_pipe_adapter *mna, *sna, *reqna;
-	struct ifnet *ifp = NULL;
+	if_t ifp = NULL;
 	const char *pipe_id = NULL;
 	int role = 0;
 	int error, retries = 0;
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 7813984ad..f5e65f1c0 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -126,7 +126,7 @@ SYSCTL_UINT(_dev_netmap, OID_AUTO, max_bridges, CTLFLAG_RDTUN, &vale_max_bridges
 		"Max number of vale bridges");
 SYSEND;
 
-static int netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *,
+static int netmap_vale_vp_create(struct nmreq_header *hdr, if_t,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **);
 static int netmap_vale_vp_bdg_attach(const char *, struct netmap_adapter *,
 		struct nm_bridge *);
@@ -411,7 +411,7 @@ netmap_vale_vp_dtor(struct netmap_adapter *na)
 	if (na->ifp != NULL && !nm_iszombie(na)) {
 		NM_DETACH_NA(na->ifp);
 		if (vpna->autodelete) {
-			nm_prdis("releasing %s", na->ifp->if_xname);
+			nm_prdis("releasing %s", if_name(na->ifp));
 			NMG_UNLOCK();
 			nm_os_vi_detach(na->ifp);
 			NMG_LOCK();
@@ -1139,7 +1139,7 @@ netmap_vale_vp_txsync(struct netmap_kring *kring, int flags)
  * Only persistent VALE ports have a non-null ifp.
  */
 static int
-netmap_vale_vp_create(struct nmreq_header *hdr, struct ifnet *ifp,
+netmap_vale_vp_create(struct nmreq_header *hdr, if_t ifp,
 		struct netmap_mem_d *nmd, struct netmap_vp_adapter **ret)
 {
 	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
@@ -1352,7 +1352,7 @@ nm_vi_create(struct nmreq_header *hdr)
 int
 nm_vi_destroy(const char *name)
 {
-	struct ifnet *ifp;
+	if_t ifp;
 	struct netmap_vp_adapter *vpna;
 	int error;
 
@@ -1384,7 +1384,7 @@ nm_vi_destroy(const char *name)
 	NMG_UNLOCK();
 
 	if (netmap_verbose)
-		nm_prinf("destroying a persistent vale interface %s", ifp->if_xname);
+		nm_prinf("destroying a persistent vale interface %s", if_name(ifp));
 	/* Linux requires all the references are released
 	 * before unregister
 	 */
@@ -1419,7 +1419,7 @@ int
 netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 {
 	struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
-	struct ifnet *ifp;
+	if_t ifp;
 	struct netmap_vp_adapter *vpna;
 	struct netmap_mem_d *nmd = NULL;
 	int error;
@@ -1483,7 +1483,7 @@ netmap_vi_create(struct nmreq_header *hdr, int autodelete)
 	if (nmd)
 		netmap_mem_put(nmd);
 	NMG_UNLOCK();
-	nm_prdis("created %s", ifp->if_xname);
+	nm_prdis("created %s", if_name(ifp));
 	return 0;
 
 err_2:

From 6af672a15539d62e9236075cf6e5b5655eec8404 Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Tue, 7 Mar 2023 09:44:54 -0500
Subject: [PATCH 2090/2207] pkt-gen.c: update IP/UDP checksums if size changes

When randomizing the packet size using '-l max -l min', the checksums
and IP/UDP lengths are set using the maximum payload size. After that
all size changes are truncations of the payload field. The IP/UDP
lengths and the associated checksums are not recalculated.

The IP header can quickly be modified by changing the length and
modifying the existing checksum (for IPv4). The UDP checksum covers the
entire payload and cannot be trivially updated. The current solution is
to recompute the checksum across the payload each call.

Since recomputing the UDP checksum can have a non-trival cost, I have
added a new option OPT_UPDATE_CSUM (4096). When this option is set,
IP/UDP lengths will be updated and checksums will be valid.
---
 apps/pkt-gen/pkt-gen.c | 82 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 296208018..1539fe7f8 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -283,6 +283,7 @@ struct glob_arg {
 #define OPT_RANDOM_SRC  512
 #define OPT_RANDOM_DST  1024
 #define OPT_PPS_STATS   2048
+#define OPT_UPDATE_CSUM 4096
 	int dev_type;
 #ifndef NO_PCAP
 	pcap_t *p;
@@ -1005,6 +1006,85 @@ update_addresses(struct pkt *pkt, struct targ *t)
 	else
 		update_ip6(pkt, t);
 }
+
+static void
+update_ip_size(struct pkt *pkt, struct targ *t, int size)
+{
+	struct ip ip;
+	struct udphdr udp;
+	uint16_t oiplen, niplen;
+	uint16_t nudplen;
+	uint16_t ip_sum = 0;
+
+	memcpy(&ip, &pkt->ipv4.ip, sizeof(ip));
+	memcpy(&udp, &pkt->ipv4.udp, sizeof(udp));
+
+	oiplen = ntohs(ip.ip_len);
+	niplen = size - sizeof(struct ether_header);
+	ip.ip_len = htons(niplen);
+	nudplen = niplen - sizeof(struct ip);
+	udp.uh_ulen = htons(nudplen);
+	ip_sum = new_udp_sum(ip_sum, oiplen, niplen);
+
+	/* update checksums */
+	if (ip_sum != 0)
+		ip.ip_sum = ~cksum_add(~ip.ip_sum, htons(ip_sum));
+
+	udp.uh_sum = 0;
+	/* Magic: taken from sbin/dhclient/packet.c */
+	udp.uh_sum = wrapsum(
+		checksum(&udp, sizeof(udp),	/* udp header */
+		checksum(pkt->ipv4.body,	/* udp payload */
+		nudplen - sizeof(udp),
+		checksum(&ip.ip_src, /* pseudo header */
+		2 * sizeof(ip.ip_src),
+		IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen)))));
+
+	memcpy(&pkt->ipv4.ip, &ip, sizeof(ip));
+	memcpy(&pkt->ipv4.udp, &udp, sizeof(udp));
+}
+
+static void
+update_ip6_size(struct pkt *pkt, struct targ *t, int size)
+{
+	struct ip6_hdr ip6;
+	struct udphdr udp;
+	uint16_t niplen, nudplen;
+	uint32_t csum;
+
+	memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6));
+	memcpy(&udp, &pkt->ipv6.udp, sizeof(udp));
+
+	nudplen = niplen = size - sizeof(struct ether_header) - sizeof(ip6);
+	ip6.ip6_plen = htons(niplen);
+	udp.uh_ulen = htons(nudplen);
+
+	/* Save part of pseudo header checksum into csum */
+	udp.uh_sum = 0;
+	csum = IPPROTO_UDP << 24;
+	csum = checksum(&csum, sizeof(csum), nudplen);
+	udp.uh_sum = wrapsum(
+		checksum(&udp, sizeof(udp),	/* udp header */
+		checksum(pkt->ipv6.body,	/* udp payload */
+		nudplen - sizeof(udp),
+		checksum(&pkt->ipv6.ip.ip6_src, /* pseudo header */
+		2 * sizeof(pkt->ipv6.ip.ip6_src), csum))));
+
+	memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6));
+	memcpy(&pkt->ipv6.udp, &udp, sizeof(udp));
+}
+
+static void
+update_size(struct pkt *pkt, struct targ *t, int size)
+{
+	if (t->g->options & OPT_UPDATE_CSUM) {
+		if (t->g->af == AF_INET)
+			update_ip_size(pkt, t, size);
+		else
+			update_ip6_size(pkt, t, size);
+	}
+}
+
 /*
  * initialize one packet and prepare for the next one.
  * The copy could be done better instead of repeating it each time.
@@ -1744,6 +1824,7 @@ sender_body(void *data)
 				size = nrand48(targ->seed) %
 					(targ->g->pkt_size - targ->g->pkt_min_size) +
 					targ->g->pkt_min_size;
+				update_size(pkt, targ, size);
 			}
 			m = send_packets(txring, pkt, frame, size, targ,
 					 limit, options);
@@ -2528,6 +2609,7 @@ usage(int errcode)
 "				OPT_RANDOM_SRC  512\n"
 "				OPT_RANDOM_DST  1024\n"
 "				OPT_PPS_STATS   2048\n"
+"				OPT_UPDATE_CSUM 4096\n"
 		     "",
 		cmd);
 	exit(errcode);

From e98d744e6b0c3e64ad5a78df32cb63748e0dc307 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 11 Mar 2023 18:04:39 +0100
Subject: [PATCH 2091/2207] Remove obsolete compatibility defines

No functional change intended.

Submitted by:	Mark Johnston 
---
 sys/dev/netmap/netmap_freebsd.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 3b2fdd214..296c37576 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1024,11 +1024,6 @@ netmap_dev_pager_fault(vm_object_t object, vm_ooffset_t offset,
 		 * Replace the passed in reqpage page with our own fake page and
 		 * free up the all of the original pages.
 		 */
-#ifndef VM_OBJECT_WUNLOCK	/* FreeBSD < 10.x */
-#define VM_OBJECT_WUNLOCK VM_OBJECT_UNLOCK
-#define VM_OBJECT_WLOCK	VM_OBJECT_LOCK
-#endif /* VM_OBJECT_WUNLOCK */
-
 		VM_OBJECT_WUNLOCK(object);
 		page = vm_page_getfake(paddr, memattr);
 		VM_OBJECT_WLOCK(object);

From 4aff215e366435bb5aa7c20f22ecfe6bb9ba10d0 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Sat, 11 Mar 2023 18:17:58 +0100
Subject: [PATCH 2092/2207] emulated netmap: improve log line

---
 sys/dev/netmap/netmap_generic.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 18a2685f8..eb98f0053 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -438,8 +438,7 @@ generic_mbuf_destructor(struct mbuf *m)
 	unsigned int r_orig = r;
 
 	if (unlikely(!nm_netmap_on(na) || r >= na->num_tx_rings)) {
-		nm_prerr("Error: no netmap adapter on device %p",
-		  GEN_TX_MBUF_IFP(m));
+		nm_prerr("Error: no netmap adapter on device %s", na->name);
 		return;
 	}
 

From 9ec79f8f621be4e63c0a6d0662d16a69499510b6 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Tue, 14 Mar 2023 23:24:34 +0100
Subject: [PATCH 2093/2207] netmap: get rid of save_if_input for emulated
 adapters

The save_if_input function pointer was meant to save the previous
value of ifp->if_input before replacing it with the emulated
adapter hook.
However, the same pointer value is already stored in the if_input
field of the netmap_adapter struct, to be used for host TX ring processing.

Reuse the netmap_adapter if_input field to simplify the code
and save some space.
---
 sys/dev/netmap/netmap_freebsd.c | 20 ++------------------
 sys/dev/netmap/netmap_kern.h    |  3 ---
 2 files changed, 2 insertions(+), 21 deletions(-)

diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 296c37576..4b3b1a6ed 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -327,9 +327,7 @@ freebsd_generic_rx_handler(if_t ifp, struct mbuf *m)
 
 	stolen = generic_rx_handler(ifp, m);
 	if (!stolen) {
-		struct netmap_generic_adapter *gna =
-				(struct netmap_generic_adapter *)NA(ifp);
-		gna->save_if_input(ifp, m);
+		NA(ifp)->if_input(ifp, m);
 	}
 }
 
@@ -346,26 +344,12 @@ nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept)
 
 	nm_os_ifnet_lock();
 	if (intercept) {
-		if (gna->save_if_input) {
-			nm_prerr("RX on %s already intercepted", na->name);
-			ret = EBUSY; /* already set */
-			goto out;
-		}
 		if_setcapenablebit(ifp, IFCAP_NETMAP, 0);
-		gna->save_if_input = if_getinputfn(ifp);
 		if_setinputfn(ifp, freebsd_generic_rx_handler);
 	} else {
-		if (!gna->save_if_input) {
-			nm_prerr("Failed to undo RX intercept on %s",
-				na->name);
-			ret = EINVAL;  /* not saved */
-			goto out;
-		}
 		if_setcapenablebit(ifp, 0, IFCAP_NETMAP);
-		if_setinputfn(ifp, gna->save_if_input);
-		gna->save_if_input = NULL;
+		if_setinputfn(ifp, na->if_input);
 	}
-out:
 	nm_os_ifnet_unlock();
 
 	return ret;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c34733f91..7c68c79c6 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1042,11 +1042,8 @@ struct netmap_generic_adapter {	/* emulated device */
 	struct netmap_adapter *prev;
 
 	/* Emulated netmap adapters support:
-	 *  - save_if_input saves the if_input hook (FreeBSD);
 	 *  - mit implements rx interrupt mitigation;
 	 */
-	void (*save_if_input)(if_t, struct mbuf *);
-
 	struct nm_generic_mit *mit;
 #ifdef linux
         netdev_tx_t (*save_start_xmit)(struct mbuf *, if_t);

From 786ae482b90db964e67286b91deaca3367d47911 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 18 Mar 2023 09:17:08 +0100
Subject: [PATCH 2094/2207] fix copyin/out of nmreq option list

The previous code tried unsuccesfully to report a precise error for each
option in the user list. Moreover, commit 253b2ec199b broke some
ctrl-api-test (see
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=260547).

The new code bails out as soon as an unrecoverable error is detected and
properly checks for copy boundaries. EOPNOTSUPP no longer immediately
returns an error, so that any other option in the list may be examined
by the caller code and a precise report of the (un)supported options can
be returned to the user.

With this patch, all ctrl-api-test unit tests can be passed again.
---
 sys/dev/netmap/netmap.c | 69 +++++++++++++++++++++++++----------------
 utils/ctrl-api-test.c   | 21 +++++++++++--
 2 files changed, 61 insertions(+), 29 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e6c9a41f9..59533db53 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3377,7 +3377,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	size_t rqsz, optsz, bufsz;
 	int error = 0;
 	char *ker = NULL, *p;
-	struct nmreq_option **next, *src, **opt_tab;
+	struct nmreq_option **next, *src, **opt_tab, *opt;
 	uint64_t *ptrs;
 
 	if (hdr->nr_reserved) {
@@ -3428,24 +3428,36 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	*ptrs++ = hdr->nr_body;
 	*ptrs++ = hdr->nr_options;
 	p = (char *)ptrs;
+	/* overwrite the user pointer with the in-kernel one */
+	hdr->nr_body = (uintptr_t)p;
+	/* prepare the options-list pointers and temporarily terminate
+	 * the in-kernel list, in case we have to jump to out_restore
+	 */
+	next = (struct nmreq_option **)&hdr->nr_options;
+	src = *next;
+	hdr->nr_options = 0;
 
 	/* copy the body */
-	error = copyin((void *)(uintptr_t)hdr->nr_body, p, rqsz);
+	error = copyin(*(void **)ker, p, rqsz);
 	if (error)
 		goto out_restore;
-	/* overwrite the user pointer with the in-kernel one */
-	hdr->nr_body = (uintptr_t)p;
 	p += rqsz;
 	/* start of the options table */
 	opt_tab = (struct nmreq_option **)p;
 	p += sizeof(opt_tab) * NETMAP_REQ_OPT_MAX;
 
 	/* copy the options */
-	next = (struct nmreq_option **)&hdr->nr_options;
-	src = *next;
 	while (src) {
-		struct nmreq_option *opt;
+		struct nmreq_option *nsrc;
 
+		if (p - ker + sizeof(uint64_t*) + sizeof(*src) > bufsz) {
+			error = EMSGSIZE;
+			/* there might be a loop in the list: don't try to
+			 * copyout the options
+			 */
+			hdr->nr_options = 0;
+			goto out_restore;
+		}
 		/* copy the option header */
 		ptrs = (uint64_t *)p;
 		opt = (struct nmreq_option *)(ptrs + 1);
@@ -3453,15 +3465,19 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		if (error)
 			goto out_restore;
 		rqsz += sizeof(*src);
+		p = (char *)(opt + 1);
+
 		/* make a copy of the user next pointer */
 		*ptrs = opt->nro_next;
-		/* overwrite the user pointer with the in-kernel one */
+		/* append the option to the in-kernel list */
 		*next = opt;
-
-		/* initialize the option as not supported.
-		 * Recognized options will update this field.
+		/* temporarily teminate the in-kernel list, in case we have to
+		 * jump to out_restore
 		 */
-		opt->nro_status = EOPNOTSUPP;
+		nsrc = (struct nmreq_option *)opt->nro_next;
+		opt->nro_next = 0;
+
+		opt->nro_status = 0;
 
 		/* check for invalid types */
 		if (opt->nro_reqtype < 1) {
@@ -3469,12 +3485,11 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 				nm_prinf("invalid option type: %u", opt->nro_reqtype);
 			opt->nro_status = EINVAL;
 			error = EINVAL;
-			goto next;
+			goto out_restore;
 		}
 
 		if (opt->nro_reqtype >= NETMAP_REQ_OPT_MAX) {
-			/* opt->nro_status is already EOPNOTSUPP */
-			error = EOPNOTSUPP;
+			/* opt->nro_status will be set to EOPNOTSUPP */
 			goto next;
 		}
 
@@ -3487,12 +3502,10 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 			opt->nro_status = EINVAL;
 			opt_tab[opt->nro_reqtype]->nro_status = EINVAL;
 			error = EINVAL;
-			goto next;
+			goto out_restore;
 		}
 		opt_tab[opt->nro_reqtype] = opt;
 
-		p = (char *)(opt + 1);
-
 		/* copy the option body */
 		optsz = nmreq_opt_size_by_type(opt->nro_reqtype,
 						opt->nro_size);
@@ -3515,18 +3528,20 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 	next:
 		/* move to next option */
 		next = (struct nmreq_option **)&opt->nro_next;
-		src = *next;
+		src = nsrc;
 	}
-	if (error)
-		nmreq_copyout(hdr, error);
-	return error;
+
+	/* initialize all the options as not supported.  Recognized options
+	 * will update their field.
+	 */
+	for (src = (struct nmreq_option *)hdr->nr_options; src;
+			src = (struct nmreq_option *)src->nro_next) {
+		src->nro_status = EOPNOTSUPP;
+	}
+	return 0;
 
 out_restore:
-	ptrs = (uint64_t *)ker;
-	hdr->nr_body = *ptrs++;
-	hdr->nr_options = *ptrs++;
-	hdr->nr_reserved = 0;
-	nm_os_free(ker);
+	nmreq_copyout(hdr, error);
 out_err:
 	return error;
 }
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index c582a32d7..fdedd5773 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1012,9 +1012,9 @@ infinite_options(struct TestContext *ctx)
 {
 	struct nmreq_option opt;
 
-	printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
+	printf("Testing infinite list of options on %s (invalid options)\n", ctx->ifname_ext);
 
-	opt.nro_reqtype = 1234;
+	opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
 	push_option(&opt, ctx);
 	opt.nro_next = (uintptr_t)&opt;
 	if (port_register_hwall(ctx) >= 0)
@@ -1023,6 +1023,22 @@ infinite_options(struct TestContext *ctx)
 	return (errno == EMSGSIZE ? 0 : -1);
 }
 
+static int
+infinite_options2(struct TestContext *ctx)
+{
+	struct nmreq_option opt;
+
+	printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
+
+	opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
+	push_option(&opt, ctx);
+	opt.nro_next = (uintptr_t)&opt;
+	if (port_register_hwall(ctx) >= 0)
+		return -1;
+	clear_options(ctx);
+	return (errno == EINVAL ? 0 : -1);
+}
+
 #ifdef CONFIG_NETMAP_EXTMEM
 int
 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
@@ -2049,6 +2065,7 @@ static struct mytest tests[] = {
 	decltest(vale_polling_enable_disable),
 	decltest(unsupported_option),
 	decltest(infinite_options),
+	decltest(infinite_options2),
 #ifdef CONFIG_NETMAP_EXTMEM
 	decltest(extmem_option),
 	decltest(bad_extmem_option),

From 0a53f85876d9ec7c7272c08cddcc401da163fb1e Mon Sep 17 00:00:00 2001
From: jhk 
Date: Wed, 22 Mar 2023 00:17:47 +0100
Subject: [PATCH 2095/2207] ctrl-api-test: fix uninitialized variable bug

This causes random test failures because of uninitialized
opt.nro_size.
---
 utils/ctrl-api-test.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index fdedd5773..98ee020eb 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1014,6 +1014,7 @@ infinite_options(struct TestContext *ctx)
 
 	printf("Testing infinite list of options on %s (invalid options)\n", ctx->ifname_ext);
 
+	memset(&opt, 0, sizeof(opt));
 	opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
 	push_option(&opt, ctx);
 	opt.nro_next = (uintptr_t)&opt;
@@ -1030,6 +1031,7 @@ infinite_options2(struct TestContext *ctx)
 
 	printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
 
+	memset(&opt, 0, sizeof(opt));
 	opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
 	push_option(&opt, ctx);
 	opt.nro_next = (uintptr_t)&opt;

From 817991cae832cc44edcfe1753aee0a6f86bd05e0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 3 Apr 2023 14:59:25 +0200
Subject: [PATCH 2096/2207] linux/drivers: patches for latest Intel drivers

---
 LINUX/final-patches/intel--ice--1.11.14     | 223 ++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.13.16     | 138 ++++++++++++
 LINUX/final-patches/intel--ixgbe--5.18.11   | 173 +++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.17.11 | 169 +++++++++++++++
 4 files changed, 703 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ice--1.11.14
 create mode 100644 LINUX/final-patches/intel--igb--5.13.16
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.18.11
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.17.11

diff --git a/LINUX/final-patches/intel--ice--1.11.14 b/LINUX/final-patches/intel--ice--1.11.14
new file mode 100644
index 000000000..059e55d58
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.11.14
@@ -0,0 +1,223 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 7cf1e17..0b5d5ea 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -68,12 +68,12 @@ ice-y := ice_main.o	\
+ 	 ice_fwlog.o		\
+ 	 ice_ieps.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -86,21 +86,21 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_GNSS:m=y) += ice_gnss.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_GNSS:m=y) += ice_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ 
+ 
+@@ -113,7 +113,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -147,7 +147,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -192,7 +192,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index fdbf6f9..c094d20 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -480,6 +485,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -636,6 +645,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -908,6 +922,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *tx_ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 7bdd417..061fbe3 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6551,6 +6556,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6680,6 +6689,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	hw = &pf->hw;
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index e3ee85c..5fcb360 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -229,6 +233,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -1624,6 +1632,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.13.16 b/LINUX/final-patches/intel--igb--5.13.16
new file mode 100644
index 000000000..dfc0e5a50
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.13.16
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index e761697..38767eb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index d9afbd4..db4f6de 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.18.11 b/LINUX/final-patches/intel--ixgbe--5.18.11
new file mode 100644
index 000000000..206a0cefd
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.18.11
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 884cbf7..4ffc802 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 9fa2109..0c36a59 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2229,6 +2257,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4434,6 +4476,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13250,6 +13298,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13306,6 +13358,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.17.11 b/LINUX/final-patches/intel--ixgbevf--4.17.11
new file mode 100644
index 000000000..fa47ad3bd
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.17.11
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index df6689d..03ce8eb 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 666aae8..1635113 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -345,6 +345,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -365,6 +382,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1383,6 +1411,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2101,6 +2139,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2335,6 +2377,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5643,8 +5689,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5685,6 +5733,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 3211170..13630cc 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 561efc912d9063fc002880eeff6162e14dcf1037 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 3 Apr 2023 16:49:04 +0200
Subject: [PATCH 2097/2207] linux/igb: disable some warnings

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 81e118eb3..be5ea12ff 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -84,7 +84,7 @@ $(eval $(call default,ice,1.9.11))
 
 # some additional, driver-specific CFLAGS (used in the @build variable above) and fixes
 e1000e@cflags := -fno-pie
-igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie
+igb@cflags := -DDISABLE_PACKET_SPLIT -fno-pie $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
 ixgbe@cflags := $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
 i40e@cflags :=  $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
 igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2 5.7.2 5.8.5 5.9.3 5.10.2),@BUILDDIR@/intel-fix.sh igb,)

From 7970abb4d673c46708031aed82daa995c5ba74f9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Apr 2023 18:00:55 +0200
Subject: [PATCH 2098/2207] linux/i40e: don't try to fix common.mk in 2.22.8

---
 LINUX/default-config.mak.in_ | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index be5ea12ff..840a85926 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -91,7 +91,7 @@ igb@prepare := $(if $(filter $(igb@v),5.3.5.61 5.3.6 5.4.6 5.5.2 5.7.2 5.8.5 5.9
 e1000e@prepare := $(if $(filter $(e1000e@v),3.8.4 3.8.7),@BUILDDIR@/intel-fix.sh e1000e,)
 ixgbevf@prepare := $(if $(filter $(ixgbevf@v),4.7.1 4.8.1 4.9.3 4.10.2 4.11.1 4.12.4 4.13.3 4.14.5 4.15.1),@BUILDDIR@/intel-fix.sh ixgbevf,)
 ixgbe@prepare := $(if $(filter $(ixgbe@v),5.8.1 5.9.4 5.10.2 5.11.3 5.12.5 5.13.4),@BUILDDIR@/intel-fix.sh ixgbe,)
-i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3 2.22.8),@BUILDDIR@/intel-fix.sh i40e,)
+i40e@prepare := $(if $(filter $(i40e@v),2.12.6 2.14.13 2.15.9 2.16.11 2.17.4 2.17.15 2.18.9 2.19.3),@BUILDDIR@/intel-fix.sh i40e,)
 ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7 1.9.11 1.10.1.2 1.10.1.2.2),@BUILDDIR@/intel-fix.sh ice,)
 
 # some additional, driver-specific configuration

From 4668b92211d4d41f9ac87e30f66634e91703fe72 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Apr 2023 18:03:53 +0200
Subject: [PATCH 2099/2207] linux/i40e: patch for Intel 2.22.18 version

---
 LINUX/final-patches/intel--i40e--2.22.18 | 173 +++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.22.18

diff --git a/LINUX/final-patches/intel--i40e--2.22.18 b/LINUX/final-patches/intel--i40e--2.22.18
new file mode 100644
index 000000000..fc1eec6b2
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.22.18
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index ac4e0ca..aecc31e 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index cd83ec2..44a23a2 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -161,6 +161,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4154,6 +4159,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4282,6 +4291,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4310,6 +4323,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15711,6 +15729,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16104,6 +16128,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 31f9819..7e6dabe 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -981,6 +985,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2948,7 +2957,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif

From a5fac12d23e391da476eafbdd300a44fc1e5336a Mon Sep 17 00:00:00 2001
From: Jose Luis Duran 
Date: Wed, 19 Apr 2023 19:53:48 +0000
Subject: [PATCH 2100/2207] Fix compilation on some 32-bit platforms

The type of tv_sec is time_t, which is 32-bit on some platforms.
The type of tv_nsec is long (long long only since C23).

When building the port net/pkt-gen without this patch, a package fallout
occurs.

Cast to an intmax_t to avoid the warning/error, given -Werror (NB: The
original patch in the net/pkt-gen port used a long long, we opted for an
intmax_t instead).

See the aftermath of bug report #270440 for further details.
---
 apps/pkt-gen/pkt-gen.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 296208018..3bfb79a08 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -3284,8 +3284,8 @@ main(int arc, char **argv)
 		g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000;
 	}
 	if (g.td_type == TD_TYPE_SENDER)
-	    D("Sending %d packets every  %ld.%09ld s",
-			g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec);
+	    D("Sending %d packets every  %jd.%09ld s",
+			g.burst, (intmax_t)g.tx_period.tv_sec, g.tx_period.tv_nsec);
 	/* Install ^C handler. */
 	global_nthreads = g.nthreads;
 	sigemptyset(&ss);

From 7a299222efc0c77621ff65048c358f8bd98f11d5 Mon Sep 17 00:00:00 2001
From: Jose Luis Duran 
Date: Thu, 20 Apr 2023 06:53:28 +0000
Subject: [PATCH 2101/2207] apps: Import man page changes, mostly from FreeBSD

For bridge.8 and nmreplay.8, sync with FreeBSD.

For pkt-gen.8:

Chiefly, change .Ar (argument) macros with .Cm (command modifier).

Per mdoc(7):

> The arguments to the Ar macro are names and placeholders for command
> arguments; for fixed strings to be passed verbatim as arguments, use Fl
> or Cm.

Also, split a long command line.

For lb.8, leave as is, given FreeBSD renamed vale-ctl to valectl.
---
 apps/bridge/bridge.8     | 17 +++++++++++++++-
 apps/nmreplay/nmreplay.8 | 25 ++++++++++-------------
 apps/pkt-gen/pkt-gen.8   | 44 +++++++++++++++++++++-------------------
 3 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/apps/bridge/bridge.8 b/apps/bridge/bridge.8
index 9ba4cb73a..b6314ece6 100644
--- a/apps/bridge/bridge.8
+++ b/apps/bridge/bridge.8
@@ -23,7 +23,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 23, 2018
+.Dd November 21, 2020
 .Dt BRIDGE 8
 .Os
 .Sh NAME
@@ -49,6 +49,20 @@ forwards packets without copying the packets payload (zero-copy mode), unless
 explicitly prevented by the
 .Fl c
 flag.
+.Pp
+When bridging two physical ports, it is necessary that both NICS are in
+promiscuous mode, otherwise unicast traffic directed to other hosts will
+be dropped by the hardware, and bridging will not work.
+.Pp
+When bridging the hardware rings of a physical port with the corresponding
+host rings, it is necessary to turn off the offloads, because netmap does
+not prepare the NIC rings with offload information.
+Example:
+.Bd -literal -offset indent
+ifconfig em0 -rxcsum -txcsum -tso4 -tso6 -lro
+.Ed
+.Pp
+Available options:
 .Bl -tag -width Ds
 .It Fl i Ar port
 Name of the netmap port.
@@ -71,6 +85,7 @@ Disable zero-copy mode.
 .El
 .Sh SEE ALSO
 .Xr netmap 4 ,
+.Xr lb 8 ,
 .Xr pkt-gen 8
 .Sh AUTHORS
 .An -nosplit
diff --git a/apps/nmreplay/nmreplay.8 b/apps/nmreplay/nmreplay.8
index 5279af8bf..8b7ffae5a 100644
--- a/apps/nmreplay/nmreplay.8
+++ b/apps/nmreplay/nmreplay.8
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 16, 2016
+.Dd December 21, 2018
 .Dt NMREPLAY 8
 .Os
 .Sh NAME
@@ -43,6 +43,8 @@
 .Op Fl w Ar wait-link
 .Op Fl v
 .Op Fl C Ar cpu-placement
+.El
+.Ek
 .Sh DESCRIPTION
 .Nm
 works like
@@ -62,7 +64,8 @@ Command line options are as follows
 .It Fl f Ar pcap-file
 Name of the pcap file to replay.
 .It Fl i Ar interface
-Name of the netmap interface to use as output. See
+Name of the netmap interface to use as output.
+See
 .Xr netmap 4
 for interface name format.
 .It Fl v
@@ -73,7 +76,7 @@ Maximum batch size to use during transmissions.
 normally transmits packets one at a time, but it may use
 larger batches, up to the value specified with this option,
 when running at high rates.
-.It Fl B Ar bps | Cm constant, Ns Ar bps | Cm ether, Ns Ar bps | Cm real Ns Op , Ns Ar speedup
+.It Fl B Ar bps | Cm constant , Ns Ar bps | Cm ether , Ns Ar bps | Cm real Ns Op , Ns Ar speedup
 Bandwidth to be used for transmission.
 .Ar bps
 is a floating point number optionally follow by a character
@@ -87,11 +90,12 @@ indicates that the ethernet framing (160 bits) and CRC (32 bits)
 will be included in the computation of the packet size.
 .Cm real
 means transmission will occur according to the timestamps
-recorded in the trace. The optional
+recorded in the trace.
+The optional
 .Ar speedup
 multiplier (defaults to 1) indicates how much faster
 or slower than real time the trace should be replayed.
-.It Fl D Ar dt | Cm constant, Ns Ar dt | Cm uniform, Ns Ar dmin,dmax | Cm exp, Ar dmin,davg
+.It Fl D Ar dt | Cm constant , Ns Ar dt | Cm uniform , Ns Ar dmin,dmax | Cm exp , Ar dmin,davg
 Adds additional delay to the packet transmission, whose distribution
 can be constant, uniform or exponential.
 .Ar dt, dmin, dmax, avt
@@ -100,7 +104,7 @@ by a character (s, m, u, n) to indicate seconds, milliseconds,
 microseconds, nanoseconds.
 The delay is added to the transmit time and adjusted so that there is
 never packet reordering.
-.It Fl L Ar x | Cm plr, Ns Ar x | Cm ber, Ns Ar x
+.It Fl L Ar x | Cm plr , Ns Ar x | Cm ber , Ns Ar x
 Simulates packet or bit errors, causing offending packets to be dropped.
 .Ar x
 is a floating point number indicating the packet or bit error rate.
@@ -115,14 +119,7 @@ creates an in-memory schedule with all packets to be transmitted,
 and then launches a separate thread to take care of transmissions
 while the main thread reports statistics every second.
 .Sh SEE ALSO
-.Pa http://info.iet.unipi.it/~luigi/netmap/
-.Pp
-Luigi Rizzo, Revisiting network I/O APIs: the netmap framework,
-Communications of the ACM, 55 (3), pp.45-51, March 2012
-.Pp
-Luigi Rizzo, Giuseppe Lettieri,
-VALE, a switched ethernet for virtual machines,
-ACM CoNEXT'12, December 2012, Nice
+.Xr netmap 4
 .Sh AUTHORS
 .An -nosplit
 .Nm
diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
index 2d5365884..2a80f160b 100644
--- a/apps/pkt-gen/pkt-gen.8
+++ b/apps/pkt-gen/pkt-gen.8
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 25, 2018
+.Dd April 21, 2023
 .Dt PKT-GEN 8
 .Os
 .Sh NAME
@@ -84,28 +84,28 @@ library function, as documented in
 The function to be executed by
 .Nm .
 Specify
-.Ar tx
+.Cm tx
 for transmission,
-.Ar rx
+.Cm rx
 for reception,
-.Ar ping
+.Cm ping
 for client-side ping-pong operation, and
-.Ar pong
+.Cm pong
 for server-side ping-pong operation.
 .It Fl n Ar count
 Number of iterations of the
 .Nm
 function (with 0 meaning infinite).
 In case of
-.Ar tx
+.Cm tx
 or
-.Ar rx ,
+.Cm rx ,
 .Ar count
 is the number of packets to receive or transmit.
 In case of
-.Ar ping
+.Cm ping
 or
-.Ar pong ,
+.Cm pong ,
 .Ar count
 is the number of ping-pong transactions.
 .It Fl l Ar pkt_size
@@ -144,9 +144,9 @@ to handle all the netmap rings.
 If
 .Ar threads
 is larger than one, each thread handles a single TX ring (in
-.Ar tx
+.Cm tx
 mode), a single RX ring (in
-.Ar rx
+.Cm rx
 mode), or a TX/RX ring pair.
 The number of
 .Ar threads
@@ -175,7 +175,8 @@ so this option should be used unless your intention is to saturate the link.
 .It Fl X
 Dump payload of each packet transmitted or received.
 .It Fl H Ar len
-Add empty virtio-net-header with size 'len'.
+Add empty virtio-net-header with size
+.Ar len .
 Valid sizes are 0, 10 and 12.
 This option is only used with Virtual Machine technologies that use virtio
 as a network interface.
@@ -218,7 +219,7 @@ examined.
 Increase the verbosity level.
 .It Fl r
 In
-.Ar tx
+.Cm tx
 mode, do not initialize packets, but send whatever the content of
 the uninitialized netmap buffers is (rubbish mode).
 .It Fl A
@@ -227,13 +228,13 @@ transmit or receive rate.
 .It Fl B
 Take Ethernet framing and CRC into account when computing the average bps.
 This adds 4 bytes of CRC and 20 bytes of framing to each packet.
-.It Fl C Ar tx_slots[,rx_slots[,tx_rings[,rx_rings]]]
+.It Fl C Ar tx_slots Ns Oo Cm \&, Ns Ar rx_slots Ns Oo Cm \&, Ns Ar tx_rings Ns Oo Cm \&, Ns Ar rx_rings Oc Oc Oc
 Configuration in terms of number of rings and slots to be used when
 opening the netmap port.
 Such configuration has an effect on software ports
 created on the fly, such as VALE ports and netmap pipes.
 The configuration may consist of 1 to 4 numbers separated by commas:
-.Ar tx_slots , rx_slots , tx_rings , rx_rings .
+.Dq tx_slots,rx_slots,tx_rings,rx_rings .
 Missing numbers or zeroes stand for default values.
 As an additional convenience, if exactly one number is specified,
 then this is assigned to both
@@ -278,17 +279,18 @@ Capture and count all packets arriving on the operating system's cxl0
 interface.
 Using this will block packets from reaching the operating
 system's network stack.
-.Pp
-.Nm
--i cxl0 -f rx
+.Bd -literal -offset indent
+pkt-gen -i cxl0 -f rx
+.Ed
 .Pp
 Send a stream of fake DNS packets between two hosts with a packet
 length of 128 bytes.
 You must set the destination MAC address for
 packets to be received by the target host.
-.Pp
-.Nm
--i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 -D 00:07:43:29:2a:e0
+.Bd -literal -offset indent
+pkt-gen -i netmap:ncxl0 -f tx -s 172.16.0.1:53 -d 172.16.1.3:53 \e
+-D 00:07:43:29:2a:e0
+.Ed
 .Sh SEE ALSO
 .Xr netmap 4 ,
 .Xr bridge 8

From 9620282c04af3c60d51a0299b55c0c6cbd567dd2 Mon Sep 17 00:00:00 2001
From: Jose Luis Duran 
Date: Fri, 21 Apr 2023 17:25:56 +0000
Subject: [PATCH 2102/2207] pkt-gen: Silence an unused parameter warning

Related to:	#912
---
 apps/pkt-gen/pkt-gen.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 2942c1570..621e3e215 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -1008,7 +1008,7 @@ update_addresses(struct pkt *pkt, struct targ *t)
 }
 
 static void
-update_ip_size(struct pkt *pkt, struct targ *t, int size)
+update_ip_size(struct pkt *pkt, int size)
 {
 	struct ip ip;
 	struct udphdr udp;
@@ -1045,7 +1045,7 @@ update_ip_size(struct pkt *pkt, struct targ *t, int size)
 }
 
 static void
-update_ip6_size(struct pkt *pkt, struct targ *t, int size)
+update_ip6_size(struct pkt *pkt, int size)
 {
 	struct ip6_hdr ip6;
 	struct udphdr udp;
@@ -1079,9 +1079,9 @@ update_size(struct pkt *pkt, struct targ *t, int size)
 {
 	if (t->g->options & OPT_UPDATE_CSUM) {
 		if (t->g->af == AF_INET)
-			update_ip_size(pkt, t, size);
+			update_ip_size(pkt, size);
 		else
-			update_ip6_size(pkt, t, size);
+			update_ip6_size(pkt, size);
 	}
 }
 

From 242e3c3ea0115aeb69db39c00a6ee8268f5ab2c8 Mon Sep 17 00:00:00 2001
From: Michio Honda 
Date: Sun, 23 Apr 2023 21:30:38 +0100
Subject: [PATCH 2103/2207] linux/ice: vanilla driver support

Tested in Linux 5.8 and 6.2.
---
 LINUX/configure                               |  15 ++
 .../final-patches/vanilla--ice--20620--99999  | 131 ++++++++++++++++++
 LINUX/ice_netmap_linux.h                      |  39 ++++--
 3 files changed, 171 insertions(+), 14 deletions(-)
 create mode 100644 LINUX/final-patches/vanilla--ice--20620--99999

diff --git a/LINUX/configure b/LINUX/configure
index c007a2b3c..5be382360 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2343,6 +2343,21 @@ EOF
 EOF
   fi # i40e
 
+  if drv enabled ice; then
+    add_test 'have ICE_XRINGS' <tx_rings[0];
+	}
+	struct ice_rx_ring *
+	dummy2(struct ice_vsi *vsi) {
+		return vsi->rx_rings[0];
+	}
+EOF
+  fi # ice
+
   if drv enabled igb; then
     add_test 'have IGB_RD32' <
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -448,6 +453,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -565,6 +574,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -831,6 +845,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 8ec24f6cf6be..49e1c1f37cc4 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -48,6 +48,11 @@ static DEFINE_IDA(ice_aux_ida);
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -4980,6 +4985,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	}
+ 
+ 	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_init_aux_unroll:
+@@ -5085,6 +5094,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	ice_devlink_unregister(pf);
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 086f0b3ab68d..37d1734da9da 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -23,6 +23,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -1120,6 +1128,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index 9d1bf3f61..212f6c6bb 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -1,6 +1,13 @@
 #include 
 #include 
 #include 
+#ifdef NETMAP_LINUX_HAVE_ICE_XRINGS
+#define NM_ICE_RXRING ice_rx_ring
+#define NM_ICE_TXRING ice_tx_ring
+#else
+#define NM_ICE_RXRING ice_ring
+#define NM_ICE_TXRING ice_ring
+#endif /* NETMAP_LINUX_HAVE_ICE_XRINGS */
 
 extern int ix_crcstrip;
 
@@ -41,7 +48,7 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
 	/* device-specific */
 	struct ice_netdev_priv *np = netdev_priv(ifp);
 	struct ice_vsi *vsi = np->vsi;
-	struct ice_ring *txr;
+	struct NM_ICE_TXRING *txr;
 
 	if (!netif_carrier_ok(ifp))
 		return 0;
@@ -213,7 +220,7 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 	/* device-specific */
 	struct ice_netdev_priv *np = netdev_priv(ifp);
 	struct ice_vsi *vsi = np->vsi;
-	struct ice_ring *rxr;
+	struct NM_ICE_RXRING *rxr;
 
 	if (!netif_running(ifp))
 		return 0;
@@ -258,9 +265,7 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 
 		for (n = 0; ; n++) {
 			union ice_32b_rx_flex_desc *curr = ICE_RX_DESC(rxr, nic_i);
-			uint64_t qword = le64toh(*(uint64_t*)&curr->wb.status_error0);
-			uint32_t staterr = (qword & ICE_RXD_QW1_STATUS_M)
-				 >> ICE_RXD_QW1_STATUS_S;
+			uint16_t stat_err_bits;
 		        uint16_t slot_flags = 0;
 			struct netmap_slot *slot;
 			uint64_t paddr;
@@ -270,18 +275,24 @@ ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 				complete = 0;
 			}
 
-			if ((staterr & (1<wb.status_error0 &
+			    cpu_to_le16(stat_err_bits)) == 0)
 				break;
-			}
 			dma_rmb();
 			slot = ring->slot + nm_i;
-			slot->len = (le16_to_cpu(curr->wb.pkt_len) & ICE_RX_FLX_DESC_PKT_LEN_M) - crclen;
+			slot->len = (le16_to_cpu(curr->wb.pkt_len) &
+					ICE_RX_FLX_DESC_PKT_LEN_M) - crclen;
 
-			if (unlikely((staterr & (1<wb.status_error0 &
+			    cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S)))) {
 				complete = 1;
+			} else {
+				slot_flags = NS_MOREFRAG;
 			}
+
 			slot->flags = slot_flags;
 			PNMB_O(kring, slot, &paddr);
 			netmap_sync_map_cpu(na, (bus_dma_tag_t) na->pdev,
@@ -493,7 +504,7 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip,
 		CTLFLAG_RW, &ix_crcstrip, 1, "NIC strips CRC on rx frames");
 
 static void
-ice_netmap_configure_tx_ring(struct ice_ring *ring)
+ice_netmap_configure_tx_ring(struct NM_ICE_TXRING *ring)
 {
 	struct netmap_adapter *na;
 
@@ -507,7 +518,7 @@ ice_netmap_configure_tx_ring(struct ice_ring *ring)
 }
 
 static void
-ice_netmap_preconfigure_rx_ring(struct ice_ring *ring,
+ice_netmap_preconfigure_rx_ring(struct NM_ICE_RXRING *ring,
 		struct ice_rlan_ctx *rx_ctx)
 {
 	struct netmap_adapter *na;
@@ -528,7 +539,7 @@ ice_netmap_preconfigure_rx_ring(struct ice_ring *ring,
 }
 
 static int
-ice_netmap_configure_rx_ring(struct ice_ring *ring)
+ice_netmap_configure_rx_ring(struct NM_ICE_RXRING *ring)
 {
 	struct netmap_adapter *na;
 	struct netmap_slot *slot;

From b58a473becf02c03db4504bbd66987ef5b2fc3d8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 24 Apr 2023 20:13:54 +0200
Subject: [PATCH 2104/2207] linux/ice: limit patch applicability

---
 .../final-patches/vanilla--ice--50d00--50e00  | 129 +++++++++++++++++
 .../final-patches/vanilla--ice--50e00--51000  | 128 +++++++++++++++++
 .../final-patches/vanilla--ice--51000--51100  | 130 ++++++++++++++++++
 .../final-patches/vanilla--ice--51100--51200  | 130 ++++++++++++++++++
 ...0620--99999 => vanilla--ice--51300--60300} |  22 +--
 5 files changed, 528 insertions(+), 11 deletions(-)
 create mode 100644 LINUX/final-patches/vanilla--ice--50d00--50e00
 create mode 100644 LINUX/final-patches/vanilla--ice--50e00--51000
 create mode 100644 LINUX/final-patches/vanilla--ice--51000--51100
 create mode 100644 LINUX/final-patches/vanilla--ice--51100--51200
 rename LINUX/final-patches/{vanilla--ice--20620--99999 => vanilla--ice--51300--60300} (84%)

diff --git a/LINUX/final-patches/vanilla--ice--50d00--50e00 b/LINUX/final-patches/vanilla--ice--50d00--50e00
new file mode 100644
index 000000000..354388294
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--50d00--50e00
@@ -0,0 +1,129 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 5985a7e5ca8a..7db16b634a4e 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -5,6 +5,10 @@
+ #include "ice_base.h"
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -424,6 +428,10 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -476,6 +484,11 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -728,6 +741,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 0eb2307325d3..41b3bb90bd8b 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -35,6 +35,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -4282,6 +4287,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 
+ 	/* ready to go, so clear down state bit */
+ 	clear_bit(ICE_DOWN, pf->state);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_netdev_reg:
+@@ -4382,6 +4391,9 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 04748aa4c7c8..b02a895af69e 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -18,6 +18,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -208,6 +212,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buf = &tx_ring->tx_buf[i];
+ 	tx_desc = ICE_TX_DESC(tx_ring, i);
+@@ -1067,6 +1075,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/final-patches/vanilla--ice--50e00--51000 b/LINUX/final-patches/vanilla--ice--50e00--51000
new file mode 100644
index 000000000..5cf2745fc
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--50e00--51000
@@ -0,0 +1,128 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index c36057efc7ae..5dec738c6fe9 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -5,6 +5,10 @@
+ #include "ice_base.h"
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -395,6 +399,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -512,6 +520,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -764,6 +777,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index fe2ded775f25..e305a1cceea6 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -43,6 +43,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ 
+ static DEFINE_IDA(ice_aux_ida);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -4497,6 +4502,9 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 		dev_warn(dev, "RDMA is not supported on this device\n");
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_init_aux_unroll:
+@@ -4600,6 +4608,9 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 6ee8e0032d52..912416091772 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -19,6 +19,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -209,6 +213,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buf = &tx_ring->tx_buf[i];
+ 	tx_desc = ICE_TX_DESC(tx_ring, i);
+@@ -1071,6 +1079,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/final-patches/vanilla--ice--51000--51100 b/LINUX/final-patches/vanilla--ice--51000--51100
new file mode 100644
index 000000000..3afd804fb
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--51000--51100
@@ -0,0 +1,130 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index fafe020e46ee..a405f76a8824 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -5,6 +5,10 @@
+ #include "ice_base.h"
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
+ 
+ static bool ice_alloc_rx_buf_zc(struct ice_rx_ring *rx_ring)
+ {
+@@ -446,6 +450,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -568,6 +576,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -834,6 +847,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 73c61cdb036f..130eaaac16a1 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -47,6 +47,11 @@ static DEFINE_IDA(ice_aux_ida);
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -4742,6 +4747,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	}
+ 
+ 	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_init_aux_unroll:
+@@ -4841,6 +4850,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	ice_devlink_unregister(pf);
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index dccf09eefc75..c62ae39cf418 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -21,6 +21,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -218,6 +222,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buf = &tx_ring->tx_buf[i];
+ 	tx_desc = ICE_TX_DESC(tx_ring, i);
+@@ -1104,6 +1112,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/final-patches/vanilla--ice--51100--51200 b/LINUX/final-patches/vanilla--ice--51100--51200
new file mode 100644
index 000000000..5352cc9e0
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--51100--51200
@@ -0,0 +1,130 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 1a5ece3bce79..b815458ab34a 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -5,6 +5,10 @@
+ #include "ice_base.h"
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
+ 
+ static bool ice_alloc_rx_buf_zc(struct ice_rx_ring *rx_ring)
+ {
+@@ -446,6 +450,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -568,6 +576,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -834,6 +847,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index b7e8744b0c0a..eecab6226fe5 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -47,6 +47,11 @@ static DEFINE_IDA(ice_aux_ida);
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -4757,6 +4762,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	}
+ 
+ 	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_init_aux_unroll:
+@@ -4857,6 +4866,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	ice_devlink_unregister(pf);
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 3e38695f1c9d..5d1e4cba1b56 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -22,6 +22,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -219,6 +223,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	if (!ice_ring_is_xdp(tx_ring))
+@@ -1112,6 +1120,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/final-patches/vanilla--ice--20620--99999 b/LINUX/final-patches/vanilla--ice--51300--60300
similarity index 84%
rename from LINUX/final-patches/vanilla--ice--20620--99999
rename to LINUX/final-patches/vanilla--ice--51300--60300
index 7c7da9246..cbbcc9dc9 100644
--- a/LINUX/final-patches/vanilla--ice--20620--99999
+++ b/LINUX/final-patches/vanilla--ice--51300--60300
@@ -1,5 +1,5 @@
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index 554095b25f44..c39b1555ce5e 100644
+index 136d7911adb4..a9caf17a5160 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -12,9 +12,9 @@ index 554095b25f44..c39b1555ce5e 100644
 +#endif
 +
  
- /**
-  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
-@@ -448,6 +453,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ static bool ice_alloc_rx_buf_zc(struct ice_rx_ring *rx_ring)
+ {
+@@ -461,6 +466,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
  	/* Rx queue threshold in units of 64 */
  	rlan_ctx.lrxqthresh = 1;
  
@@ -25,7 +25,7 @@ index 554095b25f44..c39b1555ce5e 100644
  	/* Enable Flexible Descriptors in the queue context which
  	 * allows this driver to select a specific receive descriptor format
  	 * increasing context priority to pick up profile ID; default is 0x01;
-@@ -565,6 +574,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+@@ -583,6 +592,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
  		return 0;
  	}
  
@@ -37,7 +37,7 @@ index 554095b25f44..c39b1555ce5e 100644
  	ice_alloc_rx_bufs(ring, num_bufs);
  
  	return 0;
-@@ -831,6 +845,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+@@ -849,6 +863,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
  	if (pf_q == le16_to_cpu(txq->txq_id))
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
  
@@ -49,7 +49,7 @@ index 554095b25f44..c39b1555ce5e 100644
  }
  
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index 8ec24f6cf6be..49e1c1f37cc4 100644
+index 9f02b60459f1..0186182d5e16 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -48,6 +48,11 @@ static DEFINE_IDA(ice_aux_ida);
@@ -64,7 +64,7 @@ index 8ec24f6cf6be..49e1c1f37cc4 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -4980,6 +4985,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+@@ -4872,6 +4877,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
  	}
  
  	ice_devlink_register(pf);
@@ -75,7 +75,7 @@ index 8ec24f6cf6be..49e1c1f37cc4 100644
  	return 0;
  
  err_init_aux_unroll:
-@@ -5085,6 +5094,10 @@ static void ice_remove(struct pci_dev *pdev)
+@@ -4972,6 +4981,10 @@ static void ice_remove(struct pci_dev *pdev)
  	struct ice_pf *pf = pci_get_drvdata(pdev);
  	int i;
  
@@ -87,7 +87,7 @@ index 8ec24f6cf6be..49e1c1f37cc4 100644
  	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
  		if (!ice_is_reset_in_progress(pf->state))
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 086f0b3ab68d..37d1734da9da 100644
+index 836dce840712..b5a272c8cfe4 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -23,6 +23,10 @@
@@ -112,7 +112,7 @@ index 086f0b3ab68d..37d1734da9da 100644
  
  	/* get the bql data ready */
  	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
-@@ -1120,6 +1128,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+@@ -1117,6 +1125,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
  	struct xdp_buff xdp;
  	bool failure;
  

From 659604ecdc53f43d8c5329a1744c99e0aac5ec94 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 19 May 2023 08:28:40 +0200
Subject: [PATCH 2105/2207] make sure tailroom is sufficiently aligned in
 krings

---
 sys/dev/netmap/netmap_kern.h | 9 +++++++++
 sys/dev/netmap/netmap_vale.c | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7c68c79c6..066bb3f3b 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1501,6 +1501,15 @@ int netmap_update_config(struct netmap_adapter *na);
  * leasing-related data structures
  */
 int netmap_krings_create(struct netmap_adapter *na, u_int tailroom);
+
+/*
+ * tailroom must be properly aligned with nm_tailroom_align().
+ */
+static inline u_int
+nm_tailroom_align(u_int tr) {
+	return (tr + 15) & ~15U;
+}
+
 /* deletes the kring array of the adapter. The array must have
  * been created using netmap_krings_create
  */
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index f5e65f1c0..fd4682751 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -436,7 +436,7 @@ netmap_vale_vp_krings_create(struct netmap_adapter *na)
 	/*
 	 * Leases are attached to RX rings on vale ports
 	 */
-	tailroom = sizeof(uint32_t) * na->num_rx_desc * nrx;
+	tailroom = nm_tailroom_align(sizeof(uint32_t) * na->num_rx_desc * nrx);
 
 	error = netmap_krings_create(na, tailroom);
 	if (error)

From 541e6bdf7d0927584e3467eecf3fb1ff2fb0d43e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 19 May 2023 14:21:15 +0200
Subject: [PATCH 2106/2207] fd_server: fix uninitialized variable

Fixes #920 on github.
---
 utils/fd_server.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/fd_server.c b/utils/fd_server.c
index 61a0dc9fc..fa0db1c9b 100644
--- a/utils/fd_server.c
+++ b/utils/fd_server.c
@@ -122,6 +122,7 @@ get_fd(const char *if_name, struct fd_response *res)
 		}
 		if (marshal(res, entry) < 0)
 			return -1;
+		res->result = 0;
 		return entry->nmd->fd;
 	}
 

From 793bce98e614c694b71bb685a3c4188de5456ef7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 22 May 2023 14:29:17 +0200
Subject: [PATCH 2107/2207] make sure krings are aligned to cachelines

---
 sys/dev/netmap/netmap.c      | 13 +++++++++----
 sys/dev/netmap/netmap_kern.h | 11 ++++++-----
 sys/dev/netmap/netmap_vale.c |  2 +-
 3 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 59533db53..744ad2887 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -837,6 +837,10 @@ netmap_default_bufcfg(struct netmap_kring *kring, uint64_t target)
  *                    |          |  } tailroom bytes
  *                    |          | /
  *                    +----------+
+ * netmap_kring       |          | (aligned to NM_KRING_ALIGNMENT)
+ * structs            ~          ~
+ *                    |          |
+ *                    +----------+
  *
  * Note: for compatibility, host krings are created even when not needed.
  * The tailroom space is currently used by vale ports for allocating leases.
@@ -861,9 +865,9 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	n[NR_TX] = netmap_all_rings(na, NR_TX);
 	n[NR_RX] = netmap_all_rings(na, NR_RX);
 
-	len = (n[NR_TX] + n[NR_RX]) *
-		(sizeof(struct netmap_kring) + sizeof(struct netmap_kring *))
-		+ tailroom;
+	len = nm_tailroom_align((n[NR_TX] + n[NR_RX]) *
+		sizeof(struct netmap_kring *) + tailroom) +
+		(n[NR_TX] + n[NR_RX]) * sizeof(struct netmap_kring);
 
 	na->tx_rings = nm_os_malloc((size_t)len);
 	if (na->tx_rings == NULL) {
@@ -874,7 +878,8 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	na->tailroom = na->rx_rings + n[NR_RX];
 
 	/* link the krings in the krings array */
-	kring = (struct netmap_kring *)((char *)na->tailroom + tailroom);
+	kring = (struct netmap_kring *)
+		nm_tailroom_align((uint64_t)((char *)na->tailroom + tailroom));
 	for (i = 0; i < n[NR_TX] + n[NR_RX]; i++) {
 		na->tx_rings[i] = kring;
 		kring++;
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 066bb3f3b..669048f17 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -407,6 +407,7 @@ struct netmap_zmon_list {
  * RX rings attached to the VALE switch are accessed by both senders
  * and receiver. They are protected through the q_lock on the RX ring.
  */
+#define NM_KRING_ALIGNMENT 64
 struct netmap_kring {
 	struct netmap_ring	*ring;
 
@@ -584,9 +585,9 @@ struct netmap_kring {
 #endif
 }
 #ifdef _WIN32
-__declspec(align(64));
+__declspec(align(NM_KRING_ALIGNMENT));
 #else
-__attribute__((__aligned__(64)));
+__attribute__((__aligned__(NM_KRING_ALIGNMENT)));
 #endif
 
 /* return 1 iff the kring needs to be turned on */
@@ -1505,9 +1506,9 @@ int netmap_krings_create(struct netmap_adapter *na, u_int tailroom);
 /*
  * tailroom must be properly aligned with nm_tailroom_align().
  */
-static inline u_int
-nm_tailroom_align(u_int tr) {
-	return (tr + 15) & ~15U;
+static inline uint64_t
+nm_tailroom_align(uint64_t tr) {
+	return (tr + (NM_KRING_ALIGNMENT - 1)) & ~((uint64_t)NM_KRING_ALIGNMENT - 1);
 }
 
 /* deletes the kring array of the adapter. The array must have
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index fd4682751..f5e65f1c0 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -436,7 +436,7 @@ netmap_vale_vp_krings_create(struct netmap_adapter *na)
 	/*
 	 * Leases are attached to RX rings on vale ports
 	 */
-	tailroom = nm_tailroom_align(sizeof(uint32_t) * na->num_rx_desc * nrx);
+	tailroom = sizeof(uint32_t) * na->num_rx_desc * nrx;
 
 	error = netmap_krings_create(na, tailroom);
 	if (error)

From 369ccb9d00e73ba03cb36b1f6c7e7755ecff08d6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 24 May 2023 11:36:58 +0200
Subject: [PATCH 2108/2207] avoid possible crash while reading user rings that
 are concurrently updated

fixes #923 on github.
---
 sys/dev/netmap/netmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 744ad2887..874818dc3 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1245,16 +1245,17 @@ netmap_grab_packets(struct netmap_kring *kring, struct mbq *q, int force)
 	for (n = kring->nr_hwcur; n != head; n = nm_next(n, lim)) {
 		struct mbuf *m;
 		struct netmap_slot *slot = &kring->ring->slot[n];
+		uint16_t len = NM_ACCESS_ONCE(slot->len);
 
 		if ((slot->flags & NS_FORWARD) == 0 && !force)
 			continue;
-		if (slot->len < 14 || slot->len > NETMAP_BUF_SIZE(na)) {
-			nm_prlim(5, "bad pkt at %d len %d", n, slot->len);
+		if (len < 14 || len > NETMAP_BUF_SIZE(na)) {
+			nm_prlim(5, "bad pkt at %d len %d", n, len);
 			continue;
 		}
 		slot->flags &= ~NS_FORWARD; // XXX needed ?
 		/* XXX TODO: adapt to the case of a multisegment packet */
-		m = m_devget(NMB(na, slot), slot->len, 0, na->ifp, NULL);
+		m = m_devget(NMB(na, slot), len, 0, na->ifp, NULL);
 
 		if (m == NULL)
 			break;

From a2408e28c060dff528c2ec83006f4cf1a31ebe4e Mon Sep 17 00:00:00 2001
From: msaare123 
Date: Sat, 10 Jun 2023 13:15:47 +0300
Subject: [PATCH 2109/2207] add offset support to host rings

Slot offsets were not taken into account in host rings and caused
malformed packets were send/received to/from host network stack
when offsets were configured to NIC ring slots.
---
 sys/dev/netmap/netmap.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 874818dc3..e5f6e1f14 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1246,16 +1246,17 @@ netmap_grab_packets(struct netmap_kring *kring, struct mbq *q, int force)
 		struct mbuf *m;
 		struct netmap_slot *slot = &kring->ring->slot[n];
 		uint16_t len = NM_ACCESS_ONCE(slot->len);
+		uint64_t offset = nm_get_offset(kring, slot);
 
 		if ((slot->flags & NS_FORWARD) == 0 && !force)
 			continue;
-		if (len < 14 || len > NETMAP_BUF_SIZE(na)) {
+		if (len < 14 || len > (NETMAP_BUF_SIZE(na) - offset)) {
 			nm_prlim(5, "bad pkt at %d len %d", n, len);
 			continue;
 		}
 		slot->flags &= ~NS_FORWARD; // XXX needed ?
 		/* XXX TODO: adapt to the case of a multisegment packet */
-		m = m_devget(NMB(na, slot), len, 0, na->ifp, NULL);
+		m = m_devget(NMB_O(kring, slot), len, 0, na->ifp, NULL);
 
 		if (m == NULL)
 			break;
@@ -1407,14 +1408,14 @@ netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
 
 		nm_i = kring->nr_hwtail;
 		stop_i = nm_prev(kring->nr_hwcur, lim);
-		while ( nm_i != stop_i && (m = mbq_dequeue(q)) != NULL ) {
+		while (nm_i != stop_i && (m = mbq_dequeue(q)) != NULL) {
 			int len = MBUF_LEN(m);
 			struct netmap_slot *slot = &ring->slot[nm_i];
 
-			m_copydata(m, 0, len, NMB(na, slot));
+			m_copydata(m, 0, len, NMB_O(kring, slot));
 			nm_prdis("nm %d len %d", nm_i, len);
 			if (netmap_debug & NM_DEBUG_HOST)
-				nm_prinf("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
+				nm_prinf("%s", nm_dump_buf(NMB_O(kring, slot), len, 128, NULL));
 
 			slot->len = len;
 			slot->flags = 0;

From 1c23613c46684e55e9c5f60b55dc6de7c10de8ec Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 14 Jun 2023 16:26:28 +0200
Subject: [PATCH 2110/2207] linux/drivers: patches for latest Intel drivers

---
 LINUX/final-patches/intel--i40e--2.22.20    | 173 ++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.13.20     | 138 ++++++++++++++++
 LINUX/final-patches/intel--ixgbe--5.18.13   | 173 ++++++++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.17.13 | 169 +++++++++++++++++++
 4 files changed, 653 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.22.20
 create mode 100644 LINUX/final-patches/intel--igb--5.13.20
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.18.13
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.17.13

diff --git a/LINUX/final-patches/intel--i40e--2.22.20 b/LINUX/final-patches/intel--i40e--2.22.20
new file mode 100644
index 000000000..7904b2e3f
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.22.20
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index ac4e0ca..aecc31e 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 996a4c0..707fa4e 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -161,6 +161,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4154,6 +4159,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4282,6 +4291,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4310,6 +4323,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15720,6 +15738,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16113,6 +16137,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 31f9819..7e6dabe 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -981,6 +985,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2948,7 +2957,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--igb--5.13.20 b/LINUX/final-patches/intel--igb--5.13.20
new file mode 100644
index 000000000..ba4f3d1c7
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.13.20
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index e761697..38767eb 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index ca98377..9766c5c 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3238,6 +3242,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3443,6 +3451,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3857,6 +3869,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7431,6 +7446,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8447,6 +8467,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8766,6 +8791,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.18.13 b/LINUX/final-patches/intel--ixgbe--5.18.13
new file mode 100644
index 000000000..d2928d78e
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.18.13
@@ -0,0 +1,173 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 884cbf7..4ffc802 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,24 +29,24 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -119,9 +119,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index df8e130..6c2dc2b 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -719,6 +719,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+  * @q_vector: structure containing interrupt and ring information
+@@ -738,6 +755,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2229,6 +2257,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3742,6 +3780,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4434,6 +4476,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13250,6 +13298,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13306,6 +13358,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.17.13 b/LINUX/final-patches/intel--ixgbevf--4.17.13
new file mode 100644
index 000000000..c4b8707e5
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.17.13
@@ -0,0 +1,169 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index df6689d..03ce8eb 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 2102b94..b2a0f4e 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -344,6 +344,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -364,6 +381,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1382,6 +1410,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2100,6 +2138,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2334,6 +2376,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5642,8 +5688,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5684,6 +5732,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 7d1bb06..29a4e15 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -5,6 +5,9 @@
+ #define _KCOMPAT_H_
+ 
+ #include "kcompat_gcc.h"
++
++#include 
++
+ #ifndef LINUX_VERSION_CODE
+ #include 
+ #else

From 237d6b8485f92de506f8876a37e5a1087b33d6e6 Mon Sep 17 00:00:00 2001
From: msaare123 
Date: Thu, 15 Jun 2023 22:31:43 +0300
Subject: [PATCH 2111/2207] Make VLAN tags visible to Linux generic adapter

Push tag in skb metadata back to payload so it will be visible in
rx ring
---
 LINUX/netmap_linux.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e36ab2de6..144491b83 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -550,6 +550,11 @@ linux_generic_rx_handler_common(struct mbuf *m)
 	   can see it. */
 	skb_push(m, ETH_HLEN);
 
+	/* First VLAN tag has been already popped to skb metadata. */
+	if (skb_vlan_tag_present(m)) {
+		m = __vlan_hwaccel_push_inside(m);
+	}
+
 	/* Possibly steal the mbuf and notify the pollers for a new RX
 	 * packet. */
 	stolen = generic_rx_handler(m->dev, m);
@@ -557,6 +562,11 @@ linux_generic_rx_handler_common(struct mbuf *m)
 		return NM_RX_HANDLER_STOLEN;
 	}
 
+	/* Untag once again if not stolen */
+	if (eth_type_vlan(m->protocol)) {
+		m = skb_vlan_untag(m);
+	}
+
 	skb_pull(m, ETH_HLEN);
 
 	return NM_RX_HANDLER_PASS;

From 4dfedf40ffadd83942bb9b4156db283981ddf4a8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 27 Jun 2023 20:40:52 +0200
Subject: [PATCH 2112/2207] tests: fix for #928

---
 utils/tests/008_partial_read_pipe_test | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/tests/008_partial_read_pipe_test b/utils/tests/008_partial_read_pipe_test
index 7e8ec038b..058421747 100755
--- a/utils/tests/008_partial_read_pipe_test
+++ b/utils/tests/008_partial_read_pipe_test
@@ -58,7 +58,7 @@ exit_status=0
 pending_packets="$(($max_packets - $avail_packets))"
 pending_transmissions="$(($num_send - $num_recv))"
 if [ $pending_packets != $pending_transmissions ] ; then
-	exit_status = 1
+	exit_status=1
 fi
 check_exit $pending_transmissions $pending_packets "pending_transmissions=pending_packets"
 

From bd5813a69bfb14e8f5d9979e7858aa6935dccf1f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 27 Jun 2023 20:41:28 +0200
Subject: [PATCH 2113/2207] linux: patches for 6.4

---
 ...000--99999 => vanilla--i40e--51000--60400} |   0
 .../final-patches/vanilla--i40e--60400--99999 | 116 +++++++++++++++
 .../final-patches/vanilla--ice--60300--99999  | 133 ++++++++++++++++++
 ...0600--99999 => vanilla--igc--50600--60400} |   0
 4 files changed, 249 insertions(+)
 rename LINUX/final-patches/{vanilla--i40e--51000--99999 => vanilla--i40e--51000--60400} (100%)
 create mode 100644 LINUX/final-patches/vanilla--i40e--60400--99999
 create mode 100644 LINUX/final-patches/vanilla--ice--60300--99999
 rename LINUX/final-patches/{vanilla--igc--50600--99999 => vanilla--igc--50600--60400} (100%)

diff --git a/LINUX/final-patches/vanilla--i40e--51000--99999 b/LINUX/final-patches/vanilla--i40e--51000--60400
similarity index 100%
rename from LINUX/final-patches/vanilla--i40e--51000--99999
rename to LINUX/final-patches/vanilla--i40e--51000--60400
diff --git a/LINUX/final-patches/vanilla--i40e--60400--99999 b/LINUX/final-patches/vanilla--i40e--60400--99999
new file mode 100644
index 000000000..57bde714b
--- /dev/null
+++ b/LINUX/final-patches/vanilla--i40e--60400--99999
@@ -0,0 +1,116 @@
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index b847bd105b16..605cc4551b5e 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -100,6 +100,10 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+ MODULE_LICENSE("GPL v2");
+ 
+ static struct workqueue_struct *i40e_wq;
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
+ 
+ static void netdev_hw_addr_refcnt(struct i40e_mac_filter *f,
+ 				  struct net_device *netdev, int delta)
+@@ -3548,6 +3552,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -3644,6 +3652,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -3680,6 +3692,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->xsk_pool) {
+ 		xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+ 		ok = i40e_alloc_rx_buffers_zc(ring, I40E_DESC_UNUSED(ring));
+@@ -14209,6 +14226,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 		return -ENODEV;
+ 	}
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -14577,6 +14600,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index 8b8bf4880faa..c0aa5b742342 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -11,6 +11,10 @@
+ #include "i40e_txrx_common.h"
+ #include "i40e_xsk.h"
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -938,6 +942,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2503,6 +2512,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
+ 	bool failure = false;
+ 	int xdp_res = 0;
+ 
++#ifdef DEV_NETMAP
++	int dummy;
++	if (rx_ring->netdev &&
++	    netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+ 
+ 	while (likely(total_rx_packets < (unsigned int)budget)) {
diff --git a/LINUX/final-patches/vanilla--ice--60300--99999 b/LINUX/final-patches/vanilla--ice--60300--99999
new file mode 100644
index 000000000..ca0781998
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--60300--99999
@@ -0,0 +1,133 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 1911d644dfa8..366a70eda634 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -445,6 +450,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -568,6 +577,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -834,6 +848,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 0d8b8c6f9bd3..b58bc2ce4b95 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -48,6 +48,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5055,6 +5060,12 @@ static int ice_init(struct ice_pf *pf)
+ 	/* since everything is good, start the service timer */
+ 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ 
++	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_link:
+@@ -5318,6 +5329,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 4fcf2d07eb85..0ad1b7528bfb 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -23,6 +23,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -1162,6 +1170,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	bool failure;
+ 	u32 first;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	xdp->frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/final-patches/vanilla--igc--50600--99999 b/LINUX/final-patches/vanilla--igc--50600--60400
similarity index 100%
rename from LINUX/final-patches/vanilla--igc--50600--99999
rename to LINUX/final-patches/vanilla--igc--50600--60400

From 1ab3b78fa2ea5f9b6132a8447a38e4485a010095 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 5 Jul 2023 23:30:08 +0200
Subject: [PATCH 2114/2207] linux/scripts: add workaround for GNU make quoted
 pound

---
 LINUX/scripts/np | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 073e187ac..c0da6d371 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -377,6 +377,10 @@ function build-prep()
 
 	(
 		cd $dst
+		# fix for incompatible GNU make change
+		sed -i -e '/^squote/a\
+pound	:= \\#
+			/\/{s/\\#/$(pound)/}' tools/build/Build.include || true
 		last=compiler-gcc.h
 		for i in $(seq 12); do
 			[ -e include/linux/compiler-gcc$i.h ] ||

From 308ab59aee089f6b230ab624e4a3b6c0f3c0790c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Jul 2023 00:00:30 +0200
Subject: [PATCH 2115/2207] linux/scripts: more robust test for refcount

---
 LINUX/configure | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 5be382360..1ebea1643 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1688,8 +1688,7 @@ EOF
 	#include 
 
 	unsigned int
-	dummy(void) {
-                struct sk_buff *skb = NULL;
+	dummy(struct sk_buff *skb) {
                 return refcount_read(&skb->users);
 	}
 EOF

From b65eeae30e847d3ed9acabf4f4c0f0070077df72 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 6 Jul 2023 10:53:45 +0200
Subject: [PATCH 2116/2207] linux/configure: check for eth_type_vlan

---
 LINUX/bsd_glue.h | 8 ++++++++
 LINUX/configure  | 9 +++++++++
 2 files changed, 17 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 002c0edc9..684fa2f9f 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -190,6 +190,14 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb) {
 #define page_to_virt(p) 		phys_to_virt(page_to_phys(p))
 #endif /* NETMAP_LINUX_HAVE_PAGE_TO_VIRT */
 
+#ifndef NETMAP_LINUX_HAVE_ETH_TYPE_VLAN
+static inline bool eth_type_vlan(__be16 ethertype)
+{
+	return ethertype == htons(ETH_P_8021Q) ||
+		ethertype == htons(ETH_P_8021AD);
+}
+#endif /* NETMAP_LINUX_HAVE_ETH_TYPE_VLAN */
+
 /*----------- end of LINUX_VERSION_CODE dependencies ----------*/
 
 /* Type redefinitions. XXX check them */
diff --git a/LINUX/configure b/LINUX/configure
index 1ebea1643..15f3d187b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1895,6 +1895,15 @@ EOF
 	}
 EOF
 
+  # eth_type_vlan?
+  add_test 'have ETH_TYPE_VLAN' <
+
+	bool dummy(__be16 ethertype) {
+		return eth_type_vlan(ethertype);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################

From d997a7a473b4a44a9bd784ac9b162043394d1abb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 8 Jul 2023 09:50:20 +0200
Subject: [PATCH 2117/2207] linux/scripts: add workaround for objtool segfault

---
 LINUX/scripts/np | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index c0da6d371..10a8a84bd 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -409,6 +409,9 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		fi
 		# old kernels' selinux causes compilation failures with gcc >= 9
 		echo "CONFIG_SECURITY_SELINUX=n" >> .config
+		# workaround for some objtool/binutils incompatibility
+		sed -i -e 's/^CONFIG_UNWINDER_ORC=/#&/' .config
+		echo "CONFIG_UNWINDER_FRAME_POINTER=y" >> .config
 		yes '' | make oldconfig
 		# some tools do not compile with -Werror and gcc >= 9
 		sed -i 's/-Werror/-Wno-error/g' $(grep -Rl -- -Werror tools)

From 974b68c0677a4db6df6a7c60555b706b3ee22a0d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 8 Jul 2023 13:35:16 +0200
Subject: [PATCH 2118/2207] linux/generic: fix compilation for old kernels

---
 LINUX/bsd_glue.h     | 18 ++++++++++++++++++
 LINUX/configure      | 27 +++++++++++++++++++++++++++
 LINUX/netmap_linux.c |  4 ++++
 3 files changed, 49 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 684fa2f9f..90b78f336 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -59,6 +59,7 @@
 #include 	// virt_to_phys
 #include 
 #include  // kmap
+#include  // tags
 
 #define KASSERT(a, b)		BUG_ON(!(a))
 
@@ -190,6 +191,7 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb) {
 #define page_to_virt(p) 		phys_to_virt(page_to_phys(p))
 #endif /* NETMAP_LINUX_HAVE_PAGE_TO_VIRT */
 
+#ifdef NETMAP_LINUX_HAVE_VLAN_UNTAG
 #ifndef NETMAP_LINUX_HAVE_ETH_TYPE_VLAN
 static inline bool eth_type_vlan(__be16 ethertype)
 {
@@ -198,6 +200,22 @@ static inline bool eth_type_vlan(__be16 ethertype)
 }
 #endif /* NETMAP_LINUX_HAVE_ETH_TYPE_VLAN */
 
+#ifndef NETMAP_LINUX_HAVE_SKB_VLAN_TAG_PRESENT
+#define skb_vlan_tag_present(__skb)	vlan_tx_tag_present(__skb)
+#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_TAG_PRESENT */
+
+#ifndef NETMAP_LINUX_HAVE_VLAN_HWACCEL_PUSH_INSIDE
+static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
+{
+	skb = __vlan_put_tag(skb, skb->vlan_proto,
+			vlan_tx_tag_get(skb));
+	if (likely(skb))
+		skb->vlan_tci = 0;
+	return skb;
+}
+#endif /* NETMAP_LINUX_HAVE_VLAN_HWACCESS_PUSH_INSIDE */
+#endif /* NETMAP_LINUX_HAVE_VLAN_UNTAG */
+
 /*----------- end of LINUX_VERSION_CODE dependencies ----------*/
 
 /* Type redefinitions. XXX check them */
diff --git a/LINUX/configure b/LINUX/configure
index 15f3d187b..b6771f237 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1904,6 +1904,33 @@ EOF
 	}
 EOF
 
+  # skb_vlan_tag_present?
+  add_test 'have SKB_VLAN_TAG_PRESENT' <
+
+	int dummy(struct sk_buff *skb) {
+		return skb_vlan_tag_present(skb);
+	}
+EOF
+
+  # __vlan_hwaccess_push_inside?
+  add_test 'have VLAN_HWACCEL_PUSH_INSIDE' <
+
+	struct sk_buff* dummy(struct sk_buff *skb) {
+		return __vlan_hwaccel_push_inside(skb);
+	}
+EOF
+
+  # skb_vlan_untag?
+  add_test 'have SKB_VLAN_UNTAG' <
+
+	struct sk_buff* dummy(struct sk_buff *skb) {
+		return skb_vlan_untag(skb);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 144491b83..a22aaad4f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -550,10 +550,12 @@ linux_generic_rx_handler_common(struct mbuf *m)
 	   can see it. */
 	skb_push(m, ETH_HLEN);
 
+#ifdef NETMAP_LINUX_HAVE_VLAN_UNTAG
 	/* First VLAN tag has been already popped to skb metadata. */
 	if (skb_vlan_tag_present(m)) {
 		m = __vlan_hwaccel_push_inside(m);
 	}
+#endif /* NETMAP_LINUX_HAVE_VLAN_UNTAG */
 
 	/* Possibly steal the mbuf and notify the pollers for a new RX
 	 * packet. */
@@ -562,10 +564,12 @@ linux_generic_rx_handler_common(struct mbuf *m)
 		return NM_RX_HANDLER_STOLEN;
 	}
 
+#ifdef NETMAP_LINUX_HAVE_VLAN_UNTAG
 	/* Untag once again if not stolen */
 	if (eth_type_vlan(m->protocol)) {
 		m = skb_vlan_untag(m);
 	}
+#endif /* NETMAP_LINUX_HAVE_VLAN_UNTAG */
 
 	skb_pull(m, ETH_HLEN);
 

From 71b0e2997db8e96bc74db0d7c7d8b508bb8549ef Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 28 Aug 2023 17:30:34 +0200
Subject: [PATCH 2119/2207] linux: patches for v6.5

---
 ...99 => vanilla--virtio_net.c--50b00--60500} |   0
 .../vanilla--virtio_net.c--60500--99999       | 100 ++++++++++++++++++
 2 files changed, 100 insertions(+)
 rename LINUX/final-patches/{vanilla--virtio_net.c--50b00--99999 => vanilla--virtio_net.c--50b00--60500} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--60500--99999

diff --git a/LINUX/final-patches/vanilla--virtio_net.c--50b00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--50b00--60500
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--50b00--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--50b00--60500
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60500--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60500--99999
new file mode 100644
index 000000000..4cdce8046
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--60500--99999
@@ -0,0 +1,100 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 8e9f4cfe941f..a4eae7a07304 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -293,6 +293,10 @@ struct virtnet_info {
+ 	struct failover *failover;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_v1_hash hdr;
+ 	/*
+@@ -421,6 +425,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -1955,6 +1964,18 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int received;
+ 	unsigned int xdp_xmit = 0;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -2015,6 +2036,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	enable_delayed_refill(vi);
+ 
+@@ -4259,6 +4289,12 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		goto free_unregister_netdev;
+ 	}
+ 
++	virtnet_set_queues(vi, vi->curr_queue_pairs);
++
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	netif_carrier_off(dev);
+@@ -4311,7 +4347,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -4386,6 +4429,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From 9f7cacb431bd2a3f2e02602d12b54ac0556fc4d9 Mon Sep 17 00:00:00 2001
From: Cordell O'Leary 
Date: Thu, 26 Oct 2023 17:32:59 +1300
Subject: [PATCH 2120/2207] linux: Use correct define for vlan untagging.

---
 LINUX/bsd_glue.h     | 4 ++--
 LINUX/netmap_linux.c | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 90b78f336..0b6277894 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -191,7 +191,7 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb) {
 #define page_to_virt(p) 		phys_to_virt(page_to_phys(p))
 #endif /* NETMAP_LINUX_HAVE_PAGE_TO_VIRT */
 
-#ifdef NETMAP_LINUX_HAVE_VLAN_UNTAG
+#ifdef NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG
 #ifndef NETMAP_LINUX_HAVE_ETH_TYPE_VLAN
 static inline bool eth_type_vlan(__be16 ethertype)
 {
@@ -214,7 +214,7 @@ static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
 	return skb;
 }
 #endif /* NETMAP_LINUX_HAVE_VLAN_HWACCESS_PUSH_INSIDE */
-#endif /* NETMAP_LINUX_HAVE_VLAN_UNTAG */
+#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG */
 
 /*----------- end of LINUX_VERSION_CODE dependencies ----------*/
 
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a22aaad4f..88c253b54 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -550,12 +550,12 @@ linux_generic_rx_handler_common(struct mbuf *m)
 	   can see it. */
 	skb_push(m, ETH_HLEN);
 
-#ifdef NETMAP_LINUX_HAVE_VLAN_UNTAG
+#ifdef NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG
 	/* First VLAN tag has been already popped to skb metadata. */
 	if (skb_vlan_tag_present(m)) {
 		m = __vlan_hwaccel_push_inside(m);
 	}
-#endif /* NETMAP_LINUX_HAVE_VLAN_UNTAG */
+#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG */
 
 	/* Possibly steal the mbuf and notify the pollers for a new RX
 	 * packet. */
@@ -564,12 +564,12 @@ linux_generic_rx_handler_common(struct mbuf *m)
 		return NM_RX_HANDLER_STOLEN;
 	}
 
-#ifdef NETMAP_LINUX_HAVE_VLAN_UNTAG
+#ifdef NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG
 	/* Untag once again if not stolen */
 	if (eth_type_vlan(m->protocol)) {
 		m = skb_vlan_untag(m);
 	}
-#endif /* NETMAP_LINUX_HAVE_VLAN_UNTAG */
+#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG */
 
 	skb_pull(m, ETH_HLEN);
 

From e4855cb74056b21dce42bd88744d20415798db86 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 2 Nov 2023 11:05:13 +0100
Subject: [PATCH 2121/2207] linux/igc: fix compilation on >= 6.4

---
 ...vanilla--igc--50600--60400 => vanilla--igc--50600--99999} | 0
 LINUX/if_igc_netmap.h                                        | 5 ++++-
 2 files changed, 4 insertions(+), 1 deletion(-)
 rename LINUX/final-patches/{vanilla--igc--50600--60400 => vanilla--igc--50600--99999} (100%)

diff --git a/LINUX/final-patches/vanilla--igc--50600--60400 b/LINUX/final-patches/vanilla--igc--50600--99999
similarity index 100%
rename from LINUX/final-patches/vanilla--igc--50600--60400
rename to LINUX/final-patches/vanilla--igc--50600--99999
diff --git a/LINUX/if_igc_netmap.h b/LINUX/if_igc_netmap.h
index f49dfbe42..e2c293721 100644
--- a/LINUX/if_igc_netmap.h
+++ b/LINUX/if_igc_netmap.h
@@ -11,6 +11,9 @@
 #include 
 
 #define SOFTC_T	igc_adapter
+#ifndef IGC_SRRCTL_BSIZEPKT_SHIFT
+#define IGC_SRRCTL_BSIZEPKT_SHIFT 10
+#endif /* IGC_SRRCTL_BSIZEPKT_SHIFT */
 
 #define igc_driver_name netmap_igc_driver_name
 char netmap_igc_driver_name[] = "igc" NETMAP_LINUX_DRIVER_SUFFIX;
@@ -63,7 +66,7 @@ igc_netmap_configure_srrctl(struct igc_ring *rxr)
 	struct igc_adapter *adapter = netdev_priv(ifp);
 	u32 srrctl;
 
-	/* set descriptor configuration not using spilit header */
+	/* set descriptor configuration not using split header */
 	srrctl = ALIGN(NETMAP_BUF_SIZE(na), 1024) >> IGC_SRRCTL_BSIZEPKT_SHIFT;
 	srrctl |= IGC_SRRCTL_DESCTYPE_ADV_ONEBUF;
 	// XXX: DROP_ENABLE neither defined or enabled in the main driver

From c1ce4bd1c3bf8210f9058f0d4d2f1d79d4132040 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 2 Nov 2023 11:12:31 +0100
Subject: [PATCH 2122/2207] linux/vmxnet3: fix compilation on 6.6

---
 LINUX/configure                               |  15 ++
 ...--99999 => vanilla--vmxnet3--40d00--60600} |   0
 .../vanilla--vmxnet3--60600--99999            | 147 ++++++++++++++++++
 LINUX/if_vmxnet3_netmap_v2.h                  |   5 +-
 4 files changed, 166 insertions(+), 1 deletion(-)
 rename LINUX/final-patches/{vanilla--vmxnet3--40d00--99999 => vanilla--vmxnet3--40d00--60600} (100%)
 create mode 100644 LINUX/final-patches/vanilla--vmxnet3--60600--99999

diff --git a/LINUX/configure b/LINUX/configure
index b6771f237..2e8dfed6f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2423,6 +2423,21 @@ EOF
   	#define NETMAP_LINUX_CONFIG_H
 EOF
 
+  if drv enabled vmxnet3; then
+    add_test 'have VMXNET3_STATIC_RQ_CREATE' <netdev;
++
++	if (netmap_tx_irq(netdev, tq - adapter->tx_queue) != NM_IRQ_PASS)
++		return 0;
++#endif
++
+ 	gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+ 	while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
+ 		/* Prevent any &gdesc->tcd field from being (speculatively)
+@@ -546,6 +558,10 @@ vmxnet3_tq_init(struct vmxnet3_tx_queue *tq,
+ 	for (i = 0; i < tq->tx_ring.size; i++)
+ 		tq->buf_info[i].map_type = VMXNET3_MAP_NONE;
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_tq_config_tx_buf(tq, adapter);
++#endif /* DEV_NETMAP */
++
+ 	/* stats are not reset */
+ }
+ 
+@@ -1519,6 +1535,14 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ #endif
+ 	bool need_flush = false;
+ 
++#ifdef DEV_NETMAP
++	u_int total_packets = 0;
++	struct net_device *netdev = adapter->netdev;
++
++	if (netmap_rx_irq(netdev, rq - adapter->rx_queue, &total_packets) != NM_IRQ_PASS)
++		return 1;
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
+ 			  &rxComp);
+ 	while (rcd->gen == rq->comp_ring.gen) {
+@@ -2079,6 +2103,9 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
+ 	if (err)
+ 		return err;
+ 
++#ifdef DEV_NETMAP
++	if (!vmxnet3_netmap_rq_config_rx_buf(rq, adapter)) {
++#endif /* DEV_NETMAP */
+ 	if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1,
+ 				    adapter) == 0) {
+ 		xdp_rxq_info_unreg(&rq->xdp_rxq);
+@@ -2089,6 +2116,9 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
+ 		return -ENOMEM;
+ 	}
+ 	vmxnet3_rq_alloc_rx_buf(rq, 1, rq->rx_ring[1].size - 1, adapter);
++#ifdef DEV_NETMAP
++	}
++#endif /* DEV_NETMAP */
+ 
+ 	/* reset the comp ring */
+ 	rq->comp_ring.next2proc = 0;
+@@ -2191,7 +2221,11 @@ vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter)
+ {
+ 	int i, err = 0;
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_set_rxdataring_enabled(adapter);
++#else
+ 	adapter->rxdataring_enabled = VMXNET3_VERSION_GE_3(adapter);
++#endif /* DEV_NETMAP */
+ 
+ 	for (i = 0; i < adapter->num_rx_queues; i++) {
+ 		err = vmxnet3_rq_create(&adapter->rx_queue[i], adapter);
+@@ -3019,7 +3053,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+ 		adapter->rx_queue[0].rx_ring[0].size,
+ 		adapter->rx_queue[0].rx_ring[1].size);
+ 
+-	vmxnet3_tq_init_all(adapter);
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_init_buffers(adapter);
++#endif /* DEV_NETMAP */
++
+ 	err = vmxnet3_rq_init_all(adapter);
+ 	if (err) {
+ 		netdev_err(adapter->netdev,
+@@ -3027,6 +3064,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+ 		goto rq_err;
+ 	}
+ 
++	vmxnet3_tq_init_all(adapter);
++
+ 	err = vmxnet3_request_irqs(adapter);
+ 	if (err) {
+ 		netdev_err(adapter->netdev,
+@@ -3312,7 +3351,12 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
+ 	adapter->rx_queue[0].rx_ring[1].size = rx_ring2_size;
+ 	vmxnet3_adjust_rx_ring_size(adapter);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_set_rxdataring_enabled(adapter);
++#else
+ 	adapter->rxdataring_enabled = VMXNET3_VERSION_GE_3(adapter);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < adapter->num_rx_queues; i++) {
+ 		struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
+ 		/* qid and qid2 for rx queues will be assigned later when num
+@@ -4101,6 +4145,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
+ 		goto err_register;
+ 	}
+ 
++
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_check_link(adapter, false);
+ 	return 0;
+ 
+@@ -4176,6 +4225,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
+ 
+ 	unregister_netdev(netdev);
+ 
++#ifdef DEV_NETMAP
++	vmxnet3_netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	vmxnet3_free_intr_resources(adapter);
+ 	vmxnet3_free_pci_resources(adapter);
+ 	if (VMXNET3_VERSION_GE_3(adapter)) {
diff --git a/LINUX/if_vmxnet3_netmap_v2.h b/LINUX/if_vmxnet3_netmap_v2.h
index 0b4352680..392f67336 100644
--- a/LINUX/if_vmxnet3_netmap_v2.h
+++ b/LINUX/if_vmxnet3_netmap_v2.h
@@ -8,7 +8,10 @@
 
 #define SOFTC_T vmxnet3_adapter
 
-static int vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter);
+#ifdef NETMAP_LINUX_HAVE_VMXNET3_STATIC_RQ_CREATE
+static
+#endif /* NETMAP_LINUX_HAVE_STATIC_RQ_CREATE */
+int vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter);
 
 static int
 vmxnet3_netmap_reg(struct netmap_adapter *na, int onoff)

From 6055e3b0e20b7d93d92cc983fd08155d4078f3ac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 2 Nov 2023 16:56:52 +0100
Subject: [PATCH 2123/2207] linux: patches for latest Intel drivers

---
 LINUX/final-patches/intel--i40e--2.23.17   | 173 +++++++++++++++
 LINUX/final-patches/intel--ice--1.11.17.1  | 221 +++++++++++++++++++
 LINUX/final-patches/intel--ice--1.12.6     | 240 +++++++++++++++++++++
 LINUX/final-patches/intel--ice--1.12.7     | 240 +++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.14.16    | 138 ++++++++++++
 LINUX/final-patches/intel--ixgbe--5.19.6   | 174 +++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.18.7 | 168 +++++++++++++++
 7 files changed, 1354 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.23.17
 create mode 100644 LINUX/final-patches/intel--ice--1.11.17.1
 create mode 100644 LINUX/final-patches/intel--ice--1.12.6
 create mode 100644 LINUX/final-patches/intel--ice--1.12.7
 create mode 100644 LINUX/final-patches/intel--igb--5.14.16
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.19.6
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.18.7

diff --git a/LINUX/final-patches/intel--i40e--2.23.17 b/LINUX/final-patches/intel--i40e--2.23.17
new file mode 100644
index 000000000..ca1671ed7
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.23.17
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index aafff04..44e33f6 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index da5a6e8..3111d22 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -161,6 +161,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4158,6 +4163,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4286,6 +4295,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4314,6 +4327,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15838,6 +15856,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16231,6 +16255,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index b3234d3..299402e 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -13,6 +13,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -986,6 +990,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2958,7 +2967,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.11.17.1 b/LINUX/final-patches/intel--ice--1.11.17.1
new file mode 100644
index 000000000..ac270f923
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.11.17.1
@@ -0,0 +1,221 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 5f29380..e6499f6 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -69,12 +69,12 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -87,20 +87,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+@@ -123,7 +123,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -157,7 +157,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -202,7 +202,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index fdbf6f9..c094d20 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -480,6 +485,10 @@ static int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -636,6 +645,11 @@ int ice_vsi_cfg_rxq(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -908,6 +922,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *tx_ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		tx_ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index dd4ee2b..45bef2b 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -104,6 +104,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6559,6 +6564,10 @@ probe_done:
+ #ifdef HAVE_DEVLINK_NOTIFY_REGISTER
+ 	ice_devlink_register(pf);
+ #endif /* HAVE_DEVLINK_NOTIFY_REGISTER */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ 	/* Unwind non-managed device resources, etc. if something failed */
+@@ -6688,6 +6697,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	hw = &pf->hw;
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index e3ee85c..5fcb360 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -229,6 +233,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -1624,6 +1632,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--ice--1.12.6 b/LINUX/final-patches/intel--ice--1.12.6
new file mode 100644
index 000000000..7d671b48b
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.12.6
@@ -0,0 +1,240 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 16ec261..783a3ba 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -70,13 +70,13 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_peer_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -89,20 +89,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+@@ -131,7 +131,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -172,7 +172,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -217,7 +217,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 84adc70..32340d8 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -481,6 +486,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -638,6 +647,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -910,6 +924,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 8f515cd..1aa4974 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -105,6 +105,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6828,6 +6833,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ }
+ 
+@@ -7201,6 +7210,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 582e2cf..e2c6401 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -237,6 +241,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -419,6 +427,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1670,6 +1688,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--ice--1.12.7 b/LINUX/final-patches/intel--ice--1.12.7
new file mode 100644
index 000000000..1df6f69e6
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.12.7
@@ -0,0 +1,240 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 16ec261..783a3ba 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -70,13 +70,13 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_peer_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -89,20 +89,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+@@ -131,7 +131,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ COMMON_MK ?= $(wildcard common.mk)
+ ifeq (${COMMON_MK},)
+@@ -172,7 +172,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -217,7 +217,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 84adc70..32340d8 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -481,6 +486,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -638,6 +647,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -910,6 +924,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(tx_ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index a32bb2a..1a116db 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -105,6 +105,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6835,6 +6840,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ }
+ 
+@@ -7208,6 +7217,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 582e2cf..e2c6401 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -237,6 +241,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -419,6 +427,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1670,6 +1688,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.14.16 b/LINUX/final-patches/intel--igb--5.14.16
new file mode 100644
index 000000000..f871cd9d0
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.14.16
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index f72e6da..c387ecd 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 8427c35..5b866be 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3243,6 +3247,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3448,6 +3456,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3862,6 +3874,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7437,6 +7452,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8453,6 +8473,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8772,6 +8797,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.19.6 b/LINUX/final-patches/intel--ixgbe--5.19.6
new file mode 100644
index 000000000..8257d24ca
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.19.6
@@ -0,0 +1,174 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 1d4c83e..65cf773 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,25 +29,25 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -120,9 +120,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index bf5eddd..97dc25e 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -721,6 +721,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_reset_pf_report - reset pf and print reset report
+  * @tx_ring: tx ring number
+@@ -774,6 +791,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2246,6 +2274,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3759,6 +3797,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4451,6 +4493,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13288,6 +13336,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13346,6 +13398,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.18.7 b/LINUX/final-patches/intel--ixgbevf--4.18.7
new file mode 100644
index 000000000..6b763f347
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.18.7
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index df6689d..03ce8eb 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 6af15b2..85d8ed3 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -344,6 +344,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -364,6 +381,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1382,6 +1410,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2100,6 +2138,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2334,6 +2376,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5642,8 +5688,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5684,6 +5732,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index afc88b1..104ea20 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -12,6 +12,8 @@
+ 
+ #include "kcompat_gcc.h"
+ 
++#include 
++
+ #include 
+ #include 
+ #include 

From 765f097948d700cda6fa9d0cbe24188dc139fffd Mon Sep 17 00:00:00 2001
From: Franco Fichtner 
Date: Wed, 8 Nov 2023 09:50:20 +0100
Subject: [PATCH 2124/2207] libnetmap: remove interface name validation

When trying to use a VLAN device (e.g. "em0.123") with a dot
the library fails to parse the interface correctly. The former
pattern is much too restrictive given that almost all characters
can be coerced into a device name via ifconfig.

Remove the particularly restrictive validation.  Some characters
still cannot be used as an interface name as they are used as
delimiters in the syntax, but this allows to be able to use most
of them without an issue.

Note that the dotted VLAN naming is the default in FreeBSD now
and a patch was proposed here https://reviews.freebsd.org/D42485
as well.
---
 libnetmap/nmreq.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index 0aa9839af..f5d4605ed 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -156,11 +156,6 @@ nmreq_header_decode(const char **pifname, struct nmreq_header *h, struct nmctx *
 	for (pipesep = vpname; pipesep != scan && !index("{}", *pipesep); pipesep++)
 		;
 
-	if (!nm_is_identifier(vpname, pipesep)) {
-		nmctx_ferror(ctx, "%s: invalid port name '%.*s'", *pifname,
-				pipesep - vpname, vpname);
-		goto fail;
-	}
 	if (pipesep != scan) {
 		pipesep++;
 		if (*pipesep == '\0') {

From 477b50021618704170ac5c26f792f9385f709a04 Mon Sep 17 00:00:00 2001
From: Kieran Kunhya 
Date: Sun, 24 Dec 2023 01:57:13 +0000
Subject: [PATCH 2125/2207] Add mlx5 version 5.4

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/mellanox--mlx5--5.4 | 426 ++++++++++++++++++++++++
 2 files changed, 427 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--5.4

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 840a85926..3618af75f 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -116,7 +116,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,5.3-1.0.0.1))
+$(eval $(call default,mlx5,5.4-1.0.3.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 mlx5@cflags	= -Wframe-larger-than=2000
diff --git a/LINUX/final-patches/mellanox--mlx5--5.4 b/LINUX/final-patches/mellanox--mlx5--5.4
new file mode 100644
index 000000000..0e0304698
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--5.4
@@ -0,0 +1,426 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 544058a..6f34c0d 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -7,12 +7,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o fs_ft_pool.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
+@@ -21,12 +21,12 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		mst_dump.o en_diag.o sriov_sysfs.o crdump.o diag/diag_cnt.o \
+ 		eswitch_devlink_compat.o params.o fw_exp.o fw_reset.o
+ 
+-mlx5_core-y += compat.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y += compat.o
+ 
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o \
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+ 		en/reporter_tx.o en/reporter_rx.o en/params.o en/xsk/umem.o \
+@@ -36,65 +36,65 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += lag_mp.o lib/geneve.o lib/port_tun.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += lag_mp.o lib/geneve.o lib/port_tun.o \
+ 					en_rep.o en/rep/bond.o en/mod_hdr.o \
+ 					en/flow_meter_aso.o
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					en/mapping.o lib/fs_chains.o en/tc_tun.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
+ 					en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
+ 					en/tc_sample.o esw/indir_table.o en/tc_tun_common.o
+-mlx5_core-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ 				      ecpf.o rdma.o esw/vf_meter.o esw/legacy.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
+ 				      esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
+ 				      esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o \
+ 				      esw/vporttbl.o esw/devlink_port.o esw/pet_offloads.o \
+ 				      esw/qos.o
+ 
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
+-mlx5_core-$(CONFIG_MLXDEVM) += mlx5_devm.o esw/devm_port.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLXDEVM) += mlx5_devm.o esw/devm_port.o
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
+-mlx5_core-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o en_accel/ipsec_fs.o esw/ipsec.o \
+ 				     en/ipsec_aso.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ 				   en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
+ 				   en_accel/ktls_tx.o en_accel/ktls_rx.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o \
+ 					steering/dr_ste.o steering/dr_send.o \
+@@ -104,14 +104,14 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # SF device
+ #
+-mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o
+ 
+ #
+ # SF manager
+ #
+-mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
+ 
+ #
+ # SF cfg driver basic
+ #
+-mlx5_core-$(CONFIG_MLX5_SF_CFG) += sf/dev/cfg_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF_CFG) += sf/dev/cfg_driver.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index 6491456..d8e07e1 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -15,6 +15,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index a4667bb..709804d 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -85,8 +85,21 @@
+ #include "fpga/ipsec.h"
+ #include "compat.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
+ 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
+ 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 		MLX5_CAP_ETH(mdev, reg_umr_sq);
+@@ -1075,6 +1088,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ {
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(rq->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1140,6 +1159,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1272,6 +1295,10 @@ int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ 	if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_SKB_XMIT_MORE))
+ 		__set_bit(MLX5E_RQ_STATE_SKB_XMIT_MORE, &c->rq.state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
+@@ -1285,6 +1312,9 @@ err_dealloc_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->netdev)) || NA(rq->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ 	mlx5e_trigger_irq(rq->icosq);
+ }
+@@ -1569,6 +1599,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1763,6 +1798,9 @@ void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1783,6 +1821,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3984,6 +4028,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -4019,6 +4068,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 	mlx5e_apply_traps(priv, false);
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++       netmap_disable_all_rings(netdev);
++#endif
++
+ 	netif_carrier_off(priv->netdev);
+ 	mlx5e_destroy_debugfs(priv);
+ #if defined(CONFIG_MLX5_EN_SPECIAL_SQ) && (defined(HAVE_NDO_SET_TX_MAXRATE) || defined(HAVE_NDO_SET_TX_MAXRATE_EXTENDED))
+@@ -7339,6 +7392,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ {
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++       netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_netdev_cleanup(netdev, priv);
+ 	free_netdev(netdev);
+ }
+@@ -7450,6 +7507,10 @@ static int mlx5e_probe(struct auxiliary_device *adev,
+ 	mlx5e_dcbnl_init_app(priv);
+ 	mlx5_uplink_netdev_set(mdev, netdev);
+ 
++#ifdef DEV_NETMAP
++       mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_unregister_netdev:
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index 8237d9a..194370c 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -81,6 +81,14 @@ const struct mlx5e_rx_handlers mlx5e_rx_handlers_nic = {
+ 	.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -209,7 +217,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -2000,6 +2008,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 2cf0c41..36a8835 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -41,8 +41,16 @@
+ #include "ipoib/ipoib.h"
+ #include "en_accel/en_accel.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+-				       u32 cqcc, void *data)
++                                       u32 cqcc, void *data)
+ {
+ 	u32 ci = mlx5_cqwq_ctr2ix(wq, cqcc);
+ 
+@@ -1023,6 +1031,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->netdev, sq->ch_ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -1145,23 +1158,29 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 
+ 		sqcc += wi->num_wqebbs;
+ 
+-		if (likely(wi->skb)) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			dev_kfree_skb_any(wi->skb);
++                if (!nm_netmap_on(NA(sq->txq->dev))) {
++                       /* do not free skbs in netmap mode */
++			if (likely(wi->skb)) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				dev_kfree_skb_any(wi->skb);
+ 
+-			npkts++;
+-			nbytes += wi->num_bytes;
+-			continue;
+-		}
++				npkts++;
++				nbytes += wi->num_bytes;
++				continue;
++			}
+ 
+-		if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
+-			continue;
++			if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
++				continue;
+ 
+-		if (wi->num_fifo_pkts) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
++			if (wi->num_fifo_pkts) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
+ 
+-			npkts += wi->num_fifo_pkts;
++				npkts += wi->num_fifo_pkts;
++				nbytes += wi->num_bytes;
++			}
++                } else {
++			npkts++;
+ 			nbytes += wi->num_bytes;
+ 		}
+ 	}

From 185fa49485fe2c8b70d0e5fae5387091120b77c2 Mon Sep 17 00:00:00 2001
From: msaare123 
Date: Sun, 7 Jan 2024 20:56:29 +0200
Subject: [PATCH 2126/2207] linux: use net_if_rx_ni() in nm_os_send_up()

In older kernels net_if_rx() is to be used in interrupt context and
netmap nm_os_send_up() is from process context. Thus using netif_rx_ni()
is correct function variant in this case and using it prevents pending
softirqs. In newerkernels netif_rx() can handle both contexts.
---
 LINUX/configure      | 10 ++++++++++
 LINUX/netmap_linux.c |  5 +++++
 2 files changed, 15 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 2e8dfed6f..4f8d232c7 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1305,6 +1305,16 @@ EOF
 	}
 EOF
 
+  # check for netif_rx_ni
+  add_test 'have NETIF_RX_NI' <
+
+	void dummy(struct sk_buff *skb)
+	{
+	    netif_rx_ni(skb);
+	}
+EOF
+
   # poll_table key field
   for k in _key key; do
 	add_test "define PWAIT_KEY $k" <priority = NM_MAGIC_PRIORITY_RX; /* do not reinject to netmap */
+#ifdef NETMAP_LINUX_HAVE_NETIF_RX_NI
+	netif_rx_ni(m);
+#else
 	netif_rx(m);
+#endif
+
 	return NULL;
 }
 

From 4e9a6e29b44d12743818740c1f7c867da3f5b925 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2024 11:35:06 +0100
Subject: [PATCH 2127/2207] linux/scripts: workaround for old kernels with gcc
 13

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 10a8a84bd..580bd1f9c 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -382,7 +382,7 @@ function build-prep()
 pound	:= \\#
 			/\/{s/\\#/$(pound)/}' tools/build/Build.include || true
 		last=compiler-gcc.h
-		for i in $(seq 12); do
+		for i in $(seq 13); do
 			[ -e include/linux/compiler-gcc$i.h ] ||
 				ln -s $last include/linux/compiler-gcc$i.h
 			last=compiler-gcc$i.h

From bd6cf6d9055323ef2487661e58f28ce235e93d4c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2024 11:36:30 +0100
Subject: [PATCH 2128/2207] linux/scripts: don't error-out for modpost warnings

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 580bd1f9c..a5f16dd69 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -520,7 +520,7 @@ function check-patch()
 				--kernel-opts=CONFIG_STACK_VALIDATION= \
 				$config_opts \
 				--cache=$cache >>$log
-			(make get-$driver && make -j $PARALLEL_MAKE) >>$log 2>&1 && ok=true
+			(make get-$driver && KBUILD_MODPOST_WARN=1 make -j $PARALLEL_MAKE) >>$log 2>&1 && ok=true
 			grep -q warning: $log && { warn=true; echo $warn > $cwarn; }
 			cat config.log >>$log
 			cat netmap_linux_config.h >>$log 2>/dev/null

From 379f99b135ca4e95b14946f8b2521fca38bdb108 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2024 11:37:21 +0100
Subject: [PATCH 2129/2207] linux/configure: disable enum-int-mismatch warnings

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 2e8dfed6f..000a44af7 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -823,7 +823,7 @@ EOF
 DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned \
 	stringop-truncation missing-attributes format-truncation \
 	maybe-uninitialized unused-variable unused-label \
-	implicit-fallthrough"
+	implicit-fallthrough enum-int-mismatch"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"

From dce32ef491864ded7152df486acae9e72f3d899a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 9 Jan 2024 17:12:56 +0100
Subject: [PATCH 2130/2207] linux/configure: disable warnings that may cause
 problems with old kernels

---
 LINUX/netmap.mak.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index b8e92d39f..8c579b1f8 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -18,7 +18,7 @@ DEBUG:=@DEBUG@
 SUBSYS_FLAGS = $(foreach s,$(SUBSYS),-DCONFIG_NETMAP_$(shell echo $s|tr a-z- A-Z_))
 # Additional compile flags (e.g. header location)
 EXTRA_CFLAGS := -I$(BUILDDIR) -I$(SRCDIR) -I$(SRCDIR)/../sys -I$(SRCDIR)/../sys/dev -DCONFIG_NETMAP
-EXTRA_CFLAGS += -Wno-unused-but-set-variable
+EXTRA_CFLAGS += $(addprefix -Wno-,@REC_DISABLED_WARNINGS@)
 EXTRA_CFLAGS += $(if $(DEBUG),-g)
 EXTRA_CFLAGS += $(SUBSYS_FLAGS)
 

From 901f342b9da033e1d1282d2986e23540ae489232 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 10 Jan 2024 09:38:55 +0100
Subject: [PATCH 2131/2207] linux: patches for v6.7

---
 ...0--99999 => vanilla--veth.c--41400--60700} |  0
 .../vanilla--veth.c--60700--99999             | 37 +++++++++++++++++++
 2 files changed, 37 insertions(+)
 rename LINUX/final-patches/{vanilla--veth.c--41400--99999 => vanilla--veth.c--41400--60700} (100%)
 create mode 100644 LINUX/final-patches/vanilla--veth.c--60700--99999

diff --git a/LINUX/final-patches/vanilla--veth.c--41400--99999 b/LINUX/final-patches/vanilla--veth.c--41400--60700
similarity index 100%
rename from LINUX/final-patches/vanilla--veth.c--41400--99999
rename to LINUX/final-patches/vanilla--veth.c--41400--60700
diff --git a/LINUX/final-patches/vanilla--veth.c--60700--99999 b/LINUX/final-patches/vanilla--veth.c--60700--99999
new file mode 100644
index 000000000..1324a96dc
--- /dev/null
+++ b/LINUX/final-patches/vanilla--veth.c--60700--99999
@@ -0,0 +1,37 @@
+diff --git a/veth.c b/veth.c
+index 977861c46b1f..22ec126909ea 100644
+--- a/veth.c
++++ b/veth.c
+@@ -82,6 +82,10 @@ struct veth_xdp_tx_bq {
+ 	unsigned int count;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /*
+  * ethtool interface
+  */
+@@ -1487,6 +1491,10 @@ static int veth_alloc_queues(struct net_device *dev)
+ 		u64_stats_init(&priv->rq[i].stats.syncp);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	veth_netmap_attach(dev);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -1505,6 +1513,10 @@ static int veth_dev_init(struct net_device *dev)
+ static void veth_dev_free(struct net_device *dev)
+ {
+ 	veth_free_queues(dev);
++
++#ifdef DEV_NETMAP
++	netmap_detach(dev);
++#endif /* DEV_NETMAP */
+ }
+ 
+ #ifdef CONFIG_NET_POLL_CONTROLLER

From 9376b2ccab9da248cdb45df89000d797fba59ce2 Mon Sep 17 00:00:00 2001
From: Brian Poole 
Date: Tue, 27 Feb 2024 15:49:34 -0500
Subject: [PATCH 2132/2207] linux: fix to avoid fortify panic on 6.5

Fortify was detecting "buffer overflow in strcpy" in tc_configure()
where a string is copied into a TCA_KIND attribute. The nlreq object has
sufficient space with a 100 character buffer but the attribute pointer
is set to &nlreq.hdr which has a fixed sized. By changing the pointer to
&nlreq, fortify is able to see the extra bytes and not panic.

Also remove a duplicate strcpy() in netmap_sink_init().
---
 LINUX/netmap_linux.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a64b21395..1afa4c3ab 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -850,7 +850,7 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 	}
 
 	/* Push TCA_KIND attr. */
-	attr_kind = (struct nlattr *)(((void *)&nlreq.hdr) +
+	attr_kind = (struct nlattr *)(((void *)&nlreq) +
 				 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
 	attr_kind->nla_len = NLA_HDRLEN + strlen(qdisc_name) + 1;
 	attr_kind->nla_type = TCA_KIND;
@@ -860,7 +860,7 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 
 	if (limit > 0) {
 		/* Push TCA_OPTIONS attr. */
-		attr_opt = (struct nlattr *)(((void *)&nlreq.hdr) +
+		attr_opt = (struct nlattr *)(((void *)&nlreq) +
 					 NLMSG_ALIGN(nlreq.hdr.nlmsg_len));
 		attr_opt->nla_len = NLA_HDRLEN + sizeof(uint32_t);
 		attr_opt->nla_type = TCA_OPTIONS;
@@ -2207,7 +2207,6 @@ netmap_sink_init(void)
 	netdev->netdev_ops = &nm_sink_netdev_ops ;
 	strlcpy(netdev->name, "nmsink", sizeof(netdev->name));
 	netdev->features = NETIF_F_HIGHDMA;
-	strcpy(netdev->name, "nmsink%d");
 	err = register_netdev(netdev);
 	if (err) {
 		free_netdev(netdev);

From 9b0be692870965ce72d3d5384bc2e8eab65f074e Mon Sep 17 00:00:00 2001
From: James Darnley 
Date: Thu, 5 Aug 2021 13:20:06 +0200
Subject: [PATCH 2133/2207] mlx5: copy fix for RX packet loss from f14770c7
 into 5.3

Full commit hash f14770c7f84985fccd7a3f28b5ccf167f38ac587
---
 LINUX/final-patches/mellanox--mlx5--5.3 | 28 ++++++++++++-------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/LINUX/final-patches/mellanox--mlx5--5.3 b/LINUX/final-patches/mellanox--mlx5--5.3
index 1c08468c2..552bb82d0 100644
--- a/LINUX/final-patches/mellanox--mlx5--5.3
+++ b/LINUX/final-patches/mellanox--mlx5--5.3
@@ -140,7 +140,7 @@ index a6dceb6..a3cb81d 100644
  
  	netdev_err(sq->netdev,
 diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
-index 47260b9..0c0e90a 100644
+index 47260b9..25857eb 100644
 --- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 +++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
 @@ -84,8 +84,21 @@
@@ -165,18 +165,7 @@ index 47260b9..0c0e90a 100644
  	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
  		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
  		MLX5_CAP_ETH(mdev, reg_umr_sq);
-@@ -824,6 +837,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
- 		rq->dim_obj.dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_free_by_rq_type:
-@@ -1051,6 +1068,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+@@ -1051,6 +1064,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
  {
  	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
  
@@ -189,7 +178,7 @@ index 47260b9..0c0e90a 100644
  	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
  
  	do {
-@@ -1115,6 +1138,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+@@ -1115,6 +1134,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
  
  		while (!mlx5_wq_cyc_is_empty(wq)) {
  			wqe_ix = mlx5_wq_cyc_get_tail(wq);
@@ -200,6 +189,17 @@ index 47260b9..0c0e90a 100644
  			rq->dealloc_wqe(rq, wqe_ix);
  			mlx5_wq_cyc_pop(wq);
  		}
+@@ -1248,6 +1271,10 @@ int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
+ 	if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_SKB_XMIT_MORE))
+ 		__set_bit(MLX5E_RQ_STATE_SKB_XMIT_MORE, &c->rq.state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
 @@ -1261,6 +1288,9 @@ err_dealloc_rq:
  
  void mlx5e_activate_rq(struct mlx5e_rq *rq)

From 2087e8ac5e86d6c12319c377e78d8d585fef8056 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 15 Mar 2024 11:18:31 +0100
Subject: [PATCH 2134/2207] remove stale file

---
 LINUX/final-patches/intel--ice--v1.8.8 | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 LINUX/final-patches/intel--ice--v1.8.8

diff --git a/LINUX/final-patches/intel--ice--v1.8.8 b/LINUX/final-patches/intel--ice--v1.8.8
deleted file mode 100644
index e69de29bb..000000000

From 1f471582037b7a0f6c7eb303efa0c7f4c5876e1c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 15 Mar 2024 11:47:15 +0100
Subject: [PATCH 2135/2207] linux/configure: add ability to run a single test

---
 LINUX/configure | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index df6c40953..4c0a5af80 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -437,7 +437,7 @@ EOF
 #     explicitly naming the test.
 NEXTTEST=1
 add_test() {
-	local t="__test__$NEXTTEST"
+	local t="test__$NEXTTEST"
 	add_named_test $t "$@"
 	NEXTTEST=$(($NEXTTEST+1))
 }
@@ -530,6 +530,9 @@ all: \$(S_DRIVERS:%=get-%) \$(TOBUILD:%=build-%) \$(I_DRIVERS:%=patch-%) tests
 tests:
 	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts
 
+test__%:
+	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts \$@.o
+
 -include $BUILDDIR/extdrv-versions.mak
 -include $BUILDDIR/default-config.mak
 -include $BUILDDIR/config.mak

From 2859b8dd7e035d03a21536b0581e11e3ea7e56d0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 15 Mar 2024 12:46:21 +0100
Subject: [PATCH 2136/2207] linux/configure: add ability to set per-test cflags

---
 LINUX/configure | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 4c0a5af80..dea26d0d7 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -442,6 +442,15 @@ add_test() {
 	NEXTTEST=$(($NEXTTEST+1))
 }
 
+PERTESTFLAGS=
+# add_test_flags flags...
+# 	call this immediately before add_test to set special compilation flags
+# 	for the next test
+add_test_flags() {
+	PERTESTFLAGS="$PERTESTFLAGS
+CFLAGS___test__$NEXTTEST.o := $@"
+}
+
 reset_tests() {
 	rm -rf $TMPDIR
 	mkdir $TMPDIR
@@ -516,6 +525,7 @@ run_tests() {
 SRCDIR=$SRCDIR
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
+$PERTESTFLAGS
 else
 WARN_CFLAGS := -Werror \$(addprefix -Wno-error=,$REC_DISABLED_WARNINGS)
 S_DRIVERS := $(drv print)
@@ -2392,6 +2402,7 @@ EOF
   fi # i40e
 
   if drv enabled ice; then
+    add_test_flags '-I$M/ice'
     add_test 'have ICE_XRINGS' <
Date: Fri, 15 Mar 2024 12:46:49 +0100
Subject: [PATCH 2137/2207] linux/ice: fix build of 1.12.6/7

---
 LINUX/final-patches/intel--ice--1.12.6 | 4 ++--
 LINUX/final-patches/intel--ice--1.12.7 | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/LINUX/final-patches/intel--ice--1.12.6 b/LINUX/final-patches/intel--ice--1.12.6
index 7d671b48b..c1db7d7c7 100644
--- a/LINUX/final-patches/intel--ice--1.12.6
+++ b/LINUX/final-patches/intel--ice--1.12.6
@@ -91,7 +91,7 @@ index 16ec261..783a3ba 100644
  # After installing all the files, perform necessary work to ensure the system
  # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index 84adc70..32340d8 100644
+index 84adc70..3a910f1 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -135,7 +135,7 @@ index 84adc70..32340d8 100644
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+	ice_netmap_configure_tx_ring(tx_ring);
++	ice_netmap_configure_tx_ring(ring);
 +#endif /* DEV_NETMAP */
  
  	return 0;
diff --git a/LINUX/final-patches/intel--ice--1.12.7 b/LINUX/final-patches/intel--ice--1.12.7
index 1df6f69e6..135b11f87 100644
--- a/LINUX/final-patches/intel--ice--1.12.7
+++ b/LINUX/final-patches/intel--ice--1.12.7
@@ -91,7 +91,7 @@ index 16ec261..783a3ba 100644
  # After installing all the files, perform necessary work to ensure the system
  # will use the new modules. This includes running depmod to update module
 diff --git a/ice/ice_base.c b/ice/ice_base.c
-index 84adc70..32340d8 100644
+index 84adc70..3a910f1 100644
 --- a/ice/ice_base.c
 +++ b/ice/ice_base.c
 @@ -6,6 +6,11 @@
@@ -135,7 +135,7 @@ index 84adc70..32340d8 100644
  		ring->txq_teid = le32_to_cpu(txq->q_teid);
 +    
 +#ifdef DEV_NETMAP
-+	ice_netmap_configure_tx_ring(tx_ring);
++	ice_netmap_configure_tx_ring(ring);
 +#endif /* DEV_NETMAP */
  
  	return 0;

From 1e3867bc2ba841cf9605ac99f3fb97800fce3ddf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 15 Mar 2024 13:33:19 +0100
Subject: [PATCH 2138/2207] linux: add patches for latest Intel drivers

---
 LINUX/configure                            |   8 +
 LINUX/final-patches/intel--i40e--2.24.6    | 173 +++++++++++++++
 LINUX/final-patches/intel--ice--1.12.18    | 240 +++++++++++++++++++++
 LINUX/final-patches/intel--ice--1.13.7     | 240 +++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.15.6     | 138 ++++++++++++
 LINUX/final-patches/intel--ixgbe--5.19.9   | 174 +++++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.18.9 | 168 +++++++++++++++
 LINUX/if_igb_netmap.h                      |   9 +-
 8 files changed, 1148 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.24.6
 create mode 100644 LINUX/final-patches/intel--ice--1.12.18
 create mode 100644 LINUX/final-patches/intel--ice--1.13.7
 create mode 100644 LINUX/final-patches/intel--igb--5.15.6
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.19.9
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.18.9

diff --git a/LINUX/configure b/LINUX/configure
index dea26d0d7..5e6c960c8 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2435,6 +2435,14 @@ EOF
 		return ring->next_to_alloc;
        }
 EOF
+
+    add_test 'have IGB_STATE_INDIR' <state);
+	}
+EOF
   fi # igb
 
   # END_TESTS
diff --git a/LINUX/final-patches/intel--i40e--2.24.6 b/LINUX/final-patches/intel--i40e--2.24.6
new file mode 100644
index 000000000..dd33b7297
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.24.6
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index aafff04..44e33f6 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index 91965dc..350f142 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -162,6 +162,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4160,6 +4165,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4288,6 +4297,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4316,6 +4329,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -15996,6 +16014,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16389,6 +16413,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index da83e97..a011384 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -983,6 +987,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2954,7 +2963,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.12.18 b/LINUX/final-patches/intel--ice--1.12.18
new file mode 100644
index 000000000..357638457
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.12.18
@@ -0,0 +1,240 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 62548b3..65ac0f4 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -52,9 +52,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -96,13 +96,13 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_peer_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -115,20 +115,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+@@ -157,7 +157,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ # ice does not support building on kernels older than 3.10.0
+ $(call minimum_kver_check,3,10,0)
+@@ -176,7 +176,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -221,7 +221,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 84adc70..3a910f1 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -481,6 +486,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -638,6 +647,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -910,6 +924,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 112e871..8c28abc 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -105,6 +105,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6841,6 +6846,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ }
+ 
+@@ -7214,6 +7223,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 582e2cf..e2c6401 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -237,6 +241,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -419,6 +427,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1670,6 +1688,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--ice--1.13.7 b/LINUX/final-patches/intel--ice--1.13.7
new file mode 100644
index 000000000..a6ff98d65
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.13.7
@@ -0,0 +1,240 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index 66ba8a6..1e5b9eb 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -52,9 +52,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -97,13 +97,13 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_aux_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+ 
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -116,20 +116,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_vf_lib.o
+ 
+ ifneq (${ENABLE_SIOV_SUPPORT},)
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+@@ -158,7 +158,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ EXTRA_CFLAGS += -std=gnu11
+ 
+ # ice does not support building on kernels older than 3.10.0
+@@ -178,7 +178,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -223,7 +223,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index c020e40..c1e82a2 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -482,6 +487,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -639,6 +648,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -911,6 +925,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index e9cc474..60bc2ef 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -107,6 +107,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
+ module_param(fwlog_events, ulong, 0644);
+ MODULE_PARM_DESC(fwlog_events, "FW events to log (32-bit mask)\n");
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -7008,6 +7013,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ }
+ 
+@@ -7385,6 +7394,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 0117124..e20f29e 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -237,6 +241,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -424,6 +432,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1675,6 +1693,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.15.6 b/LINUX/final-patches/intel--igb--5.15.6
new file mode 100644
index 000000000..3fb6dcca5
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.15.6
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index f72e6da..c387ecd 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 9d3192f..10ed047 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3243,6 +3247,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3448,6 +3456,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3862,6 +3874,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7437,6 +7452,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8453,6 +8473,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8772,6 +8797,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.19.9 b/LINUX/final-patches/intel--ixgbe--5.19.9
new file mode 100644
index 000000000..fcc8fa08f
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.19.9
@@ -0,0 +1,174 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index 1d4c83e..65cf773 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -29,25 +29,25 @@ define ixgbe-y
+ 	ixgbe_x540.o
+ 	ixgbe_x550.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -120,9 +120,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index b55418c..a342914 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -721,6 +721,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_reset_pf_report - reset pf and print reset report
+  * @tx_ring: tx ring number
+@@ -774,6 +791,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2246,6 +2274,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -3759,6 +3797,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4451,6 +4493,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -13289,6 +13337,10 @@ no_info_string:
+ 		hw->mac.ops.setup_eee(hw, eee_enable);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_register:
+@@ -13347,6 +13399,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.18.9 b/LINUX/final-patches/intel--ixgbevf--4.18.9
new file mode 100644
index 000000000..e041e6309
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.18.9
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index df6689d..03ce8eb 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index bbe4a4f..0827dc8 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -344,6 +344,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -364,6 +381,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1382,6 +1410,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2100,6 +2138,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2334,6 +2376,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5642,8 +5688,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5684,6 +5732,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index afc88b1..104ea20 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -12,6 +12,8 @@
+ 
+ #include "kcompat_gcc.h"
+ 
++#include 
++
+ #include 
+ #include 
+ #include 
diff --git a/LINUX/if_igb_netmap.h b/LINUX/if_igb_netmap.h
index e23ddf631..576a002f0 100644
--- a/LINUX/if_igb_netmap.h
+++ b/LINUX/if_igb_netmap.h
@@ -101,6 +101,11 @@ static inline void NM_WRITE_SRRCTL(struct igb_adapter *adapter, struct igb_ring
 #define	rx_buffer_info			buffer_info
 #endif
 
+#ifdef NETMAP_LINUX_HAVE_IGB_STATE_INDIR
+#define NM_IGB_STATE(a_) (&(a_)->state)
+#else
+#define NM_IGB_STATE(a_) ((a_)->state)
+#endif /* NETMAP_LINUX_HAVE_IGB_STATE_INDIR */
 
 /*
  * Register/unregister. We are already under netmap lock.
@@ -113,7 +118,7 @@ igb_netmap_reg(struct netmap_adapter *na, int onoff)
 	struct SOFTC_T *adapter = netdev_priv(ifp);
 
 	/* protect against other reinit */
-	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+	while (test_and_set_bit(__IGB_RESETTING, NM_IGB_STATE(adapter)))
 		usleep_range(1000, 2000);
 
 	if (netif_running(adapter->netdev))
@@ -130,7 +135,7 @@ igb_netmap_reg(struct netmap_adapter *na, int onoff)
 	else
 		igb_reset(adapter); // XXX is it needed ?
 
-	clear_bit(__IGB_RESETTING, &adapter->state);
+	clear_bit(__IGB_RESETTING, NM_IGB_STATE(adapter));
 	return (0);
 }
 

From 4e1571c411f50fd5d8c7244a35b3cc629dcfc49c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 15 Mar 2024 13:44:35 +0100
Subject: [PATCH 2139/2207] linux/configure: fix inconsistent test naming in
 commit 75d363ded1

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 5e6c960c8..d7b8378b8 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -448,7 +448,7 @@ PERTESTFLAGS=
 # 	for the next test
 add_test_flags() {
 	PERTESTFLAGS="$PERTESTFLAGS
-CFLAGS___test__$NEXTTEST.o := $@"
+CFLAGS_test__$NEXTTEST.o := $@"
 }
 
 reset_tests() {

From c3affab404c54553365a0e8abcc5de6ad1230aac Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Mar 2024 10:08:14 +0100
Subject: [PATCH 2140/2207] linux/ptnet: fix build on recent kernels

---
 LINUX/bsd_glue.h     | 6 ++++++
 LINUX/configure      | 9 +++++++++
 LINUX/netmap_ptnet.c | 2 +-
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 0b6277894..70a5f6508 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -610,4 +610,10 @@ void netmap_bns_unregister(void);
 #define NM_NETIF_NAPI_ADD	netif_napi_add
 #endif /* NETMAP_LINUX_HAVE_NAPI_POLL_WEIGHT */
 
+#ifdef NETMAP_LINUX_HAVE_DEV_ADDR_SET
+#define NM_DEV_ADDR_SET(a_, m_)	dev_addr_set(a_, m_)
+#else
+#define NM_DEV_ADDR_SET(a_, m_)	memcpy((a_)->dev_addr, m_, (a_)->addr_len)
+#endif	/* NETMAP_LINUX_HAVE_DEV_ADDR_SET */
+
 #endif /* NETMAP_BSD_GLUE_H */
diff --git a/LINUX/configure b/LINUX/configure
index d7b8378b8..6ad2db16f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1954,6 +1954,15 @@ EOF
 	}
 EOF
 
+  # check for dev_addr_set()
+  add_test 'have DEV_ADDR_SET' <
+
+	void dummy(struct net_device *dev, const unsigned char *addr) {
+		dev_addr_set(dev, addr);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index 95a1d7322..ce993a5b0 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -1404,7 +1404,7 @@ ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	macaddr[3] = (macreg >> 16) & 0xff;
 	macaddr[4] = (macreg >> 8) & 0xff;
 	macaddr[5] = macreg & 0xff;
-	memcpy(netdev->dev_addr, macaddr, netdev->addr_len);
+	NM_DEV_ADDR_SET(netdev, macaddr);
 
 	netdev->features = NETIF_F_HIGHDMA;
 

From ed5244ade318745025d351a4ff985d1e19d3ec83 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Mar 2024 11:01:41 +0100
Subject: [PATCH 2141/2207] linux/configure: ignore missing protoypes during
 config

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 6ad2db16f..71527ee90 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -836,7 +836,7 @@ EOF
 DISABLED_WARNINGS="unused-but-set-variable attributes packed-not-aligned \
 	stringop-truncation missing-attributes format-truncation \
 	maybe-uninitialized unused-variable unused-label \
-	implicit-fallthrough enum-int-mismatch"
+	implicit-fallthrough enum-int-mismatch missing-prototypes"
 REC_DISABLED_WARNINGS=
 disable_warning() {
 	REC_DISABLED_WARNINGS="$1 $REC_DISABLED_WARNINGS"

From 0c3f594305233277dc38f50ebb93e04bafb1caf0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Mar 2024 11:02:44 +0100
Subject: [PATCH 2142/2207] linux: switch to strscpy if available

---
 LINUX/bsd_glue.h | 4 ++++
 LINUX/configure  | 9 +++++++++
 2 files changed, 13 insertions(+)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 70a5f6508..161de94c7 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -616,4 +616,8 @@ void netmap_bns_unregister(void);
 #define NM_DEV_ADDR_SET(a_, m_)	memcpy((a_)->dev_addr, m_, (a_)->addr_len)
 #endif	/* NETMAP_LINUX_HAVE_DEV_ADDR_SET */
 
+#ifdef NETMAP_LINUX_HAVE_STRSCPY
+#define strlcpy	strscpy
+#endif /* NETMAP_LINUX_HAVE_STRSCPY */
+
 #endif /* NETMAP_BSD_GLUE_H */
diff --git a/LINUX/configure b/LINUX/configure
index 71527ee90..739a22557 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1963,6 +1963,15 @@ EOF
 	}
 EOF
 
+  # check for strscpy()
+  add_test 'have STRSCPY' <
+
+	ssize_t dummy(char *d, const char *s, size_t l) {
+		return strscpy(d, s, l);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################

From 1e577ab973900a96d552feaf5fc0fb92844d598c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Mar 2024 11:21:29 +0100
Subject: [PATCH 2143/2207] linux: use single arg eventfd_signal if needed

---
 LINUX/bsd_glue.h              |  6 ++++++
 LINUX/configure               |  9 +++++++++
 sys/dev/netmap/netmap_kloop.c | 12 ++++++------
 3 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 161de94c7..46d27b503 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -620,4 +620,10 @@ void netmap_bns_unregister(void);
 #define strlcpy	strscpy
 #endif /* NETMAP_LINUX_HAVE_STRSCPY */
 
+#ifdef NETMAP_LINUX_HAVE_EVENTFD_SIG_2ARGS
+#define NM_EVENTFD_SIGNAL(c_)	eventfd_signal(c_, 1)
+#else
+#define NM_EVENTFD_SIGNAL	eventfd_signal
+#endif /* NETMAP_LINUX_HAVE_EVENTFD_SIG_2ARGS */
+
 #endif /* NETMAP_BSD_GLUE_H */
diff --git a/LINUX/configure b/LINUX/configure
index 739a22557..cc1a169a0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1972,6 +1972,15 @@ EOF
 	}
 EOF
 
+  # check for 2nd param of eventfd_signal()
+  add_test 'have EVENTFD_SIG_2ARGS' <
+
+	void dummy(struct eventfd_ctx *ctx) {
+		eventfd_signal(ctx, 1);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index e8f71d772..eb25db972 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -255,7 +255,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 		if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
 			/* We could disable kernel --> application kicks here,
 			 * to avoid spurious interrupts. */
-			eventfd_signal(a->irq_ctx, 1);
+			NM_EVENTFD_SIGNAL(a->irq_ctx);
 			more_txspace = false;
 		}
 #endif /* SYNC_KLOOP_POLL */
@@ -297,7 +297,7 @@ netmap_sync_kloop_tx_ring(const struct sync_kloop_ring_args *a)
 
 #ifdef SYNC_KLOOP_POLL
 	if (a->irq_ctx && more_txspace && csb_atok_intr_enabled(csb_atok)) {
-		eventfd_signal(a->irq_ctx, 1);
+		NM_EVENTFD_SIGNAL(a->irq_ctx);
 	}
 #endif /* SYNC_KLOOP_POLL */
 }
@@ -394,7 +394,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 		if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
 			/* We could disable kernel --> application kicks here,
 			 * to avoid spurious interrupts. */
-			eventfd_signal(a->irq_ctx, 1);
+			NM_EVENTFD_SIGNAL(a->irq_ctx);
 			some_recvd = false;
 		}
 #endif /* SYNC_KLOOP_POLL */
@@ -440,7 +440,7 @@ netmap_sync_kloop_rx_ring(const struct sync_kloop_ring_args *a)
 #ifdef SYNC_KLOOP_POLL
 	/* Interrupt the application if needed. */
 	if (a->irq_ctx && some_recvd && csb_atok_intr_enabled(csb_atok)) {
-		eventfd_signal(a->irq_ctx, 1);
+		NM_EVENTFD_SIGNAL(a->irq_ctx);
 	}
 #endif /* SYNC_KLOOP_POLL */
 }
@@ -529,7 +529,7 @@ sync_kloop_tx_irq_wake_fun(wait_queue_t *wait, unsigned mode,
 		struct eventfd_ctx *irq_ctx = poll_ctx->entries[i].irq_ctx;
 
 		if (irq_ctx) {
-			eventfd_signal(irq_ctx, 1);
+			NM_EVENTFD_SIGNAL(irq_ctx);
 		}
 	}
 
@@ -561,7 +561,7 @@ sync_kloop_rx_irq_wake_fun(wait_queue_t *wait, unsigned mode,
 		struct eventfd_ctx *irq_ctx = poll_ctx->entries[i].irq_ctx;
 
 		if (irq_ctx) {
-			eventfd_signal(irq_ctx, 1);
+			NM_EVENTFD_SIGNAL(irq_ctx);
 		}
 	}
 

From 3fe7dee61cfcd4cfb214ec65006e1d150749c4fb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Mar 2024 11:35:31 +0100
Subject: [PATCH 2144/2207] linux: add decls/static to fix build on 6.8

---
 LINUX/ice_netmap_linux.h     | 4 ++--
 LINUX/netmap_linux.c         | 9 ++++++---
 LINUX/netmap_ptnet.c         | 6 +++++-
 sys/dev/netmap/netmap_kern.h | 7 +++----
 4 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index 212f6c6bb..59dc80f10 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -28,7 +28,7 @@ extern int ix_crcstrip;
  * methods should be handled by the individual drivers.
  */
 
-int
+static int
 ice_netmap_txsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
@@ -203,7 +203,7 @@ ice_netmap_txsync(struct netmap_kring *kring, int flags)
  * If (flags & NAF_FORCE_READ) also check for incoming packets irrespective
  * of whether or not we received an interrupt.
  */
-int
+static int
 ice_netmap_rxsync(struct netmap_kring *kring, int flags)
 {
 	struct netmap_adapter *na = kring->na;
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 1afa4c3ab..e205781ac 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1390,6 +1390,9 @@ linux_netmap_change_mtu(struct net_device *dev, int new_mtu)
  *
  * Linux calls this while holding the rtnl_lock().
  */
+#ifdef NETMAP_LINUX_HAVE_AX25PTR
+static
+#endif
 int
 linux_netmap_set_ringparam(struct net_device *dev,
 	struct ethtool_ringparam *e
@@ -2071,7 +2074,7 @@ ptnetmap_guest_init(void)
 /*
  * Driver Exit Cleanup Routine
  */
-void
+static void
 ptnetmap_guest_fini(void)
 {
 	/* unregister pci driver */
@@ -2193,7 +2196,7 @@ static const struct net_device_ops nm_sink_netdev_ops = {
 	.ndo_start_xmit = nm_sink_start_xmit,
 };
 
-int
+static int
 netmap_sink_init(void)
 {
 	struct netmap_adapter na;
@@ -2228,7 +2231,7 @@ netmap_sink_init(void)
 	return 0;
 }
 
-void
+static void
 netmap_sink_fini(void)
 {
 	struct net_device *netdev = nm_sink_netdev;
diff --git a/LINUX/netmap_ptnet.c b/LINUX/netmap_ptnet.c
index ce993a5b0..ac4ffef6e 100644
--- a/LINUX/netmap_ptnet.c
+++ b/LINUX/netmap_ptnet.c
@@ -41,6 +41,10 @@ extern int ptnet_vnet_hdr;
 static bool ptnet_gso = true;
 module_param(ptnet_gso, bool, 0644);
 
+int ptnet_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+void ptnet_remove(struct pci_dev *pdev);
+void ptnet_shutdown(struct pci_dev *pdev);
+
 /* Enable to debug RX-side hangs */
 //#define HANGCTRL
 
@@ -755,7 +759,7 @@ ptnet_netpoll(struct net_device *netdev)
 #endif
 
 
-unsigned int
+static unsigned int
 ptnet_get_irq_vector(struct ptnet_info *pi, unsigned int i)
 {
 #ifdef NETMAP_LINUX_HAVE_PCI_ENABLE_MSIX
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 669048f17..a9735c320 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1370,14 +1370,13 @@ int netmap_rx_irq(if_t, u_int, u_int *);
 #define netmap_tx_irq(_n, _q) netmap_rx_irq(_n, _q, NULL)
 int netmap_common_irq(struct netmap_adapter *, u_int, u_int *work_done);
 
-
+const char *netmap_bdg_name(struct netmap_vp_adapter *);
 #ifdef WITH_VALE
 /* functions used by external modules to interface with VALE */
 #define netmap_vp_to_ifp(_vp)	((_vp)->up.ifp)
 #define netmap_ifp_to_vp(_ifp)	(NA(_ifp)->na_vp)
 #define netmap_ifp_to_host_vp(_ifp) (NA(_ifp)->na_hostvp)
 #define netmap_bdg_idx(_vp)	((_vp)->bdg_port)
-const char *netmap_bdg_name(struct netmap_vp_adapter *);
 #else /* !WITH_VALE */
 #define netmap_vp_to_ifp(_vp)	NULL
 #define netmap_ifp_to_vp(_ifp)	NULL
@@ -2122,6 +2121,8 @@ struct netmap_monitor_adapter {
 #endif /* WITH_MONITOR */
 
 
+int nm_os_generic_find_num_desc(if_t ifp, u_int *tx, u_int *rx);
+void nm_os_generic_find_num_queues(if_t ifp, u_int *txq, u_int *rxq);
 #ifdef WITH_GENERIC
 /*
  * generic netmap emulation for devices that do not have
@@ -2156,8 +2157,6 @@ struct nm_os_gen_arg {
 };
 
 int nm_os_generic_xmit_frame(struct nm_os_gen_arg *);
-int nm_os_generic_find_num_desc(if_t ifp, u_int *tx, u_int *rx);
-void nm_os_generic_find_num_queues(if_t ifp, u_int *txq, u_int *rxq);
 void nm_os_generic_set_features(struct netmap_generic_adapter *gna);
 
 static inline if_t

From f227a8d257212a4b360545bdf61f62c1e217dafe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 16 Mar 2024 19:13:10 +0100
Subject: [PATCH 2145/2207] linux/virtio_net: fix name clash in 6.8

---
 ...99 => vanilla--virtio_net.c--60500--60800} |   0
 .../vanilla--virtio_net.c--60800--99999       | 100 ++++++++++++++++++
 LINUX/virtio_netmap.h                         |   6 ++
 3 files changed, 106 insertions(+)
 rename LINUX/final-patches/{vanilla--virtio_net.c--60500--99999 => vanilla--virtio_net.c--60500--60800} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--60800--99999

diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60500--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60500--60800
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--60500--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--60500--60800
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60800--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60800--99999
new file mode 100644
index 000000000..3596812da
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--60800--99999
@@ -0,0 +1,100 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index d7ce4a1011ea..d4234a5eeea2 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -331,6 +331,10 @@ struct virtnet_info {
+ 	struct failover *failover;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_v1_hash hdr;
+ 	/*
+@@ -482,6 +486,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -2198,6 +2207,18 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int xdp_xmit = 0;
+ 	bool napi_complete;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		nm_napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -2262,6 +2283,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	enable_delayed_refill(vi);
+ 
+@@ -4838,6 +4868,12 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		goto free_unregister_netdev;
+ 	}
+ 
++	virtnet_set_queues(vi, vi->curr_queue_pairs);
++
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	netif_carrier_off(dev);
+@@ -4890,7 +4926,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -4966,6 +5009,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {
diff --git a/LINUX/virtio_netmap.h b/LINUX/virtio_netmap.h
index 0c2eafa4d..bb15287c3 100644
--- a/LINUX/virtio_netmap.h
+++ b/LINUX/virtio_netmap.h
@@ -704,4 +704,10 @@ virtio_netmap_attach(struct virtnet_info *vi)
 			na.num_tx_rings, na.num_tx_desc,
 			na.num_rx_rings, na.num_rx_desc);
 }
+
+static inline void
+nm_napi_complete(struct napi_struct *napi)
+{
+	napi_complete(napi);
+}
 /* end of file */

From d05b0227bd04c1f5132c2f0b3a3df1b4ae937496 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2024 14:04:44 +0100
Subject: [PATCH 2146/2207] sink: refactor in preparation for multiple sinks

---
 LINUX/netmap_linux.c | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index e205781ac..f3234321c 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2105,7 +2105,11 @@ ptnetmap_guest_fini(void)
 static int sink_delay_ns = 100;
 module_param(sink_delay_ns, int, 0644);
 static struct net_device *nm_sink_netdev = NULL; /* global sink netdev */
-s64 nm_sink_next_link_idle; /* for link emulation */
+
+struct netmap_sink_adapter {
+	struct netmap_hw_adapter up;
+	s64 next_link_idle;
+};
 
 #define NM_SINK_SLOTS	1024
 #define NM_SINK_DELAY_NS \
@@ -2114,36 +2118,41 @@ s64 nm_sink_next_link_idle; /* for link emulation */
 static int
 nm_sink_register(struct netmap_adapter *na, int onoff)
 {
+	struct netmap_sink_adapter *sa =
+		(struct netmap_sink_adapter *)na;
+
 	if (onoff)
 		nm_set_native_flags(na);
 	else
 		nm_clear_native_flags(na);
 
-	nm_sink_next_link_idle = ktime_get_ns();
+	sa->next_link_idle = ktime_get_ns();
 
 	return 0;
 }
 
 static inline void
-nm_sink_emu(unsigned int n)
+nm_sink_emu(struct netmap_adapter *na, unsigned int n)
 {
-	u64 wait_until = nm_sink_next_link_idle;
+	struct netmap_sink_adapter *sa =
+		(struct netmap_sink_adapter *)na;
+	u64 wait_until = sa->next_link_idle;
 	u64 now = ktime_get_ns();
 
-	if (sink_delay_ns < 0 || nm_sink_next_link_idle < now) {
+	if (sink_delay_ns < 0 || sa->next_link_idle < now) {
 		/* If we are emulating packet consumer mode or the link went
 		 * idle some time ago, we need to update the link emulation
 		 * variable, because we don't want the caller to accumulate
 		 * credit. */
-		nm_sink_next_link_idle = now;
+		sa->next_link_idle = now;
 	}
 	/* Schedule new transmissions. */
-	nm_sink_next_link_idle += n * NM_SINK_DELAY_NS;
+	sa->next_link_idle += n * NM_SINK_DELAY_NS;
 	if (sink_delay_ns < 0) {
 		/* In packet consumer mode we emulate synchronous
 		 * transmission, so we have to wait right now for the link
 		 * to become idle. */
-		wait_until = nm_sink_next_link_idle;
+		wait_until = sa->next_link_idle;
 	}
 	while (ktime_get_ns() < wait_until) ;
 }
@@ -2162,7 +2171,7 @@ nm_sink_txsync(struct netmap_kring *kring, int flags)
 	kring->nr_hwcur = head;
 	kring->nr_hwtail = nm_prev(kring->nr_hwcur, lim);
 
-	nm_sink_emu(n);
+	nm_sink_emu(kring->na, n);
 
 	return 0;
 }
@@ -2186,7 +2195,7 @@ static netdev_tx_t
 nm_sink_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	kfree_skb(skb);
-	nm_sink_emu(1);
+	nm_sink_emu(NA(netdev), 1);
 	return NETDEV_TX_OK;
 }
 
@@ -2223,7 +2232,9 @@ netmap_sink_init(void)
 	na.nm_txsync = nm_sink_txsync;
 	na.nm_rxsync = nm_sink_rxsync;
 	na.num_tx_rings = na.num_rx_rings = 1;
-	netmap_attach(&na);
+	if (netmap_attach_ext(&na, sizeof(struct netmap_sink_adapter), 1)) {
+		dev_err(&netdev->dev, "failed to attach netmap adapter");
+	}
 
 	netif_carrier_on(netdev);
 	nm_sink_netdev = netdev;

From b4e94f0dccde7a8afadc1a79e032ea6c72fc44f1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 18 Mar 2024 14:33:30 +0100
Subject: [PATCH 2147/2207] sink: add option to create multiple sink devices

---
 LINUX/netmap_linux.c | 87 +++++++++++++++++++++++++++++---------------
 1 file changed, 58 insertions(+), 29 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index f3234321c..dd9ec3557 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2104,7 +2104,11 @@ ptnetmap_guest_fini(void)
  */
 static int sink_delay_ns = 100;
 module_param(sink_delay_ns, int, 0644);
-static struct net_device *nm_sink_netdev = NULL; /* global sink netdev */
+#define NM_MAX_SINKS	100
+static int sink_num = 1;
+static int sink_actual_num = 0;
+module_param(sink_num, int, 0644);
+static struct net_device **nm_sink_netdev = NULL; /* global sink netdev */
 
 struct netmap_sink_adapter {
 	struct netmap_hw_adapter up;
@@ -2210,47 +2214,72 @@ netmap_sink_init(void)
 {
 	struct netmap_adapter na;
 	struct net_device *netdev;
-	int err;
+	int i, err = 0;
 
-	netdev = alloc_etherdev(0);
-	if (!netdev) {
-		return -ENOMEM;
-	}
-	netdev->netdev_ops = &nm_sink_netdev_ops ;
-	strlcpy(netdev->name, "nmsink", sizeof(netdev->name));
-	netdev->features = NETIF_F_HIGHDMA;
-	err = register_netdev(netdev);
-	if (err) {
-		free_netdev(netdev);
+	sink_actual_num = sink_num;
+
+	if (sink_actual_num > NM_MAX_SINKS) {
+		pr_err("too many netmap sink devices (max %d)", NM_MAX_SINKS);
+		return -EINVAL;
 	}
 
-	bzero(&na, sizeof(na));
-	na.ifp = netdev;
-	na.num_tx_desc = NM_SINK_SLOTS;
-	na.num_rx_desc = NM_SINK_SLOTS;
-	na.nm_register = nm_sink_register;
-	na.nm_txsync = nm_sink_txsync;
-	na.nm_rxsync = nm_sink_rxsync;
-	na.num_tx_rings = na.num_rx_rings = 1;
-	if (netmap_attach_ext(&na, sizeof(struct netmap_sink_adapter), 1)) {
-		dev_err(&netdev->dev, "failed to attach netmap adapter");
+	nm_sink_netdev = nm_os_malloc(sizeof(struct netdev *) * sink_actual_num);
+	if (!nm_sink_netdev) {
+		return -ENOMEM;
 	}
 
-	netif_carrier_on(netdev);
-	nm_sink_netdev = netdev;
+	for (i = 0; i < sink_actual_num; i++) {
+		netdev = alloc_etherdev(0);
+		if (!netdev) {
+			err = -ENOMEM;
+			break;
+		}
+		netdev->netdev_ops = &nm_sink_netdev_ops ;
+		strlcpy(netdev->name, "nmsink%d", sizeof(netdev->name));
+		netdev->features = NETIF_F_HIGHDMA;
+		err = register_netdev(netdev);
+		if (err) {
+			free_netdev(netdev);
+			break;
+		}
 
-	return 0;
+		bzero(&na, sizeof(na));
+		na.ifp = netdev;
+		na.num_tx_desc = NM_SINK_SLOTS;
+		na.num_rx_desc = NM_SINK_SLOTS;
+		na.nm_register = nm_sink_register;
+		na.nm_txsync = nm_sink_txsync;
+		na.nm_rxsync = nm_sink_rxsync;
+		na.num_tx_rings = na.num_rx_rings = 1;
+		if (netmap_attach_ext(&na, sizeof(struct netmap_sink_adapter), 1)) {
+			dev_err(&netdev->dev, "failed to attach netmap adapter");
+			unregister_netdev(netdev);
+			free_netdev(netdev);
+			break;
+		}
+
+		netif_carrier_on(netdev);
+		nm_sink_netdev[i] = netdev;
+	}
+	sink_actual_num = i;
+
+	return err;
 }
 
 static void
 netmap_sink_fini(void)
 {
-	struct net_device *netdev = nm_sink_netdev;
+	struct net_device *netdev;
+	int i;
 
+	for (i = 0; i < sink_actual_num; i++) {
+		netdev = nm_sink_netdev[i];
+		unregister_netdev(netdev);
+		netmap_detach(netdev);
+		free_netdev(netdev);
+	}
+	kfree(nm_sink_netdev);
 	nm_sink_netdev = NULL;
-	unregister_netdev(netdev);
-	netmap_detach(netdev);
-	free_netdev(netdev);
 }
 #endif  /* WITH_SINK */
 

From f4bf86f7ad4e10fed4e42749f82be20e0b8d2407 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Mar 2024 07:25:54 +0100
Subject: [PATCH 2148/2207] linux/ice: fix netmap suffix in Makefile

---
 LINUX/final-patches/intel--ice--1.11.17.1 | 26 +++++++++----
 LINUX/final-patches/intel--ice--1.12.18   | 45 +++++++++++++++++------
 LINUX/final-patches/intel--ice--1.12.6    | 45 +++++++++++++++++------
 LINUX/final-patches/intel--ice--1.12.7    | 45 +++++++++++++++++------
 LINUX/final-patches/intel--ice--1.13.7    | 45 +++++++++++++++++------
 5 files changed, 151 insertions(+), 55 deletions(-)

diff --git a/LINUX/final-patches/intel--ice--1.11.17.1 b/LINUX/final-patches/intel--ice--1.11.17.1
index ac270f923..04143ac4d 100644
--- a/LINUX/final-patches/intel--ice--1.11.17.1
+++ b/LINUX/final-patches/intel--ice--1.11.17.1
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 5f29380..e6499f6 100644
+index 5f29380..ae7008b 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -32,7 +32,7 @@ index 5f29380..e6499f6 100644
  	ice_dcf.o			\
  	ice_sriov.o			\
  	ice_vf_mbx.o			\
-@@ -87,20 +87,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+@@ -87,30 +87,30 @@ ice-$(CONFIG_PCI_IOV) +=		\
  	ice_vf_lib.o
  
  ifneq (${ENABLE_SIOV_SUPPORT},)
@@ -44,11 +44,11 @@ index 5f29380..e6499f6 100644
 -ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
 -ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
 -ice-y += kcompat.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
  # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
  ifndef CONFIG_PLDMFW
 -ice-y += kcompat_pldmfw.o
@@ -61,6 +61,18 @@ index 5f29380..e6499f6 100644
  endif
  # Use kcompat GNSS if kernel doesn't provide it
  ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ 
 @@ -123,7 +123,7 @@ endif
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile
diff --git a/LINUX/final-patches/intel--ice--1.12.18 b/LINUX/final-patches/intel--ice--1.12.18
index 357638457..9dc7ab8d6 100644
--- a/LINUX/final-patches/intel--ice--1.12.18
+++ b/LINUX/final-patches/intel--ice--1.12.18
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 62548b3..65ac0f4 100644
+index 62548b3..018ca55 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -52,9 +52,9 @@ ifneq ($(KERNELRELEASE),)
@@ -23,18 +23,18 @@ index 62548b3..65ac0f4 100644
 -ice-y += ice_peer_support.o
 -ice-y += ice_idc.o
 -ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
  
 -ice-$(CONFIG_PCI_IOV) +=		\
 +ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
  	ice_dcf.o			\
  	ice_sriov.o			\
  	ice_vf_mbx.o			\
-@@ -115,20 +115,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+@@ -115,37 +115,37 @@ ice-$(CONFIG_PCI_IOV) +=		\
  	ice_vf_lib.o
  
  ifneq (${ENABLE_SIOV_SUPPORT},)
@@ -46,11 +46,11 @@ index 62548b3..65ac0f4 100644
 -ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
 -ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
 -ice-y += kcompat.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
  # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
  ifndef CONFIG_PLDMFW
 -ice-y += kcompat_pldmfw.o
@@ -63,6 +63,27 @@ index 62548b3..65ac0f4 100644
  endif
  # Use kcompat GNSS if kernel doesn't provide it
  ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq (${ENABLE_LM_SUPPORT},)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
 @@ -157,7 +157,7 @@ endif
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile
diff --git a/LINUX/final-patches/intel--ice--1.12.6 b/LINUX/final-patches/intel--ice--1.12.6
index c1db7d7c7..3e6e81668 100644
--- a/LINUX/final-patches/intel--ice--1.12.6
+++ b/LINUX/final-patches/intel--ice--1.12.6
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 16ec261..783a3ba 100644
+index 16ec261..8b2034b 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -23,18 +23,18 @@ index 16ec261..783a3ba 100644
 -ice-y += ice_peer_support.o
 -ice-y += ice_idc.o
 -ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
  
 -ice-$(CONFIG_PCI_IOV) +=		\
 +ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
  	ice_dcf.o			\
  	ice_sriov.o			\
  	ice_vf_mbx.o			\
-@@ -89,20 +89,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+@@ -89,37 +89,37 @@ ice-$(CONFIG_PCI_IOV) +=		\
  	ice_vf_lib.o
  
  ifneq (${ENABLE_SIOV_SUPPORT},)
@@ -46,11 +46,11 @@ index 16ec261..783a3ba 100644
 -ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
 -ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
 -ice-y += kcompat.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
  # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
  ifndef CONFIG_PLDMFW
 -ice-y += kcompat_pldmfw.o
@@ -63,6 +63,27 @@ index 16ec261..783a3ba 100644
  endif
  # Use kcompat GNSS if kernel doesn't provide it
  ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq (${ENABLE_LM_SUPPORT},)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
 @@ -131,7 +131,7 @@ endif
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile
diff --git a/LINUX/final-patches/intel--ice--1.12.7 b/LINUX/final-patches/intel--ice--1.12.7
index 135b11f87..7fe66f63b 100644
--- a/LINUX/final-patches/intel--ice--1.12.7
+++ b/LINUX/final-patches/intel--ice--1.12.7
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 16ec261..783a3ba 100644
+index 16ec261..8b2034b 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -26,9 +26,9 @@ ifneq ($(KERNELRELEASE),)
@@ -23,18 +23,18 @@ index 16ec261..783a3ba 100644
 -ice-y += ice_peer_support.o
 -ice-y += ice_idc.o
 -ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_peer_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
  
 -ice-$(CONFIG_PCI_IOV) +=		\
 +ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
  	ice_dcf.o			\
  	ice_sriov.o			\
  	ice_vf_mbx.o			\
-@@ -89,20 +89,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+@@ -89,37 +89,37 @@ ice-$(CONFIG_PCI_IOV) +=		\
  	ice_vf_lib.o
  
  ifneq (${ENABLE_SIOV_SUPPORT},)
@@ -46,11 +46,11 @@ index 16ec261..783a3ba 100644
 -ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
 -ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
 -ice-y += kcompat.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
  # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
  ifndef CONFIG_PLDMFW
 -ice-y += kcompat_pldmfw.o
@@ -63,6 +63,27 @@ index 16ec261..783a3ba 100644
  endif
  # Use kcompat GNSS if kernel doesn't provide it
  ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq (${ENABLE_LM_SUPPORT},)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
 @@ -131,7 +131,7 @@ endif
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile
diff --git a/LINUX/final-patches/intel--ice--1.13.7 b/LINUX/final-patches/intel--ice--1.13.7
index a6ff98d65..360da8362 100644
--- a/LINUX/final-patches/intel--ice--1.13.7
+++ b/LINUX/final-patches/intel--ice--1.13.7
@@ -1,5 +1,5 @@
 diff --git a/ice/Makefile b/ice/Makefile
-index 66ba8a6..1e5b9eb 100644
+index 66ba8a6..436d2e2 100644
 --- a/ice/Makefile
 +++ b/ice/Makefile
 @@ -52,9 +52,9 @@ ifneq ($(KERNELRELEASE),)
@@ -23,18 +23,18 @@ index 66ba8a6..1e5b9eb 100644
 -ice-y += ice_aux_support.o
 -ice-y += ice_idc.o
 -ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
  
 -ice-$(CONFIG_PCI_IOV) +=		\
 +ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
  	ice_dcf.o			\
  	ice_sriov.o			\
  	ice_vf_mbx.o			\
-@@ -116,20 +116,20 @@ ice-$(CONFIG_PCI_IOV) +=		\
+@@ -116,37 +116,37 @@ ice-$(CONFIG_PCI_IOV) +=		\
  	ice_vf_lib.o
  
  ifneq (${ENABLE_SIOV_SUPPORT},)
@@ -46,11 +46,11 @@ index 66ba8a6..1e5b9eb 100644
 -ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
 -ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
 -ice-y += kcompat.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
-+ice-$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
  # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
  ifndef CONFIG_PLDMFW
 -ice-y += kcompat_pldmfw.o
@@ -63,6 +63,27 @@ index 66ba8a6..1e5b9eb 100644
  endif
  # Use kcompat GNSS if kernel doesn't provide it
  ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq (${ENABLE_LM_SUPPORT},)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
 @@ -158,7 +158,7 @@ endif
  else	# ifneq($(KERNELRELEASE),)
  # normal makefile

From 1978f453b41810f963d7fb8d9efae4d0c2c77b1a Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Mar 2024 07:46:47 +0100
Subject: [PATCH 2149/2207] linux/ice: move netmap_attach to end of probe

---
 LINUX/final-patches/intel--ice--1.12.18 | 17 +++++++++++++----
 LINUX/final-patches/intel--ice--1.12.6  | 17 +++++++++++++----
 LINUX/final-patches/intel--ice--1.12.7  | 17 +++++++++++++----
 LINUX/final-patches/intel--ice--1.13.7  | 17 +++++++++++++----
 4 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/LINUX/final-patches/intel--ice--1.12.18 b/LINUX/final-patches/intel--ice--1.12.18
index 9dc7ab8d6..6722cec49 100644
--- a/LINUX/final-patches/intel--ice--1.12.18
+++ b/LINUX/final-patches/intel--ice--1.12.18
@@ -162,7 +162,7 @@ index 84adc70..3a910f1 100644
  	return 0;
  }
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index 112e871..8c28abc 100644
+index 112e871..202face 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -105,6 +105,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
@@ -177,18 +177,27 @@ index 112e871..8c28abc 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -6841,6 +6846,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+@@ -6841,6 +6846,7 @@ static int ice_init_devlink(struct ice_pf *pf)
  	if (need_register)
  		ice_devlink_register(pf);
  #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7122,6 +7128,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
 +
 +#ifdef DEV_NETMAP
 +	ice_netmap_attach(pf);
 +#endif
++
  	return 0;
- }
  
-@@ -7214,6 +7223,10 @@ static void ice_remove(struct pci_dev *pdev)
+ err_init_features:
+@@ -7214,6 +7225,10 @@ static void ice_remove(struct pci_dev *pdev)
  	if (!pf)
  		return;
  
diff --git a/LINUX/final-patches/intel--ice--1.12.6 b/LINUX/final-patches/intel--ice--1.12.6
index 3e6e81668..125db4d82 100644
--- a/LINUX/final-patches/intel--ice--1.12.6
+++ b/LINUX/final-patches/intel--ice--1.12.6
@@ -162,7 +162,7 @@ index 84adc70..3a910f1 100644
  	return 0;
  }
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index 8f515cd..1aa4974 100644
+index 8f515cd..b15f994 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -105,6 +105,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
@@ -177,18 +177,27 @@ index 8f515cd..1aa4974 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -6828,6 +6833,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+@@ -6828,6 +6833,7 @@ static int ice_init_devlink(struct ice_pf *pf)
  	if (need_register)
  		ice_devlink_register(pf);
  #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7109,6 +7115,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
 +
 +#ifdef DEV_NETMAP
 +	ice_netmap_attach(pf);
 +#endif
++
  	return 0;
- }
  
-@@ -7201,6 +7210,10 @@ static void ice_remove(struct pci_dev *pdev)
+ err_init_features:
+@@ -7201,6 +7212,10 @@ static void ice_remove(struct pci_dev *pdev)
  	if (!pf)
  		return;
  
diff --git a/LINUX/final-patches/intel--ice--1.12.7 b/LINUX/final-patches/intel--ice--1.12.7
index 7fe66f63b..26008b4cc 100644
--- a/LINUX/final-patches/intel--ice--1.12.7
+++ b/LINUX/final-patches/intel--ice--1.12.7
@@ -162,7 +162,7 @@ index 84adc70..3a910f1 100644
  	return 0;
  }
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index a32bb2a..1a116db 100644
+index a32bb2a..5b455c5 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -105,6 +105,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
@@ -177,18 +177,27 @@ index a32bb2a..1a116db 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -6835,6 +6840,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+@@ -6835,6 +6840,7 @@ static int ice_init_devlink(struct ice_pf *pf)
  	if (need_register)
  		ice_devlink_register(pf);
  #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7116,6 +7122,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
 +
 +#ifdef DEV_NETMAP
 +	ice_netmap_attach(pf);
 +#endif
++
  	return 0;
- }
  
-@@ -7208,6 +7217,10 @@ static void ice_remove(struct pci_dev *pdev)
+ err_init_features:
+@@ -7208,6 +7219,10 @@ static void ice_remove(struct pci_dev *pdev)
  	if (!pf)
  		return;
  
diff --git a/LINUX/final-patches/intel--ice--1.13.7 b/LINUX/final-patches/intel--ice--1.13.7
index 360da8362..d093ccd07 100644
--- a/LINUX/final-patches/intel--ice--1.13.7
+++ b/LINUX/final-patches/intel--ice--1.13.7
@@ -162,7 +162,7 @@ index c020e40..c1e82a2 100644
  	return 0;
  }
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index e9cc474..60bc2ef 100644
+index e9cc474..0eed1e5 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -107,6 +107,11 @@ static unsigned long fwlog_events; /* no enabled events by default */
@@ -177,18 +177,27 @@ index e9cc474..60bc2ef 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -7008,6 +7013,10 @@ static int ice_init_devlink(struct ice_pf *pf)
+@@ -7008,6 +7013,7 @@ static int ice_init_devlink(struct ice_pf *pf)
  	if (need_register)
  		ice_devlink_register(pf);
  #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7294,6 +7300,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
 +
 +#ifdef DEV_NETMAP
 +	ice_netmap_attach(pf);
 +#endif
++
  	return 0;
- }
  
-@@ -7385,6 +7394,10 @@ static void ice_remove(struct pci_dev *pdev)
+ err_init_features:
+@@ -7385,6 +7396,10 @@ static void ice_remove(struct pci_dev *pdev)
  	if (!pf)
  		return;
  

From cfdc6861ae2398cde12323dbeeb3cfe48c3a4e6c Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 20 Mar 2024 08:05:19 +0100
Subject: [PATCH 2150/2207] fix declaration of flexible arrays

---
 sys/net/netmap.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 74150f608..241cd7bde 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -323,7 +323,7 @@ struct netmap_ring {
 #endif
 
 	/* the slots follow. This struct has variable size */
-	struct netmap_slot slot[0];	/* array of slots. */
+	struct netmap_slot slot[];	/* array of slots. */
 };
 
 
@@ -402,7 +402,7 @@ struct netmap_if {
 	 * The area is filled up by the kernel on NETMAP_REQ_REGISTER,
 	 * and then only read by userspace code.
 	 */
-	const ssize_t	ring_ofs[0];
+	const ssize_t	ring_ofs[];
 };
 
 /* Legacy interface to interact with a netmap control device.
@@ -940,7 +940,7 @@ struct nmreq_opt_sync_kloop_eventfds {
 		int32_t ioeventfd;
 		/* Notifier for the kernel loop --> application direction. */
 		int32_t irqfd;
-	} eventfds[0];
+	} eventfds[];
 };
 
 struct nmreq_opt_sync_kloop_mode {

From 65bcd3e00f6709b36a5137fb9df50bf14243acbe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 22 Mar 2024 13:36:15 +0100
Subject: [PATCH 2151/2207] linux: reduce scope of vlan functions fallback
 definitions

Move the fallback definitions of eth_type_vlan etc. to the only file
where they are needed. The definitions in bsd_glue.h clashed with
similar definitions in kcompat.h for some Intel external drivers.
---
 LINUX/bsd_glue.h     | 25 -------------------------
 LINUX/netmap_linux.c | 25 +++++++++++++++++++++++++
 2 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 46d27b503..88bfb4f15 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -191,31 +191,6 @@ static inline int skb_checksum_start_offset(const struct sk_buff *skb) {
 #define page_to_virt(p) 		phys_to_virt(page_to_phys(p))
 #endif /* NETMAP_LINUX_HAVE_PAGE_TO_VIRT */
 
-#ifdef NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG
-#ifndef NETMAP_LINUX_HAVE_ETH_TYPE_VLAN
-static inline bool eth_type_vlan(__be16 ethertype)
-{
-	return ethertype == htons(ETH_P_8021Q) ||
-		ethertype == htons(ETH_P_8021AD);
-}
-#endif /* NETMAP_LINUX_HAVE_ETH_TYPE_VLAN */
-
-#ifndef NETMAP_LINUX_HAVE_SKB_VLAN_TAG_PRESENT
-#define skb_vlan_tag_present(__skb)	vlan_tx_tag_present(__skb)
-#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_TAG_PRESENT */
-
-#ifndef NETMAP_LINUX_HAVE_VLAN_HWACCEL_PUSH_INSIDE
-static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
-{
-	skb = __vlan_put_tag(skb, skb->vlan_proto,
-			vlan_tx_tag_get(skb));
-	if (likely(skb))
-		skb->vlan_tci = 0;
-	return skb;
-}
-#endif /* NETMAP_LINUX_HAVE_VLAN_HWACCESS_PUSH_INSIDE */
-#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG */
-
 /*----------- end of LINUX_VERSION_CODE dependencies ----------*/
 
 /* Type redefinitions. XXX check them */
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index dd9ec3557..130d1740b 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -45,6 +45,31 @@
 
 #include "netmap_linux_config.h"
 
+#ifdef NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG
+#ifndef NETMAP_LINUX_HAVE_ETH_TYPE_VLAN
+static inline bool eth_type_vlan(__be16 ethertype)
+{
+	return ethertype == htons(ETH_P_8021Q) ||
+		ethertype == htons(ETH_P_8021AD);
+}
+#endif /* NETMAP_LINUX_HAVE_ETH_TYPE_VLAN */
+
+#ifndef NETMAP_LINUX_HAVE_SKB_VLAN_TAG_PRESENT
+#define skb_vlan_tag_present(__skb)	vlan_tx_tag_present(__skb)
+#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_TAG_PRESENT */
+
+#ifndef NETMAP_LINUX_HAVE_VLAN_HWACCEL_PUSH_INSIDE
+static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
+{
+	skb = __vlan_put_tag(skb, skb->vlan_proto,
+			vlan_tx_tag_get(skb));
+	if (likely(skb))
+		skb->vlan_tci = 0;
+	return skb;
+}
+#endif /* NETMAP_LINUX_HAVE_VLAN_HWACCESS_PUSH_INSIDE */
+#endif /* NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG */
+
 void *
 nm_os_malloc(size_t size)
 {

From 988fe36dfb54a3630ac4371de3d96e27bb0e500e Mon Sep 17 00:00:00 2001
From: James Darnley 
Date: Tue, 12 Mar 2024 16:41:44 +0100
Subject: [PATCH 2152/2207] download a smaller mellanox source tarball

---
 LINUX/default-config.mak.in_ | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 3618af75f..ce04cc3aa 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -105,8 +105,8 @@ e1000e@fetch := test -e @SRCDIR@/ext-drivers/e1000e-$(e1000e@v).tar.gz || wget h
 endif
 
 define mellanox_driver
-$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz || wget http://content.mellanox.com/ofed/MLNX_EN-$(2)/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz -P @SRCDIR@/ext-drivers
-$(1)@src	:= tar xf @SRCDIR@/ext-drivers/mlnx-en-$(2)-ubuntu18.04-x86_64.tgz && tar xf mlnx-en-$(2)-ubuntu18.04-x86_64/src/MLNX_EN_SRC-$(2).tgz && tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
+$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/MLNX_EN_SRC-debian-$(2).tgz || wget https://content.mellanox.com/ofed/MLNX_EN-$(2)/MLNX_EN_SRC-debian-$(2).tgz -P @SRCDIR@/ext-drivers
+$(1)@src	:= tar xf @SRCDIR@/ext-drivers/MLNX_EN_SRC-debian-$(2).tgz&& tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
 $(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@
 $(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$$($(1)@cflags) $(EXTRA_CFLAGS)"

From 9174a59262d3111ef6f0edc377246e929a5a5744 Mon Sep 17 00:00:00 2001
From: James Darnley 
Date: Tue, 2 Apr 2024 18:53:25 +0200
Subject: [PATCH 2153/2207] Add mlx5 version 5.8 support

---
 LINUX/default-config.mak.in_            |   2 +-
 LINUX/final-patches/mellanox--mlx5--5.8 | 446 ++++++++++++++++++++++++
 LINUX/mlx5_netmap_linux.h               |   2 +-
 3 files changed, 448 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--5.8

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index ce04cc3aa..933a6b4cb 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -116,7 +116,7 @@ $(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
 $(1)@force	:= 1
 endef
 
-$(eval $(call default,mlx5,5.4-1.0.3.0))
+$(eval $(call default,mlx5,5.8-3.0.7.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 mlx5@cflags	= -Wframe-larger-than=2000
diff --git a/LINUX/final-patches/mellanox--mlx5--5.8 b/LINUX/final-patches/mellanox--mlx5--5.8
new file mode 100644
index 000000000..ba8eb6cc8
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--5.8
@@ -0,0 +1,446 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 2a88532..37d3415 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -6,12 +6,12 @@
+ 
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o fs_ft_pool.o rl.o lag/lag.o lag/debugfs.o dev.o events.o wq.o lib/gid.o \
+@@ -21,11 +21,11 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		diag/diag_cnt.o params.o fw_exp.o lib/tout.o eswitch_devlink_compat.o \
+ 		ecpf.o lib/aso.o
+ 
+-mlx5_core-y += compat.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y += compat.o
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
+ 		en/channels.o en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o\
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+@@ -37,14 +37,14 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += lag/mp.o lag/port_sel.o lib/geneve.o lib/port_tun.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += lag/mp.o lag/port_sel.o lib/geneve.o lib/port_tun.o \
+ 					en_rep.o en/rep/bond.o en/mod_hdr.o \
+ 					en/mapping.o en/rep/meter.o en/rep/sysfs.o
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					lib/fs_chains.o en/tc_tun.o \
+ 					esw/indir_table.o en/tc_tun_encap.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
+@@ -52,7 +52,7 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					en/tc/post_act.o en/tc/int_port.o \
+ 					en/tc/post_meter.o
+ 
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
+ 					en/tc/act/accept.o en/tc/act/mark.o en/tc/act/goto.o \
+ 					en/tc/act/tun.o en/tc/act/csum.o en/tc/act/pedit.o \
+ 					en/tc/act/vlan.o en/tc/act/vlan_mangle.o en/tc/act/mpls.o \
+@@ -60,60 +60,60 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/a
+ 					en/tc/act/ct.o en/tc/act/sample.o en/tc/act/ptype.o \
+ 					en/tc/act/redirect_ingress.o en/tc/act/prio.o en/tc/act/police.o
+ 
+-mlx5_core-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o en/tc/ct_fs_dmfs.o en/tc/ct_fs_smfs.o
+-mlx5_core-$(CONFIG_MLX5_TC_SAMPLE)   += en/tc/sample.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_CT)	     += en/tc_ct.o en/tc/ct_fs_dmfs.o en/tc/ct_fs_smfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_SAMPLE)   += en/tc/sample.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ 				      ecpf.o rdma.o esw/legacy.o esw/vf_meter.o \
+ 				      esw/debugfs.o esw/devlink_port.o esw/vporttbl.o esw/qos.o \
+ 				      esw/pet_offloads.o
+ 
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
+ 				      esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
+ 				      esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o
+ 
+-mlx5_core-$(CONFIG_MLX5_BRIDGE)    += esw/bridge.o en/rep/bridge.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_BRIDGE)    += esw/bridge.o en/rep/bridge.o
+ 
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
+-mlx5_core-$(CONFIG_MLXDEVM) += mlx5_devm.o esw/devm_port.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLXDEVM) += mlx5_devm.o esw/devm_port.o
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
+-mlx5_core-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
+-mlx5_core-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_IPSEC) += accel/ipsec_offload.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_IPSEC) += fpga/ipsec.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA_TLS)   += fpga/tls.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL)      += lib/crypto.o accel/tls.o accel/ipsec.o
+ 
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_MACSEC) += en_accel/macsec.o en_accel/macsec_fs.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_MACSEC) += en_accel/macsec.o en_accel/macsec_fs.o \
+ 				      en_accel/macsec_stats.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o en_accel/ipsec_fs.o esw/ipsec.o \
+ 				     en/ipsec_aso.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o \
+ 				   en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
+ 				   en_accel/ktls_tx.o en_accel/ktls_rx.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o steering/dr_buddy.o \
+ 					steering/dr_ste.o steering/dr_send.o \
+@@ -125,14 +125,14 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # SF device
+ #
+-mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o irq_affinity.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o irq_affinity.o
+ 
+ #
+ # SF manager
+ #
+-mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
+ 
+ #
+ ## SF cfg driver basic
+ #
+-mlx5_core-$(CONFIG_MLX5_SF_CFG) += sf/dev/cfg_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF_CFG) += sf/dev/cfg_driver.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index e1cd67b..d9f90b6 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -18,6 +18,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 03f309e..37a8368 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -88,8 +88,22 @@
+ #include "fpga/ipsec.h"
+ #include "compat.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
+ {
++#ifdef DEV_NETMAP
++	return 0;
++#endif
++
+ 	bool striding_rq_umr, inline_umr;
+ 	u16 max_wqe_sz_cap;
+ 
+@@ -1239,6 +1253,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ {
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(rq->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1321,6 +1341,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1458,6 +1482,10 @@ int mlx5e_open_rq(struct mlx5e_priv *priv, struct mlx5e_params *params,
+ 	if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_SKB_XMIT_MORE))
+ 		__set_bit(MLX5E_RQ_STATE_SKB_XMIT_MORE, &rq->state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
+@@ -1471,6 +1499,9 @@ err_dealloc_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->netdev)) || NA(rq->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ }
+ 
+@@ -1765,6 +1796,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -1978,6 +2014,9 @@ void mlx5e_stop_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -1998,6 +2037,12 @@ void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3569,6 +3614,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_clear_state_opened_flag:
+@@ -3604,6 +3654,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 	mlx5e_apply_traps(priv, false);
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++       netmap_disable_all_rings(netdev);
++#endif
++
+ 	netif_carrier_off(priv->netdev);
+ 	if (!mlx5e_is_uplink_rep(priv) && !mlx5e_is_vport_rep(priv))
+ 		mlx5e_destroy_debugfs(priv);
+@@ -7279,6 +7333,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ {
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++       netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_priv_cleanup(priv);
+ 	free_netdev(netdev);
+ }
+@@ -7391,6 +7449,11 @@ static int mlx5e_probe(struct auxiliary_device *adev,
+ 
+ 	mlx5e_dcbnl_init_app(priv);
+ 	mlx5_uplink_netdev_set(mdev, netdev);
++
++#ifdef DEV_NETMAP
++       mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_unregister_netdev:
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index 7ac3a9d..c077d87 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -94,6 +94,14 @@ const struct mlx5e_rx_handlers mlx5e_rx_handlers_nic = {
+ #endif
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
+ {
+ 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
+@@ -228,7 +236,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -2598,6 +2606,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 		priv = netdev_priv(rq->netdev);
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 20a529b..2c532db 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -43,6 +43,14 @@
+ #include "en/ptp.h"
+ #include 
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+ 				       u32 cqcc, void *data)
+ {
+@@ -996,6 +1004,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->netdev, sq->ch_ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -1118,23 +1131,29 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 
+ 		sqcc += wi->num_wqebbs;
+ 
+-		if (likely(wi->skb)) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			dev_kfree_skb_any(wi->skb);
++		if (!nm_netmap_on(NA(sq->txq->dev))) {
++			/* do not free skbs in netmap mode */
++			if (likely(wi->skb)) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				dev_kfree_skb_any(wi->skb);
+ 
+-			npkts++;
+-			nbytes += wi->num_bytes;
+-			continue;
+-		}
++				npkts++;
++				nbytes += wi->num_bytes;
++				continue;
++			}
+ 
+-		if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
+-			continue;
++			if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
++				continue;
+ 
+-		if (wi->num_fifo_pkts) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
++			if (wi->num_fifo_pkts) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
+ 
+-			npkts += wi->num_fifo_pkts;
++				npkts += wi->num_fifo_pkts;
++				nbytes += wi->num_bytes;
++			}
++		} else {
++			npkts++;
+ 			nbytes += wi->num_bytes;
+ 		}
+ 	}
diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index a22fe6689..98f858dbf 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -711,7 +711,7 @@ void mlx5e_netmap_attach(struct NM_MLX5E_ADAPTER *adapter) {
   na.nm_config = mlx5e_netmap_config;
 
   /* each channel has 1 rx ring and a tx for each tc */
-  na.num_tx_rings = adapter->channels.params.num_channels * adapter->channels.params.num_tc;
+  na.num_tx_rings = adapter->channels.params.num_channels * adapter->channels.params.mqprio.num_tc;
   na.num_rx_rings = adapter->channels.params.num_channels;
   na.rx_buf_maxsize = 1500; /* will be overwritten by nm_config */
   netmap_attach(&na);

From 04ed7ad9211862d0fb866e9d6c58477c8631e8bb Mon Sep 17 00:00:00 2001
From: James Darnley 
Date: Tue, 2 Apr 2024 18:29:14 +0200
Subject: [PATCH 2154/2207] add mlx5 to dkms

---
 LINUX/dkms/dkms.conf | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/LINUX/dkms/dkms.conf b/LINUX/dkms/dkms.conf
index 1154cff91..5f503bf3a 100644
--- a/LINUX/dkms/dkms.conf
+++ b/LINUX/dkms/dkms.conf
@@ -50,3 +50,24 @@ DEST_MODULE_LOCATION[8]=/kernel/drivers/net/ethernet/intel/i40e/
 BUILT_MODULE_NAME[9]=vmxnet3
 BUILT_MODULE_LOCATION[9]=vmxnet3/
 DEST_MODULE_LOCATION[9]=/kernel/drivers/net/vmxnet3/
+
+# mlx5 driver
+BUILT_MODULE_NAME[10]=mlx5_core
+BUILT_MODULE_LOCATION[10]=mlx5/drivers/net/ethernet/mellanox/mlx5/core
+DEST_MODULE_LOCATION[10]=/kernel/drivers/net/ethernet/mellanox/mlx5/
+
+BUILT_MODULE_NAME[11]=mlxfw
+BUILT_MODULE_LOCATION[11]=mlx5/drivers/net/ethernet/mellanox/mlxfw/
+DEST_MODULE_LOCATION[11]=/kernel/drivers/net/ethernet/mellanox/mlx5/
+
+BUILT_MODULE_NAME[12]=mlx_compat
+BUILT_MODULE_LOCATION[12]=mlx5/compat/
+DEST_MODULE_LOCATION[12]=/kernel/drivers/net/ethernet/mellanox/mlx5/
+
+BUILT_MODULE_NAME[13]=auxiliary
+BUILT_MODULE_LOCATION[13]=mlx5/drivers/base/
+DEST_MODULE_LOCATION[13]=/kernel/drivers/net/ethernet/mellanox/mlx5/
+
+BUILT_MODULE_NAME[14]=mlxdevm
+BUILT_MODULE_LOCATION[14]=mlx5/net/mlxdevm/
+DEST_MODULE_LOCATION[14]=/kernel/drivers/net/ethernet/mellanox/mlx5/

From 9b0fbe7be1c6892f01b4a15ffe3ca31578799748 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 30 Jun 2024 07:33:47 +0200
Subject: [PATCH 2155/2207] linux/configure: more robust strscpy test

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index cc1a169a0..32c0712c0 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1965,7 +1965,7 @@ EOF
 
   # check for strscpy()
   add_test 'have STRSCPY' <
+	#include 
 
 	ssize_t dummy(char *d, const char *s, size_t l) {
 		return strscpy(d, s, l);

From 57f9594109a810927c50856c37e251db5f8982c6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 15 Jul 2024 12:31:47 +0200
Subject: [PATCH 2156/2207] avoid empty-body warning

---
 LINUX/bsd_glue.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 88bfb4f15..a689a2f1e 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -397,7 +397,7 @@ static inline void mtx_unlock(safe_spinlock_t *m)
 }
 
 #define mtx_init(a, b, c, d)	spin_lock_init(&((a)->sl))
-#define mtx_destroy(a)
+#define mtx_destroy(a)		do {} while(0)
 
 #define mtx_lock_spin(a)	mtx_lock(a)
 #define mtx_unlock_spin(a)	mtx_unlock(a)

From 4f1f4c61ee6cdd27d3d0d56515c1ea16b4d97757 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 15 Jul 2024 18:11:55 +0200
Subject: [PATCH 2157/2207] linux: add patches for latest Intel drivers

---
 LINUX/final-patches/intel--i40e--2.25.11    | 173 ++++++++++++
 LINUX/final-patches/intel--ice--1.14.13     | 280 ++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.16.10     | 138 ++++++++++
 LINUX/final-patches/intel--ixgbe--5.20.10   | 178 +++++++++++++
 LINUX/final-patches/intel--ixgbevf--4.19.10 | 168 ++++++++++++
 5 files changed, 937 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.25.11
 create mode 100644 LINUX/final-patches/intel--ice--1.14.13
 create mode 100644 LINUX/final-patches/intel--igb--5.16.10
 create mode 100644 LINUX/final-patches/intel--ixgbe--5.20.10
 create mode 100644 LINUX/final-patches/intel--ixgbevf--4.19.10

diff --git a/LINUX/final-patches/intel--i40e--2.25.11 b/LINUX/final-patches/intel--i40e--2.25.11
new file mode 100644
index 000000000..bd95b7f07
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.25.11
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/i40e/Makefile
+index 5f1e70d..ff4910f 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
+index ede3885..cc10297 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -162,6 +162,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_get_lump - find a lump of free generic resource
+  * @pf: board private structure
+@@ -4171,6 +4176,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4299,6 +4308,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4327,6 +4340,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -16049,6 +16067,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16442,6 +16466,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
+index e21ecf1..aed14cd 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -983,6 +987,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2954,7 +2963,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.14.13 b/LINUX/final-patches/intel--ice--1.14.13
new file mode 100644
index 000000000..db7435aa6
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.14.13
@@ -0,0 +1,280 @@
+diff --git a/ice/Makefile b/ice/Makefile
+index c1be1d4..23ba9d4 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -41,9 +41,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -85,14 +85,14 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/ice_devlink_health.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_aux_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_DEBUG_FS) += ice_fwlog.o
+-
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/ice_devlink_health.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_fwlog.o
++
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -104,42 +104,42 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_virtchnl_fsub.o		\
+ 	ice_vf_lib.o
+ 
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ 
+ ifneq (${CONFIG_DPLL},)
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
+ else
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq ($(shell grep HAVE_LMV1_SUPPORT $(src)/kcompat_generated_defs.h),)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
+@@ -151,7 +151,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ # ice does not support building on kernels older than 3.10.0
+ $(call minimum_kver_check,3,10,0)
+@@ -170,7 +170,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -215,7 +215,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 68aeb25..8e3be6d 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -9,6 +9,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -477,6 +482,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -635,6 +644,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -907,6 +921,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	return 0;
+ }
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 4a07275..3e41b15 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -66,6 +66,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6879,6 +6884,7 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7149,6 +7155,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_features:
+@@ -7242,6 +7253,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 5fb23d2..a7305fd 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -237,6 +241,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -424,6 +432,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1670,6 +1688,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.16.10 b/LINUX/final-patches/intel--igb--5.16.10
new file mode 100644
index 000000000..8054228b7
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.16.10
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/igb/Makefile
+index 247e336..33aad62 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/igb/igb_main.c
+index 09a7478..475059f 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3245,6 +3249,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3450,6 +3458,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3862,6 +3874,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7437,6 +7452,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8453,6 +8473,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8772,6 +8797,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--5.20.10 b/LINUX/final-patches/intel--ixgbe--5.20.10
new file mode 100644
index 000000000..d5bf03bff
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--5.20.10
@@ -0,0 +1,178 @@
+diff --git a/ixgbe/Makefile b/ixgbe/Makefile
+index b6eb61f..66cc02c 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -32,29 +32,29 @@ define ixgbe-y
+ 	ixgbe_devlink.o
+ 	ixgbe_fw_update.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+ ixgbe-y += kcompat_pldmfw.o
+ endif
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 09081f5..94c7429 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -778,6 +778,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_reset_pf_report - reset pf and print reset report
+  * @tx_ring: tx ring number
+@@ -943,6 +960,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2417,6 +2445,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -4643,6 +4681,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -5337,6 +5379,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -14760,6 +14808,10 @@ no_info_string:
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_devlink_register:
+@@ -14853,6 +14905,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 	}
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--4.19.10 b/LINUX/final-patches/intel--ixgbevf--4.19.10
new file mode 100644
index 000000000..1a39ccbc4
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--4.19.10
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/ixgbevf/Makefile
+index 2ec8757..fea9d2b 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
+index 75136a0..cf8023a 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -352,6 +352,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -372,6 +389,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1390,6 +1418,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2108,6 +2146,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2342,6 +2384,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5655,8 +5701,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5697,6 +5745,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/ixgbevf/kcompat.h
+index 3167668..2bf3b6d 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -12,6 +12,8 @@
+ 
+ #include "kcompat_gcc.h"
+ 
++#include 
++
+ #include 
+ #include 
+ #include 

From e6b8f568e952aae47f4e0163fa7054d0fb8124d2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 16 Jul 2024 11:28:59 +0200
Subject: [PATCH 2158/2207] linux/scripts: shellcheck

---
 LINUX/configure     | 189 ++++++++++++-------------
 LINUX/netmap.mak.in |   1 -
 LINUX/scripts/np    | 335 +++++++++++++++++++++++---------------------
 3 files changed, 274 insertions(+), 251 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 32c0712c0..7b5c5d890 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1,7 +1,8 @@
 #!/bin/sh
+# shellcheck disable=SC3043,SC2034,SC2012,SC1091
 
 BUILDDIR=$PWD
-SRCDIR=$(cd $(dirname $0); pwd)
+SRCDIR=$(cd "$(dirname "$0")" || exit; pwd)
 MODNAME=netmap
 DEBUG=1
 UTILS=1
@@ -13,8 +14,8 @@ setelem2n()
 {
 	local i=1
 	local n
-	for n in $(eval echo \$$1_avail); do
-		if [ $n = $2 ]; then
+	for n in $(eval echo \$"$1"_avail); do
+		if [ "$n" = "$2" ]; then
 			echo $i
 			return
 		fi
@@ -50,7 +51,7 @@ setop()
 	esac
 
 	if [ -n "$3" ]; then
-		w=$(setelem2n $1 $3)
+		w=$(setelem2n "$1" "$3")
 		[ -n "$w" ] || {
 			echo "unknown $1: $3" | warning
 			return
@@ -58,14 +59,14 @@ setop()
 	fi
 	case "$2" in
 	is-empty)
-		[ $(eval echo \$$1) -eq 0 ]
+		[ "$(eval echo \$"$1")" -eq 0 ]
 		;;
 	disable-all)
 		eval "$1=0"
 		;;
 	enable-all)
 		eval "$1=0"
-		s=$(eval echo \$$1_avail)
+		s=$(eval echo \$"$1"_avail)
 		for n in $s; do
 			eval "$1=\$(( ($1 << 1) | 1))"
 		done
@@ -78,17 +79,17 @@ setop()
 		;;
         enabled)
 		eval "w=\$(($1 & $w))"
-		[ $w -ne 0 ]
+		[ "$w" -ne 0 ]
 		;;
 	print)
-		s=$(eval echo \$$1_avail)
+		s=$(eval echo \$"$1"_avail)
 		e=
 		for n in $s; do
-			w=$(setelem2n $1 $n)
+			w=$(setelem2n "$1" "$n")
 			eval "w=\$(($1 & $w))"
-			[ $w -ne 0 ] && e="$n $e"
+			[ "$w" -ne 0 ] && e="$n $e"
 		done
-		echo $e
+		echo "$e"
 		;;
         esac
 }
@@ -179,7 +180,7 @@ ld=ld
 
 # with : success iff  is available
 with() {
-	type $1 >/dev/null 2>&1
+	type "$1" >/dev/null 2>&1
 }
 
 print_realpath() {
@@ -193,19 +194,20 @@ print_realpath() {
 
 decode_version() {
 	if [ -n "$1" ] && with perl; then
-		echo " [$($SRCDIR/scripts/vers $1 -C)]"
+		echo " [$("$SRCDIR"/scripts/vers "$1" -C)]"
 	fi
 }
 
 # report: print the current state of the configuration variables
 report() {
 	echo "kernel directory            $ksrc"
-	print_realpath $ksrc
+	print_realpath "$ksrc"
 	echo "kernel sources              $src"
 	print_realpath "$src"
-	local v=$lin_ver
+	local v="$lin_ver"
 	[ -n "$v" ] || v="-"
-	local dv="$(decode_version $lin_ver)"
+	local dv
+	dv="$(decode_version "$lin_ver")"
 	echo "linux version               $v $dv"
 	echo "module file                 $MODNAME.ko"
 	echo
@@ -278,7 +280,6 @@ replace_vars()
 		-e "s|@SUBSYS@|$(subsys print)|g" \
 		-e "s|@LIN_VER@|$lin_ver|g" \
 		-e "s|@MOD_LIST@|$mod_list|g" \
-		-e "s|@PATCHES@|$(echo $patches)|g" \
 		-e "s|@S_DRIVERS@|$(drv print)|g" \
 		-e "s|@E_DRIVERS@|$(edrv print)|g" \
 		-e "s|@I_DRIVERS@|$(idrv print)|g" \
@@ -291,7 +292,7 @@ replace_vars()
 		-e "s|@DEBUG@|$DEBUG|g" \
 		-e "s|@UTILS@|$UTILS|g" \
 		-e "s|@REC_DISABLED_WARNINGS@|$REC_DISABLED_WARNINGS|g" \
-		$1
+		"$1"
 }
 
 # print_help
@@ -415,14 +416,14 @@ EOF
 		cat < $TMPDIR/$1.c
+	} > "$TMPDIR/$1".c
 	{
 		cat <> config.log
 	# add the module to the running list
 	TESTOBJS="$1.o $TESTOBJS"
@@ -439,7 +440,7 @@ NEXTTEST=1
 add_test() {
 	local t="test__$NEXTTEST"
 	add_named_test $t "$@"
-	NEXTTEST=$(($NEXTTEST+1))
+	NEXTTEST=$((NEXTTEST+1))
 }
 
 PERTESTFLAGS=
@@ -448,12 +449,12 @@ PERTESTFLAGS=
 # 	for the next test
 add_test_flags() {
 	PERTESTFLAGS="$PERTESTFLAGS
-CFLAGS_test__$NEXTTEST.o := $@"
+CFLAGS_test__$NEXTTEST.o := $*"
 }
 
 reset_tests() {
-	rm -rf $TMPDIR
-	mkdir $TMPDIR
+	rm -rf "$TMPDIR"
+	mkdir "$TMPDIR"
 
 	TESTOBJS=
 	TESTPOSTPROC=
@@ -474,7 +475,7 @@ run_preliminary_tests() {
 ifneq (\$(KERNELRELEASE),)
 obj-m := $TESTOBJS
 EOF
-		if [ -e $TMPDIR/extra.mk ]; then cat $TMPDIR/extra.mk; fi
+		if [ -e "$TMPDIR"/extra.mk ]; then cat "$TMPDIR"/extra.mk; fi
 		cat < $TMPDIR/Makefile
+	} > "$TMPDIR"/Makefile
 	NPROC=$(grep -c processor /proc/cpuinfo)
 	MAKE_OPT=-O
 	{
@@ -492,21 +493,21 @@ EOF
 ##############################################################################
 ## Makefile:
 EOF
-		cat $TMPDIR/Makefile
+		cat "$TMPDIR"/Makefile
 		cat <> config.log
 	(
-		cd $TMPDIR
-		LANG=C make $MAKE_OPT -k -j $NPROC
+		cd "$TMPDIR" || exit
+		LANG=C make $MAKE_OPT -k -j "$NPROC"
 	) >> config.log 2>&1
 	if grep -q ": invalid option -- 'O'" config.log; then
 		MAKE_OPT=
 		# let us try again without -O
 		(
-			cd $TMPDIR
-			make -k -j $NPROC
+			cd "$TMPDIR" || exit
+			make -k -j "$NPROC"
 		) >> config.log 2>&1
 	fi
 	eval "$TESTPOSTPROC"
@@ -520,8 +521,8 @@ EOF
 # run_tests: run all accumulated tests and exec the pertinent
 #   success/failure actions for each one.
 run_tests() {
-	ln -s $BUILDDIR/patches $TMPDIR
-	cat > $TMPDIR/Makefile < "$TMPDIR"/Makefile <> $TMPDIR/Makefile <> "$TMPDIR"/Makefile <> $TMPDIR/Makefile
+	echo endif >> "$TMPDIR"/Makefile
 	{
 		cat <> config.log
 	(
-		cd $TMPDIR
-		make $MAKE_OPT -k -j $NPROC
+		cd "$TMPDIR" || exit
+		make $MAKE_OPT -k -j "$NPROC"
 	) >> config.log 2>&1
 	eval "$TESTPOSTPROC"
 	cat >> config.log <> config.log
 cp pre-commit .git/hooks
 
 appl_arch=$($cc -dumpmachine | cut -d '-' -f 1)
-if [ $appl_arch != "x86_64" ]; then
+if [ "$appl_arch" != x86_64 ]; then
     # dedup uses inline x86_64 assembly
     app disable dedup
 fi
@@ -797,7 +798,7 @@ Otherwise, check that the 'build' symlink in
 is not broken.
 EOF
 fi
-ksrc=$(cd $ksrc; pwd)
+ksrc=$(cd "$ksrc" || exit; pwd)
 
 # check that ksrc has been prepared for external modules compilation
 # It should contain a version.h file (in one of two possible places,
@@ -811,7 +812,7 @@ kernel not configured.
 The kernel directory must be ready for external module compilation.
 You may need to issue the following or equivalent commands:
 
-    cd $ksrc
+    cd "$ksrc"
     make oldconfig
     make modules_prepare
 EOF
@@ -845,8 +846,8 @@ disable_warning() {
 i=1
 for w in $DISABLED_WARNINGS; do
 	add_named_test "__warn__$i" "disable_warning $w" < /dev/null
-	echo "CFLAGS___warn__$i.o = -Wno-error=$w" >> $TMPDIR/extra.mk
-	i=$(($i+1))
+	echo "CFLAGS___warn__$i.o = -Wno-error=$w" >> "$TMPDIR"/extra.mk
+	i=$((i+1))
 done
 
   message " NOTE  " <> extdrv-versions.mak
 done
 
-replace_vars $SRCDIR/default-config.mak.in_ > default-config.mak
-replace_vars $SRCDIR/intel-fix.sh_ > intel-fix.sh
+replace_vars "$SRCDIR"/default-config.mak.in_ > default-config.mak
+replace_vars "$SRCDIR"/intel-fix.sh_ > intel-fix.sh
 chmod +x intel-fix.sh
 
 ###############################################################
@@ -882,13 +883,13 @@ chmod +x intel-fix.sh
 
 mod_list=
 if ! drv is-empty; then
-	[ -d patches ] || { rm -f patches; ln -s $SRCDIR/final-patches patches; }
+	[ -d patches ] || { rm -f patches; ln -s "$SRCDIR"/final-patches patches; }
 fi
 
-ln -s $SRCDIR/read-vars.mak 2>/dev/null || true
+ln -s "$SRCDIR"/read-vars.mak 2>/dev/null . || true
 rm -f drivers.mak
 # read in all the kernel .config, we use it below
-. $ksrc/.config
+. "$ksrc"/.config
 # check for full kernel sources just once
 src_checked=
 src_found=
@@ -901,19 +902,19 @@ for d in $(drv print); do
 	drv_patch=
 	drv_build=
 	drv_distclean=
-	drv_conf="CONFIG_$(basename $d .c | tr a-z- A-Z_)"
+	drv_conf="CONFIG_$(basename "$d" .c | tr a-z- A-Z_)"
 	# possibly override from config.mak
-	eval $(make -snrf read-vars.mak $d@vars E_DRIVERS="$e_drivers")
+	eval "$(make -snrf read-vars.mak "$d"@vars E_DRIVERS="$e_drivers")"
 
 	# check that the original driver had been compiled as a module, otherwise
 	# skip this driver
 	# (we do this mainly to be sure that any module dependency has already
 	#  been taken care of)
 	if [ -z "$drv_force" ]; then
-		m="$(eval echo \$$drv_conf)"
+		m="$(eval echo \$"$drv_conf")"
 		[ -n "$m" ] || {
 			echo "$drv_conf not set in $ksrc/.config, skipping $d" | warning
-			drv disable $d
+			drv disable "$d"
 			continue
 		}
 	fi
@@ -939,12 +940,12 @@ $d using the following command:
   $drv_fetch
 
 If this fails, please download the above file and put it
-in $SRCDIR/ext-drivers/, then run configure again.
+in "$SRCDIR/ext-drivers/", then run configure again.
 EOF
-		eval $drv_fetch 2>&1 || { drverror <&1 || { drverror <> drivers.mak <' $TMPDIR/e1000e/netdev.c \
+  add_test "grep -q '\' '$TMPDIR'/e1000e/netdev.c \
   	&& have E1000E_EXT_RXDESC" > config.log
+  symf="$ksrc"/Module.symvers
+  if [ -e "$symf" ]; then
+	  if cut -f2 "$symf" | grep -q split_page; then
+		  echo "found in '$symf'" >> config.log
 		  have SPLIT_PAGE
 	  else
-		  echo "not found in $symf" >> config.log
+		  echo "not found in '$symf'" >> config.log
 	  fi
   else
-	  echo "$symf file not found" >> config.log
+	  echo "'$symf' file not found" >> config.log
   fi
   cat >> config.log <> $configh < $(basename $f .in)
+for f in "$SRCDIR"/*.in; do
+	replace_vars "$f" > "$(basename "$f" .in)"
 done
 
 # if we are in SRCDIR this will fail, since
 # Makefile already exists
-ln -s $SRCDIR/../GNUmakefile || true
-ln -s $SRCDIR/drv-subdir.mak || true
+ln -s "$SRCDIR"/../GNUmakefile . || true
+ln -s "$SRCDIR"/drv-subdir.mak . || true
 
 
 
@@ -2560,20 +2561,20 @@ report
 
 # create the build directory for libnetmap
 mkdir -p build-libnetmap
-ln -s $SRCDIR/../libnetmap/GNUmakefile build-libnetmap 2>/dev/null || true
+ln -s "$SRCDIR"/../libnetmap/GNUmakefile build-libnetmap 2>/dev/null || true
 
 # create the build directory for the examples
 mkdir -p build-apps
 for a in $(app print); do
-	mkdir -p build-apps/$a
-	ln -s $SRCDIR/../apps/$a/GNUmakefile build-apps/$a/GNUmakefile 2> /dev/null || true
+	mkdir -p build-apps/"$a"
+	ln -s "$SRCDIR"/../apps/"$a"/GNUmakefile build-apps/"$a"/GNUmakefile 2> /dev/null || true
 done
 
 # create the build directory for the utils
 if [ -n "$UTILS" ]; then
 	mkdir -p build-utils
-	ln -s $SRCDIR/../utils/GNUmakefile build-utils/GNUmakefile 2>/dev/null || true
-	ln -s $SRCDIR/../utils/tests 2>/dev/null || true
+	ln -s "$SRCDIR"/../utils/GNUmakefile build-utils/GNUmakefile 2>/dev/null || true
+	ln -s "$SRCDIR"/../utils/tests 2>/dev/null . || true
 fi
 
 # config.status can be used to rerun configure with the
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 8c579b1f8..99f0e4472 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -31,7 +31,6 @@ KOPTS = @KOPTS@
 MODPATH = @MODPATH@
 LIN_VER = @LIN_VER@
 MOD_LIST := @MOD_LIST@
-PATCHES = @PATCHES@
 S_DRIVERS = @S_DRIVERS@
 E_DRIVERS = @E_DRIVERS@
 DRVSUFFIX = @DRVSUFFIX@
diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index a5f16dd69..db16f7f45 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -1,4 +1,5 @@
 #!/bin/bash
+# shellcheck disable=SC1091,SC2064,SC2012
 ## Manage linux driver patches for netmap.
 ##
 ## Initial setup: 
@@ -53,7 +54,7 @@
 PROGNAME=$0
 
 [ -n "$1" ] || {
-	scripts/help $PROGNAME;
+	scripts/help "$PROGNAME";
 	exit 1
 }
 
@@ -76,21 +77,21 @@ function error {
 }
 
 function get-params {
-	local params=$1; shift
-	err_msg="$PROGNAME $COMMAND $(echo $params| perl -pe 's/\S+/<$&>/g')"
-	local param
+	local params param
+	params=$1; shift
+	err_msg="$PROGNAME $COMMAND $(echo "$params"| perl -pe 's/\S+/<$&>/g')"
 	for param in $params; do
-		[[ -z "$@" ]] && error "$err_msg"
-		pname=$(echo -n $param | perl -pe 's/\W/_/g')
-		eval $pname="$1"
+		[[ -z "$*" ]] && error "$err_msg"
+		pname=$(echo -n "$param" | perl -pe 's/\W/_/g')
+		eval "$pname=$1"
 		shift
 	done
-	[[ -n "$@" ]] && error "$err_msg"
+	[[ -n "$*" ]] && error "$err_msg"
 }
 
 function need {
 	eval "local v=\${$1}"
-	[ -n "$v" ] && [ -d "$v${2:+/$2}" ] || error "Variable $1 not set or not valid"
+	{ [ -n "$v" ] && [ -d "$v${2:+/$2}" ]; } || error "Variable $1 not set or not valid"
 }
 
 ## The following environment variables must be set:
@@ -127,16 +128,18 @@ need LINUX_CONFIGS
 ##	file system search.
 function driver-path()
 {
+	declare driver version
 	get-params "driver version" "$@"
 	
-	cat cache/$version/vanilla-$driver/path 2>/dev/null && return
-	local kern=$(get-kernel $version)
+	cat cache/"$version"/vanilla-"$driver"/path 2>/dev/null && return
+	local kern
+	kern="$(get-kernel "$version")"
 	[ -z "$kern" ] && error "no such kernel version: $version"
-	mkdir -p cache/$version/vanilla-$driver
+	mkdir -p cache/"$version"/vanilla-"$driver"
 	(
-		cd $kern
-		find drivers/net -name $driver
-	) | tee cache/$version/vanilla-$driver/path
+		cd "$kern" || exit
+		find drivers/net -name "$driver"
+	) | tee cache/"$version"/vanilla-"$driver"/path
 }
 
 
@@ -153,25 +156,27 @@ function get-patch()
 	local use_cache
 	[ "$1" = -c ] && { use_cache=1; shift; }
 
+	declare driver version
 	get-params "driver version" "$@"
 
+	local v1 v2 patchname out drvpath drvdir
 	# convert kernel version to fixed notation
-	local v1=$(scripts/vers $version -c)
+	v1=$(scripts/vers "$version" -c)
 	# compute next kernel version (in fixed notation)
-	local v2=$(scripts/vers $version -i -c)
-	local patchname=vanilla--$driver--$v1--$v2
-	local out=tmp-patches/$patchname
-	[ -n "$use_cache" ] && [ -s $out ] && { echo $out; return; }
-	local drvpath=$(driver-path $driver $version)
+	v2=$(scripts/vers "$version" -i -c)
+	patchname=vanilla--$driver--$v1--$v2
+	out=tmp-patches/$patchname
+	[ -n "$use_cache" ] && [ -s "$out" ] && { echo "$out"; return; }
+	drvpath=$(driver-path "$driver" "$version")
 	[ -n "$drvpath" ] || return
-	local drvdir=$(dirname $drvpath)
+	drvdir=$(dirname "$drvpath")
 	(
-		cd $GITDIR
-		git diff --relative=$drvdir v$version..netmap-$version -- $drvpath
-	) > $out
+		cd "$GITDIR" || exit
+		git diff --relative="$drvdir" "v$version..netmap-$version" -- "$drvpath"
+	) > "$out"
 	# an empty patch means no netmap support for this driver
-	[ -s $out ] || { rm $out; return 1; }
-	echo $out
+	[ -s "$out" ] || { rm "$out"; return 1; }
+	echo "$out"
 	return 0;
 }
 
@@ -183,22 +188,23 @@ function get-patch()
 ##	and their names are output to stdout.
 function get-range()
 {
+	declare driver version1 version2
 	get-params "driver version1 version2"	 "$@"
 
-	local v=$version1
-	local nv
+	local v nv V1 V2 p
+	v=$version1
 	# while version is less than $version2
-	while scripts/vers -b $v $version2 -L; do
+	while scripts/vers -b "$v" "$version2" -L; do
 		# compute next version
-		nv=$(scripts/vers $v -i)
+		nv=$(scripts/vers "$v" -i)
 		if [ -z "$EXTDRV" ]; then
-			get-patch $driver $v
+			get-patch "$driver" "$v"
 		else
-			local V1=$(scripts/vers $v -c)
-			local V2=$(scripts/vers $nv -c)
-			local p=tmp-patches/external--$driver--$V1--$V2
-			touch $p
-			echo $p
+			V1=$(scripts/vers "$v" -c)
+			V2=$(scripts/vers "$nv" -c)
+			p=tmp-patches/external--$driver--$V1--$V2
+			touch "$p"
+			echo "$p"
 		fi
 		v=$nv
 	done
@@ -212,12 +218,14 @@ function get-range()
 ##	directory.
 function get-src()
 {
+	declare driver version dest
 	get-params "driver version dest" "$@"
 
-	local kern=$(get-kernel $version)
+	local kern src
+	kern=$(get-kernel "$version")
 	[ -z "$kern" ] && error "no such kernel version: $version"
-	local src=$(driver-path $driver $version)
-	cp -r $kern/$src $dest
+	src=$(driver-path "$driver" "$version")
+	cp -r "$kern/$src" "$dest"
 }
 
 
@@ -228,13 +236,15 @@ function get-src()
 ##	It returns 0 on success and 1 on failure.
 function extend()
 {
+	declare patch version
 	get-params "patch version" "$@"
 
-	local _patch=$(realpath $patch)
+	local _patch driver tmpdir1 tmpdir2 patch2
+	_patch=$(realpath "$patch")
 	# extract the driver name from the patch name
-	local driver=$(scripts/vers $_patch -s -p -p)
-	local tmpdir1=$(mktemp -d)
-	local tmpdir2=$(mktemp -d)
+	driver=$(scripts/vers "$_patch" -s -p -p)
+	tmpdir1=$(mktemp -d)
+	tmpdir2=$(mktemp -d)
 	trap "rm -rf $tmpdir1 $tmpdir2" 0
 	# we get the driver sources for the given  and
 	# we apply two patches separately:
@@ -243,19 +253,19 @@ function extend()
 	# We declare  to be extendable if
 	# - it is still applicable AND
 	# - we obtain the same files from i) and ii) (ignoring whitespace)
-	get-src $driver $version $tmpdir1
-	get-src $driver $version $tmpdir2
+	get-src "$driver" "$version" "$tmpdir1"
+	get-src "$driver" "$version" "$tmpdir2"
 	(
-		cd $tmpdir1
-		patch --no-backup-if-mismatch -p1 < $_patch >/dev/null 2>&1
+		cd "$tmpdir1" || exit 1
+		patch --no-backup-if-mismatch -p1 < "$_patch" >/dev/null 2>&1
 	) || return 1
-	local patch2=$(get-patch -c $driver $version)
-	patch2=$(realpath $patch2)
+	patch2=$(get-patch -c "$driver" "$version")
+	patch2=$(realpath "$patch2")
 	(
-		cd $tmpdir2
-		patch -p1 < $patch2 >/dev/null 2>&1
+		cd "$tmpdir2" || exit 1
+		patch -p1 < "$patch2" >/dev/null 2>&1
 	) # this will certainly apply
-	diff -qbBr $tmpdir1 $tmpdir2 >/dev/null || return 1
+	diff -qbBr "$tmpdir1" "$tmpdir2" >/dev/null || return 1
 	return 0
 } 
 
@@ -268,15 +278,17 @@ function extend()
 ##	they are deleted first.
 function minimize()
 {
+	declare driver
 	get-params "driver" "$@"
 
 	mkdir -p final-patches
-	local drv=$(basename $driver)
-	local patches=$(ls tmp-patches/vanilla--$drv--* 2>/dev/null)
+	local drv patches pivot ple pre nle nre
+	drv=$(basename "$driver")
+	patches=$(ls tmp-patches/vanilla--"$drv"--* 2>/dev/null)
 	[ -n "$patches" ] || return 1
 	# put the patch names in $1, $2, ...
 	set $patches
-	rm -f final-patches/vanilla--$drv--*
+	rm -f final-patches/vanilla--"$drv"--*
 	# the original patches (in tmp-patches) are ordered by version number.
 	# We consider one patch in turn (the 'pivot') and try
 	# to extend its range to cover the range of the next
@@ -284,19 +296,19 @@ function minimize()
 	# pivot, otherwise the current pivot is output and the
 	# next patch becomes the new pivot. The process
 	# is repeated until there are no more patches to consider.
-	local pivot=$1
+	pivot=$1
 	[ -n "$pivot" ] && [ -e "$pivot" ] || return 1
 	# extract the left end and right end of the pivot's range
-	local ple=$(scripts/vers $pivot -s -p -C)
-	local pre=$(scripts/vers $pivot -s -C)
+	ple=$(scripts/vers "$pivot" -s -p -C)
+	pre=$(scripts/vers "$pivot" -s -C)
 	while [ -n "$pivot" ]; do
 		shift
 		if [ -n "$1" ]; then 
 			# extract the left end and right end of the next patch
-			local nle=$(scripts/vers $1 -s -p -C)
-			local nre=$(scripts/vers $1 -s -C)
+			nle=$(scripts/vers "$1" -s -p -C)
+			nre=$(scripts/vers "$1" -s -C)
 			# we admit no gaps in the range
-			if [ $pre = $nle ] && extend $pivot $nle; then
+			if [ "$pre" = "$nle" ] && extend "$pivot" "$nle"; then
 				pre=$nre
 				continue
 			fi
@@ -304,8 +316,8 @@ function minimize()
 		# either out of patches or failed merge.
 		# Compute the file name of the current pivot and store
 		# the patch in its final location
-		out=$(scripts/vers vanilla $drv $ple -c $pre -c -S4)
-		cp $pivot final-patches/$out
+		out=$(scripts/vers vanilla "$drv" "$ple" -c "$pre" -c -S4)
+		cp "$pivot" final-patches/"$out"
 		# the new pivot becomes the next patch (if any)
 		pivot=$1
 		pre=$nre
@@ -321,32 +333,36 @@ function minimize()
 ##	Do nothing otherwise.
 function infty()
 {
+	declare driver version
 	get-params "driver version" "$@"
 
-	local drv=$(basename $driver)
+	local drv v last
+	drv=$(basename "$driver")
 	# convert kernel version to fixed notation
-	local v=$(scripts/vers $version -c)
-	local last=$(ls final-patches/vanilla--$drv--*--$v 2>/dev/null|tail -n1)
+	v=$(scripts/vers "$version" -c)
+	last=$(ls final-patches/vanilla--"$drv"--*--"$v" 2>/dev/null|tail -n1)
 	[ -n "$last" ] || return 1
-	mv -n $last $(scripts/vers $last -s -p 99999 -S4) 2>/dev/null
+	mv -n "$last" "$(scripts/vers "$last" -s -p 99999 -S4)" 2>/dev/null
 }
 
 function get-kernel()
 {
+	declare version
 	get-params "version" "$@"
 
-	local dst="$(realpath $LINUX_SOURCES)/linux-$version"
+	local dst v
+	dst=$(realpath "$LINUX_SOURCES")/linux-"$version"
 
-	[ -d $dst ] && { echo $dst; return; }
+	[ -d "$dst" ] && { echo "$dst"; return; }
 
-	local v=$version
+	v=$version
 
 	(
-		cd $GITDIR
+		cd "$GITDIR" || exit
 		if git show-ref --tags --quiet --verify -- "refs/tags/v$v"; then
-			mkdir -p $dst
-			git archive v$v | tar xf - -C $dst
-			echo $dst
+			mkdir -p "$dst"
+			git archive v"$v" | tar xf - -C "$dst"
+			echo "$dst"
 		fi
 	)
 }
@@ -368,23 +384,25 @@ function get-kernel()
 ##	output.
 function build-prep()
 {
+	declare version
 	get-params "version" "$@"
 
-	local dst=$(get-kernel $version)
+	local dst
+	dst=$(get-kernel "$version")
 	local last
 
-	[ -f $dst/.build-prep ] && { echo $dst; return; }
+	[ -f "$dst"/.build-prep ] && { echo "$dst"; return; }
 
 	(
-		cd $dst
+		cd "$dst" || exit 1
 		# fix for incompatible GNU make change
 		sed -i -e '/^squote/a\
 pound	:= \\#
 			/\/{s/\\#/$(pound)/}' tools/build/Build.include || true
 		last=compiler-gcc.h
 		for i in $(seq 13); do
-			[ -e include/linux/compiler-gcc$i.h ] ||
-				ln -s $last include/linux/compiler-gcc$i.h
+			[ -e include/linux/compiler-gcc"$i".h ] ||
+				ln -s "$last" include/linux/compiler-gcc"$i".h
 			last=compiler-gcc$i.h
 		done
 		# force disabling PIE and fcf-protection
@@ -401,8 +419,8 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		# make sure per_cpu_load_addr is static
 		sed -i -e 's/^[[:blank:]]*Elf_Addr[[:blank:]][[:blank:]]*per_cpu_load_addr;/static &/' \
 			arch/x86/tools/relocs.c
-		if [ -f $LINUX_CONFIGS/config-$version ]; then
-			cp $LINUX_CONFIGS/config-$version .config
+		if [ -f "$LINUX_CONFIGS/config-$version" ]; then
+			cp "$LINUX_CONFIGS/config-$version" .config
 			yes '' | make oldconfig
 		else
 			make allmodconfig
@@ -417,8 +435,8 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 		sed -i 's/-Werror/-Wno-error/g' $(grep -Rl -- -Werror tools)
 		make scripts modules_prepare
 		touch .build-prep
-	) >$dst.log 2>&1 || error "build-prep failed for linux $version. Please check $dst.log"
-	echo $dst
+	) >"$dst".log 2>&1 || error "build-prep failed for linux $version. Please check $dst.log"
+	echo "$dst"
 }
 
 ##
@@ -428,68 +446,71 @@ KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)' Makefile
 ##	Errors are logged to log/.
 function check-patch()
 {
+	declare patch
 	get-params "patch" "$@"
 
-	local _patch=$(basename $patch)
+	local _patch v1 v2 end driver dtype p log nmcommit warn
+	_patch=$(basename "$patch")
 	# extract the left version
-	local v1=$(scripts/vers $_patch -s -p -C)
+	v1=$(scripts/vers "$_patch" -s -p -C)
 	# extract the right version
-	local v2=$(scripts/vers $_patch -s -C)
+	v2=$(scripts/vers "$_patch" -s -C)
 	# extract the unconverted right version (might be 99999)
-	local end=$(scripts/vers $_patch -s)
+	end=$(scripts/vers "$_patch" -s)
 	# extract the driver name
-	local driver=$(scripts/vers $_patch -s -p -p)
+	driver=$(scripts/vers "$_patch" -s -p -p)
 	# possibly extract the selected driver version
 	driver_version=$(echo "$driver" | sed -n 's/^.*://p')
 	driver=${driver%%:*}
 	# extract the driver type (vanilla or external)
-	local dtype=$(scripts/vers $_patch -s -p -p -p)
-	local p=$(realpath $patch)
+	dtype=$(scripts/vers "$_patch" -s -p -p -p)
+	p=$(realpath "$patch")
 	mkdir -p log
-	local log="$(realpath log)/$(basename $patch)"
-	local nmcommit=$(cd ..; git show-ref -s heads/$NETMAP_BRANCH)
-	local warn=false
+	log=$(realpath log)/$(basename "$patch")
+	nmcommit=$(cd .. || exit 1; git show-ref -s heads/"$NETMAP_BRANCH")
+	warn=false
 
-	rm -f $log
+	rm -f "$log"
 
-	echo -n $patch...
+	echo -n "$patch..."
 
-	while scripts/vers -b $v1 $v2 -L; do
+	local cache cpatch cnmcommit cstatus cwarn clog ksrc tmpdir
+	while scripts/vers -b "$v1" "$v2" -L; do
 		# cache lookup
-		local cache=$PWD/cache/$v1/$dtype-$driver${driver_version:+:$driver_version}
-		mkdir -p $cache
-		local cpatch=$cache/patch
-		local cnmcommit=$cache/nmcommit
-		local cstatus=$cache/status
-		local cwarn=$cache/warn
-		local clog=$cache/log
-		if [ -f $cpatch ]				&&
-		   cmp -s $cpatch $patch			&&
-		   [ "$nmcommit" = "$(cat $cnmcommit)" ]; then
-			cp $clog $log
-			ok=$(cat $cstatus)
-			if [ -f "$cwarn" ]; then warn=$(cat $cwarn); fi
+		cache=$PWD/cache/$v1/$dtype-$driver${driver_version:+:$driver_version}
+		mkdir -p "$cache"
+		cpatch=$cache/patch
+		cnmcommit=$cache/nmcommit
+		cstatus=$cache/status
+		cwarn=$cache/warn
+		clog=$cache/log
+		if [ -f "$cpatch" ]				&&
+		   cmp -s "$cpatch" "$patch"			&&
+		   [ "$nmcommit" = "$(cat "$cnmcommit")" ]; then
+			cp "$clog" "$log"
+			ok=$(cat "$cstatus")
+			if [ -f "$cwarn" ]; then warn=$(cat "$cwarn"); fi
 		else
 			# update cache
-			cp $patch $cpatch
-			echo $nmcommit > $cnmcommit
+			cp "$patch" "$cpatch"
+			echo "$nmcommit" > "$cnmcommit"
 
-			local ksrc=$(build-prep $v1)
+			ksrc=$(build-prep "$v1")
 			if [ -z "$ksrc" ]; then
-				rm -rf $cache
+				rm -rf "$cache"
 				if [ "$end" = 99999 ]; then
 					ok=true
 					break
 				fi
 				error "no such kernel version: $v1"
 			fi
-			local tmpdir=$(mktemp -d)
+			tmpdir=$(mktemp -d)
 			if [ "$NP_DEBUG" -lt 1 ]; then
-				trap "rm -rf $tmpdir" 0
+				trap "rm -rf '$tmpdir'" 0
 			fi
-			echo "====== $tmpdir =====" >>$log
-			(cd ..; git archive $NETMAP_BRANCH | tar xf - -C $tmpdir )
-			pushd $tmpdir/LINUX >/dev/null
+			echo "====== $tmpdir =====" >>"$log"
+			(cd ..; git archive "$NETMAP_BRANCH" | tar xf - -C "$tmpdir" )
+			pushd "$tmpdir"/LINUX >/dev/null || exit
 			rm -f patches
 			ok=false
 			config_opts=
@@ -497,10 +518,10 @@ function check-patch()
 				config_opts=--no-ext-drivers
 				mkdir single-patch
 				ln -s single-patch patches
-				cp $p single-patch
+				cp "$p" single-patch
 			else
 				rm -rf ext-drivers
-				ln -s $EXT_DRIVERS ext-drivers
+				ln -s "$EXT_DRIVERS" ext-drivers
 				ln -s final-patches patches
 				if [ -n "$driver_version" ]; then
 					config_opts="$config_opts --select-version=$driver:$driver_version"
@@ -509,8 +530,8 @@ function check-patch()
 			if [ "$driver" != "veth.c" ]; then
 				config_opts="$config_opts --disable-pipe"
 			fi
-			./configure --kernel-dir=$ksrc --driver-suffix=$DRIVER_SUFFIX \
-				--drivers=$driver \
+			./configure --kernel-dir="$ksrc" --driver-suffix="$DRIVER_SUFFIX" \
+				--drivers="$driver" \
 				--disable-generic \
 				--disable-vale \
 				--disable-monitor \
@@ -519,21 +540,21 @@ function check-patch()
 				--no-apps \
 				--kernel-opts=CONFIG_STACK_VALIDATION= \
 				$config_opts \
-				--cache=$cache >>$log
-			(make get-$driver && KBUILD_MODPOST_WARN=1 make -j $PARALLEL_MAKE) >>$log 2>&1 && ok=true
-			grep -q warning: $log && { warn=true; echo $warn > $cwarn; }
-			cat config.log >>$log
-			cat netmap_linux_config.h >>$log 2>/dev/null
-			popd >/dev/null
-			cp $log $clog
+				--cache="$cache" >>"$log"
+			(make get-"$driver" && KBUILD_MODPOST_WARN=1 make -j "$PARALLEL_MAKE") >>"$log" 2>&1 && ok=true
+			grep -q warning: "$log" && { warn=true; echo "$warn" > "$cwarn"; }
+			cat config.log >>"$log"
+			cat netmap_linux_config.h >>"$log" 2>/dev/null
+			popd >/dev/null || exit
+			cp "$log" "$clog"
 		fi
-		[ "$ok" = true ] || { echo FAILED; echo false > $cstatus; return 1; }
-		echo true > $cstatus
+		[ "$ok" = true ] || { echo FAILED; echo false > "$cstatus"; return 1; }
+		echo true > "$cstatus"
 		if [ "$NP_DEBUG" -lt 2 ]; then
-			rm -rf $tmpdir
+			rm -rf "$tmpdir"
 		fi
 		# compute next version
-		v1=$(scripts/vers $v1 -i)
+		v1=$(scripts/vers "$v1" -i)
 	done
 	if [ "$warn" = true ]; then
 		echo WARNING
@@ -549,18 +570,19 @@ function check-patch()
 ##	are moved to failed-patches.
 function build-check()
 {
+	declare driver
 	get-params "driver" "$@"
 
 	mkdir -p failed-patches
-	local dtype=vanilla
+	local dtype drv patches p
+	dtype=vanilla
 	if [ "$EXTDRV" = 1 ]; then
 		dtype=external
 	fi
-	local drv=$(basename $driver)
-	local patches=$(ls tmp-patches/$dtype--$drv--* 2>/dev/null)
-	local p
+	drv=$(basename "$driver")
+	patches=$(ls tmp-patches/"$dtype"--"$drv"--* 2>/dev/null)
 	for p in $patches; do
-		check-patch $p || mv $p failed-patches
+		check-patch "$p "|| mv "$p" failed-patches
 	done
 }
 
@@ -574,30 +596,31 @@ NEXTVERS=
 ##	available netmap-* branches in GITDIR
 function auto()
 {
+	decleare driver
 	get-params "driver" "$@"
 
+	local branches b v
 	if [ -z "$MAXVERS" ]; then 
 		# get the latest netmap-* branch
-		local branches=$(
-			cd $GITDIR;
+		branches=$(
+			cd "$GITDIR" || exit 1
 			git for-each-ref refs/heads/netmap-[0-9]* --format='%(refname:short)'
 		)
 		MAXVERS=$MINVERS
-		local b
 		for b in $branches; do
-			local v=${b#netmap-}
-			if scripts/vers -b $MAXVERS $v -L; then
+			v=${b#netmap-}
+			if scripts/vers -b "$MAXVERS" "$v" -L; then
 				MAXVERS=$v
 			fi
 		done
 		echo "Latest netmap linux branch: $MAXVERS"
-		NEXTVERS=$(scripts/vers $MAXVERS -i)
+		NEXTVERS=$(scripts/vers "$MAXVERS" -i)
 	fi
-	get-range $driver $MINVERS $NEXTVERS
-	build-check $driver
+	get-range "$driver" "$MINVERS" "$NEXTVERS"
+	build-check "$driver"
 	if [ -z "$EXTDRV" ]; then
-		minimize $driver
-		infty $driver $NEXTVERS
+		minimize "$driver"
+		infty "$driver" "$NEXTVERS"
 	fi
 }
 
@@ -606,12 +629,12 @@ function auto()
 ##	exec   [args...] for all known drivers.
 function forall()
 {
-	local cmd=$1
+	local cmd driver
+	cmd=$1
 	shift
 
-	local driver
-	for driver in $(./configure --show${EXTDRV:+-ext}-drivers); do
-		$cmd $(basename $driver) "$@"
+	for driver in $(./configure --show"${EXTDRV:+-ext}"-drivers); do
+		"$cmd" "$(basename "$driver")" "$@"
 	done
 }
 
@@ -638,12 +661,12 @@ case $COMMAND in
 ##  -all [args...]
 ##	same as: forall  [args...]
 *-all)
-	forall ${COMMAND%-all} "$@"
+	forall "${COMMAND%-all}" "$@"
 	;;
 -[hH]|--help|-help|help)
-	scripts/help $PROGNAME
+	scripts/help "$PROGNAME"
 	;;
 *)
-	$COMMAND "$@"
+	"$COMMAND" "$@"
 	;;
 esac

From 570c1c6d89fd533416c450525a5aa754cbb9ebfe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 16 Sep 2024 13:13:29 +0200
Subject: [PATCH 2159/2207] linux/configure: fix regression

---
 LINUX/configure  | 8 ++++----
 LINUX/scripts/np | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 7b5c5d890..c38b75b94 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -544,10 +544,10 @@ tests:
 test__%:
 	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts \$@.o
 
--include "$BUILDDIR"/extdrv-versions.mak
--include "$BUILDDIR"/default-config.mak
--include "$BUILDDIR"/config.mak
--include "$BUILDDIR"/drivers.mak
+-include $BUILDDIR/extdrv-versions.mak
+-include $BUILDDIR/default-config.mak
+-include $BUILDDIR/config.mak
+-include $BUILDDIR/drivers.mak
 EOF
 	for d in $(drv print); do
 		cat >> "$TMPDIR"/Makefile <
Date: Mon, 16 Sep 2024 16:29:21 +0200
Subject: [PATCH 2160/2207] linux: patches for v6.11

---
 ...0300--99999 => vanilla--ice--60300--60b00} |   0
 .../final-patches/vanilla--ice--60b00--99999  | 133 ++++++++++++++++++
 ...99 => vanilla--virtio_net.c--60800--60b00} |   0
 .../vanilla--virtio_net.c--60b00--99999       | 100 +++++++++++++
 4 files changed, 233 insertions(+)
 rename LINUX/final-patches/{vanilla--ice--60300--99999 => vanilla--ice--60300--60b00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ice--60b00--99999
 rename LINUX/final-patches/{vanilla--virtio_net.c--60800--99999 => vanilla--virtio_net.c--60800--60b00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--60b00--99999

diff --git a/LINUX/final-patches/vanilla--ice--60300--99999 b/LINUX/final-patches/vanilla--ice--60300--60b00
similarity index 100%
rename from LINUX/final-patches/vanilla--ice--60300--99999
rename to LINUX/final-patches/vanilla--ice--60300--60b00
diff --git a/LINUX/final-patches/vanilla--ice--60b00--99999 b/LINUX/final-patches/vanilla--ice--60b00--99999
new file mode 100644
index 000000000..fc1be9715
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--60b00--99999
@@ -0,0 +1,133 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index c158749a80e0..5c364110a07c 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -456,6 +461,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -622,6 +631,11 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -942,6 +956,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index ea780d468579..194f0b4ca3bb 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -51,6 +51,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5134,6 +5139,12 @@ static int ice_init(struct ice_pf *pf)
+ 	/* since everything is good, start the service timer */
+ 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ 
++	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_link:
+@@ -5436,6 +5447,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index c9bc3f1add5d..dc1247b501ef 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -23,6 +23,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -1130,6 +1138,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	bool failure;
+ 	u32 first;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+ 	if (xdp_prog) {
+ 		xdp_ring = rx_ring->xdp_ring;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60800--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60800--60b00
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--60800--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--60800--60b00
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60b00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60b00--99999
new file mode 100644
index 000000000..a5d2e8303
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--60b00--99999
@@ -0,0 +1,100 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 5a1c1ec5a64b..30ac7195521b 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -482,6 +482,10 @@ struct virtnet_info {
+ 	u64 device_stats_cap;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_v1_hash hdr;
+ 	/*
+@@ -714,6 +718,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -2812,6 +2821,18 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int xdp_xmit = 0;
+ 	bool napi_complete;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		nm_napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq, budget);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -2888,6 +2909,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	enable_delayed_refill(vi);
+ 
+@@ -6578,6 +6608,12 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		goto free_unregister_netdev;
+ 	}
+ 
++	virtnet_set_queues(vi, vi->curr_queue_pairs);
++
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
++
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	netif_carrier_off(dev);
+@@ -6630,7 +6666,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -6710,6 +6753,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From 46fcb4a069f9f75ae34915ad7d6a60f3c44f96d1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Dec 2024 12:36:28 +0100
Subject: [PATCH 2161/2207] linux/scripts: add workaround for missing gcc14
 support

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 8b0518d87..b124d8133 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -400,7 +400,7 @@ function build-prep()
 pound	:= \\#
 			/\/{s/\\#/$(pound)/}' tools/build/Build.include || true
 		last=compiler-gcc.h
-		for i in $(seq 13); do
+		for i in $(seq 14); do
 			[ -e include/linux/compiler-gcc"$i".h ] ||
 				ln -s "$last" include/linux/compiler-gcc"$i".h
 			last=compiler-gcc$i.h

From 163fe5ed0017ba52d24583a6b53fb8fedc51fff1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Dec 2024 17:43:30 +0100
Subject: [PATCH 2162/2207] linux: check for SetPageSwapBacked

---
 LINUX/configure      | 9 +++++++++
 LINUX/netmap_linux.c | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index c38b75b94..5e744851c 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1982,6 +1982,15 @@ EOF
 	}
 EOF
 
+  # check for SetPageSwapBacked
+  add_test 'have SETPAGESWAPBACKED' <
+
+	void dummy(struct page *page) {
+		SetPageSwapBacked(page);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 130d1740b..101ef1bc1 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1297,6 +1297,9 @@ linux_netmap_poll(struct file *file, struct poll_table_struct *pwait)
 	return netmap_poll(priv, events, &sr);
 }
 
+#ifndef NETMAP_LINUX_HAVE_SETPAGESWAPBACKED
+#define SetPageSwapBacked(p_)
+#endif /* NETMAP_LINUX_HAVE_SETPAGESWAPBACKED */
 #ifdef NETMAP_LINUX_HAVE_VMFAULT_T
 static vm_fault_t
 #else

From 415650d1bb0a50595ea5575e0eef74e3b91e315b Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Fri, 13 Dec 2024 17:44:28 +0100
Subject: [PATCH 2163/2207] linux: check for NETIF_F_LLTX

---
 LINUX/configure      |  9 +++++++++
 LINUX/netmap_linux.c | 10 ++++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 5e744851c..ec32c843d 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1991,6 +1991,15 @@ EOF
 	}
 EOF
 
+  # check for NETIF_F_LLTX
+  add_test 'have NETIF_F_LLTX' <
+
+	u64 dummy(void) {
+		return NETIF_F_LLTX;
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 101ef1bc1..a4be082e2 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2440,6 +2440,11 @@ static const struct net_device_ops nm_vi_ops = {
 	.ndo_get_stats64 = linux_nm_vi_get_stats,
 #endif
 };
+#ifdef NETMAP_LINUX_HAVE_NETIF_F_LLTX
+#define linux_nm_set_lltx(dev_) do { (dev_)->features |= NETIF_F_LLTX; } while (0)
+#else /* !NETMAP_LINUX_HAVE_NETIF_F_LLTX */
+#define linux_nm_set_lltx(dev_)	do { (dev_)->lltx = true; } while (0)
+#endif /* NETMAP_LINUX_HAVE_NETIF_F_LLTX */
 /* dev->name is not initialized yet */
 static void
 linux_nm_vi_setup(struct ifnet *dev)
@@ -2455,10 +2460,11 @@ linux_nm_vi_setup(struct ifnet *dev)
 #endif
 	dev->tx_queue_len = 0;
 	/* XXX */
-	dev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST |
+	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
 		NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_TSO;
+	linux_nm_set_lltx(dev);
 #ifdef NETMAP_LINUX_HAVE_HW_FEATURES
-	dev->hw_features = dev->features & ~NETIF_F_LLTX;
+	dev->hw_features = dev->features;
 #endif
 #ifdef NETMAP_LINUX_HAVE_ADDR_RANDOM
 	eth_hw_addr_random(dev);

From 2f86673ab7cd547663fcca1c09109680c5aadb03 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 14 Dec 2024 15:02:23 +0100
Subject: [PATCH 2164/2207] linux/drivers: patch for 6.12

---
 ...1300--60300 => vanilla--ice--51200--60300} | 14 +--
 ...99 => vanilla--virtio_net.c--60b00--60c00} |  0
 .../vanilla--virtio_net.c--60c00--99999       | 97 +++++++++++++++++++
 3 files changed, 104 insertions(+), 7 deletions(-)
 rename LINUX/final-patches/{vanilla--ice--51300--60300 => vanilla--ice--51200--60300} (90%)
 rename LINUX/final-patches/{vanilla--virtio_net.c--60b00--99999 => vanilla--virtio_net.c--60b00--60c00} (100%)
 create mode 100644 LINUX/final-patches/vanilla--virtio_net.c--60c00--99999

diff --git a/LINUX/final-patches/vanilla--ice--51300--60300 b/LINUX/final-patches/vanilla--ice--51200--60300
similarity index 90%
rename from LINUX/final-patches/vanilla--ice--51300--60300
rename to LINUX/final-patches/vanilla--ice--51200--60300
index cbbcc9dc9..eaadf55ba 100644
--- a/LINUX/final-patches/vanilla--ice--51300--60300
+++ b/LINUX/final-patches/vanilla--ice--51200--60300
@@ -49,7 +49,7 @@ index 136d7911adb4..a9caf17a5160 100644
  }
  
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index 9f02b60459f1..0186182d5e16 100644
+index 963a5f40e071..49e1adb1e4da 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -48,6 +48,11 @@ static DEFINE_IDA(ice_aux_ida);
@@ -64,7 +64,7 @@ index 9f02b60459f1..0186182d5e16 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -4872,6 +4877,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+@@ -4854,6 +4859,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
  	}
  
  	ice_devlink_register(pf);
@@ -75,7 +75,7 @@ index 9f02b60459f1..0186182d5e16 100644
  	return 0;
  
  err_init_aux_unroll:
-@@ -4972,6 +4981,10 @@ static void ice_remove(struct pci_dev *pdev)
+@@ -4954,6 +4963,10 @@ static void ice_remove(struct pci_dev *pdev)
  	struct ice_pf *pf = pci_get_drvdata(pdev);
  	int i;
  
@@ -87,10 +87,10 @@ index 9f02b60459f1..0186182d5e16 100644
  	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
  		if (!ice_is_reset_in_progress(pf->state))
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 836dce840712..b5a272c8cfe4 100644
+index f9bf008471c9..59b8d5769068 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
-@@ -23,6 +23,10 @@
+@@ -22,6 +22,10 @@
  #define FDIR_DESC_RXDID 0x40
  #define ICE_FDIR_CLEAN_DELAY 10
  
@@ -101,7 +101,7 @@ index 836dce840712..b5a272c8cfe4 100644
  /**
   * ice_prgm_fdir_fltr - Program a Flow Director filter
   * @vsi: VSI to send dummy packet
-@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+@@ -221,6 +225,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
  	s16 i = tx_ring->next_to_clean;
  	struct ice_tx_desc *tx_desc;
  	struct ice_tx_buf *tx_buf;
@@ -112,7 +112,7 @@ index 836dce840712..b5a272c8cfe4 100644
  
  	/* get the bql data ready */
  	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
-@@ -1117,6 +1125,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+@@ -1116,6 +1124,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
  	struct xdp_buff xdp;
  	bool failure;
  
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60b00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60b00--60c00
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--60b00--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--60b00--60c00
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60c00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60c00--99999
new file mode 100644
index 000000000..7c50e2949
--- /dev/null
+++ b/LINUX/final-patches/vanilla--virtio_net.c--60c00--99999
@@ -0,0 +1,97 @@
+diff --git a/virtio_net.c b/virtio_net.c
+index 53a038fcbe99..37fd3e5fa584 100644
+--- a/virtio_net.c
++++ b/virtio_net.c
+@@ -483,6 +483,10 @@ struct virtnet_info {
+ 	u64 device_stats_cap;
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ struct padded_vnet_hdr {
+ 	struct virtio_net_hdr_v1_hash hdr;
+ 	/*
+@@ -734,6 +738,11 @@ static void skb_xmit_done(struct virtqueue *vq)
+ 	/* Suppress further interrupts. */
+ 	virtqueue_disable_cb(vq);
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
++		return;
++#endif
++
+ 	if (napi->weight)
+ 		virtqueue_napi_schedule(napi, vq);
+ 	else
+@@ -2838,6 +2847,18 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+ 	unsigned int xdp_xmit = 0;
+ 	bool napi_complete;
+ 
++#ifdef DEV_NETMAP
++        int work_done = 0;
++	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
++
++	if (nm_irq == NM_IRQ_COMPLETED) {
++		nm_napi_complete(napi);
++                return 1;
++        } else if (nm_irq == NM_IRQ_RESCHED) {
++		return budget;
++	}
++#endif
++
+ 	virtnet_poll_cleantx(rq, budget);
+ 
+ 	received = virtnet_receive(rq, budget, &xdp_xmit);
+@@ -2933,6 +2954,15 @@ static int virtnet_open(struct net_device *dev)
+ {
+ 	struct virtnet_info *vi = netdev_priv(dev);
+ 	int i, err;
++#ifdef DEV_NETMAP
++        int ok = virtio_netmap_init_buffers(vi);
++
++        if (ok) {
++            for (i = 0; i < vi->max_queue_pairs; i++)
++		virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
++            return 0;
++        }
++#endif
+ 
+ 	enable_delayed_refill(vi);
+ 
+@@ -6677,6 +6707,9 @@ static int virtnet_probe(struct virtio_device *vdev)
+ 		vi->device_stats_cap = le64_to_cpu(v);
+ 	}
+ 
++#ifdef DEV_NETMAP
++        virtio_netmap_attach(vi);
++#endif
+ 	/* Assume link up if device can't report link status,
+ 	   otherwise get link status from config. */
+ 	netif_carrier_off(dev);
+@@ -6737,7 +6770,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+ static void virtnet_remove(struct virtio_device *vdev)
+ {
+ 	struct virtnet_info *vi = vdev->priv;
++#ifdef DEV_NETMAP
++	/* Save the pointer, will go away after netmap_detach(). */
++	struct netmap_adapter *token = NA(vi->dev);
+ 
++	netmap_detach(vi->dev);
++	virtio_netmap_clean_used_rings(vi, token);
++	virtio_netmap_reclaim_unused(vi);
++#endif
+ 	virtnet_cpu_notif_remove(vi);
+ 
+ 	/* Make sure no work handler is accessing the device. */
+@@ -6819,6 +6859,9 @@ static unsigned int features_legacy[] = {
+ 	VIRTNET_FEATURES,
+ 	VIRTIO_NET_F_GSO,
+ 	VIRTIO_F_ANY_LAYOUT,
++#ifdef VIRTIO_NET_F_PTNETMAP
++	VIRTIO_NET_F_PTNETMAP,
++#endif
+ };
+ 
+ static struct virtio_driver virtio_net_driver = {

From 65c9bb9b04927e43695bd4995fe5b038673ae7ce Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 21 Jan 2025 09:53:12 +0100
Subject: [PATCH 2165/2207] linux/drivers: patches for 6.13

---
 .../final-patches/vanilla--ice--60b00--60d00  | 133 ++++++++++++++++++
 1 file changed, 133 insertions(+)
 create mode 100644 LINUX/final-patches/vanilla--ice--60b00--60d00

diff --git a/LINUX/final-patches/vanilla--ice--60b00--60d00 b/LINUX/final-patches/vanilla--ice--60b00--60d00
new file mode 100644
index 000000000..fc1be9715
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--60b00--60d00
@@ -0,0 +1,133 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index c158749a80e0..5c364110a07c 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -456,6 +461,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -622,6 +631,11 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -942,6 +956,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index ea780d468579..194f0b4ca3bb 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -51,6 +51,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5134,6 +5139,12 @@ static int ice_init(struct ice_pf *pf)
+ 	/* since everything is good, start the service timer */
+ 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ 
++	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_link:
+@@ -5436,6 +5447,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index c9bc3f1add5d..dc1247b501ef 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -23,6 +23,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -1130,6 +1138,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	bool failure;
+ 	u32 first;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+ 	if (xdp_prog) {
+ 		xdp_ring = rx_ring->xdp_ring;

From 3c152446379a8d44103a59b7bb5f2f79b06f32bd Mon Sep 17 00:00:00 2001
From: "hari.thirusangu" 
Date: Mon, 3 Feb 2025 19:06:32 +0000
Subject: [PATCH 2166/2207] generic: fix possible out of bound write

---
 sys/dev/netmap/netmap.c |  1 +
 utils/ctrl-api-test.c   | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index e5f6e1f14..89640b5e1 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3519,6 +3519,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
 		/* check optsz and nro_size to avoid for possible integer overflows of rqsz */
 		if ((optsz > NETMAP_REQ_MAXSIZE) || (opt->nro_size > NETMAP_REQ_MAXSIZE)
 				|| (rqsz + optsz > NETMAP_REQ_MAXSIZE)
+				|| (p - ker + optsz > bufsz)
 				|| (optsz > 0 && rqsz + optsz <= rqsz)) {
 			error = EMSGSIZE;
 			goto out_restore;
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 98ee020eb..969237eb6 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1041,6 +1041,28 @@ infinite_options2(struct TestContext *ctx)
 	return (errno == EINVAL ? 0 : -1);
 }
 
+static int
+invalid_valid_options3(struct TestContext *ctx)
+{
+	struct nmreq_option opt[100];
+	unsigned int i;
+
+	printf("Testing infinite list of options on %s (invalid and valid option)\n", ctx->ifname_ext);
+
+	memset(&opt, 0, sizeof(opt));
+	for (i = 0; i < (sizeof(opt)/sizeof(struct nmreq_option) - 1); i++) {
+		opt[i].nro_reqtype = NETMAP_REQ_OPT_MAX;
+		opt[i].nro_next = (uintptr_t)&opt[i+1];
+	}
+	opt[i].nro_size = 1000;
+	opt[i].nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
+	ctx->nr_opt = opt;
+	if (port_register_hwall(ctx) >= 0)
+		return -1;
+	clear_options(ctx);
+	return (errno == EMSGSIZE ? 0 : -1);
+}
+
 #ifdef CONFIG_NETMAP_EXTMEM
 int
 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
@@ -2068,6 +2090,7 @@ static struct mytest tests[] = {
 	decltest(unsupported_option),
 	decltest(infinite_options),
 	decltest(infinite_options2),
+	decltest(invalid_valid_options3),
 #ifdef CONFIG_NETMAP_EXTMEM
 	decltest(extmem_option),
 	decltest(bad_extmem_option),

From e84fc4b47510ec16d93fde88522d52cd054ab1fd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Feb 2025 10:46:17 +0100
Subject: [PATCH 2167/2207] linux/configure: make driver tests depend on driver
 build

The new build system of Intel drivers generates kcompat files
that are then included in the driver's headers. If we run our
own driver-specific tests in parallel, we may end up reading
the kcompat files while they are being benerated. As a general
solution, we add a Makefile dependency between all the
$DRIVER-specific netmap tests and the build-$DRIVER target.
As a bonus, the netmap $DRIVER-specific tests will not run if $DRIVER
cannot be built.
---
 LINUX/configure | 45 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index ec32c843d..a62ea27a6 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -426,7 +426,7 @@ EOF
 		cat "$TMPDIR/$1".c
 	} >> config.log
 	# add the module to the running list
-	TESTOBJS="$1.o $TESTOBJS"
+	eval TESTOBJS$DRIVERTEST=\"$1.o \$TESTOBJS$DRIVERTEST\"
 	# add the postprocess script for this test
 	if [ -n "$2" ]; then
 		add_file_exists_check "$1.o" "$2" "$3"
@@ -438,7 +438,7 @@ EOF
 #     explicitly naming the test.
 NEXTTEST=1
 add_test() {
-	local t="test__$NEXTTEST"
+	local t="${TESTPREFIX}test__$NEXTTEST"
 	add_named_test $t "$@"
 	NEXTTEST=$((NEXTTEST+1))
 }
@@ -457,7 +457,7 @@ reset_tests() {
 	mkdir "$TMPDIR"
 
 	TESTOBJS=
-	TESTPOSTPROC=
+	DRIVERTEST=
 	NEXTTEST=1
 	cat >> config.log < "$TMPDIR"/Makefile <> "$TMPDIR"/Makefile <> "$TMPDIR"/Makefile <> "$TMPDIR"/Makefile
@@ -2009,6 +2018,8 @@ EOF
 
   add_file_exists_check e1000e/e1000.h true "drv_source_error e1000e"
 
+  DRIVERTEST=e1000e
+
   add_test 'have E1000E_HWADDR' <
 
@@ -2426,6 +2443,10 @@ EOF
   fi # virtio-net
 
   if drv enabled i40e; then
+
+    DRIVERTEST=i40e
+
+    add_test_flags -I\$M/i40e
     add_test 'define I40E_PTR_ARRAY' <
@@ -2449,6 +2471,9 @@ EOF
 
   if drv enabled ice; then
     add_test_flags -I\$M/ice
+
+    DRIVERTEST=ice
+
     add_test 'have ICE_XRINGS' <
Date: Tue, 11 Feb 2025 21:18:17 +0100
Subject: [PATCH 2168/2207] linux/drivers: switch to github for Intel

---
 LINUX/default-config.mak.in_ | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 933a6b4cb..1eaa976f9 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -59,6 +59,17 @@
 # all the intel drivers are compiled in much the same way, so we factor them
 # here. $(1) is the driver name, while $(2) is the driver version
 define intel_driver
+$(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)/v$(2).zip || wget https://github.com/intel/ethernet-linux-$(1)/archive/refs/tags/v$(2).zip -P @SRCDIR@/ext-drivers/$(1)
+$(1)@src 	:= unzip -u @SRCDIR@/ext-drivers/$(1)/v$(2).zip && ln -s ethernet-linux-$(1)-$(2)/src $(1)
+$(1)@patch 	:= patches/intel--$(1)--$(2)
+$(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
+$(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
+$(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
+$(1)@distclean	:= rm -rf ethernet-linux-$(1)-$(2)
+$(1)@force	:= 1
+endef
+
+define intel_legacy_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz || wget https://sourceforge.net/projects/e1000/files/$(1)%20stable/$(2)/$(1)-$(2).tar.gz -P @SRCDIR@/ext-drivers/
 $(1)@src 	:= tar xf @SRCDIR@/ext-drivers/$(1)-$(2).tar.gz && ln -s $(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
@@ -98,7 +109,8 @@ ice@prepare := $(if $(filter $(ice@v),1.7.16 1.8.8 1.8.9 1.9.7 1.9.11 1.10.1.2 1
 stmmac@conf := CONFIG_STMMAC_ETH
 
 # only define the drivers that are selected after the --(no-)ext-drivers= processing (variable E_DRIVERS)
-$(foreach d,$(filter ixgbe ixgbevf e1000e igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
+$(foreach d,$(filter ixgbe ixgbevf igb ice i40e,$(E_DRIVERS)),$(eval $(call intel_driver,$d,$($(d)@v))))
+$(foreach d,$(filter e1000e,$(E_DRIVERS)),$(eval $(call intel_legacy_driver,$d,$($(d)@v))))
 
 ifneq ($(filter e1000e,$(E_DRIVERS)),)
 e1000e@fetch := test -e @SRCDIR@/ext-drivers/e1000e-$(e1000e@v).tar.gz || wget https://sourceforge.net/projects/e1000/files/e1000e%20historic%20archive/$(e1000e@v)/e1000e-$(e1000e@v).tar.gz -P @SRCDIR@/ext-drivers/

From 707bf25000a29ac9ab387397875bfafdf44c8dbf Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 11 Feb 2025 20:19:55 +0100
Subject: [PATCH 2169/2207] linux/drivers: patches for latest Intel drivers

---
 LINUX/configure                           |   8 +
 LINUX/final-patches/intel--i40e--2.27.8   | 173 +++++++++++++
 LINUX/final-patches/intel--ice--1.15.4    | 282 ++++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.18.7    | 138 +++++++++++
 LINUX/final-patches/intel--ixgbe--6.0.5   | 178 ++++++++++++++
 LINUX/final-patches/intel--ixgbevf--5.0.2 | 168 +++++++++++++
 LINUX/ixgbe_netmap_linux.h                |  12 +-
 7 files changed, 957 insertions(+), 2 deletions(-)
 create mode 100644 LINUX/final-patches/intel--i40e--2.27.8
 create mode 100644 LINUX/final-patches/intel--ice--1.15.4
 create mode 100644 LINUX/final-patches/intel--igb--5.18.7
 create mode 100644 LINUX/final-patches/intel--ixgbe--6.0.5
 create mode 100644 LINUX/final-patches/intel--ixgbevf--5.0.2

diff --git a/LINUX/configure b/LINUX/configure
index a62ea27a6..1768431f5 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2137,6 +2137,14 @@ EOF
        }
 EOF
 
+  # state bitmap or unsigned long?
+  add_test "have IXGBE_STATE_BITMAP" <state);
+	}
+EOF
+
   fi # ixgbe
 
   if drv enabled ixgbevf; then
diff --git a/LINUX/final-patches/intel--i40e--2.27.8 b/LINUX/final-patches/intel--i40e--2.27.8
new file mode 100644
index 000000000..4c12c530b
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.27.8
@@ -0,0 +1,173 @@
+diff --git a/i40e/Makefile b/src/Makefile
+index 5f1e70d..ff4910f 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,9 +10,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
+ 
+-i40e-y := i40e_main.o \
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -29,9 +29,9 @@ i40e-y := i40e_main.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+ 
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ 
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+@@ -42,7 +42,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ 
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+@@ -96,9 +96,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../${DRIVER}.${MANSECTION}:
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/src/i40e_main.c
+index f15e9b9..86a17c0 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -162,6 +162,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_allocate_dma_mem - OS specific memory alloc for shared code
+  * @hw:   pointer to the HW structure
+@@ -4264,6 +4269,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4392,6 +4401,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4420,6 +4433,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -16136,6 +16154,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16532,6 +16556,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/src/i40e_txrx.c
+index 1b8e9bb..8d057a7 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -986,6 +990,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2954,7 +2963,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--1.15.4 b/LINUX/final-patches/intel--ice--1.15.4
new file mode 100644
index 000000000..3dd306b22
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.15.4
@@ -0,0 +1,282 @@
+diff --git a/ice/Makefile b/src/Makefile
+index 43bc5a9..b59b7d7 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -41,9 +41,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -85,14 +85,14 @@ ice-y := ice_main.o	\
+ 	 ice_ieps.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/ice_devlink_health.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_aux_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_DEBUG_FS) += ice_fwlog.o
+-
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/ice_devlink_health.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_fwlog.o
++
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -104,43 +104,43 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_virtchnl_fsub.o		\
+ 	ice_vf_lib.o
+ 
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ 
+ ifneq (${CONFIG_DPLL},)
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
+ else
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_tspll.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_tspll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq ($(shell grep HAVE_LMV1_SUPPORT $(src)/kcompat_generated_defs.h),)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
+@@ -152,7 +152,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ # ice does not support building on kernels older than 3.10.0
+ $(call minimum_kver_check,3,10,0)
+@@ -171,7 +171,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -216,7 +216,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/src/ice_base.c
+index 714abce..e318b40 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -9,6 +9,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -536,6 +541,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -694,6 +703,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -968,6 +982,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	if (tstamp_ring) {
+ 		u8 txtime_buf_len = struct_size(txtime_qg_buf, txtimeqs, 1);
+diff --git a/ice/ice_main.c b/src/ice_main.c
+index 06d8413..3d468f2 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -66,6 +66,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6917,6 +6922,7 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7196,6 +7202,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_features:
+@@ -7289,6 +7300,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/src/ice_txrx.c
+index 78945b7..44ae62f 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -258,6 +262,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -476,6 +484,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1720,6 +1738,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.18.7 b/LINUX/final-patches/intel--igb--5.18.7
new file mode 100644
index 000000000..4eeeb5b96
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.18.7
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/src/Makefile
+index 982cd53..d54cb7a 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/src/igb_main.c
+index 07d1b87..e8bc3e9 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -249,6 +249,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3245,6 +3249,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3451,6 +3459,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3867,6 +3879,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7442,6 +7457,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8458,6 +8478,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8777,6 +8802,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--6.0.5 b/LINUX/final-patches/intel--ixgbe--6.0.5
new file mode 100644
index 000000000..606f813e8
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--6.0.5
@@ -0,0 +1,178 @@
+diff --git a/ixgbe/Makefile b/src/Makefile
+index 84a7f13..268a300 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -32,29 +32,29 @@ define ixgbe-y
+ 	ixgbe_devlink.o
+ 	ixgbe_fw_update.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+ ixgbe-y += kcompat_pldmfw.o
+ endif
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/src/ixgbe_main.c
+index 5bd35bd..20c6429 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -779,6 +779,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_reset_pf_report - reset pf and print reset report
+  * @tx_ring: tx ring number
+@@ -944,6 +961,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2418,6 +2446,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -4499,6 +4537,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -5193,6 +5235,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -14610,6 +14658,10 @@ no_info_string:
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_devlink_register:
+@@ -14694,6 +14746,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		ixgbe_pf_fwlog_deinit(adapter);
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--5.0.2 b/LINUX/final-patches/intel--ixgbevf--5.0.2
new file mode 100644
index 000000000..7c7174855
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--5.0.2
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/src/Makefile
+index 117871c..02290b5 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/src/ixgbevf_main.c
+index 32b3998..ab9efe5 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -352,6 +352,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -372,6 +389,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1390,6 +1418,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2108,6 +2146,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2342,6 +2384,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5661,8 +5707,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5703,6 +5751,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/src/kcompat.h
+index ab1d295..21bc1e7 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -12,6 +12,8 @@
+ 
+ #include "kcompat_gcc.h"
+ 
++#include 
++
+ #include 
+ #include 
+ #include 
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 44557e7c1..73b75c7d2 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -145,6 +145,12 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBE_HAVE_NTA */
 
+#ifdef NETMAP_LINUX_IXGBE_HAVE_STATE_BITMAP
+#define NM_IXGBE_STATE(adapter) (&(adapter)->state)
+#else
+#define NM_IXGBE_STATE(adapter) ((adapter)->state)
+#endif /* NETMAP_LINUX_IXGBE_HAVE_STATE_BITMAP */
+
 #else
 /***********************************************************************
  *                        ixgbevf                                      *
@@ -196,6 +202,8 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBEVF_HAVE_NTA */
 
+#define NM_IXGBE_STATE(adapter)	(&(adapter)->state)
+
 #endif /* NM_IXGBE */
 /**********************************************************************/
 
@@ -227,7 +235,7 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 
 	// adapter->netdev->trans_start = jiffies; // disable watchdog ?
 	/* protect against other reinit */
-	while (test_and_set_bit(NM_IXGBE_RESETTING, &adapter->state))
+	while (test_and_set_bit(NM_IXGBE_RESETTING, NM_IXGBE_STATE(adapter)))
 		usleep_range(1000, 2000);
 
 	if (netif_running(adapter->netdev))
@@ -242,7 +250,7 @@ ixgbe_netmap_reg(struct netmap_adapter *na, int onoff)
 	/* XXX SRIOV might need another 2sec wait */
 	if (netif_running(adapter->netdev))
 		NM_IXGBE_UP(adapter);	/* also enables intr */
-	clear_bit(NM_IXGBE_RESETTING, &adapter->state);
+	clear_bit(NM_IXGBE_RESETTING, NM_IXGBE_STATE(adapter));
 	return (0);
 }
 

From 19a7eb6a0ded578f725febffda2d0e270b64e7dc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 12 Feb 2025 13:07:15 +0100
Subject: [PATCH 2170/2207] reset TESTPOSTPROC between tests

---
 LINUX/configure | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/configure b/LINUX/configure
index 1768431f5..710b71e06 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -457,6 +457,7 @@ reset_tests() {
 	mkdir "$TMPDIR"
 
 	TESTOBJS=
+	TESTPOSTPROC=
 	DRIVERTEST=
 	NEXTTEST=1
 	cat >> config.log <
Date: Mon, 24 Feb 2025 18:13:11 +0100
Subject: [PATCH 2171/2207] linux/drivers: patches for latest Intel versions

---
 LINUX/final-patches/intel--ice--1.16.3  | 288 ++++++++++++++++++++++++
 LINUX/final-patches/intel--ixgbe--6.0.6 | 178 +++++++++++++++
 2 files changed, 466 insertions(+)
 create mode 100644 LINUX/final-patches/intel--ice--1.16.3
 create mode 100644 LINUX/final-patches/intel--ixgbe--6.0.6

diff --git a/LINUX/final-patches/intel--ice--1.16.3 b/LINUX/final-patches/intel--ice--1.16.3
new file mode 100644
index 000000000..9adf21dc6
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--1.16.3
@@ -0,0 +1,288 @@
+commit 969129ed6281851577a098501a489e72fa486491
+Author: Giuseppe Lettieri 
+Date:   Tue Feb 11 20:12:52 2025 +0100
+
+    netmap patch
+
+diff --git a/ice/Makefile b/src/Makefile
+index 8b06e64..684df0f 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -41,9 +41,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+ 	 ice_nvm.o	\
+@@ -87,14 +87,14 @@ ice-y := ice_main.o	\
+ 	 ice_ieps_lm.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/ice_devlink_health.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_aux_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_DEBUG_FS) += ice_fwlog.o
+-
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/ice_devlink_health.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_fwlog.o
++
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -106,43 +106,43 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_virtchnl_fsub.o		\
+ 	ice_vf_lib.o
+ 
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ 
+ ifneq (${CONFIG_DPLL},)
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
+ else
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_tspll.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_tspll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifneq ($(shell grep HAVE_LMV1_SUPPORT $(src)/kcompat_generated_defs.h),)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
+@@ -154,7 +154,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ # ice does not support building on kernels older than 3.10.0
+ $(call minimum_kver_check,3,10,0)
+@@ -173,7 +173,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -218,7 +218,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/src/ice_base.c
+index f977414..e494a00 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -9,6 +9,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -537,6 +542,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -695,6 +704,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -974,6 +988,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	if (tstamp_ring) {
+ 		u8 txtime_buf_len = struct_size(txtime_qg_buf, txtimeqs, 1);
+diff --git a/ice/ice_main.c b/src/ice_main.c
+index a8c1721..63f2e69 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -67,6 +67,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -6995,6 +7000,7 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
++
+ 	return 0;
+ }
+ 
+@@ -7274,6 +7280,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_features:
+@@ -7367,6 +7378,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/src/ice_txrx.c
+index d5f7d5c..f84602d 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -258,6 +262,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -476,6 +484,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1720,6 +1738,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--ixgbe--6.0.6 b/LINUX/final-patches/intel--ixgbe--6.0.6
new file mode 100644
index 000000000..9a28af638
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--6.0.6
@@ -0,0 +1,178 @@
+diff --git a/ixgbe/Makefile b/src/Makefile
+index 84a7f13..268a300 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbe-y
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -32,29 +32,29 @@ define ixgbe-y
+ 	ixgbe_devlink.o
+ 	ixgbe_fw_update.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
+ 
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+ 
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+ 
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+ 
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ 
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+ ixgbe-y += kcompat_pldmfw.o
+ endif
+ 
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbe
++DRIVER := ixgbe$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -127,9 +127,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/src/ixgbe_main.c
+index ed3e43b..5db5331 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -779,6 +779,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_reset_pf_report - reset pf and print reset report
+  * @tx_ring: tx ring number
+@@ -944,6 +961,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2418,6 +2446,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -4499,6 +4537,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -5193,6 +5235,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -14610,6 +14658,10 @@ no_info_string:
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_devlink_register:
+@@ -14694,6 +14746,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		ixgbe_pf_fwlog_deinit(adapter);
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 

From c9c481999906954600582ef1d056e003de33d7a2 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 31 Mar 2025 13:57:38 +0200
Subject: [PATCH 2172/2207] linux/scripts: fix regresssion in build-tests for
 internal drivers

---
 LINUX/configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 710b71e06..af78323b1 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -542,7 +542,7 @@ E_DRIVERS := $(edrv print)
 C_DRIVERS := $(cdrv print)
 I_DRIVERS := $(idrv print)
 
-TOBUILD := \$(filter-out \$(C_DRIVERS),\$(E_DRIVERS))
+TOBUILD := \$(filter-out \$(C_DRIVERS),\$(S_DRIVERS))
 
 all: \$(S_DRIVERS:%=get-%) \$(TOBUILD:%=build-%) \$(TOBUILD:%=tests-%) \$(I_DRIVERS:%=patch-%) tests
 

From c99b13f7e968c2213a44c85f68c19026008252b1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 31 Mar 2025 14:32:44 +0200
Subject: [PATCH 2173/2207] linux/ixgbe: fix build test for recent kernels

---
 LINUX/ixgbe_netmap_linux.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 73b75c7d2..64a4b70ef 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -145,7 +145,7 @@ ixgbe_netmap_configure_srrctl(struct NM_IXGBE_ADAPTER *adapter, struct NM_IXGBE_
 #define NETMAP_LINUX_HAVE_NTA
 #endif /* NETMAP_LINUX_IXGBE_HAVE_NTA */
 
-#ifdef NETMAP_LINUX_IXGBE_HAVE_STATE_BITMAP
+#ifdef NETMAP_LINUX_HAVE_IXGBE_STATE_BITMAP
 #define NM_IXGBE_STATE(adapter) (&(adapter)->state)
 #else
 #define NM_IXGBE_STATE(adapter) ((adapter)->state)

From cb299c51bc1e47245e03041c21ab1c0c5a82d2d0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 31 Mar 2025 14:55:29 +0200
Subject: [PATCH 2174/2207] linux: make sure we can actually use the ax25 ptr

---
 LINUX/configure | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index af78323b1..608386ebb 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1128,9 +1128,10 @@ EOF
   add_test 'have AX25PTR' <
 
-	void * dummy(struct net_device *dev)
+	extern struct netmap_adapter *na;
+	void dummy(struct net_device *dev)
 	{
-		return dev->ax25_ptr;
+		dev->ax25_ptr = na;
 	}
 EOF
 

From f452c5714f315d55de3c429baaf355b4a02366c1 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 1 Apr 2025 15:02:45 +0200
Subject: [PATCH 2175/2207] linux/ice: remove access to vsi->rx_buf_len

---
 .../final-patches/vanilla--ice--60b00--60d00  | 133 ------------------
 LINUX/ice_netmap_linux.h                      |   2 +-
 2 files changed, 1 insertion(+), 134 deletions(-)
 delete mode 100644 LINUX/final-patches/vanilla--ice--60b00--60d00

diff --git a/LINUX/final-patches/vanilla--ice--60b00--60d00 b/LINUX/final-patches/vanilla--ice--60b00--60d00
deleted file mode 100644
index fc1be9715..000000000
--- a/LINUX/final-patches/vanilla--ice--60b00--60d00
+++ /dev/null
@@ -1,133 +0,0 @@
-diff --git a/ice/ice_base.c b/ice/ice_base.c
-index c158749a80e0..5c364110a07c 100644
---- a/ice/ice_base.c
-+++ b/ice/ice_base.c
-@@ -6,6 +6,11 @@
- #include "ice_lib.h"
- #include "ice_dcb_lib.h"
- #include "ice_sriov.h"
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#define NETMAP_ICE_BASE
-+#include 
-+#endif
-+
- 
- /**
-  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
-@@ -456,6 +461,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
- 		rxdid = ICE_RXDID_FLEX_NIC_2;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
-+#endif /* DEV_NETMAP */
-+
- 	/* Enable Flexible Descriptors in the queue context which
- 	 * allows this driver to select a specific receive descriptor format
- 	 * increasing context priority to pick up profile ID; default is 0x01;
-@@ -622,6 +631,11 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
- 		return 0;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	if (ice_netmap_configure_rx_ring(ring))
-+		return 0;
-+#endif /* DEV_NETMAP */
-+
- 	ice_alloc_rx_bufs(ring, num_bufs);
- 
- 	return 0;
-@@ -942,6 +956,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
- 	if (pf_q == le16_to_cpu(txq->txq_id))
- 		ring->txq_teid = le32_to_cpu(txq->q_teid);
- 
-+#ifdef DEV_NETMAP
-+	ice_netmap_configure_tx_ring(ring);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- }
- 
-diff --git a/ice/ice_main.c b/ice/ice_main.c
-index ea780d468579..194f0b4ca3bb 100644
---- a/ice/ice_main.c
-+++ b/ice/ice_main.c
-@@ -51,6 +51,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
- DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
- EXPORT_SYMBOL(ice_xdp_locking_key);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#define NETMAP_ICE_LIB
-+#include 
-+#endif
-+
- /**
-  * ice_hw_to_dev - Get device pointer from the hardware structure
-  * @hw: pointer to the device HW structure
-@@ -5134,6 +5139,12 @@ static int ice_init(struct ice_pf *pf)
- 	/* since everything is good, start the service timer */
- 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
- 
-+	ice_devlink_register(pf);
-+
-+#ifdef DEV_NETMAP
-+	ice_netmap_attach(pf);
-+#endif
-+
- 	return 0;
- 
- err_init_link:
-@@ -5436,6 +5447,10 @@ static void ice_remove(struct pci_dev *pdev)
- 	struct ice_pf *pf = pci_get_drvdata(pdev);
- 	int i;
- 
-+#ifdef DEV_NETMAP
-+	ice_netmap_detach(pf);
-+#endif /* DEV_NETMAP */
-+
- 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
- 		if (!ice_is_reset_in_progress(pf->state))
- 			break;
-diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index c9bc3f1add5d..dc1247b501ef 100644
---- a/ice/ice_txrx.c
-+++ b/ice/ice_txrx.c
-@@ -23,6 +23,10 @@
- #define FDIR_DESC_RXDID 0x40
- #define ICE_FDIR_CLEAN_DELAY 10
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /**
-  * ice_prgm_fdir_fltr - Program a Flow Director filter
-  * @vsi: VSI to send dummy packet
-@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
- 	s16 i = tx_ring->next_to_clean;
- 	struct ice_tx_desc *tx_desc;
- 	struct ice_tx_buf *tx_buf;
-+#ifdef DEV_NETMAP
-+	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
- 
- 	/* get the bql data ready */
- 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
-@@ -1130,6 +1138,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
- 	bool failure;
- 	u32 first;
- 
-+#ifdef DEV_NETMAP
-+	if (rx_ring->netdev) {
-+		int dummy, nm_irq;
-+		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
-+		if (nm_irq != NM_IRQ_PASS) {
-+			return 1;
-+		}
-+	}
-+#endif /* DEV_NETMAP */
-+
- 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
- 	if (xdp_prog) {
- 		xdp_ring = rx_ring->xdp_ring;
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index 59dc80f10..d6eadebff 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -462,7 +462,7 @@ ice_netmap_attach(struct ice_pf *pf)
 	na.num_rx_desc = vsi->rx_rings[0]->count;
 	na.num_tx_rings = vsi->num_txq;
 	na.num_rx_rings = vsi->num_rxq;
-	na.rx_buf_maxsize = vsi->rx_buf_len;
+	na.rx_buf_maxsize = vsi->rx_rings[0]->rx_buf_len;
 	na.nm_txsync = ice_netmap_txsync;
 	na.nm_rxsync = ice_netmap_rxsync;
 	na.nm_register = ice_netmap_reg;

From 1005debd4cd3dc70ca38574f15ae1aa5f53d5deb Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 1 Apr 2025 15:12:16 +0200
Subject: [PATCH 2176/2207] linux/ice: fix compilation on older kernels

---
 LINUX/configure                               |  11 +-
 .../final-patches/vanilla--ice--50500--50800  | 128 +++++++++++++++++
 .../final-patches/vanilla--ice--50800--50c00  | 130 ++++++++++++++++++
 .../final-patches/vanilla--ice--50c00--50d00  | 129 +++++++++++++++++
 LINUX/ice_netmap_linux.h                      |   3 +
 5 files changed, 400 insertions(+), 1 deletion(-)
 create mode 100644 LINUX/final-patches/vanilla--ice--50500--50800
 create mode 100644 LINUX/final-patches/vanilla--ice--50800--50c00
 create mode 100644 LINUX/final-patches/vanilla--ice--50c00--50d00

diff --git a/LINUX/configure b/LINUX/configure
index 608386ebb..7444f7f73 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2480,10 +2480,10 @@ EOF
   fi # i40e
 
   if drv enabled ice; then
-    add_test_flags -I\$M/ice
 
     DRIVERTEST=ice
 
+    add_test_flags -I\$M/ice
     add_test 'have ICE_XRINGS' <rx_rings[0];
 	}
 EOF
+
+    add_test_flags -I\$M/ice
+    add_test 'have ICE_VSI_DOWN' <
++#endif
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -396,6 +400,10 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 		wr32(hw, QRXFLXP_CNTXT(pf_q), regval);
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Absolute queue number out of 2K needs to be passed */
+ 	err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q);
+ 	if (err) {
+@@ -418,6 +426,11 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	ring->tail = hw->hw_addr + QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	err = ring->xsk_umem ?
+ 	      ice_alloc_rx_bufs_slow_zc(ring, ICE_DESC_UNUSED(ring)) :
+ 	      ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring));
+@@ -656,6 +669,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 69bff085acf7..c0c88851609d 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -41,6 +41,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -3365,6 +3370,9 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	/* print PCI link speed and width */
+ 	pcie_print_link_status(pf->pdev);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_alloc_sw_unroll:
+@@ -3396,6 +3404,9 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 2c212f64d99f..30eeb4bbcc77 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -15,6 +15,10 @@
+ 
+ #define ICE_RX_HDR_SIZE		256
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_unmap_and_free_tx_buf - Release a Tx buffer
+  * @ring: the ring that owns the buffer
+@@ -122,6 +126,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buf = &tx_ring->tx_buf[i];
+ 	tx_desc = ICE_TX_DESC(tx_ring, i);
+@@ -992,6 +1000,16 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 
+ 	xdp.rxq = &rx_ring->xdp_rxq;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* start the loop to process Rx packets bounded by 'budget' */
+ 	while (likely(total_rx_pkts < (unsigned int)budget)) {
+ 		union ice_32b_rx_flex_desc *rx_desc;
diff --git a/LINUX/final-patches/vanilla--ice--50800--50c00 b/LINUX/final-patches/vanilla--ice--50800--50c00
new file mode 100644
index 000000000..0e22be056
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--50800--50c00
@@ -0,0 +1,130 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index d620d26d42ed..a103c5442483 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -5,6 +5,10 @@
+ #include "ice_base.h"
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -385,6 +389,10 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -433,6 +441,11 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -682,6 +695,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 4cbd49c87568..07d22e56f33b 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -43,6 +43,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -3502,6 +3507,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ probe_done:
+ 	/* ready to go, so clear down state bit */
+ 	clear_bit(__ICE_DOWN, pf->state);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_alloc_sw_unroll:
+@@ -3537,6 +3546,9 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index abdb137c8bb7..0962a043fc0b 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -18,6 +18,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -208,6 +212,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buf = &tx_ring->tx_buf[i];
+ 	tx_desc = ICE_TX_DESC(tx_ring, i);
+@@ -1094,6 +1102,17 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	bool failure;
+ 
+ 	xdp.rxq = &rx_ring->xdp_rxq;
++
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/final-patches/vanilla--ice--50c00--50d00 b/LINUX/final-patches/vanilla--ice--50c00--50d00
new file mode 100644
index 000000000..65500e09e
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--50c00--50d00
@@ -0,0 +1,129 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 1148d768f8ed..7c6f966a0167 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -5,6 +5,10 @@
+ #include "ice_base.h"
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -401,6 +405,10 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 	/* Rx queue threshold in units of 64 */
+ 	rlan_ctx.lrxqthresh = 1;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -453,6 +461,11 @@ int ice_setup_rx_ctx(struct ice_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+ 	return 0;
+@@ -702,6 +715,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index d821c687f239..316669305b98 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -35,6 +35,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ static struct workqueue_struct *ice_wq;
+ static const struct net_device_ops ice_netdev_safe_mode_ops;
+ static const struct net_device_ops ice_netdev_ops;
+@@ -4263,6 +4268,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ probe_done:
+ 	/* ready to go, so clear down state bit */
+ 	clear_bit(__ICE_DOWN, pf->state);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
+ 	return 0;
+ 
+ err_send_version_unroll:
+@@ -4362,6 +4371,9 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index b91dcfd12727..a2e0687c1771 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -18,6 +18,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -208,6 +212,10 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	tx_buf = &tx_ring->tx_buf[i];
+ 	tx_desc = ICE_TX_DESC(tx_ring, i);
+@@ -1062,6 +1070,16 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ice_rx_frame_truesize(rx_ring, 0);
diff --git a/LINUX/ice_netmap_linux.h b/LINUX/ice_netmap_linux.h
index d6eadebff..f83588ef1 100644
--- a/LINUX/ice_netmap_linux.h
+++ b/LINUX/ice_netmap_linux.h
@@ -8,6 +8,9 @@
 #define NM_ICE_RXRING ice_ring
 #define NM_ICE_TXRING ice_ring
 #endif /* NETMAP_LINUX_HAVE_ICE_XRINGS */
+#ifndef NETMAP_LINUX_HAVE_ICE_VSI_DOWN
+#define ICE_VSI_DOWN __ICE_DOWN
+#endif /* !NETMAP_LINUX_HAVE_ICE_VSI_DOWN */
 
 extern int ix_crcstrip;
 

From e71c1888da0fd2b7eeed114d9312b1a34721b121 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 1 Apr 2025 16:32:20 +0200
Subject: [PATCH 2177/2207] linux/forcedeth: fix compilation for 6.14

---
 LINUX/forcedeth_netmap.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LINUX/forcedeth_netmap.h b/LINUX/forcedeth_netmap.h
index 0fd7a2915..35ac46b78 100644
--- a/LINUX/forcedeth_netmap.h
+++ b/LINUX/forcedeth_netmap.h
@@ -79,7 +79,7 @@ forcedeth_netmap_reg(struct netmap_adapter *na, int onoff)
 
 	// first half of nv_change_mtu() - down
 	nv_disable_irq(ifp);
-	nv_napi_disable(ifp);
+	napi_disable(&np->napi);
 	netif_tx_lock_bh(ifp);
 	netif_addr_lock(ifp);
 	spin_lock(&np->lock);
@@ -112,7 +112,7 @@ forcedeth_netmap_reg(struct netmap_adapter *na, int onoff)
 	spin_unlock(&np->lock);
 	netif_addr_unlock(ifp);
 	netif_tx_unlock_bh(ifp);
-	nv_napi_enable(ifp);
+	napi_enable(&np->napi);
 	nv_enable_irq(ifp);
 
 	return (0);

From d4593cd1f8b536a2d20b58f12846b7ae4c900e11 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 2 Apr 2025 15:51:48 +0200
Subject: [PATCH 2178/2207] linux/ice: remove spurious hooks

---
 LINUX/final-patches/intel--ice--1.12.18 | 21 ++-------------------
 LINUX/final-patches/intel--ice--1.12.7  | 21 ++-------------------
 LINUX/final-patches/intel--ice--1.13.7  | 21 ++-------------------
 3 files changed, 6 insertions(+), 57 deletions(-)

diff --git a/LINUX/final-patches/intel--ice--1.12.18 b/LINUX/final-patches/intel--ice--1.12.18
index 6722cec49..c9da8e07f 100644
--- a/LINUX/final-patches/intel--ice--1.12.18
+++ b/LINUX/final-patches/intel--ice--1.12.18
@@ -209,7 +209,7 @@ index 112e871..202face 100644
  	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
  	 * driver transitions to recovery mode. If this is not set
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 582e2cf..e2c6401 100644
+index 582e2cf..f5e07bd 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -32,6 +32,10 @@
@@ -234,24 +234,7 @@ index 582e2cf..e2c6401 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -419,6 +427,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
- 	u32 size;
- 	u16 i;
- 
-+#ifdef DEV_NETMAP
-+    if (rx_ring->netdev) {
-+        int dummy, nm_irq;
-+        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
-+        if (nm_irq != NM_IRQ_PASS) {
-+            return;
-+        }
-+    }
-+#endif /* DEV_NETMAP */
-+
- 	/* ring already cleared, nothing to do */
- 	if (!rx_ring->rx_buf)
- 		return;
-@@ -1670,6 +1688,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+@@ -1670,6 +1678,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
  #endif
  	bool failure;
  
diff --git a/LINUX/final-patches/intel--ice--1.12.7 b/LINUX/final-patches/intel--ice--1.12.7
index 26008b4cc..d91286592 100644
--- a/LINUX/final-patches/intel--ice--1.12.7
+++ b/LINUX/final-patches/intel--ice--1.12.7
@@ -209,7 +209,7 @@ index a32bb2a..5b455c5 100644
  	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
  	 * driver transitions to recovery mode. If this is not set
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 582e2cf..e2c6401 100644
+index 582e2cf..f5e07bd 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -32,6 +32,10 @@
@@ -234,24 +234,7 @@ index 582e2cf..e2c6401 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -419,6 +427,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
- 	u32 size;
- 	u16 i;
- 
-+#ifdef DEV_NETMAP
-+    if (rx_ring->netdev) {
-+        int dummy, nm_irq;
-+        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
-+        if (nm_irq != NM_IRQ_PASS) {
-+            return;
-+        }
-+    }
-+#endif /* DEV_NETMAP */
-+
- 	/* ring already cleared, nothing to do */
- 	if (!rx_ring->rx_buf)
- 		return;
-@@ -1670,6 +1688,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+@@ -1670,6 +1678,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
  #endif
  	bool failure;
  
diff --git a/LINUX/final-patches/intel--ice--1.13.7 b/LINUX/final-patches/intel--ice--1.13.7
index d093ccd07..cbd588c5d 100644
--- a/LINUX/final-patches/intel--ice--1.13.7
+++ b/LINUX/final-patches/intel--ice--1.13.7
@@ -209,7 +209,7 @@ index e9cc474..0eed1e5 100644
  	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
  	 * driver transitions to recovery mode. If this is not set
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index 0117124..e20f29e 100644
+index 0117124..1caa0a3 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
 @@ -32,6 +32,10 @@
@@ -234,24 +234,7 @@ index 0117124..e20f29e 100644
  
  	/* get the bql data ready */
  #ifdef HAVE_XDP_SUPPORT
-@@ -424,6 +432,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
- 	u32 size;
- 	u16 i;
- 
-+#ifdef DEV_NETMAP
-+    if (rx_ring->netdev) {
-+        int dummy, nm_irq;
-+        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
-+        if (nm_irq != NM_IRQ_PASS) {
-+            return;
-+        }
-+    }
-+#endif /* DEV_NETMAP */
-+
- 	/* ring already cleared, nothing to do */
- 	if (!rx_ring->rx_buf)
- 		return;
-@@ -1675,6 +1693,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+@@ -1675,6 +1683,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
  #endif
  	bool failure;
  

From c138d342f7f25a7551d51223793940557fd53777 Mon Sep 17 00:00:00 2001
From: Konstantin Kogdenko 
Date: Tue, 24 Jun 2025 21:47:15 +0300
Subject: [PATCH 2179/2207] linux: veth: fix kernel oops in multiqueue mode

Make the ring configuration identical at both veth endpoints.
Oops can be reproduced with pkt-gen:
ip l a dev vetha type veth peer vethb
ethtool -L vetha rx 4 tx 4
pkt-get -f rx -i vetha
---
 LINUX/netmap_linux.c         |  7 ++++---
 LINUX/veth_netmap.h          | 21 ++++++++++++++++++++-
 sys/dev/netmap/netmap_kern.h |  2 ++
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a4be082e2..672c22ee2 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -1225,8 +1225,8 @@ netmap_rings_config_get(struct netmap_adapter *na, struct nm_config_info *info)
 EXPORT_SYMBOL(netmap_rings_config_get);
 
 /* Default nm_config implementation for netmap_hw_adapter on Linux. */
-static int
-netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
+int
+nm_os_config(struct netmap_adapter *na, struct nm_config_info *info)
 {
 	int ret = netmap_rings_config_get(na, info);
 
@@ -1239,6 +1239,7 @@ netmap_linux_config(struct netmap_adapter *na, struct nm_config_info *info)
 
 	return 0;
 }
+EXPORT_SYMBOL(nm_os_config);
 
 /* ######################## FILE OPERATIONS ####################### */
 
@@ -2559,7 +2560,7 @@ nm_os_onattach(struct ifnet *ifp)
 #endif /* NETMAP_LINUX_HAVE_SET_CHANNELS */
 #endif /* NETMAP_LINUX_HAVE_AX25PTR */
 	if (na->nm_config == NULL) {
-		hwna->up.nm_config = netmap_linux_config;
+		hwna->up.nm_config = nm_os_config;
 	}
 }
 
diff --git a/LINUX/veth_netmap.h b/LINUX/veth_netmap.h
index 19488e4d6..a34686423 100644
--- a/LINUX/veth_netmap.h
+++ b/LINUX/veth_netmap.h
@@ -47,6 +47,7 @@ struct netmap_veth_adapter {
 static struct netmap_adapter *
 veth_get_peer_na(struct netmap_adapter *na)
 {
+	struct netmap_adapter *ona;
 	struct ifnet *ifp = na->ifp;
 	struct veth_priv *priv = netdev_priv(ifp);
 	struct ifnet *peer_ifp;
@@ -63,9 +64,14 @@ veth_get_peer_na(struct netmap_adapter *na)
 		/* Cross link the peer netmap adapters. Note that we
 		 * can retrieve the peer to do our clean-up even if
 		 * the peer_ifp is detached from us. */
-		vna->peer = (struct netmap_veth_adapter *)NA(peer_ifp);
+		ona = NA(peer_ifp);
+		vna->peer = (struct netmap_veth_adapter *)ona;
 		vna->peer->peer = vna;
 
+		/* Both endpoints must have identical ring configurations */
+		ona->num_rx_rings = na->num_tx_rings;
+		ona->num_tx_rings = na->num_rx_rings;
+
 		/* Get a reference to the other endpoint. */
 		netmap_adapter_get(&vna->peer->up.up);
 		vna->peer_ref = 1;
@@ -223,6 +229,18 @@ veth_netmap_krings_delete(struct netmap_adapter *na)
 	vna->peer = NULL;
 }
 
+static int
+veth_netmap_config(struct netmap_adapter *na, struct nm_config_info *info)
+{
+	/* To maintain identical ring configurations,
+	 * only one of the two endpoint should be configured. */
+	if (((struct netmap_veth_adapter *)na)->peer != NULL) {
+		return EBUSY;
+	}
+
+	return nm_os_config(na, info);
+}
+
 static void
 veth_netmap_attach(struct ifnet *ifp)
 {
@@ -240,6 +258,7 @@ veth_netmap_attach(struct ifnet *ifp)
 	na.nm_krings_create = veth_netmap_krings_create;
 	na.nm_krings_delete = veth_netmap_krings_delete;
 	na.nm_dtor = veth_netmap_dtor;
+	na.nm_config = veth_netmap_config;
 	na.num_tx_rings = na.num_rx_rings = 1;
 	netmap_attach_ext(&na, sizeof(struct netmap_veth_adapter),
 			0 /* do not override reg */);
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index a9735c320..7bab5e2bb 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1783,6 +1783,8 @@ netmap_reload_map(struct netmap_adapter *na,
 
 #else /* linux */
 
+int nm_os_config(struct netmap_adapter *na, struct nm_config_info *info);
+
 int nm_iommu_group_id(bus_dma_tag_t dev);
 #include 
 

From fbbff69a04572a3954b9563132963e2dca0bf6a7 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 29 Jul 2025 10:43:37 +0200
Subject: [PATCH 2180/2207] linux/build: use ccflags-y instead of EXTRA_CFLAGS

---
 LINUX/configure     | 8 ++++----
 LINUX/netmap.mak.in | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 7444f7f73..3d4dff12f 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -481,7 +481,7 @@ EOF
 else
 
 all:
-	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(EXTRA_CFLAGS)" $kopts
+	\$(MAKE) -C $ksrc M=\$\$PWD ccflags-y="\$(EXTRA_CFLAGS)" $kopts
 endif
 EOF
 	} > "$TMPDIR"/Makefile
@@ -547,10 +547,10 @@ TOBUILD := \$(filter-out \$(C_DRIVERS),\$(S_DRIVERS))
 all: \$(S_DRIVERS:%=get-%) \$(TOBUILD:%=build-%) \$(TOBUILD:%=tests-%) \$(I_DRIVERS:%=patch-%) tests
 
 tests:
-	+\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts NETMAP_ALL=m
+	+\$(MAKE) -C $ksrc M=\$\$PWD ccflags-y="\$(WARN_CFLAGS)" $kopts NETMAP_ALL=m
 
 test__%:
-	\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts NETMAP_ALL=m \$@.o
+	\$(MAKE) -C $ksrc M=\$\$PWD ccflags-y="\$(WARN_CFLAGS)" $kopts NETMAP_ALL=m \$@.o
 
 -include $BUILDDIR/extdrv-versions.mak
 -include $BUILDDIR/default-config.mak
@@ -573,7 +573,7 @@ patch-$d: get-$d
 	\$(foreach p,\$($d@patch),patch --quiet --force -p1 < \$(p);)
 	touch patch-$d
 tests-$d: build-$d
-	+\$(MAKE) -C $ksrc M=\$\$PWD EXTRA_CFLAGS="\$(WARN_CFLAGS)" $kopts NETMAP_ALL=n NETMAP_$d=m
+	+\$(MAKE) -C $ksrc M=\$\$PWD ccflags-y="\$(WARN_CFLAGS)" $kopts NETMAP_ALL=n NETMAP_$d=m
 EOF
 	done
 	echo endif >> "$TMPDIR"/Makefile
diff --git a/LINUX/netmap.mak.in b/LINUX/netmap.mak.in
index 99f0e4472..136927074 100644
--- a/LINUX/netmap.mak.in
+++ b/LINUX/netmap.mak.in
@@ -46,7 +46,7 @@ DRIVERS = $(shell [ -n "$(S_DRIVERS)" ] && ls -dAp $(S_DRIVERS) 2> /dev/null)
 # external drivers after copy and patch
 DRIVERS_EXT = $(shell [ -n "$(E_DRIVERS)" ] && ls -dAp $(E_DRIVERS) 2> /dev/null)
 
-COMMON_OPTS=-C $(KSRC) M=$(BUILDDIR) EXTRA_CFLAGS='$(EXTRA_CFLAGS)' $(KOPTS) modules
+COMMON_OPTS=-C $(KSRC) M=$(BUILDDIR) ccflags-y='$(EXTRA_CFLAGS)' $(KOPTS) modules
 
 define common_driver
 get-$(1):

From a4dcd00b17d48d05711c0ae081ca3761f5d3f2b4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 29 Jul 2025 10:44:20 +0200
Subject: [PATCH 2181/2207] linux/build: more precise test for HRTIMER_MODE_REL

---
 LINUX/configure | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 3d4dff12f..bee96c638 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1445,10 +1445,7 @@ EOF
   add_test 'have HRTIMER_MODE_REL' <
 
-	void dummy(struct hrtimer *timer, clockid_t which_clock)
-	{
-	        hrtimer_init(timer, which_clock, HRTIMER_MODE_REL);
-	}
+	int dummy = HRTIMER_MODE_REL;
 EOF
 
   # check for IFF_LIVE_ADDR_CHANGE

From bc3a1263c3e1776458f5ec0255051e31e58feda9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 29 Jul 2025 11:00:18 +0200
Subject: [PATCH 2182/2207] linux/build: check for hrtimer_setup

---
 LINUX/bsd_glue.h     |  9 +++++++++
 LINUX/configure      | 12 ++++++++++++
 LINUX/netmap_linux.c |  4 ++--
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index a689a2f1e..9c42bdcbb 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -78,6 +78,15 @@
 #define HRTIMER_MODE_REL	HRTIMER_REL
 #endif
 
+#ifdef NETMAP_LINUX_HAVE_HRTIMER_SETUP
+#define nm_hrtimer_setup	hrtimer_setup
+#else
+#define nm_hrtimer_setup(t_, f_, c_, m_) do {	\
+	hrtimer_init(t_, c_, m_);		\
+	(t_)->function = (c_);			\
+} while (0)
+#endif
+
 #ifndef NETMAP_LINUX_HAVE_SKB_COPY_LINEAR
 #define skb_copy_from_linear_data_offset(skb, offset, to, copy)	\
 	memcpy(to, (skb)->data + offset, copy)
diff --git a/LINUX/configure b/LINUX/configure
index bee96c638..344278ce7 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2008,6 +2008,18 @@ EOF
 	}
 EOF
 
+  # check for hrtimer_setup
+  add_test 'have HRTIMER_SETUP' <
+
+	void dummy(struct hrtimer *timer,
+		enum hrtimer_restart (*function)(struct hrtimer *),
+		clockid_t clock_id, enum hrtimer_mode mode)
+	{
+		hrtimer_setup(timer, function, clock_id, mode);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index a4be082e2..7c844fc96 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -510,8 +510,8 @@ void
 nm_os_mitigation_init(struct nm_generic_mit *mit, int idx,
 			struct netmap_adapter *na)
 {
-	hrtimer_init(&mit->mit_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	mit->mit_timer.function = &generic_timer_handler;
+	nm_hrtimer_setup(&mit->mit_timer, &generic_timer_handler,
+			CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	mit->mit_pending = 0;
 	mit->mit_ring_idx = idx;
 	mit->mit_na = na;

From c249ac6bb43f0a118173c227161a9abd3c3d41d6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 30 Jul 2025 08:02:12 +0200
Subject: [PATCH 2183/2207] linux/drivers: patches for 6.16

---
 ...00--99999 => vanilla--ixgbe--50c00--61000} |   0
 .../vanilla--ixgbe--61000--99999              | 118 ++++++++++++++++++
 ...99 => vanilla--virtio_net.c--60c00--60f00} |   0
 3 files changed, 118 insertions(+)
 rename LINUX/final-patches/{vanilla--ixgbe--50c00--99999 => vanilla--ixgbe--50c00--61000} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--61000--99999
 rename LINUX/final-patches/{vanilla--virtio_net.c--60c00--99999 => vanilla--virtio_net.c--60c00--60f00} (100%)

diff --git a/LINUX/final-patches/vanilla--ixgbe--50c00--99999 b/LINUX/final-patches/vanilla--ixgbe--50c00--61000
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbe--50c00--99999
rename to LINUX/final-patches/vanilla--ixgbe--50c00--61000
diff --git a/LINUX/final-patches/vanilla--ixgbe--61000--99999 b/LINUX/final-patches/vanilla--ixgbe--61000--99999
new file mode 100644
index 000000000..6a0791e04
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--61000--99999
@@ -0,0 +1,118 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index cba860f0e1f1..3d5eefdb7ad5 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -475,6 +475,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1178,6 +1194,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2343,6 +2370,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	struct xdp_buff xdp;
+ 	int xdp_res = 0;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ixgbe_rx_frame_truesize(rx_ring, 0);
+@@ -3803,6 +3840,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4412,6 +4453,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ 	else
+@@ -6077,6 +6122,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -11829,6 +11877,11 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	ixgbe_devlink_init_regions(adapter);
+ 	devl_register(adapter->devlink);
+ 	devl_unlock(adapter->devlink);
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_netdev:
+@@ -11883,6 +11936,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	devl_lock(adapter->devlink);
+ 	devl_unregister(adapter->devlink);
+ 	ixgbe_devlink_destroy_regions(adapter);
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--60c00--99999 b/LINUX/final-patches/vanilla--virtio_net.c--60c00--60f00
similarity index 100%
rename from LINUX/final-patches/vanilla--virtio_net.c--60c00--99999
rename to LINUX/final-patches/vanilla--virtio_net.c--60c00--60f00

From 4822769483029a7b81cef0219e8837b069e6998e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 31 Jul 2025 17:43:51 +0200
Subject: [PATCH 2184/2207] linux: patches for latest Intel drivers

---
 LINUX/final-patches/intel--i40e--2.28.9   | 170 +++++++++++++
 LINUX/final-patches/intel--ice--2.2.9     | 286 ++++++++++++++++++++++
 LINUX/final-patches/intel--igb--5.19.4    | 138 +++++++++++
 LINUX/final-patches/intel--ixgbe--6.1.6   | 168 +++++++++++++
 LINUX/final-patches/intel--ixgbevf--5.1.5 | 168 +++++++++++++
 5 files changed, 930 insertions(+)
 create mode 100644 LINUX/final-patches/intel--i40e--2.28.9
 create mode 100644 LINUX/final-patches/intel--ice--2.2.9
 create mode 100644 LINUX/final-patches/intel--igb--5.19.4
 create mode 100644 LINUX/final-patches/intel--ixgbe--6.1.6
 create mode 100644 LINUX/final-patches/intel--ixgbevf--5.1.5

diff --git a/LINUX/final-patches/intel--i40e--2.28.9 b/LINUX/final-patches/intel--i40e--2.28.9
new file mode 100644
index 000000000..4d8e4d04e
--- /dev/null
+++ b/LINUX/final-patches/intel--i40e--2.28.9
@@ -0,0 +1,170 @@
+diff --git a/i40e/Makefile b/src/Makefile
+index fc5830b..1cee489 100644
+--- a/i40e/Makefile
++++ b/i40e/Makefile
+@@ -10,8 +10,8 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += i40e.o
+-i40e-y := i40e_main.o \
++obj-m += i40e$(NETMAP_DRIVER_SUFFIX).o
++i40e$(NETMAP_DRIVER_SUFFIX)-y := i40e_main.o \
+ 	i40e_ethtool.o \
+ 	i40e_xsk.o \
+ 	i40e_adminq.o \
+@@ -27,9 +27,9 @@ i40e-y := i40e_main.o \
+ 	i40e_ddp.o \
+ 	i40e_client.o \
+ 	i40e_virtchnl_pf.o
+-i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
+-i40e-y += kcompat.o
+-i40e-y += kcompat_vfd.o
++i40e$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
++i40e$(NETMAP_DRIVER_SUFFIX)-y += kcompat_vfd.o
+ ifeq (${NEED_AUX_BUS},2)
+ intel_auxiliary-objs := auxiliary.o
+ obj-m += intel_auxiliary.o
+@@ -38,7 +38,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := i40e
++DRIVER := i40e$(NETMAP_DRIVER_SUFFIX)
+ # If the user just wants to print the help output, don't include common.mk or
+ # perform any other checks. This ensures that running "make help" will always
+ # work even if kernel-devel is not installed, or if the common.mk fails under
+@@ -88,8 +88,10 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report)
+ 
+ # Build manfiles
+-manfile:
++manfile: ../${DRIVER}.${MANSECTION}
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++../${DRIVER}.${MANSECTION}:
++	touch $@
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/i40e/i40e_main.c b/src/i40e_main.c
+index ed85099..8d7bc02 100644
+--- a/i40e/i40e_main.c
++++ b/i40e/i40e_main.c
+@@ -163,6 +163,11 @@ bool i40e_is_l4mode_enabled(void)
+ 	return l4mode > L4_MODE_DISABLED;
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_I40E_MAIN
++#include 
++#endif
++
+ /**
+  * i40e_allocate_dma_mem - OS specific memory alloc for shared code
+  * @hw:   pointer to the HW structure
+@@ -4280,6 +4285,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+ 	/* cache tail off for easier writes later */
+ 	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+@@ -4407,6 +4416,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
+ 
++#ifdef DEV_NETMAP
++	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* clear the context in the HMC */
+ 	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+ 	if (err) {
+@@ -4435,6 +4448,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+ 	writel(0, ring->tail);
+ 
++#ifdef DEV_NETMAP
++	if (i40e_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ #ifdef HAVE_MEM_TYPE_XSK_BUFF_POOL
+ #ifdef HAVE_NETDEV_BPF_XSK_POOL
+@@ -16081,6 +16099,12 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+ 	}
+ 
+ 	set_bit(__I40E_VSI_RELEASING, vsi->state);
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		netmap_detach(vsi->netdev);
++#endif
++
+ 	uplink_seid = vsi->uplink_seid;
+ 	if (vsi->type != I40E_VSI_SRIOV) {
+ 		if (vsi->netdev_registered) {
+@@ -16477,6 +16501,12 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+ 	    (vsi->type == I40E_VSI_VMDQ2)) {
+ 		ret = i40e_vsi_config_rss(vsi);
+ 	}
++
++#ifdef DEV_NETMAP
++	if (vsi->netdev_registered)
++		i40e_netmap_attach(vsi);
++#endif
++
+ 	return vsi;
+ 
+ err_rings:
+diff --git a/i40e/i40e_txrx.c b/src/i40e_txrx.c
+index 9434135..57425a5 100644
+--- a/i40e/i40e_txrx.c
++++ b/i40e/i40e_txrx.c
+@@ -10,6 +10,10 @@
+ #include "i40e_xsk.h"
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
+ 
++#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
++#include 
++#endif /* DEV_NETMAP */
++
+ #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+ /**
+  * i40e_fdir - Generate a Flow Director descriptor based on fdata
+@@ -986,6 +990,11 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	unsigned int budget = vsi->work_limit;
+ 
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buf = &tx_ring->tx_bi[i];
+ 	tx_desc = I40E_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2952,7 +2961,17 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	struct xdp_buff xdp;
+ 	u16 tpid;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return (nm_irq == NM_IRQ_COMPLETED) ? 1 : budget;
++		}
++	}
++#endif /* DEV_NETMAP */
+ #ifdef HAVE_XDP_BUFF_FRAME_SZ
++
+ #if (PAGE_SIZE < 8192)
+ 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
+ #endif
diff --git a/LINUX/final-patches/intel--ice--2.2.9 b/LINUX/final-patches/intel--ice--2.2.9
new file mode 100644
index 000000000..33d261f37
--- /dev/null
+++ b/LINUX/final-patches/intel--ice--2.2.9
@@ -0,0 +1,286 @@
+diff --git a/ice/Makefile b/src/Makefile
+index 4b73d8c..9456cdd 100644
+--- a/ice/Makefile
++++ b/ice/Makefile
+@@ -41,9 +41,9 @@ ifneq ($(KERNELRELEASE),)
+ ccflags-y += -I$(src)
+ subdir-ccflags-y += -I$(src)
+ 
+-obj-m += ice.o
++obj-m += ice$(NETMAP_DRIVER_SUFFIX).o
+ 
+-ice-y := ice_main.o	\
++ice$(NETMAP_DRIVER_SUFFIX)-y := ice_main.o	\
+ 	ice_adapter.o	\
+ 	 ice_controlq.o	\
+ 	 ice_common.o	\
+@@ -88,14 +88,14 @@ ice-y := ice_main.o	\
+ 	 ice_ieps_lm.o		\
+ 	 ice_gnss.o		\
+ 	 ice_ethtool.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/health.o ice_fw_update.o
+-ice-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
+-ice-y += ice_aux_support.o
+-ice-y += ice_idc.o
+-ice-$(CONFIG_DEBUG_FS) += ice_debugfs.o
+-ice-$(CONFIG_DEBUG_FS) += ice_fwlog.o
+-
+-ice-$(CONFIG_PCI_IOV) +=		\
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_devlink.o devlink/health.o ice_fw_update.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_NET_DEVLINK:m=y) += ice_eswitch.o ice_repr.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_aux_support.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += ice_idc.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_debugfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DEBUG_FS) += ice_fwlog.o
++
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_IOV) +=		\
+ 	ice_dcf.o			\
+ 	ice_sriov.o			\
+ 	ice_vf_mbx.o			\
+@@ -107,36 +107,36 @@ ice-$(CONFIG_PCI_IOV) +=		\
+ 	ice_virtchnl_fsub.o		\
+ 	ice_vf_lib.o
+ 
+-ice-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_MDEV:m=y) += ice_vdcm.o ice_siov.o
+ 
+ ifneq (${CONFIG_DPLL},)
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
+ else
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_ptp.o ice_ptp_hw.o
+ endif
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
+-ice-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_tspll.o
+-ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
+-ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
+-ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
+-ice-y += kcompat.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_cpi.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ice_tspll.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_RFS_ACCEL) += ice_arfs.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ice-y += kcompat_pldmfw.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+ # Use kcompat DIMLIB if kernel doesn't provide it
+ ifndef CONFIG_DIMLIB
+-ice-y += kcompat_dim.o kcompat_net_dim.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_dim.o kcompat_net_dim.o
+ endif
+ # Use kcompat GNSS if kernel doesn't provide it
+ ifneq (${CONFIG_GNSS}, y)
+ ifneq (${CONFIG_GNSS}, m)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ endif
+ 
+ ifeq (${CONFIG_SUSE_KERNEL}, y)
+-ice-y += kcompat_gnss.o
++ice$(NETMAP_DRIVER_SUFFIX)-y += kcompat_gnss.o
+ endif
+ 
+ ifeq ($(shell grep HAVE_XARRAY_API $(src)/kcompat_generated_defs.h),)
+@@ -146,8 +146,8 @@ endif
+ ifneq ($(shell grep HAVE_LMV1_SUPPORT $(src)/kcompat_generated_defs.h),)
+ obj-$(CONFIG_VFIO_PCI_CORE:y=m) += ice-vfio-pci.o
+ 
+-ice-vfio-pci-y := ice_vfio_pci.o
+-ice-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
++ice$(NETMAP_DRIVER_SUFFIX)-vfio-pci-y := ice_vfio_pci.o
++ice$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_VFIO_PCI_CORE:m=y) += ice_migration.o
+ endif
+ 
+ 
+@@ -159,7 +159,7 @@ endif
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ice
++DRIVER := ice$(NETMAP_DRIVER_SUFFIX)
+ 
+ # ice does not support building on kernels older than 3.10.0
+ $(call minimum_kver_check,3,10,0)
+@@ -178,7 +178,7 @@ endif
+ 
+ all:
+ 	+$(call kernelbuild,modules)
+-	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++	##@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ ifneq ($(wildcard lttng),)
+ 	$(MAKE) -C lttng
+ endif
+@@ -223,7 +223,7 @@ ifneq (${DDP_PKG_ORIGIN},)
+ endif
+ 
+ mandocs_install: all
+-	install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
++	##install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}/${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+ 
+ # After installing all the files, perform necessary work to ensure the system
+ # will use the new modules. This includes running depmod to update module
+diff --git a/ice/ice_base.c b/src/ice_base.c
+index 240113e..3aaf525 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -9,6 +9,11 @@
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+  * @qs_cfg: gathered variables needed for PF->VSI queues assignment
+@@ -572,6 +577,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -730,6 +739,11 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ #endif /* HAVE_AF_XDP_ZC_SUPPORT */
++    
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
+ 
+ 	ice_alloc_rx_bufs(ring, num_bufs);
+ 
+@@ -1009,6 +1023,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	txq = &qg_buf->txqs[0];
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
++    
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
+ 
+ 	if (tstamp_ring) {
+ 		u8 txtime_buf_len = struct_size(txtime_qg_buf, txtimeqs, 1);
+diff --git a/ice/ice_main.c b/src/ice_main.c
+index 3534b0a..ce039f0 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -69,6 +69,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXX
+ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ #endif /* !CONFIG_DYNAMIC_DEBUG */
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -7042,8 +7047,7 @@ static int ice_init_devlink(struct ice_pf *pf)
+ 	if (need_register)
+ 		ice_devlink_register(pf);
+ #endif /* !HAVE_DEVLINK_PARAMS_PUBLISH */
+-	ice_health_init(pf);
+-#endif  /* CONFIG_NET_DEVLINK */
++
+ 	return 0;
+ }
+ 
+@@ -7340,6 +7344,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+ 	err = ice_init_features(pf);
+ 	if (err)
+ 		goto err_init_features;
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_features:
+@@ -7435,6 +7444,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	if (!pf)
+ 		return;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(ICE_SHUTTING_DOWN, pf->state);
+ 	/* ICE_PREPPED_RECOVERY_MODE is set when the up and running
+ 	 * driver transitions to recovery mode. If this is not set
+diff --git a/ice/ice_txrx.c b/src/ice_txrx.c
+index 2e1afb5..4f5df19 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -32,6 +32,10 @@
+ #define FDIR_DESC_RXDID 0x40
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -258,6 +262,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++    if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++        return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ #ifdef HAVE_XDP_SUPPORT
+@@ -476,6 +484,16 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
+ 	u32 size;
+ 	u16 i;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ 	/* ring already cleared, nothing to do */
+ 	if (!rx_ring->rx_buf)
+ 		return;
+@@ -1720,6 +1738,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ #endif
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++    if (rx_ring->netdev) {
++        int dummy, nm_irq;
++        nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++        if (nm_irq != NM_IRQ_PASS) {
++            return 1;
++        }
++    }
++#endif /* DEV_NETMAP */
++
+ #ifndef CONFIG_ICE_USE_SKB
+ #ifdef HAVE_XDP_SUPPORT
+ #ifdef HAVE_XDP_BUFF_RXQ
diff --git a/LINUX/final-patches/intel--igb--5.19.4 b/LINUX/final-patches/intel--igb--5.19.4
new file mode 100644
index 000000000..f03a5cee8
--- /dev/null
+++ b/LINUX/final-patches/intel--igb--5.19.4
@@ -0,0 +1,138 @@
+diff --git a/igb/Makefile b/src/Makefile
+index f09ad2a..6a2d070 100644
+--- a/igb/Makefile
++++ b/igb/Makefile
+@@ -7,9 +7,9 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) Gigabit Ethernet Linux Driver
+ #
+ 
+-obj-$(CONFIG_IGB) += igb.o
++obj-$(CONFIG_IGB) += igb$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define igb-y
++define igb$(NETMAP_DRIVER_SUFFIX)-y
+ 	igb_main.o
+ 	e1000_api.o
+ 	igb_ethtool.o
+@@ -26,19 +26,19 @@ define igb-y
+ 	e1000_i210.o
+ 	e1000_base.o
+ endef
+-igb-y := $(strip ${igb-y})
++igb$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${igb$(NETMAP_DRIVER_SUFFIX)-y})
+ 
+-igb-${CONFIG_DEBUG_FS} += igb_debugfs.o
++igb$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += igb_debugfs.o
+ 
+-igb-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
++igb$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += igb_ptp.o
+ 
+ 
+-igb-y += kcompat.o
++igb$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := igb
++DRIVER := igb$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -107,9 +107,12 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	@touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/igb/igb_main.c b/src/igb_main.c
+index 13469f3..aa59b2f 100644
+--- a/igb/igb_main.c
++++ b/igb/igb_main.c
+@@ -252,6 +252,10 @@ static struct pci_error_handlers igb_err_handler = {
+ static void igb_init_fw(struct igb_adapter *adapter);
+ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ static struct pci_driver igb_driver = {
+ 	.name     = igb_driver_name,
+ 	.id_table = igb_pci_tbl,
+@@ -3187,6 +3191,10 @@ static int igb_probe(struct pci_dev *pdev,
+ 	/* carrier off reporting is important to ethtool even BEFORE open */
+ 	netif_carrier_off(netdev);
+ 
++#ifdef DEV_NETMAP
++	igb_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef IGB_DCA
+ 	if (dca_add_requester(&pdev->dev) == E1000_SUCCESS) {
+ 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
+@@ -3393,6 +3401,10 @@ static void igb_remove(struct pci_dev *pdev)
+ 	 */
+ 	igb_release_hw_control(adapter);
+ 
++#ifdef DEV_NETMAP
++	netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	unregister_netdev(netdev);
+ 
+ 	igb_clear_interrupt_scheme(adapter);
+@@ -3809,6 +3821,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+ 
+ 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+ 	E1000_WRITE_REG(hw, E1000_TXDCTL(reg_idx), txdctl);
++#ifdef DEV_NETMAP
++	igb_netmap_configure_tx_ring(adapter, reg_idx);
++#endif /* DEV_NETMAP */
+ }
+ 
+ /**
+@@ -7384,6 +7399,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+ 	if (test_bit(__IGB_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
++                return true; /* cleaned ok */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IGB_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -8400,6 +8420,11 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
+ 	unsigned int total_bytes = 0, total_packets = 0;
+ 	u16 cleaned_count = igb_desc_unused(rx_ring);
+ 
++#ifdef DEV_NETMAP
++	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	do {
+ 		struct igb_rx_buffer *rx_buffer;
+ 		union e1000_adv_rx_desc *rx_desc;
+@@ -8719,6 +8744,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+ 	struct igb_rx_buffer *bi;
+ 	u16 i = rx_ring->next_to_use;
+ 
++#ifdef DEV_NETMAP
++	if (igb_netmap_configure_rx_ring(rx_ring))
++		return;
++#endif /* DEV_NETMAP */
++
+ 	/* nothing to do */
+ 	if (!cleaned_count)
+ 		return;
diff --git a/LINUX/final-patches/intel--ixgbe--6.1.6 b/LINUX/final-patches/intel--ixgbe--6.1.6
new file mode 100644
index 000000000..5027ce4f7
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbe--6.1.6
@@ -0,0 +1,168 @@
+diff --git a/ixgbe/Makefile b/src/Makefile
+index 057b034..5b9092c 100644
+--- a/ixgbe/Makefile
++++ b/ixgbe/Makefile
+@@ -7,8 +7,8 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Linux Network Driver
+ #
+ 
+-obj-$(CONFIG_IXGBE) += ixgbe.o
+-define ixgbe-y
++obj-$(CONFIG_IXGBE) += ixgbe$(NETMAP_DRIVER_SUFFIX).o
++define ixgbe$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbe_main.o
+ 	ixgbe_api.o
+ 	ixgbe_common.o
+@@ -31,19 +31,19 @@ define ixgbe-y
+ 	ixgbe_devlink.o
+ 	ixgbe_fw_update.o
+ endef
+-ixgbe-y := $(strip ${ixgbe-y})
+-
+-ixgbe-${CONFIG_DCB} += ixgbe_dcb_nl.o
+-ixgbe-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
+-ixgbe-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
+-ixgbe-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp_e600.o
+-ixgbe-${CONFIG_SYSFS} += ixgbe_sysfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbe$(NETMAP_DRIVER_SUFFIX)-y})
++
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DCB} += ixgbe_dcb_nl.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_DEBUG_FS} += ixgbe_debugfs.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_FCOE:m=y} += ixgbe_fcoe.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PTP_1588_CLOCK:m=y) += ixgbe_ptp_e600.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-${CONFIG_SYSFS} += ixgbe_sysfs.o
+ # Use kcompat pldmfw.c if kernel does not provide CONFIG_PLDMFW
+ ifndef CONFIG_PLDMFW
+-ixgbe-y += kcompat_pldmfw.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat_pldmfw.o
+ endif
+-ixgbe-y += kcompat.o
++ixgbe$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+@@ -116,8 +116,10 @@ ccc: clean
+ 	@+$(call devkernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
++../$(DRIVER).$(MANSECTION):
++	touch $@
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call devkernelbuild,clean)
+diff --git a/ixgbe/ixgbe_main.c b/src/ixgbe_main.c
+index e41b4a8..2fa2a6e 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -805,6 +805,23 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
+ 	}
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
++
+ /**
+  * ixgbe_reset_pf_report - reset pf and print reset report
+  * @tx_ring: tx ring number
+@@ -980,6 +997,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2497,6 +2525,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	unsigned int xdp_xmit = 0;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -4587,6 +4625,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -5280,6 +5322,12 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_AF_XDP_ZC_SUPPORT
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+@@ -15170,6 +15218,11 @@ no_info_string:
+ 		ixgbe_ptp_init_e600(adapter);
+ 
+ #endif /* HAVE_PTP_1588_CLOCK && LINKVILLE_HW */
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_devlink_register:
+@@ -15259,6 +15312,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		ixgbe_pf_fwlog_deinit(adapter);
+ 
+ 	netdev = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ #ifdef HAVE_IXGBE_DEBUG_FS
+ 	ixgbe_dbg_adapter_exit(adapter);
+ 
diff --git a/LINUX/final-patches/intel--ixgbevf--5.1.5 b/LINUX/final-patches/intel--ixgbevf--5.1.5
new file mode 100644
index 000000000..63495755c
--- /dev/null
+++ b/LINUX/final-patches/intel--ixgbevf--5.1.5
@@ -0,0 +1,168 @@
+diff --git a/ixgbevf/Makefile b/src/Makefile
+index 117871c..02290b5 100644
+--- a/ixgbevf/Makefile
++++ b/ixgbevf/Makefile
+@@ -7,22 +7,22 @@ ifneq ($(KERNELRELEASE),)
+ # Makefile for the Intel(R) 10GbE PCI Express Virtual Function Driver
+ #
+ 
+-obj-$(CONFIG_IXGBEVF) += ixgbevf.o
++obj-$(CONFIG_IXGBEVF) += ixgbevf$(NETMAP_DRIVER_SUFFIX).o
+ 
+-define ixgbevf-y
++define ixgbevf$(NETMAP_DRIVER_SUFFIX)-y
+ 	ixgbevf_main.o
+ 	ixgbevf_ethtool.o
+ 	ixgbe_vf.o
+ 	ixgbe_mbx.o
+ endef
+-ixgbevf-y := $(strip ${ixgbevf-y})
+-ixgbevf-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
+-ixgbevf-y += kcompat.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y := $(strip ${ixgbevf$(NETMAP_DRIVER_SUFFIX)-y})
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-${CONFIG_PCI_HYPERV:m=y} += ixgbe_hv_vf.o
++ixgbevf$(NETMAP_DRIVER_SUFFIX)-y += kcompat.o
+ 
+ else	# ifneq($(KERNELRELEASE),)
+ # normal makefile
+ 
+-DRIVER := ixgbevf
++DRIVER := ixgbevf$(NETMAP_DRIVER_SUFFIX)
+ 
+ ifeq (,$(wildcard common.mk))
+   $(error Cannot find common.mk build rules)
+@@ -81,9 +81,12 @@ ccc: clean
+ 	@+$(call kernelbuild,modules,coccicheck MODE=report))
+ 
+ # Build manfiles
+-manfile:
++manfile: ../$(DRIVER).$(MANSECTION)
+ 	@gzip -c ../${DRIVER}.${MANSECTION} > ${DRIVER}.${MANSECTION}.gz
+ 
++../$(DRIVER).$(MANSECTION):
++	touch $@
++
+ # Clean the module subdirectories
+ clean:
+ 	@+$(call kernelbuild,clean)
+diff --git a/ixgbevf/ixgbevf_main.c b/src/ixgbevf_main.c
+index e9d31d5..c7ec472 100644
+--- a/ixgbevf/ixgbevf_main.c
++++ b/ixgbevf/ixgbevf_main.c
+@@ -352,6 +352,23 @@ static void ixgbevf_tx_timeout(struct net_device *netdev)
+ 	ixgbevf_tx_timeout_reset(adapter);
+ }
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#define NM_IXGBEVF
++#include 
++#endif
+ 
+ /**
+  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+@@ -372,6 +389,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
+ 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -1390,6 +1418,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+ 	bool xdp_xmit = false;
+ 	struct xdp_buff xdp;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	xdp.data = NULL;
+ 	xdp.data_end = NULL;
+ #ifdef HAVE_XDP_BUFF_RXQ
+@@ -2108,6 +2146,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
+ 	clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+ 	clear_bit(__IXGBEVF_TX_XDP_RING_PRIMED, &ring->state);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
+ 
+ 	/* poll to verify queue is enabled */
+@@ -2342,6 +2384,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbevf_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
+ }
+ 
+@@ -5661,8 +5707,10 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+         if (netdev->features & NETIF_F_GRO)
+                 DPRINTK(PROBE, INFO, "GRO is enabled\n");
+ #endif
+-
+ 	DPRINTK(PROBE, INFO, "%s\n", ixgbevf_driver_string);
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
+ 	return 0;
+ 
+ err_register:
+@@ -5703,6 +5751,10 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+ 
+ 	adapter = netdev_priv(netdev);
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
+ 	cancel_work_sync(&adapter->service_task);
+ 
+diff --git a/ixgbevf/kcompat.h b/src/kcompat.h
+index 8d5e4fd..8a8399c 100644
+--- a/ixgbevf/kcompat.h
++++ b/ixgbevf/kcompat.h
+@@ -12,6 +12,8 @@
+ 
+ #include "kcompat_gcc.h"
+ 
++#include 
++
+ #ifndef HAVE_XARRAY_API
+ #include "kcompat_xarray.h"
+ #endif /* !HAVE_XARRAY_API */

From 88440dc2a59b45419998cfb37c6461fdd43bedf0 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 2 Sep 2025 16:27:14 +0200
Subject: [PATCH 2185/2207] linux: fix regression introduced by bc3a1263c3

---
 LINUX/bsd_glue.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/bsd_glue.h b/LINUX/bsd_glue.h
index 9c42bdcbb..5aefb98b5 100644
--- a/LINUX/bsd_glue.h
+++ b/LINUX/bsd_glue.h
@@ -83,7 +83,7 @@
 #else
 #define nm_hrtimer_setup(t_, f_, c_, m_) do {	\
 	hrtimer_init(t_, c_, m_);		\
-	(t_)->function = (c_);			\
+	(t_)->function = (f_);			\
 } while (0)
 #endif
 

From aedfef01f5e9768b987428696d701d475209c96e Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 2 Dec 2025 12:14:02 +0100
Subject: [PATCH 2186/2207] linux/drivers: patches for 6.18

---
 ...0b00--99999 => vanilla--ice--60b00--61100} |   0
 .../final-patches/vanilla--ice--61100--61200  | 133 +++++++++++++++++
 .../final-patches/vanilla--ice--61200--99999  | 134 ++++++++++++++++++
 ...00--99999 => vanilla--ixgbe--61000--61200} |   0
 .../vanilla--ixgbe--61200--99999              | 117 +++++++++++++++
 5 files changed, 384 insertions(+)
 rename LINUX/final-patches/{vanilla--ice--60b00--99999 => vanilla--ice--60b00--61100} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ice--61100--61200
 create mode 100644 LINUX/final-patches/vanilla--ice--61200--99999
 rename LINUX/final-patches/{vanilla--ixgbe--61000--99999 => vanilla--ixgbe--61000--61200} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ixgbe--61200--99999

diff --git a/LINUX/final-patches/vanilla--ice--60b00--99999 b/LINUX/final-patches/vanilla--ice--60b00--61100
similarity index 100%
rename from LINUX/final-patches/vanilla--ice--60b00--99999
rename to LINUX/final-patches/vanilla--ice--60b00--61100
diff --git a/LINUX/final-patches/vanilla--ice--61100--61200 b/LINUX/final-patches/vanilla--ice--61100--61200
new file mode 100644
index 000000000..ab74a7897
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--61100--61200
@@ -0,0 +1,133 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index c5da8e9cc0a0..149ede8c074a 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -462,6 +467,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -623,6 +632,11 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->vsi->type == ICE_VSI_CTRL)
+ 		ice_init_ctrl_rx_descs(ring, num_bufs);
+ 	else
+@@ -947,6 +961,10 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 	if (pf_q == le16_to_cpu(txq->txq_id))
+ 		ring->txq_teid = le32_to_cpu(txq->q_teid);
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ }
+ 
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 77781277aa8e..fb0a37d71402 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -53,6 +53,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5106,6 +5111,12 @@ static int ice_init(struct ice_pf *pf)
+ 	/* since everything is good, start the service timer */
+ 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ 
++	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_link:
+@@ -5452,6 +5463,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 41e7e29879a3..5cde03b399df 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -22,6 +22,10 @@
+ 
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -221,6 +225,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -1261,6 +1269,16 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	u32 xdp_xmit = 0;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+ 	if (xdp_prog) {
+ 		xdp_ring = rx_ring->xdp_ring;
diff --git a/LINUX/final-patches/vanilla--ice--61200--99999 b/LINUX/final-patches/vanilla--ice--61200--99999
new file mode 100644
index 000000000..70ee51b6c
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--61200--99999
@@ -0,0 +1,134 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index 2d35a278c555..73ad54aa5ce7 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -6,6 +6,11 @@
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -566,6 +571,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -727,6 +736,11 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->vsi->type == ICE_VSI_CTRL)
+ 		ice_init_ctrl_rx_descs(ring, num_bufs);
+ 	else
+@@ -1109,6 +1123,11 @@ ice_vsi_cfg_txq(const struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 			goto err_cfg_tstamp;
+ 		}
+ 	}
++
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_cfg_tstamp:
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index 86f5859e88ef..b48951ac689a 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -54,6 +54,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5083,6 +5088,12 @@ static int ice_init(struct ice_pf *pf)
+ 	/* since everything is good, start the service timer */
+ 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ 
++	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_link:
+@@ -5429,6 +5440,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index 73f08d02f9c7..962c7d103257 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -22,6 +22,10 @@
+ 
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -274,6 +278,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -1391,6 +1399,16 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	u32 xdp_xmit = 0;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+ 	if (xdp_prog) {
+ 		xdp_ring = rx_ring->xdp_ring;
diff --git a/LINUX/final-patches/vanilla--ixgbe--61000--99999 b/LINUX/final-patches/vanilla--ixgbe--61000--61200
similarity index 100%
rename from LINUX/final-patches/vanilla--ixgbe--61000--99999
rename to LINUX/final-patches/vanilla--ixgbe--61000--61200
diff --git a/LINUX/final-patches/vanilla--ixgbe--61200--99999 b/LINUX/final-patches/vanilla--ixgbe--61200--99999
new file mode 100644
index 000000000..b3b68768e
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ixgbe--61200--99999
@@ -0,0 +1,117 @@
+diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
+index 3190ce7e44c7..e5d7fe1e1b86 100644
+--- a/ixgbe/ixgbe_main.c
++++ b/ixgbe/ixgbe_main.c
+@@ -477,6 +477,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
++ * be a reference on how to implement netmap support in a driver.
++ * Additional comments are in ixgbe_netmap_linux.h .
++ *
++ * The code is originally developed on FreeBSD and in the interest
++ * of maintainability we try to limit differences between the two systems.
++ *
++ *  contains functions for netmap support
++ * that extend the standard driver.
++ * It also defines DEV_NETMAP so further conditional sections use
++ * that instead of CONFIG_NETMAP
++ */
++#include 
++#endif
+ 
+ /*
+  * ixgbe_regdump - register printout routine
+@@ -1360,6 +1376,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return true;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * In netmap mode, all the work is done in the context
++	 * of the client thread. Interrupt handlers only wake up
++	 * clients, which may be sleeping on individual rings
++	 * or on a global resource for all rings.
++	 */
++	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
++		return 1; /* seems to be ignored */
++#endif /* DEV_NETMAP */
++
+ 	tx_buffer = &tx_ring->tx_buffer_info[i];
+ 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
+ 	i -= tx_ring->count;
+@@ -2509,6 +2536,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+ 	struct xdp_buff xdp;
+ 	int xdp_res = 0;
+ 
++#ifdef DEV_NETMAP
++	/*
++	 * 	 Same as the txeof routine: only wakeup clients on intr.
++	 */
++	int dummy, nm_irq;
++	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif /* DEV_NETMAP */
++
+ 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
+ #if (PAGE_SIZE < 8192)
+ 	frame_sz = ixgbe_rx_frame_truesize(rx_ring, 0);
+@@ -3973,6 +4010,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+ 	memset(ring->tx_buffer_info, 0,
+ 	       sizeof(struct ixgbe_tx_buffer) * ring->count);
+ 
++#ifdef DEV_NETMAP
++	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
++#endif /* DEV_NETMAP */
++
+ 	/* enable queue */
+ 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
+ 
+@@ -4589,6 +4630,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+ 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+ 
+ 	ixgbe_rx_desc_queue_enable(adapter, ring);
++#ifdef DEV_NETMAP
++	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
++		return;
++#endif /* DEV_NETMAP */
+ 	if (ring->xsk_pool)
+ 		ixgbe_alloc_rx_buffers_zc(ring, ixgbe_desc_unused(ring));
+ 	else
+@@ -6254,6 +6299,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+ 			e_crit(drv, "Fan has stopped, replace the adapter\n");
+ 	}
+ 
++	/* enable transmits */
++	netif_tx_start_all_queues(adapter->netdev);
++
+ 	/* bring the link up in the watchdog, this could race with our first
+ 	 * link up interrupt but shouldn't be a problem */
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+@@ -12008,6 +12056,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (ixgbe_fwlog_init(hw))
+ 		e_dev_info("Firmware logging not supported\n");
+ 
++#ifdef DEV_NETMAP
++	ixgbe_netmap_attach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_netdev:
+@@ -12062,6 +12114,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+ 		return;
+ 
+ 	netdev  = adapter->netdev;
++
++#ifdef DEV_NETMAP
++	ixgbe_netmap_detach(adapter);
++#endif /* DEV_NETMAP */
++
+ 	devl_lock(adapter->devlink);
+ 	devl_unregister(adapter->devlink);
+ 	ixgbe_devlink_destroy_regions(adapter);

From 77ada22d5b61c9c72ad0f4c09d722dea447519dc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 29 Jan 2026 18:22:52 +0100
Subject: [PATCH 2187/2207] linux/intel: improve compatibility with Debian

Debian puts most kernel files in /lib/modules/$(uname -r)/source
rather then .../build. For this reason, the Intel build system
fails when using the build link. Test for the existence of the
source link and use that in preference.
---
 LINUX/configure              | 1 +
 LINUX/default-config.mak.in_ | 7 ++++---
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/LINUX/configure b/LINUX/configure
index 344278ce7..8b047694e 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -786,6 +786,7 @@ fi
 	# user did not provide the path for the full kernel sources
 	# we try to find one by ourselves
 	[ -d "$ksrc/source" ] && src="$ksrc/source"
+	[ -d "/lib/modules/${kernelver}/source" ] && src="/lib/modules/${kernelver}/source"
 	[ -n "$src" ] || src=$ksrc
 }
 
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index 1eaa976f9..e457207bc 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -44,6 +44,7 @@
 # SRCDIR	absolute path of the netmap/LINUX directory
 # KSRC		source directory of the linux kernel (headers should be sufficient
 # 		for external drivers)
+# SRC		source directory of the full kernel sources
 # KOPTS		options intended for the linux make (accumulated via the
 # 		--kernel-opts= configure option
 # DRVSUFFIX	the netmap driver suffix (--driver-suffix= configure option)
@@ -62,9 +63,9 @@ define intel_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/$(1)/v$(2).zip || wget https://github.com/intel/ethernet-linux-$(1)/archive/refs/tags/v$(2).zip -P @SRCDIR@/ext-drivers/$(1)
 $(1)@src 	:= unzip -u @SRCDIR@/ext-drivers/$(1)/v$(2).zip && ln -s ethernet-linux-$(1)-$(2)/src $(1)
 $(1)@patch 	:= patches/intel--$(1)--$(2)
-$(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
-$(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
-$(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@KSRC@; fi
+$(1)@build 	 = make -C $(1) CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" @KOPTS@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@SRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
+$(1)@install 	 = make -C $(1) install INSTALL_MOD_PATH=@MODPATH@ CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@SRC@ KBUILD_EXTRA_SYMBOLS=@BUILDDIR@/Module.symvers
+$(1)@clean 	 = if [ -d $(1) ]; then make -C $(1) clean CFLAGS_EXTRA="$$($(1)@cflags) $(EXTRA_CFLAGS)" NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ KSRC=@SRC@; fi
 $(1)@distclean	:= rm -rf ethernet-linux-$(1)-$(2)
 $(1)@force	:= 1
 endef

From 3c7a7e55cb02ea1384b39a067341e11f42f0e0fe Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 10 Feb 2026 09:30:35 +0100
Subject: [PATCH 2188/2207] linux/drivers: patches for 6.19

---
 ...20--99999 => vanilla--e1000--31200--99999} |  60 ++++----
 .../vanilla--e1000e--20620--30100             |  91 ------------
 .../vanilla--e1000e--30100--30400             |  91 ------------
 .../vanilla--e1000e--30400--30900             |  91 ------------
 ...0--99999 => vanilla--e1000e--31200--99999} |  22 +--
 ...999 => vanilla--forcedeth.c--31200--99999} |  18 +--
 ...c00--40100 => vanilla--i40e--31200--40100} |  36 ++---
 ...1200--60300 => vanilla--ice--51300--60300} |  14 +-
 ...1200--99999 => vanilla--ice--61200--61300} |   0
 .../final-patches/vanilla--ice--61300--99999  | 134 ++++++++++++++++++
 .../final-patches/vanilla--igb--20621--20623  |  82 -----------
 .../final-patches/vanilla--igb--20623--30200  |  82 -----------
 .../final-patches/vanilla--igb--30200--30800  | 103 --------------
 .../final-patches/vanilla--igb--30800--30f00  |  81 -----------
 ...0f00--40100 => vanilla--igb--31200--40100} |  20 +--
 .../vanilla--ixgbe--20620--20622              | 121 ----------------
 .../vanilla--ixgbe--20622--20623              | 125 ----------------
 .../vanilla--ixgbe--20623--20625              | 116 ---------------
 .../vanilla--ixgbe--20625--20626              | 107 --------------
 .../vanilla--ixgbe--20626--30100              | 107 --------------
 .../vanilla--ixgbe--30100--30200              | 108 --------------
 .../vanilla--ixgbe--30200--30400              | 106 --------------
 .../vanilla--ixgbe--30400--30500              | 115 ---------------
 .../vanilla--ixgbe--30500--30700              | 114 ---------------
 .../vanilla--ixgbe--30700--30a00              | 114 ---------------
 .../vanilla--ixgbe--30a00--30d00              | 114 ---------------
 .../vanilla--ixgbe--30d00--30f00              | 131 -----------------
 ...00--31300 => vanilla--ixgbe--31200--31300} |  24 ++--
 .../vanilla--ixgbevf--20622--30500            | 120 ----------------
 .../vanilla--ixgbevf--30500--30600            | 117 ---------------
 .../vanilla--ixgbevf--30600--30700            | 118 ---------------
 .../vanilla--ixgbevf--30700--30d00            | 118 ---------------
 .../vanilla--ixgbevf--30d00--30e00            | 118 ---------------
 .../vanilla--ixgbevf--30e00--30f00            | 111 ---------------
 .../vanilla--ixgbevf--30f00--31200            | 110 --------------
 .../vanilla--veth.c--20620--30900             |  35 -----
 .../vanilla--veth.c--30900--30f00             |  33 -----
 ...0--41300 => vanilla--veth.c--31200--41300} |   2 +-
 .../vanilla--virtio_net.c--20622--20625       |  80 -----------
 .../vanilla--virtio_net.c--20625--20626       |  80 -----------
 .../vanilla--virtio_net.c--20626--30300       |  80 -----------
 .../vanilla--virtio_net.c--30300--30500       |  82 -----------
 .../vanilla--virtio_net.c--30500--30800       |  82 -----------
 .../vanilla--virtio_net.c--30800--30a00       |  85 -----------
 .../vanilla--virtio_net.c--30a00--30b00       |  85 -----------
 .../vanilla--virtio_net.c--30b00--31100       |  85 -----------
 ...00 => vanilla--virtio_net.c--31200--31300} |  16 +--
 ...--40d00 => vanilla--vmxnet3--31200--40d00} |   8 +-
 LINUX/scripts/np                              |   2 +-
 49 files changed, 245 insertions(+), 3649 deletions(-)
 rename LINUX/final-patches/{vanilla--e1000--20620--99999 => vanilla--e1000--31200--99999} (56%)
 delete mode 100644 LINUX/final-patches/vanilla--e1000e--20620--30100
 delete mode 100644 LINUX/final-patches/vanilla--e1000e--30100--30400
 delete mode 100644 LINUX/final-patches/vanilla--e1000e--30400--30900
 rename LINUX/final-patches/{vanilla--e1000e--30900--99999 => vanilla--e1000e--31200--99999} (79%)
 rename LINUX/final-patches/{vanilla--forcedeth.c--20626--99999 => vanilla--forcedeth.c--31200--99999} (70%)
 rename LINUX/final-patches/{vanilla--i40e--30c00--40100 => vanilla--i40e--31200--40100} (74%)
 rename LINUX/final-patches/{vanilla--ice--51200--60300 => vanilla--ice--51300--60300} (90%)
 rename LINUX/final-patches/{vanilla--ice--61200--99999 => vanilla--ice--61200--61300} (100%)
 create mode 100644 LINUX/final-patches/vanilla--ice--61300--99999
 delete mode 100644 LINUX/final-patches/vanilla--igb--20621--20623
 delete mode 100644 LINUX/final-patches/vanilla--igb--20623--30200
 delete mode 100644 LINUX/final-patches/vanilla--igb--30200--30800
 delete mode 100644 LINUX/final-patches/vanilla--igb--30800--30f00
 rename LINUX/final-patches/{vanilla--igb--30f00--40100 => vanilla--igb--31200--40100} (78%)
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--20620--20622
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--20622--20623
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--20623--20625
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--20625--20626
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--20626--30100
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30100--30200
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30200--30400
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30400--30500
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30500--30700
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30700--30a00
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30a00--30d00
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--30d00--30f00
 rename LINUX/final-patches/{vanilla--ixgbe--30f00--31300 => vanilla--ixgbe--31200--31300} (83%)
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--20622--30500
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30500--30600
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30600--30700
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30700--30d00
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--30f00--31200
 delete mode 100644 LINUX/final-patches/vanilla--veth.c--20620--30900
 delete mode 100644 LINUX/final-patches/vanilla--veth.c--30900--30f00
 rename LINUX/final-patches/{vanilla--veth.c--30f00--41300 => vanilla--veth.c--31200--41300} (94%)
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--20622--20625
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--20625--20626
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--20626--30300
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--30300--30500
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--30500--30800
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--30800--30a00
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
 rename LINUX/final-patches/{vanilla--virtio_net.c--31100--31300 => vanilla--virtio_net.c--31200--31300} (81%)
 rename LINUX/final-patches/{vanilla--vmxnet3--31000--40d00 => vanilla--vmxnet3--31200--40d00} (90%)

diff --git a/LINUX/final-patches/vanilla--e1000--20620--99999 b/LINUX/final-patches/vanilla--e1000--31200--99999
similarity index 56%
rename from LINUX/final-patches/vanilla--e1000--20620--99999
rename to LINUX/final-patches/vanilla--e1000--31200--99999
index b6d431c66..19287e5e6 100644
--- a/LINUX/final-patches/vanilla--e1000--20620--99999
+++ b/LINUX/final-patches/vanilla--e1000--31200--99999
@@ -1,8 +1,8 @@
 diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index bcd192ca47b0..1e1a6b61ece4 100644
+index 24f3986cfae2..3f6227bb5107 100644
 --- a/e1000/e1000_main.c
 +++ b/e1000/e1000_main.c
-@@ -190,6 +190,10 @@ static struct pci_error_handlers e1000_err_handler = {
+@@ -200,6 +200,10 @@ static const struct pci_error_handlers e1000_err_handler = {
  	.resume = e1000_io_resume,
  };
  
@@ -13,7 +13,7 @@ index bcd192ca47b0..1e1a6b61ece4 100644
  static struct pci_driver e1000_driver = {
  	.name     = e1000_driver_name,
  	.id_table = e1000_pci_tbl,
-@@ -375,6 +379,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -395,6 +399,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  	e1000_configure_tx(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -23,19 +23,19 @@ index bcd192ca47b0..1e1a6b61ece4 100644
 +#endif /* DEV_NETMAP */
  	/* call E1000_DESC_UNUSED which always leaves
  	 * at least 1 descriptor unused to make sure
- 	 * next_to_use != next_to_clean */
-@@ -1035,6 +1043,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
- 	adapter->wol = adapter->eeprom_wol;
- 	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ 	 * next_to_use != next_to_clean
+@@ -1213,6 +1221,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 
+ 	e1000_vlan_filter_on_off(adapter, false);
  
 +#ifdef DEV_NETMAP
 +	e1000_netmap_attach(adapter);
 +#endif /* DEV_NETMAP */
 +
  	/* print bus type/speed/width info */
- 	DPRINTK(PROBE, INFO, "(PCI%s:%s:%s) ",
- 		((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
-@@ -1113,6 +1125,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
+ 	e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n",
+ 	       ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
+@@ -1277,6 +1289,10 @@ static void e1000_remove(struct pci_dev *pdev)
  
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
@@ -44,11 +44,11 @@ index bcd192ca47b0..1e1a6b61ece4 100644
 +	netmap_detach(netdev);
 +#endif /* DEV_NETMAP */
  
- 	iounmap(hw->hw_addr);
- 	if (hw->flash_address)
-@@ -3429,6 +3445,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
- 	unsigned int count = 0;
+ 	if (hw->mac_type == e1000_ce4100)
+ 		iounmap(hw->ce4100_gbe_mdio_base_virt);
+@@ -3841,6 +3857,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
  	unsigned int total_tx_bytes=0, total_tx_packets=0;
+ 	unsigned int bytes_compl = 0, pkts_compl = 0;
  
 +#ifdef DEV_NETMAP
 +	if (netmap_tx_irq(netdev, 0) != NM_IRQ_PASS)
@@ -57,34 +57,34 @@ index bcd192ca47b0..1e1a6b61ece4 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -3614,6 +3634,15 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+@@ -4135,6 +4155,15 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
  	bool cleaned = false;
  	unsigned int total_rx_bytes=0, total_rx_packets=0;
  
 +#ifdef DEV_NETMAP
-+       int nm_irq = netmap_rx_irq(netdev, 0, work_done);
-+       if (nm_irq != NM_IRQ_PASS) {
-+               if (nm_irq == NM_IRQ_RESCHED) {
-+                       *work_done = work_to_do;
-+               }
-+               return 1;
-+       }
++	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
++	if (nm_irq != NM_IRQ_PASS) {
++		if (nm_irq == NM_IRQ_RESCHED) {
++			*work_done = work_to_do;
++		}
++		return 1;
++	}
 +#endif /* DEV_NETMAP */
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC(*rx_ring, i);
  	buffer_info = &rx_ring->buffer_info[i];
-@@ -3795,6 +3824,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
+@@ -4355,6 +4384,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
  	bool cleaned = false;
  	unsigned int total_rx_bytes=0, total_rx_packets=0;
  
 +#ifdef DEV_NETMAP
-+       int nm_irq = netmap_rx_irq(netdev, 0, work_done);
-+       if (nm_irq != NM_IRQ_PASS) {
-+               if (nm_irq == NM_IRQ_RESCHED) {
-+                       *work_done = work_to_do;
-+               }
-+               return 1;
-+       }
++	int nm_irq = netmap_rx_irq(netdev, 0, work_done);
++	if (nm_irq != NM_IRQ_PASS) {
++		if (nm_irq == NM_IRQ_RESCHED) {
++			*work_done = work_to_do;
++		}
++		return 1;
++	}
 +#endif /* DEV_NETMAP */
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC(*rx_ring, i);
diff --git a/LINUX/final-patches/vanilla--e1000e--20620--30100 b/LINUX/final-patches/vanilla--e1000e--20620--30100
deleted file mode 100644
index 133852ab1..000000000
--- a/LINUX/final-patches/vanilla--e1000e--20620--30100
+++ /dev/null
@@ -1,91 +0,0 @@
-diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index fad8f9ea0043..e109db98e6ea 100644
---- a/e1000e/netdev.c
-+++ b/e1000e/netdev.c
-@@ -87,6 +87,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
- 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /**
-  * e1000_receive_skb - helper function to handle Rx indications
-  * @adapter: board private structure
-@@ -446,6 +450,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, 0, work_done))
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];
-@@ -624,6 +632,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
- 	unsigned int count = 0;
- 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(netdev, 0))
-+		return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -910,6 +922,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes=0, total_rx_packets=0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, 0, work_done))
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];
-@@ -2379,6 +2395,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
- 		adapter->rx_ps_pages = pages;
- 	else
- 		adapter->rx_ps_pages = 0;
-+#ifdef DEV_NETMAP
-+       /* Keep packet-split disabled with netmap. */
-+       adapter->rx_ps_pages = 0;
-+#endif /* DEV_NETMAP */
- 
- 	if (adapter->rx_ps_pages) {
- 		/* Configure extra packet-split registers */
-@@ -2632,6 +2652,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
- 	e1000_configure_tx(adapter);
- 	e1000_setup_rctl(adapter);
- 	e1000_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	if (e1000e_netmap_init_buffers(adapter))
-+		return;
-+#endif /* DEV_NETMAP */
- 	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring));
- }
- 
-@@ -5227,6 +5251,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
- 	if (err)
- 		goto err_register;
- 
-+#ifdef DEV_NETMAP
-+	e1000_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-@@ -5300,6 +5327,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
- 	kfree(adapter->tx_ring);
- 	kfree(adapter->rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 	iounmap(adapter->hw.hw_addr);
- 	if (adapter->hw.flash_address)
- 		iounmap(adapter->hw.flash_address);
diff --git a/LINUX/final-patches/vanilla--e1000e--30100--30400 b/LINUX/final-patches/vanilla--e1000e--30100--30400
deleted file mode 100644
index 22777f7cc..000000000
--- a/LINUX/final-patches/vanilla--e1000e--30100--30400
+++ /dev/null
@@ -1,91 +0,0 @@
-diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 2198e615f241..408d54a7c02f 100644
---- a/e1000e/netdev.c
-+++ b/e1000e/netdev.c
-@@ -452,6 +452,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
- 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /**
-  * e1000_receive_skb - helper function to handle Rx indications
-  * @adapter: board private structure
-@@ -849,6 +853,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, 0, work_done))
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];
-@@ -1066,6 +1074,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
- 	unsigned int count = 0;
- 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(netdev, 0))
-+		return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -1355,6 +1367,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes=0, total_rx_packets=0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, 0, work_done))
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC(*rx_ring, i);
- 	buffer_info = &rx_ring->buffer_info[i];
-@@ -2908,6 +2924,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
- 		adapter->rx_ps_pages = pages;
- 	else
- 		adapter->rx_ps_pages = 0;
-+#ifdef DEV_NETMAP
-+       /* Keep packet-split disabled with netmap. */
-+       adapter->rx_ps_pages = 0;
-+#endif /* DEV_NETMAP */
- 
- 	if (adapter->rx_ps_pages) {
- 		u32 psrctl = 0;
-@@ -3177,6 +3197,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
- 	e1000_configure_tx(adapter);
- 	e1000_setup_rctl(adapter);
- 	e1000_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	if (e1000e_netmap_init_buffers(adapter))
-+		return;
-+#endif /* DEV_NETMAP */
- 	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring),
- 			      GFP_KERNEL);
- }
-@@ -6147,6 +6171,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
- 	if (err)
- 		goto err_register;
- 
-+#ifdef DEV_NETMAP
-+	e1000_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-@@ -6234,6 +6261,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
- 	kfree(adapter->tx_ring);
- 	kfree(adapter->rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 	iounmap(adapter->hw.hw_addr);
- 	if (adapter->hw.flash_address)
- 		iounmap(adapter->hw.flash_address);
diff --git a/LINUX/final-patches/vanilla--e1000e--30400--30900 b/LINUX/final-patches/vanilla--e1000e--30400--30900
deleted file mode 100644
index 977ef0464..000000000
--- a/LINUX/final-patches/vanilla--e1000e--30400--30900
+++ /dev/null
@@ -1,91 +0,0 @@
-diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 9520a6ac1f30..244e75747e16 100644
---- a/e1000e/netdev.c
-+++ b/e1000e/netdev.c
-@@ -467,6 +467,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
- 	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /**
-  * e1000_receive_skb - helper function to handle Rx indications
-  * @adapter: board private structure
-@@ -875,6 +879,10 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, 0, work_done))
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1129,6 +1137,10 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
- 	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
- 	unsigned int bytes_compl = 0, pkts_compl = 0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(netdev, 0))
-+		return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -1433,6 +1445,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes=0, total_rx_packets=0;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, 0, work_done))
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2976,6 +2992,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
- 		adapter->rx_ps_pages = pages;
- 	else
- 		adapter->rx_ps_pages = 0;
-+#ifdef DEV_NETMAP
-+	/* Keep packet-split disabled with netmap. */
-+	adapter->rx_ps_pages = 0;
-+#endif /* DEV_NETMAP */
- 
- 	if (adapter->rx_ps_pages) {
- 		u32 psrctl = 0;
-@@ -3358,6 +3378,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
- 		e1000e_setup_rss_hash(adapter);
- 	e1000_setup_rctl(adapter);
- 	e1000_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	if (e1000e_netmap_init_buffers(adapter))
-+		return;
-+#endif /* DEV_NETMAP */
- 	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
- }
- 
-@@ -6417,6 +6441,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
- 	if (err)
- 		goto err_register;
- 
-+#ifdef DEV_NETMAP
-+	e1000_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-@@ -6504,6 +6531,10 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
- 	kfree(adapter->tx_ring);
- 	kfree(adapter->rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 	iounmap(adapter->hw.hw_addr);
- 	if (adapter->hw.flash_address)
- 		iounmap(adapter->hw.flash_address);
diff --git a/LINUX/final-patches/vanilla--e1000e--30900--99999 b/LINUX/final-patches/vanilla--e1000e--31200--99999
similarity index 79%
rename from LINUX/final-patches/vanilla--e1000e--30900--99999
rename to LINUX/final-patches/vanilla--e1000e--31200--99999
index 2b82b74b1..c62d743c2 100644
--- a/LINUX/final-patches/vanilla--e1000e--30900--99999
+++ b/LINUX/final-patches/vanilla--e1000e--31200--99999
@@ -1,8 +1,8 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 7e615e2bf7e6..9b2b1945c6d2 100644
+index 247335d2c7ec..14045858fc88 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
-@@ -473,6 +473,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
+@@ -493,6 +493,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
  	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
  }
  
@@ -13,7 +13,7 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  /**
   * e1000e_systim_to_hwtstamp - convert system time value to hw time stamp
   * @adapter: board private structure
-@@ -914,6 +918,10 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
+@@ -935,6 +939,10 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
  	bool cleaned = false;
  	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
  
@@ -24,7 +24,7 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1203,6 +1211,10 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
+@@ -1223,6 +1231,10 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
  	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
  	unsigned int bytes_compl = 0, pkts_compl = 0;
  
@@ -35,9 +35,9 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  	i = tx_ring->next_to_clean;
  	eop = tx_ring->buffer_info[i].next_to_watch;
  	eop_desc = E1000_TX_DESC(*tx_ring, eop);
-@@ -1502,6 +1514,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
- 	bool cleaned = false;
- 	unsigned int total_rx_bytes=0, total_rx_packets=0;
+@@ -1524,6 +1536,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
+ 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ 	struct skb_shared_info *shinfo;
  
 +#ifdef DEV_NETMAP
 +	if (netmap_rx_irq(netdev, 0, work_done))
@@ -46,7 +46,7 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  	i = rx_ring->next_to_clean;
  	rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
  	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -3087,6 +3103,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
+@@ -3128,6 +3144,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
  		adapter->rx_ps_pages = pages;
  	else
  		adapter->rx_ps_pages = 0;
@@ -57,7 +57,7 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  
  	if (adapter->rx_ps_pages) {
  		u32 psrctl = 0;
-@@ -3685,6 +3705,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -3736,6 +3756,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  		e1000e_setup_rss_hash(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -68,7 +68,7 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
  }
  
-@@ -6768,6 +6792,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -7022,6 +7046,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	if (err)
  		goto err_register;
  
@@ -78,7 +78,7 @@ index 7e615e2bf7e6..9b2b1945c6d2 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -6866,6 +6893,10 @@ static void e1000_remove(struct pci_dev *pdev)
+@@ -7117,6 +7144,10 @@ static void e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999 b/LINUX/final-patches/vanilla--forcedeth.c--31200--99999
similarity index 70%
rename from LINUX/final-patches/vanilla--forcedeth.c--20626--99999
rename to LINUX/final-patches/vanilla--forcedeth.c--31200--99999
index 4eb888276..51306c1f2 100644
--- a/LINUX/final-patches/vanilla--forcedeth.c--20626--99999
+++ b/LINUX/final-patches/vanilla--forcedeth.c--31200--99999
@@ -1,8 +1,8 @@
 diff --git a/forcedeth.c b/forcedeth.c
-index 9c0b1bac6af6..b081d6ba11a2 100644
+index f39cae620f61..3af3ef806b45 100644
 --- a/forcedeth.c
 +++ b/forcedeth.c
-@@ -1865,12 +1865,25 @@ static void nv_init_tx(struct net_device *dev)
+@@ -1962,12 +1962,25 @@ static void nv_init_tx(struct net_device *dev)
  	}
  }
  
@@ -28,7 +28,7 @@ index 9c0b1bac6af6..b081d6ba11a2 100644
  
  	if (!nv_optimized(np))
  		return nv_alloc_rx(dev);
-@@ -3386,6 +3399,11 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
+@@ -3660,6 +3673,11 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
  	int i;
  	unsigned long flags;
  
@@ -39,8 +39,8 @@ index 9c0b1bac6af6..b081d6ba11a2 100644
 +
  	for (i = 0;; i++) {
  		events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
- 		writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
-@@ -3497,6 +3515,11 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
+ 		writel(events, base + NvRegMSIXIrqStatus);
+@@ -3772,6 +3790,11 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
  	int i;
  	unsigned long flags;
  
@@ -51,8 +51,8 @@ index 9c0b1bac6af6..b081d6ba11a2 100644
 +
  	for (i = 0;; i++) {
  		events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
- 		writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
-@@ -5645,6 +5668,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
+ 		writel(events, base + NvRegMSIXIrqStatus);
+@@ -5988,6 +6011,10 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
  		goto out_error;
  	}
  
@@ -62,8 +62,8 @@ index 9c0b1bac6af6..b081d6ba11a2 100644
 +
  	netif_carrier_off(dev);
  
- 	dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
-@@ -5728,6 +5755,10 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
+ 	/* Some NICs freeze when TX pause is enabled while NIC is
+@@ -6084,6 +6111,10 @@ static void nv_remove(struct pci_dev *pci_dev)
  
  	unregister_netdev(dev);
  
diff --git a/LINUX/final-patches/vanilla--i40e--30c00--40100 b/LINUX/final-patches/vanilla--i40e--31200--40100
similarity index 74%
rename from LINUX/final-patches/vanilla--i40e--30c00--40100
rename to LINUX/final-patches/vanilla--i40e--31200--40100
index 0694fe964..fd1fc6241 100644
--- a/LINUX/final-patches/vanilla--i40e--30c00--40100
+++ b/LINUX/final-patches/vanilla--i40e--31200--40100
@@ -1,8 +1,8 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index 221aa4795017..db5394879249 100644
+index c3a7f4a4b775..2239a55bc221 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
-@@ -86,6 +86,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+@@ -89,6 +89,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
  
@@ -14,7 +14,7 @@ index 221aa4795017..db5394879249 100644
  /**
   * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
   * @hw:   pointer to the HW structure
-@@ -2124,6 +2129,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+@@ -2476,6 +2481,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
  	/* cache tail off for easier writes later */
  	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
  
@@ -25,9 +25,9 @@ index 221aa4795017..db5394879249 100644
  	return 0;
  }
  
-@@ -2185,6 +2194,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
- 	rx_ctx.l2tsel = 1;
- 	rx_ctx.showiv = 1;
+@@ -2541,6 +2550,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+ 	/* set the prefena field to 1 because the manual says to */
+ 	rx_ctx.prefena = 1;
  
 +#ifdef DEV_NETMAP
 +	i40e_netmap_preconfigure_rx_ring(ring, &rx_ctx);
@@ -36,7 +36,7 @@ index 221aa4795017..db5394879249 100644
  	/* clear the context in the HMC */
  	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
  	if (err) {
-@@ -2207,6 +2220,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2563,6 +2576,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -48,7 +48,7 @@ index 221aa4795017..db5394879249 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -5876,6 +5894,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -7833,6 +7851,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -60,7 +60,7 @@ index 221aa4795017..db5394879249 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -6124,6 +6147,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -8150,6 +8173,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  		break;
  	}
  
@@ -73,12 +73,12 @@ index 221aa4795017..db5394879249 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 49d2cfa9b0cc..8511b05e7d07 100644
+index 3195d82e4942..74493427510b 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
-@@ -27,6 +27,10 @@
- 
+@@ -28,6 +28,10 @@
  #include "i40e.h"
+ #include "i40e_prototype.h"
  
 +#if defined(CONFIG_NETMAP) || defined (CONFIG_NETMAP_MODULE)
 +#include 
@@ -87,7 +87,7 @@ index 49d2cfa9b0cc..8511b05e7d07 100644
  static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
  				u32 td_tag)
  {
-@@ -329,6 +333,11 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
+@@ -674,6 +678,11 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
  	unsigned int total_packets = 0;
  	unsigned int total_bytes = 0;
  
@@ -98,10 +98,10 @@ index 49d2cfa9b0cc..8511b05e7d07 100644
 +
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
- 
-@@ -897,6 +906,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
- 	u32 rx_error, rx_status;
- 	u64 qword;
+ 	i -= tx_ring->count;
+@@ -1387,6 +1396,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+ 	if (budget <= 0)
+ 		return 0;
  
 +#ifdef DEV_NETMAP
 +	if (rx_ring->netdev) {
@@ -114,4 +114,4 @@ index 49d2cfa9b0cc..8511b05e7d07 100644
 +
  	rx_desc = I40E_RX_DESC(rx_ring, i);
  	qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- 	rx_status = (qword & I40E_RXD_QW1_STATUS_MASK)
+ 	rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
diff --git a/LINUX/final-patches/vanilla--ice--51200--60300 b/LINUX/final-patches/vanilla--ice--51300--60300
similarity index 90%
rename from LINUX/final-patches/vanilla--ice--51200--60300
rename to LINUX/final-patches/vanilla--ice--51300--60300
index eaadf55ba..cbbcc9dc9 100644
--- a/LINUX/final-patches/vanilla--ice--51200--60300
+++ b/LINUX/final-patches/vanilla--ice--51300--60300
@@ -49,7 +49,7 @@ index 136d7911adb4..a9caf17a5160 100644
  }
  
 diff --git a/ice/ice_main.c b/ice/ice_main.c
-index 963a5f40e071..49e1adb1e4da 100644
+index 9f02b60459f1..0186182d5e16 100644
 --- a/ice/ice_main.c
 +++ b/ice/ice_main.c
 @@ -48,6 +48,11 @@ static DEFINE_IDA(ice_aux_ida);
@@ -64,7 +64,7 @@ index 963a5f40e071..49e1adb1e4da 100644
  /**
   * ice_hw_to_dev - Get device pointer from the hardware structure
   * @hw: pointer to the device HW structure
-@@ -4854,6 +4859,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
+@@ -4872,6 +4877,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
  	}
  
  	ice_devlink_register(pf);
@@ -75,7 +75,7 @@ index 963a5f40e071..49e1adb1e4da 100644
  	return 0;
  
  err_init_aux_unroll:
-@@ -4954,6 +4963,10 @@ static void ice_remove(struct pci_dev *pdev)
+@@ -4972,6 +4981,10 @@ static void ice_remove(struct pci_dev *pdev)
  	struct ice_pf *pf = pci_get_drvdata(pdev);
  	int i;
  
@@ -87,10 +87,10 @@ index 963a5f40e071..49e1adb1e4da 100644
  	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
  		if (!ice_is_reset_in_progress(pf->state))
 diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
-index f9bf008471c9..59b8d5769068 100644
+index 836dce840712..b5a272c8cfe4 100644
 --- a/ice/ice_txrx.c
 +++ b/ice/ice_txrx.c
-@@ -22,6 +22,10 @@
+@@ -23,6 +23,10 @@
  #define FDIR_DESC_RXDID 0x40
  #define ICE_FDIR_CLEAN_DELAY 10
  
@@ -101,7 +101,7 @@ index f9bf008471c9..59b8d5769068 100644
  /**
   * ice_prgm_fdir_fltr - Program a Flow Director filter
   * @vsi: VSI to send dummy packet
-@@ -221,6 +225,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+@@ -222,6 +226,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
  	s16 i = tx_ring->next_to_clean;
  	struct ice_tx_desc *tx_desc;
  	struct ice_tx_buf *tx_buf;
@@ -112,7 +112,7 @@ index f9bf008471c9..59b8d5769068 100644
  
  	/* get the bql data ready */
  	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
-@@ -1116,6 +1124,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+@@ -1117,6 +1125,16 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
  	struct xdp_buff xdp;
  	bool failure;
  
diff --git a/LINUX/final-patches/vanilla--ice--61200--99999 b/LINUX/final-patches/vanilla--ice--61200--61300
similarity index 100%
rename from LINUX/final-patches/vanilla--ice--61200--99999
rename to LINUX/final-patches/vanilla--ice--61200--61300
diff --git a/LINUX/final-patches/vanilla--ice--61300--99999 b/LINUX/final-patches/vanilla--ice--61300--99999
new file mode 100644
index 000000000..9e2a572ed
--- /dev/null
+++ b/LINUX/final-patches/vanilla--ice--61300--99999
@@ -0,0 +1,134 @@
+diff --git a/ice/ice_base.c b/ice/ice_base.c
+index eadb1e3d12b3..bed56a61e5ce 100644
+--- a/ice/ice_base.c
++++ b/ice/ice_base.c
+@@ -7,6 +7,11 @@
+ #include "ice_lib.h"
+ #include "ice_dcb_lib.h"
+ #include "ice_sriov.h"
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_BASE
++#include 
++#endif
++
+ 
+ /**
+  * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI
+@@ -575,6 +580,10 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
+ 		rxdid = ICE_RXDID_FLEX_NIC_2;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_preconfigure_rx_ring(ring, &rlan_ctx);
++#endif /* DEV_NETMAP */
++
+ 	/* Enable Flexible Descriptors in the queue context which
+ 	 * allows this driver to select a specific receive descriptor format
+ 	 * increasing context priority to pick up profile ID; default is 0x01;
+@@ -745,6 +754,11 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
+ 		return 0;
+ 	}
+ 
++#ifdef DEV_NETMAP
++	if (ice_netmap_configure_rx_ring(ring))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	if (ring->vsi->type == ICE_VSI_CTRL)
+ 		ice_init_ctrl_rx_descs(ring, num_bufs);
+ 	else
+@@ -1127,6 +1141,11 @@ ice_vsi_cfg_txq(const struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ 			goto err_cfg_tstamp;
+ 		}
+ 	}
++
++#ifdef DEV_NETMAP
++	ice_netmap_configure_tx_ring(ring);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_cfg_tstamp:
+diff --git a/ice/ice_main.c b/ice/ice_main.c
+index d04605d3e61a..f2398e0119bc 100644
+--- a/ice/ice_main.c
++++ b/ice/ice_main.c
+@@ -56,6 +56,11 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+ DEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
+ EXPORT_SYMBOL(ice_xdp_locking_key);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#define NETMAP_ICE_LIB
++#include 
++#endif
++
+ /**
+  * ice_hw_to_dev - Get device pointer from the hardware structure
+  * @hw: pointer to the device HW structure
+@@ -5066,6 +5071,12 @@ static int ice_init(struct ice_pf *pf)
+ 	/* since everything is good, start the service timer */
+ 	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ 
++	ice_devlink_register(pf);
++
++#ifdef DEV_NETMAP
++	ice_netmap_attach(pf);
++#endif
++
+ 	return 0;
+ 
+ err_init_link:
+@@ -5421,6 +5432,10 @@ static void ice_remove(struct pci_dev *pdev)
+ 	struct ice_pf *pf = pci_get_drvdata(pdev);
+ 	int i;
+ 
++#ifdef DEV_NETMAP
++	ice_netmap_detach(pf);
++#endif /* DEV_NETMAP */
++
+ 	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
+ 		if (!ice_is_reset_in_progress(pf->state))
+ 			break;
+diff --git a/ice/ice_txrx.c b/ice/ice_txrx.c
+index ad76768a4232..65baa7edc636 100644
+--- a/ice/ice_txrx.c
++++ b/ice/ice_txrx.c
+@@ -24,6 +24,10 @@
+ 
+ #define ICE_FDIR_CLEAN_DELAY 10
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++#include 
++#endif
++
+ /**
+  * ice_prgm_fdir_fltr - Program a Flow Director filter
+  * @vsi: VSI to send dummy packet
+@@ -276,6 +280,10 @@ static bool ice_clean_tx_irq(struct ice_tx_ring *tx_ring, int napi_budget)
+ 	s16 i = tx_ring->next_to_clean;
+ 	struct ice_tx_desc *tx_desc;
+ 	struct ice_tx_buf *tx_buf;
++#ifdef DEV_NETMAP
++	if (tx_ring->netdev && netmap_tx_irq(tx_ring->netdev, tx_ring->q_index) != NM_IRQ_PASS)
++		return true;
++#endif /* DEV_NETMAP */
+ 
+ 	/* get the bql data ready */
+ 	netdev_txq_bql_complete_prefetchw(txring_txq(tx_ring));
+@@ -953,6 +961,16 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
+ 	u32 xdp_xmit = 0;
+ 	bool failure;
+ 
++#ifdef DEV_NETMAP
++	if (rx_ring->netdev) {
++		int dummy, nm_irq;
++		nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->q_index, &dummy);
++		if (nm_irq != NM_IRQ_PASS) {
++			return 1;
++		}
++	}
++#endif /* DEV_NETMAP */
++
+ 	libeth_xdp_init_buff(xdp, &rx_ring->xdp, &rx_ring->xdp_rxq);
+ 
+ 	xdp_prog = READ_ONCE(rx_ring->xdp_prog);
diff --git a/LINUX/final-patches/vanilla--igb--20621--20623 b/LINUX/final-patches/vanilla--igb--20621--20623
deleted file mode 100644
index 22476d6f2..000000000
--- a/LINUX/final-patches/vanilla--igb--20621--20623
+++ /dev/null
@@ -1,82 +0,0 @@
-diff --git a/igb/igb_main.c b/igb/igb_main.c
-index c881347cb26d..a2af3799f5a8 100644
---- a/igb/igb_main.c
-+++ b/igb/igb_main.c
-@@ -226,6 +226,10 @@ char *igb_get_hw_dev_name(struct e1000_hw *hw)
- 	return adapter->netdev->name;
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /**
-  * igb_get_time_str - format current NIC and system time as string
-  */
-@@ -1614,6 +1618,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-+#ifdef DEV_NETMAP
-+	igb_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- #ifdef CONFIG_IGB_DCA
- 	if (dca_add_requester(&pdev->dev) == 0) {
- 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -1699,6 +1707,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
- 		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
- 	}
- #endif
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 
- 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
- 	 * would have already happened in close and is redundant. */
-@@ -2196,6 +2208,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
- 
- 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
- 	wr32(E1000_TXDCTL(reg_idx), txdctl);
-+#ifdef DEV_NETMAP
-+	igb_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
- 
- /**
-@@ -4905,6 +4920,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
- 	unsigned int i, eop, count = 0;
- 	bool cleaned = false;
- 
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(netdev, tx_ring->queue_index))
-+                return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
-@@ -5109,6 +5129,11 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
- 	u16 length;
- 	u16 vlan_tag;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, rx_ring->queue_index, work_done))
-+		return 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	buffer_info = &rx_ring->buffer_info[i];
- 	rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
-@@ -5236,6 +5261,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
- 	unsigned int i;
- 	int bufsz;
- 
-+#ifdef DEV_NETMAP
-+	if (igb_netmap_configure_rx_ring(rx_ring))
-+                return;
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_use;
- 	buffer_info = &rx_ring->buffer_info[i];
- 
diff --git a/LINUX/final-patches/vanilla--igb--20623--30200 b/LINUX/final-patches/vanilla--igb--20623--30200
deleted file mode 100644
index a258b2391..000000000
--- a/LINUX/final-patches/vanilla--igb--20623--30200
+++ /dev/null
@@ -1,82 +0,0 @@
-diff --git a/igb/igb_main.c b/igb/igb_main.c
-index cea37e0837ff..81fd28b8cb4e 100644
---- a/igb/igb_main.c
-+++ b/igb/igb_main.c
-@@ -201,6 +201,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
- MODULE_LICENSE("GPL");
- MODULE_VERSION(DRV_VERSION);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct igb_reg_info {
- 	u32 ofs;
- 	char *name;
-@@ -1963,6 +1967,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-+#ifdef DEV_NETMAP
-+	igb_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- #ifdef CONFIG_IGB_DCA
- 	if (dca_add_requester(&pdev->dev) == 0) {
- 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -2072,6 +2080,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
- 		dev_info(&pdev->dev, "IOV Disabled\n");
- 	}
- #endif
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 
- 	iounmap(hw->hw_addr);
- 	if (hw->flash_address)
-@@ -2545,6 +2557,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
- 
- 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
- 	wr32(E1000_TXDCTL(reg_idx), txdctl);
-+#ifdef DEV_NETMAP
-+	igb_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
- 
- /**
-@@ -5338,6 +5353,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
- 	unsigned int i, eop, count = 0;
- 	bool cleaned = false;
- 
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(netdev, tx_ring->queue_index))
-+                return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->buffer_info[i].next_to_watch;
- 	eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
-@@ -5540,6 +5560,11 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
- 	u16 length;
- 	u16 vlan_tag;
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(netdev, rx_ring->queue_index, work_done))
-+		return 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	buffer_info = &rx_ring->buffer_info[i];
- 	rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
-@@ -5668,6 +5693,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
- 	unsigned int i;
- 	int bufsz;
- 
-+#ifdef DEV_NETMAP
-+	if (igb_netmap_configure_rx_ring(rx_ring))
-+                return;
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_use;
- 	buffer_info = &rx_ring->buffer_info[i];
- 
diff --git a/LINUX/final-patches/vanilla--igb--30200--30800 b/LINUX/final-patches/vanilla--igb--30200--30800
deleted file mode 100644
index 9ae06fa01..000000000
--- a/LINUX/final-patches/vanilla--igb--30200--30800
+++ /dev/null
@@ -1,103 +0,0 @@
-diff --git a/igb/igb_main.c b/igb/igb_main.c
-index ced544499f1b..43c2419cd340 100644
---- a/igb/igb_main.c
-+++ b/igb/igb_main.c
-@@ -225,6 +225,10 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
- MODULE_LICENSE("GPL");
- MODULE_VERSION(DRV_VERSION);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct igb_reg_info {
- 	u32 ofs;
- 	char *name;
-@@ -2073,6 +2077,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-+#ifdef DEV_NETMAP
-+	igb_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- #ifdef CONFIG_IGB_DCA
- 	if (dca_add_requester(&pdev->dev) == 0) {
- 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -2199,6 +2207,10 @@ static void __devexit igb_remove(struct pci_dev *pdev)
- 		dev_info(&pdev->dev, "IOV Disabled\n");
- 	}
- #endif
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 
- 	iounmap(hw->hw_addr);
- 	if (hw->flash_address)
-@@ -2711,6 +2723,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
- 
- 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
- 	wr32(E1000_TXDCTL(reg_idx), txdctl);
-+#ifdef DEV_NETMAP
-+	igb_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
- 
- /**
-@@ -3088,6 +3103,19 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
- 	/* Only set Drop Enable if we are supporting multiple queues */
- 	if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
- 		srrctl |= E1000_SRRCTL_DROP_EN;
-+#ifdef DEV_NETMAP
-+	{
-+		/* The driver uses split buffers, which are not
-+		 * supported in native netmap mode */
-+		struct ifnet *ifp = adapter->netdev;
-+		struct netmap_adapter *na = NA(ifp);
-+		if (nm_native_on(na)) {
-+			srrctl &= ~(7 << 25); /* clear descriptor type */
-+			srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
-+			/* XXX we should set tail here */
-+		}
-+	}
-+#endif
- 
- 	wr32(E1000_SRRCTL(reg_idx), srrctl);
- 
-@@ -5705,6 +5733,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
- 
- 	if (test_bit(__IGB_DOWN, &adapter->state))
- 		return true;
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
-+                return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IGB_TX_DESC(tx_ring, i);
-@@ -5980,6 +6012,12 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget)
- 	u16 cleaned_count = igb_desc_unused(rx_ring);
- 	u16 i = rx_ring->next_to_clean;
- 
-+#ifdef DEV_NETMAP
-+	int dummy = 1; // select rx irq handling
-+	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy))
-+		return 1;
-+#endif /* DEV_NETMAP */
-+
- 	rx_desc = IGB_RX_DESC(rx_ring, i);
- 
- 	while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
-@@ -6170,6 +6208,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
- 	struct igb_rx_buffer *bi;
- 	u16 i = rx_ring->next_to_use;
- 
-+#ifdef DEV_NETMAP
-+	if (igb_netmap_configure_rx_ring(rx_ring))
-+                return;
-+#endif /* DEV_NETMAP */
-+
- 	rx_desc = IGB_RX_DESC(rx_ring, i);
- 	bi = &rx_ring->rx_buffer_info[i];
- 	i -= rx_ring->count;
diff --git a/LINUX/final-patches/vanilla--igb--30800--30f00 b/LINUX/final-patches/vanilla--igb--30800--30f00
deleted file mode 100644
index 1eaa64b3c..000000000
--- a/LINUX/final-patches/vanilla--igb--30800--30f00
+++ /dev/null
@@ -1,81 +0,0 @@
-diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 31cfe2ec75df..2776ed444bf4 100644
---- a/igb/igb_main.c
-+++ b/igb/igb_main.c
-@@ -247,6 +247,10 @@ static int debug = -1;
- module_param(debug, int, 0);
- MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct igb_reg_info {
- 	u32 ofs;
- 	char *name;
-@@ -2127,6 +2131,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	/* carrier off reporting is important to ethtool even BEFORE open */
- 	netif_carrier_off(netdev);
- 
-+#ifdef DEV_NETMAP
-+	igb_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- #ifdef CONFIG_IGB_DCA
- 	if (dca_add_requester(&pdev->dev) == 0) {
- 		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -2233,6 +2241,10 @@ static void igb_remove(struct pci_dev *pdev)
- 		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
- 	}
- #endif
-+#ifdef DEV_NETMAP
-+	netmap_detach(netdev);
-+#endif /* DEV_NETMAP */
-+
- 
- 	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
- 	 * would have already happened in close and is redundant. */
-@@ -2746,6 +2758,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
- 
- 	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
- 	wr32(E1000_TXDCTL(reg_idx), txdctl);
-+#ifdef DEV_NETMAP
-+	igb_netmap_configure_tx_ring(adapter, reg_idx);
-+#endif /* DEV_NETMAP */
- }
- 
- /**
-@@ -5690,6 +5705,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
- 
- 	if (test_bit(__IGB_DOWN, &adapter->state))
- 		return true;
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(tx_ring->netdev, tx_ring->queue_index))
-+                return 1; /* cleaned ok */
-+#endif /* DEV_NETMAP */
- 
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IGB_TX_DESC(tx_ring, i);
-@@ -6349,6 +6368,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
- 	unsigned int total_bytes = 0, total_packets = 0;
- 	u16 cleaned_count = igb_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &total_packets))
-+		return true;
-+#endif /* DEV_NETMAP */
- 	do {
- 		union e1000_adv_rx_desc *rx_desc;
- 
-@@ -6461,6 +6484,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
- 	struct igb_rx_buffer *bi;
- 	u16 i = rx_ring->next_to_use;
- 
-+#ifdef DEV_NETMAP
-+	if (igb_netmap_configure_rx_ring(rx_ring))
-+		return;
-+#endif /* DEV_NETMAP */
-+
- 	/* nothing to do */
- 	if (!cleaned_count)
- 		return;
diff --git a/LINUX/final-patches/vanilla--igb--30f00--40100 b/LINUX/final-patches/vanilla--igb--31200--40100
similarity index 78%
rename from LINUX/final-patches/vanilla--igb--30f00--40100
rename to LINUX/final-patches/vanilla--igb--31200--40100
index 81138684a..db5e5531c 100644
--- a/LINUX/final-patches/vanilla--igb--30f00--40100
+++ b/LINUX/final-patches/vanilla--igb--31200--40100
@@ -1,8 +1,8 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 16430a8440fa..c2c462218ec3 100644
+index 487cd9c4ac0d..706d0cbeb75b 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -257,6 +257,10 @@ static int debug = -1;
+@@ -253,6 +253,10 @@ static int debug = -1;
  module_param(debug, int, 0);
  MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
  
@@ -13,15 +13,15 @@ index 16430a8440fa..c2c462218ec3 100644
  struct igb_reg_info {
  	u32 ofs;
  	char *name;
-@@ -1798,7 +1802,6 @@ void igb_down(struct igb_adapter *adapter)
- 		napi_disable(&(adapter->q_vector[i]->napi));
+@@ -1799,7 +1803,6 @@ void igb_down(struct igb_adapter *adapter)
+ 		}
  	}
  
 -
  	del_timer_sync(&adapter->watchdog_timer);
  	del_timer_sync(&adapter->phy_info_timer);
  
-@@ -2540,6 +2543,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -2548,6 +2551,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
@@ -32,7 +32,7 @@ index 16430a8440fa..c2c462218ec3 100644
  #ifdef CONFIG_IGB_DCA
  	if (dca_add_requester(&pdev->dev) == 0) {
  		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -2805,6 +2812,10 @@ static void igb_remove(struct pci_dev *pdev)
+@@ -2813,6 +2820,10 @@ static void igb_remove(struct pci_dev *pdev)
  		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
  	}
  #endif
@@ -43,7 +43,7 @@ index 16430a8440fa..c2c462218ec3 100644
  
  	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
  	 * would have already happened in close and is redundant.
-@@ -3276,6 +3287,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+@@ -3285,6 +3296,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
  
  	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
  	wr32(E1000_TXDCTL(reg_idx), txdctl);
@@ -53,7 +53,7 @@ index 16430a8440fa..c2c462218ec3 100644
  }
  
  /**
-@@ -6321,6 +6335,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+@@ -6354,6 +6368,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
  
  	if (test_bit(__IGB_DOWN, &adapter->state))
  		return true;
@@ -64,7 +64,7 @@ index 16430a8440fa..c2c462218ec3 100644
  
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IGB_TX_DESC(tx_ring, i);
-@@ -6984,6 +7002,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
+@@ -6914,6 +6932,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
  	unsigned int total_bytes = 0, total_packets = 0;
  	u16 cleaned_count = igb_desc_unused(rx_ring);
  
@@ -75,7 +75,7 @@ index 16430a8440fa..c2c462218ec3 100644
  	while (likely(total_packets < budget)) {
  		union e1000_adv_rx_desc *rx_desc;
  
-@@ -7101,6 +7123,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+@@ -7031,6 +7053,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
  	struct igb_rx_buffer *bi;
  	u16 i = rx_ring->next_to_use;
  
diff --git a/LINUX/final-patches/vanilla--ixgbe--20620--20622 b/LINUX/final-patches/vanilla--ixgbe--20620--20622
deleted file mode 100644
index d803909ec..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--20620--20622
+++ /dev/null
@@ -1,121 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index a456578b8578..12c38576bdac 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -337,6 +337,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int i, eop, count = 0;
- 	unsigned int total_bytes = 0, total_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	* In netmap mode, all the work is done in the context
-+	* of the client thread. Interrupt handlers only wake up
-+	* clients, which may be sleeping on individual rings
-+	* or on a global resource for all rings.
-+	*/
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-@@ -778,6 +788,18 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	int ddp_bytes = 0;
- #endif /* IXGBE_FCOE */
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq;
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		*work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
-+		return true;
-+	}
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1008,6 +1030,24 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
- 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
-+
-+
- enum latency_range {
- 	lowest_latency = 0,
- 	low_latency = 1,
-@@ -1044,7 +1084,6 @@ static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter,
- 	if (packets == 0)
- 		goto update_itr_done;
- 
--
- 	/* simple throttlerate management
- 	 *    0-20MB/s lowest (100000 ints/s)
- 	 *   20-100MB/s low   (20000 ints/s)
-@@ -2568,6 +2607,12 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
- 
- 	ixgbe_configure_tx(adapter);
- 	ixgbe_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	for (i = 0; i < adapter->num_rx_queues; i++)
-+		ixgbe_netmap_configure_rx_ring(adapter,
-+			adapter->rx_ring[i].reg_idx);
-+	return;
-+#endif /* DEV_NETMAP */
- 	for (i = 0; i < adapter->num_rx_queues; i++)
- 		ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
- 		                       (adapter->rx_ring[i].count - 1));
-@@ -2751,8 +2796,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 	for (i = 0; i < adapter->num_tx_queues; i++) {
- 		j = adapter->tx_ring[i].reg_idx;
- 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-+#ifdef DEV_NETMAP // XXX i and j are the same ?
-+		txdctl = ixgbe_netmap_configure_tx_ring(adapter, j, txdctl);
-+#endif /* DEV_NETMAP */
- 		txdctl |= IXGBE_TXDCTL_ENABLE;
- 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
-+
-+
- 	}
- 
- 	for (i = 0; i < num_rx_rings; i++) {
-@@ -4290,6 +4340,9 @@ static int ixgbe_open(struct net_device *netdev)
- 		goto err_up;
- 
- 	netif_tx_start_all_queues(netdev);
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
- 
- 	return 0;
- 
-@@ -5893,6 +5946,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	/* clear the module not found bit to make sure the worker won't
- 	 * reschedule
diff --git a/LINUX/final-patches/vanilla--ixgbe--20622--20623 b/LINUX/final-patches/vanilla--ixgbe--20622--20623
deleted file mode 100644
index 721b9d6e0..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--20622--20623
+++ /dev/null
@@ -1,125 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 6c00ee493a3b..36f9ef2f366f 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -400,6 +400,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int i, eop, count = 0;
- 	unsigned int total_bytes = 0, total_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	* In netmap mode, all the work is done in the context
-+	* of the client thread. Interrupt handlers only wake up
-+	* clients, which may be sleeping on individual rings
-+	* or on a global resource for all rings.
-+	*/
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-@@ -845,6 +855,18 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	int ddp_bytes = 0;
- #endif /* IXGBE_FCOE */
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq;
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		*work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
-+		return true;
-+	}
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1103,6 +1125,24 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
- 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
- }
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
-+
-+
- enum latency_range {
- 	lowest_latency = 0,
- 	low_latency = 1,
-@@ -1139,7 +1179,6 @@ static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter,
- 	if (packets == 0)
- 		goto update_itr_done;
- 
--
- 	/* simple throttlerate management
- 	 *    0-20MB/s lowest (100000 ints/s)
- 	 *   20-100MB/s low   (20000 ints/s)
-@@ -2738,6 +2777,12 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
- 
- 	ixgbe_configure_tx(adapter);
- 	ixgbe_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	for (i = 0; i < adapter->num_rx_queues; i++)
-+		ixgbe_netmap_configure_rx_ring(adapter,
-+			adapter->rx_ring[i]->reg_idx);
-+	return;
-+#endif /* DEV_NETMAP */
- 	for (i = 0; i < adapter->num_rx_queues; i++)
- 		ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
- 		                       (adapter->rx_ring[i]->count - 1));
-@@ -2941,6 +2986,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 	for (i = 0; i < adapter->num_tx_queues; i++) {
- 		j = adapter->tx_ring[i]->reg_idx;
- 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-+#ifdef DEV_NETMAP // XXX i and j are the same ?
-+		txdctl = ixgbe_netmap_configure_tx_ring(adapter, j, txdctl);
-+#endif /* DEV_NETMAP */
- 		txdctl |= IXGBE_TXDCTL_ENABLE;
- 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
- 		if (hw->mac.type == ixgbe_mac_82599EB) {
-@@ -2955,6 +3003,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 				DPRINTK(DRV, ERR, "Could not enable "
- 				        "Tx Queue %d\n", j);
- 		}
-+
- 	}
- 
- 	for (i = 0; i < num_rx_rings; i++) {
-@@ -4641,6 +4690,9 @@ static int ixgbe_open(struct net_device *netdev)
- 		goto err_up;
- 
- 	netif_tx_start_all_queues(netdev);
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
- 
- 	return 0;
- 
-@@ -6402,6 +6454,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	/* clear the module not found bit to make sure the worker won't
- 	 * reschedule
diff --git a/LINUX/final-patches/vanilla--ixgbe--20623--20625 b/LINUX/final-patches/vanilla--ixgbe--20623--20625
deleted file mode 100644
index 1e0b7de53..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--20623--20625
+++ /dev/null
@@ -1,116 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 74d9b6df3029..803bc4befaa2 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -741,6 +757,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int i, eop, count = 0;
- 	unsigned int total_bytes = 0, total_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-@@ -1187,6 +1213,17 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	int ddp_bytes = 0;
- #endif /* IXGBE_FCOE */
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq;
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		*work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
-+		return true;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -3159,6 +3196,12 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
- 
- 	ixgbe_configure_tx(adapter);
- 	ixgbe_configure_rx(adapter);
-+#ifdef DEV_NETMAP
-+	for (i = 0; i < adapter->num_rx_queues; i++)
-+		ixgbe_netmap_configure_rx_ring(adapter,
-+			adapter->rx_ring[i]->reg_idx);
-+	return;
-+#endif /* DEV_NETMAP */
- 	for (i = 0; i < adapter->num_rx_queues; i++)
- 		ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
- 		                       (adapter->rx_ring[i]->count - 1));
-@@ -3376,6 +3419,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 	for (i = 0; i < adapter->num_tx_queues; i++) {
- 		j = adapter->tx_ring[i]->reg_idx;
- 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-+#ifdef DEV_NETMAP // XXX i and j are the same ?
-+		txdctl = ixgbe_netmap_configure_tx_ring(adapter, j, txdctl);
-+#endif /* DEV_NETMAP */
- 		txdctl |= IXGBE_TXDCTL_ENABLE;
- 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
- 		if (hw->mac.type == ixgbe_mac_82599EB) {
-@@ -3390,6 +3436,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 				DPRINTK(DRV, ERR, "Could not enable "
- 				        "Tx Queue %d\n", j);
- 		}
-+
- 	}
- 
- 	for (i = 0; i < num_rx_rings; i++) {
-@@ -6833,6 +6880,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 
- 	dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
- 	cards_found++;
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -6873,6 +6925,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	/* clear the module not found bit to make sure the worker won't
- 	 * reschedule
diff --git a/LINUX/final-patches/vanilla--ixgbe--20625--20626 b/LINUX/final-patches/vanilla--ixgbe--20625--20626
deleted file mode 100644
index a1a53d5c5..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--20625--20626
+++ /dev/null
@@ -1,107 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index eee0b298bd36..b7722c97827f 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -214,6 +214,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -740,6 +756,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int i, eop, count = 0;
- 	unsigned int total_bytes = 0, total_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
-@@ -1185,6 +1211,17 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	int ddp_bytes = 0;
- #endif /* IXGBE_FCOE */
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq;
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		*work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
-+		return true;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2503,6 +2540,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 	/* reinitialize flowdirector state */
- 	set_bit(__IXGBE_FDIR_INIT_DONE, &ring->reinit_state);
- 
-+#ifdef DEV_NETMAP 
-+		txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	txdctl |= IXGBE_TXDCTL_ENABLE;
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
-@@ -2833,6 +2874,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(adapter, ring, IXGBE_DESC_UNUSED(ring));
- }
- 
-@@ -7048,6 +7093,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 
- 	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
- 	cards_found++;
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7088,6 +7138,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	/* clear the module not found bit to make sure the worker won't
- 	 * reschedule
diff --git a/LINUX/final-patches/vanilla--ixgbe--20626--30100 b/LINUX/final-patches/vanilla--ixgbe--20626--30100
deleted file mode 100644
index f6004d9fa..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--20626--30100
+++ /dev/null
@@ -1,107 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 30f9ccfb4f87..4f5a19efbc65 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -221,6 +221,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -826,6 +842,16 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int total_bytes = 0, total_packets = 0;
- 	u16 i, eop, count = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
-@@ -1308,6 +1334,17 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	u16 cleaned_count = 0;
- 	bool pkt_is_rsc = false;
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq;
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		*work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
-+		return;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2714,6 +2751,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP 
-+		txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	txdctl |= IXGBE_TXDCTL_ENABLE;
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
-@@ -3094,6 +3135,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, IXGBE_DESC_UNUSED(ring));
- }
- 
-@@ -7450,6 +7495,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 
- 	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
- 	cards_found++;
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7490,6 +7540,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 
- 	/*
diff --git a/LINUX/final-patches/vanilla--ixgbe--30100--30200 b/LINUX/final-patches/vanilla--ixgbe--30100--30200
deleted file mode 100644
index 2ab977802..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30100--30200
+++ /dev/null
@@ -1,108 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e1fcc9589278..8753411450c4 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -249,6 +249,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -801,6 +817,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int total_bytes = 0, total_packets = 0;
- 	u16 i, eop, count = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
-@@ -1303,6 +1330,17 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	u16 cleaned_count = 0;
- 	bool pkt_is_rsc = false;
- 
-+#ifdef DEV_NETMAP
-+	int nm_irq;
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, work_done);
-+	if (nm_irq != NM_IRQ_PASS) {
-+		*work_done = (nm_irq == NM_IRQ_RESCHED) ? work_to_do : 1;
-+		return;
-+	}
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2660,6 +2698,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP 
-+		txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	txdctl |= IXGBE_TXDCTL_ENABLE;
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
-@@ -3039,6 +3081,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -7696,6 +7742,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 
- 	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
- 	cards_found++;
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7732,6 +7783,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	cancel_work_sync(&adapter->service_task);
- 
diff --git a/LINUX/final-patches/vanilla--ixgbe--30200--30400 b/LINUX/final-patches/vanilla--ixgbe--30200--30400
deleted file mode 100644
index c470e60ef..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30200--30400
+++ /dev/null
@@ -1,106 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 8ef92d1a6aa1..65746992e80f 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -188,6 +188,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -745,6 +761,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	unsigned int budget = q_vector->tx.work_limit;
- 	u16 i = tx_ring->next_to_clean;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
- 
-@@ -1253,6 +1280,15 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- 	u16 cleaned_count = 0;
- 	bool pkt_is_rsc = false;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -2405,6 +2441,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -2783,6 +2823,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -7710,6 +7754,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 
- 	e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
- 	cards_found++;
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7746,6 +7795,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	cancel_work_sync(&adapter->service_task);
- 
diff --git a/LINUX/final-patches/vanilla--ixgbe--30400--30500 b/LINUX/final-patches/vanilla--ixgbe--30400--30500
deleted file mode 100644
index 78fa4923f..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30400--30500
+++ /dev/null
@@ -1,115 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 467948e9ecd9..568104f44cae 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -749,6 +765,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -1629,6 +1656,16 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- #endif /* IXGBE_FCOE */
- 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	do {
- 		struct ixgbe_rx_buffer *rx_buffer;
- 		union ixgbe_adv_rx_desc *rx_desc;
-@@ -2668,6 +2705,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -3032,6 +3073,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -4764,6 +4809,7 @@ static int ixgbe_open(struct net_device *netdev)
- 
- 	ixgbe_up_complete(adapter);
- 
-+
- 	return 0;
- 
- err_req_irq:
-@@ -7152,6 +7198,11 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 
- 	e_dev_info("%s\n", ixgbe_default_device_descr);
- 	cards_found++;
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7187,6 +7238,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	cancel_work_sync(&adapter->service_task);
- 
diff --git a/LINUX/final-patches/vanilla--ixgbe--30500--30700 b/LINUX/final-patches/vanilla--ixgbe--30500--30700
deleted file mode 100644
index eb8e67881..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30500--30700
+++ /dev/null
@@ -1,114 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index e242104ab471..6320fd181a90 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -204,6 +204,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -764,6 +780,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -1665,6 +1692,16 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- #endif /* IXGBE_FCOE */
- 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	do {
- 		struct ixgbe_rx_buffer *rx_buffer;
- 		union ixgbe_adv_rx_desc *rx_desc;
-@@ -2710,6 +2747,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -3102,6 +3143,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -4827,6 +4872,7 @@ static int ixgbe_open(struct net_device *netdev)
- 
- 	ixgbe_up_complete(adapter);
- 
-+
- 	return 0;
- 
- err_req_irq:
-@@ -7358,6 +7404,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 		e_err(probe, "failed to allocate sysfs resources\n");
- #endif /* CONFIG_IXGBE_HWMON */
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7393,6 +7443,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBE_DOWN, &adapter->state);
- 	cancel_work_sync(&adapter->service_task);
- 
diff --git a/LINUX/final-patches/vanilla--ixgbe--30700--30a00 b/LINUX/final-patches/vanilla--ixgbe--30700--30a00
deleted file mode 100644
index e4adf9a7d..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30700--30a00
+++ /dev/null
@@ -1,114 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index fa3d552e1f4a..f0f47356e3f7 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -205,6 +205,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -766,6 +782,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -1791,6 +1818,16 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- #endif /* IXGBE_FCOE */
- 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	do {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct sk_buff *skb;
-@@ -2773,6 +2810,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -3157,6 +3198,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -4903,6 +4948,7 @@ static int ixgbe_open(struct net_device *netdev)
- 
- 	ixgbe_up_complete(adapter);
- 
-+
- 	return 0;
- 
- err_set_queues:
-@@ -7464,6 +7510,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
- 	ixgbe_dbg_adapter_init(adapter);
- #endif /* CONFIG_DEBUG_FS */
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7498,6 +7548,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- #ifdef CONFIG_DEBUG_FS
- 	ixgbe_dbg_adapter_exit(adapter);
- #endif /*CONFIG_DEBUG_FS */
diff --git a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00 b/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
deleted file mode 100644
index f5db6e7d4..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30a00--30d00
+++ /dev/null
@@ -1,114 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d30fbdd81fca..a6bcb88e6004 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -248,6 +248,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -872,6 +888,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -1906,6 +1933,16 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- #endif /* IXGBE_FCOE */
- 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	do {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct sk_buff *skb;
-@@ -2890,6 +2927,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -3266,6 +3307,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -5037,6 +5082,7 @@ static int ixgbe_open(struct net_device *netdev)
- 
- 	ixgbe_up_complete(adapter);
- 
-+
- 	return 0;
- 
- err_set_queues:
-@@ -7658,6 +7704,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
- 			true);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -7692,6 +7742,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	ixgbe_dbg_adapter_exit(adapter);
- 
- 	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00 b/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
deleted file mode 100644
index febd3bc92..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--30d00--30f00
+++ /dev/null
@@ -1,131 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 5bcc870f8367..eef466715f03 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -328,6 +328,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -959,6 +975,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -1995,6 +2022,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- #endif /* IXGBE_FCOE */
- 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	do {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct sk_buff *skb;
-@@ -3018,6 +3055,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -3394,6 +3435,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -4600,16 +4645,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 	/* enable transmits */
- 	netif_tx_start_all_queues(adapter->netdev);
- 
--	/* enable any upper devices */
--	netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
--		if (netif_is_macvlan(upper)) {
--			struct macvlan_dev *vlan = netdev_priv(upper);
--
--			if (vlan->fwd_priv)
--				netif_tx_start_all_queues(upper);
--		}
--	}
--
- 	/* bring the link up in the watchdog, this could race with our first
- 	 * link up interrupt but shouldn't be a problem */
- 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5412,6 +5447,7 @@ static int ixgbe_open(struct net_device *netdev)
- 
- 	ixgbe_up_complete(adapter);
- 
-+
- 	return 0;
- 
- err_set_queues:
-@@ -8174,6 +8210,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
- 			true);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -8208,6 +8248,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
- 	struct net_device *netdev = adapter->netdev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	ixgbe_dbg_adapter_exit(adapter);
- 
- 	set_bit(__IXGBE_DOWN, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--30f00--31300 b/LINUX/final-patches/vanilla--ixgbe--31200--31300
similarity index 83%
rename from LINUX/final-patches/vanilla--ixgbe--30f00--31300
rename to LINUX/final-patches/vanilla--ixgbe--31200--31300
index c6584010a..7947b9ba0 100644
--- a/LINUX/final-patches/vanilla--ixgbe--30f00--31300
+++ b/LINUX/final-patches/vanilla--ixgbe--31200--31300
@@ -1,9 +1,9 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index d62e7a25cf97..1c0b31aa4880 100644
+index cc51554c9e99..a88dfd15d9d4 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
-@@ -417,6 +417,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{}
+@@ -443,6 +443,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+ 	{ .name = NULL }
  };
  
 +#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
@@ -25,7 +25,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  
  /*
   * ixgbe_regdump - register printout routine
-@@ -1048,6 +1064,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+@@ -1068,6 +1084,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
  	if (test_bit(__IXGBE_DOWN, &adapter->state))
  		return true;
  
@@ -43,7 +43,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -2087,6 +2114,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+@@ -1991,6 +2018,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
  #endif /* IXGBE_FCOE */
  	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
  
@@ -60,7 +60,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3116,6 +3153,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+@@ -3013,6 +3050,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  
  	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
  
@@ -71,7 +71,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	/* enable queue */
  	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
-@@ -3496,6 +3537,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3393,6 +3434,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -82,7 +82,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4698,6 +4743,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4706,6 +4751,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
@@ -92,7 +92,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5503,6 +5551,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5518,6 +5566,7 @@ static int ixgbe_open(struct net_device *netdev)
  
  	ixgbe_up_complete(adapter);
  
@@ -100,7 +100,7 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	return 0;
  
  err_set_queues:
-@@ -8310,6 +8359,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8364,6 +8413,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -111,9 +111,9 @@ index d62e7a25cf97..1c0b31aa4880 100644
  	return 0;
  
  err_register:
-@@ -8345,6 +8398,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
- 	struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
+@@ -8402,6 +8455,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
  	struct net_device *netdev = adapter->netdev;
+ 	bool disable_dev;
  
 +#ifdef DEV_NETMAP
 +	ixgbe_netmap_detach(adapter);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--20622--30500 b/LINUX/final-patches/vanilla--ixgbevf--20622--30500
deleted file mode 100644
index 9304d203b..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--20622--30500
+++ /dev/null
@@ -1,120 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 0cd6202dfacc..57e93f43df51 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -209,6 +209,24 @@ static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @adapter: board private structure
-@@ -224,6 +242,20 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
- 	unsigned int i, eop, count = 0;
- 	unsigned int total_bytes = 0, total_packets = 0;
- 
-+	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
-+		return true;
-+
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-@@ -507,6 +539,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED);
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1289,6 +1331,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter,
- }
- 
- /**
-+}
-+
-  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
-  * @adapter: board private structure
-  *
-@@ -1319,6 +1363,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
- 		 */
- 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-+#ifdef DEV_NETMAP
-+		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
-+#endif /* DEV_NETMAP */
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
- 	}
- }
-@@ -1582,6 +1629,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
- 	ixgbevf_configure_rx(adapter);
- 	for (i = 0; i < adapter->num_rx_queues; i++) {
- 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
-+#ifdef DEV_NETMAP
-+		if (!ixgbe_netmap_configure_rx_ring(adapter, i))
-+#endif /* DEV_NETMAP */
- 		ixgbevf_alloc_rx_buffers(adapter, ring, ring->count);
- 		ring->next_to_use = ring->count - 1;
- 		writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail);
-@@ -3485,6 +3535,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
- 	hw_dbg(hw, "LRO is disabled \n");
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3516,6 +3571,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30500--30600 b/LINUX/final-patches/vanilla--ixgbevf--30500--30600
deleted file mode 100644
index deb5d9bb6..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30500--30600
+++ /dev/null
@@ -1,117 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 41e32257a4e8..5a9610ec6b8b 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -186,6 +186,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @adapter: board private structure
-@@ -204,6 +222,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
-@@ -474,6 +503,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED);
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1265,6 +1304,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter,
- }
- 
- /**
-+}
-+
-  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
-  * @adapter: board private structure
-  *
-@@ -1295,6 +1336,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
- 		 */
- 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-+#ifdef DEV_NETMAP
-+		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
-+#endif /* DEV_NETMAP */
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
- 	}
- }
-@@ -1532,6 +1576,9 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
- 	ixgbevf_configure_rx(adapter);
- 	for (i = 0; i < adapter->num_rx_queues; i++) {
- 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
-+#ifdef DEV_NETMAP
-+		if (!ixgbe_netmap_configure_rx_ring(adapter, i))
-+#endif /* DEV_NETMAP */
- 		ixgbevf_alloc_rx_buffers(adapter, ring, ring->count);
- 		ring->next_to_use = ring->count - 1;
- 		writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail);
-@@ -3463,6 +3510,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
- 	hw_dbg(hw, "LRO is disabled\n");
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3494,6 +3546,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30600--30700 b/LINUX/final-patches/vanilla--ixgbevf--30600--30700
deleted file mode 100644
index 0fb79f717..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30600--30700
+++ /dev/null
@@ -1,118 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 60ef64587412..b0c3eb141ec0 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -196,6 +214,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBEVF_TX_DESC(tx_ring, eop);
-@@ -397,6 +426,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED);
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1009,6 +1048,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter)
- }
- 
- /**
-+}
-+
-  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
-  * @adapter: board private structure
-  *
-@@ -1039,6 +1080,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
- 		 */
- 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-+#ifdef DEV_NETMAP
-+		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
-+#endif /* DEV_NETMAP */
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
- 	}
- }
-@@ -1242,6 +1286,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
- 	ixgbevf_configure_rx(adapter);
- 	for (i = 0; i < adapter->num_rx_queues; i++) {
- 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
-+#ifdef DEV_NETMAP
-+		if (ixgbe_netmap_configure_rx_ring(adapter, i))
-+			continue;
-+#endif /* DEV_NETMAP */
- 		ixgbevf_alloc_rx_buffers(adapter, ring,
- 					 IXGBE_DESC_UNUSED(ring));
- 	}
-@@ -3127,6 +3175,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3158,6 +3211,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00 b/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
deleted file mode 100644
index 2fab97397..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30700--30d00
+++ /dev/null
@@ -1,118 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index de1ad506665d..154571deebe0 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -179,6 +179,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -196,6 +214,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	eop = tx_ring->tx_buffer_info[i].next_to_watch;
- 	eop_desc = IXGBEVF_TX_DESC(tx_ring, eop);
-@@ -397,6 +426,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED);
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -996,6 +1035,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter)
- }
- 
- /**
-+}
-+
-  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
-  * @adapter: board private structure
-  *
-@@ -1026,6 +1067,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
- 		 */
- 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-+#ifdef DEV_NETMAP
-+		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
-+#endif /* DEV_NETMAP */
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
- 	}
- }
-@@ -1266,6 +1310,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
- 	ixgbevf_configure_rx(adapter);
- 	for (i = 0; i < adapter->num_rx_queues; i++) {
- 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
-+#ifdef DEV_NETMAP
-+		if (ixgbe_netmap_configure_rx_ring(adapter, i))
-+			continue;
-+#endif /* DEV_NETMAP */
- 		ixgbevf_alloc_rx_buffers(adapter, ring,
- 					 IXGBE_DESC_UNUSED(ring));
- 	}
-@@ -3243,6 +3291,11 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3275,6 +3328,11 @@ static void __devexit ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00 b/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
deleted file mode 100644
index 0dc67d0a7..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30d00--30e00
+++ /dev/null
@@ -1,118 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 92ef4cb5a8e8..3c5d85cec0a7 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -176,6 +176,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -193,6 +211,17 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
- 	i = tx_ring->next_to_clean;
- 	tx_buffer_info = &tx_ring->tx_buffer_info[i];
- 	eop_desc = tx_buffer_info->next_to_watch;
-@@ -434,6 +463,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1087,6 +1126,8 @@ static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter)
- }
- 
- /**
-+}
-+
-  * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
-  * @adapter: board private structure
-  *
-@@ -1117,6 +1158,9 @@ static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
- 		 */
- 		txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-+#ifdef DEV_NETMAP
-+		txctrl = ixgbe_netmap_configure_tx_ring(adapter, i, txctrl);
-+#endif /* DEV_NETMAP */
- 		IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
- 	}
- }
-@@ -1379,6 +1423,10 @@ static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
- 	ixgbevf_configure_rx(adapter);
- 	for (i = 0; i < adapter->num_rx_queues; i++) {
- 		struct ixgbevf_ring *ring = &adapter->rx_ring[i];
-+#ifdef DEV_NETMAP
-+		if (ixgbe_netmap_configure_rx_ring(adapter, i))
-+			continue;
-+#endif /* DEV_NETMAP */
- 		ixgbevf_alloc_rx_buffers(adapter, ring,
- 					 ixgbevf_desc_unused(ring));
- 	}
-@@ -3545,6 +3593,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3577,6 +3630,11 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00 b/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
deleted file mode 100644
index b1a3980ee..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30e00--30f00
+++ /dev/null
@@ -1,111 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 9df28985eba7..05d9620c5c3f 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -175,6 +175,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -193,6 +211,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -448,6 +478,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1152,6 +1192,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
- 		  32;          /* PTHRESH = 32 */
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
- 
- 	/* poll to verify queue is enabled */
-@@ -1330,6 +1374,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
- 
- 	ixgbevf_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
- }
- 
-@@ -3538,6 +3586,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3570,6 +3623,11 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_DOWN, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200 b/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
deleted file mode 100644
index 3b72e5c37..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--30f00--31200
+++ /dev/null
@@ -1,110 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index d0799e8e31e4..3105f9c82ac3 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -237,6 +255,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -492,6 +522,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1199,6 +1239,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
- 		  32;          /* PTHRESH = 32 */
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
- 
- 	/* poll to verify queue is enabled */
-@@ -1381,6 +1425,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
- 
- 	ixgbevf_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
- }
- 
-@@ -3601,6 +3649,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	cards_found++;
- 	return 0;
- 
-@@ -3634,6 +3687,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--veth.c--20620--30900 b/LINUX/final-patches/vanilla--veth.c--20620--30900
deleted file mode 100644
index c63d70bf1..000000000
--- a/LINUX/final-patches/vanilla--veth.c--20620--30900
+++ /dev/null
@@ -1,35 +0,0 @@
-diff --git a/veth.c b/veth.c
-index 52af5017c46b..a416e437bebf 100644
---- a/veth.c
-+++ b/veth.c
-@@ -38,6 +38,10 @@ struct veth_priv {
- 	unsigned ip_summed;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /*
-  * ethtool interface
-  */
-@@ -284,6 +288,9 @@ static int veth_dev_init(struct net_device *dev)
- 
- 	priv = netdev_priv(dev);
- 	priv->stats = stats;
-+#ifdef DEV_NETMAP
-+	veth_netmap_attach(dev);
-+#endif /* DEV_NETMAP */
- 	return 0;
- }
- 
-@@ -291,6 +298,9 @@ static void veth_dev_free(struct net_device *dev)
- {
- 	struct veth_priv *priv;
- 
-+#ifdef DEV_NETMAP
-+	netmap_detach(dev);
-+#endif /* DEV_NETMAP */
- 	priv = netdev_priv(dev);
- 	free_percpu(priv->stats);
- 	free_netdev(dev);
diff --git a/LINUX/final-patches/vanilla--veth.c--30900--30f00 b/LINUX/final-patches/vanilla--veth.c--30900--30f00
deleted file mode 100644
index 04f5b4e43..000000000
--- a/LINUX/final-patches/vanilla--veth.c--30900--30f00
+++ /dev/null
@@ -1,33 +0,0 @@
-diff --git a/veth.c b/veth.c
-index 07a4af0aa3dc..672375e5c5c8 100644
---- a/veth.c
-+++ b/veth.c
-@@ -36,6 +36,10 @@ struct veth_priv {
- 	atomic64_t		dropped;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- /*
-  * ethtool interface
-  */
-@@ -234,11 +238,17 @@ static int veth_dev_init(struct net_device *dev)
- 	if (!dev->vstats)
- 		return -ENOMEM;
- 
-+#ifdef DEV_NETMAP
-+	veth_netmap_attach(dev);
-+#endif /* DEV_NETMAP */
- 	return 0;
- }
- 
- static void veth_dev_free(struct net_device *dev)
- {
-+#ifdef DEV_NETMAP
-+	netmap_detach(dev);
-+#endif /* DEV_NETMAP */
- 	free_percpu(dev->vstats);
- 	free_netdev(dev);
- }
diff --git a/LINUX/final-patches/vanilla--veth.c--30f00--41300 b/LINUX/final-patches/vanilla--veth.c--31200--41300
similarity index 94%
rename from LINUX/final-patches/vanilla--veth.c--30f00--41300
rename to LINUX/final-patches/vanilla--veth.c--31200--41300
index 9d0b49ad7..af7140d45 100644
--- a/LINUX/final-patches/vanilla--veth.c--30f00--41300
+++ b/LINUX/final-patches/vanilla--veth.c--31200--41300
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index b4a10bcb66a0..52b7c371f06b 100644
+index 8ad596573d17..a3cf12c2ede6 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -37,6 +37,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625 b/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
deleted file mode 100644
index 342b63b0b..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--20622--20625
+++ /dev/null
@@ -1,80 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index b0577dd1a42d..0c873c4ae173 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -64,6 +64,10 @@ struct virtnet_info
- 	struct page *pages;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -121,6 +125,10 @@ static void skb_xmit_done(struct virtqueue *svq)
- 	/* Suppress further interrupts. */
- 	svq->vq_ops->disable_cb(svq);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(vi->dev, 0))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_queue(vi->dev);
- }
-@@ -470,7 +478,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, 0, &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
-@@ -638,6 +656,9 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_init_buffers(vi);
-+#endif
- 	napi_enable(&vi->napi);
- 
- 	/* If all buffers were filled by other side before we napi_enabled, we
-@@ -985,6 +1006,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto unregister;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_attach(vi);
-+#endif
-+
- 	vi->status = VIRTIO_NET_S_LINK_UP;
- 	virtnet_update_status(vi);
- 	netif_carrier_on(dev);
-@@ -1027,7 +1052,14 @@ static void free_unused_bufs(struct virtnet_info *vi)
- static void __devexit virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	/* Stop all the virtqueues. */
- 	vdev->config->reset(vdev);
- 
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626 b/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
deleted file mode 100644
index 8edbcc909..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--20625--20626
+++ /dev/null
@@ -1,80 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index b6d402806ae6..60bb2b2cc257 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -67,6 +67,10 @@ struct virtnet_info {
- 	struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -124,6 +128,10 @@ static void skb_xmit_done(struct virtqueue *svq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(svq);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(vi->dev, 0))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_queue(vi->dev);
- }
-@@ -467,7 +475,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, 0, &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
-@@ -638,6 +656,9 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_init_buffers(vi);
-+#endif
- 	napi_enable(&vi->napi);
- 
- 	/* If all buffers were filled by other side before we napi_enabled, we
-@@ -986,6 +1007,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto unregister;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1034,7 +1059,14 @@ static void free_unused_bufs(struct virtnet_info *vi)
- static void __devexit virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	/* Stop all the virtqueues. */
- 	vdev->config->reset(vdev);
- 
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300 b/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
deleted file mode 100644
index d6a60b6db..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--20626--30300
+++ /dev/null
@@ -1,80 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index 82dba5aaf423..06324f8b2593 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -67,6 +67,10 @@ struct virtnet_info {
- 	struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -124,6 +128,10 @@ static void skb_xmit_done(struct virtqueue *svq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(svq);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(vi->dev, 0))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_queue(vi->dev);
- }
-@@ -481,7 +489,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, 0, &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
-@@ -652,6 +670,9 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_init_buffers(vi);
-+#endif
- 	virtnet_napi_enable(vi);
- 	return 0;
- }
-@@ -991,6 +1012,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto unregister;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1039,7 +1064,14 @@ static void free_unused_bufs(struct virtnet_info *vi)
- static void __devexit virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	/* Stop all the virtqueues. */
- 	vdev->config->reset(vdev);
- 
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500 b/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
deleted file mode 100644
index b233d3428..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--30300--30500
+++ /dev/null
@@ -1,82 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index 4880aa8b4c28..6521c7e1b366 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -80,6 +80,10 @@ struct virtnet_info {
- 	struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -137,6 +141,10 @@ static void skb_xmit_done(struct virtqueue *svq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(svq);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(vi->dev, 0))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_queue(vi->dev);
- }
-@@ -517,7 +525,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, 0, &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
-@@ -727,7 +745,11 @@ static void virtnet_netpoll(struct net_device *dev)
- static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
-+#ifdef DEV_NETMAP
-+	int ok = virtio_netmap_init_buffers(vi);
- 
-+	if (!ok)
-+#endif
- 	/* Make sure we have some buffers: if oom use wq. */
- 	if (!try_fill_recv(vi, GFP_KERNEL))
- 		queue_delayed_work(system_nrt_wq, &vi->refill, 0);
-@@ -1107,6 +1129,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto unregister;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1169,7 +1195,14 @@ static void remove_vq_common(struct virtnet_info *vi)
- static void __devexit virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	unregister_netdev(vi->dev);
- 
- 	remove_vq_common(vi);
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800 b/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
deleted file mode 100644
index bd6128748..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--30500--30800
+++ /dev/null
@@ -1,82 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index f18149ae2588..19d344ac1326 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -90,6 +90,10 @@ struct virtnet_info {
- 	struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -147,6 +151,10 @@ static void skb_xmit_done(struct virtqueue *svq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(svq);
- 
-+#ifdef DEV_NETMAP
-+	if (netmap_tx_irq(vi->dev, 0))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_queue(vi->dev);
- }
-@@ -529,7 +537,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, 0, &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(vi->rvq, &len)) != NULL) {
-@@ -742,7 +760,11 @@ static void virtnet_netpoll(struct net_device *dev)
- static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
-+#ifdef DEV_NETMAP
-+	int ok = virtio_netmap_init_buffers(vi);
- 
-+	if (!ok)
-+#endif
- 	/* Make sure we have some buffers: if oom use wq. */
- 	if (!try_fill_recv(vi, GFP_KERNEL))
- 		queue_delayed_work(system_nrt_wq, &vi->refill, 0);
-@@ -1148,6 +1170,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto unregister;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1210,7 +1236,14 @@ static void remove_vq_common(struct virtnet_info *vi)
- static void __devexit virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	/* Prevent config work handler from accessing the device. */
- 	mutex_lock(&vi->config_lock);
- 	vi->config_enable = false;
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30800--30a00 b/LINUX/final-patches/vanilla--virtio_net.c--30800--30a00
deleted file mode 100644
index faf009b22..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--30800--30a00
+++ /dev/null
@@ -1,85 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index 35c00c5ea02a..93a37247e2c8 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -132,6 +132,10 @@ struct virtnet_info {
- 	struct notifier_block nb;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -211,6 +215,10 @@ static void skb_xmit_done(struct virtqueue *vq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(vq);
- 
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_subqueue(vi->dev, vq2txq(vq));
- }
-@@ -603,7 +611,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = rq->vq->vdev->priv;
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
-@@ -635,8 +653,14 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 	int i;
-+#ifdef DEV_NETMAP
-+        int ok = virtio_netmap_init_buffers(vi);
-+#endif
- 
- 	for (i = 0; i < vi->max_queue_pairs; i++) {
-+#ifdef DEV_NETMAP
-+		if (!ok)
-+#endif
- 		/* Make sure we have some buffers: if oom use wq. */
- 		if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
- 			schedule_delayed_work(&vi->refill, 0);
-@@ -1572,6 +1596,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto free_recv_bufs;
- 	}
- 
-+#ifdef DEV_NETMAP
-+        virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1617,7 +1645,14 @@ static void remove_vq_common(struct virtnet_info *vi)
- static void virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	unregister_hotcpu_notifier(&vi->nb);
- 
- 	/* Prevent config work handler from accessing the device. */
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00 b/LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00
deleted file mode 100644
index 600fd790d..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--30a00--30b00
+++ /dev/null
@@ -1,85 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index c9e00387d999..3d4fcc032940 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -131,6 +131,10 @@ struct virtnet_info {
- 	struct notifier_block nb;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -210,6 +214,10 @@ static void skb_xmit_done(struct virtqueue *vq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(vq);
- 
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_subqueue(vi->dev, vq2txq(vq));
- }
-@@ -603,7 +611,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = rq->vq->vdev->priv;
- 	void *buf;
- 	unsigned int len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
-@@ -635,8 +653,14 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 	int i;
-+#ifdef DEV_NETMAP
-+        int ok = virtio_netmap_init_buffers(vi);
-+#endif
- 
- 	for (i = 0; i < vi->max_queue_pairs; i++) {
-+#ifdef DEV_NETMAP
-+		if (!ok)
-+#endif
- 		if (i < vi->curr_queue_pairs)
- 			/* Make sure we have some buffers: if oom use wq. */
- 			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
-@@ -1594,6 +1618,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto free_recv_bufs;
- 	}
- 
-+#ifdef DEV_NETMAP
-+        virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1639,7 +1667,14 @@ static void remove_vq_common(struct virtnet_info *vi)
- static void virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	unregister_hotcpu_notifier(&vi->nb);
- 
- 	/* Prevent config work handler from accessing the device. */
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100 b/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
deleted file mode 100644
index 22b4bf14a..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--30b00--31100
+++ /dev/null
@@ -1,85 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index 3d2a90a62649..435ad46baab3 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -131,6 +131,10 @@ struct virtnet_info {
- 	struct notifier_block nb;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -210,6 +214,10 @@ static void skb_xmit_done(struct virtqueue *vq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(vq);
- 
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_subqueue(vi->dev, vq2txq(vq));
- }
-@@ -603,7 +611,17 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 	struct virtnet_info *vi = rq->vq->vdev->priv;
- 	void *buf;
- 	unsigned int r, len, received = 0;
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
- 
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+	} else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+        }
-+#endif
- again:
- 	while (received < budget &&
- 	       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
-@@ -636,8 +654,14 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 	int i;
-+#ifdef DEV_NETMAP
-+        int ok = virtio_netmap_init_buffers(vi);
-+#endif
- 
- 	for (i = 0; i < vi->max_queue_pairs; i++) {
-+#ifdef DEV_NETMAP
-+		if (!ok)
-+#endif
- 		if (i < vi->curr_queue_pairs)
- 			/* Make sure we have some buffers: if oom use wq. */
- 			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
-@@ -1592,6 +1616,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto free_recv_bufs;
- 	}
- 
-+#ifdef DEV_NETMAP
-+        virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1637,7 +1665,14 @@ static void remove_vq_common(struct virtnet_info *vi)
- static void virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	unregister_hotcpu_notifier(&vi->nb);
- 
- 	/* Prevent config work handler from accessing the device. */
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300 b/LINUX/final-patches/vanilla--virtio_net.c--31200--31300
similarity index 81%
rename from LINUX/final-patches/vanilla--virtio_net.c--31100--31300
rename to LINUX/final-patches/vanilla--virtio_net.c--31200--31300
index c2278934d..05c27ed6f 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31100--31300
+++ b/LINUX/final-patches/vanilla--virtio_net.c--31200--31300
@@ -1,8 +1,8 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 59caa06f34a6..2480ecd71b1d 100644
+index b0bc8ead47de..ef1a06d54185 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
-@@ -145,6 +145,10 @@ struct virtnet_info {
+@@ -139,6 +139,10 @@ struct virtnet_info {
  	struct notifier_block nb;
  };
  
@@ -13,7 +13,7 @@ index 59caa06f34a6..2480ecd71b1d 100644
  struct skb_vnet_hdr {
  	union {
  		struct virtio_net_hdr hdr;
-@@ -224,6 +228,10 @@ static void skb_xmit_done(struct virtqueue *vq)
+@@ -218,6 +222,10 @@ static void skb_xmit_done(struct virtqueue *vq)
  	/* Suppress further interrupts. */
  	virtqueue_disable_cb(vq);
  
@@ -24,7 +24,7 @@ index 59caa06f34a6..2480ecd71b1d 100644
  	/* We were probably waiting for more output buffers. */
  	netif_wake_subqueue(vi->dev, vq2txq(vq));
  }
-@@ -754,6 +762,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
+@@ -759,6 +767,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
  		container_of(napi, struct receive_queue, napi);
  	unsigned int r, received = 0;
  
@@ -44,7 +44,7 @@ index 59caa06f34a6..2480ecd71b1d 100644
  again:
  	received += virtnet_receive(rq, budget - received);
  
-@@ -813,8 +834,14 @@ static int virtnet_open(struct net_device *dev)
+@@ -818,8 +839,14 @@ static int virtnet_open(struct net_device *dev)
  {
  	struct virtnet_info *vi = netdev_priv(dev);
  	int i;
@@ -59,7 +59,7 @@ index 59caa06f34a6..2480ecd71b1d 100644
  		if (i < vi->curr_queue_pairs)
  			/* Make sure we have some buffers: if oom use wq. */
  			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
-@@ -1826,6 +1853,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1862,6 +1889,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -70,7 +70,7 @@ index 59caa06f34a6..2480ecd71b1d 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1872,7 +1903,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1910,7 +1941,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
@@ -84,4 +84,4 @@ index 59caa06f34a6..2480ecd71b1d 100644
 +#endif
  	unregister_hotcpu_notifier(&vi->nb);
  
- 	/* Prevent config work handler from accessing the device. */
+ 	/* Make sure no work handler is accessing the device. */
diff --git a/LINUX/final-patches/vanilla--vmxnet3--31000--40d00 b/LINUX/final-patches/vanilla--vmxnet3--31200--40d00
similarity index 90%
rename from LINUX/final-patches/vanilla--vmxnet3--31000--40d00
rename to LINUX/final-patches/vanilla--vmxnet3--31200--40d00
index a4a3d2345..fd9b11b90 100644
--- a/LINUX/final-patches/vanilla--vmxnet3--31000--40d00
+++ b/LINUX/final-patches/vanilla--vmxnet3--31200--40d00
@@ -1,7 +1,7 @@
 diff --git a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
 old mode 100644
 new mode 100755
-index b76f7dcde0db..f87199abe09e
+index 6dfcbf523936..2d2f4a669aca
 --- a/vmxnet3/vmxnet3_drv.c
 +++ b/vmxnet3/vmxnet3_drv.c
 @@ -308,6 +308,11 @@ static u32 get_bitfield32(const __le32 *bitfield, u32 pos, u32 size)
@@ -47,7 +47,7 @@ index b76f7dcde0db..f87199abe09e
  	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
  			  &rxComp);
  	while (rcd->gen == rq->comp_ring.gen) {
-@@ -2262,6 +2284,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+@@ -2263,6 +2285,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
  		adapter->rx_queue[0].rx_ring[0].size,
  		adapter->rx_queue[0].rx_ring[1].size);
  
@@ -58,7 +58,7 @@ index b76f7dcde0db..f87199abe09e
  	vmxnet3_tq_init_all(adapter);
  	err = vmxnet3_rq_init_all(adapter);
  	if (err) {
-@@ -3103,6 +3129,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
+@@ -3104,6 +3130,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
  		goto err_register;
  	}
  
@@ -70,7 +70,7 @@ index b76f7dcde0db..f87199abe09e
  	vmxnet3_check_link(adapter, false);
  	return 0;
  
-@@ -3154,6 +3185,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
+@@ -3155,6 +3186,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
  
  	unregister_netdev(netdev);
  
diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index b124d8133..84cc54d64 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -400,7 +400,7 @@ function build-prep()
 pound	:= \\#
 			/\/{s/\\#/$(pound)/}' tools/build/Build.include || true
 		last=compiler-gcc.h
-		for i in $(seq 14); do
+		for i in $(seq 15); do
 			[ -e include/linux/compiler-gcc"$i".h ] ||
 				ln -s "$last" include/linux/compiler-gcc"$i".h
 			last=compiler-gcc$i.h

From 89607e1406c1fa5ac2106bd2ff33417f090c0d60 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 10 Feb 2026 19:25:06 +0100
Subject: [PATCH 2189/2207] fix alignment in krings creation

While creating the krings* array + tailroom + krings data structure,
the previous code added 32 bytes in most cases for alignment purposes,
but since the alignment was set to 64, sometimes 48 bytes where needed.
Fix the issue by always adding 64 bytes to the allocation.
---
 sys/dev/netmap/netmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 89640b5e1..53e288a1d 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -865,9 +865,10 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
 	n[NR_TX] = netmap_all_rings(na, NR_TX);
 	n[NR_RX] = netmap_all_rings(na, NR_RX);
 
-	len = nm_tailroom_align((n[NR_TX] + n[NR_RX]) *
-		sizeof(struct netmap_kring *) + tailroom) +
-		(n[NR_TX] + n[NR_RX]) * sizeof(struct netmap_kring);
+	len = (n[NR_TX] + n[NR_RX]) * sizeof(struct netmap_kring *) +
+		tailroom +
+		(n[NR_TX] + n[NR_RX]) * sizeof(struct netmap_kring) +
+		NM_KRING_ALIGNMENT;
 
 	na->tx_rings = nm_os_malloc((size_t)len);
 	if (na->tx_rings == NULL) {

From bdd2667997cfac45dc4621761ebbde9fd8f20572 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Thu, 19 Feb 2026 12:22:18 +0100
Subject: [PATCH 2190/2207] linux/mellanox: update for latest drivers

---
 LINUX/configure                           |   2 +
 LINUX/default-config.mak.in_              |   7 +-
 LINUX/final-patches/mellanox--mlx5--24.10 | 453 ++++++++++++++++++++++
 LINUX/mlx5-config.sh_                     |  10 +
 LINUX/mlx5-prepare.sh                     |   0
 LINUX/mlx5_netmap_linux.h                 |   9 +
 6 files changed, 478 insertions(+), 3 deletions(-)
 create mode 100644 LINUX/final-patches/mellanox--mlx5--24.10
 create mode 100755 LINUX/mlx5-config.sh_
 mode change 100755 => 100644 LINUX/mlx5-prepare.sh

diff --git a/LINUX/configure b/LINUX/configure
index 8b047694e..0f9db127b 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -879,7 +879,9 @@ done
 
 replace_vars "$SRCDIR"/default-config.mak.in_ > default-config.mak
 replace_vars "$SRCDIR"/intel-fix.sh_ > intel-fix.sh
+replace_vars "$SRCDIR"/mlx5-config.sh_ > mlx5-config.sh
 chmod +x intel-fix.sh
+chmod +x mlx5-config.sh
 
 ###############################################################
 # Makefile creation
diff --git a/LINUX/default-config.mak.in_ b/LINUX/default-config.mak.in_
index e457207bc..b4f4c8d53 100644
--- a/LINUX/default-config.mak.in_
+++ b/LINUX/default-config.mak.in_
@@ -119,13 +119,13 @@ endif
 
 define mellanox_driver
 $(1)@fetch	:= test -e @SRCDIR@/ext-drivers/MLNX_EN_SRC-debian-$(2).tgz || wget https://content.mellanox.com/ofed/MLNX_EN-$(2)/MLNX_EN_SRC-debian-$(2).tgz -P @SRCDIR@/ext-drivers
-$(1)@src	:= tar xf @SRCDIR@/ext-drivers/MLNX_EN_SRC-debian-$(2).tgz&& tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv).orig.tar.gz && ln -s mlnx-en-$($(1)@pv) $(1)
+$(1)@src	:= tar xf @SRCDIR@/ext-drivers/MLNX_EN_SRC-debian-$(2).tgz&& tar xf MLNX_EN_SRC-$(2)/SOURCES/mlnx-en_$($(1)@pv)*.tar.gz && ln -s mlnx-en-$($(1)@pv)* $(1)
 $(1)@patch	:= patches/mellanox--$(1)--$($(1)@pv)
-$(1)@prepare	:= @SRCDIR@/mlx5-prepare.sh @KSRC@
+$(1)@prepare	:= @BUILDDIR@/mlx5-config.sh
 $(1)@build	:= make -C $(1) NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@ EXTRA_CFLAGS="$$($(1)@cflags) $(EXTRA_CFLAGS)"
 $(1)@install	:= make -C $(1) install_modules INSTALL_MOD_PATH=@MODPATH@ NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
 $(1)@clean	:= if [ -d $(1) ]; then make -C $(1) clean; fi NETMAP_DRIVER_SUFFIX=@DRVSUFFIX@
-$(1)@distclean  := rm -rf mlnx-en-$($(1)@pv) mlnx-en-$(2)
+$(1)@distclean  := rm -rf mlnx-en-$($(1)@pv).* mlnx-en-$(2) mlx5-config.sh MLNX_EN_SRC-$(2)
 $(1)@force	:= 1
 endef
 
@@ -133,6 +133,7 @@ $(eval $(call default,mlx5,5.8-3.0.7.0))
 mlx5@pv		= $(firstword $(subst -, ,$(mlx5@v)))
 mlx5@conf	= CONFIG_MLX5_CORE_EN
 mlx5@cflags	= -Wframe-larger-than=2000
+mlx5@prepare    := $(if $(filter $(mlx5@v),5.8),@SRCDIR@/mlx5-prepare.sh @KSRC@,)
 
 $(foreach d,$(filter mlx5,$(E_DRIVERS)),$(eval $(call mellanox_driver,$d,$($(d)@v))))
 
diff --git a/LINUX/final-patches/mellanox--mlx5--24.10 b/LINUX/final-patches/mellanox--mlx5--24.10
new file mode 100644
index 000000000..44c6c79b3
--- /dev/null
+++ b/LINUX/final-patches/mellanox--mlx5--24.10
@@ -0,0 +1,453 @@
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+index 49d9987..d9f4e09 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+@@ -10,12 +10,12 @@ ifeq ($(CONFIG_IS_AZURELINUX), y)
+ EXTRA_CFLAGS += -fno-exceptions
+ endif
+ 
+-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
++obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
+ 
+ #
+ # mlx5 core basic
+ #
+-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		health.o mcg.o cq.o alloc.o port.o mr.o pd.o \
+ 		transobj.o vport.o sriov.o fs_cmd.o fs_core.o pci_irq.o \
+ 		fs_counters.o fs_ft_pool.o rl.o lag/debugfs.o lag/lag.o dev.o events.o wq.o lib/gid.o \
+@@ -25,12 +25,11 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+ 		sriov_sysfs.o crdump.o diag/diag_cnt.o fw_exp.o \
+ 		eswitch_devlink_compat.o ecpf.o wc.o auxiliary_sysfs_compat.o
+ 
+-mlx5_core-y += compat.o
+-
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-y += compat.o
+ #
+ # Netdev basic
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
+ 		en/channels.o en_main.o en_common.o en_fs.o en_ethtool.o \
+ 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o\
+ 		en_selftest.o en/port.o en/monitor_stats.o en/health.o \
+@@ -42,14 +41,14 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
+ #
+ # Netdev extra
+ #
+-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += lag/mp.o lag/port_sel.o lib/geneve.o lib/port_tun.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += lag/mp.o lag/port_sel.o lib/geneve.o lib/port_tun.o \
+ 					en_rep.o en/rep/bond.o en/mod_hdr.o \
+ 					en/mapping.o lag/mpesw.o en/rep/meter.o en/rep/sysfs.o
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					lib/fs_chains.o en/tc_tun.o \
+ 					esw/indir_table.o en/tc_tun_encap.o \
+ 					en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
+@@ -57,7 +56,7 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
+ 					en/tc/post_act.o en/tc/int_port.o en/tc/meter.o \
+ 					en/tc/post_meter.o en/tc/act_stats.o
+ 
+-mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
+ 					en/tc/act/accept.o en/tc/act/mark.o en/tc/act/goto.o \
+ 					en/tc/act/tun.o en/tc/act/csum.o en/tc/act/pedit.o \
+ 					en/tc/act/vlan.o en/tc/act/vlan_mangle.o en/tc/act/mpls.o \
+@@ -67,60 +66,60 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/a
+ 
+ mlx5_core-$(CONFIG_MLX5_TC_CT) += en/tc_ct.o en/tc/ct_fs_dmfs.o en/tc/ct_fs_smfs.o en/tc/act/ct.o
+ 
+-mlx5_core-$(CONFIG_MLX5_TC_SAMPLE)   += en/tc/sample.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_TC_SAMPLE)   += en/tc/sample.o
+ 
+ #
+ # Core extra
+ #
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
+ 				      ecpf.o rdma.o esw/legacy.o \
+ 				      esw/devlink_port.o esw/vporttbl.o esw/qos.o esw/ipsec.o \
+ 				      esw/pet_offloads.o esw/vf_meter.o
+ 
+-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/acl/helper.o \
+ 				      esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
+ 				      esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o
+ 
+ ifneq ($(CONFIG_MLX5_EN_IPSEC),)
+-	mlx5_core-$(CONFIG_MLX5_ESWITCH)   += esw/ipsec_fs.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += esw/ipsec_fs.o
+ endif
+ 
+-mlx5_core-$(CONFIG_MLX5_BRIDGE)    += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_BRIDGE)    += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \
+ 				      en/rep/bridge.o
+ 
+-mlx5_core-$(CONFIG_HWMON)          += hwmon.o
+-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_HWMON)          += hwmon.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+ ifneq ($(CONFIG_VXLAN),)
+-	mlx5_core-y		+= lib/vxlan.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
+ endif
+ ifneq ($(CONFIG_PTP_1588_CLOCK),)
+-	mlx5_core-y		+= lib/clock.o
++	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
+ endif
+-mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
+-mlx5_core-$(CONFIG_MLXDEVM) += mlx5_devm.o esw/devm_port.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_PCI_HYPERV_INTERFACE) += lib/hv.o lib/hv_vhca.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLXDEVM) += mlx5_devm.o esw/devm_port.o
+ 
+ #
+ # Ipoib netdev
+ #
+-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+ 
+ #
+ # Accelerations & FPGA
+ #
+-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
+ 
+-mlx5_core-$(CONFIG_MLX5_MACSEC) += en_accel/macsec.o lib/macsec_fs.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MACSEC) += en_accel/macsec.o lib/macsec_fs.o \
+ 				      en_accel/macsec_stats.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+ 				     en_accel/ipsec_stats.o en_accel/ipsec_fs.o \
+ 				     en_accel/ipsec_offload.o lib/ipsec_fs_roce.o
+ 
+-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/ktls_stats.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/ktls_stats.o \
+ 				   en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
+ 				   en_accel/ktls_tx.o en_accel/ktls_rx.o
+ 
+-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
+ 					steering/dr_matcher.o steering/dr_rule.o \
+ 					steering/dr_icm_pool.o steering/dr_buddy.o \
+ 					steering/dr_ste.o steering/dr_send.o \
+@@ -133,17 +132,17 @@ mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o
+ #
+ # SF device
+ #
+-mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o irq_affinity.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o irq_affinity.o
+ 
+ #
+ # SF manager
+ #
+-mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
+ 
+ #
+ ## SF cfg driver basic
+ #
+-mlx5_core-$(CONFIG_MLX5_SF_CFG) += sf/dev/cfg_driver.o
++mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_SF_CFG) += sf/dev/cfg_driver.o
+ 
+ obj-$(CONFIG_MLX5_DPLL) += mlx5_dpll.o
+ mlx5_dpll-y :=	dpll.o
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+index dea5bf6..06622b7 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+@@ -32,6 +32,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
+ 			return 0;
+ 
+ 		msleep(20);
++#ifdef DEV_NETMAP
++		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
+ 	}
+ 
+ 	netdev_err(sq->netdev,
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index ad3931d..16e62e1 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -96,6 +96,16 @@
+ #include "lib/sd.h"
+ #include "compat.h"
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#define NETMAP_MLX5_MAIN
++#define DEV_NETMAP
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static void mlx5e_mqprio_build_default_tc_to_txq(struct netdev_tc_txq *tc_to_txq,
+ 						 int ntc, int nch);
+ 
+@@ -105,6 +115,10 @@ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev, u8 page_
+ 	u16 umr_wqebbs, max_wqebbs;
+ 	bool striding_rq_umr;
+ 
++#ifdef DEV_NETMAP
++	return 0;
++#endif
++
+ 	striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) && MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
+ 			  MLX5_CAP_ETH(mdev, reg_umr_sq);
+ 	if (!striding_rq_umr)
+@@ -1665,6 +1679,12 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
+ {
+ 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
+ 
++#ifdef DEV_NETMAP
++	struct netmap_adapter *na = NA(rq->netdev);
++	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
++		return 0; /* no need to wait when netmap has built wqes */
++#endif
++
+ 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
+ 
+ 	do {
+@@ -1767,6 +1787,10 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
+ 
+ 		while (!mlx5_wq_cyc_is_empty(wq)) {
+ 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
++#ifdef DEV_NETMAP
++			struct netmap_adapter *na = NA(rq->netdev);
++			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 			rq->dealloc_wqe(rq, wqe_ix);
+ 			mlx5_wq_cyc_pop(wq);
+ 		}
+@@ -1910,6 +1934,10 @@ int mlx5e_open_rq(struct mlx5e_params *params, struct mlx5e_rq_param *param,
+ 	    MLX5_CAP_GEN(mdev, enhanced_cqe_compression))
+ 		__set_bit(MLX5E_RQ_STATE_MINI_CQE_ENHANCED, &rq->state);
+ 
++#ifdef DEV_NETMAP
++	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_destroy_rq:
+@@ -1923,6 +1951,9 @@ err_dealloc_rq:
+ 
+ void mlx5e_activate_rq(struct mlx5e_rq *rq)
+ {
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(rq->netdev)) || NA(rq->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
++#endif
+ 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
+ }
+ 
+@@ -2235,6 +2266,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
+ 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
+ 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
+ 
++#ifdef DEV_NETMAP
++	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
++		return 0;
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_sq_wq_destroy:
+@@ -2442,6 +2478,9 @@ void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
+ 	mlx5e_tx_disable_queue(sq->txq);
+ 
+ 	/* last doorbell out, godspeed .. */
++#ifdef DEV_NETMAP
++	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
++#endif
+ 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
+ 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
+ 		struct mlx5e_tx_wqe *nop;
+@@ -2462,6 +2501,12 @@ void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
+ 
+ 	cancel_work_sync(&sq->dim_obj.dim.work);
+ 	cancel_work_sync(&sq->recover_work);
++
++#ifdef DEV_NETMAP
++	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
++		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
++#endif
++
+ 	mlx5e_destroy_sq(mdev, sq->sqn);
+ 	if (sq->rate_limit) {
+ 		rl.rate = sq->rate_limit;
+@@ -3986,6 +4031,11 @@ int mlx5e_open_locked(struct net_device *netdev)
+ 		priv->profile->update_carrier(priv);
+ 
+ 	mlx5e_queue_update_stats(priv);
++
++#ifdef DEV_NETMAP
++        netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
++#endif
++
+ 	return 0;
+ 
+ err_close_channels:
+@@ -4023,6 +4073,10 @@ int mlx5e_close_locked(struct net_device *netdev)
+ 	mlx5e_apply_traps(priv, false);
+ 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
+ 
++#ifdef DEV_NETMAP
++       netmap_disable_all_rings(netdev);
++#endif
++
+ 	netif_carrier_off(priv->netdev);
+ 	mlx5e_destroy_debugfs(priv);
+ 	mlx5e_deactivate_priv_channels(priv);
+@@ -7292,6 +7346,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
+ {
+ 	struct net_device *netdev = priv->netdev;
+ 
++#ifdef DEV_NETMAP
++       netmap_detach(netdev);
++#endif /* DEV_NETMAP */
++
+ 	mlx5e_priv_cleanup(priv);
+ 	free_netdev(netdev);
+ }
+@@ -7544,6 +7602,11 @@ static int _mlx5e_probe(struct auxiliary_device *adev)
+ 
+ 	mlx5e_dcbnl_init_app(priv);
+ 	mlx5_core_uplink_netdev_set(mdev, netdev);
++
++#ifdef DEV_NETMAP
++       mlx5e_netmap_attach(priv);
++#endif /* DEV_NETMAP */
++
+ 	return 0;
+ 
+ err_unregister_netdev:
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+index 35291db..7174e8c 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+@@ -86,6 +86,14 @@ const struct mlx5e_rx_handlers mlx5e_rx_handlers_nic = {
+ 	.handle_rx_cqe_mpwqe_shampo = mlx5e_handle_rx_cqe_mpwrq_shampo,
+ };
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+ 				       u32 cqcc, void *data)
+ {
+@@ -261,7 +269,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
+ 	return cqe_count;
+ }
+ 
+-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
++u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+ 					      struct mlx5_cqwq *wq,
+ 					      int budget_rem)
+ {
+@@ -4028,6 +4036,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
+ 	struct mlx5_cqwq *cqwq = &cq->wq;
+ 	int work_done;
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	int dummy;
++	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
++	if (nm_irq != NM_IRQ_PASS)
++		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
+ 		return 0;
+ 
+diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 04459c5..08109d3 100644
+--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -46,6 +46,15 @@
+ #include 
+ #endif
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++/*
++ * mlx5_netmap_linux.h contains functions for netmap support
++ * that extend the standard driver.
++ */
++#include "mlx5_netmap_linux.h"
++#endif
++
++
+ #ifdef HAVE_BASECODE_EXTRAS
+ static inline void mlx5e_read_cqe_slot(struct mlx5_cqwq *wq,
+ 				       u32 cqcc, void *data)
+@@ -975,6 +984,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
+ 
+ 	sq = container_of(cq, struct mlx5e_txqsq, cq);
+ 
++#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
++	if (netmap_tx_irq(sq->netdev, sq->ch_ix) != NM_IRQ_PASS)
++		return false;
++#endif
++
+ 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
+ 		return false;
+ 
+@@ -1093,23 +1107,29 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
+ 
+ 		sqcc += wi->num_wqebbs;
+ 
+-		if (likely(wi->skb)) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			dev_kfree_skb_any(wi->skb);
++		if (!nm_netmap_on(NA(sq->txq->dev))) {
++			/* do not free skbs in netmap mode */
++			if (likely(wi->skb)) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				dev_kfree_skb_any(wi->skb);
+ 
+-			npkts++;
+-			nbytes += wi->num_bytes;
+-			continue;
+-		}
++				npkts++;
++				nbytes += wi->num_bytes;
++				continue;
++			}
+ 
+-		if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
+-			continue;
++			if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc)))
++				continue;
+ 
+-		if (wi->num_fifo_pkts) {
+-			mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
+-			mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
++			if (wi->num_fifo_pkts) {
++				mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc);
++				mlx5e_tx_wi_kfree_fifo_skbs(sq, wi);
+ 
+-			npkts += wi->num_fifo_pkts;
++				npkts += wi->num_fifo_pkts;
++				nbytes += wi->num_bytes;
++			}
++		} else {
++			npkts++;
+ 			nbytes += wi->num_bytes;
+ 		}
+ 	}
diff --git a/LINUX/mlx5-config.sh_ b/LINUX/mlx5-config.sh_
new file mode 100755
index 000000000..94d1e095e
--- /dev/null
+++ b/LINUX/mlx5-config.sh_
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+if [ -e mlx5/configure.mk.kernel ]; then
+	exit 0
+fi
+
+LINVER=$(@SRCDIR@/scripts/vers @LIN_VER@ -C)
+
+cd mlx5
+./configure --mlnx_en --kernel-version=$LINVER --kernel-sources=@KSRC@ -j$(nproc)
diff --git a/LINUX/mlx5-prepare.sh b/LINUX/mlx5-prepare.sh
old mode 100755
new mode 100644
diff --git a/LINUX/mlx5_netmap_linux.h b/LINUX/mlx5_netmap_linux.h
index 98f858dbf..415163531 100644
--- a/LINUX/mlx5_netmap_linux.h
+++ b/LINUX/mlx5_netmap_linux.h
@@ -96,6 +96,15 @@ u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
                           struct mlx5e_cq *cq,
                           int budget_rem);
 
+int mlx5e_netmap_reg(struct netmap_adapter *na, int onoff);
+int mlx5e_netmap_txsync(struct netmap_kring *kring, int flags);
+int mlx5e_netmap_rxsync(struct netmap_kring *kring, int flags);
+int mlx5e_netmap_tx_flush(struct mlx5e_txqsq *sq);
+int mlx5e_netmap_rx_flush(struct mlx5e_rq *rq);
+int mlx5e_netmap_configure_tx_ring(struct NM_MLX5E_ADAPTER *adapter, int ring_nr);
+int mlx5e_netmap_configure_rx_ring(struct mlx5e_rq *rq, int ring_nr);
+int mlx5e_netmap_config(struct netmap_adapter *na, struct nm_config_info *info);
+void mlx5e_netmap_attach(struct NM_MLX5E_ADAPTER *adapter);
 
 /*
  * Register/unregister. We are already under netmap lock.

From 7a7b08be85a476aa762330ca39d295b28bbee8cd Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sun, 12 Apr 2026 13:36:52 +0200
Subject: [PATCH 2191/2207] linux/vers: handle 6.19 -> 7.0 transition

---
 LINUX/scripts/vers | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/LINUX/scripts/vers b/LINUX/scripts/vers
index 6f9905b73..f7e2a3ec6 100755
--- a/LINUX/scripts/vers
+++ b/LINUX/scripts/vers
@@ -20,7 +20,8 @@ sub checkversion
 	   ($may == 2 && $min != 6 && !($sub >= 32 && !$sub <= 39)) ||
 	   ($may == 3 && $min > 19) ||
 	   ($may == 4 && $min > 20) ||
-	   ($may == 5 && $min > 19)) {
+	   ($may == 5 && $min > 19) ||
+           ($may == 6 && $min > 19)) {
 		die "Bad version $v";
 	}
 }
@@ -67,11 +68,11 @@ sub next
 		} else {
 			return "5.0";
 		}
-	} elsif ($may == 5) {
+	} elsif ($may == 5 || $may == 6) {
 		if ($min < 19) {
-			return "5." . ($min +1);
+			return "" . $may . "." . ($min +1);
 		} else {
-			return "6.0";
+			return "" . ($may + 1) . ".0";
 		}
 	} else {
 		return "$may." . ($min + 1);
@@ -90,8 +91,8 @@ sub prev
 			return "3.19";
 		} elsif ($may == 5) {
 			return "4.20";
-		} elsif ($may == 6) {
-			return "5.19";
+		} elsif ($may == 6 || $may == 7) {
+			return "" . ($may - 1) . ".19";
 		} else {
 			die "Unknown version: $v";
 		}

From 8c708b52cfc62644d79c8d7f985bef382ef270cc Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 13 Apr 2026 16:09:37 +0200
Subject: [PATCH 2192/2207] linux/scripts: np: add commands to apply patches to
 linux tree

---
 LINUX/scripts/np | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 84cc54d64..536cfe8a4 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -180,6 +180,34 @@ function get-patch()
 	return 0;
 }
 
+##
+##  put-patch  
+function put-patch()
+{
+	declare driver version
+	get-params "driver version" "$@"
+
+	local drvpath drvdir v patchname
+	# convert kernel version to fixed notation
+	drvpath=$(driver-path "$driver" "$version")
+	[ -n "$drvpath" ] || return
+	drvdir=$(dirname "$drvpath")
+	v=$(scripts/vers "$version" -c)
+	patchname=$(ls final-patches/vanilla--"$driver"--* | awk -v v="$v" -F -- '($3 != "*") && ($3 <= v"") && (v"" < $4)')
+	[ -n "$patchname" ] || return
+	(
+		set -e
+		cd "$GITDIR"
+		git checkout netmap-$version || git checkout -b netmap-$version v$version
+		cd "$drvdir"
+		patch -N --no-backup-if-mismatch -p1 || { git restore .; git clean -fdx .; exit; }
+		git add -u
+		git commit -m "patch for netmap $driver driver"
+		git clean -fdx .
+	) < "$patchname"
+	return 0;
+}
+
 ##
 ##  get-range   
 ##	extracts the netmap patches for the given  for
@@ -210,6 +238,21 @@ function get-range()
 	done
 }
 
+##
+##  put-range  
+function put-range()
+{
+	declare version1 version2
+	get-params "version1 version2"	 "$@"
+
+	local v
+	v=$version1
+	while scripts/vers -b "$v" "$version2" -L; do
+		forall put-patch "$v"
+		v=$(scripts/vers "$v" -i)
+	done
+}
+
 
 ##
 ##  get-src   

From a69a57fe43786832cfdd9292be859d52d36685f4 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 13 Apr 2026 16:45:15 +0200
Subject: [PATCH 2193/2207] linux/scripts: update MINVERS to 4.0

---
 LINUX/scripts/np | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/scripts/np b/LINUX/scripts/np
index 536cfe8a4..ff4c4eef2 100755
--- a/LINUX/scripts/np
+++ b/LINUX/scripts/np
@@ -629,7 +629,7 @@ function build-check()
 	done
 }
 
-MINVERS=2.6.32
+MINVERS=4.0
 MAXVERS=
 NEXTVERS=
 ##

From 2ccd15df5818948df81d231bc30cbd47901c4688 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 14 Apr 2026 13:53:59 +0200
Subject: [PATCH 2194/2207] linux/drivers: patches for 7.0

---
 ...00--99999 => vanilla--e1000--40000--99999} |   2 +-
 ...0--99999 => vanilla--e1000e--40000--99999} |   8 +-
 ...999 => vanilla--forcedeth.c--40000--99999} |   2 +-
 ...200--40100 => vanilla--i40e--40000--40100} |  20 +--
 ...1200--40100 => vanilla--igb--40000--40100} |  18 +--
 ...0600--99999 => vanilla--igc--50600--61300} |   0
 .../vanilla--ixgbe--31200--31300              | 124 ------------------
 ...00--40900 => vanilla--ixgbe--40000--40900} |  24 ++--
 .../vanilla--ixgbevf--31200--31300            | 110 ----------------
 .../vanilla--ixgbevf--31300--40000            | 109 ---------------
 ...0--41300 => vanilla--veth.c--40000--41300} |   2 +-
 .../vanilla--virtio_net.c--31200--31300       |  87 ------------
 ...00 => vanilla--virtio_net.c--40000--40100} |   6 +-
 ...--40d00 => vanilla--vmxnet3--40000--40d00} |   8 +-
 14 files changed, 45 insertions(+), 475 deletions(-)
 rename LINUX/final-patches/{vanilla--e1000--31200--99999 => vanilla--e1000--40000--99999} (98%)
 rename LINUX/final-patches/{vanilla--e1000e--31200--99999 => vanilla--e1000e--40000--99999} (92%)
 rename LINUX/final-patches/{vanilla--forcedeth.c--31200--99999 => vanilla--forcedeth.c--40000--99999} (97%)
 rename LINUX/final-patches/{vanilla--i40e--31200--40100 => vanilla--i40e--40000--40100} (82%)
 rename LINUX/final-patches/{vanilla--igb--31200--40100 => vanilla--igb--40000--40100} (80%)
 rename LINUX/final-patches/{vanilla--igc--50600--99999 => vanilla--igc--50600--61300} (100%)
 delete mode 100644 LINUX/final-patches/vanilla--ixgbe--31200--31300
 rename LINUX/final-patches/{vanilla--ixgbe--31300--40900 => vanilla--ixgbe--40000--40900} (82%)
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--31200--31300
 delete mode 100644 LINUX/final-patches/vanilla--ixgbevf--31300--40000
 rename LINUX/final-patches/{vanilla--veth.c--31200--41300 => vanilla--veth.c--40000--41300} (94%)
 delete mode 100644 LINUX/final-patches/vanilla--virtio_net.c--31200--31300
 rename LINUX/final-patches/{vanilla--virtio_net.c--31300--40100 => vanilla--virtio_net.c--40000--40100} (93%)
 rename LINUX/final-patches/{vanilla--vmxnet3--31200--40d00 => vanilla--vmxnet3--40000--40d00} (90%)

diff --git a/LINUX/final-patches/vanilla--e1000--31200--99999 b/LINUX/final-patches/vanilla--e1000--40000--99999
similarity index 98%
rename from LINUX/final-patches/vanilla--e1000--31200--99999
rename to LINUX/final-patches/vanilla--e1000--40000--99999
index 19287e5e6..c2c2c3b26 100644
--- a/LINUX/final-patches/vanilla--e1000--31200--99999
+++ b/LINUX/final-patches/vanilla--e1000--40000--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000/e1000_main.c b/e1000/e1000_main.c
-index 24f3986cfae2..3f6227bb5107 100644
+index 7f997d36948f..816877487878 100644
 --- a/e1000/e1000_main.c
 +++ b/e1000/e1000_main.c
 @@ -200,6 +200,10 @@ static const struct pci_error_handlers e1000_err_handler = {
diff --git a/LINUX/final-patches/vanilla--e1000e--31200--99999 b/LINUX/final-patches/vanilla--e1000e--40000--99999
similarity index 92%
rename from LINUX/final-patches/vanilla--e1000e--31200--99999
rename to LINUX/final-patches/vanilla--e1000e--40000--99999
index c62d743c2..075d9792e 100644
--- a/LINUX/final-patches/vanilla--e1000e--31200--99999
+++ b/LINUX/final-patches/vanilla--e1000e--40000--99999
@@ -1,5 +1,5 @@
 diff --git a/e1000e/netdev.c b/e1000e/netdev.c
-index 247335d2c7ec..14045858fc88 100644
+index 1e8c40fd5c3d..7d560555ecff 100644
 --- a/e1000e/netdev.c
 +++ b/e1000e/netdev.c
 @@ -493,6 +493,10 @@ static int e1000_desc_unused(struct e1000_ring *ring)
@@ -57,7 +57,7 @@ index 247335d2c7ec..14045858fc88 100644
  
  	if (adapter->rx_ps_pages) {
  		u32 psrctl = 0;
-@@ -3736,6 +3756,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
+@@ -3733,6 +3753,10 @@ static void e1000_configure(struct e1000_adapter *adapter)
  		e1000e_setup_rss_hash(adapter);
  	e1000_setup_rctl(adapter);
  	e1000_configure_rx(adapter);
@@ -68,7 +68,7 @@ index 247335d2c7ec..14045858fc88 100644
  	adapter->alloc_rx_buf(rx_ring, e1000_desc_unused(rx_ring), GFP_KERNEL);
  }
  
-@@ -7022,6 +7046,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -7020,6 +7044,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	if (err)
  		goto err_register;
  
@@ -78,7 +78,7 @@ index 247335d2c7ec..14045858fc88 100644
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
-@@ -7117,6 +7144,10 @@ static void e1000_remove(struct pci_dev *pdev)
+@@ -7115,6 +7142,10 @@ static void e1000_remove(struct pci_dev *pdev)
  	kfree(adapter->tx_ring);
  	kfree(adapter->rx_ring);
  
diff --git a/LINUX/final-patches/vanilla--forcedeth.c--31200--99999 b/LINUX/final-patches/vanilla--forcedeth.c--40000--99999
similarity index 97%
rename from LINUX/final-patches/vanilla--forcedeth.c--31200--99999
rename to LINUX/final-patches/vanilla--forcedeth.c--40000--99999
index 51306c1f2..7888b0130 100644
--- a/LINUX/final-patches/vanilla--forcedeth.c--31200--99999
+++ b/LINUX/final-patches/vanilla--forcedeth.c--40000--99999
@@ -1,5 +1,5 @@
 diff --git a/forcedeth.c b/forcedeth.c
-index f39cae620f61..3af3ef806b45 100644
+index a41bb5e6b954..52ff9d8fb7bc 100644
 --- a/forcedeth.c
 +++ b/forcedeth.c
 @@ -1962,12 +1962,25 @@ static void nv_init_tx(struct net_device *dev)
diff --git a/LINUX/final-patches/vanilla--i40e--31200--40100 b/LINUX/final-patches/vanilla--i40e--40000--40100
similarity index 82%
rename from LINUX/final-patches/vanilla--i40e--31200--40100
rename to LINUX/final-patches/vanilla--i40e--40000--40100
index fd1fc6241..3e141786b 100644
--- a/LINUX/final-patches/vanilla--i40e--31200--40100
+++ b/LINUX/final-patches/vanilla--i40e--40000--40100
@@ -1,8 +1,8 @@
 diff --git a/i40e/i40e_main.c b/i40e/i40e_main.c
-index c3a7f4a4b775..2239a55bc221 100644
+index dadda3c5d658..ae060c279662 100644
 --- a/i40e/i40e_main.c
 +++ b/i40e/i40e_main.c
-@@ -89,6 +89,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+@@ -90,6 +90,11 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
  
@@ -14,7 +14,7 @@ index c3a7f4a4b775..2239a55bc221 100644
  /**
   * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
   * @hw:   pointer to the HW structure
-@@ -2476,6 +2481,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
+@@ -2509,6 +2514,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
  	/* cache tail off for easier writes later */
  	ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
  
@@ -25,7 +25,7 @@ index c3a7f4a4b775..2239a55bc221 100644
  	return 0;
  }
  
-@@ -2541,6 +2550,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2574,6 +2583,10 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	/* set the prefena field to 1 because the manual says to */
  	rx_ctx.prefena = 1;
  
@@ -36,7 +36,7 @@ index c3a7f4a4b775..2239a55bc221 100644
  	/* clear the context in the HMC */
  	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
  	if (err) {
-@@ -2563,6 +2576,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
+@@ -2596,6 +2609,11 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
  	ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
  	writel(0, ring->tail);
  
@@ -48,7 +48,7 @@ index c3a7f4a4b775..2239a55bc221 100644
  	i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
  
  	return 0;
-@@ -7833,6 +7851,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
+@@ -8040,6 +8058,11 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
  		return -ENODEV;
  	}
  
@@ -60,7 +60,7 @@ index c3a7f4a4b775..2239a55bc221 100644
  	uplink_seid = vsi->uplink_seid;
  	if (vsi->type != I40E_VSI_SRIOV) {
  		if (vsi->netdev_registered) {
-@@ -8150,6 +8173,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+@@ -8367,6 +8390,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
  		break;
  	}
  
@@ -73,7 +73,7 @@ index c3a7f4a4b775..2239a55bc221 100644
  
  err_rings:
 diff --git a/i40e/i40e_txrx.c b/i40e/i40e_txrx.c
-index 3195d82e4942..74493427510b 100644
+index bbf1b1247ac4..0cfe40a333ab 100644
 --- a/i40e/i40e_txrx.c
 +++ b/i40e/i40e_txrx.c
 @@ -28,6 +28,10 @@
@@ -87,7 +87,7 @@ index 3195d82e4942..74493427510b 100644
  static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
  				u32 td_tag)
  {
-@@ -674,6 +678,11 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
+@@ -682,6 +686,11 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
  	unsigned int total_packets = 0;
  	unsigned int total_bytes = 0;
  
@@ -99,7 +99,7 @@ index 3195d82e4942..74493427510b 100644
  	tx_buf = &tx_ring->tx_bi[i];
  	tx_desc = I40E_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1387,6 +1396,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+@@ -1432,6 +1441,15 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
  	if (budget <= 0)
  		return 0;
  
diff --git a/LINUX/final-patches/vanilla--igb--31200--40100 b/LINUX/final-patches/vanilla--igb--40000--40100
similarity index 80%
rename from LINUX/final-patches/vanilla--igb--31200--40100
rename to LINUX/final-patches/vanilla--igb--40000--40100
index db5e5531c..ef9eb8384 100644
--- a/LINUX/final-patches/vanilla--igb--31200--40100
+++ b/LINUX/final-patches/vanilla--igb--40000--40100
@@ -1,8 +1,8 @@
 diff --git a/igb/igb_main.c b/igb/igb_main.c
-index 487cd9c4ac0d..706d0cbeb75b 100644
+index f366b3b96d03..f7ee2c4c5eaf 100644
 --- a/igb/igb_main.c
 +++ b/igb/igb_main.c
-@@ -253,6 +253,10 @@ static int debug = -1;
+@@ -251,6 +251,10 @@ static int debug = -1;
  module_param(debug, int, 0);
  MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
  
@@ -13,7 +13,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  struct igb_reg_info {
  	u32 ofs;
  	char *name;
-@@ -1799,7 +1803,6 @@ void igb_down(struct igb_adapter *adapter)
+@@ -1797,7 +1801,6 @@ void igb_down(struct igb_adapter *adapter)
  		}
  	}
  
@@ -21,7 +21,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  	del_timer_sync(&adapter->watchdog_timer);
  	del_timer_sync(&adapter->phy_info_timer);
  
-@@ -2548,6 +2551,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -2546,6 +2549,10 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
@@ -32,7 +32,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  #ifdef CONFIG_IGB_DCA
  	if (dca_add_requester(&pdev->dev) == 0) {
  		adapter->flags |= IGB_FLAG_DCA_ENABLED;
-@@ -2813,6 +2820,10 @@ static void igb_remove(struct pci_dev *pdev)
+@@ -2811,6 +2818,10 @@ static void igb_remove(struct pci_dev *pdev)
  		wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
  	}
  #endif
@@ -43,7 +43,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  
  	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
  	 * would have already happened in close and is redundant.
-@@ -3285,6 +3296,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
+@@ -3283,6 +3294,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
  
  	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
  	wr32(E1000_TXDCTL(reg_idx), txdctl);
@@ -53,7 +53,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  }
  
  /**
-@@ -6354,6 +6368,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
+@@ -6399,6 +6413,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
  
  	if (test_bit(__IGB_DOWN, &adapter->state))
  		return true;
@@ -64,7 +64,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IGB_TX_DESC(tx_ring, i);
-@@ -6914,6 +6932,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
+@@ -6950,6 +6968,10 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
  	unsigned int total_bytes = 0, total_packets = 0;
  	u16 cleaned_count = igb_desc_unused(rx_ring);
  
@@ -75,7 +75,7 @@ index 487cd9c4ac0d..706d0cbeb75b 100644
  	while (likely(total_packets < budget)) {
  		union e1000_adv_rx_desc *rx_desc;
  
-@@ -7031,6 +7053,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
+@@ -7067,6 +7089,11 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
  	struct igb_rx_buffer *bi;
  	u16 i = rx_ring->next_to_use;
  
diff --git a/LINUX/final-patches/vanilla--igc--50600--99999 b/LINUX/final-patches/vanilla--igc--50600--61300
similarity index 100%
rename from LINUX/final-patches/vanilla--igc--50600--99999
rename to LINUX/final-patches/vanilla--igc--50600--61300
diff --git a/LINUX/final-patches/vanilla--ixgbe--31200--31300 b/LINUX/final-patches/vanilla--ixgbe--31200--31300
deleted file mode 100644
index 7947b9ba0..000000000
--- a/LINUX/final-patches/vanilla--ixgbe--31200--31300
+++ /dev/null
@@ -1,124 +0,0 @@
-diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index cc51554c9e99..a88dfd15d9d4 100644
---- a/ixgbe/ixgbe_main.c
-+++ b/ixgbe/ixgbe_main.c
-@@ -443,6 +443,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
- 	{ .name = NULL }
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#include 
-+#endif
- 
- /*
-  * ixgbe_regdump - register printout routine
-@@ -1068,6 +1084,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
- 	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return 1; /* seems to be ignored */
-+#endif /* DEV_NETMAP */
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBE_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -1991,6 +2018,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
- #endif /* IXGBE_FCOE */
- 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 		struct sk_buff *skb;
-@@ -3013,6 +3050,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
- 
- 	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	/* enable queue */
- 	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
- 
-@@ -3393,6 +3434,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
- 
- 	ixgbe_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
- }
- 
-@@ -4706,6 +4751,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
- 			e_crit(drv, "Fan has stopped, replace the adapter\n");
- 	}
- 
-+	/* enable transmits */
-+	netif_tx_start_all_queues(adapter->netdev);
-+
- 	/* bring the link up in the watchdog, this could race with our first
- 	 * link up interrupt but shouldn't be a problem */
- 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5518,6 +5566,7 @@ static int ixgbe_open(struct net_device *netdev)
- 
- 	ixgbe_up_complete(adapter);
- 
-+
- 	return 0;
- 
- err_set_queues:
-@@ -8364,6 +8413,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
- 			true);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -8402,6 +8455,10 @@ static void ixgbe_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = adapter->netdev;
- 	bool disable_dev;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	ixgbe_dbg_adapter_exit(adapter);
- 
- 	set_bit(__IXGBE_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--ixgbe--31300--40900 b/LINUX/final-patches/vanilla--ixgbe--40000--40900
similarity index 82%
rename from LINUX/final-patches/vanilla--ixgbe--31300--40900
rename to LINUX/final-patches/vanilla--ixgbe--40000--40900
index 97909dd2e..3b406348f 100644
--- a/LINUX/final-patches/vanilla--ixgbe--31300--40900
+++ b/LINUX/final-patches/vanilla--ixgbe--40000--40900
@@ -1,8 +1,8 @@
 diff --git a/ixgbe/ixgbe_main.c b/ixgbe/ixgbe_main.c
-index 67b02bde179e..ba3e46d70c49 100644
+index 70cc4c5c0a01..5ad76a0d3494 100644
 --- a/ixgbe/ixgbe_main.c
 +++ b/ixgbe/ixgbe_main.c
-@@ -458,6 +458,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+@@ -459,6 +459,22 @@ static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
  	{ .name = NULL }
  };
  
@@ -25,7 +25,7 @@ index 67b02bde179e..ba3e46d70c49 100644
  
  /*
   * ixgbe_regdump - register printout routine
-@@ -1087,6 +1103,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
+@@ -1088,6 +1104,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
  	if (test_bit(__IXGBE_DOWN, &adapter->state))
  		return true;
  
@@ -43,7 +43,7 @@ index 67b02bde179e..ba3e46d70c49 100644
  	tx_buffer = &tx_ring->tx_buffer_info[i];
  	tx_desc = IXGBE_TX_DESC(tx_ring, i);
  	i -= tx_ring->count;
-@@ -1997,6 +2024,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+@@ -2018,6 +2045,16 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
  #endif /* IXGBE_FCOE */
  	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
  
@@ -60,7 +60,7 @@ index 67b02bde179e..ba3e46d70c49 100644
  	while (likely(total_rx_packets < budget)) {
  		union ixgbe_adv_rx_desc *rx_desc;
  		struct sk_buff *skb;
-@@ -3034,6 +3071,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+@@ -3055,6 +3092,10 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
  
  	clear_bit(__IXGBE_HANG_CHECK_ARMED, &ring->state);
  
@@ -71,7 +71,7 @@ index 67b02bde179e..ba3e46d70c49 100644
  	/* enable queue */
  	IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
  
-@@ -3483,6 +3524,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+@@ -3504,6 +3545,10 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
  	IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
  
  	ixgbe_rx_desc_queue_enable(adapter, ring);
@@ -82,7 +82,7 @@ index 67b02bde179e..ba3e46d70c49 100644
  	ixgbe_alloc_rx_buffers(ring, ixgbe_desc_unused(ring));
  }
  
-@@ -4805,6 +4850,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
+@@ -4840,6 +4885,9 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
@@ -92,15 +92,15 @@ index 67b02bde179e..ba3e46d70c49 100644
  	/* bring the link up in the watchdog, this could race with our first
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
-@@ -5627,6 +5675,7 @@ static int ixgbe_open(struct net_device *netdev)
+@@ -5714,6 +5762,7 @@ static int ixgbe_close(struct net_device *netdev)
  
- 	ixgbe_up_complete(adapter);
+ 	ixgbe_release_hw_control(adapter);
  
 +
  	return 0;
+ }
  
- err_set_queues:
-@@ -8521,6 +8570,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8629,6 +8678,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  			IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
  			true);
  
@@ -111,7 +111,7 @@ index 67b02bde179e..ba3e46d70c49 100644
  	return 0;
  
  err_register:
-@@ -8564,6 +8617,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
+@@ -8672,6 +8725,11 @@ static void ixgbe_remove(struct pci_dev *pdev)
  		return;
  
  	netdev  = adapter->netdev;
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31200--31300 b/LINUX/final-patches/vanilla--ixgbevf--31200--31300
deleted file mode 100644
index cffd903e3..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--31200--31300
+++ /dev/null
@@ -1,110 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 030a219c85e3..07adcf8211df 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -219,6 +219,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -237,6 +255,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -492,6 +522,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	int cleaned_count = 0;
- 	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	i = rx_ring->next_to_clean;
- 	rx_desc = IXGBEVF_RX_DESC(rx_ring, i);
- 	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-@@ -1199,6 +1239,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
- 		  32;          /* PTHRESH = 32 */
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
- 
- 	/* poll to verify queue is enabled */
-@@ -1381,6 +1425,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
- 
- 	ixgbevf_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
- }
- 
-@@ -3598,6 +3646,11 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 	hw_dbg(hw, "MAC: %d\n", hw->mac.type);
- 
- 	hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
-+
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -3630,6 +3683,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	struct net_device *netdev = pci_get_drvdata(pdev);
- 	struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
- 
- 	del_timer_sync(&adapter->watchdog_timer);
diff --git a/LINUX/final-patches/vanilla--ixgbevf--31300--40000 b/LINUX/final-patches/vanilla--ixgbevf--31300--40000
deleted file mode 100644
index 1a74b70dc..000000000
--- a/LINUX/final-patches/vanilla--ixgbevf--31300--40000
+++ /dev/null
@@ -1,109 +0,0 @@
-diff --git a/ixgbevf/ixgbevf_main.c b/ixgbevf/ixgbevf_main.c
-index 38c7a0be8197..ce0c37370f07 100644
---- a/ixgbevf/ixgbevf_main.c
-+++ b/ixgbevf/ixgbevf_main.c
-@@ -208,6 +208,24 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
- 
- static void ixgbevf_tx_timeout(struct net_device *netdev);
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+/*
-+ * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to
-+ * be a reference on how to implement netmap support in a driver.
-+ * Additional comments are in ixgbe_netmap_linux.h .
-+ *
-+ * The code is originally developed on FreeBSD and in the interest
-+ * of maintainability we try to limit differences between the two systems.
-+ *
-+ *  contains functions for netmap support
-+ * that extend the standard driver.
-+ * It also defines DEV_NETMAP so further conditional sections use
-+ * that instead of CONFIG_NETMAP
-+ */
-+#define NM_IXGBEVF
-+#include 
-+#endif
-+
- /**
-  * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
-  * @q_vector: board private structure
-@@ -226,6 +244,18 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
- 	if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- 		return true;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * In netmap mode, all the work is done in the context
-+	 * of the client thread. Interrupt handlers only wake up
-+	 * clients, which may be sleeping on individual rings
-+	 * or on a global resource for all rings.
-+	 */
-+	if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index) != NM_IRQ_PASS)
-+		return true;
-+#endif /* DEV_NETMAP */
-+
-+
- 	tx_buffer = &tx_ring->tx_buffer_info[i];
- 	tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
- 	i -= tx_ring->count;
-@@ -806,6 +836,16 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
- 	u16 cleaned_count = ixgbevf_desc_unused(rx_ring);
- 	struct sk_buff *skb = rx_ring->skb;
- 
-+#ifdef DEV_NETMAP
-+	/*
-+	 * 	 Same as the txeof routine: only wakeup clients on intr.
-+	 */
-+	int dummy, nm_irq;
-+	nm_irq = netmap_rx_irq(rx_ring->netdev, rx_ring->queue_index, &dummy);
-+	if (nm_irq != NM_IRQ_PASS)
-+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
-+#endif /* DEV_NETMAP */
-+
- 	while (likely(total_rx_packets < budget)) {
- 		union ixgbe_adv_rx_desc *rx_desc;
- 
-@@ -1479,6 +1519,10 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
- 	txdctl |= (1 << 8) |    /* HTHRESH = 1 */
- 		  32;          /* PTHRESH = 32 */
- 
-+#ifdef DEV_NETMAP
-+	txdctl = ixgbe_netmap_configure_tx_ring(adapter, reg_idx, txdctl);
-+#endif /* DEV_NETMAP */
-+
- 	IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
- 
- 	/* poll to verify queue is enabled */
-@@ -1624,6 +1668,10 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
- 	IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(reg_idx), rxdctl);
- 
- 	ixgbevf_rx_desc_queue_enable(adapter, ring);
-+#ifdef DEV_NETMAP
-+	if (ixgbe_netmap_configure_rx_ring(adapter, reg_idx))
-+		return;
-+#endif /* DEV_NETMAP */
- 	ixgbevf_alloc_rx_buffers(ring, ixgbevf_desc_unused(ring));
- }
- 
-@@ -3877,6 +3925,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- 		break;
- 	}
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_attach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	return 0;
- 
- err_register:
-@@ -3914,6 +3966,10 @@ static void ixgbevf_remove(struct pci_dev *pdev)
- 	if (!netdev)
- 		return;
- 
-+#ifdef DEV_NETMAP
-+	ixgbe_netmap_detach(adapter);
-+#endif /* DEV_NETMAP */
-+
- 	adapter = netdev_priv(netdev);
- 
- 	set_bit(__IXGBEVF_REMOVING, &adapter->state);
diff --git a/LINUX/final-patches/vanilla--veth.c--31200--41300 b/LINUX/final-patches/vanilla--veth.c--40000--41300
similarity index 94%
rename from LINUX/final-patches/vanilla--veth.c--31200--41300
rename to LINUX/final-patches/vanilla--veth.c--40000--41300
index af7140d45..bdd96ac12 100644
--- a/LINUX/final-patches/vanilla--veth.c--31200--41300
+++ b/LINUX/final-patches/vanilla--veth.c--40000--41300
@@ -1,5 +1,5 @@
 diff --git a/veth.c b/veth.c
-index 8ad596573d17..a3cf12c2ede6 100644
+index 4cca36ebc4fb..54502397b5ac 100644
 --- a/veth.c
 +++ b/veth.c
 @@ -37,6 +37,10 @@ struct veth_priv {
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31200--31300 b/LINUX/final-patches/vanilla--virtio_net.c--31200--31300
deleted file mode 100644
index 05c27ed6f..000000000
--- a/LINUX/final-patches/vanilla--virtio_net.c--31200--31300
+++ /dev/null
@@ -1,87 +0,0 @@
-diff --git a/virtio_net.c b/virtio_net.c
-index b0bc8ead47de..ef1a06d54185 100644
---- a/virtio_net.c
-+++ b/virtio_net.c
-@@ -139,6 +139,10 @@ struct virtnet_info {
- 	struct notifier_block nb;
- };
- 
-+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
-+#include 
-+#endif
-+
- struct skb_vnet_hdr {
- 	union {
- 		struct virtio_net_hdr hdr;
-@@ -218,6 +222,10 @@ static void skb_xmit_done(struct virtqueue *vq)
- 	/* Suppress further interrupts. */
- 	virtqueue_disable_cb(vq);
- 
-+#ifdef DEV_NETMAP
-+        if (netmap_tx_irq(vi->dev, vq2txq(vq)))
-+		return;
-+#endif
- 	/* We were probably waiting for more output buffers. */
- 	netif_wake_subqueue(vi->dev, vq2txq(vq));
- }
-@@ -759,6 +767,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
- 		container_of(napi, struct receive_queue, napi);
- 	unsigned int r, received = 0;
- 
-+#ifdef DEV_NETMAP
-+        int work_done = 0;
-+	struct virtnet_info *vi = rq->vq->vdev->priv;
-+	int nm_irq = netmap_rx_irq(vi->dev, vq2rxq(rq->vq), &work_done);
-+
-+	if (nm_irq == NM_IRQ_COMPLETED) {
-+		napi_complete(napi);
-+                return 1;
-+        } else if (nm_irq == NM_IRQ_RESCHED) {
-+		return budget;
-+	}
-+#endif
-+
- again:
- 	received += virtnet_receive(rq, budget - received);
- 
-@@ -818,8 +839,14 @@ static int virtnet_open(struct net_device *dev)
- {
- 	struct virtnet_info *vi = netdev_priv(dev);
- 	int i;
-+#ifdef DEV_NETMAP
-+        int ok = virtio_netmap_init_buffers(vi);
-+#endif
- 
- 	for (i = 0; i < vi->max_queue_pairs; i++) {
-+#ifdef DEV_NETMAP
-+		if (!ok)
-+#endif
- 		if (i < vi->curr_queue_pairs)
- 			/* Make sure we have some buffers: if oom use wq. */
- 			if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
-@@ -1862,6 +1889,10 @@ static int virtnet_probe(struct virtio_device *vdev)
- 		goto free_recv_bufs;
- 	}
- 
-+#ifdef DEV_NETMAP
-+        virtio_netmap_attach(vi);
-+#endif
-+
- 	/* Assume link up if device can't report link status,
- 	   otherwise get link status from config. */
- 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1910,7 +1941,14 @@ static void remove_vq_common(struct virtnet_info *vi)
- static void virtnet_remove(struct virtio_device *vdev)
- {
- 	struct virtnet_info *vi = vdev->priv;
-+#ifdef DEV_NETMAP
-+	/* Save the pointer, will go away after netmap_detach(). */
-+	struct netmap_adapter *token = NA(vi->dev);
- 
-+	netmap_detach(vi->dev);
-+	virtio_netmap_clean_used_rings(vi, token);
-+	virtio_netmap_reclaim_unused(vi);
-+#endif
- 	unregister_hotcpu_notifier(&vi->nb);
- 
- 	/* Make sure no work handler is accessing the device. */
diff --git a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100 b/LINUX/final-patches/vanilla--virtio_net.c--40000--40100
similarity index 93%
rename from LINUX/final-patches/vanilla--virtio_net.c--31300--40100
rename to LINUX/final-patches/vanilla--virtio_net.c--40000--40100
index e6caac237..70dd5ce36 100644
--- a/LINUX/final-patches/vanilla--virtio_net.c--31300--40100
+++ b/LINUX/final-patches/vanilla--virtio_net.c--40000--40100
@@ -1,5 +1,5 @@
 diff --git a/virtio_net.c b/virtio_net.c
-index 059fdf1bf5ee..8c97bc74d8a5 100644
+index 59b0e9754ae3..96597c5617e5 100644
 --- a/virtio_net.c
 +++ b/virtio_net.c
 @@ -142,6 +142,10 @@ struct virtnet_info {
@@ -59,7 +59,7 @@ index 059fdf1bf5ee..8c97bc74d8a5 100644
  		if (i < vi->curr_queue_pairs)
  			/* Make sure we have some buffers: if oom use wq. */
  			if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
-@@ -1859,6 +1886,10 @@ static int virtnet_probe(struct virtio_device *vdev)
+@@ -1873,6 +1900,10 @@ static int virtnet_probe(struct virtio_device *vdev)
  		goto free_recv_bufs;
  	}
  
@@ -70,7 +70,7 @@ index 059fdf1bf5ee..8c97bc74d8a5 100644
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
-@@ -1907,7 +1938,14 @@ static void remove_vq_common(struct virtnet_info *vi)
+@@ -1921,7 +1952,14 @@ static void remove_vq_common(struct virtnet_info *vi)
  static void virtnet_remove(struct virtio_device *vdev)
  {
  	struct virtnet_info *vi = vdev->priv;
diff --git a/LINUX/final-patches/vanilla--vmxnet3--31200--40d00 b/LINUX/final-patches/vanilla--vmxnet3--40000--40d00
similarity index 90%
rename from LINUX/final-patches/vanilla--vmxnet3--31200--40d00
rename to LINUX/final-patches/vanilla--vmxnet3--40000--40d00
index fd9b11b90..a087ef13c 100644
--- a/LINUX/final-patches/vanilla--vmxnet3--31200--40d00
+++ b/LINUX/final-patches/vanilla--vmxnet3--40000--40d00
@@ -1,7 +1,7 @@
 diff --git a/vmxnet3/vmxnet3_drv.c b/vmxnet3/vmxnet3_drv.c
 old mode 100644
 new mode 100755
-index 6dfcbf523936..2d2f4a669aca
+index 294214c15292..c6d334b8d096
 --- a/vmxnet3/vmxnet3_drv.c
 +++ b/vmxnet3/vmxnet3_drv.c
 @@ -308,6 +308,11 @@ static u32 get_bitfield32(const __le32 *bitfield, u32 pos, u32 size)
@@ -47,7 +47,7 @@ index 6dfcbf523936..2d2f4a669aca
  	vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
  			  &rxComp);
  	while (rcd->gen == rq->comp_ring.gen) {
-@@ -2263,6 +2285,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
+@@ -2256,6 +2278,10 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
  		adapter->rx_queue[0].rx_ring[0].size,
  		adapter->rx_queue[0].rx_ring[1].size);
  
@@ -58,7 +58,7 @@ index 6dfcbf523936..2d2f4a669aca
  	vmxnet3_tq_init_all(adapter);
  	err = vmxnet3_rq_init_all(adapter);
  	if (err) {
-@@ -3104,6 +3130,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
+@@ -3101,6 +3127,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
  		goto err_register;
  	}
  
@@ -70,7 +70,7 @@ index 6dfcbf523936..2d2f4a669aca
  	vmxnet3_check_link(adapter, false);
  	return 0;
  
-@@ -3155,6 +3186,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
+@@ -3152,6 +3183,10 @@ vmxnet3_remove_device(struct pci_dev *pdev)
  
  	unregister_netdev(netdev);
  

From 3a18ae4774ac09b78fd8ec16ed163fad7d42223f Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Dec 2023 18:09:11 +0100
Subject: [PATCH 2195/2207] linux: netmap sync: pretend offsets are supported

---
 LINUX/netmap_linux.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index cd5a5b7ff..4b1b3f6c0 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2280,6 +2280,7 @@ netmap_sink_init(void)
 		na.nm_txsync = nm_sink_txsync;
 		na.nm_rxsync = nm_sink_rxsync;
 		na.num_tx_rings = na.num_rx_rings = 1;
+		na.na_flags = NAF_OFFSETS;
 		if (netmap_attach_ext(&na, sizeof(struct netmap_sink_adapter), 1)) {
 			dev_err(&netdev->dev, "failed to attach netmap adapter");
 			unregister_netdev(netdev);

From adfc085136a78a5bde4e5780b6761632bf1d3223 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 27 Mar 2024 08:22:19 +0100
Subject: [PATCH 2196/2207] sink: pretend MOREFRAG is supported

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4b1b3f6c0..3c470838e 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -2280,7 +2280,7 @@ netmap_sink_init(void)
 		na.nm_txsync = nm_sink_txsync;
 		na.nm_rxsync = nm_sink_rxsync;
 		na.num_tx_rings = na.num_rx_rings = 1;
-		na.na_flags = NAF_OFFSETS;
+		na.na_flags = NAF_OFFSETS | NAF_MOREFRAG;
 		if (netmap_attach_ext(&na, sizeof(struct netmap_sink_adapter), 1)) {
 			dev_err(&netdev->dev, "failed to attach netmap adapter");
 			unregister_netdev(netdev);

From 201be8dda56632c0f24a8c9cd38f94ff709e257d Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 18 Feb 2025 18:43:11 +0100
Subject: [PATCH 2197/2207] linux/extmem: use FOLL_LONGTERM when available

---
 LINUX/netmap_linux.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 3c470838e..0cc97885f 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -263,6 +263,9 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 {
 #ifndef FOLL_POPULATE
 #define FOLL_POPULATE 0
+#endif /* FOLL_POPULATE */
+#ifndef FOLL_LONGTERM
+#define FOLL_LONGTERM 0
 #endif /* FOLL_POPULATE */
 	unsigned long end, start;
 	int nr_pages, res;
@@ -295,7 +298,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			p,
 			nr_pages,
 			pages,
-			FOLL_WRITE | FOLL_SPLIT | FOLL_POPULATE);
+			FOLL_WRITE | FOLL_SPLIT | FOLL_POPULATE | FOLL_LONGTERM);
 #elif defined(NETMAP_LINUX_HAVE_GUP_4ARGS)
 	res = get_user_pages_unlocked(
 			p,

From ed70ac0a38defb91a4e1364c51a055abfb9278a1 Mon Sep 17 00:00:00 2001
From: Alessandra Fais 
Date: Sat, 29 Nov 2025 09:26:35 +0100
Subject: [PATCH 2198/2207] extmem: return more precise errno on failure

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 0cc97885f..c8c9816e6 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -339,7 +339,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 
 	if (res < nr_pages) {
 		nm_prerr("failed to get user pages: res %d nr_pages %d", res, nr_pages);
-		err = EFAULT;
+		err = (res < 0) ? -res : EFAULT;
 		goto out;
 	}
 

From 2c5c7700a51cedcc951d00fdac000fc22195cd18 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 29 Nov 2025 11:21:20 +0100
Subject: [PATCH 2199/2207] extmem: omit FOLL_SPLIT_PMD from GUP

---
 LINUX/netmap_linux.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index c8c9816e6..4abb05aee 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -298,7 +298,7 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			p,
 			nr_pages,
 			pages,
-			FOLL_WRITE | FOLL_SPLIT | FOLL_POPULATE | FOLL_LONGTERM);
+			FOLL_WRITE | FOLL_POPULATE | FOLL_LONGTERM);
 #elif defined(NETMAP_LINUX_HAVE_GUP_4ARGS)
 	res = get_user_pages_unlocked(
 			p,

From ef8fa11e38f9ae68069d8c0db4163834e646f8d6 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Mon, 1 Dec 2025 18:30:47 +0100
Subject: [PATCH 2200/2207] vale: use offsets only if supported by dst ring

---
 sys/dev/netmap/netmap_vale.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index f5e65f1c0..c014c94f0 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -982,16 +982,18 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 
 					slot = &ring->slot[j];
 					dst = NMB(&dst_na->up, slot);
-					dstoff = nm_get_offset(kring, slot);
-					dstoff_cb = dstoff & ~mask;
 					src_cb = ((uintptr_t)src) & ~mask;
 					src_co = ((uintptr_t)src) & mask;
 					dst_co = ((uintptr_t)(dst + dstoff)) & mask;
-					if (dst_co < src_co) {
-						dstoff_cb += NM_BUF_ALIGN;
+					if (kring->offset_mask) {
+						dstoff = nm_get_offset(kring, slot);
+						dstoff_cb = dstoff & ~mask;
+						if (src_co < dst_co) {
+							dstoff_cb += NM_BUF_ALIGN;
+						}
+						dstoff = dstoff_cb + src_co;
+						copy_len += src_co;
 					}
-					dstoff = dstoff_cb + src_co;
-					copy_len += src_co;
 
 					nm_prdis("send [%d] %d(%d) bytes at %s:%d",
 							i, (int)copy_len, (int)dst_len,
@@ -1010,13 +1012,15 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 							// invalid user pointer, pretend len is 0
 							dst_len = 0;
 						}
-					} else {
+					} else if (!src_co || kring->offset_mask) {
 						//memcpy(dst, src, copy_len);
 						pkt_copy((char *)src_cb, dst + dstoff_cb, (int)copy_len);
+						nm_write_offset(kring, slot, dstoff);
+					} else {
+						memcpy(dst, src, copy_len);
 					}
 					slot->len = dst_len;
 					slot->flags = (cnt << 8)| NS_MOREFRAG;
-					nm_write_offset(kring, slot, dstoff);
 					j = nm_next(j, lim);
 					needed--;
 					ft_p++;

From e0de5b52903de5b39b9481cfea3baf5354b8dd37 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 11 Feb 2026 18:25:26 +0100
Subject: [PATCH 2201/2207] vale: fix computation of destination offset

---
 sys/dev/netmap/netmap_vale.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index c014c94f0..bfb624728 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -976,7 +976,7 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 					char *dst, *src = ft_p->ft_buf;
 					size_t copy_len = ft_p->ft_len, dst_len = copy_len;
 					uintptr_t src_cb;
-					uint64_t dstoff, dstoff_cb;
+					uint64_t dstoff = 0, dstoff_cb = 0;
 					int src_co, dst_co;
 					const uintptr_t mask = NM_BUF_ALIGN - 1;
 
@@ -984,16 +984,14 @@ nm_vale_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na,
 					dst = NMB(&dst_na->up, slot);
 					src_cb = ((uintptr_t)src) & ~mask;
 					src_co = ((uintptr_t)src) & mask;
+					dstoff = nm_get_offset(kring, slot);
+					dstoff_cb = dstoff & ~mask;
 					dst_co = ((uintptr_t)(dst + dstoff)) & mask;
-					if (kring->offset_mask) {
-						dstoff = nm_get_offset(kring, slot);
-						dstoff_cb = dstoff & ~mask;
-						if (src_co < dst_co) {
-							dstoff_cb += NM_BUF_ALIGN;
-						}
-						dstoff = dstoff_cb + src_co;
-						copy_len += src_co;
+					if (src_co < dst_co) {
+						dstoff_cb += NM_BUF_ALIGN;
 					}
+					dstoff = dstoff_cb + src_co;
+					copy_len += src_co;
 
 					nm_prdis("send [%d] %d(%d) bytes at %s:%d",
 							i, (int)copy_len, (int)dst_len,

From 063d399a53bb496576a50ff817e37fd5774b7769 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Wed, 11 Feb 2026 11:16:58 +0100
Subject: [PATCH 2202/2207] linux/configure: add get_user_pages with 6 args

---
 LINUX/configure      | 12 ++++++++++++
 LINUX/netmap_linux.c |  8 ++++++++
 2 files changed, 20 insertions(+)

diff --git a/LINUX/configure b/LINUX/configure
index 0f9db127b..90c56eec6 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -1760,6 +1760,18 @@ EOF
 	}
 EOF
 
+  add_test 'have GUP_6ARGS' <
+
+	long
+	dummy(struct task_struct *tsk, struct mm_struct *mm,
+		unsigned long start, unsigned long nr_pages,
+		struct page **pages, unsigned int gup_flags) {
+		return get_user_pages_unlocked(tsk, mm, start, nr_pages,
+			pages, gup_flags);
+	}
+EOF
+
   add_test 'have GUP_7ARGS' <
 
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index 4abb05aee..ce79c2749 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -312,6 +312,14 @@ nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
 			1, /* write */
 			0, /* don't force */
 			pages);
+#elif defined(NETMAP_LINUX_HAVE_GUP_6ARGS)
+	res = get_user_pages_unlocked(
+			current,
+			current->mm,
+			p,
+			nr_pages,
+			pages,
+			FOLL_WRITE | FOLL_GET | FOLL_SPLIT | FOLL_POPULATE); // XXX check other flags
 #elif defined(NETMAP_LINUX_HAVE_GUP_7ARGS)
 	res = get_user_pages_unlocked(
 			current,

From 609ba105f6360a4fd857583584834126e41a51f8 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Sat, 18 Apr 2026 09:17:08 +0200
Subject: [PATCH 2203/2207] linux: check for sockaddr_unsized

---
 LINUX/configure      | 12 ++++++++++++
 LINUX/netmap_linux.c |  8 +++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/LINUX/configure b/LINUX/configure
index 90c56eec6..c6bedb209 100755
--- a/LINUX/configure
+++ b/LINUX/configure
@@ -2035,6 +2035,18 @@ EOF
 	}
 EOF
 
+  # check for sockaddr_unsized
+  add_test 'have SOCKADDR_UNSIZED' <
+
+	int dummy(struct socket *sock,
+		struct sockaddr_unsized *sa,
+		int sa_len)
+	{
+		return kernel_bind(sock, sa, sa_len);
+	}
+EOF
+
   #####################################################
   # checks related to drivers                         #
   #####################################################
diff --git a/LINUX/netmap_linux.c b/LINUX/netmap_linux.c
index ce79c2749..a5ed20633 100644
--- a/LINUX/netmap_linux.c
+++ b/LINUX/netmap_linux.c
@@ -70,6 +70,12 @@ static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
 #endif /* NETMAP_LINUX_HAVE_VLAN_HWACCESS_PUSH_INSIDE */
 #endif /* NETMAP_LINUX_HAVE_SKB_VLAN_UNTAG */
 
+#ifdef NETMAP_LINUX_HAVE_SOCKADDR_UNSIZED
+#define NM_SOCKADDR sockaddr_unsized
+#else /* !NETMAP_LINUX_HAVE_SOCKADDR_UNSIZED */
+#define NM_SOCKADDR sockaddr
+#endif /* NETMAP_LINUX_HAVE_SOCKADDR_UNSIZED */
+
 void *
 nm_os_malloc(size_t size)
 {
@@ -879,7 +885,7 @@ tc_configure(struct ifnet *ifp, const char *qdisc_name,
 	}
 
 
-	ret = kernel_bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
+	ret = kernel_bind(sock, (struct NM_SOCKADDR *)&saddr, sizeof(saddr));
 	if (ret) {
 		nm_prerr("Failed to bind() netlink socket (err=%d)", ret);
 		goto release;

From 10986ec1479b54552333d4cef913bef3dd159727 Mon Sep 17 00:00:00 2001
From: jhk 
Date: Wed, 29 Apr 2026 23:17:37 +0200
Subject: [PATCH 2204/2207] ctrl-api-test: drop redundant check

---
 utils/ctrl-api-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 969237eb6..2ae418876 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -218,7 +218,7 @@ port_info_get(struct TestContext *ctx)
 	printf("nr_mem_id %u\n", req.nr_mem_id);
 
 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
-	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
+	          req.nr_tx_rings && req.nr_rx_rings;
 	if (!success) {
 		return -1;
 	}

From 5e1bb6e4b3de319b32550f44110bcbbeeafe2af9 Mon Sep 17 00:00:00 2001
From: Giuseppe Lettieri 
Date: Tue, 26 May 2026 17:06:45 +0200
Subject: [PATCH 2205/2207] Add CodeQL analysis workflow configuration

---
 .github/workflows/codeql.yml | 101 +++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)
 create mode 100644 .github/workflows/codeql.yml

diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000..0e73629b8
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,101 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL Advanced"
+
+on:
+  push:
+    branches: [ "master" ]
+  pull_request:
+    branches: [ "master" ]
+  schedule:
+    - cron: '15 11 * * 0'
+
+jobs:
+  analyze:
+    name: Analyze (${{ matrix.language }})
+    # Runner size impacts CodeQL analysis time. To learn more, please see:
+    #   - https://gh.io/recommended-hardware-resources-for-running-codeql
+    #   - https://gh.io/supported-runners-and-hardware-resources
+    #   - https://gh.io/using-larger-runners (GitHub.com only)
+    # Consider using larger runners or machines with greater resources for possible analysis time improvements.
+    runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
+    permissions:
+      # required for all workflows
+      security-events: write
+
+      # required to fetch internal or private CodeQL packs
+      packages: read
+
+      # only required for workflows in private repositories
+      actions: read
+      contents: read
+
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+        - language: c-cpp
+          build-mode: autobuild
+        - language: python
+          build-mode: none
+        # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
+        # Use `c-cpp` to analyze code written in C, C++ or both
+        # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
+        # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+        # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
+        # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
+        # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
+        # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+
+    # Add any setup steps before running the `github/codeql-action/init` action.
+    # This includes steps like installing compilers or runtimes (`actions/setup-node`
+    # or others). This is typically only required for manual builds.
+    # - name: Setup runtime (example)
+    #   uses: actions/setup-example@v1
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v4
+      with:
+        languages: ${{ matrix.language }}
+        build-mode: ${{ matrix.build-mode }}
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file.
+        # Prefix the list here with "+" to use these queries and those in the config file.
+
+        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+        # queries: security-extended,security-and-quality
+
+    # If the analyze step fails for one of the languages you are analyzing with
+    # "We were unable to automatically build your code", modify the matrix above
+    # to set the build mode to "manual" for that language. Then modify this step
+    # to build your code.
+    # â„šī¸ Command-line programs to run using the OS shell.
+    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+    - name: Run manual build steps
+      if: matrix.build-mode == 'manual'
+      shell: bash
+      run: |
+        echo 'If you are using a "manual" build mode for one or more of the' \
+          'languages you are analyzing, replace this with the commands to build' \
+          'your code, for example:'
+        echo '  make bootstrap'
+        echo '  make release'
+        exit 1
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v4
+      with:
+        category: "/language:${{matrix.language}}"

From 40010b25c05e9c6cda05f1b7e1a5d7f990a2b80b Mon Sep 17 00:00:00 2001
From: Jose Luis Duran 
Date: Fri, 10 Jul 2026 10:01:54 +0000
Subject: [PATCH 2206/2207] spdx: The BSD-2-Clause-FreeBSD identifier is
 obsolete, drop -FreeBSD

The SPDX folks have obsoleted the BSD-2-Clause-FreeBSD identifier. Catch
up to that fact and revert to their recommended match of BSD-2-Clause.
---
 libnetmap/libnetmap.h               | 2 +-
 libnetmap/nmctx-pthreads.c          | 2 +-
 libnetmap/nmctx.c                   | 2 +-
 libnetmap/nmport.c                  | 2 +-
 libnetmap/nmreq.c                   | 2 +-
 sys/dev/netmap/if_em_netmap.h       | 2 +-
 sys/dev/netmap/if_igb_netmap.h      | 2 +-
 sys/dev/netmap/if_lem_netmap.h      | 2 +-
 sys/dev/netmap/if_re_netmap.h       | 2 +-
 sys/dev/netmap/ixgbe_netmap.h       | 2 +-
 sys/dev/netmap/netmap.c             | 2 +-
 sys/dev/netmap/netmap_bdg.h         | 2 +-
 sys/dev/netmap/netmap_freebsd.c     | 2 +-
 sys/dev/netmap/netmap_generic.c     | 2 +-
 sys/dev/netmap/netmap_kern.h        | 2 +-
 sys/dev/netmap/netmap_legacy.c      | 2 +-
 sys/dev/netmap/netmap_mbq.c         | 2 +-
 sys/dev/netmap/netmap_mbq.h         | 2 +-
 sys/dev/netmap/netmap_mem2.c        | 2 +-
 sys/dev/netmap/netmap_mem2.h        | 2 +-
 sys/dev/netmap/netmap_offloadings.c | 2 +-
 sys/dev/netmap/netmap_pipe.c        | 2 +-
 sys/dev/netmap/netmap_vale.c        | 2 +-
 sys/net/netmap.h                    | 2 +-
 sys/net/netmap_legacy.h             | 2 +-
 sys/net/netmap_user.h               | 2 +-
 utils/ctrl-api-test.c               | 2 +-
 27 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/libnetmap/libnetmap.h b/libnetmap/libnetmap.h
index 62fa36996..280132035 100644
--- a/libnetmap/libnetmap.h
+++ b/libnetmap/libnetmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Universita` di Pisa
  * All rights reserved.
diff --git a/libnetmap/nmctx-pthreads.c b/libnetmap/nmctx-pthreads.c
index 2943b7ccc..fdad20c7c 100644
--- a/libnetmap/nmctx-pthreads.c
+++ b/libnetmap/nmctx-pthreads.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Universita` di Pisa
  * All rights reserved.
diff --git a/libnetmap/nmctx.c b/libnetmap/nmctx.c
index 489988f33..fe83b8864 100644
--- a/libnetmap/nmctx.c
+++ b/libnetmap/nmctx.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Universita` di Pisa
  * All rights reserved.
diff --git a/libnetmap/nmport.c b/libnetmap/nmport.c
index 80690a7f8..c892c94db 100644
--- a/libnetmap/nmport.c
+++ b/libnetmap/nmport.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Universita` di Pisa
  * All rights reserved.
diff --git a/libnetmap/nmreq.c b/libnetmap/nmreq.c
index f5d4605ed..a083099f0 100644
--- a/libnetmap/nmreq.c
+++ b/libnetmap/nmreq.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Universita` di Pisa
  * All rights reserved.
diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index a3987b92b..d1ec2c32b 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index 8ae54e54a..5f351edf6 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved.
  *
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index 46b168c40..4867c4f9f 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index d658a3e5c..236cd904f 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Luigi Rizzo. All rights reserved.
  *
diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h
index feac9da1b..120b19366 100644
--- a/sys/dev/netmap/ixgbe_netmap.h
+++ b/sys/dev/netmap/ixgbe_netmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 53e288a1d..c22b66a72 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi
  * Copyright (C) 2011-2016 Luigi Rizzo
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index f5148c740..688a6fbde 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2013-2018 Universita` di Pisa
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 4b3b1a6ed..b57687963 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved.
  *
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index eb98f0053..4dea40554 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2013-2016 Vincenzo Maffione
  * Copyright (C) 2013-2016 Luigi Rizzo
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index 7bab5e2bb..c52bd03a0 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo
  * Copyright (C) 2013-2016 Universita` di Pisa
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 3f676fccf..658a1c223 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Vincenzo Maffione
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_mbq.c b/sys/dev/netmap/netmap_mbq.c
index 3ce73f0e0..0c8ed17c7 100644
--- a/sys/dev/netmap/netmap_mbq.c
+++ b/sys/dev/netmap/netmap_mbq.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2013-2014 Vincenzo Maffione
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_mbq.h b/sys/dev/netmap/netmap_mbq.h
index 044cb54bb..2db14cc10 100644
--- a/sys/dev/netmap/netmap_mbq.h
+++ b/sys/dev/netmap/netmap_mbq.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2013-2014 Vincenzo Maffione
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index 1b290c966..dd3b95d8e 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2012-2014 Matteo Landi
  * Copyright (C) 2012-2016 Luigi Rizzo
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 036e44d1b..53e7f2b0c 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2012-2014 Matteo Landi
  * Copyright (C) 2012-2016 Luigi Rizzo
diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index a6ff8b00a..745f5f401 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2014-2015 Vincenzo Maffione
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index 91cad5201..ab2d591df 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2014-2018 Giuseppe Lettieri
  * All rights reserved.
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index bfb624728..199731af6 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2013-2016 Universita` di Pisa
  * All rights reserved.
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index 241cd7bde..bd99d2157 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index f1dd7d625..042a42985 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
  *
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index e8983565d..526953916 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2011-2016 Universita` di Pisa
  * All rights reserved.
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 2ae418876..7ee29c6f0 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -1,5 +1,5 @@
 /*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
  *
  * Copyright (C) 2018 Vincenzo Maffione
  *

From a21a20858cf71536493b8f494ede7c16ab73013c Mon Sep 17 00:00:00 2001
From: Jose Luis Duran 
Date: Fri, 10 Jul 2026 10:21:11 +0000
Subject: [PATCH 2207/2207] Remove $FreeBSD$: one/two-line pattern

Remove /^\s*\*+\s*\$FreeBSD\$.*$\n/
Remove /^\s*\*\n \*\s+\$FreeBSD\$$\n/
---
 LINUX/i40e_netmap_linux.h           | 2 --
 LINUX/ixgbe_netmap_linux.h          | 2 --
 WINDOWS/includes/net/ethernet.h     | 3 ---
 WINDOWS/includes/net/if_dl.h        | 1 -
 apps/bridge/bridge.8                | 2 --
 apps/bridge/bridge.c                | 2 --
 apps/include/ctrs.h                 | 2 --
 apps/lb/lb.8                        | 2 --
 apps/lb/lb.c                        | 1 -
 apps/lb/pkt_hash.c                  | 1 -
 apps/lb/pkt_hash.h                  | 1 -
 apps/nmreplay/nmreplay.8            | 2 --
 apps/nmreplay/nmreplay.c            | 2 --
 apps/pkt-gen/pkt-gen.8              | 2 --
 apps/pkt-gen/pkt-gen.c              | 1 -
 apps/tlem/tlem.8                    | 2 --
 apps/vale-ctl/vale-ctl.4            | 2 --
 apps/vale-ctl/vale-ctl.c            | 2 --
 share/man/man4/netmap.4             | 2 --
 share/man/man4/ptnet.4              | 2 --
 share/man/man4/vale.4               | 1 -
 sys/dev/netmap/if_em_netmap.h       | 2 --
 sys/dev/netmap/if_igb_netmap.h      | 2 --
 sys/dev/netmap/if_ixl_netmap.h      | 2 --
 sys/dev/netmap/if_lem_netmap.h      | 2 --
 sys/dev/netmap/if_ptnet.c           | 2 --
 sys/dev/netmap/if_re_netmap.h       | 2 --
 sys/dev/netmap/if_vtnet_netmap.h    | 4 ----
 sys/dev/netmap/ixgbe_netmap.h       | 2 --
 sys/dev/netmap/netmap.c             | 2 --
 sys/dev/netmap/netmap_bdg.c         | 2 --
 sys/dev/netmap/netmap_bdg.h         | 2 --
 sys/dev/netmap/netmap_freebsd.c     | 1 -
 sys/dev/netmap/netmap_generic.c     | 2 --
 sys/dev/netmap/netmap_kern.h        | 2 --
 sys/dev/netmap/netmap_kloop.c       | 2 --
 sys/dev/netmap/netmap_legacy.c      | 2 --
 sys/dev/netmap/netmap_mbq.c         | 5 -----
 sys/dev/netmap/netmap_mbq.h         | 5 -----
 sys/dev/netmap/netmap_mem2.c        | 2 --
 sys/dev/netmap/netmap_mem2.h        | 2 --
 sys/dev/netmap/netmap_monitor.c     | 2 --
 sys/dev/netmap/netmap_null.c        | 1 -
 sys/dev/netmap/netmap_offloadings.c | 2 --
 sys/dev/netmap/netmap_pipe.c        | 2 --
 sys/dev/netmap/netmap_vale.c        | 2 --
 sys/modules/netmap/Makefile         | 2 --
 sys/net/netmap.h                    | 2 --
 sys/net/netmap_legacy.h             | 2 --
 sys/net/netmap_user.h               | 2 --
 sys/net/netmap_virt.h               | 2 --
 utils/README                        | 2 --
 utils/click-test.cfg                | 2 --
 utils/ctrl-api-test.c               | 2 --
 54 files changed, 109 deletions(-)

diff --git a/LINUX/i40e_netmap_linux.h b/LINUX/i40e_netmap_linux.h
index 9ccd7d53c..76ec22187 100644
--- a/LINUX/i40e_netmap_linux.h
+++ b/LINUX/i40e_netmap_linux.h
@@ -24,8 +24,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * netmap support for: i40e (LINUX version)
  *
  * derived from ixgbe
diff --git a/LINUX/ixgbe_netmap_linux.h b/LINUX/ixgbe_netmap_linux.h
index 64a4b70ef..7d0f86b15 100644
--- a/LINUX/ixgbe_netmap_linux.h
+++ b/LINUX/ixgbe_netmap_linux.h
@@ -24,8 +24,6 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/ixgbe_netmap.h 230572 2012-01-26 09:55:16Z luigi $
- *
  * netmap support for: ixgbe (LINUX version)
  *
  * This file is meant to be a reference on how to implement
diff --git a/WINDOWS/includes/net/ethernet.h b/WINDOWS/includes/net/ethernet.h
index dc0f635c2..a677a8a17 100644
--- a/WINDOWS/includes/net/ethernet.h
+++ b/WINDOWS/includes/net/ethernet.h
@@ -1,8 +1,5 @@
 /*
  * Fundamental constants relating to ethernet.
- *
- * $FreeBSD: head/sys/net/ethernet.h 249925 2013-04-26 12:50:32Z glebius $
- *
  */
 
 #ifndef _NET_ETHERNET_H_
diff --git a/WINDOWS/includes/net/if_dl.h b/WINDOWS/includes/net/if_dl.h
index 4d2b4f743..cfad7acb5 100644
--- a/WINDOWS/includes/net/if_dl.h
+++ b/WINDOWS/includes/net/if_dl.h
@@ -27,7 +27,6 @@
  * SUCH DAMAGE.
  *
  *	@(#)if_dl.h	8.1 (Berkeley) 6/10/93
- * $FreeBSD: src/sys/net/if_dl.h,v 1.14 2005/01/07 01:45:34 imp Exp $
  */
 
 #ifndef _NET_IF_DL_H_
diff --git a/apps/bridge/bridge.8 b/apps/bridge/bridge.8
index b6314ece6..d3720ff45 100644
--- a/apps/bridge/bridge.8
+++ b/apps/bridge/bridge.8
@@ -21,8 +21,6 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd November 21, 2020
 .Dt BRIDGE 8
 .Os
diff --git a/apps/bridge/bridge.c b/apps/bridge/bridge.c
index 6bd8809b8..b8c6e786a 100644
--- a/apps/bridge/bridge.c
+++ b/apps/bridge/bridge.c
@@ -5,8 +5,6 @@
  *
  * A netmap application to bridge two network interfaces,
  * or one interface and the host stack.
- *
- * $FreeBSD$
  */
 
 #include 
diff --git a/apps/include/ctrs.h b/apps/include/ctrs.h
index 7e0265b48..49fb6a652 100644
--- a/apps/include/ctrs.h
+++ b/apps/include/ctrs.h
@@ -1,8 +1,6 @@
 #ifndef CTRS_H_
 #define CTRS_H_
 
-/* $FreeBSD$ */
-
 #include 
 #include 
 #include 
diff --git a/apps/lb/lb.8 b/apps/lb/lb.8
index 91694cb9b..b0d674e8c 100644
--- a/apps/lb/lb.8
+++ b/apps/lb/lb.8
@@ -22,8 +22,6 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd October 28, 2018
 .Dt LB 8
 .Os
diff --git a/apps/lb/lb.c b/apps/lb/lb.c
index 778360d9e..91affce58 100644
--- a/apps/lb/lb.c
+++ b/apps/lb/lb.c
@@ -22,7 +22,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-/* $FreeBSD$ */
 #include 
 #include 
 #include 
diff --git a/apps/lb/pkt_hash.c b/apps/lb/pkt_hash.c
index a5b2e7102..643f6398a 100644
--- a/apps/lb/pkt_hash.c
+++ b/apps/lb/pkt_hash.c
@@ -25,7 +25,6 @@
  ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  ** POSSIBILITY OF SUCH DAMAGE.
  **/
-/* $FreeBSD$ */
 
 /* for func prototypes */
 #include "pkt_hash.h"
diff --git a/apps/lb/pkt_hash.h b/apps/lb/pkt_hash.h
index 7371f0740..1f73ff97e 100644
--- a/apps/lb/pkt_hash.h
+++ b/apps/lb/pkt_hash.h
@@ -25,7 +25,6 @@
  ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  ** POSSIBILITY OF SUCH DAMAGE.
  **/
-/* $FreeBSD$ */
 #ifndef LB_PKT_HASH_H
 #define LB_PKT_HASH_H
 /*---------------------------------------------------------------------*/
diff --git a/apps/nmreplay/nmreplay.8 b/apps/nmreplay/nmreplay.8
index 8b7ffae5a..5307ec6f7 100644
--- a/apps/nmreplay/nmreplay.8
+++ b/apps/nmreplay/nmreplay.8
@@ -22,8 +22,6 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd December 21, 2018
 .Dt NMREPLAY 8
 .Os
diff --git a/apps/nmreplay/nmreplay.c b/apps/nmreplay/nmreplay.c
index 1ccfb6e31..54e5dae1f 100644
--- a/apps/nmreplay/nmreplay.c
+++ b/apps/nmreplay/nmreplay.c
@@ -21,8 +21,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
 
diff --git a/apps/pkt-gen/pkt-gen.8 b/apps/pkt-gen/pkt-gen.8
index 2a80f160b..83643d749 100644
--- a/apps/pkt-gen/pkt-gen.8
+++ b/apps/pkt-gen/pkt-gen.8
@@ -23,8 +23,6 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd April 21, 2023
 .Dt PKT-GEN 8
 .Os
diff --git a/apps/pkt-gen/pkt-gen.c b/apps/pkt-gen/pkt-gen.c
index 621e3e215..c17579a14 100644
--- a/apps/pkt-gen/pkt-gen.c
+++ b/apps/pkt-gen/pkt-gen.c
@@ -25,7 +25,6 @@
  */
 
 /*
- * $FreeBSD$
  * $Id: pkt-gen.c 12346 2013-06-12 17:36:25Z luigi $
  *
  * Example program to show how to build a multithreaded packet
diff --git a/apps/tlem/tlem.8 b/apps/tlem/tlem.8
index f5b600a3f..fa8c9841c 100644
--- a/apps/tlem/tlem.8
+++ b/apps/tlem/tlem.8
@@ -22,8 +22,6 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd February 13, 2020
 .Dt TLEM 1
 .Os
diff --git a/apps/vale-ctl/vale-ctl.4 b/apps/vale-ctl/vale-ctl.4
index a2ea6d693..0bfaea955 100644
--- a/apps/vale-ctl/vale-ctl.4
+++ b/apps/vale-ctl/vale-ctl.4
@@ -22,8 +22,6 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd March 31, 2020
 .Dt VALE-CTL 4
 .Os
diff --git a/apps/vale-ctl/vale-ctl.c b/apps/vale-ctl/vale-ctl.c
index bf1bc6229..1b8d74e61 100644
--- a/apps/vale-ctl/vale-ctl.c
+++ b/apps/vale-ctl/vale-ctl.c
@@ -23,8 +23,6 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD$ */
-
 #define LIBNETMAP_NOTHREADSAFE
 #include 
 
diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4
index 9ea100f02..3efa34c29 100644
--- a/share/man/man4/netmap.4
+++ b/share/man/man4/netmap.4
@@ -25,8 +25,6 @@
 .\" This document is derived in part from the enet man page (enet.4)
 .\" distributed with 4.3BSD Unix.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd October 3, 2020
 .Dt NETMAP 4
 .Os
diff --git a/share/man/man4/ptnet.4 b/share/man/man4/ptnet.4
index b4a1a5379..71efb3cdd 100644
--- a/share/man/man4/ptnet.4
+++ b/share/man/man4/ptnet.4
@@ -22,8 +22,6 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
-.\"
 .Dd December 11, 2018
 .Dt PTNET 4
 .Os
diff --git a/share/man/man4/vale.4 b/share/man/man4/vale.4
index d506ff114..85204de68 100644
--- a/share/man/man4/vale.4
+++ b/share/man/man4/vale.4
@@ -25,7 +25,6 @@
 .\" This document is derived in part from the enet man page (enet.4)
 .\" distributed with 4.3BSD Unix.
 .\"
-.\" $FreeBSD$
 .\" $Id: $
 .\"
 .Dd February 6, 2020
diff --git a/sys/dev/netmap/if_em_netmap.h b/sys/dev/netmap/if_em_netmap.h
index d1ec2c32b..cda0ee38f 100644
--- a/sys/dev/netmap/if_em_netmap.h
+++ b/sys/dev/netmap/if_em_netmap.h
@@ -26,8 +26,6 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_em_netmap.h 238985 2012-08-02 11:59:43Z luigi $
- *
  * netmap support for: em.
  *
  * For more details on netmap support please see ixgbe_netmap.h
diff --git a/sys/dev/netmap/if_igb_netmap.h b/sys/dev/netmap/if_igb_netmap.h
index 5f351edf6..b10348e7d 100644
--- a/sys/dev/netmap/if_igb_netmap.h
+++ b/sys/dev/netmap/if_igb_netmap.h
@@ -26,8 +26,6 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_igb_netmap.h 256200 2013-10-09 17:32:52Z jfv $
- *
  * Netmap support for igb, partly contributed by Ahmed Kooli
  * For details on netmap support please see ixgbe_netmap.h
  */
diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h
index 547ed3d8a..43ea9fb48 100644
--- a/sys/dev/netmap/if_ixl_netmap.h
+++ b/sys/dev/netmap/if_ixl_netmap.h
@@ -24,8 +24,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * netmap support for: ixl
  *
  * derived from ixgbe
diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h
index 4867c4f9f..9842f9714 100644
--- a/sys/dev/netmap/if_lem_netmap.h
+++ b/sys/dev/netmap/if_lem_netmap.h
@@ -27,8 +27,6 @@
 
 
 /*
- * $FreeBSD: head/sys/dev/netmap/if_lem_netmap.h 271849 2014-09-19 03:51:26Z glebius $
- *
  * netmap support for: lem
  *
  * For details on netmap support please see ixgbe_netmap.h
diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c
index 5b3332ee5..56d853eb7 100644
--- a/sys/dev/netmap/if_ptnet.c
+++ b/sys/dev/netmap/if_ptnet.c
@@ -22,8 +22,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
 /* Driver for ptnet paravirtualized network device. */
diff --git a/sys/dev/netmap/if_re_netmap.h b/sys/dev/netmap/if_re_netmap.h
index 236cd904f..4864f3b50 100644
--- a/sys/dev/netmap/if_re_netmap.h
+++ b/sys/dev/netmap/if_re_netmap.h
@@ -26,8 +26,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * netmap support for: re
  *
  * For more details on netmap support please see ixgbe_netmap.h
diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h
index fc18976ee..4eafff5ed 100644
--- a/sys/dev/netmap/if_vtnet_netmap.h
+++ b/sys/dev/netmap/if_vtnet_netmap.h
@@ -23,10 +23,6 @@
  * SUCH DAMAGE.
  */
 
-/*
- * $FreeBSD$
- */
-
 #include 
 #include 
 #include 
diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h
index 120b19366..c7ff503ed 100644
--- a/sys/dev/netmap/ixgbe_netmap.h
+++ b/sys/dev/netmap/ixgbe_netmap.h
@@ -26,8 +26,6 @@
  */
 
 /*
- * $FreeBSD: head/sys/dev/netmap/ixgbe_netmap.h 244514 2012-12-20 22:26:03Z luigi $
- *
  * netmap support for: ixgbe (both ix and ixv)
  *
  * This file is meant to be a reference on how to implement
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index c22b66a72..2c4e8ce28 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -31,8 +31,6 @@
 
 
 /*
- * $FreeBSD$
- *
  * This module supports memory mapped access to network devices,
  * see netmap(4).
  *
diff --git a/sys/dev/netmap/netmap_bdg.c b/sys/dev/netmap/netmap_bdg.c
index ef8cb8104..4c19874d9 100644
--- a/sys/dev/netmap/netmap_bdg.c
+++ b/sys/dev/netmap/netmap_bdg.c
@@ -58,8 +58,6 @@ ports attached to the switch)
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
-__FBSDID("$FreeBSD$");
-
 #include 
 #include 
 #include 	/* defines used in kernel.h */
diff --git a/sys/dev/netmap/netmap_bdg.h b/sys/dev/netmap/netmap_bdg.h
index 688a6fbde..ca00e3ce3 100644
--- a/sys/dev/netmap/netmap_bdg.h
+++ b/sys/dev/netmap/netmap_bdg.h
@@ -24,8 +24,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 #ifndef _NET_NETMAP_BDG_H_
 #define _NET_NETMAP_BDG_H_
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index b57687963..6eb707a28 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -25,7 +25,6 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD$ */
 #include "opt_inet.h"
 #include "opt_inet6.h"
 
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index 4dea40554..41e89b893 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -67,8 +67,6 @@
 #ifdef __FreeBSD__
 
 #include  /* prerequisite */
-__FBSDID("$FreeBSD$");
-
 #include 
 #include 
 #include 
diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h
index c52bd03a0..4f66efb31 100644
--- a/sys/dev/netmap/netmap_kern.h
+++ b/sys/dev/netmap/netmap_kern.h
@@ -28,8 +28,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * The header contains the definitions of constants and function
  * prototypes used only in kernelspace.
  */
diff --git a/sys/dev/netmap/netmap_kloop.c b/sys/dev/netmap/netmap_kloop.c
index eb25db972..e9027249b 100644
--- a/sys/dev/netmap/netmap_kloop.c
+++ b/sys/dev/netmap/netmap_kloop.c
@@ -23,8 +23,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
 /*
diff --git a/sys/dev/netmap/netmap_legacy.c b/sys/dev/netmap/netmap_legacy.c
index 658a1c223..b52bf24e1 100644
--- a/sys/dev/netmap/netmap_legacy.c
+++ b/sys/dev/netmap/netmap_legacy.c
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD$ */
-
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 #include 
diff --git a/sys/dev/netmap/netmap_mbq.c b/sys/dev/netmap/netmap_mbq.c
index 0c8ed17c7..6b1e0da07 100644
--- a/sys/dev/netmap/netmap_mbq.c
+++ b/sys/dev/netmap/netmap_mbq.c
@@ -26,11 +26,6 @@
  * SUCH DAMAGE.
  */
 
-/*
- * $FreeBSD$
- */
-
-
 #ifdef linux
 #include "bsd_glue.h"
 #elif defined (_WIN32)
diff --git a/sys/dev/netmap/netmap_mbq.h b/sys/dev/netmap/netmap_mbq.h
index 2db14cc10..b8b811c64 100644
--- a/sys/dev/netmap/netmap_mbq.h
+++ b/sys/dev/netmap/netmap_mbq.h
@@ -26,11 +26,6 @@
  * SUCH DAMAGE.
  */
 
-/*
- * $FreeBSD$
- */
-
-
 #ifndef _NET_NETMAP_MBQ_H__
 #define _NET_NETMAP_MBQ_H__
 
diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c
index dd3b95d8e..9a3e5a7b0 100644
--- a/sys/dev/netmap/netmap_mem2.c
+++ b/sys/dev/netmap/netmap_mem2.c
@@ -38,8 +38,6 @@
 
 #ifdef __FreeBSD__
 #include  /* prerequisite */
-__FBSDID("$FreeBSD$");
-
 #include 
 #include 
 #include 		/* MALLOC_DEFINE */
diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h
index 53e7f2b0c..b1ccc0138 100644
--- a/sys/dev/netmap/netmap_mem2.h
+++ b/sys/dev/netmap/netmap_mem2.h
@@ -29,8 +29,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * (New) memory allocator for netmap
  */
 
diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c
index a8bd2d17b..2e04f4e7a 100644
--- a/sys/dev/netmap/netmap_monitor.c
+++ b/sys/dev/netmap/netmap_monitor.c
@@ -25,8 +25,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * Monitors
  *
  * netmap monitors can be used to do monitoring of network traffic
diff --git a/sys/dev/netmap/netmap_null.c b/sys/dev/netmap/netmap_null.c
index c91afdb55..8066c1363 100644
--- a/sys/dev/netmap/netmap_null.c
+++ b/sys/dev/netmap/netmap_null.c
@@ -23,7 +23,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-/* $FreeBSD$ */
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c
index 745f5f401..96dad21a6 100644
--- a/sys/dev/netmap/netmap_offloadings.c
+++ b/sys/dev/netmap/netmap_offloadings.c
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD$ */
-
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 
diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c
index ab2d591df..cfaa6554b 100644
--- a/sys/dev/netmap/netmap_pipe.c
+++ b/sys/dev/netmap/netmap_pipe.c
@@ -26,8 +26,6 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD$ */
-
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
 
diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c
index 199731af6..0ada47922 100644
--- a/sys/dev/netmap/netmap_vale.c
+++ b/sys/dev/netmap/netmap_vale.c
@@ -29,8 +29,6 @@
 
 #if defined(__FreeBSD__)
 #include  /* prerequisite */
-__FBSDID("$FreeBSD$");
-
 #include 
 #include 
 #include 	/* defines used in kernel.h */
diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile
index 8d0b35811..06212aa5f 100644
--- a/sys/modules/netmap/Makefile
+++ b/sys/modules/netmap/Makefile
@@ -1,5 +1,3 @@
-# $FreeBSD$
-#
 # Compile netmap as a module, useful if you want a netmap bridge
 # or loadable drivers.
 
diff --git a/sys/net/netmap.h b/sys/net/netmap.h
index bd99d2157..998e3153c 100644
--- a/sys/net/netmap.h
+++ b/sys/net/netmap.h
@@ -27,8 +27,6 @@
  */
 
 /*
- * $FreeBSD: head/sys/net/netmap.h 251139 2013-05-30 14:07:14Z luigi $
- *
  * Definitions of constants and the structures used by the netmap
  * framework, for the part visible to both kernel and userspace.
  * Detailed info on netmap is available with "man netmap" or at
diff --git a/sys/net/netmap_legacy.h b/sys/net/netmap_legacy.h
index 042a42985..ccf9c5b3d 100644
--- a/sys/net/netmap_legacy.h
+++ b/sys/net/netmap_legacy.h
@@ -30,8 +30,6 @@
 #define _NET_NETMAP_LEGACY_H_
 
 /*
- * $FreeBSD$
- *
  * ioctl names and related fields
  *
  * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h
index 526953916..0a9cbac05 100644
--- a/sys/net/netmap_user.h
+++ b/sys/net/netmap_user.h
@@ -28,8 +28,6 @@
  */
 
 /*
- * $FreeBSD$
- *
  * Functions and macros to manipulate netmap structures and packets
  * in userspace. See netmap(4) for more information.
  *
diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h
index 07e551aff..c9921d2c5 100644
--- a/sys/net/netmap_virt.h
+++ b/sys/net/netmap_virt.h
@@ -25,8 +25,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
 #ifndef NETMAP_VIRT_H
diff --git a/utils/README b/utils/README
index 002fa9e56..08ab2d4ed 100644
--- a/utils/README
+++ b/utils/README
@@ -1,5 +1,3 @@
-$FreeBSD$
-
 This directory contains miscellaneous programs related to netmap
 
 	ctrl-api-test.c		suite of unit tests for the netmap control ABI
diff --git a/utils/click-test.cfg b/utils/click-test.cfg
index d95ab4a6d..927ba10ba 100644
--- a/utils/click-test.cfg
+++ b/utils/click-test.cfg
@@ -1,6 +1,4 @@
 //
-// $FreeBSD: head/tools/tools/netmap/click-test.cfg 227614 2011-11-17 12:17:39Z luigi $
-//
 // A sample test configuration for click
 //
 //
diff --git a/utils/ctrl-api-test.c b/utils/ctrl-api-test.c
index 7ee29c6f0..64c980e01 100644
--- a/utils/ctrl-api-test.c
+++ b/utils/ctrl-api-test.c
@@ -23,8 +23,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $FreeBSD$
  */
 
 /*